Merge branch 'next' (accumulated 3.16 merge window patches) into master

Now that 3.15 is released, this merges the 'next' branch into 'master',
bringing us to the normal situation where my 'master' branch is the
merge window.

* accumulated work in next: (6809 commits)
  ufs: sb mutex merge + mutex_destroy
  powerpc: update comments for generic idle conversion
  cris: update comments for generic idle conversion
  idle: remove cpu_idle() forward declarations
  nbd: zero from and len fields in NBD_CMD_DISCONNECT.
  mm: convert some level-less printks to pr_*
  MAINTAINERS: adi-buildroot-devel is moderated
  MAINTAINERS: add linux-api for review of API/ABI changes
  mm/kmemleak-test.c: use pr_fmt for logging
  fs/dlm/debug_fs.c: replace seq_printf by seq_puts
  fs/dlm/lockspace.c: convert simple_str to kstr
  fs/dlm/config.c: convert simple_str to kstr
  mm: mark remap_file_pages() syscall as deprecated
  mm: memcontrol: remove unnecessary memcg argument from soft limit functions
  mm: memcontrol: clean up memcg zoneinfo lookup
  mm/memblock.c: call kmemleak directly from memblock_(alloc|free)
  mm/mempool.c: update the kmemleak stack trace for mempool allocations
  lib/radix-tree.c: update the kmemleak stack trace for radix tree allocations
  mm: introduce kmemleak_update_trace()
  mm/kmemleak.c: use %u to print ->checksum
  ...
This commit is contained in:
Linus Torvalds
2014-06-08 11:31:16 -07:00
5560 changed files with 309083 additions and 158345 deletions

View File

@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/goldfish.h>
enum {
GOLDFISH_TTY_PUT_CHAR = 0x00,
@@ -29,6 +30,7 @@ enum {
GOLDFISH_TTY_DATA_PTR = 0x10,
GOLDFISH_TTY_DATA_LEN = 0x14,
GOLDFISH_TTY_DATA_PTR_HIGH = 0x18,
GOLDFISH_TTY_CMD_INT_DISABLE = 0,
GOLDFISH_TTY_CMD_INT_ENABLE = 1,
@@ -57,7 +59,8 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
struct goldfish_tty *qtty = &goldfish_ttys[line];
void __iomem *base = qtty->base;
spin_lock_irqsave(&qtty->lock, irq_flags);
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR,
base + GOLDFISH_TTY_DATA_PTR_HIGH);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
@@ -73,12 +76,13 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
u32 count;
count = readl(base + GOLDFISH_TTY_BYTES_READY);
if(count == 0)
if (count == 0)
return IRQ_NONE;
count = tty_prepare_flip_string(&qtty->port, &buf, count);
spin_lock_irqsave(&qtty->lock, irq_flags);
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR,
base + GOLDFISH_TTY_DATA_PTR_HIGH);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
@@ -88,24 +92,26 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
{
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
port);
writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
return 0;
}
static void goldfish_tty_shutdown(struct tty_port *port)
{
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
port);
writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
}
static int goldfish_tty_open(struct tty_struct * tty, struct file * filp)
static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
{
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
return tty_port_open(&qtty->port, tty, filp);
}
static void goldfish_tty_close(struct tty_struct * tty, struct file * filp)
static void goldfish_tty_close(struct tty_struct *tty, struct file *filp)
{
tty_port_close(tty->port, tty, filp);
}
@@ -115,7 +121,8 @@ static void goldfish_tty_hangup(struct tty_struct *tty)
tty_port_hangup(tty->port);
}
static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf,
int count)
{
goldfish_tty_do_write(tty->index, buf, count);
return count;
@@ -133,12 +140,14 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
return readl(base + GOLDFISH_TTY_BYTES_READY);
}
static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count)
static void goldfish_tty_console_write(struct console *co, const char *b,
unsigned count)
{
goldfish_tty_do_write(co->index, b, count);
}
static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index)
static struct tty_driver *goldfish_tty_console_device(struct console *c,
int *index)
{
*index = c->index;
return goldfish_tty_driver;
@@ -146,9 +155,9 @@ static struct tty_driver *goldfish_tty_console_device(struct console *c, int *in
static int goldfish_tty_console_setup(struct console *co, char *options)
{
if((unsigned)co->index > goldfish_tty_line_count)
if ((unsigned)co->index > goldfish_tty_line_count)
return -ENODEV;
if(goldfish_ttys[co->index].base == 0)
if (goldfish_ttys[co->index].base == 0)
return -ENODEV;
return 0;
}
@@ -158,7 +167,7 @@ static struct tty_port_operations goldfish_port_ops = {
.shutdown = goldfish_tty_shutdown
};
static struct tty_operations goldfish_tty_ops = {
static const struct tty_operations goldfish_tty_ops = {
.open = goldfish_tty_open,
.close = goldfish_tty_close,
.hangup = goldfish_tty_hangup,
@@ -172,13 +181,14 @@ static int goldfish_tty_create_driver(void)
int ret;
struct tty_driver *tty;
goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL);
if(goldfish_ttys == NULL) {
goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) *
goldfish_tty_line_count, GFP_KERNEL);
if (goldfish_ttys == NULL) {
ret = -ENOMEM;
goto err_alloc_goldfish_ttys_failed;
}
tty = alloc_tty_driver(goldfish_tty_line_count);
if(tty == NULL) {
if (tty == NULL) {
ret = -ENOMEM;
goto err_alloc_tty_driver_failed;
}
@@ -187,10 +197,11 @@ static int goldfish_tty_create_driver(void)
tty->type = TTY_DRIVER_TYPE_SERIAL;
tty->subtype = SERIAL_TYPE_NORMAL;
tty->init_termios = tty_std_termios;
tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(tty, &goldfish_tty_ops);
ret = tty_register_driver(tty);
if(ret)
if (ret)
goto err_tty_register_driver_failed;
goldfish_tty_driver = tty;
@@ -225,7 +236,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
u32 irq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(r == NULL)
if (r == NULL)
return -EINVAL;
base = ioremap(r->start, 0x1000);
@@ -233,18 +244,18 @@ static int goldfish_tty_probe(struct platform_device *pdev)
pr_err("goldfish_tty: unable to remap base\n");
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if(r == NULL)
if (r == NULL)
goto err_unmap;
irq = r->start;
if(pdev->id >= goldfish_tty_line_count)
if (pdev->id >= goldfish_tty_line_count)
goto err_unmap;
mutex_lock(&goldfish_tty_lock);
if(goldfish_tty_current_line_count == 0) {
if (goldfish_tty_current_line_count == 0) {
ret = goldfish_tty_create_driver();
if(ret)
if (ret)
goto err_create_driver_failed;
}
goldfish_tty_current_line_count++;
@@ -258,14 +269,15 @@ static int goldfish_tty_probe(struct platform_device *pdev)
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev);
if(ret)
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
"goldfish_tty", pdev);
if (ret)
goto err_request_irq_failed;
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
pdev->id, &pdev->dev);
if(IS_ERR(ttydev)) {
if (IS_ERR(ttydev)) {
ret = PTR_ERR(ttydev);
goto err_tty_register_device_failed;
}
@@ -286,7 +298,7 @@ err_tty_register_device_failed:
free_irq(irq, pdev);
err_request_irq_failed:
goldfish_tty_current_line_count--;
if(goldfish_tty_current_line_count == 0)
if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
err_create_driver_failed:
mutex_unlock(&goldfish_tty_lock);
@@ -308,7 +320,7 @@ static int goldfish_tty_remove(struct platform_device *pdev)
qtty->base = 0;
free_irq(qtty->irq, pdev);
goldfish_tty_current_line_count--;
if(goldfish_tty_current_line_count == 0)
if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
mutex_unlock(&goldfish_tty_lock);
return 0;

View File

@@ -760,10 +760,17 @@ static int khvcd(void *unused)
if (poll_mask == 0)
schedule();
else {
unsigned long j_timeout;
if (timeout < MAX_TIMEOUT)
timeout += (timeout >> 6) + 1;
msleep_interruptible(timeout);
/*
* We don't use msleep_interruptible otherwise
* "kick" will fail to wake us up
*/
j_timeout = msecs_to_jiffies(timeout) + 1;
schedule_timeout_interruptible(j_timeout);
}
}
__set_current_state(TASK_RUNNING);

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -8,20 +8,11 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <asm/dcc.h>
#include <asm/processor.h>
#include "hvc_console.h"
@@ -30,35 +21,6 @@
#define DCC_STATUS_RX (1 << 30)
#define DCC_STATUS_TX (1 << 29)
static inline u32 __dcc_getstatus(void)
{
u32 __ret;
asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
: "=r" (__ret) : : "cc");
return __ret;
}
static inline char __dcc_getchar(void)
{
char __c;
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
: "=r" (__c));
isb();
return __c;
}
static inline void __dcc_putchar(char c)
{
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
: /* no output register */
: "r" (c));
isb();
}
static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
{
int i;

View File

@@ -133,14 +133,14 @@ static int hvc_tile_probe(struct platform_device *pdev)
int tile_hvc_irq;
/* Create our IRQ and register it. */
tile_hvc_irq = create_irq();
if (tile_hvc_irq < 0)
tile_hvc_irq = irq_alloc_hwirq(-1);
if (!tile_hvc_irq)
return -ENXIO;
tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU);
hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128);
if (IS_ERR(hp)) {
destroy_irq(tile_hvc_irq);
irq_free_hwirq(tile_hvc_irq);
return PTR_ERR(hp);
}
dev_set_drvdata(&pdev->dev, hp);
@@ -155,7 +155,7 @@ static int hvc_tile_remove(struct platform_device *pdev)
rc = hvc_remove(hp);
if (rc == 0)
destroy_irq(hp->data);
irq_free_hwirq(hp->data);
return rc;
}

View File

@@ -848,13 +848,11 @@ static struct n_hdlc *n_hdlc_alloc(void)
{
struct n_hdlc_buf *buf;
int i;
struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
if (!n_hdlc)
return NULL;
memset(n_hdlc, 0, sizeof(*n_hdlc));
n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
@@ -952,8 +950,6 @@ static char hdlc_register_ok[] __initdata =
KERN_INFO "N_HDLC line discipline registered.\n";
static char hdlc_register_fail[] __initdata =
KERN_ERR "error registering line discipline: %d\n";
static char hdlc_init_fail[] __initdata =
KERN_INFO "N_HDLC: init failure %d\n";
static int __init n_hdlc_init(void)
{
@@ -973,8 +969,6 @@ static int __init n_hdlc_init(void)
else
printk(hdlc_register_fail, status);
if (status)
printk(hdlc_init_fail, status);
return status;
} /* end of init_module() */

View File

@@ -2041,7 +2041,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
if (found)
clear_bit(eol, ldata->read_flags);
smp_mb__after_clear_bit();
smp_mb__after_atomic();
ldata->read_tail += c;
if (found) {

View File

@@ -1926,13 +1926,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
wait_for_xmitr(up, BOTH_EMPTY);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_port_out(port, UART_TX, c);
if (c == 10) {
wait_for_xmitr(up, BOTH_EMPTY);
serial_port_out(port, UART_TX, 13);
}
/*
* Finally, wait for transmitter to become empty
@@ -2338,9 +2333,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
* the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
* UART to respond. IOW, at least 32 bytes of FIFO.
* UART to respond. IOW, at least 32 bytes of FIFO. Also enable
* AFE if hw flow control is supported
*/
if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
(port->flags & UPF_HARD_FLOW)) {
up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE;

View File

@@ -192,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p)
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
&dma->rx_addr, GFP_KERNEL);
if (!dma->rx_buf) {
dma_release_channel(dma->rxchan);
dma_release_channel(dma->txchan);
return -ENOMEM;
}
if (!dma->rx_buf)
goto err;
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
p->port.state->xmit.buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
dma->rx_buf, dma->rx_addr);
goto err;
}
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
return 0;
err:
dma_release_channel(dma->rxchan);
dma_release_channel(dma->txchan);
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(serial8250_request_dma);

View File

@@ -62,6 +62,70 @@ struct dw8250_data {
struct uart_8250_dma dma;
};
struct dw8250_acpi_desc {
void (*set_termios)(struct uart_port *p, struct ktermios *termios,
struct ktermios *old);
};
#define BYT_PRV_CLK 0x800
#define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1
#define BYT_PRV_CLK_N_VAL_SHIFT 16
#define BYT_PRV_CLK_UPDATE (1 << 31)
static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
unsigned int m, n;
u32 reg;
/*
* For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
* dividers must be adjusted.
*
* uartclk = (m / n) * 100 MHz, where m <= n
*/
switch (baud) {
case 500000:
case 1000000:
case 2000000:
case 4000000:
m = 64;
n = 100;
p->uartclk = 64000000;
break;
case 3500000:
m = 56;
n = 100;
p->uartclk = 56000000;
break;
case 1500000:
case 3000000:
m = 48;
n = 100;
p->uartclk = 48000000;
break;
case 2500000:
m = 40;
n = 100;
p->uartclk = 40000000;
break;
default:
m = 2304;
n = 3125;
p->uartclk = 73728000;
}
/* Reset the clock */
reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
writel(reg, p->membase + BYT_PRV_CLK);
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
writel(reg, p->membase + BYT_PRV_CLK);
serial8250_do_set_termios(p, termios, old);
}
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -278,6 +342,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
{
const struct acpi_device_id *id;
struct uart_port *p = &up->port;
struct dw8250_acpi_desc *acpi_desc;
dw8250_setup_port(up);
@@ -290,14 +355,18 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
p->serial_out = dw8250_serial_out32;
p->regshift = 2;
if (!p->uartclk)
p->uartclk = (unsigned int)id->driver_data;
up->dma = &data->dma;
up->dma->rxconf.src_maxburst = p->fifosize / 4;
up->dma->txconf.dst_maxburst = p->fifosize / 4;
acpi_desc = (struct dw8250_acpi_desc *)id->driver_data;
if (!acpi_desc)
return 0;
if (acpi_desc->set_termios)
p->set_termios = acpi_desc->set_termios;
return 0;
}
@@ -445,12 +514,16 @@ static const struct of_device_id dw8250_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
static struct dw8250_acpi_desc byt_8250_desc = {
.set_termios = byt_set_termios,
};
static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 0 },
{ "INT33C5", 0 },
{ "INT3434", 0 },
{ "INT3435", 0 },
{ "80860F0A", 0 },
{ "80860F0A", (kernel_ulong_t)&byt_8250_desc},
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);

View File

@@ -35,18 +35,8 @@
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/serial.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/pgtable.h>
#include <asm/fixmap.h>
#endif
struct early_serial8250_device {
struct uart_port port;
char options[16]; /* e.g., 115200n8 */
unsigned int baud;
};
static struct early_serial8250_device early_device;
static struct earlycon_device *early_device;
unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
{
@@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c)
static void __init early_serial8250_write(struct console *console,
const char *s, unsigned int count)
{
struct uart_port *port = &early_device.port;
struct uart_port *port = &early_device->port;
unsigned int ier;
/* Save the IER and disable interrupts */
@@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
return (port->uartclk / 16) / quot;
}
static void __init init_port(struct early_serial8250_device *device)
static void __init init_port(struct earlycon_device *device)
{
struct uart_port *port = &device->port;
unsigned int divisor;
@@ -148,128 +138,42 @@ static void __init init_port(struct early_serial8250_device *device)
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
static int __init parse_options(struct early_serial8250_device *device,
char *options)
static int __init early_serial8250_setup(struct earlycon_device *device,
const char *options)
{
struct uart_port *port = &device->port;
int mmio, mmio32, length;
if (!options)
return -ENODEV;
port->uartclk = BASE_BAUD * 16;
mmio = !strncmp(options, "mmio,", 5);
mmio32 = !strncmp(options, "mmio32,", 7);
if (mmio || mmio32) {
port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
&options, 0);
if (mmio32)
port->regshift = 2;
#ifdef CONFIG_FIX_EARLYCON_MEM
set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
port->mapbase & PAGE_MASK);
port->membase =
(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
port->membase += port->mapbase & ~PAGE_MASK;
#else
port->membase = ioremap_nocache(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
__func__,
(unsigned long long) port->mapbase);
return -ENOMEM;
}
#endif
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
port->iobase = simple_strtoul(options + 3, &options, 0);
mmio = 0;
} else
return -EINVAL;
options = strchr(options, ',');
if (options) {
options++;
device->baud = simple_strtoul(options, NULL, 0);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
strlcpy(device->options, options, length);
} else {
device->baud = probe_baud(port);
snprintf(device->options, sizeof(device->options), "%u",
device->baud);
}
if (mmio || mmio32)
printk(KERN_INFO
"Early serial console at MMIO%s 0x%llx (options '%s')\n",
mmio32 ? "32" : "",
(unsigned long long)port->mapbase,
device->options);
else
printk(KERN_INFO
"Early serial console at I/O port 0x%lx (options '%s')\n",
port->iobase,
device->options);
return 0;
}
static struct console early_serial8250_console __initdata = {
.name = "uart",
.write = early_serial8250_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
static int __init early_serial8250_setup(char *options)
{
struct early_serial8250_device *device = &early_device;
int err;
if (device->port.membase || device->port.iobase)
if (!(device->port.membase || device->port.iobase))
return 0;
err = parse_options(device, options);
if (err < 0)
return err;
if (!device->baud)
device->baud = probe_baud(&device->port);
init_port(device);
early_device = device;
device->con->write = early_serial8250_write;
return 0;
}
EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
int __init setup_early_serial8250_console(char *cmdline)
{
char *options;
int err;
char match[] = "uart8250";
options = strstr(cmdline, "uart8250,");
if (!options) {
options = strstr(cmdline, "uart,");
if (!options)
return 0;
}
if (cmdline && cmdline[4] == ',')
match[4] = '\0';
options = strchr(cmdline, ',') + 1;
err = early_serial8250_setup(options);
if (err < 0)
return err;
register_console(&early_serial8250_console);
return 0;
return setup_earlycon(cmdline, match, early_serial8250_setup);
}
int serial8250_find_port_for_earlycon(void)
{
struct early_serial8250_device *device = &early_device;
struct uart_port *port = &device->port;
struct earlycon_device *device = early_device;
struct uart_port *port = device ? &device->port : NULL;
int line;
int ret;
if (!device->port.membase && !device->port.iobase)
if (!port || (!port->membase && !port->iobase))
return -ENODEV;
line = serial8250_find_port(port);
@@ -284,5 +188,3 @@ int serial8250_find_port_for_earlycon(void)
return ret;
}
early_param("earlycon", setup_early_serial8250_console);

View File

@@ -1753,6 +1753,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618
#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618
#define PCI_DEVICE_ID_TITAN_200I 0x8028
#define PCI_DEVICE_ID_TITAN_400I 0x8048
#define PCI_DEVICE_ID_TITAN_800I 0x8088
@@ -1778,6 +1780,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
@@ -2410,6 +2413,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
},
/* WCH CH353 1S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
.device = PCI_DEVICE_ID_WCH_CH353_1S1P,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 2S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
@@ -3526,6 +3537,7 @@ static const struct pci_device_id blacklist[] = {
/* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
};
/*
@@ -3880,6 +3892,13 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
pbn_b2_8_921600 },
/* Advantech also use 0x3618 and 0xf618 */
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,

View File

@@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
---help---
If you say Y here, it will be possible to use a serial port as the
system console (the system console is the device which receives all
@@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE
If unsure, say N.
config FIX_EARLYCON_MEM
bool
depends on X86
default y
config SERIAL_8250_GSC
tristate
depends on SERIAL_8250 && GSC

View File

@@ -7,6 +7,13 @@ if TTY
menu "Serial drivers"
depends on HAS_IOMEM
config SERIAL_EARLYCON
bool
help
Support for early consoles with the earlycon parameter. This enables
the console before standard serial driver is probed. The console is
enabled when early_param is processed.
source "drivers/tty/serial/8250/Kconfig"
comment "Non-8250 serial port support"
@@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE
bool "Support for console on AMBA serial port"
depends on SERIAL_AMBA_PL011=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
---help---
Say Y here if you wish to use an AMBA PrimeCell UART as the system
console (the system console is the device which receives all kernel
@@ -65,6 +73,18 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_EARLYCON_ARM_SEMIHOST
bool "Early console using ARM semihosting"
depends on ARM64 || ARM
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
Support for early debug console using ARM semihosting. This enables
the console before standard serial driver is probed. This is enabled
with "earlycon=smh" on the kernel command line. The console is
enabled when early_param is processed.
config SERIAL_SB1250_DUART
tristate "BCM1xxx on-chip DUART serial support"
depends on SIBYTE_SB1xxx_SOC=y
@@ -97,6 +117,7 @@ config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
depends on ARCH_AT91 || AVR32
select SERIAL_CORE
select SERIAL_MCTRL_GPIO
help
This enables the driver for the on-chip UARTs of the Atmel
AT91 and AT32 processors.
@@ -1160,6 +1181,16 @@ config SERIAL_SCCNXP_CONSOLE
help
Support for console on SCCNXP serial ports.
config SERIAL_SC16IS7XX
tristate "SC16IS7xx serial support"
depends on I2C
select SERIAL_CORE
select REGMAP_I2C if I2C
help
This selects support for SC16IS7xx serial ports.
Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
SC16IS760 and SC16IS762.
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
@@ -1323,7 +1354,7 @@ config SERIAL_IFX6X60
config SERIAL_PCH_UART
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
depends on PCI
depends on PCI && (X86_32 || COMPILE_TEST)
select SERIAL_CORE
help
This driver is for PCH(Platform controller Hub) UART of Intel EG20T
@@ -1369,18 +1400,19 @@ config SERIAL_MXS_AUART_CONSOLE
Enable a MXS AUART port to be the system console.
config SERIAL_XILINX_PS_UART
tristate "Xilinx PS UART support"
tristate "Cadence (Xilinx Zynq) UART support"
depends on OF
select SERIAL_CORE
help
This driver supports the Xilinx PS UART port.
This driver supports the Cadence UART. It is found e.g. in Xilinx
Zynq.
config SERIAL_XILINX_PS_UART_CONSOLE
bool "Xilinx PS UART console support"
bool "Cadence UART console support"
depends on SERIAL_XILINX_PS_UART=y
select SERIAL_CORE_CONSOLE
help
Enable a Xilinx PS UART port to be the system console.
Enable a Cadence UART port to be the system console.
config SERIAL_AR933X
tristate "AR933X serial port support"
@@ -1479,6 +1511,7 @@ config SERIAL_RP2_NR_UARTS
config SERIAL_FSL_LPUART
tristate "Freescale lpuart serial port support"
depends on HAS_DMA
select SERIAL_CORE
help
Support for the on-chip lpuart on some Freescale SOCs.
@@ -1508,6 +1541,20 @@ config SERIAL_ST_ASC_CONSOLE
depends on SERIAL_ST_ASC=y
select SERIAL_CORE_CONSOLE
config SERIAL_MEN_Z135
tristate "MEN 16z135 Support"
select SERIAL_CORE
depends on MCB
help
Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core
on a MCB carrier.
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
endmenu
config SERIAL_MCTRL_GPIO
tristate
endif # TTY

View File

@@ -5,6 +5,9 @@
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
# These Sparc drivers have to appear before others such as 8250
# which share ttySx minor node space. Otherwise console device
# names change and other unplesantries.
@@ -48,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@@ -87,3 +91,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o

View File

@@ -303,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
/* Optionally make use of an RX channel as well */
chan = dma_request_slave_channel(dev, "rx");
if (!chan && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
@@ -2045,6 +2045,35 @@ static struct console amba_console = {
};
#define AMBA_CONSOLE (&amba_console)
static void pl011_putc(struct uart_port *port, int c)
{
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
;
writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
;
}
static void pl011_early_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, pl011_putc);
}
static int __init pl011_early_console_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
device->con->write = pl011_early_write;
return 0;
}
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
#else
#define AMBA_CONSOLE NULL
#endif

View File

@@ -43,6 +43,9 @@
#include <linux/platform_data/atmel.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -57,6 +60,8 @@
#include <linux/serial_core.h>
#include "serial_mctrl_gpio.h"
static void atmel_start_rx(struct uart_port *port);
static void atmel_stop_rx(struct uart_port *port);
@@ -162,8 +167,10 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct serial_rs485 rs485; /* rs485 settings */
int rts_gpio; /* optional RTS GPIO */
struct mctrl_gpios *gpios;
int gpio_irq[UART_GPIO_MAX];
unsigned int tx_done_mask;
bool ms_irq_enabled;
bool is_usart; /* usart or uart */
struct timer_list uart_timer; /* uart timer */
int (*prepare_rx)(struct uart_port *port);
@@ -237,6 +244,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
return atmel_port->use_dma_rx;
}
static unsigned int atmel_get_lines_status(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, ret = 0;
status = UART_GET_CSR(port);
mctrl_gpio_get(atmel_port->gpios, &ret);
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_CTS))) {
if (ret & TIOCM_CTS)
status &= ~ATMEL_US_CTS;
else
status |= ATMEL_US_CTS;
}
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_DSR))) {
if (ret & TIOCM_DSR)
status &= ~ATMEL_US_DSR;
else
status |= ATMEL_US_DSR;
}
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_RI))) {
if (ret & TIOCM_RI)
status &= ~ATMEL_US_RI;
else
status |= ATMEL_US_RI;
}
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_DCD))) {
if (ret & TIOCM_CD)
status &= ~ATMEL_US_DCD;
else
status |= ATMEL_US_DCD;
}
return status;
}
/* Enable or disable the rs485 support */
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
{
@@ -296,17 +347,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
unsigned int mode;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/*
* AT91RM9200 Errata #39: RTS0 is not internally connected
* to PA21. We need to drive the pin as a GPIO.
*/
if (gpio_is_valid(atmel_port->rts_gpio)) {
if (mctrl & TIOCM_RTS)
gpio_set_value(atmel_port->rts_gpio, 0);
else
gpio_set_value(atmel_port->rts_gpio, 1);
}
if (mctrl & TIOCM_RTS)
control |= ATMEL_US_RTSEN;
else
@@ -319,6 +359,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
UART_PUT_CR(port, control);
mctrl_gpio_set(atmel_port->gpios, mctrl);
/* Local loopback mode? */
mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
if (mctrl & TIOCM_LOOP)
@@ -346,7 +388,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
*/
static u_int atmel_get_mctrl(struct uart_port *port)
{
unsigned int status, ret = 0;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int ret = 0, status;
status = UART_GET_CSR(port);
@@ -362,7 +405,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
if (!(status & ATMEL_US_RI))
ret |= TIOCM_RI;
return ret;
return mctrl_gpio_get(atmel_port->gpios, &ret);
}
/*
@@ -449,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
*/
static void atmel_enable_ms(struct uart_port *port)
{
UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
uint32_t ier = 0;
/*
* Interrupt should not be enabled twice
*/
if (atmel_port->ms_irq_enabled)
return;
atmel_port->ms_irq_enabled = true;
if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
else
ier |= ATMEL_US_CTSIC;
if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
else
ier |= ATMEL_US_DSRIC;
if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
else
ier |= ATMEL_US_RIIC;
if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
else
ier |= ATMEL_US_DCDIC;
UART_PUT_IER(port, ier);
}
/*
@@ -1039,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
static irqreturn_t atmel_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, pending, pass_counter = 0;
bool gpio_handled = false;
do {
status = UART_GET_CSR(port);
status = atmel_get_lines_status(port);
pending = status & UART_GET_IMR(port);
if (!gpio_handled) {
/*
* Dealing with GPIO interrupt
*/
if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
pending |= ATMEL_US_CTSIC;
if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
pending |= ATMEL_US_DSRIC;
if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
pending |= ATMEL_US_RIIC;
if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
pending |= ATMEL_US_DCDIC;
gpio_handled = true;
}
if (!pending)
break;
@@ -1523,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
}
}
static void atmel_free_gpio_irq(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
enum mctrl_gpio_idx i;
for (i = 0; i < UART_GPIO_MAX; i++)
if (atmel_port->gpio_irq[i] >= 0)
free_irq(atmel_port->gpio_irq[i], port);
}
static int atmel_request_gpio_irq(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int *irq = atmel_port->gpio_irq;
enum mctrl_gpio_idx i;
int err = 0;
for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
if (irq[i] < 0)
continue;
irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
"atmel_serial", port);
if (err)
dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
irq[i]);
}
/*
* If something went wrong, rollback.
*/
while (err && (--i >= 0))
if (irq[i] >= 0)
free_irq(irq[i], port);
return err;
}
/*
* Perform initialization and enable port for reception
*/
@@ -1539,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
* handle an unexpected interrupt
*/
UART_PUT_IDR(port, -1);
atmel_port->ms_irq_enabled = false;
/*
* Allocate the IRQ
@@ -1550,6 +1683,13 @@ static int atmel_startup(struct uart_port *port)
return retval;
}
/*
* Get the GPIO lines IRQ
*/
retval = atmel_request_gpio_irq(port);
if (retval)
goto free_irq;
/*
* Initialize DMA (if necessary)
*/
@@ -1568,7 +1708,7 @@ static int atmel_startup(struct uart_port *port)
}
/* Save current CSR for comparison in atmel_tasklet_func() */
atmel_port->irq_status_prev = UART_GET_CSR(port);
atmel_port->irq_status_prev = atmel_get_lines_status(port);
atmel_port->irq_status = atmel_port->irq_status_prev;
/*
@@ -1614,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
}
return 0;
free_irq:
free_irq(port->irq, port);
return retval;
}
/*
@@ -1661,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
atmel_port->rx_ring.tail = 0;
/*
* Free the interrupt
* Free the interrupts
*/
free_irq(port->irq, port);
atmel_free_gpio_irq(port);
atmel_port->ms_irq_enabled = false;
}
/*
@@ -2324,6 +2472,26 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
{
enum mctrl_gpio_idx i;
struct gpio_desc *gpiod;
p->gpios = mctrl_gpio_init(dev, 0);
if (IS_ERR_OR_NULL(p->gpios))
return -1;
for (i = 0; i < UART_GPIO_MAX; i++) {
gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
p->gpio_irq[i] = gpiod_to_irq(gpiod);
else
p->gpio_irq[i] = -EINVAL;
}
return 0;
}
static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
@@ -2359,25 +2527,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
port = &atmel_ports[ret];
port->backup_imr = 0;
port->uart.line = ret;
port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
if (pdata)
port->rts_gpio = pdata->rts_gpio;
else if (np)
port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
if (gpio_is_valid(port->rts_gpio)) {
ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
if (ret) {
dev_err(&pdev->dev, "error requesting RTS GPIO\n");
goto err;
}
/* Default to 1 as RTS is active low */
ret = gpio_direction_output(port->rts_gpio, 1);
if (ret) {
dev_err(&pdev->dev, "error setting up RTS GPIO\n");
goto err;
}
}
ret = atmel_init_gpios(port, &pdev->dev);
if (ret < 0)
dev_err(&pdev->dev, "%s",
"Failed to initialize GPIOs. The serial port may not work as expected");
ret = atmel_init_port(port, pdev);
if (ret)

View File

@@ -971,7 +971,7 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)
* Note that this is called with interrupts already disabled
*/
static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
const char *string, u_int count)
const char *string, u_int count, bool handle_linefeed)
{
unsigned int i;
cbd_t __iomem *bdp, *bdbase;
@@ -1013,7 +1013,7 @@ static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
bdp++;
/* if a LF, also do CR... */
if (*string == 10) {
if (handle_linefeed && *string == 10) {
while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
@@ -1111,7 +1111,7 @@ static void cpm_put_poll_char(struct uart_port *port,
static char ch[2];
ch[0] = (char)c;
cpm_uart_early_write(pinfo, ch, 1);
cpm_uart_early_write(pinfo, ch, 1, false);
}
#endif /* CONFIG_CONSOLE_POLL */
@@ -1275,7 +1275,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
spin_lock_irqsave(&pinfo->port.lock, flags);
}
cpm_uart_early_write(pinfo, s, count);
cpm_uart_early_write(pinfo, s, count, true);
if (unlikely(nolock)) {
local_irq_restore(flags);

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2012 ARM Ltd.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* Adapted for ARM and earlycon:
* Copyright (C) 2014 Linaro Ltd.
* Author: Rob Herring <robh@kernel.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#ifdef CONFIG_THUMB2_KERNEL
#define SEMIHOST_SWI "0xab"
#else
#define SEMIHOST_SWI "0x123456"
#endif
/*
* Semihosting-based debug console
*/
static void smh_putc(struct uart_port *port, int c)
{
#ifdef CONFIG_ARM64
asm volatile("mov x1, %0\n"
"mov x0, #3\n"
"hlt 0xf000\n"
: : "r" (&c) : "x0", "x1", "memory");
#else
asm volatile("mov r1, %0\n"
"mov r0, #3\n"
"svc " SEMIHOST_SWI "\n"
: : "r" (&c) : "r0", "r1", "memory");
#endif
}
static void smh_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, smh_putc);
}
int __init early_smh_setup(struct earlycon_device *device, const char *opt)
{
device->con->write = smh_write;
return 0;
}
EARLYCON_DECLARE(smh, early_smh_setup);

View File

@@ -0,0 +1,172 @@
/*
* Copyright (C) 2014 Linaro Ltd.
* Author: Rob Herring <robh@kernel.org>
*
* Based on 8250 earlycon:
* (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/serial_core.h>
#include <linux/sizes.h>
#include <linux/mod_devicetable.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
#endif
#include <asm/serial.h>
static struct console early_con = {
.name = "earlycon",
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
static struct earlycon_device early_console_dev = {
.con = &early_con,
};
static const struct of_device_id __earlycon_of_table_sentinel
__used __section(__earlycon_of_table_end);
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
#ifdef CONFIG_FIX_EARLYCON_MEM
set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
base += paddr & ~PAGE_MASK;
#else
base = ioremap(paddr, size);
#endif
if (!base)
pr_err("%s: Couldn't map 0x%llx\n", __func__,
(unsigned long long)paddr);
return base;
}
static int __init parse_options(struct earlycon_device *device,
char *options)
{
struct uart_port *port = &device->port;
int mmio, mmio32, length;
unsigned long addr;
if (!options)
return -ENODEV;
mmio = !strncmp(options, "mmio,", 5);
mmio32 = !strncmp(options, "mmio32,", 7);
if (mmio || mmio32) {
port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
options += mmio ? 5 : 7;
addr = simple_strtoul(options, NULL, 0);
port->mapbase = addr;
if (mmio32)
port->regshift = 2;
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
options += 3;
addr = simple_strtoul(options, NULL, 0);
port->iobase = addr;
mmio = 0;
} else if (!strncmp(options, "0x", 2)) {
port->iotype = UPIO_MEM;
addr = simple_strtoul(options, NULL, 0);
port->mapbase = addr;
} else {
return -EINVAL;
}
port->uartclk = BASE_BAUD * 16;
options = strchr(options, ',');
if (options) {
options++;
device->baud = simple_strtoul(options, NULL, 0);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
strlcpy(device->options, options, length);
}
if (mmio || mmio32)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
mmio32 ? "32" : "",
(unsigned long long)port->mapbase,
device->options);
else
pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
port->iobase,
device->options);
return 0;
}
int __init setup_earlycon(char *buf, const char *match,
int (*setup)(struct earlycon_device *, const char *))
{
int err;
size_t len;
struct uart_port *port = &early_console_dev.port;
if (!buf || !match || !setup)
return 0;
len = strlen(match);
if (strncmp(buf, match, len))
return 0;
if (buf[len] && (buf[len] != ','))
return 0;
buf += len + 1;
err = parse_options(&early_console_dev, buf);
/* On parsing error, pass the options buf to the setup function */
if (!err)
buf = NULL;
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
early_console_dev.con->data = &early_console_dev;
err = setup(&early_console_dev, buf);
if (err < 0)
return err;
if (!early_console_dev.con->write)
return -ENODEV;
register_console(early_console_dev.con);
return 0;
}
int __init of_setup_earlycon(unsigned long addr,
int (*setup)(struct earlycon_device *, const char *))
{
int err;
struct uart_port *port = &early_console_dev.port;
port->iotype = UPIO_MEM;
port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
port->membase = earlycon_map(addr, SZ_4K);
early_console_dev.con->data = &early_console_dev;
err = setup(&early_console_dev, NULL);
if (err < 0)
return err;
if (!early_console_dev.con->write)
return -ENODEV;
register_console(early_console_dev.con);
return 0;
}

View File

@@ -842,6 +842,7 @@ static void __exit efm32_uart_exit(void)
platform_driver_unregister(&efm32_uart_driver);
uart_unregister_driver(&efm32_uart_reg);
}
module_exit(efm32_uart_exit);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 UART/USART driver");

View File

@@ -116,7 +116,7 @@
#define UCR3_DSR (1<<10) /* Data set ready */
#define UCR3_DCD (1<<9) /* Data carrier detect */
#define UCR3_RI (1<<8) /* Ring indicator */
#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
@@ -444,6 +444,10 @@ static void imx_stop_rx(struct uart_port *port)
temp = readl(sport->port.membase + UCR2);
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
/* disable the `Receiver Ready Interrrupt` */
temp = readl(sport->port.membase + UCR1);
writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);
}
/*
@@ -1070,7 +1074,7 @@ static void imx_disable_dma(struct imx_port *sport)
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval;
int retval, i;
unsigned long flags, temp;
retval = clk_prepare_enable(sport->clk_per);
@@ -1098,17 +1102,15 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
if (USE_IRDA(sport)) {
/* reset fifo's and state machines */
int i = 100;
temp = readl(sport->port.membase + UCR2);
temp &= ~UCR2_SRST;
writel(temp, sport->port.membase + UCR2);
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
(--i > 0)) {
udelay(1);
}
}
/* Reset fifo's and state machines */
i = 100;
temp = readl(sport->port.membase + UCR2);
temp &= ~UCR2_SRST;
writel(temp, sport->port.membase + UCR2);
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
@@ -1163,18 +1165,9 @@ static int imx_startup(struct uart_port *port)
temp |= UCR2_IRTS;
writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
/* clear RX-FIFO */
int i = 64;
while ((--i > 0) &&
(readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
barrier();
}
}
if (!is_imx1_uart(sport)) {
temp = readl(sport->port.membase + UCR3);
temp |= IMX21_UCR3_RXDMUXSEL;
temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
writel(temp, sport->port.membase + UCR3);
}

View File

@@ -44,13 +44,22 @@ MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
static bool kgdb_nmi_tty_enabled;
static int kgdb_nmi_console_setup(struct console *co, char *options)
{
/* The NMI console uses the dbg_io_ops to issue console messages. To
* avoid duplicate messages during kdb sessions we must inform kdb's
* I/O utilities that messages sent to the console will automatically
* be displayed on the dbg_io.
*/
dbg_io_ops->is_console = true;
return 0;
}
static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
{
int i;
if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0)
return;
for (i = 0; i < c; i++)
dbg_io_ops->write_char(s[i]);
}
@@ -65,6 +74,7 @@ static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
static struct console kgdb_nmi_console = {
.name = "ttyNMI",
.setup = kgdb_nmi_console_setup,
.write = kgdb_nmi_console_write,
.device = kgdb_nmi_console_device,
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
@@ -80,29 +90,10 @@ static struct console kgdb_nmi_console = {
struct kgdb_nmi_tty_priv {
struct tty_port port;
struct tasklet_struct tlet;
struct timer_list timer;
STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
};
static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port)
{
return container_of(port, struct kgdb_nmi_tty_priv, port);
}
/*
* Our debugging console is polled in a tasklet, so we'll check for input
* every tick. In HZ-less mode, we should program the next tick. We have
* to use the lowlevel stuff as no locks should be grabbed.
*/
#ifdef CONFIG_HIGH_RES_TIMERS
static void kgdb_tty_poke(void)
{
tick_program_event(ktime_get(), 0);
}
#else
static inline void kgdb_tty_poke(void) {}
#endif
static struct tty_port *kgdb_nmi_port;
static void kgdb_tty_recv(int ch)
@@ -113,14 +104,13 @@ static void kgdb_tty_recv(int ch)
if (!kgdb_nmi_port || ch < 0)
return;
/*
* Can't use port->tty->driver_data as tty might be not there. Tasklet
* Can't use port->tty->driver_data as tty might be not there. Timer
* will check for tty and will get the ref, but here we don't have to
* do that, and actually, we can't: we're in NMI context, no locks are
* possible.
*/
priv = kgdb_nmi_port_to_priv(kgdb_nmi_port);
priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
kfifo_in(&priv->fifo, &c, 1);
kgdb_tty_poke();
}
static int kgdb_nmi_poll_one_knock(void)
@@ -204,7 +194,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
struct kgdb_nmi_tty_priv *priv = (void *)data;
char ch;
tasklet_schedule(&priv->tlet);
priv->timer.expires = jiffies + (HZ/100);
add_timer(&priv->timer);
if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
return;
@@ -216,18 +207,22 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
{
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
struct kgdb_nmi_tty_priv *priv =
container_of(port, struct kgdb_nmi_tty_priv, port);
kgdb_nmi_port = port;
tasklet_schedule(&priv->tlet);
priv->timer.expires = jiffies + (HZ/100);
add_timer(&priv->timer);
return 0;
}
static void kgdb_nmi_tty_shutdown(struct tty_port *port)
{
struct kgdb_nmi_tty_priv *priv = port->tty->driver_data;
struct kgdb_nmi_tty_priv *priv =
container_of(port, struct kgdb_nmi_tty_priv, port);
tasklet_kill(&priv->tlet);
del_timer(&priv->timer);
kgdb_nmi_port = NULL;
}
@@ -246,7 +241,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
return -ENOMEM;
INIT_KFIFO(priv->fifo);
tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv);
setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv);
tty_port_init(&priv->port);
priv->port.ops = &kgdb_nmi_tty_port_ops;
tty->driver_data = priv;

View File

@@ -0,0 +1,867 @@
/*
* MEN 16z135 High Speed UART
*
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
*
* 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; version 2 of the License.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/tty_flip.h>
#include <linux/bitops.h>
#include <linux/mcb.h>
#define MEN_Z135_MAX_PORTS 12
#define MEN_Z135_BASECLK 29491200
#define MEN_Z135_FIFO_SIZE 1024
#define MEN_Z135_NUM_MSI_VECTORS 2
#define MEN_Z135_FIFO_WATERMARK 1020
#define MEN_Z135_STAT_REG 0x0
#define MEN_Z135_RX_RAM 0x4
#define MEN_Z135_TX_RAM 0x400
#define MEN_Z135_RX_CTRL 0x800
#define MEN_Z135_TX_CTRL 0x804
#define MEN_Z135_CONF_REG 0x808
#define MEN_Z135_UART_FREQ 0x80c
#define MEN_Z135_BAUD_REG 0x810
#define MENZ135_TIMEOUT 0x814
#define MEN_Z135_MEM_SIZE 0x818
#define IS_IRQ(x) ((x) & 1)
#define IRQ_ID(x) (((x) >> 1) & 7)
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */
#define MEN_Z135_IER_RLSIEN BIT(2) /* Receiver Line Status IRQ */
#define MEN_Z135_IER_MSIEN BIT(3) /* Modem Status IRQ */
#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN \
| MEN_Z135_IER_RLSIEN \
| MEN_Z135_IER_MSIEN \
| MEN_Z135_IER_TXCIEN)
#define MEN_Z135_MCR_DTR BIT(24)
#define MEN_Z135_MCR_RTS BIT(25)
#define MEN_Z135_MCR_OUT1 BIT(26)
#define MEN_Z135_MCR_OUT2 BIT(27)
#define MEN_Z135_MCR_LOOP BIT(28)
#define MEN_Z135_MCR_RCFC BIT(29)
#define MEN_Z135_MSR_DCTS BIT(0)
#define MEN_Z135_MSR_DDSR BIT(1)
#define MEN_Z135_MSR_DRI BIT(2)
#define MEN_Z135_MSR_DDCD BIT(3)
#define MEN_Z135_MSR_CTS BIT(4)
#define MEN_Z135_MSR_DSR BIT(5)
#define MEN_Z135_MSR_RI BIT(6)
#define MEN_Z135_MSR_DCD BIT(7)
#define MEN_Z135_LCR_SHIFT 8 /* LCR shift mask */
#define MEN_Z135_WL5 0 /* CS5 */
#define MEN_Z135_WL6 1 /* CS6 */
#define MEN_Z135_WL7 2 /* CS7 */
#define MEN_Z135_WL8 3 /* CS8 */
#define MEN_Z135_STB_SHIFT 2 /* Stopbits */
#define MEN_Z135_NSTB1 0
#define MEN_Z135_NSTB2 1
#define MEN_Z135_PEN_SHIFT 3 /* Parity enable */
#define MEN_Z135_PAR_DIS 0
#define MEN_Z135_PAR_ENA 1
#define MEN_Z135_PTY_SHIFT 4 /* Parity type */
#define MEN_Z135_PTY_ODD 0
#define MEN_Z135_PTY_EVN 1
#define MEN_Z135_LSR_DR BIT(0)
#define MEN_Z135_LSR_OE BIT(1)
#define MEN_Z135_LSR_PE BIT(2)
#define MEN_Z135_LSR_FE BIT(3)
#define MEN_Z135_LSR_BI BIT(4)
#define MEN_Z135_LSR_THEP BIT(5)
#define MEN_Z135_LSR_TEXP BIT(6)
#define MEN_Z135_LSR_RXFIFOERR BIT(7)
#define MEN_Z135_IRQ_ID_MST 0
#define MEN_Z135_IRQ_ID_TSA 1
#define MEN_Z135_IRQ_ID_RDA 2
#define MEN_Z135_IRQ_ID_RLS 3
#define MEN_Z135_IRQ_ID_CTI 6
#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
#define BYTES_TO_ALIGN(x) ((x) & 0x3)
static int line;
static int txlvl = 5;
module_param(txlvl, int, S_IRUGO);
MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)");
static int rxlvl = 6;
module_param(rxlvl, int, S_IRUGO);
MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)");
static int align;
module_param(align, int, S_IRUGO);
MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
struct men_z135_port {
struct uart_port port;
struct mcb_device *mdev;
unsigned char *rxbuf;
u32 stat_reg;
spinlock_t lock;
};
#define to_men_z135(port) container_of((port), struct men_z135_port, port)
/**
* men_z135_reg_set() - Set value in register
* @uart: The UART port
* @addr: Register address
* @val: value to set
*/
static inline void men_z135_reg_set(struct men_z135_port *uart,
u32 addr, u32 val)
{
struct uart_port *port = &uart->port;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&uart->lock, flags);
reg = ioread32(port->membase + addr);
reg |= val;
iowrite32(reg, port->membase + addr);
spin_unlock_irqrestore(&uart->lock, flags);
}
/**
* men_z135_reg_clr() - Unset value in register
* @uart: The UART port
* @addr: Register address
* @val: value to clear
*/
static inline void men_z135_reg_clr(struct men_z135_port *uart,
u32 addr, u32 val)
{
struct uart_port *port = &uart->port;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&uart->lock, flags);
reg = ioread32(port->membase + addr);
reg &= ~val;
iowrite32(reg, port->membase + addr);
spin_unlock_irqrestore(&uart->lock, flags);
}
/**
* men_z135_handle_modem_status() - Handle change of modem status
* @port: The UART port
*
* Handle change of modem status register. This is done by reading the "delta"
* versions of DCD (Data Carrier Detect) and CTS (Clear To Send).
*/
static void men_z135_handle_modem_status(struct men_z135_port *uart)
{
if (uart->stat_reg & MEN_Z135_MSR_DDCD)
uart_handle_dcd_change(&uart->port,
uart->stat_reg & ~MEN_Z135_MSR_DCD);
if (uart->stat_reg & MEN_Z135_MSR_DCTS)
uart_handle_cts_change(&uart->port,
uart->stat_reg & ~MEN_Z135_MSR_CTS);
}
static void men_z135_handle_lsr(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
u8 lsr;
lsr = (uart->stat_reg >> 16) & 0xff;
if (lsr & MEN_Z135_LSR_OE)
port->icount.overrun++;
if (lsr & MEN_Z135_LSR_PE)
port->icount.parity++;
if (lsr & MEN_Z135_LSR_FE)
port->icount.frame++;
if (lsr & MEN_Z135_LSR_BI) {
port->icount.brk++;
uart_handle_break(port);
}
}
/**
* get_rx_fifo_content() - Get the number of bytes in RX FIFO
* @uart: The UART port
*
* Read RXC register from hardware and return current FIFO fill size.
*/
static u16 get_rx_fifo_content(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
u32 stat_reg;
u16 rxc;
u8 rxc_lo;
u8 rxc_hi;
stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
rxc_lo = stat_reg >> 24;
rxc_hi = (stat_reg & 0xC0) >> 6;
rxc = rxc_lo | (rxc_hi << 8);
return rxc;
}
/**
* men_z135_handle_rx() - RX tasklet routine
* @arg: Pointer to struct men_z135_port
*
* Copy from RX FIFO and acknowledge number of bytes copied.
*/
static void men_z135_handle_rx(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
struct tty_port *tport = &port->state->port;
int copied;
u16 size;
int room;
size = get_rx_fifo_content(uart);
if (size == 0)
return;
/* Avoid accidently accessing TX FIFO instead of RX FIFO. Last
* longword in RX FIFO cannot be read.(0x004-0x3FF)
*/
if (size > MEN_Z135_FIFO_WATERMARK)
size = MEN_Z135_FIFO_WATERMARK;
room = tty_buffer_request_room(tport, size);
if (room != size)
dev_warn(&uart->mdev->dev,
"Not enough room in flip buffer, truncating to %d\n",
room);
if (room == 0)
return;
memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room);
/* Be sure to first copy all data and then acknowledge it */
mb();
iowrite32(room, port->membase + MEN_Z135_RX_CTRL);
copied = tty_insert_flip_string(tport, uart->rxbuf, room);
if (copied != room)
dev_warn(&uart->mdev->dev,
"Only copied %d instead of %d bytes\n",
copied, room);
port->icount.rx += copied;
tty_flip_buffer_push(tport);
}
/**
* men_z135_handle_tx() - TX tasklet routine
* @arg: Pointer to struct men_z135_port
*
*/
static void men_z135_handle_tx(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
struct circ_buf *xmit = &port->state->xmit;
u32 txc;
u32 wptr;
int qlen;
int n;
int txfree;
int head;
int tail;
int s;
if (uart_circ_empty(xmit))
goto out;
if (uart_tx_stopped(port))
goto out;
if (port->x_char)
goto out;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
/* calculate bytes to copy */
qlen = uart_circ_chars_pending(xmit);
if (qlen <= 0)
goto out;
wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
txc = (wptr >> 16) & 0x3ff;
wptr &= 0x3ff;
if (txc > MEN_Z135_FIFO_WATERMARK)
txc = MEN_Z135_FIFO_WATERMARK;
txfree = MEN_Z135_FIFO_WATERMARK - txc;
if (txfree <= 0) {
pr_err("Not enough room in TX FIFO have %d, need %d\n",
txfree, qlen);
goto irq_en;
}
/* if we're not aligned, it's better to copy only 1 or 2 bytes and
* then the rest.
*/
if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr))
n = 4 - BYTES_TO_ALIGN(wptr);
else if (qlen > txfree)
n = txfree;
else
n = qlen;
if (n <= 0)
goto irq_en;
head = xmit->head & (UART_XMIT_SIZE - 1);
tail = xmit->tail & (UART_XMIT_SIZE - 1);
s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
n = min(n, s);
memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1);
mmiowb();
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
port->icount.tx += n;
irq_en:
if (!uart_circ_empty(xmit))
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
else
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
out:
return;
}
/**
* men_z135_intr() - Handle legacy IRQs
* @irq: The IRQ number
* @data: Pointer to UART port
*
* Check IIR register to see which tasklet to start.
*/
static irqreturn_t men_z135_intr(int irq, void *data)
{
struct men_z135_port *uart = (struct men_z135_port *)data;
struct uart_port *port = &uart->port;
int irq_id;
uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
/* IRQ pending is low active */
if (IS_IRQ(uart->stat_reg))
return IRQ_NONE;
irq_id = IRQ_ID(uart->stat_reg);
switch (irq_id) {
case MEN_Z135_IRQ_ID_MST:
men_z135_handle_modem_status(uart);
break;
case MEN_Z135_IRQ_ID_TSA:
men_z135_handle_tx(uart);
break;
case MEN_Z135_IRQ_ID_CTI:
dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
/* Fallthrough */
case MEN_Z135_IRQ_ID_RDA:
/* Reading data clears RX IRQ */
men_z135_handle_rx(uart);
break;
case MEN_Z135_IRQ_ID_RLS:
men_z135_handle_lsr(uart);
break;
default:
dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
/**
* men_z135_request_irq() - Request IRQ for 16z135 core
* @uart: z135 private uart port structure
*
* Request an IRQ for 16z135 to use. First try using MSI, if it fails
* fall back to using legacy interrupts.
*/
static int men_z135_request_irq(struct men_z135_port *uart)
{
struct device *dev = &uart->mdev->dev;
struct uart_port *port = &uart->port;
int err = 0;
err = request_irq(port->irq, men_z135_intr, IRQF_SHARED,
"men_z135_intr", uart);
if (err)
dev_err(dev, "Error %d getting interrupt\n", err);
return err;
}
/**
* men_z135_tx_empty() - Handle tx_empty call
* @port: The UART port
*
* This function tests whether the TX FIFO and shifter for the port
* described by @port is empty.
*/
static unsigned int men_z135_tx_empty(struct uart_port *port)
{
u32 wptr;
u16 txc;
wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
txc = (wptr >> 16) & 0x3ff;
if (txc == 0)
return TIOCSER_TEMT;
else
return 0;
}
/**
* men_z135_set_mctrl() - Set modem control lines
* @port: The UART port
* @mctrl: The modem control lines
*
* This function sets the modem control lines for a port described by @port
* to the state described by @mctrl
*/
static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct men_z135_port *uart = to_men_z135(port);
u32 conf_reg = 0;
if (mctrl & TIOCM_RTS)
conf_reg |= MEN_Z135_MCR_RTS;
if (mctrl & TIOCM_DTR)
conf_reg |= MEN_Z135_MCR_DTR;
if (mctrl & TIOCM_OUT1)
conf_reg |= MEN_Z135_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
conf_reg |= MEN_Z135_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
conf_reg |= MEN_Z135_MCR_LOOP;
men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
}
/**
* men_z135_get_mctrl() - Get modem control lines
* @port: The UART port
*
* Retruns the current state of modem control inputs.
*/
static unsigned int men_z135_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = 0;
u32 stat_reg;
u8 msr;
stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
msr = ~((stat_reg >> 8) & 0xff);
if (msr & MEN_Z135_MSR_CTS)
mctrl |= TIOCM_CTS;
if (msr & MEN_Z135_MSR_DSR)
mctrl |= TIOCM_DSR;
if (msr & MEN_Z135_MSR_RI)
mctrl |= TIOCM_RI;
if (msr & MEN_Z135_MSR_DCD)
mctrl |= TIOCM_CAR;
return mctrl;
}
/**
* men_z135_stop_tx() - Stop transmitting characters
* @port: The UART port
*
* Stop transmitting characters. This might be due to CTS line becomming
* inactive or the tty layer indicating we want to stop transmission due to
* an XOFF character.
*/
static void men_z135_stop_tx(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
}
/**
* men_z135_start_tx() - Start transmitting characters
* @port: The UART port
*
* Start transmitting character. This actually doesn't transmit anything, but
* fires off the TX tasklet.
*/
static void men_z135_start_tx(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_handle_tx(uart);
}
/**
* men_z135_stop_rx() - Stop receiving characters
* @port: The UART port
*
* Stop receiving characters; the port is in the process of being closed.
*/
static void men_z135_stop_rx(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_RXCIEN);
}
/**
* men_z135_enable_ms() - Enable Modem Status
* port:
*
* Enable Modem Status IRQ.
*/
static void men_z135_enable_ms(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
}
static int men_z135_startup(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
int err;
u32 conf_reg = 0;
err = men_z135_request_irq(uart);
if (err)
return -ENODEV;
conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
/* Activate all but TX space available IRQ */
conf_reg |= MEN_Z135_ALL_IRQS & ~MEN_Z135_IER_TXCIEN;
conf_reg &= ~(0xff << 16);
conf_reg |= (txlvl << 16);
conf_reg |= (rxlvl << 20);
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
return 0;
}
static void men_z135_shutdown(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
u32 conf_reg = 0;
conf_reg |= MEN_Z135_ALL_IRQS;
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg);
free_irq(uart->port.irq, uart);
}
static void men_z135_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud;
u32 conf_reg;
u32 bd_reg;
u32 uart_freq;
u8 lcr;
conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
lcr = LCR(conf_reg);
/* byte size */
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr |= MEN_Z135_WL5;
break;
case CS6:
lcr |= MEN_Z135_WL6;
break;
case CS7:
lcr |= MEN_Z135_WL7;
break;
case CS8:
lcr |= MEN_Z135_WL8;
break;
}
/* stop bits */
if (termios->c_cflag & CSTOPB)
lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT;
/* parity */
if (termios->c_cflag & PARENB) {
lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT;
if (termios->c_cflag & PARODD)
lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT;
else
lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT;
} else
lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
conf_reg |= lcr << MEN_Z135_LCR_SHIFT;
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ);
if (uart_freq == 0)
uart_freq = MEN_Z135_BASECLK;
baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16);
spin_lock(&port->lock);
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
bd_reg = uart_freq / (4 * baud);
iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG);
uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock(&port->lock);
}
static const char *men_z135_type(struct uart_port *port)
{
return KBUILD_MODNAME;
}
static void men_z135_release_port(struct uart_port *port)
{
iounmap(port->membase);
port->membase = NULL;
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
}
static int men_z135_request_port(struct uart_port *port)
{
int size = MEN_Z135_MEM_SIZE;
if (!request_mem_region(port->mapbase, size, "men_z135_port"))
return -EBUSY;
port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE);
if (port->membase == NULL) {
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
return -ENOMEM;
}
return 0;
}
static void men_z135_config_port(struct uart_port *port, int type)
{
port->type = PORT_MEN_Z135;
men_z135_request_port(port);
}
static int men_z135_verify_port(struct uart_port *port,
struct serial_struct *serinfo)
{
return -EINVAL;
}
static struct uart_ops men_z135_ops = {
.tx_empty = men_z135_tx_empty,
.set_mctrl = men_z135_set_mctrl,
.get_mctrl = men_z135_get_mctrl,
.stop_tx = men_z135_stop_tx,
.start_tx = men_z135_start_tx,
.stop_rx = men_z135_stop_rx,
.enable_ms = men_z135_enable_ms,
.startup = men_z135_startup,
.shutdown = men_z135_shutdown,
.set_termios = men_z135_set_termios,
.type = men_z135_type,
.release_port = men_z135_release_port,
.request_port = men_z135_request_port,
.config_port = men_z135_config_port,
.verify_port = men_z135_verify_port,
};
static struct uart_driver men_z135_driver = {
.owner = THIS_MODULE,
.driver_name = KBUILD_MODNAME,
.dev_name = "ttyHSU",
.major = 0,
.minor = 0,
.nr = MEN_Z135_MAX_PORTS,
};
/**
* men_z135_probe() - Probe a z135 instance
* @mdev: The MCB device
* @id: The MCB device ID
*
* men_z135_probe does the basic setup of hardware resources and registers the
* new uart port to the tty layer.
*/
static int men_z135_probe(struct mcb_device *mdev,
const struct mcb_device_id *id)
{
struct men_z135_port *uart;
struct resource *mem;
struct device *dev;
int err;
dev = &mdev->dev;
uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL);
if (!uart)
return -ENOMEM;
uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!uart->rxbuf)
return -ENOMEM;
mem = &mdev->mem;
mcb_set_drvdata(mdev, uart);
uart->port.uartclk = MEN_Z135_BASECLK * 16;
uart->port.fifosize = MEN_Z135_FIFO_SIZE;
uart->port.iotype = UPIO_MEM;
uart->port.ops = &men_z135_ops;
uart->port.irq = mcb_get_irq(mdev);
uart->port.iotype = UPIO_MEM;
uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
uart->port.line = line++;
uart->port.dev = dev;
uart->port.type = PORT_MEN_Z135;
uart->port.mapbase = mem->start;
uart->port.membase = NULL;
uart->mdev = mdev;
spin_lock_init(&uart->port.lock);
spin_lock_init(&uart->lock);
err = uart_add_one_port(&men_z135_driver, &uart->port);
if (err)
goto err;
return 0;
err:
free_page((unsigned long) uart->rxbuf);
dev_err(dev, "Failed to add UART: %d\n", err);
return err;
}
/**
* men_z135_remove() - Remove a z135 instance from the system
*
* @mdev: The MCB device
*/
static void men_z135_remove(struct mcb_device *mdev)
{
struct men_z135_port *uart = mcb_get_drvdata(mdev);
line--;
uart_remove_one_port(&men_z135_driver, &uart->port);
free_page((unsigned long) uart->rxbuf);
}
static const struct mcb_device_id men_z135_ids[] = {
{ .device = 0x87 },
};
MODULE_DEVICE_TABLE(mcb, men_z135_ids);
static struct mcb_driver mcb_driver = {
.driver = {
.name = "z135-uart",
.owner = THIS_MODULE,
},
.probe = men_z135_probe,
.remove = men_z135_remove,
.id_table = men_z135_ids,
};
/**
* men_z135_init() - Driver Registration Routine
*
* men_z135_init is the first routine called when the driver is loaded. All it
* does is register with the legacy MEN Chameleon subsystem.
*/
static int __init men_z135_init(void)
{
int err;
err = uart_register_driver(&men_z135_driver);
if (err) {
pr_err("Failed to register UART: %d\n", err);
return err;
}
err = mcb_register_driver(&mcb_driver);
if (err) {
pr_err("Failed to register MCB driver: %d\n", err);
uart_unregister_driver(&men_z135_driver);
return err;
}
return 0;
}
module_init(men_z135_init);
/**
* men_z135_exit() - Driver Exit Routine
*
* men_z135_exit is called just before the driver is removed from memory.
*/
static void __exit men_z135_exit(void)
{
mcb_unregister_driver(&mcb_driver);
uart_unregister_driver(&men_z135_driver);
}
module_exit(men_z135_exit);
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
MODULE_ALIAS("mcb:16z135");

View File

@@ -52,7 +52,6 @@ struct msm_port {
struct clk *clk;
struct clk *pclk;
unsigned int imr;
void __iomem *gsbi_base;
int is_uartdm;
unsigned int old_snap_state;
};
@@ -599,9 +598,7 @@ static const char *msm_type(struct uart_port *port)
static void msm_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
struct msm_port *msm_port = UART_TO_MSM(port);
struct resource *uart_resource;
struct resource *gsbi_resource;
resource_size_t size;
uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -612,28 +609,12 @@ static void msm_release_port(struct uart_port *port)
release_mem_region(port->mapbase, size);
iounmap(port->membase);
port->membase = NULL;
if (msm_port->gsbi_base) {
writel_relaxed(GSBI_PROTOCOL_IDLE,
msm_port->gsbi_base + GSBI_CONTROL);
gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (unlikely(!gsbi_resource))
return;
size = resource_size(gsbi_resource);
release_mem_region(gsbi_resource->start, size);
iounmap(msm_port->gsbi_base);
msm_port->gsbi_base = NULL;
}
}
static int msm_request_port(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
struct platform_device *pdev = to_platform_device(port->dev);
struct resource *uart_resource;
struct resource *gsbi_resource;
resource_size_t size;
int ret;
@@ -652,30 +633,8 @@ static int msm_request_port(struct uart_port *port)
goto fail_release_port;
}
gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
/* Is this a GSBI-based port? */
if (gsbi_resource) {
size = resource_size(gsbi_resource);
if (!request_mem_region(gsbi_resource->start, size,
"msm_serial")) {
ret = -EBUSY;
goto fail_release_port_membase;
}
msm_port->gsbi_base = ioremap(gsbi_resource->start, size);
if (!msm_port->gsbi_base) {
ret = -EBUSY;
goto fail_release_gsbi;
}
}
return 0;
fail_release_gsbi:
release_mem_region(gsbi_resource->start, size);
fail_release_port_membase:
iounmap(port->membase);
fail_release_port:
release_mem_region(port->mapbase, size);
return ret;
@@ -683,7 +642,6 @@ fail_release_port:
static void msm_config_port(struct uart_port *port, int flags)
{
struct msm_port *msm_port = UART_TO_MSM(port);
int ret;
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_MSM;
@@ -691,9 +649,6 @@ static void msm_config_port(struct uart_port *port, int flags)
if (ret)
return;
}
if (msm_port->gsbi_base)
writel_relaxed(GSBI_PROTOCOL_UART,
msm_port->gsbi_base + GSBI_CONTROL);
}
static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -1110,6 +1065,7 @@ static struct of_device_id msm_match_table[] = {
static struct platform_driver msm_platform_driver = {
.remove = msm_serial_remove,
.probe = msm_serial_probe,
.driver = {
.name = "msm_serial",
.owner = THIS_MODULE,
@@ -1125,7 +1081,7 @@ static int __init msm_serial_init(void)
if (unlikely(ret))
return ret;
ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
ret = platform_driver_register(&msm_platform_driver);
if (unlikely(ret))
uart_unregister_driver(&msm_uart_driver);

View File

@@ -109,11 +109,6 @@
#define UART_ISR 0x0014
#define UART_ISR_TX_READY (1 << 7)
#define GSBI_CONTROL 0x0
#define GSBI_PROTOCOL_CODE 0x30
#define GSBI_PROTOCOL_UART 0x40
#define GSBI_PROTOCOL_IDLE 0x0
#define UARTDM_RXFS 0x50
#define UARTDM_RXFS_BUF_SHIFT 0x7
#define UARTDM_RXFS_BUF_MASK 0x7

View File

@@ -29,7 +29,7 @@
#include <asm/irq.h>
#include <asm/parisc-device.h>
#ifdef CONFIG_MAGIC_SYSRQ
#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#include <linux/sysrq.h>
#define SUPPORT_SYSRQ
#endif
@@ -613,7 +613,7 @@ static void __exit mux_exit(void)
{
/* Delete the Mux timer. */
if(port_cnt > 0) {
del_timer(&mux_timer);
del_timer_sync(&mux_timer);
#ifdef CONFIG_SERIAL_MUX_CONSOLE
unregister_console(&mux_console);
#endif

View File

@@ -200,7 +200,7 @@ static void dma_tx_callback(void *param)
/* clear the bit used to serialize the DMA tx. */
clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
smp_mb__after_clear_bit();
smp_mb__after_atomic();
/* wake up the possible processes. */
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -275,7 +275,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
mxs_auart_dma_tx(s, i);
} else {
clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
smp_mb__after_clear_bit();
smp_mb__after_atomic();
}
return;
}

View File

@@ -173,6 +173,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
{
struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250));
port.type = port_type;
port8250.port = port;
if (port.fifosize)
@@ -182,6 +183,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
"auto-flow-control"))
port8250.capabilities |= UART_CAP_AFE;
if (of_property_read_bool(ofdev->dev.of_node,
"has-hw-flow-control"))
port8250.port.flags |= UPF_HARD_FLOW;
ret = serial8250_register_8250_port(&port8250);
break;
}

View File

@@ -163,10 +163,6 @@ struct uart_omap_port {
u8 wakeups_enabled;
u32 features;
int DTR_gpio;
int DTR_inverted;
int DTR_active;
struct serial_rs485 rs485;
int rts_gpio;
@@ -184,8 +180,6 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
static struct workqueue_struct *serial_omap_uart_wq;
static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
{
offset <<= up->port.regshift;
@@ -398,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
spin_unlock(&up->port.lock);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
spin_lock(&up->port.lock);
}
if (uart_circ_empty(xmit))
serial_omap_stop_tx(&up->port);
@@ -697,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial_out(up, UART_MCR, up->mcr);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
if (gpio_is_valid(up->DTR_gpio) &&
!!(mctrl & TIOCM_DTR) != up->DTR_active) {
up->DTR_active = !up->DTR_active;
if (gpio_cansleep(up->DTR_gpio))
schedule_work(&up->qos_work);
else
gpio_set_value(up->DTR_gpio,
up->DTR_active != up->DTR_inverted);
}
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -850,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
qos_work);
pm_qos_update_request(&up->pm_qos_request, up->latency);
if (gpio_is_valid(up->DTR_gpio))
gpio_set_value_cansleep(up->DTR_gpio,
up->DTR_active != up->DTR_inverted);
}
static void
@@ -1420,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
switch (cmd) {
case TIOCSRS485:
if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
if (copy_from_user(&rs485conf, (void __user *) arg,
sizeof(rs485conf)))
return -EFAULT;
@@ -1428,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
break;
case TIOCGRS485:
if (copy_to_user((struct serial_rs485 *) arg,
if (copy_to_user((void __user *) arg,
&(to_uart_omap_port(port)->rs485),
sizeof(rs485conf)))
return -EFAULT;
@@ -1614,7 +1592,7 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
/* check for tx enable gpio */
up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
if (gpio_is_valid(up->rts_gpio)) {
ret = gpio_request(up->rts_gpio, "omap-serial");
ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial");
if (ret < 0)
return ret;
ret = gpio_direction_output(up->rts_gpio,
@@ -1644,10 +1622,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
static int serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
struct resource *mem, *irq;
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
int ret, uartirq = 0, wakeirq = 0;
struct uart_omap_port *up;
struct resource *mem;
void __iomem *base;
int uartirq = 0;
int wakeirq = 0;
int ret;
/* The optional wakeirq may be specified in the board dts file */
if (pdev->dev.of_node) {
@@ -1658,48 +1639,19 @@ static int serial_omap_probe(struct platform_device *pdev)
omap_up_info = of_get_uart_port_info(&pdev->dev);
pdev->dev.platform_data = omap_up_info;
} else {
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "no irq resource?\n");
return -ENODEV;
}
uartirq = irq->start;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n");
return -ENODEV;
}
if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
pdev->dev.driver->name)) {
dev_err(&pdev->dev, "memory region already claimed\n");
return -EBUSY;
}
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
omap_up_info->DTR_present) {
ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
if (ret < 0)
return ret;
ret = gpio_direction_output(omap_up_info->DTR_gpio,
omap_up_info->DTR_inverted);
if (ret < 0)
return ret;
uartirq = platform_get_irq(pdev, 0);
if (uartirq < 0)
return -EPROBE_DEFER;
}
up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
omap_up_info->DTR_present) {
up->DTR_gpio = omap_up_info->DTR_gpio;
up->DTR_inverted = omap_up_info->DTR_inverted;
} else
up->DTR_gpio = -EINVAL;
up->DTR_active = 0;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(base))
return PTR_ERR(base);
up->dev = &pdev->dev;
up->port.dev = &pdev->dev;
@@ -1733,14 +1685,7 @@ static int serial_omap_probe(struct platform_device *pdev)
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
up->port.membase = devm_ioremap(&pdev->dev, mem->start,
resource_size(mem));
if (!up->port.membase) {
dev_err(&pdev->dev, "can't ioremap UART\n");
ret = -ENOMEM;
goto err_ioremap;
}
up->port.membase = base;
up->port.flags = omap_up_info->flags;
up->port.uartclk = omap_up_info->uartclk;
if (!up->port.uartclk) {
@@ -1754,12 +1699,12 @@ static int serial_omap_probe(struct platform_device *pdev)
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
pm_qos_add_request(&up->pm_qos_request,
PM_QOS_CPU_DMA_LATENCY, up->latency);
serial_omap_uart_wq = create_singlethread_workqueue(up->name);
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
platform_set_drvdata(pdev, up);
if (omap_up_info->autosuspend_timeout == 0)
omap_up_info->autosuspend_timeout = -1;
device_init_wakeup(up->dev, true);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
@@ -1786,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev)
err_add_port:
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
err_ioremap:
err_rs485:
err_port_line:
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",

View File

@@ -257,6 +257,8 @@ struct eg20t_port {
dma_addr_t rx_buf_dma;
struct dentry *debugfs;
#define IRQ_NAME_SIZE 17
char irq_name[IRQ_NAME_SIZE];
/* protect the eg20t_port private structure and io access to membase */
spinlock_t lock;
@@ -1343,7 +1345,7 @@ static int pch_uart_startup(struct uart_port *port)
return ret;
ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
KBUILD_MODNAME, priv);
priv->irq_name, priv);
if (ret < 0)
return ret;
@@ -1588,13 +1590,8 @@ static void pch_uart_put_poll_char(struct uart_port *port,
wait_for_xmitr(priv, UART_LSR_THRE);
/*
* Send the character out.
* If a LF, also do CR...
*/
iowrite8(c, priv->membase + PCH_UART_THR);
if (c == 10) {
wait_for_xmitr(priv, UART_LSR_THRE);
iowrite8(13, priv->membase + PCH_UART_THR);
}
/*
* Finally, wait for transmitter to become empty
@@ -1818,6 +1815,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->port.line = board->line_no;
priv->trigger = PCH_UART_HAL_TRIGGER_M;
snprintf(priv->irq_name, IRQ_NAME_SIZE,
KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d",
priv->port.line);
spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv);

View File

@@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port,
wait_for_xmitr(up);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_out(up, UART_TX, c);
if (c == 10) {
wait_for_xmitr(up);
serial_out(up, UART_TX, 13);
}
/*
* Finally, wait for transmitter to become empty

View File

@@ -53,6 +53,29 @@
#include "samsung.h"
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
defined(CONFIG_DEBUG_LL) && \
!defined(MODULE)
extern void printascii(const char *);
__printf(1, 2)
static void dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vscnprintf(buff, sizeof(buf), fmt, va);
va_end(va);
printascii(buff);
}
#else
#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0)
#endif
/* UART name and device definitions */
#define S3C24XX_SERIAL_NAME "ttySAC"
@@ -468,8 +491,8 @@ static int s3c24xx_serial_startup(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n",
port, (unsigned long long)port->mapbase, port->membase);
rx_enabled(port) = 1;
@@ -514,8 +537,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
port, (unsigned long long)port->mapbase, port->membase);
wr_regl(port, S3C64XX_UINTM, 0xf);
@@ -1160,7 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
return -EINVAL;
}
dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
dbg("resource %pR)\n", res);
port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
if (!port->membase) {
@@ -1203,7 +1226,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
wr_regl(port, S3C64XX_UINTSP, 0xf);
}
dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
dbg("port: map=%08x, mem=%p, irq=%d (%d,%d), clock=%u\n",
port->mapbase, port->membase, port->irq,
ourport->rx_irq, ourport->tx_irq, port->uartclk);

View File

@@ -1,3 +1,6 @@
#ifndef __SAMSUNG_H
#define __SAMSUNG_H
/*
* Driver for Samsung SoC onboard UARTs.
*
@@ -77,24 +80,4 @@ struct s3c24xx_uart_port {
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
defined(CONFIG_DEBUG_LL) && \
!defined(MODULE)
extern void printascii(const char *);
static void dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vsprintf(buff, fmt, va);
va_end(va);
printascii(buff);
}
#else
#define dbg(x...) do { } while (0)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -474,9 +474,7 @@ static void sccnxp_timer(unsigned long data)
sccnxp_handle_events(s);
spin_unlock_irqrestore(&s->lock, flags);
if (!timer_pending(&s->timer))
mod_timer(&s->timer, jiffies +
usecs_to_jiffies(s->pdata.poll_time_us));
mod_timer(&s->timer, jiffies + usecs_to_jiffies(s->pdata.poll_time_us));
}
static irqreturn_t sccnxp_ist(int irq, void *dev_id)
@@ -674,6 +672,8 @@ static void sccnxp_set_termios(struct uart_port *port,
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNBRK)
port->ignore_status_mask |= SR_BRK;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= SR_PE;
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK;

View File

@@ -174,8 +174,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
if (tty_port_cts_enabled(port)) {
/*
* if hw support flow control without software intervention,
* then skip the below check
*/
if (tty_port_cts_enabled(port) &&
!(uport->flags & UPF_HARD_FLOW)) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -2239,6 +2243,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
return;
port = state->uart_port;
if (ch == '\n')
port->ops->poll_put_char(port, '\r');
port->ops->poll_put_char(port, ch);
}
#endif
@@ -2772,7 +2779,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
if (tty_port_cts_enabled(port)) {
/* skip below code if the hw flow control is supported */
if (tty_port_cts_enabled(port) &&
!(uport->flags & UPF_HARD_FLOW)) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;

View File

@@ -0,0 +1,143 @@
/*
* Helpers for controlling modem lines via GPIO
*
* Copyright (C) 2014 Paratronic S.A.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/err.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <uapi/asm-generic/termios.h>
#include "serial_mctrl_gpio.h"
struct mctrl_gpios {
struct gpio_desc *gpio[UART_GPIO_MAX];
};
static const struct {
const char *name;
unsigned int mctrl;
bool dir_out;
} mctrl_gpios_desc[UART_GPIO_MAX] = {
{ "cts", TIOCM_CTS, false, },
{ "dsr", TIOCM_DSR, false, },
{ "dcd", TIOCM_CD, false, },
{ "rng", TIOCM_RNG, false, },
{ "rts", TIOCM_RTS, true, },
{ "dtr", TIOCM_DTR, true, },
{ "out1", TIOCM_OUT1, true, },
{ "out2", TIOCM_OUT2, true, },
};
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{
enum mctrl_gpio_idx i;
if (IS_ERR_OR_NULL(gpios))
return;
for (i = 0; i < UART_GPIO_MAX; i++)
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
mctrl_gpios_desc[i].dir_out)
gpiod_set_value(gpios->gpio[i],
!!(mctrl & mctrl_gpios_desc[i].mctrl));
}
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx)
{
if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
return gpios->gpio[gidx];
else
return NULL;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
enum mctrl_gpio_idx i;
/*
* return it unchanged if the structure is not allocated
*/
if (IS_ERR_OR_NULL(gpios))
return *mctrl;
for (i = 0; i < UART_GPIO_MAX; i++) {
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
!mctrl_gpios_desc[i].dir_out) {
if (gpiod_get_value(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
}
}
return *mctrl;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_get);
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
{
struct mctrl_gpios *gpios;
enum mctrl_gpio_idx i;
int err;
gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
if (!gpios)
return ERR_PTR(-ENOMEM);
for (i = 0; i < UART_GPIO_MAX; i++) {
gpios->gpio[i] = devm_gpiod_get_index(dev,
mctrl_gpios_desc[i].name,
idx);
/*
* The GPIOs are maybe not all filled,
* this is not an error.
*/
if (IS_ERR_OR_NULL(gpios->gpio[i]))
continue;
if (mctrl_gpios_desc[i].dir_out)
err = gpiod_direction_output(gpios->gpio[i], 0);
else
err = gpiod_direction_input(gpios->gpio[i]);
if (err) {
dev_dbg(dev, "Unable to set direction for %s GPIO",
mctrl_gpios_desc[i].name);
devm_gpiod_put(dev, gpios->gpio[i]);
gpios->gpio[i] = NULL;
}
}
return gpios;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
enum mctrl_gpio_idx i;
if (IS_ERR_OR_NULL(gpios))
return;
for (i = 0; i < UART_GPIO_MAX; i++)
if (!IS_ERR_OR_NULL(gpios->gpio[i]))
devm_gpiod_put(dev, gpios->gpio[i]);
devm_kfree(dev, gpios);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_free);

View File

@@ -0,0 +1,110 @@
/*
* Helpers for controlling modem lines via GPIO
*
* Copyright (C) 2014 Paratronic S.A.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SERIAL_MCTRL_GPIO__
#define __SERIAL_MCTRL_GPIO__
#include <linux/err.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
enum mctrl_gpio_idx {
UART_GPIO_CTS,
UART_GPIO_DSR,
UART_GPIO_DCD,
UART_GPIO_RNG,
UART_GPIO_RI = UART_GPIO_RNG,
UART_GPIO_RTS,
UART_GPIO_DTR,
UART_GPIO_OUT1,
UART_GPIO_OUT2,
UART_GPIO_MAX,
};
/*
* Opaque descriptor for modem lines controlled by GPIOs
*/
struct mctrl_gpios;
#ifdef CONFIG_GPIOLIB
/*
* Set state of the modem control output lines via GPIOs.
*/
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
/*
* Get state of the modem control output lines from GPIOs.
* The mctrl flags are updated and returned.
*/
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
/*
* Returns the associated struct gpio_desc to the modem line gidx
*/
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx);
/*
* Request and set direction of modem control lines GPIOs.
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
/*
* Free the mctrl_gpios structure.
* Normally, this function will not be called, as the GPIOs will
* be disposed of by the resource management code.
*/
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
#else /* GPIOLIB */
static inline
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{
}
static inline
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
return *mctrl;
}
static inline
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx)
{
return ERR_PTR(-ENOSYS);
}
static inline
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
{
return ERR_PTR(-ENOSYS);
}
static inline
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
}
#endif /* GPIOLIB */
#endif

View File

@@ -535,13 +535,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
wait_for_xmitr(up);
/*
* Send the character out.
* If a LF, also do CR...
*/
sio_out(up, TXX9_SITFIFO, c);
if (c == 10) {
wait_for_xmitr(up);
sio_out(up, TXX9_SITFIFO, 13);
}
/*
* Finally, wait for transmitter to become empty

View File

@@ -358,9 +358,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
{
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
struct uart_port *port = &sirfport->port;
spin_lock(&port->lock);
if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
uart_handle_cts_change(port,
!gpio_get_value(sirfport->cts_gpio));
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
@@ -428,10 +430,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
sirfport->rx_io_count += rx_count;
port->icount.rx += rx_count;
spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
spin_lock(&port->lock);
return rx_count;
}
@@ -465,6 +463,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
xmit->tail = (xmit->tail + sirfport->transfer_size) &
(UART_XMIT_SIZE - 1);
port->icount.tx += sirfport->transfer_size;
@@ -473,10 +472,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
if (sirfport->tx_dma_addr)
dma_unmap_single(port->dev, sirfport->tx_dma_addr,
sirfport->transfer_size, DMA_TO_DEVICE);
spin_lock_irqsave(&sirfport->tx_lock, flags);
sirfport->tx_dma_state = TX_DMA_IDLE;
sirfsoc_uart_tx_with_dma(sirfport);
spin_unlock_irqrestore(&sirfport->tx_lock, flags);
spin_unlock_irqrestore(&port->lock, flags);
}
static void sirfsoc_uart_insert_rx_buf_to_tty(
@@ -489,7 +487,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty(
inserted = tty_insert_flip_string(tport,
sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
port->icount.rx += inserted;
tty_flip_buffer_push(tport);
}
static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
@@ -525,7 +522,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
unsigned long flags;
struct dma_tx_state tx_state;
spin_lock_irqsave(&sirfport->rx_lock, flags);
spin_lock_irqsave(&port->lock, flags);
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@@ -541,12 +538,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
SIRFUART_IO_MODE);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
spin_lock(&port->lock);
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
spin_unlock(&port->lock);
if (sirfport->rx_io_count == 4) {
spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
@@ -557,11 +550,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
else
wr_regl(port, SIRFUART_INT_EN_CLR,
uint_en->sirfsoc_rx_done_en);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
sirfsoc_uart_start_next_rx_dma(port);
} else {
spin_lock_irqsave(&sirfport->rx_lock, flags);
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
if (!sirfport->is_marco)
@@ -571,8 +561,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
uint_en->sirfsoc_rx_done_en);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
}
spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(&port->state->port);
}
static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
@@ -581,8 +572,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
struct dma_tx_state tx_state;
spin_lock(&sirfport->rx_lock);
dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
dmaengine_terminate_all(sirfport->rx_dma_chan);
@@ -595,7 +584,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
else
wr_regl(port, SIRFUART_INT_EN_CLR,
uint_en->sirfsoc_rx_timeout_en);
spin_unlock(&sirfport->rx_lock);
tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
}
@@ -659,7 +647,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
intr_status &= port->read_status_mask;
uart_insert_char(port, intr_status,
uint_en->sirfsoc_rx_oflow_en, 0, flag);
tty_flip_buffer_push(&state->port);
}
recv_char:
if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
@@ -684,6 +671,9 @@ recv_char:
sirfsoc_uart_pio_rx_chars(port,
SIRFSOC_UART_IO_RX_MAX_CNT);
}
spin_unlock(&port->lock);
tty_flip_buffer_push(&state->port);
spin_lock(&port->lock);
if (intr_status & uint_st->sirfsoc_txfifo_empty) {
if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
@@ -702,6 +692,7 @@ recv_char:
}
}
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
@@ -713,7 +704,7 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long flags;
struct dma_tx_state tx_state;
spin_lock_irqsave(&sirfport->rx_lock, flags);
spin_lock_irqsave(&port->lock, flags);
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@@ -726,17 +717,20 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
sirfport->rx_completed++;
sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
}
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(&port->state->port);
}
static void sirfsoc_uart_rx_dma_complete_callback(void *param)
{
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
spin_lock(&sirfport->rx_lock);
unsigned long flags;
spin_lock_irqsave(&sirfport->port.lock, flags);
sirfport->rx_issued++;
sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
spin_unlock(&sirfport->rx_lock);
tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
spin_unlock_irqrestore(&sirfport->port.lock, flags);
}
/* submit rx dma task into dmaengine */
@@ -745,18 +739,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long flags;
int i;
spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
~SIRFUART_IO_MODE);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
sirfsoc_rx_submit_one_dma_desc(port, i);
sirfport->rx_completed = sirfport->rx_issued = 0;
spin_lock_irqsave(&sirfport->rx_lock, flags);
if (!sirfport->is_marco)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
@@ -764,7 +754,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
SIRFUART_RX_DMA_INT_EN(port, uint_en));
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
}
static void sirfsoc_uart_start_rx(struct uart_port *port)
@@ -1228,7 +1217,7 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
while (rd_regl(port,
ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
cpu_relax();
wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
}
static void sirfsoc_uart_console_write(struct console *co, const char *s,
@@ -1369,8 +1358,6 @@ usp_no_flow_control:
ret = -EFAULT;
goto err;
}
spin_lock_init(&sirfport->rx_lock);
spin_lock_init(&sirfport->tx_lock);
tasklet_init(&sirfport->rx_dma_complete_tasklet,
sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
tasklet_init(&sirfport->rx_tmo_process_tasklet,

View File

@@ -424,8 +424,6 @@ struct sirfsoc_uart_port {
struct dma_chan *tx_dma_chan;
dma_addr_t tx_dma_addr;
struct dma_async_tx_descriptor *tx_dma_desc;
spinlock_t rx_lock;
spinlock_t tx_lock;
struct tasklet_struct rx_dma_complete_tasklet;
struct tasklet_struct rx_tmo_process_tasklet;
unsigned int rx_io_count;
@@ -441,9 +439,7 @@ struct sirfsoc_uart_port {
/* Register Access Control */
#define portaddr(port, reg) ((port)->membase + (reg))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
/* UART Port Mask */

View File

@@ -194,9 +194,9 @@ static inline u32 asc_txfifo_is_empty(struct uart_port *port)
return asc_in(port, ASC_STA) & ASC_STA_TE;
}
static inline int asc_txfifo_is_full(struct uart_port *port)
static inline u32 asc_txfifo_is_half_empty(struct uart_port *port)
{
return asc_in(port, ASC_STA) & ASC_STA_TF;
return asc_in(port, ASC_STA) & ASC_STA_THE;
}
static inline const char *asc_port_name(struct uart_port *port)
@@ -628,7 +628,7 @@ static int asc_get_poll_char(struct uart_port *port)
static void asc_put_poll_char(struct uart_port *port, unsigned char c)
{
while (asc_txfifo_is_full(port))
while (!asc_txfifo_is_half_empty(port))
cpu_relax();
asc_out(port, ASC_TXBUF, c);
}
@@ -783,7 +783,7 @@ static void asc_console_putchar(struct uart_port *port, int ch)
unsigned int timeout = 1000000;
/* Wait for upto 1 second in case flow control is stopping us. */
while (--timeout && asc_txfifo_is_full(port))
while (--timeout && !asc_txfifo_is_half_empty(port))
udelay(1);
asc_out(port, ASC_TXBUF, ch);

View File

@@ -359,8 +359,8 @@ static int tilegx_startup(struct uart_port *port)
}
/* Create our IRQs. */
port->irq = create_irq();
if (port->irq < 0)
port->irq = irq_alloc_hwirq(-1);
if (!port->irq)
goto err_uart_dest;
tile_irq_activate(port->irq, TILE_IRQ_PERCPU);
@@ -395,7 +395,7 @@ static int tilegx_startup(struct uart_port *port)
err_free_irq:
free_irq(port->irq, port);
err_dest_irq:
destroy_irq(port->irq);
irq_free_hwirq(port->irq);
err_uart_dest:
gxio_uart_destroy(context);
ret = -ENXIO;
@@ -435,7 +435,7 @@ static void tilegx_shutdown(struct uart_port *port)
if (port->irq > 0) {
free_irq(port->irq, port);
destroy_irq(port->irq);
irq_free_hwirq(port->irq);
port->irq = 0;
}

View File

@@ -418,14 +418,23 @@ static struct uart_ops ulite_ops = {
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static void ulite_console_wait_tx(struct uart_port *port)
{
int i;
u8 val;
unsigned long timeout;
/* Spin waiting for TX fifo to have space available */
for (i = 0; i < 100000; i++) {
/*
* Spin waiting for TX fifo to have space available.
* When using the Microblaze Debug Module this can take up to 1s
*/
timeout = jiffies + msecs_to_jiffies(1000);
while (1) {
val = uart_in32(ULITE_STATUS, port);
if ((val & ULITE_STATUS_TXFULL) == 0)
break;
if (time_after(jiffies, timeout)) {
dev_warn(port->dev,
"timeout waiting for TX buffer empty\n");
break;
}
cpu_relax();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,7 @@
#include <linux/jiffies.h>
#include <linux/syscalls.h>
#include <linux/of.h>
#include <linux/rcupdate.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -88,7 +89,7 @@ static void sysrq_handle_loglevel(int key)
int i;
i = key - '0';
console_loglevel = 7;
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
printk("Loglevel set to %d\n", i);
console_loglevel = i;
}
@@ -343,7 +344,7 @@ static void send_sig_all(int sig)
static void sysrq_handle_term(int key)
{
send_sig_all(SIGTERM);
console_loglevel = 8;
console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
}
static struct sysrq_key_op sysrq_term_op = {
.handler = sysrq_handle_term,
@@ -387,7 +388,7 @@ static struct sysrq_key_op sysrq_thaw_op = {
static void sysrq_handle_kill(int key)
{
send_sig_all(SIGKILL);
console_loglevel = 8;
console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
}
static struct sysrq_key_op sysrq_kill_op = {
.handler = sysrq_handle_kill,
@@ -510,9 +511,9 @@ void __handle_sysrq(int key, bool check_mask)
struct sysrq_key_op *op_p;
int orig_log_level;
int i;
unsigned long flags;
spin_lock_irqsave(&sysrq_key_table_lock, flags);
rcu_sysrq_start();
rcu_read_lock();
/*
* Raise the apparent loglevel to maximum so that the sysrq header
* is shown to provide the user with positive feedback. We do not
@@ -520,7 +521,7 @@ void __handle_sysrq(int key, bool check_mask)
* routing in the consumers of /proc/kmsg.
*/
orig_log_level = console_loglevel;
console_loglevel = 7;
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
printk(KERN_INFO "SysRq : ");
op_p = __sysrq_get_key_op(key);
@@ -554,7 +555,8 @@ void __handle_sysrq(int key, bool check_mask)
printk("\n");
console_loglevel = orig_log_level;
}
spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
rcu_read_unlock();
rcu_sysrq_end();
}
void handle_sysrq(int key)
@@ -1043,16 +1045,23 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p)
{
int retval;
unsigned long flags;
spin_lock_irqsave(&sysrq_key_table_lock, flags);
spin_lock(&sysrq_key_table_lock);
if (__sysrq_get_key_op(key) == remove_op_p) {
__sysrq_put_key_op(key, insert_op_p);
retval = 0;
} else {
retval = -1;
}
spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
spin_unlock(&sysrq_key_table_lock);
/*
* A concurrent __handle_sysrq either got the old op or the new op.
* Wait for it to go away before returning, so the code for an old
* op is not freed (eg. on module unload) while it is in use.
*/
synchronize_rcu();
return retval;
}

View File

@@ -179,7 +179,6 @@ struct uni_pagedir {
unsigned long sum;
unsigned char *inverse_translations[4];
u16 *inverse_trans_unicode;
int readonly;
};
static struct uni_pagedir *dflt;
@@ -262,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
int m;
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
else if (!(p = *conp->vc_uni_pagedir_loc))
return glyph;
else if (use_unicode) {
if (!p->inverse_trans_unicode)
@@ -287,7 +286,7 @@ static void update_user_maps(void)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
p = *vc_cons[i].d->vc_uni_pagedir_loc;
if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
set_inverse_trans_unicode(vc_cons[i].d, p);
@@ -418,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
if (!p)
return;
*vc->vc_uni_pagedir_loc = 0;
*vc->vc_uni_pagedir_loc = NULL;
if (--p->refcount)
return;
con_release_unimap(p);
@@ -436,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
q = *vc_cons[i].d->vc_uni_pagedir_loc;
if (!q || q == p || q->sum != p->sum)
continue;
for (j = 0; j < 32; j++) {
@@ -459,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
}
if (j == 32) {
q->refcount++;
*conp->vc_uni_pagedir_loc = (unsigned long)q;
*conp->vc_uni_pagedir_loc = q;
con_release_unimap(p);
kfree(p);
return 1;
@@ -500,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p && p->readonly)
return -EIO;
p = *vc->vc_uni_pagedir_loc;
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
@@ -512,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return -ENOMEM;
}
q->refcount=1;
*vc->vc_uni_pagedir_loc = (unsigned long)q;
*vc->vc_uni_pagedir_loc = q;
} else {
if (p == dflt) dflt = NULL;
p->refcount++;
@@ -536,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int err = 0, err1, i;
struct uni_pagedir *p, *q;
if (!ct)
return 0;
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p->readonly) {
console_unlock();
return -EIO;
}
if (!ct) {
console_unlock();
return 0;
}
p = *vc->vc_uni_pagedir_loc;
if (p->refcount > 1) {
int j, k;
@@ -564,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Since refcount was > 1, con_clear_unimap() allocated a
* a new uni_pagedir for this vc. Re: p != q
*/
q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
q = *vc->vc_uni_pagedir_loc;
/*
* uni_pgdir is a 32*32*64 table with rows allocated
@@ -586,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_insert_unipair(q, l, p2[k]);
if (err1) {
p->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)p;
*vc->vc_uni_pagedir_loc = p;
con_release_unimap(q);
kfree(q);
console_unlock();
@@ -655,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)
struct uni_pagedir *p;
if (dflt) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
dflt->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
*vc->vc_uni_pagedir_loc = dflt;
if (p && !--p->refcount) {
con_release_unimap(p);
kfree(p);
@@ -674,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)
if (err)
return err;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
q = dfont_unitable;
for (i = 0; i < 256; i++)
@@ -685,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)
}
if (con_unify_unimap(vc, p)) {
dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
dflt = *vc->vc_uni_pagedir_loc;
return err;
}
@@ -713,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
return 0;
con_free_unimap(dst_vc);
q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
q = *src_vc->vc_uni_pagedir_loc;
q->refcount++;
*dst_vc->vc_uni_pagedir_loc = (long)q;
*dst_vc->vc_uni_pagedir_loc = q;
return 0;
}
EXPORT_SYMBOL(con_copy_unimap);
@@ -737,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
for (i = 0; i < 32; i++)
if ((p1 = p->uni_pgdir[i]))
for (j = 0; j < 32; j++)
@@ -810,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
if (!*conp->vc_uni_pagedir_loc)
return -3;
p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
p = *conp->vc_uni_pagedir_loc;
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
(p2 = p1[(ucs >> 6) & 0x1f]) &&
(h = p2[ucs & 0x3f]) < MAX_GLYPH)

View File

@@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)
vc->vc_num = num;
vc->vc_display_fg = &master_display_fg;
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
vc->vc_uni_pagedir = 0;
vc->vc_uni_pagedir = NULL;
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
@@ -1231,6 +1231,52 @@ static void default_attr(struct vc_data *vc)
vc->vc_color = vc->vc_def_color;
}
struct rgb { u8 r; u8 g; u8 b; };
struct rgb rgb_from_256(int i)
{
struct rgb c;
if (i < 8) { /* Standard colours. */
c.r = i&1 ? 0xaa : 0x00;
c.g = i&2 ? 0xaa : 0x00;
c.b = i&4 ? 0xaa : 0x00;
} else if (i < 16) {
c.r = i&1 ? 0xff : 0x55;
c.g = i&2 ? 0xff : 0x55;
c.b = i&4 ? 0xff : 0x55;
} else if (i < 232) { /* 6x6x6 colour cube. */
c.r = (i - 16) / 36 * 85 / 2;
c.g = (i - 16) / 6 % 6 * 85 / 2;
c.b = (i - 16) % 6 * 85 / 2;
} else /* Grayscale ramp. */
c.r = c.g = c.b = i * 10 - 2312;
return c;
}
static void rgb_foreground(struct vc_data *vc, struct rgb c)
{
u8 hue, max = c.r;
if (c.g > max)
max = c.g;
if (c.b > max)
max = c.b;
hue = (c.r > max/2 ? 4 : 0)
| (c.g > max/2 ? 2 : 0)
| (c.b > max/2 ? 1 : 0);
if (hue == 7 && max <= 0x55)
hue = 0, vc->vc_intensity = 2;
else
vc->vc_intensity = (max > 0xaa) + 1;
vc->vc_color = (vc->vc_color & 0xf0) | hue;
}
static void rgb_background(struct vc_data *vc, struct rgb c)
{
/* For backgrounds, err on the dark side. */
vc->vc_color = (vc->vc_color & 0x0f)
| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
}
/* console_lock is held */
static void csi_m(struct vc_data *vc)
{
@@ -1302,8 +1348,7 @@ static void csi_m(struct vc_data *vc)
case 27:
vc->vc_reverse = 0;
break;
case 38:
case 48: /* ITU T.416
case 38: /* ITU T.416
* Higher colour modes.
* They break the usual properties of SGR codes
* and thus need to be detected and ignored by
@@ -1315,15 +1360,41 @@ static void csi_m(struct vc_data *vc)
i++;
if (i > vc->vc_npar)
break;
if (vc->vc_par[i] == 5) /* 256 colours */
i++; /* ubiquitous */
else if (vc->vc_par[i] == 2) /* 24 bit colours */
i += 3; /* extremely rare */
if (vc->vc_par[i] == 5 && /* 256 colours */
i < vc->vc_npar) { /* ubiquitous */
i++;
rgb_foreground(vc,
rgb_from_256(vc->vc_par[i]));
} else if (vc->vc_par[i] == 2 && /* 24 bit */
i <= vc->vc_npar + 3) {/* extremely rare */
struct rgb c = {r:vc->vc_par[i+1],
g:vc->vc_par[i+2],
b:vc->vc_par[i+3]};
rgb_foreground(vc, c);
i += 3;
}
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
* that detecting them is not worth the few extra
* bytes of kernel's size.
* there's no point in supporting them.
*/
break;
case 48:
i++;
if (i > vc->vc_npar)
break;
if (vc->vc_par[i] == 5 && /* 256 colours */
i < vc->vc_npar) {
i++;
rgb_background(vc,
rgb_from_256(vc->vc_par[i]));
} else if (vc->vc_par[i] == 2 && /* 24 bit */
i <= vc->vc_npar + 3) {
struct rgb c = {r:vc->vc_par[i+1],
g:vc->vc_par[i+2],
b:vc->vc_par[i+3]};
rgb_background(vc, c);
i += 3;
}
break;
case 39:
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
break;