summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Kconfig2
-rw-r--r--drivers/tty/amiserial.c29
-rw-r--r--drivers/tty/cyclades.c30
-rw-r--r--drivers/tty/ehv_bytechan.c40
-rw-r--r--drivers/tty/goldfish.c42
-rw-r--r--drivers/tty/hvc/hvc_vio.c29
-rw-r--r--drivers/tty/hvc/hvc_xen.c6
-rw-r--r--drivers/tty/isicom.c7
-rw-r--r--drivers/tty/moxa.c1
-rw-r--r--drivers/tty/mxser.c21
-rw-r--r--drivers/tty/n_gsm.c22
-rw-r--r--drivers/tty/n_hdlc.c19
-rw-r--r--drivers/tty/n_tty.c173
-rw-r--r--drivers/tty/nozomi.c2
-rw-r--r--drivers/tty/pty.c51
-rw-r--r--drivers/tty/rocket.c18
-rw-r--r--drivers/tty/rocket_int.h1
-rw-r--r--drivers/tty/serial/68328serial.c1322
-rw-r--r--drivers/tty/serial/8250/8250.h14
-rw-r--r--drivers/tty/serial/8250/8250_accent.c13
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c2
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c146
-rw-r--r--drivers/tty/serial/8250/8250_boca.c41
-rw-r--r--drivers/tty/serial/8250/8250_core.c37
-rw-r--r--drivers/tty/serial/8250/8250_dw.c137
-rw-r--r--drivers/tty/serial/8250/8250_early.c63
-rw-r--r--drivers/tty/serial/8250/8250_exar_st16c554.c17
-rw-r--r--drivers/tty/serial/8250/8250_fourport.c28
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c7
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c27
-rw-r--r--drivers/tty/serial/8250/8250_hub6.c2
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c14
-rw-r--r--drivers/tty/serial/8250/8250_moxa.c157
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c16
-rw-r--r--drivers/tty/serial/8250/8250_of.c (renamed from drivers/tty/serial/of_serial.c)39
-rw-r--r--drivers/tty/serial/8250/8250_omap.c40
-rw-r--r--drivers/tty/serial/8250/8250_pci.c197
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c48
-rw-r--r--drivers/tty/serial/8250/8250_port.c482
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c24
-rw-r--r--drivers/tty/serial/8250/Kconfig63
-rw-r--r--drivers/tty/serial/8250/Makefile3
-rw-r--r--drivers/tty/serial/8250/serial_cs.c90
-rw-r--r--drivers/tty/serial/Kconfig77
-rw-r--r--drivers/tty/serial/Makefile4
-rw-r--r--drivers/tty/serial/amba-pl011.c361
-rw-r--r--drivers/tty/serial/amba-pl011.h34
-rw-r--r--drivers/tty/serial/arc_uart.c1
-rw-r--r--drivers/tty/serial/atmel_serial.c309
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c2
-rw-r--r--drivers/tty/serial/bfin_uart.c27
-rw-r--r--drivers/tty/serial/clps711x.c10
-rw-r--r--drivers/tty/serial/crisv10.c33
-rw-r--r--drivers/tty/serial/digicolor-usart.c9
-rw-r--r--drivers/tty/serial/earlycon.c127
-rw-r--r--drivers/tty/serial/icom.c1
-rw-r--r--drivers/tty/serial/ifx6x60.c3
-rw-r--r--drivers/tty/serial/imx.c194
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c4
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c2
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c13
-rw-r--r--drivers/tty/serial/m32r_sio.c136
-rw-r--r--drivers/tty/serial/m32r_sio.h49
-rw-r--r--drivers/tty/serial/max310x.c2
-rw-r--r--drivers/tty/serial/men_z135_uart.c2
-rw-r--r--drivers/tty/serial/meson_uart.c88
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c8
-rw-r--r--drivers/tty/serial/mpsc.c178
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/mvebu-uart.c650
-rw-r--r--drivers/tty/serial/nwpserial.c477
-rw-r--r--drivers/tty/serial/omap-serial.c12
-rw-r--r--drivers/tty/serial/pxa.c2
-rw-r--r--drivers/tty/serial/samsung.c24
-rw-r--r--drivers/tty/serial/sc16is7xx.c39
-rw-r--r--drivers/tty/serial/serial_core.c136
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c5
-rw-r--r--drivers/tty/serial/sh-sci.c695
-rw-r--r--drivers/tty/serial/sh-sci.h25
-rw-r--r--drivers/tty/serial/sprd_serial.c4
-rw-r--r--drivers/tty/serial/sunsu.c2
-rw-r--r--drivers/tty/serial/uartlite.c61
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/serial/vt8500_serial.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c543
-rw-r--r--drivers/tty/serial/zs.c4
-rw-r--r--drivers/tty/synclink.c23
-rw-r--r--drivers/tty/synclink_gt.c23
-rw-r--r--drivers/tty/synclinkmp.c63
-rw-r--r--drivers/tty/tty_audit.c237
-rw-r--r--drivers/tty/tty_buffer.c39
-rw-r--r--drivers/tty/tty_io.c382
-rw-r--r--drivers/tty/tty_ioctl.c33
-rw-r--r--drivers/tty/tty_ldisc.c245
-rw-r--r--drivers/tty/tty_ldsem.c4
-rw-r--r--drivers/tty/tty_mutex.c31
-rw-r--r--drivers/tty/tty_port.c20
-rw-r--r--drivers/tty/vt/keyboard.c14
-rw-r--r--drivers/tty/vt/selection.c2
-rw-r--r--drivers/tty/vt/vt.c5
101 files changed, 4341 insertions, 4663 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index c01f45095877..82c4d2e45319 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -226,7 +226,7 @@ config CYCLADES
config CYZ_INTR
bool "Cyclades-Z interrupt mode operation"
- depends on CYCLADES
+ depends on CYCLADES && PCI
help
The Cyclades-Z family of multiport cards allows 2 (two) driver op
modes: polling and interrupt. In polling mode, the driver will check
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index e53d9a512c6d..eacf4c9f3b29 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#undef SERIAL_PARANOIA_CHECK
-#define SERIAL_DO_RESTART
/* Set of debugging defines */
@@ -640,7 +639,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
custom.adkcon = AC_UARTBRK;
mb();
- if (tty->termios.c_cflag & HUPCL)
+ if (C_HUPCL(tty))
info->MCR &= ~(SER_DTR|SER_RTS);
rtsdtr_ctrl(info->MCR);
@@ -966,8 +965,7 @@ static void rs_throttle(struct tty_struct * tty)
struct serial_state *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("throttle %s: %d....\n", tty_name(tty),
- tty->ldisc.chars_in_buffer(tty));
+ printk("throttle %s ....\n", tty_name(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
@@ -976,7 +974,7 @@ static void rs_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
info->MCR &= ~SER_RTS;
local_irq_save(flags);
@@ -989,8 +987,7 @@ static void rs_unthrottle(struct tty_struct * tty)
struct serial_state *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("unthrottle %s: %d....\n", tty_name(tty),
- tty->ldisc.chars_in_buffer(tty));
+ printk("unthrottle %s ....\n", tty_name(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
@@ -1002,7 +999,7 @@ static void rs_unthrottle(struct tty_struct * tty)
else
rs_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
info->MCR |= SER_RTS;
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@@ -1335,8 +1332,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(tty, info, old_termios);
/* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) &&
- !(cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
info->MCR &= ~(SER_DTR|SER_RTS);
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@@ -1344,21 +1340,17 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- (cflag & CBAUD)) {
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
info->MCR |= SER_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->MCR |= SER_RTS;
- }
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
local_irq_restore(flags);
}
/* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1370,8 +1362,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* XXX It's not clear whether the current behavior is correct
* or not. Hence, this may change.....
*/
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios.c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&info->open_wait);
#endif
}
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index d4a1331675ed..d67e542bab1c 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -292,14 +292,14 @@ static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
#endif /* CONFIG_CYZ_INTR */
-static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
+static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
{
struct cyclades_card *card = port->card;
cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
}
-static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
+static u8 cyy_readb(struct cyclades_port *port, u32 reg)
{
struct cyclades_card *card = port->card;
@@ -321,7 +321,7 @@ static inline bool cyz_fpga_loaded(struct cyclades_card *card)
return __cyz_fpga_loaded(card->ctl_addr.p9060);
}
-static inline bool cyz_is_loaded(struct cyclades_card *card)
+static bool cyz_is_loaded(struct cyclades_card *card)
{
struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
@@ -329,7 +329,7 @@ static inline bool cyz_is_loaded(struct cyclades_card *card)
readl(&fw_id->signature) == ZFIRM_ID;
}
-static inline int serial_paranoia_check(struct cyclades_port *info,
+static int serial_paranoia_check(struct cyclades_port *info,
const char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
@@ -1440,7 +1440,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
- if (tty->termios.c_cflag & HUPCL)
+ if (C_HUPCL(tty))
cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
@@ -1469,7 +1469,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
free_page((unsigned long)temp);
}
- if (tty->termios.c_cflag & HUPCL)
+ if (C_HUPCL(tty))
tty_port_lower_dtr_rts(&info->port);
set_bit(TTY_IO_ERROR, &tty->flags);
@@ -2795,8 +2795,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
cy_set_line_char(info, tty);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
cy_start(tty);
}
@@ -2807,8 +2806,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* XXX It's not clear whether the current behavior is correct
* or not. Hence, this may change.....
*/
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios.c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&info->port.open_wait);
#endif
} /* cy_set_termios */
@@ -2852,8 +2850,8 @@ static void cy_throttle(struct tty_struct *tty)
unsigned long flags;
#ifdef CY_DEBUG_THROTTLE
- printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty),
- tty->ldisc.chars_in_buffer(tty), info->line);
+ printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
+ info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_throttle"))
@@ -2868,7 +2866,7 @@ static void cy_throttle(struct tty_struct *tty)
info->throttle = 1;
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
cyy_change_rts_dtr(info, 0, TIOCM_RTS);
@@ -2891,8 +2889,8 @@ static void cy_unthrottle(struct tty_struct *tty)
unsigned long flags;
#ifdef CY_DEBUG_THROTTLE
- printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
- tty_name(tty), tty_chars_in_buffer(tty), info->line);
+ printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
+ tty_name(tty), info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
@@ -2905,7 +2903,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
card = info->card;
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 342b36b9ad35..7ac9bcdf1e61 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -23,7 +23,6 @@
* byte channel used for the console is designated as the default tty.
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -719,19 +718,6 @@ error:
return ret;
}
-static int ehv_bc_tty_remove(struct platform_device *pdev)
-{
- struct ehv_bc_data *bc = dev_get_drvdata(&pdev->dev);
-
- tty_unregister_device(ehv_bc_driver, bc - bcs);
-
- tty_port_destroy(&bc->port);
- irq_dispose_mapping(bc->tx_irq);
- irq_dispose_mapping(bc->rx_irq);
-
- return 0;
-}
-
static const struct of_device_id ehv_bc_tty_of_ids[] = {
{ .compatible = "epapr,hv-byte-channel" },
{}
@@ -741,15 +727,15 @@ static struct platform_driver ehv_bc_tty_driver = {
.driver = {
.name = "ehv-bc",
.of_match_table = ehv_bc_tty_of_ids,
+ .suppress_bind_attrs = true,
},
.probe = ehv_bc_tty_probe,
- .remove = ehv_bc_tty_remove,
};
/**
* ehv_bc_init - ePAPR hypervisor byte channel driver initialization
*
- * This function is called when this module is loaded.
+ * This function is called when this driver is loaded.
*/
static int __init ehv_bc_init(void)
{
@@ -814,24 +800,4 @@ error:
return ret;
}
-
-
-/**
- * ehv_bc_exit - ePAPR hypervisor byte channel driver termination
- *
- * This function is called when this driver is unloaded.
- */
-static void __exit ehv_bc_exit(void)
-{
- platform_driver_unregister(&ehv_bc_tty_driver);
- tty_unregister_driver(ehv_bc_driver);
- put_tty_driver(ehv_bc_driver);
- kfree(bcs);
-}
-
-module_init(ehv_bc_init);
-module_exit(ehv_bc_exit);
-
-MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("ePAPR hypervisor byte channel driver");
-MODULE_LICENSE("GPL v2");
+device_initcall(ehv_bc_init);
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 0f82c0b146f6..3fc912373adf 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -68,8 +68,7 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
{
- struct platform_device *pdev = dev_id;
- struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
+ struct goldfish_tty *qtty = dev_id;
void __iomem *base = qtty->base;
unsigned long irq_flags;
unsigned char *buf;
@@ -162,7 +161,7 @@ static int goldfish_tty_console_setup(struct console *co, char *options)
return 0;
}
-static struct tty_port_operations goldfish_port_ops = {
+static const struct tty_port_operations goldfish_port_ops = {
.activate = goldfish_tty_activate,
.shutdown = goldfish_tty_shutdown
};
@@ -233,6 +232,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
struct device *ttydev;
void __iomem *base;
u32 irq;
+ unsigned int line;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL)
@@ -248,10 +248,16 @@ static int goldfish_tty_probe(struct platform_device *pdev)
irq = r->start;
- if (pdev->id >= goldfish_tty_line_count)
- goto err_unmap;
-
mutex_lock(&goldfish_tty_lock);
+
+ if (pdev->id == PLATFORM_DEVID_NONE)
+ line = goldfish_tty_current_line_count;
+ else
+ line = pdev->id;
+
+ if (line >= goldfish_tty_line_count)
+ goto err_create_driver_failed;
+
if (goldfish_tty_current_line_count == 0) {
ret = goldfish_tty_create_driver();
if (ret)
@@ -259,7 +265,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
}
goldfish_tty_current_line_count++;
- qtty = &goldfish_ttys[pdev->id];
+ qtty = &goldfish_ttys[line];
spin_lock_init(&qtty->lock);
tty_port_init(&qtty->port);
qtty->port.ops = &goldfish_port_ops;
@@ -269,13 +275,13 @@ 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);
+ "goldfish_tty", qtty);
if (ret)
goto err_request_irq_failed;
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
- pdev->id, &pdev->dev);
+ line, &pdev->dev);
if (IS_ERR(ttydev)) {
ret = PTR_ERR(ttydev);
goto err_tty_register_device_failed;
@@ -286,8 +292,9 @@ static int goldfish_tty_probe(struct platform_device *pdev)
qtty->console.device = goldfish_tty_console_device;
qtty->console.setup = goldfish_tty_console_setup;
qtty->console.flags = CON_PRINTBUFFER;
- qtty->console.index = pdev->id;
+ qtty->console.index = line;
register_console(&qtty->console);
+ platform_set_drvdata(pdev, qtty);
mutex_unlock(&goldfish_tty_lock);
return 0;
@@ -307,13 +314,12 @@ err_unmap:
static int goldfish_tty_remove(struct platform_device *pdev)
{
- struct goldfish_tty *qtty;
+ struct goldfish_tty *qtty = platform_get_drvdata(pdev);
mutex_lock(&goldfish_tty_lock);
- qtty = &goldfish_ttys[pdev->id];
unregister_console(&qtty->console);
- tty_unregister_device(goldfish_tty_driver, pdev->id);
+ tty_unregister_device(goldfish_tty_driver, qtty->console.index);
iounmap(qtty->base);
qtty->base = NULL;
free_irq(qtty->irq, pdev);
@@ -324,11 +330,19 @@ static int goldfish_tty_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id goldfish_tty_of_match[] = {
+ { .compatible = "google,goldfish-tty", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
+
static struct platform_driver goldfish_tty_platform_driver = {
.probe = goldfish_tty_probe,
.remove = goldfish_tty_remove,
.driver = {
- .name = "goldfish_tty"
+ .name = "goldfish_tty",
+ .of_match_table = goldfish_tty_of_match,
}
};
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index f575a9b5ede7..b05dc5086627 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -41,7 +41,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/console.h>
-#include <linux/module.h>
#include <asm/hvconsole.h>
#include <asm/vio.h>
@@ -61,7 +60,6 @@ static struct vio_device_id hvc_driver_table[] = {
#endif
{ "", "" }
};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
typedef enum hv_protocol {
HV_PROTOCOL_RAW,
@@ -363,26 +361,13 @@ static int hvc_vio_probe(struct vio_dev *vdev,
return 0;
}
-static int hvc_vio_remove(struct vio_dev *vdev)
-{
- struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
- int rc, termno;
-
- termno = hp->vtermno;
- rc = hvc_remove(hp);
- if (rc == 0) {
- if (hvterm_privs[termno] != &hvterm_priv0)
- kfree(hvterm_privs[termno]);
- hvterm_privs[termno] = NULL;
- }
- return rc;
-}
-
static struct vio_driver hvc_vio_driver = {
.id_table = hvc_driver_table,
.probe = hvc_vio_probe,
- .remove = hvc_vio_remove,
.name = hvc_driver_name,
+ .driver = {
+ .suppress_bind_attrs = true,
+ },
};
static int __init hvc_vio_init(void)
@@ -394,13 +379,7 @@ static int __init hvc_vio_init(void)
return rc;
}
-module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-
-static void __exit hvc_vio_exit(void)
-{
- vio_unregister_driver(&hvc_vio_driver);
-}
-module_exit(hvc_vio_exit);
+device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */
void __init hvc_vio_init_early(void)
{
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index fa816b7193b6..f417fa1ee47c 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -162,7 +162,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
return recv;
}
-static struct hv_ops domU_hvc_ops = {
+static const struct hv_ops domU_hvc_ops = {
.get_chars = domU_read_console,
.put_chars = domU_write_console,
.notifier_add = notifier_add_irq,
@@ -188,7 +188,7 @@ static int dom0_write_console(uint32_t vtermno, const char *str, int len)
return len;
}
-static struct hv_ops dom0_hvc_ops = {
+static const struct hv_ops dom0_hvc_ops = {
.get_chars = dom0_read_console,
.put_chars = dom0_write_console,
.notifier_add = notifier_add_irq,
@@ -323,6 +323,7 @@ void xen_console_resume(void)
}
}
+#ifdef CONFIG_HVC_XEN_FRONTEND
static void xencons_disconnect_backend(struct xencons_info *info)
{
if (info->irq > 0)
@@ -363,7 +364,6 @@ static int xen_console_remove(struct xencons_info *info)
return 0;
}
-#ifdef CONFIG_HVC_XEN_FRONTEND
static int xencons_remove(struct xenbus_device *dev)
{
return xen_console_remove(dev_get_drvdata(&dev->dev));
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 2054427992e0..8bf67630018b 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -220,7 +220,7 @@ static struct isi_port isi_ports[PORT_COUNT];
* it wants to talk.
*/
-static inline int WaitTillCardIsFree(unsigned long base)
+static int WaitTillCardIsFree(unsigned long base)
{
unsigned int count = 0;
unsigned int a = in_atomic(); /* do we run under spinlock? */
@@ -280,7 +280,7 @@ static void raise_dtr(struct isi_port *port)
}
/* card->lock HAS to be held */
-static inline void drop_dtr(struct isi_port *port)
+static void drop_dtr(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
@@ -1204,8 +1204,7 @@ static void isicom_set_termios(struct tty_struct *tty,
isicom_config_port(tty);
spin_unlock_irqrestore(&port->card->card_lock, flags);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
isicom_start(tty);
}
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 14c54e041065..92982d7c0489 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -155,7 +155,6 @@ struct mon_str {
#define LOWWAIT 2
#define EMPTYWAIT 3
-#define SERIAL_DO_RESTART
#define WAKEUP_CHARS 256
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 4c4a23674569..2f12bb9f4336 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -254,6 +254,7 @@ struct mxser_port {
int xmit_head;
int xmit_tail;
int xmit_cnt;
+ int closing;
struct ktermios normal_termios;
@@ -1081,6 +1082,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
return;
if (tty_port_close_start(port, tty, filp) == 0)
return;
+ info->closing = 1;
mutex_lock(&port->mutex);
mxser_close_port(port);
mxser_flush_buffer(tty);
@@ -1091,6 +1093,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
mxser_shutdown_port(port);
clear_bit(ASYNCB_INITIALIZED, &port->flags);
mutex_unlock(&port->mutex);
+ info->closing = 0;
/* Right now the tty_port set is done outside of the close_end helper
as we don't yet have everyone using refcounts */
tty_port_close_end(port, tty);
@@ -1864,7 +1867,7 @@ static void mxser_stoprx(struct tty_struct *tty)
}
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1901,7 +1904,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1949,15 +1952,13 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
mxser_change_speed(tty, old_termios);
spin_unlock_irqrestore(&info->slock, flags);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
/* Handle sw stopped */
- if ((old_termios->c_iflag & IXON) &&
- !(tty->termios.c_iflag & IXON)) {
+ if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) {
tty->stopped = 0;
if (info->board->chip_flag) {
@@ -2255,10 +2256,8 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
break;
iir &= MOXA_MUST_IIR_MASK;
tty = tty_port_tty_get(&port->port);
- if (!tty ||
- (port->port.flags & ASYNC_CLOSING) ||
- !(port->port.flags &
- ASYNC_INITIALIZED)) {
+ if (!tty || port->closing ||
+ !(port->port.flags & ASYNC_INITIALIZED)) {
status = inb(port->ioaddr + UART_LSR);
outb(0x27, port->ioaddr + UART_FCR);
inb(port->ioaddr + UART_MSR);
@@ -2337,7 +2336,7 @@ static const struct tty_operations mxser_ops = {
.get_icount = mxser_get_icount,
};
-static struct tty_port_operations mxser_port_ops = {
+static const struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.dtr_rts = mxser_dtr_rts,
.activate = mxser_activate,
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c3fe026d3168..c01620780f5b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1066,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
/* Carrier drop -> hangup */
if (tty) {
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
- if (!(tty->termios.c_cflag & CLOCAL))
+ if (!C_CLOCAL(tty))
tty_hangup(tty);
}
if (brk & 0x01)
@@ -2304,21 +2304,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
/**
- * gsmld_chars_in_buffer - report available bytes
- * @tty: tty device
- *
- * Report the number of characters buffered to be delivered to user
- * at this instant in time.
- *
- * Locking: gsm lock
- */
-
-static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-/**
* gsmld_flush_buffer - clean input queue
* @tty: terminal device
*
@@ -2830,7 +2815,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
.open = gsmld_open,
.close = gsmld_close,
.flush_buffer = gsmld_flush_buffer,
- .chars_in_buffer = gsmld_chars_in_buffer,
.read = gsmld_read,
.write = gsmld_write,
.ioctl = gsmld_ioctl,
@@ -3132,7 +3116,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
dlci->modem_tx &= ~TIOCM_DTR;
dlci->throttled = 1;
/* Send an MSC with DTR cleared */
@@ -3144,7 +3128,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
dlci->modem_tx |= TIOCM_DTR;
dlci->throttled = 0;
/* Send an MSC with DTR set */
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index bbc4ce66c2c1..bcaba17688f6 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -159,7 +159,6 @@ struct n_hdlc {
/*
* HDLC buffer list manipulation functions
*/
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
struct n_hdlc_buf *buf);
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
@@ -853,10 +852,10 @@ static struct n_hdlc *n_hdlc_alloc(void)
if (!n_hdlc)
return NULL;
- 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);
- n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
+ spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
+ spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
+ spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
+ spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
/* allocate free rx buffer list */
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
@@ -885,16 +884,6 @@ static struct n_hdlc *n_hdlc_alloc(void)
} /* end of n_hdlc_alloc() */
/**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
-{
- memset(list, 0, sizeof(*list));
- spin_lock_init(&list->spinlock);
-} /* end of n_hdlc_buf_list_init() */
-
-/**
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
* @list - pointer to buffer list
* @buf - pointer to buffer
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index e49c2bce551d..fb76a7d80e7e 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -113,8 +113,6 @@ struct n_tty_data {
DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
unsigned char echo_buf[N_TTY_BUF_SIZE];
- int minimum_to_wake;
-
/* consumer-published */
size_t read_tail;
size_t line_start;
@@ -153,23 +151,25 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}
-static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
- unsigned char __user *ptr)
+static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
+ size_t tail, size_t n)
{
struct n_tty_data *ldata = tty->disc_data;
+ size_t size = N_TTY_BUF_SIZE - tail;
+ const void *from = read_buf_addr(ldata, tail);
+ int uncopied;
- tty_audit_add_data(tty, &x, 1, ldata->icanon);
- return put_user(x, ptr);
-}
-
-static inline int tty_copy_to_user(struct tty_struct *tty,
- void __user *to,
- const void *from,
- unsigned long n)
-{
- struct n_tty_data *ldata = tty->disc_data;
+ if (n > size) {
+ tty_audit_add_data(tty, from, size);
+ uncopied = copy_to_user(to, from, size);
+ if (uncopied)
+ return uncopied;
+ to += size;
+ n -= size;
+ from = ldata->read_buf;
+ }
- tty_audit_add_data(tty, from, n, ldata->icanon);
+ tty_audit_add_data(tty, from, n);
return copy_to_user(to, from, n);
}
@@ -228,8 +228,8 @@ static ssize_t chars_in_buffer(struct tty_struct *tty)
static void n_tty_write_wakeup(struct tty_struct *tty)
{
- if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
- kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
}
static void n_tty_check_throttle(struct tty_struct *tty)
@@ -258,16 +258,11 @@ static void n_tty_check_throttle(struct tty_struct *tty)
static void n_tty_check_unthrottle(struct tty_struct *tty)
{
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
return;
- if (!tty->count)
- return;
n_tty_kick_worker(tty);
- n_tty_write_wakeup(tty->link);
- if (waitqueue_active(&tty->link->write_wait))
- wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
+ tty_wakeup(tty->link);
return;
}
@@ -284,8 +279,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
break;
- if (!tty->count)
- break;
n_tty_kick_worker(tty);
unthrottled = tty_unthrottle_safe(tty);
if (!unthrottled)
@@ -373,28 +366,6 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
}
/**
- * n_tty_chars_in_buffer - report available bytes
- * @tty: tty device
- *
- * Report the number of characters buffered to be delivered to user
- * at this instant in time.
- *
- * Locking: exclusive termios_rwsem
- */
-
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
-{
- ssize_t n;
-
- WARN_ONCE(1, "%s is deprecated and scheduled for removal.", __func__);
-
- down_write(&tty->termios_rwsem);
- n = chars_in_buffer(tty);
- up_write(&tty->termios_rwsem);
- return n;
-}
-
-/**
* is_utf8_continuation - utf8 multibyte check
* @c: byte to check
*
@@ -1201,9 +1172,7 @@ static void n_tty_receive_overrun(struct tty_struct *tty)
ldata->num_overrun++;
if (time_after(jiffies, ldata->overrun_time + HZ) ||
time_after(ldata->overrun_time, jiffies)) {
- printk(KERN_WARNING "%s: %d input overrun(s)\n",
- tty_name(tty),
- ldata->num_overrun);
+ tty_warn(tty, "%d input overrun(s)\n", ldata->num_overrun);
ldata->overrun_time = jiffies;
ldata->num_overrun = 0;
}
@@ -1486,8 +1455,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
n_tty_receive_overrun(tty);
break;
default:
- printk(KERN_ERR "%s: unknown flag %d\n",
- tty_name(tty), flag);
+ tty_err(tty, "unknown flag %d\n", flag);
break;
}
}
@@ -1556,8 +1524,6 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
flag = *fp++;
if (likely(flag == TTY_NORMAL))
n_tty_receive_char_closing(tty, *cp++);
- else
- n_tty_receive_char_flagged(tty, *cp++, flag);
}
}
@@ -1659,7 +1625,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* publish read_head to consumer */
smp_store_release(&ldata->commit_head, ldata->read_head);
- if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
+ if (read_cnt(ldata)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
@@ -1780,12 +1746,6 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
return n_tty_receive_buf_common(tty, cp, fp, count, 1);
}
-int is_ignored(int sig)
-{
- return (sigismember(&current->blocked, sig) ||
- current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
-}
-
/**
* n_tty_set_termios - termios data changed
* @tty: terminal
@@ -1932,7 +1892,6 @@ static int n_tty_open(struct tty_struct *tty)
reset_buffer_flags(tty->disc_data);
ldata->column = 0;
ldata->canon_column = 0;
- ldata->minimum_to_wake = 1;
ldata->num_overrun = 0;
ldata->no_room = 0;
ldata->lnext = 0;
@@ -2006,11 +1965,11 @@ static int copy_from_read_buf(struct tty_struct *tty,
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
if (n) {
- retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
+ const unsigned char *from = read_buf_addr(ldata, tail);
+ retval = copy_to_user(*b, from, n);
n -= retval;
- is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
- tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
- ldata->icanon);
+ is_eof = n == 1 && *from == EOF_CHAR(tty);
+ tty_audit_add_data(tty, from, n);
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
@@ -2072,12 +2031,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
if (eol == N_TTY_BUF_SIZE && more) {
/* scan wrapped without finding set bit */
eol = find_next_bit(ldata->read_flags, more, 0);
- if (eol != more)
- found = 1;
- } else if (eol != size)
- found = 1;
+ found = eol != more;
+ } else
+ found = eol != size;
- size = N_TTY_BUF_SIZE - tail;
n = eol - tail;
if (n > N_TTY_BUF_SIZE)
n += N_TTY_BUF_SIZE;
@@ -2088,17 +2045,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
n = c;
}
- n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
- __func__, eol, found, n, c, size, more);
-
- if (n > size) {
- ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size);
- if (ret)
- return -EFAULT;
- ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size);
- } else
- ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n);
+ n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
+ __func__, eol, found, n, c, tail, more);
+ ret = tty_copy_to_user(tty, *b, tail, n);
if (ret)
return -EFAULT;
*b += n;
@@ -2113,7 +2063,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
ldata->line_start = ldata->read_tail;
else
ldata->push = 0;
- tty_audit_push(tty);
+ tty_audit_push();
}
return 0;
}
@@ -2204,14 +2154,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
minimum = MIN_CHAR(tty);
if (minimum) {
time = (HZ / 10) * TIME_CHAR(tty);
- if (time)
- ldata->minimum_to_wake = 1;
- else if (!waitqueue_active(&tty->read_wait) ||
- (ldata->minimum_to_wake > minimum))
- ldata->minimum_to_wake = minimum;
} else {
timeout = (HZ / 10) * TIME_CHAR(tty);
- ldata->minimum_to_wake = minimum = 1;
+ minimum = 1;
}
}
@@ -2229,19 +2174,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
spin_unlock_irq(&tty->link->ctrl_lock);
- if (tty_put_user(tty, cs, b++)) {
+ if (put_user(cs, b)) {
retval = -EFAULT;
- b--;
break;
}
+ b++;
nr--;
break;
}
- if (((minimum - (b - buf)) < ldata->minimum_to_wake) &&
- ((minimum - (b - buf)) >= 1))
- ldata->minimum_to_wake = (minimum - (b - buf));
-
done = check_other_done(tty);
if (!input_available_p(tty, 0)) {
@@ -2279,11 +2220,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
/* Deal with packet mode. */
if (packet && b == buf) {
- if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
+ if (put_user(TIOCPKT_DATA, b)) {
retval = -EFAULT;
- b--;
break;
}
+ b++;
nr--;
}
@@ -2307,9 +2248,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
up_read(&tty->termios_rwsem);
remove_wait_queue(&tty->read_wait, &wait);
- if (!waitqueue_active(&tty->read_wait))
- ldata->minimum_to_wake = minimum;
-
mutex_unlock(&ldata->atomic_read_lock);
if (b - buf)
@@ -2421,7 +2359,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
}
break_out:
remove_wait_queue(&tty->write_wait, &wait);
- if (b - buf != nr && tty->fasync)
+ if (nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
up_read(&tty->termios_rwsem);
return (b - buf) ? b - buf : retval;
@@ -2444,7 +2382,6 @@ break_out:
static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_table *wait)
{
- struct n_tty_data *ldata = tty->disc_data;
unsigned int mask = 0;
poll_wait(file, &tty->read_wait, wait);
@@ -2457,12 +2394,6 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
mask |= POLLPRI | POLLIN | POLLRDNORM;
if (tty_hung_up_p(file))
mask |= POLLHUP;
- if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
- if (MIN_CHAR(tty) && !TIME_CHAR(tty))
- ldata->minimum_to_wake = MIN_CHAR(tty);
- else
- ldata->minimum_to_wake = 1;
- }
if (tty->ops->write && !tty_is_writelocked(tty) &&
tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
tty_write_room(tty) > 0)
@@ -2511,25 +2442,12 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
}
}
-static void n_tty_fasync(struct tty_struct *tty, int on)
-{
- struct n_tty_data *ldata = tty->disc_data;
-
- if (!waitqueue_active(&tty->read_wait)) {
- if (on)
- ldata->minimum_to_wake = 1;
- else if (!tty->fasync)
- ldata->minimum_to_wake = N_TTY_BUF_SIZE;
- }
-}
-
-struct tty_ldisc_ops tty_ldisc_N_TTY = {
+static struct tty_ldisc_ops n_tty_ops = {
.magic = TTY_LDISC_MAGIC,
.name = "n_tty",
.open = n_tty_open,
.close = n_tty_close,
.flush_buffer = n_tty_flush_buffer,
- .chars_in_buffer = n_tty_chars_in_buffer,
.read = n_tty_read,
.write = n_tty_write,
.ioctl = n_tty_ioctl,
@@ -2537,7 +2455,6 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.poll = n_tty_poll,
.receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup,
- .fasync = n_tty_fasync,
.receive_buf2 = n_tty_receive_buf2,
};
@@ -2545,14 +2462,18 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
* n_tty_inherit_ops - inherit N_TTY methods
* @ops: struct tty_ldisc_ops where to save N_TTY methods
*
- * Enables a 'subclass' line discipline to 'inherit' N_TTY
- * methods.
+ * Enables a 'subclass' line discipline to 'inherit' N_TTY methods.
*/
void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
{
- *ops = tty_ldisc_N_TTY;
+ *ops = n_tty_ops;
ops->owner = NULL;
ops->refcount = ops->flags = 0;
}
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
+
+void __init n_tty_init(void)
+{
+ tty_register_ldisc(N_TTY, &n_tty_ops);
+}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 80f9de907563..5cc80b80c82b 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
struct tty_struct *tty = tty_port_tty_get(&port->port);
int i, ret;
- read_mem32((u32 *) &size, addr, 4);
+ size = __le32_to_cpu(readl(addr));
/* DBG1( "%d bytes port: %d", size, index); */
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a45660f62db5..e16a49b507ef 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -263,8 +263,7 @@ static void pty_set_termios(struct tty_struct *tty,
{
/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
- int extproc = (old_termios->c_lflag & EXTPROC) |
- (tty->termios.c_lflag & EXTPROC);
+ int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
int old_flow = ((old_termios->c_iflag & IXON) &&
(old_termios->c_cc[VSTOP] == '\023') &&
(old_termios->c_cc[VSTART] == '\021'));
@@ -406,13 +405,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
if (legacy) {
/* We always use new tty termios data so we can do this
the easy way .. */
- retval = tty_init_termios(tty);
- if (retval)
- goto err_deinit_tty;
-
- retval = tty_init_termios(o_tty);
- if (retval)
- goto err_free_termios;
+ tty_init_termios(tty);
+ tty_init_termios(o_tty);
driver->other->ttys[idx] = o_tty;
driver->ttys[idx] = tty;
@@ -444,12 +438,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
tty->count++;
o_tty->count++;
return 0;
-err_free_termios:
- if (legacy)
- tty_free_termios(tty);
-err_deinit_tty:
- deinitialize_tty_struct(o_tty);
- free_tty_struct(o_tty);
+
err_put_module:
module_put(driver->other->owner);
err:
@@ -666,22 +655,22 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
return tty;
}
-/* We have no need to install and remove our tty objects as devpts does all
- the work for us */
-
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
{
return pty_common_install(driver, tty, false);
}
+/* this is called once with whichever end is closed last */
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
-}
+ struct inode *ptmx_inode;
-/* this is called once with whichever end is closed last */
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
- devpts_kill_index(tty->driver_data, tty->index);
+ if (tty->driver->subtype == PTY_TYPE_MASTER)
+ ptmx_inode = tty->driver_data;
+ else
+ ptmx_inode = tty->link->driver_data;
+ devpts_kill_index(ptmx_inode, tty->index);
+ devpts_del_ref(ptmx_inode);
}
static const struct tty_operations ptm_unix98_ops = {
@@ -697,7 +686,6 @@ static const struct tty_operations ptm_unix98_ops = {
.unthrottle = pty_unthrottle,
.ioctl = pty_unix98_ioctl,
.resize = pty_resize,
- .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup
};
@@ -715,7 +703,6 @@ static const struct tty_operations pty_unix98_ops = {
.set_termios = pty_set_termios,
.start = pty_start,
.stop = pty_stop,
- .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup,
};
@@ -773,6 +760,18 @@ static int ptmx_open(struct inode *inode, struct file *filp)
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty->driver_data = inode;
+ /*
+ * In the case where all references to ptmx inode are dropped and we
+ * still have /dev/tty opened pointing to the master/slave pair (ptmx
+ * is closed/released before /dev/tty), we must make sure that the inode
+ * is still valid when we call the final pty_unix98_shutdown, thus we
+ * hold an additional reference to the ptmx inode. For the same /dev/tty
+ * last close case, we also need to make sure the super_block isn't
+ * destroyed (devpts instance unmounted), before /dev/tty is closed and
+ * on its release devpts_kill_index is called.
+ */
+ devpts_add_ref(inode);
+
tty_add_file(tty, filp);
slave_inode = devpts_pty_new(inode,
@@ -788,7 +787,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
- tty_debug_hangup(tty, "(tty count=%d)\n", tty->count);
+ tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
tty_unlock(tty);
return 0;
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 802eac7e561b..0b802cdd70d0 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -643,7 +643,6 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
info->chan = chan;
tty_port_init(&info->port);
info->port.ops = &rocket_port_ops;
- init_completion(&info->close_wait);
info->flags &= ~ROCKET_MODE_MASK;
switch (pc104[board][line]) {
case 422:
@@ -960,7 +959,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
tty->alt_speed = 460800;
configure_r_port(tty, info, NULL);
- if (tty->termios.c_cflag & CBAUD) {
+ if (C_BAUD(tty)) {
sSetDTR(cp);
sSetRTS(cp);
}
@@ -1043,13 +1042,12 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
}
}
spin_lock_irq(&port->lock);
- info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
+ info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
tty->closing = 0;
spin_unlock_irq(&port->lock);
mutex_unlock(&port->mutex);
tty_port_tty_set(port, NULL);
- complete_all(&info->close_wait);
atomic_dec(&rp_num_ports_open);
#ifdef ROCKET_DEBUG_OPEN
@@ -1086,18 +1084,18 @@ static void rp_set_termios(struct tty_struct *tty,
cp = &info->channel;
/* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
sClrDTR(cp);
sClrRTS(cp);
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
sSetRTS(cp);
sSetDTR(cp);
}
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
rp_start(tty);
}
@@ -1360,8 +1358,7 @@ static void rp_throttle(struct tty_struct *tty)
struct r_port *info = tty->driver_data;
#ifdef ROCKET_DEBUG_THROTTLE
- printk(KERN_INFO "throttle %s: %d....\n", tty->name,
- tty->ldisc.chars_in_buffer(tty));
+ printk(KERN_INFO "throttle %s ....\n", tty->name);
#endif
if (rocket_paranoia_check(info, "rp_throttle"))
@@ -1377,8 +1374,7 @@ static void rp_unthrottle(struct tty_struct *tty)
{
struct r_port *info = tty->driver_data;
#ifdef ROCKET_DEBUG_THROTTLE
- printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
- tty->ldisc.chars_in_buffer(tty));
+ printk(KERN_INFO "unthrottle %s ....\n", tty->name);
#endif
if (rocket_paranoia_check(info, "rp_unthrottle"))
diff --git a/drivers/tty/rocket_int.h b/drivers/tty/rocket_int.h
index 67e0f1e778a2..ef1e1be6b26d 100644
--- a/drivers/tty/rocket_int.h
+++ b/drivers/tty/rocket_int.h
@@ -1144,7 +1144,6 @@ struct r_port {
int read_status_mask;
int cps;
- struct completion close_wait; /* Not yet matching the core */
spinlock_t slock;
struct mutex write_mtx;
};
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
deleted file mode 100644
index 0140ba4aacde..000000000000
--- a/drivers/tty/serial/68328serial.c
+++ /dev/null
@@ -1,1322 +0,0 @@
-/* 68328serial.c: Serial port driver for 68328 microcontroller
- *
- * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
- * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
- * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
- * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
- *
- * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
- * Multiple UART support Daniel Potts <danielp@cse.unsw.edu.au>
- * Power management support Daniel Potts <danielp@cse.unsw.edu.au>
- * VZ Second Serial Port enable Phil Wilshire
- * 2.4/2.5 port David McCullough
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/serial.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/reboot.h>
-#include <linux/keyboard.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-
-/* (es) */
-/* note: perhaps we can murge these files, so that you can just
- * define 1 of them, and they can sort that out for themselves
- */
-#if defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#else
-#if defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#else
-#include <asm/MC68328.h>
-#endif /* CONFIG_M68VZ328 */
-#endif /* CONFIG_M68EZ328 */
-
-/* Turn off usage of real serial interrupt code, to "support" Copilot */
-#ifdef CONFIG_XCOPILOT_BUGS
-#undef USE_INTS
-#else
-#define USE_INTS
-#endif
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- * -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real 328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- * -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- */
-struct m68k_serial {
- struct tty_port tport;
- char is_cons; /* Is this our console. */
- int magic;
- int baud_base;
- int port;
- int irq;
- int type; /* UART type */
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int line;
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
-};
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-
-static struct m68k_serial m68k_soft[NR_PORTS];
-
-static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
-
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
-
-struct tty_driver *serial_driver;
-
-static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
-
-/*
- * Setup for console. Argument comes from the boot command line.
- */
-
-/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
-#ifdef CONFIG_M68VZ328
-#define CONSOLE_BAUD_RATE 19200
-#define DEFAULT_CBAUD B19200
-#endif
-
-
-#ifndef CONSOLE_BAUD_RATE
-#define CONSOLE_BAUD_RATE 9600
-#define DEFAULT_CBAUD B9600
-#endif
-
-
-static int m68328_console_initted = 0;
-static int m68328_console_baud = CONSOLE_BAUD_RATE;
-static int m68328_console_cbaud = DEFAULT_CBAUD;
-
-
-static inline int serial_paranoia_check(struct m68k_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char *badinfo =
- "Warning: null m68k_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-/* Utility routines */
-static inline int get_baud(struct m68k_serial *ss)
-{
- unsigned long result = 115200;
- unsigned short int baud = uart_addr[ss->line].ubaud;
- if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
- result >>= GET_FIELD(baud, UBAUD_DIVIDE);
-
- return result;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- uart->ustcnt &= ~USTCNT_TXEN;
- local_irq_restore(flags);
-}
-
-static int rs_put_char(char ch)
-{
- unsigned long flags;
- int loops = 0;
-
- local_irq_save(flags);
-
- while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
- loops++;
- udelay(5);
- }
-
- UTX_TXDATA = ch;
- udelay(5);
- local_irq_restore(flags);
- return 1;
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- local_irq_save(flags);
- if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt |= USTCNT_TXEN;
-#endif
- }
- local_irq_restore(flags);
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned char ch, flag;
-
- /*
- * This do { } while() loop will get ALL chars out of Rx FIFO
- */
-#ifndef CONFIG_XCOPILOT_BUGS
- do {
-#endif
- ch = GET_FIELD(rx, URX_RXDATA);
-
- if(info->is_cons) {
- if(URX_BREAK & rx) { /* whee, break received */
- return;
-#ifdef CONFIG_MAGIC_SYSRQ
- } else if (ch == 0x10) { /* ^P */
- show_state();
- show_free_areas(0);
- show_buffers();
-/* show_net_buffers(); */
- return;
- } else if (ch == 0x12) { /* ^R */
- emergency_restart();
- return;
-#endif /* CONFIG_MAGIC_SYSRQ */
- }
- }
-
- flag = TTY_NORMAL;
-
- if (rx & URX_PARITY_ERROR)
- flag = TTY_PARITY;
- else if (rx & URX_OVRUN)
- flag = TTY_OVERRUN;
- else if (rx & URX_FRAME_ERROR)
- flag = TTY_FRAME;
-
- tty_insert_flip_char(&info->tport, ch, flag);
-#ifndef CONFIG_XCOPILOT_BUGS
- } while((rx = uart->urx.w) & URX_DATA_READY);
-#endif
-
- tty_schedule_flip(&info->tport);
-}
-
-static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
-
- if (info->x_char) {
- /* Send next char */
- uart->utx.b.txdata = info->x_char;
- info->x_char = 0;
- goto clear_and_return;
- }
-
- if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
- /* That's peculiar... TX ints off */
- uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
- goto clear_and_return;
- }
-
- /* Send char */
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
-
- if(info->xmit_cnt <= 0) {
- /* All done for now... TX ints off */
- uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
- goto clear_and_return;
- }
-
-clear_and_return:
- /* Clear interrupt (should be auto)*/
- return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
- struct m68k_serial *info = dev_id;
- struct tty_struct *tty = tty_port_tty_get(&info->tport);
- m68328_uart *uart;
- unsigned short rx;
- unsigned short tx;
-
- uart = &uart_addr[info->line];
- rx = uart->urx.w;
-
-#ifdef USE_INTS
- tx = uart->utx.w;
-
- if (rx & URX_DATA_READY)
- receive_chars(info, rx);
- if (tx & UTX_TX_AVAIL)
- transmit_chars(info, tty);
-#else
- receive_chars(info, rx);
-#endif
- tty_kref_put(tty);
-
- return IRQ_HANDLED;
-}
-
-static int startup(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (info->tport.flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- local_irq_save(flags);
-
- /*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in change_speed())
- */
-
- uart->ustcnt = USTCNT_UEN;
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
- (void)uart->urx.w;
-
- /*
- * Finally, enable sequencing and interrupts
- */
-#ifdef USE_INTS
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN |
- USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
-#endif
-
- if (tty)
- clear_bit(TTY_IO_ERROR, &tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /*
- * and set the speed of the serial port
- */
-
- change_speed(info, tty);
-
- info->tport.flags |= ASYNC_INITIALIZED;
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- uart->ustcnt = 0; /* All off! */
- if (!(info->tport.flags & ASYNC_INITIALIZED))
- return;
-
- local_irq_save(flags);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
-
- info->tport.flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
-}
-
-struct {
- int divisor, prescale;
-}
-#ifndef CONFIG_M68VZ328
- hw_baud_table[18] = {
- {0,0}, /* 0 */
- {0,0}, /* 50 */
- {0,0}, /* 75 */
- {0,0}, /* 110 */
- {0,0}, /* 134 */
- {0,0}, /* 150 */
- {0,0}, /* 200 */
- {7,0x26}, /* 300 */
- {6,0x26}, /* 600 */
- {5,0x26}, /* 1200 */
- {0,0}, /* 1800 */
- {4,0x26}, /* 2400 */
- {3,0x26}, /* 4800 */
- {2,0x26}, /* 9600 */
- {1,0x26}, /* 19200 */
- {0,0x26}, /* 38400 */
- {1,0x38}, /* 57600 */
- {0,0x38}, /* 115200 */
-};
-#else
- hw_baud_table[18] = {
- {0,0}, /* 0 */
- {0,0}, /* 50 */
- {0,0}, /* 75 */
- {0,0}, /* 110 */
- {0,0}, /* 134 */
- {0,0}, /* 150 */
- {0,0}, /* 200 */
- {0,0}, /* 300 */
- {7,0x26}, /* 600 */
- {6,0x26}, /* 1200 */
- {0,0}, /* 1800 */
- {5,0x26}, /* 2400 */
- {4,0x26}, /* 4800 */
- {3,0x26}, /* 9600 */
- {2,0x26}, /* 19200 */
- {1,0x26}, /* 38400 */
- {0,0x26}, /* 57600 */
- {1,0x38}, /* 115200 */
-};
-#endif
-/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned short port;
- unsigned short ustcnt;
- unsigned cflag;
- int i;
-
- cflag = tty->termios.c_cflag;
- port = info->port;
- if (!port)
- return;
-
- ustcnt = uart->ustcnt;
- uart->ustcnt = ustcnt & ~USTCNT_TXEN;
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i = (i & ~CBAUDEX) + B38400;
- }
-
- uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
- PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-
- ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-
- if ((cflag & CSIZE) == CS8)
- ustcnt |= USTCNT_8_7;
-
- if (cflag & CSTOPB)
- ustcnt |= USTCNT_STOP;
-
- if (cflag & PARENB)
- ustcnt |= USTCNT_PARITYEN;
- if (cflag & PARODD)
- ustcnt |= USTCNT_ODD_EVEN;
-
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- if (cflag & CRTSCTS) {
- uart->utx.w &= ~ UTX_NOCTS;
- } else {
- uart->utx.w |= UTX_NOCTS;
- }
-#endif
-
- ustcnt |= USTCNT_TXEN;
-
- uart->ustcnt = ustcnt;
- return;
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
- int left; /* Output no more than that */
- unsigned long flags;
- struct m68k_serial *info = &m68k_soft[0];
- char c;
-
- if (info == NULL) return;
- if (info->xmit_buf == NULL) return;
-
- local_irq_save(flags);
- left = info->xmit_cnt;
- while (left != 0) {
- c = info->xmit_buf[info->xmit_tail];
- info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- local_irq_restore(flags);
-
- rs_put_char(c);
-
- local_irq_save(flags);
- left = min(info->xmit_cnt, left-1);
- }
-
- /* Last character is being transmitted now (hopefully). */
- udelay(5);
-
- local_irq_restore(flags);
- return;
-}
-
-/*
- * m68k_console_print is registered for printk.
- */
-void console_print_68328(const char *p)
-{
- char c;
-
- while((c=*(p++)) != 0) {
- if(c == '\n')
- rs_put_char('\r');
- rs_put_char(c);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- rs_fair_output();
-
- return;
-}
-
-static void rs_set_ldisc(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
- return;
-
- info->is_cons = (tty->termios.c_line == N_TTY);
-
- printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-#ifndef USE_INTS
- for(;;) {
-#endif
-
- /* Enable transmitter */
- local_irq_save(flags);
-
- if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
- local_irq_restore(flags);
- return;
- }
-
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt |= USTCNT_TXEN;
-#endif
-
-#ifdef USE_INTS
- if (uart->utx.w & UTX_TX_AVAIL) {
-#else
- if (1) {
-#endif
- /* Send char */
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
-
-#ifndef USE_INTS
- while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
- }
-#endif
- local_irq_restore(flags);
-}
-
-extern void console_printn(const char * b, int count);
-
-static int rs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, total = 0;
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- local_save_flags(flags);
- while (1) {
- local_irq_disable();
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- local_irq_restore(flags);
-
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
- local_irq_disable();
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- local_irq_restore(flags);
- buf += c;
- count -= c;
- total += c;
- }
-
- if (info->xmit_cnt && !tty->stopped) {
- /* Enable transmitter */
- local_irq_disable();
-#ifndef USE_INTS
- while(info->xmit_cnt) {
-#endif
-
- uart->ustcnt |= USTCNT_TXEN;
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TX_INTR_MASK;
-#else
- while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-#endif
- if (uart->utx.w & UTX_TX_AVAIL) {
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
-
-#ifndef USE_INTS
- }
-#endif
- local_irq_restore(flags);
- }
-
- return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- local_irq_save(flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- local_irq_restore(flags);
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
-
- /* Turn off RTS line (do this atomic) */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
-
- /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct m68k_serial * info,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->tport.flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->tport.close_delay;
- tmp.closing_wait = info->tport.closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
- return 0;
-}
-
-static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
- struct serial_struct * new_info)
-{
- struct tty_port *port = &info->tport;
- struct serial_struct new_serial;
- struct m68k_serial old_info;
- int retval = 0;
-
- if (!new_info)
- return -EFAULT;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != port->close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (port->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->type = new_serial.type;
- port->close_delay = new_serial.close_delay;
- port->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- retval = startup(info, tty);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
-{
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- m68328_uart *uart = &uart_addr[info->line];
-#endif
- unsigned char status;
- unsigned long flags;
-
- local_irq_save(flags);
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
-#else
- status = 0;
-#endif
- local_irq_restore(flags);
- return put_user(status, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(struct m68k_serial * info, unsigned int duration)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
- if (!info->port)
- return;
- local_irq_save(flags);
-#ifdef USE_INTS
- uart->utx.w |= UTX_SEND_BREAK;
- msleep_interruptible(duration);
- uart->utx.w &= ~UTX_SEND_BREAK;
-#endif
- local_irq_restore(flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
- int retval;
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- send_break(info, 250); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- send_break(info, arg ? arg*(100) : 250);
- return 0;
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info, tty,
- (struct serial_struct *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct m68k_serial *) arg,
- info, sizeof(struct m68k_serial)))
- return -EFAULT;
- return 0;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- change_speed(info, tty);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
- rs_start(tty);
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
- struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
- struct tty_port *port = &info->tport;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- local_irq_save(flags);
-
- if (tty_hung_up_p(filp)) {
- local_irq_restore(flags);
- return;
- }
-
- if ((tty->count == 1) && (port->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "port->count is %d\n", port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk("rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, port->count);
- port->count = 0;
- }
- if (port->count) {
- local_irq_restore(flags);
- return;
- }
- port->flags |= ASYNC_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, port->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
-
- uart->ustcnt &= ~USTCNT_RXEN;
- uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
-
- shutdown(info, tty);
- rs_flush_buffer(tty);
-
- tty_ldisc_flush(tty);
- tty->closing = 0;
- tty_port_tty_set(&info->tport, NULL);
-#warning "This is not and has never been valid so fix it"
-#if 0
- if (tty->ldisc.num != ldiscs[N_TTY].num) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios.c_line = N_TTY;
- if (tty->ldisc.open)
- (tty->ldisc.open)(tty);
- }
-#endif
- if (port->blocked_open) {
- if (port->close_delay)
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
- wake_up_interruptible(&port->open_wait);
- }
- port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- local_irq_restore(flags);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void rs_hangup(struct tty_struct *tty)
-{
- struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info, tty);
- info->tport.count = 0;
- info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
- tty_port_tty_set(&info->tport, NULL);
- wake_up_interruptible(&info->tport.open_wait);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its S structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-int rs_open(struct tty_struct *tty, struct file * filp)
-{
- struct m68k_serial *info;
- int retval;
-
- info = &m68k_soft[tty->index];
-
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-
- info->tport.count++;
- tty->driver_data = info;
- tty_port_tty_set(&info->tport, tty);
-
- /*
- * Start up serial port
- */
- retval = startup(info, tty);
- if (retval)
- return retval;
-
- return tty_port_block_til_ready(&info->tport, tty, filp);
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
- printk("MC68328 serial driver version 1.00\n");
-}
-
-static const struct tty_operations rs_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .set_ldisc = rs_set_ldisc,
-};
-
-static const struct tty_port_operations rs_port_ops = {
-};
-
-/* rs_init inits the driver */
-static int __init
-rs68328_init(void)
-{
- unsigned long flags;
- int i;
- struct m68k_serial *info;
-
- serial_driver = alloc_tty_driver(NR_PORTS);
- if (!serial_driver)
- return -ENOMEM;
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* SPARC: Not all of this is exactly right for us. */
-
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &rs_ops);
-
- local_irq_save(flags);
-
- for(i=0;i<NR_PORTS;i++) {
-
- info = &m68k_soft[i];
- tty_port_init(&info->tport);
- info->tport.ops = &rs_port_ops;
- info->magic = SERIAL_MAGIC;
- info->port = (int) &uart_addr[i];
- info->irq = uart_irqs[i];
- info->custom_divisor = 16;
- info->x_char = 0;
- info->line = i;
- info->is_cons = 1; /* Means shortcuts work */
-
- printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line,
- info->port, info->irq);
- printk(" is a builtin MC68328 UART\n");
-
-#ifdef CONFIG_M68VZ328
- if (i > 0 )
- PJSEL &= 0xCF; /* PSW enable second port output */
-#endif
-
- if (request_irq(uart_irqs[i],
- rs_interrupt,
- 0,
- "M68328_UART", info))
- panic("Unable to attach 68328 serial interrupt\n");
-
- tty_port_link_device(&info->tport, serial_driver, i);
- }
- local_irq_restore(flags);
-
- if (tty_register_driver(serial_driver)) {
- put_tty_driver(serial_driver);
- for (i = 0; i < NR_PORTS; i++)
- tty_port_destroy(&m68k_soft[i].tport);
- printk(KERN_ERR "Couldn't register serial driver\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-module_init(rs68328_init);
-
-
-
-static void m68328_set_baud(void)
-{
- unsigned short ustcnt;
- int i;
-
- ustcnt = USTCNT;
- USTCNT = ustcnt & ~USTCNT_TXEN;
-
-again:
- for (i = 0; i < ARRAY_SIZE(baud_table); i++)
- if (baud_table[i] == m68328_console_baud)
- break;
- if (i >= ARRAY_SIZE(baud_table)) {
- m68328_console_baud = 9600;
- goto again;
- }
-
- UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
- PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
- ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
- ustcnt |= USTCNT_8_7;
- ustcnt |= USTCNT_TXEN;
- USTCNT = ustcnt;
- m68328_console_initted = 1;
- return;
-}
-
-
-int m68328_console_setup(struct console *cp, char *arg)
-{
- int i, n = CONSOLE_BAUD_RATE;
-
- if (!cp)
- return(-1);
-
- if (arg)
- n = simple_strtoul(arg,NULL,0);
-
- for (i = 0; i < ARRAY_SIZE(baud_table); i++)
- if (baud_table[i] == n)
- break;
- if (i < ARRAY_SIZE(baud_table)) {
- m68328_console_baud = n;
- m68328_console_cbaud = 0;
- if (i > 15) {
- m68328_console_cbaud |= CBAUDEX;
- i -= 15;
- }
- m68328_console_cbaud |= i;
- }
-
- m68328_set_baud(); /* make sure baud rate changes */
- return(0);
-}
-
-
-static struct tty_driver *m68328_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-
-void m68328_console_write (struct console *co, const char *str,
- unsigned int count)
-{
- if (!m68328_console_initted)
- m68328_set_baud();
- while (count--) {
- if (*str == '\n')
- rs_put_char('\r');
- rs_put_char( *str++ );
- }
-}
-
-
-static struct console m68328_driver = {
- .name = "ttyS",
- .write = m68328_console_write,
- .device = m68328_console_device,
- .setup = m68328_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-
-static int __init m68328_console_init(void)
-{
- register_console(&m68328_driver);
- return 0;
-}
-
-console_initcall(m68328_console_init);
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index d54dcd87c67e..047a7ba6796a 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -92,6 +92,18 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0
#endif
+#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF | (_flags), \
+ }
+
+#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
+
+
static inline int serial_in(struct uart_8250_port *up, int offset)
{
return up->port.serial_in(&up->port, offset);
@@ -117,6 +129,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
+int serial8250_em485_init(struct uart_8250_port *p);
+void serial8250_em485_destroy(struct uart_8250_port *p);
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
diff --git a/drivers/tty/serial/8250/8250_accent.c b/drivers/tty/serial/8250/8250_accent.c
index 34b51c651192..522aeae05192 100644
--- a/drivers/tty/serial/8250/8250_accent.c
+++ b/drivers/tty/serial/8250/8250_accent.c
@@ -10,18 +10,11 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port accent_data[] = {
- PORT(0x330, 4),
- PORT(0x338, 4),
+ SERIAL8250_PORT(0x330, 4),
+ SERIAL8250_PORT(0x338, 4),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index 549aa07c0d27..402dfdd4940e 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -70,7 +70,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
uart.port.regshift = 2;
uart.port.dev = &ec->dev;
- for (i = 0; i < info->num_ports; i ++) {
+ for (i = 0; i < info->num_ports; i++) {
uart.port.membase = info->vaddr + type->offset[i];
uart.port.mapbase = bus_addr + type->offset[i];
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
new file mode 100644
index 000000000000..e10f1244409b
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -0,0 +1,146 @@
+/*
+ * Serial port driver for BCM2835AUX UART
+ *
+ * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
+ *
+ * Based on 8250_lpc18xx.c:
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.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/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+struct bcm2835aux_data {
+ struct uart_8250_port uart;
+ struct clk *clk;
+ int line;
+};
+
+static int bcm2835aux_serial_probe(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data;
+ struct resource *res;
+ int ret;
+
+ /* allocate the custom structure */
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* initialize data */
+ spin_lock_init(&data->uart.port.lock);
+ data->uart.capabilities = UART_CAP_FIFO;
+ data->uart.port.dev = &pdev->dev;
+ data->uart.port.regshift = 2;
+ data->uart.port.type = PORT_16550;
+ data->uart.port.iotype = UPIO_MEM;
+ data->uart.port.fifosize = 8;
+ data->uart.port.flags = UPF_SHARE_IRQ |
+ UPF_FIXED_PORT |
+ UPF_FIXED_TYPE |
+ UPF_SKIP_TEST;
+
+ /* get the clock - this also enables the HW */
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ ret = PTR_ERR_OR_ZERO(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
+ return ret;
+ }
+
+ /* get the interrupt */
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "irq not found - %i", ret);
+ return ret;
+ }
+ data->uart.port.irq = ret;
+
+ /* map the main registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "memory resource not found");
+ return -EINVAL;
+ }
+ data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res);
+ ret = PTR_ERR_OR_ZERO(data->uart.port.membase);
+ if (ret)
+ return ret;
+
+ /* Check for a fixed line number */
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ data->uart.port.line = ret;
+
+ /* enable the clock as a last step */
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
+ ret);
+ return ret;
+ }
+
+ /* the HW-clock divider for bcm2835aux is 8,
+ * but 8250 expects a divider of 16,
+ * so we have to multiply the actual clock by 2
+ * to get identical baudrates.
+ */
+ data->uart.port.uartclk = clk_get_rate(data->clk) * 2;
+
+ /* register the port */
+ ret = serial8250_register_8250_port(&data->uart);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port - %d\n",
+ ret);
+ goto dis_clk;
+ }
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+dis_clk:
+ clk_disable_unprepare(data->clk);
+ return ret;
+}
+
+static int bcm2835aux_serial_remove(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->uart.port.line);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835aux_serial_match[] = {
+ { .compatible = "brcm,bcm2835-aux-uart" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
+
+static struct platform_driver bcm2835aux_serial_driver = {
+ .driver = {
+ .name = "bcm2835-aux-uart",
+ .of_match_table = bcm2835aux_serial_match,
+ },
+ .probe = bcm2835aux_serial_probe,
+ .remove = bcm2835aux_serial_remove,
+};
+module_platform_driver(bcm2835aux_serial_driver);
+
+MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
+MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_boca.c b/drivers/tty/serial/8250/8250_boca.c
index d125dc107985..a63b5998e383 100644
--- a/drivers/tty/serial/8250/8250_boca.c
+++ b/drivers/tty/serial/8250/8250_boca.c
@@ -10,32 +10,25 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port boca_data[] = {
- PORT(0x100, 12),
- PORT(0x108, 12),
- PORT(0x110, 12),
- PORT(0x118, 12),
- PORT(0x120, 12),
- PORT(0x128, 12),
- PORT(0x130, 12),
- PORT(0x138, 12),
- PORT(0x140, 12),
- PORT(0x148, 12),
- PORT(0x150, 12),
- PORT(0x158, 12),
- PORT(0x160, 12),
- PORT(0x168, 12),
- PORT(0x170, 12),
- PORT(0x178, 12),
+ SERIAL8250_PORT(0x100, 12),
+ SERIAL8250_PORT(0x108, 12),
+ SERIAL8250_PORT(0x110, 12),
+ SERIAL8250_PORT(0x118, 12),
+ SERIAL8250_PORT(0x120, 12),
+ SERIAL8250_PORT(0x128, 12),
+ SERIAL8250_PORT(0x130, 12),
+ SERIAL8250_PORT(0x138, 12),
+ SERIAL8250_PORT(0x140, 12),
+ SERIAL8250_PORT(0x148, 12),
+ SERIAL8250_PORT(0x150, 12),
+ SERIAL8250_PORT(0x158, 12),
+ SERIAL8250_PORT(0x160, 12),
+ SERIAL8250_PORT(0x168, 12),
+ SERIAL8250_PORT(0x170, 12),
+ SERIAL8250_PORT(0x178, 12),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 39126460c1f5..2f4f5ee651db 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -597,6 +597,7 @@ static void univ8250_console_write(struct console *co, const char *s,
static int univ8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
+ int retval;
/*
* Check whether an invalid uart number has been specified, and
@@ -609,7 +610,10 @@ static int univ8250_console_setup(struct console *co, char *options)
/* link port to console */
port->cons = co;
- return serial8250_console_setup(port, options, false);
+ retval = serial8250_console_setup(port, options, false);
+ if (retval != 0)
+ port->cons = NULL;
+ return retval;
}
/**
@@ -620,7 +624,7 @@ static int univ8250_console_setup(struct console *co, char *options)
* @options: ptr to option string from console command line
*
* Only attempts to match console command lines of the form:
- * console=uart[8250],io|mmio|mmio32,<addr>[,<options>]
+ * console=uart[8250],io|mmio|mmio16|mmio32,<addr>[,<options>]
* console=uart[8250],0x<addr>[,<options>]
* This form is used to register an initial earlycon boot console and
* replace it with the serial8250_console at 8250 driver init.
@@ -650,8 +654,9 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
if (port->iotype != iotype)
continue;
- if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) &&
- (port->mapbase != addr))
+ if ((iotype == UPIO_MEM || iotype == UPIO_MEM16 ||
+ iotype == UPIO_MEM32 || iotype == UPIO_MEM32BE)
+ && (port->mapbase != addr))
continue;
if (iotype == UPIO_PORT && port->iobase != addr)
continue;
@@ -686,7 +691,7 @@ static int __init univ8250_console_init(void)
}
console_initcall(univ8250_console_init);
-#define SERIAL8250_CONSOLE &univ8250_console
+#define SERIAL8250_CONSOLE (&univ8250_console)
#else
#define SERIAL8250_CONSOLE NULL
#endif
@@ -763,6 +768,7 @@ void serial8250_suspend_port(int line)
uart_suspend_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_suspend_port);
/**
* serial8250_resume_port - resume one serial port
@@ -788,6 +794,7 @@ void serial8250_resume_port(int line)
}
uart_resume_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_resume_port);
/*
* Register a set of serial devices attached to a platform device. The
@@ -1067,6 +1074,15 @@ void serial8250_unregister_port(int line)
struct uart_8250_port *uart = &serial8250_ports[line];
mutex_lock(&serial_mutex);
+
+ if (uart->em485) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ serial8250_em485_destroy(uart);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+ }
+
uart_remove_one_port(&serial8250_reg, &uart->port);
if (serial8250_isa_devs) {
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
@@ -1092,9 +1108,8 @@ static int __init serial8250_init(void)
serial8250_isa_init_ports();
- printk(KERN_INFO "Serial: 8250/16550 driver, "
- "%d ports, IRQ sharing %sabled\n", nr_uarts,
- share_irqs ? "en" : "dis");
+ pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
+ nr_uarts, share_irqs ? "en" : "dis");
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
@@ -1167,15 +1182,11 @@ static void __exit serial8250_exit(void)
module_init(serial8250_init);
module_exit(serial8250_exit);
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
module_param(share_irqs, uint, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
- " (unsafe)");
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a5d319e4aae6..a3fb95d85d7c 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -68,12 +68,6 @@ struct dw8250_data {
unsigned int uart_16550_compatible:1;
};
-#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 inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -95,25 +89,45 @@ static void dw8250_force_idle(struct uart_port *p)
(void)p->serial_in(p, UART_RX);
}
-static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+static void dw8250_check_lcr(struct uart_port *p, int value)
{
- writeb(value, p->membase + (offset << p->regshift));
+ void __iomem *offset = p->membase + (UART_LCR << p->regshift);
+ int tries = 1000;
/* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writeb(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
+ while (tries--) {
+ unsigned int lcr = p->serial_in(p, UART_LCR);
+
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
+
+ dw8250_force_idle(p);
+
+#ifdef CONFIG_64BIT
+ __raw_writeq(value & 0xff, offset);
+#else
+ if (p->iotype == UPIO_MEM32)
+ writel(value, offset);
+ else if (p->iotype == UPIO_MEM32BE)
+ iowrite32be(value, offset);
+ else
+ writeb(value, offset);
+#endif
}
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
+}
+
+static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ writeb(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
@@ -135,49 +149,26 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
__raw_readq(p->membase + (UART_LCR << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- __raw_writeq(value & 0xff,
- p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
#endif /* CONFIG_64BIT */
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
writel(value, p->membase + (offset << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writel(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
@@ -187,14 +178,33 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
return dw8250_modify_msr(p, offset, value);
}
+static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ iowrite32be(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
+}
+
+static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
+{
+ unsigned int value = ioread32be(p->membase + (offset << p->regshift));
+
+ return dw8250_modify_msr(p, offset, value);
+}
+
+
static int dw8250_handle_irq(struct uart_port *p)
{
struct dw8250_data *d = p->private_data;
unsigned int iir = p->serial_in(p, UART_IIR);
- if (serial8250_handle_irq(p, iir)) {
+ if (serial8250_handle_irq(p, iir))
return 1;
- } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+
+ if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
(void)p->serial_in(p, d->usr_reg);
@@ -281,6 +291,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
data->skip_autocfg = true;
}
#endif
+ if (of_device_is_big_endian(p->dev->of_node)) {
+ p->iotype = UPIO_MEM32BE;
+ p->serial_in = dw8250_serial_in32be;
+ p->serial_out = dw8250_serial_out32be;
+ }
} else if (has_acpi_companion(p->dev)) {
p->iotype = UPIO_MEM32;
p->regshift = 2;
@@ -309,14 +324,20 @@ static void dw8250_setup_port(struct uart_port *p)
* If the Component Version Register returns zero, we know that
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
*/
- reg = readl(p->membase + DW_UART_UCV);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_UCV);
+ else
+ reg = readl(p->membase + DW_UART_UCV);
if (!reg)
return;
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
- reg = readl(p->membase + DW_UART_CPR);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_CPR);
+ else
+ reg = readl(p->membase + DW_UART_CPR);
if (!reg)
return;
@@ -463,10 +484,8 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible) {
- p->serial_out = NULL;
+ if (data->uart_16550_compatible)
p->handle_irq = NULL;
- }
if (!data->skip_autocfg)
dw8250_setup_port(p);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index ceb85792a5cf..8d08ff5c4e34 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -39,13 +39,17 @@
static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
return readb(port->membase + offset);
+ case UPIO_MEM16:
+ return readw(port->membase + offset);
case UPIO_MEM32:
- return readl(port->membase + (offset << 2));
+ return readl(port->membase + offset);
case UPIO_MEM32BE:
- return ioread32be(port->membase + (offset << 2));
+ return ioread32be(port->membase + offset);
case UPIO_PORT:
return inb(port->iobase + offset);
default:
@@ -55,15 +59,20 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
static void __init serial8250_early_out(struct uart_port *port, int offset, int value)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
writeb(value, port->membase + offset);
break;
+ case UPIO_MEM16:
+ writew(value, port->membase + offset);
+ break;
case UPIO_MEM32:
- writel(value, port->membase + (offset << 2));
+ writel(value, port->membase + offset);
break;
case UPIO_MEM32BE:
- iowrite32be(value, port->membase + (offset << 2));
+ iowrite32be(value, port->membase + offset);
break;
case UPIO_PORT:
outb(value, port->iobase + offset);
@@ -73,43 +82,27 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-static void __init wait_for_xmitr(struct uart_port *port)
+static void __init serial_putc(struct uart_port *port, int c)
{
unsigned int status;
+ serial8250_early_out(port, UART_TX, c);
+
for (;;) {
status = serial8250_early_in(port, UART_LSR);
if ((status & BOTH_EMPTY) == BOTH_EMPTY)
- return;
+ break;
cpu_relax();
}
}
-static void __init serial_putc(struct uart_port *port, int c)
-{
- wait_for_xmitr(port);
- serial8250_early_out(port, UART_TX, c);
-}
-
static void __init early_serial8250_write(struct console *console,
const char *s, unsigned int count)
{
struct earlycon_device *device = console->data;
struct uart_port *port = &device->port;
- unsigned int ier;
-
- /* Save the IER and disable interrupts preserving the UUE bit */
- ier = serial8250_early_in(port, UART_IER);
- if (ier)
- serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
uart_console_write(port, s, count, serial_putc);
-
- /* Wait for transmitter to become empty and restore the IER */
- wait_for_xmitr(port);
-
- if (ier)
- serial8250_early_out(port, UART_IER, ier);
}
static void __init init_port(struct earlycon_device *device)
@@ -156,3 +149,25 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
+OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
+
+#ifdef CONFIG_SERIAL_8250_OMAP
+
+static int __init early_omap8250_setup(struct earlycon_device *device,
+ const char *options)
+{
+ struct uart_port *port = &device->port;
+
+ if (!(device->port.membase || device->port.iobase))
+ return -ENODEV;
+
+ port->regshift = 2;
+ device->con->write = early_serial8250_write;
+ return 0;
+}
+
+OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
+
+#endif
diff --git a/drivers/tty/serial/8250/8250_exar_st16c554.c b/drivers/tty/serial/8250/8250_exar_st16c554.c
index bf53aabf9b5e..3a7cb8262bb9 100644
--- a/drivers/tty/serial/8250/8250_exar_st16c554.c
+++ b/drivers/tty/serial/8250/8250_exar_st16c554.c
@@ -13,20 +13,13 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port exar_data[] = {
- PORT(0x100, 5),
- PORT(0x108, 5),
- PORT(0x110, 5),
- PORT(0x118, 5),
+ SERIAL8250_PORT(0x100, 5),
+ SERIAL8250_PORT(0x108, 5),
+ SERIAL8250_PORT(0x110, 5),
+ SERIAL8250_PORT(0x118, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_fourport.c b/drivers/tty/serial/8250/8250_fourport.c
index be1582609626..4045180a8cfc 100644
--- a/drivers/tty/serial/8250/8250_fourport.c
+++ b/drivers/tty/serial/8250/8250_fourport.c
@@ -10,24 +10,20 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \
- }
+#include "8250.h"
+
+#define SERIAL8250_FOURPORT(_base, _irq) \
+ SERIAL8250_PORT_FLAGS(_base, _irq, UPF_FOURPORT)
static struct plat_serial8250_port fourport_data[] = {
- PORT(0x1a0, 9),
- PORT(0x1a8, 9),
- PORT(0x1b0, 9),
- PORT(0x1b8, 9),
- PORT(0x2a0, 5),
- PORT(0x2a8, 5),
- PORT(0x2b0, 5),
- PORT(0x2b8, 5),
+ SERIAL8250_FOURPORT(0x1a0, 9),
+ SERIAL8250_FOURPORT(0x1a8, 9),
+ SERIAL8250_FOURPORT(0x1b0, 9),
+ SERIAL8250_FOURPORT(0x1b8, 9),
+ SERIAL8250_FOURPORT(0x2a0, 5),
+ SERIAL8250_FOURPORT(0x2a8, 5),
+ SERIAL8250_FOURPORT(0x2b0, 5),
+ SERIAL8250_FOURPORT(0x2b8, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index 2e3ea1a70d7b..b1e6ae9f1ff9 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -42,7 +42,7 @@ static int __init serial_init_chip(struct parisc_device *dev)
* the user what they're missing.
*/
if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
- printk(KERN_INFO
+ dev_info(&dev->dev,
"Serial: device 0x%llx not configured.\n"
"Enable support for Wax, Lasi, Asp or Dino.\n",
(unsigned long long)dev->hpa.start);
@@ -66,8 +66,9 @@ static int __init serial_init_chip(struct parisc_device *dev)
err = serial8250_register_8250_port(&uart);
if (err < 0) {
- printk(KERN_WARNING
- "serial8250_register_8250_port returned error %d\n", err);
+ dev_warn(&dev->dev,
+ "serial8250_register_8250_port returned error %d\n",
+ err);
iounmap(uart.port.membase);
return err;
}
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index 2891958cd842..38166db2b824 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -24,8 +24,7 @@
#endif
#ifdef CONFIG_HPAPCI
-struct hp300_port
-{
+struct hp300_port {
struct hp300_port *next; /* next port */
int line; /* line (tty) number */
};
@@ -111,7 +110,7 @@ int __init hp300_setup_serial_console(void)
/* Check for APCI console */
if (scode == 256) {
#ifdef CONFIG_HPAPCI
- printk(KERN_INFO "Serial console is HP APCI 1\n");
+ pr_info("Serial console is HP APCI 1\n");
port.uartclk = HPAPCI_BAUD_BASE * 16;
port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
@@ -119,7 +118,7 @@ int __init hp300_setup_serial_console(void)
port.regshift = 2;
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+ pr_warn("Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
return 0;
#endif
} else {
@@ -128,7 +127,7 @@ int __init hp300_setup_serial_console(void)
if (!pa)
return 0;
- printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+ pr_info("Serial console is HP DCA at select code %d\n", scode);
port.uartclk = HPDCA_BAUD_BASE * 16;
port.mapbase = (pa + UART_OFFSET);
@@ -142,13 +141,13 @@ int __init hp300_setup_serial_console(void)
if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+ pr_warn("Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
return 0;
#endif
}
if (early_serial_setup(&port) < 0)
- printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+ pr_warn("%s: early_serial_setup() failed.\n", __func__);
return 0;
}
#endif /* CONFIG_SERIAL_8250_CONSOLE */
@@ -180,8 +179,9 @@ static int hpdca_init_one(struct dio_dev *d,
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
- " irq %d failed\n", d->scode, uart.port.irq);
+ dev_notice(&d->dev,
+ "8250_hp300: register_serial() DCA scode %d irq %d failed\n",
+ d->scode, uart.port.irq);
return -ENOMEM;
}
@@ -249,8 +249,8 @@ static int __init hp300_8250_init(void)
/* Memory mapped I/O */
uart.port.iotype = UPIO_MEM;
- uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
- | UPF_BOOT_AUTOCONF;
+ uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
+ | UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
uart.port.irq = 0;
uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
@@ -261,8 +261,9 @@ static int __init hp300_8250_init(void)
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
- " %d irq %d failed\n", i, uart.port.irq);
+ dev_notice(uart.port.dev,
+ "8250_hp300: register_serial() APCI %d irq %d failed\n",
+ i, uart.port.irq);
kfree(port);
continue;
}
diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c
index a5c778e83de0..27124e21eb96 100644
--- a/drivers/tty/serial/8250/8250_hub6.c
+++ b/drivers/tty/serial/8250/8250_hub6.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define HUB6(card,port) \
+#define HUB6(card, port) \
{ \
.iobase = 0x302, \
.irq = 3, \
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 49394b4c5cfd..b0677f610863 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -48,6 +48,7 @@ static const struct of_device_id of_match[];
#define UART_MCR_MDCE BIT(7)
#define UART_MCR_FCM BIT(6)
+#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -140,6 +141,7 @@ OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
ingenic_early_console_setup);
+#endif /* CONFIG_SERIAL_EARLYCON */
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
{
@@ -152,14 +154,18 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
break;
case UART_IER:
- /* Enable receive timeout interrupt with the
- * receive line status interrupt */
+ /*
+ * Enable receive timeout interrupt with the receive line
+ * status interrupt.
+ */
value |= (value & 0x4) << 2;
break;
case UART_MCR:
- /* If we have enabled modem status IRQs we should enable modem
- * mode. */
+ /*
+ * If we have enabled modem status IRQs we should enable
+ * modem mode.
+ */
ier = p->serial_in(p, UART_IER);
if (ier & UART_IER_MSI)
diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c
new file mode 100644
index 000000000000..26eb5393a263
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_moxa.c
@@ -0,0 +1,157 @@
+/*
+ * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver.
+ *
+ * Author: Mathieu OTHACEHE <m.othacehe@gmail.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/module.h>
+#include <linux/pci.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
+#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
+#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
+#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
+#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+
+#define MOXA_BASE_BAUD 921600
+#define MOXA_UART_OFFSET 0x200
+#define MOXA_BASE_BAR 1
+
+struct moxa8250_board {
+ unsigned int num_ports;
+ int line[0];
+};
+
+enum {
+ moxa8250_2p = 0,
+ moxa8250_4p,
+ moxa8250_8p
+};
+
+static struct moxa8250_board moxa8250_boards[] = {
+ [moxa8250_2p] = { .num_ports = 2},
+ [moxa8250_4p] = { .num_ports = 4},
+ [moxa8250_8p] = { .num_ports = 8},
+};
+
+static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct uart_8250_port uart;
+ struct moxa8250_board *brd;
+ void __iomem *ioaddr;
+ resource_size_t baseaddr;
+ unsigned int i, nr_ports;
+ unsigned int offset;
+ int ret;
+
+ brd = &moxa8250_boards[id->driver_data];
+ nr_ports = brd->num_ports;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) +
+ sizeof(unsigned int) * nr_ports, GFP_KERNEL);
+ if (!brd)
+ return -ENOMEM;
+
+ memset(&uart, 0, sizeof(struct uart_8250_port));
+
+ uart.port.dev = &pdev->dev;
+ uart.port.irq = pdev->irq;
+ uart.port.uartclk = MOXA_BASE_BAUD * 16;
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+ baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR);
+ ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0);
+ if (!ioaddr)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_ports; i++) {
+
+ /*
+ * MOXA Smartio MUE boards with 4 ports have
+ * a different offset for port #3
+ */
+ if (nr_ports == 4 && i == 3)
+ offset = 7 * MOXA_UART_OFFSET;
+ else
+ offset = i * MOXA_UART_OFFSET;
+
+ uart.port.iotype = UPIO_MEM;
+ uart.port.iobase = 0;
+ uart.port.mapbase = baseaddr + offset;
+ uart.port.membase = ioaddr + offset;
+ uart.port.regshift = 0;
+
+ dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
+
+ brd->line[i] = serial8250_register_8250_port(&uart);
+ if (brd->line[i] < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ uart.port.iobase, uart.port.irq,
+ uart.port.iotype, brd->line[i]);
+ break;
+ }
+ }
+
+ pci_set_drvdata(pdev, brd);
+ return 0;
+}
+
+static void moxa8250_remove(struct pci_dev *pdev)
+{
+ struct moxa8250_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->num_ports; i++)
+ serial8250_unregister_port(brd->line[i]);
+}
+
+#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data }
+
+static const struct pci_device_id pci_ids[] = {
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver moxa8250_pci_driver = {
+ .name = "8250_moxa",
+ .id_table = pci_ids,
+ .probe = moxa8250_probe,
+ .remove = moxa8250_remove,
+};
+
+module_pci_driver(moxa8250_pci_driver);
+
+MODULE_AUTHOR("Mathieu OTHACEHE");
+MODULE_DESCRIPTION("MOXA SmartIO MUE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 78883ca64ddd..3489fbcb7313 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -41,12 +41,10 @@ static void
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
unsigned int baud, quot;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
-
serial8250_do_set_termios(port, termios, old);
/*
@@ -116,7 +114,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
tty_termios_encode_baud_rate(termios, baud, baud);
}
-static int mtk8250_runtime_suspend(struct device *dev)
+static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -126,7 +124,7 @@ static int mtk8250_runtime_suspend(struct device *dev)
return 0;
}
-static int mtk8250_runtime_resume(struct device *dev)
+static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
int err;
@@ -262,8 +260,7 @@ static int mtk8250_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int mtk8250_suspend(struct device *dev)
+static int __maybe_unused mtk8250_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -272,7 +269,7 @@ static int mtk8250_suspend(struct device *dev)
return 0;
}
-static int mtk8250_resume(struct device *dev)
+static int __maybe_unused mtk8250_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -280,7 +277,6 @@ static int mtk8250_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops mtk8250_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
@@ -305,7 +301,7 @@ static struct platform_driver mtk8250_platform_driver = {
};
module_platform_driver(mtk8250_platform_driver);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init early_mtk8250_setup(struct earlycon_device *device,
const char *options)
{
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/8250/8250_of.c
index de5029649795..c7ed3d2bc8b2 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -18,14 +18,9 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-#include <linux/nwpserial.h>
#include <linux/clk.h>
-#ifdef CONFIG_SERIAL_8250_MODULE
-#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE
-#endif
-
-#include "8250/8250.h"
+#include "8250.h"
struct of_serial_info {
struct clk *clk;
@@ -122,6 +117,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
case 1:
port->iotype = UPIO_MEM;
break;
+ case 2:
+ port->iotype = UPIO_MEM16;
+ break;
case 4:
port->iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32;
@@ -195,7 +193,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
goto out;
switch (port_type) {
-#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
{
struct uart_8250_port port8250;
@@ -212,12 +209,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
ret = serial8250_register_8250_port(&port8250);
break;
}
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- case PORT_NWPSERIAL:
- ret = nwpserial_register_port(&port);
- break;
-#endif
default:
/* need to add code for these */
case PORT_UNKNOWN:
@@ -245,16 +236,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
{
struct of_serial_info *info = platform_get_drvdata(ofdev);
switch (info->type) {
-#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
serial8250_unregister_port(info->line);
break;
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- case PORT_NWPSERIAL:
- nwpserial_unregister_port(info->line);
- break;
-#endif
default:
/* need to add code for these */
break;
@@ -267,7 +251,6 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
}
#ifdef CONFIG_PM_SLEEP
-#ifdef CONFIG_SERIAL_8250
static void of_serial_suspend_8250(struct of_serial_info *info)
{
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
@@ -288,15 +271,6 @@ static void of_serial_resume_8250(struct of_serial_info *info)
serial8250_resume_port(info->line);
}
-#else
-static inline void of_serial_suspend_8250(struct of_serial_info *info)
-{
-}
-
-static inline void of_serial_resume_8250(struct of_serial_info *info)
-{
-}
-#endif
static int of_serial_suspend(struct device *dev)
{
@@ -353,10 +327,6 @@ static const struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_XSCALE, },
{ .compatible = "mrvl,pxa-uart",
.data = (void *)PORT_XSCALE, },
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- { .compatible = "ibm,qpace-nwp-serial",
- .data = (void *)PORT_NWPSERIAL, },
-#endif
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
@@ -365,6 +335,7 @@ static struct platform_driver of_platform_serial_driver = {
.driver = {
.name = "of_serial",
.of_match_table = of_platform_serial_table,
+ .pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
.remove = of_platform_serial_remove,
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index a2c0734c76e2..6f760510e46d 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -318,8 +318,7 @@ static void omap_8250_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
unsigned char cval = 0;
unsigned int baud;
@@ -682,9 +681,8 @@ static void omap_8250_shutdown(struct uart_port *port)
static void omap_8250_throttle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -697,11 +695,40 @@ static void omap_8250_throttle(struct uart_port *port)
pm_runtime_put_autosuspend(port->dev);
}
+static int omap_8250_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /* Clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ port->rs485 = *rs485;
+
+ /*
+ * Both serial8250_em485_init and serial8250_em485_destroy
+ * are idempotent
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ int ret = serial8250_em485_init(up);
+
+ if (ret) {
+ rs485->flags &= ~SER_RS485_ENABLED;
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+ return ret;
+ }
+
+ serial8250_em485_destroy(up);
+
+ return 0;
+}
+
static void omap_8250_unthrottle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -1146,6 +1173,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.shutdown = omap_8250_shutdown;
up.port.throttle = omap_8250_throttle;
up.port.unthrottle = omap_8250_unthrottle;
+ up.port.rs485_config = omap_8250_rs485_config;
if (pdev->dev.of_node) {
const struct of_device_id *id;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 4097f3f65b3b..98862aa5bb58 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -55,7 +55,6 @@ struct pci_serial_quirk {
struct serial_private {
struct pci_dev *dev;
unsigned int nr;
- void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES];
struct pci_serial_quirk *quirk;
int line[0];
};
@@ -85,15 +84,13 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar);
- if (!priv->remapped_bar[bar])
+ if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
return -ENOMEM;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
- port->port.membase = priv->remapped_bar[bar] + offset;
+ port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
} else {
port->port.iotype = UPIO_PORT;
@@ -721,7 +718,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
*/
pcibios_resource_to_bus(dev->bus, &region, &dev->resource[bar]);
device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
- | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
+ | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
writel(device_window, p + MITE_IOWBSR1);
/* Set window access to go to RAMSEL IO address space */
@@ -803,12 +800,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
unsigned int pi;
unsigned short sub_serports;
- pi = (c & 0xff);
+ pi = c & 0xff;
- if (pi == 2) {
+ if (pi == 2)
return 1;
- } else if ((pi == 0) &&
- (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
+
+ if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
/* two possibilities: 0x30ps encodes number of parallel and
* serial ports, or 0x1000 indicates *something*. This is not
* immediately obvious, since the 2s1p+4s configuration seems
@@ -816,12 +813,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
* advertising the same function 3 as the 4s+2s1p config.
*/
sub_serports = dev->subsystem_device & 0xf;
- if (sub_serports > 0) {
+ if (sub_serports > 0)
return sub_serports;
- } else {
- dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
- return 0;
- }
+
+ dev_err(&dev->dev,
+ "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
+ return 0;
}
moan_device("unknown NetMos/Mostech program interface", dev);
@@ -842,21 +839,21 @@ static int pci_netmos_init(struct pci_dev *dev)
return 0;
switch (dev->device) { /* FALLTHROUGH on all */
- case PCI_DEVICE_ID_NETMOS_9904:
- case PCI_DEVICE_ID_NETMOS_9912:
- case PCI_DEVICE_ID_NETMOS_9922:
- case PCI_DEVICE_ID_NETMOS_9900:
- num_serial = pci_netmos_9900_numports(dev);
- break;
+ case PCI_DEVICE_ID_NETMOS_9904:
+ case PCI_DEVICE_ID_NETMOS_9912:
+ case PCI_DEVICE_ID_NETMOS_9922:
+ case PCI_DEVICE_ID_NETMOS_9900:
+ num_serial = pci_netmos_9900_numports(dev);
+ break;
- default:
- if (num_serial == 0 ) {
- moan_device("unknown NetMos/Mostech device", dev);
- }
+ default:
+ break;
}
- if (num_serial == 0)
+ if (num_serial == 0) {
+ moan_device("unknown NetMos/Mostech device", dev);
return -ENODEV;
+ }
return num_serial;
}
@@ -1198,8 +1195,9 @@ static int pci_quatech_has_qmcr(struct uart_8250_port *port)
static int pci_quatech_test(struct uart_8250_port *port)
{
- u8 reg;
- u8 qopr = pci_quatech_rqopr(port);
+ u8 reg, qopr;
+
+ qopr = pci_quatech_rqopr(port);
pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
reg = pci_quatech_rqopr(port) & 0xC0;
if (reg != QPCR_TEST_GET1)
@@ -1286,6 +1284,7 @@ static int pci_quatech_init(struct pci_dev *dev)
unsigned long base = pci_resource_start(dev, 0);
if (base) {
u32 tmp;
+
outl(inl(base + 0x38) | 0x00002000, base + 0x38);
tmp = inl(base + 0x3c);
outl(tmp | 0x01000000, base + 0x3c);
@@ -1334,29 +1333,6 @@ static int pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
-static int pci_pericom_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- unsigned int bar, offset = board->first_offset, maxnr;
-
- bar = FL_GET_BASE(board->flags);
- if (board->flags & FL_BASE_BARS)
- bar += idx;
- else
- offset += idx * board->uart_offset;
-
- maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
- (board->reg_shift + 3);
-
- if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
- return 1;
-
- port->port.uartclk = 14745600;
-
- return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1379,6 +1355,9 @@ ce4100_serial_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a
#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c
+#define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3
+#define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4
+
#define BYT_PRV_CLK 0x800
#define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1
@@ -1461,11 +1440,13 @@ byt_serial_setup(struct serial_private *priv,
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_BYT_UART1:
case PCI_DEVICE_ID_INTEL_BSW_UART1:
+ case PCI_DEVICE_ID_INTEL_BDW_UART1:
rx_param->src_id = 3;
tx_param->dst_id = 2;
break;
case PCI_DEVICE_ID_INTEL_BYT_UART2:
case PCI_DEVICE_ID_INTEL_BSW_UART2:
+ case PCI_DEVICE_ID_INTEL_BDW_UART2:
rx_param->src_id = 5;
tx_param->dst_id = 4;
break;
@@ -1536,10 +1517,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
static int pci_fintek_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
+ struct pci_dev *pci_dev = to_pci_dev(port->dev);
u8 setting;
u8 *index = (u8 *) port->private_data;
- struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev,
- dev);
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
@@ -1761,7 +1741,7 @@ xr17v35x_has_slave(struct serial_private *priv)
const int dev_id = priv->dev->device;
return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
- (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
+ (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
}
static int
@@ -1861,8 +1841,8 @@ pci_fastcom335_setup(struct serial_private *priv,
static int
pci_wch_ch353_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
@@ -1871,8 +1851,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
static int
pci_wch_ch38x_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16850;
@@ -1936,6 +1916,7 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCIE_VENDOR_ID_WCH 0x1c00
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
+#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253
#define PCI_VENDOR_ID_PERICOM 0x12D8
#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951
@@ -2062,6 +2043,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BDW_UART1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = byt_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BDW_UART2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = byt_serial_setup,
+ },
/*
* ITE
*/
@@ -2226,16 +2221,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.exit = pci_plx9050_exit,
},
/*
- * Pericom
- */
- {
- .vendor = PCI_VENDOR_ID_PERICOM,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
- },
- /*
* PLX
*/
{
@@ -2618,6 +2603,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
+ /* WCH CH382 2S card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH382_2S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
/* WCH CH382 2S1P card (16850 clone) */
{
.vendor = PCIE_VENDOR_ID_WCH,
@@ -2936,6 +2929,7 @@ enum pci_board_num_t {
pbn_fintek_4,
pbn_fintek_8,
pbn_fintek_12,
+ pbn_wch382_2,
pbn_wch384_4,
pbn_pericom_PI7C9X7951,
pbn_pericom_PI7C9X7952,
@@ -3704,15 +3698,10 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.reg_shift = 2,
},
- /*
- * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
- * but is overridden by byt_set_termios.
- */
[pbn_byt] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 2764800,
- .uart_offset = 0x80,
.reg_shift = 2,
},
[pbn_qrk] = {
@@ -3756,6 +3745,13 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 115200,
.first_offset = 0x40,
},
+ [pbn_wch382_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ .first_offset = 0xC0,
+ },
[pbn_wch384_4] = {
.flags = FL_BASE0,
.num_ports = 4,
@@ -3804,6 +3800,20 @@ static const struct pci_device_id blacklist[] = {
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
+ /* Moxa Smartio MUE boards handled by 8250_moxa */
+ { PCI_VDEVICE(MOXA, 0x1024), },
+ { PCI_VDEVICE(MOXA, 0x1025), },
+ { PCI_VDEVICE(MOXA, 0x1045), },
+ { PCI_VDEVICE(MOXA, 0x1144), },
+ { PCI_VDEVICE(MOXA, 0x1160), },
+ { PCI_VDEVICE(MOXA, 0x1161), },
+ { PCI_VDEVICE(MOXA, 0x1182), },
+ { PCI_VDEVICE(MOXA, 0x1183), },
+ { PCI_VDEVICE(MOXA, 0x1322), },
+ { PCI_VDEVICE(MOXA, 0x1342), },
+ { PCI_VDEVICE(MOXA, 0x1381), },
+ { PCI_VDEVICE(MOXA, 0x1683), },
+
/* Intel platforms with MID UART */
{ PCI_VDEVICE(INTEL, 0x081b), },
{ PCI_VDEVICE(INTEL, 0x081c), },
@@ -3991,12 +4001,6 @@ void pciserial_remove_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
- for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
- if (priv->remapped_bar[i])
- iounmap(priv->remapped_bar[i]);
- priv->remapped_bar[i] = NULL;
- }
-
/*
* Find the exit quirks.
*/
@@ -4068,7 +4072,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
board = &pci_boards[ent->driver_data];
- rc = pci_enable_device(dev);
+ rc = pcim_enable_device(dev);
pci_save_state(dev);
if (rc)
return rc;
@@ -4087,7 +4091,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
*/
rc = serial_pci_guess_board(dev, &tmp);
if (rc)
- goto disable;
+ return rc;
} else {
/*
* We matched an explicit entry. If we are able to
@@ -4103,16 +4107,11 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
}
priv = pciserial_init_ports(dev, board);
- if (!IS_ERR(priv)) {
- pci_set_drvdata(dev, priv);
- return 0;
- }
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
- rc = PTR_ERR(priv);
-
- disable:
- pci_disable_device(dev);
- return rc;
+ pci_set_drvdata(dev, priv);
+ return 0;
}
static void pciserial_remove_one(struct pci_dev *dev)
@@ -4120,8 +4119,6 @@ static void pciserial_remove_one(struct pci_dev *dev)
struct serial_private *priv = pci_get_drvdata(dev);
pciserial_remove_ports(priv);
-
- pci_disable_device(dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -4502,7 +4499,7 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
- PCI_ANY_ID , PCI_ANY_ID, 0, 0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_1152000 },
/*
@@ -5506,6 +5503,16 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
+ /* Intel Broadwell */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
+ pbn_byt },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
+ pbn_byt },
+
/*
* Intel Quark x1000
*/
@@ -5545,6 +5552,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 },
+ { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_wch382_2 },
+
{ PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch384_4 },
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 658b392d1170..34f05ed78b68 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -357,8 +357,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* Fujitsu Wacom 1FGT Tablet PC device */
{ "FUJ02E9", 0 },
/*
- * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
- * disguise)
+ * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6
+ * in disguise).
*/
{ "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
@@ -367,12 +367,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
- /* Winbond CIR port, should not be probed. We should keep track
- of it to prevent the legacy serial driver from probing it */
+ /*
+ * Winbond CIR port, should not be probed. We should keep track of
+ * it to prevent the legacy serial driver from probing it.
+ */
{ "WEC1022", CIR_PORT },
/*
- * SMSC IrCC SIR/FIR port, should not be probed by serial driver
- * as well so its own driver can bind to it.
+ * SMSC IrCC SIR/FIR port, should not be probed by serial driver as
+ * well so its own driver can bind to it.
*/
{ "SMCF010", CIR_PORT },
{ "", 0 }
@@ -380,35 +382,35 @@ static const struct pnp_device_id pnp_dev_table[] = {
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-static char *modem_names[] = {
+static const char *modem_names[] = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
};
-static int check_name(char *name)
+static bool check_name(const char *name)
{
- char **tmp;
+ const char **tmp;
for (tmp = modem_names; *tmp; tmp++)
if (strstr(name, *tmp))
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int check_resources(struct pnp_dev *dev)
+static bool check_resources(struct pnp_dev *dev)
{
- resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
- int i;
+ static const resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(base); i++) {
if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -425,8 +427,8 @@ static int check_resources(struct pnp_dev *dev)
static int serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
- (dev->card && check_name(dev->card->name))))
- return -ENODEV;
+ (dev->card && check_name(dev->card->name))))
+ return -ENODEV;
if (check_resources(dev))
return 0;
@@ -462,11 +464,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
} else
return -ENODEV;
-#ifdef SERIAL_DEBUG_PNP
- printk(KERN_DEBUG
- "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
-#endif
+ dev_dbg(&dev->dev,
+ "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
+ uart.port.iobase, &uart.port.mapbase,
+ uart.port.irq, uart.port.iotype);
+
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 52d82d2ac726..e213da01a3d7 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/timer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -52,7 +53,7 @@
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
#endif
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Here we define the default xmit fifo size used for each type of UART.
@@ -250,9 +251,11 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
-/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
-workaround of errata A-008006 which states that tx_loadsz should be
-configured less than Maximum supported fifo bytes */
+ /*
+ * tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+ * workaround of errata A-008006 which states that tx_loadsz should
+ * be configured less than Maximum supported fifo bytes.
+ */
[PORT_16550A_FSL64] = {
.name = "16550A_FSL64",
.fifo_size = 64,
@@ -368,6 +371,18 @@ static void mem_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset);
}
+static void mem16_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = offset << p->regshift;
+ writew(value, p->membase + offset);
+}
+
+static unsigned int mem16_serial_in(struct uart_port *p, int offset)
+{
+ offset = offset << p->regshift;
+ return readw(p->membase + offset);
+}
+
static void mem32_serial_out(struct uart_port *p, int offset, int value)
{
offset = offset << p->regshift;
@@ -425,6 +440,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem_serial_out;
break;
+ case UPIO_MEM16:
+ p->serial_in = mem16_serial_in;
+ p->serial_out = mem16_serial_out;
+ break;
+
case UPIO_MEM32:
p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out;
@@ -459,6 +479,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
{
switch (p->iotype) {
case UPIO_MEM:
+ case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
@@ -504,6 +525,20 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
+static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
+{
+ unsigned char mcr = serial_in(p, UART_MCR);
+
+ if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(p, UART_MCR, mcr);
+}
+
+static void serial8250_em485_handle_start_tx(unsigned long arg);
+static void serial8250_em485_handle_stop_tx(unsigned long arg);
+
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
serial8250_clear_fifos(p);
@@ -528,6 +563,73 @@ void serial8250_rpm_put(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
+/**
+ * serial8250_em485_init() - put uart_8250_port into rs485 emulating
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to start rs485 software emulating on the
+ * &struct uart_8250_port* @p. Namely, RTS is switched before/after
+ * transmission. The function is idempotent, so it is safe to call it
+ * multiple times.
+ *
+ * The caller MUST enable interrupt on empty shift register before
+ * calling serial8250_em485_init(). This interrupt is not a part of
+ * 8250 standard, but implementation defined.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_destroy()
+ *
+ * Return 0 - success, -errno - otherwise
+ */
+int serial8250_em485_init(struct uart_8250_port *p)
+{
+ if (p->em485 != NULL)
+ return 0;
+
+ p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
+ if (p->em485 == NULL)
+ return -ENOMEM;
+
+ setup_timer(&p->em485->stop_tx_timer,
+ serial8250_em485_handle_stop_tx, (unsigned long)p);
+ setup_timer(&p->em485->start_tx_timer,
+ serial8250_em485_handle_start_tx, (unsigned long)p);
+ p->em485->active_timer = NULL;
+
+ serial8250_em485_rts_after_send(p);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_init);
+
+/**
+ * serial8250_em485_destroy() - put uart_8250_port into normal state
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to stop rs485 software emulating on the
+ * &struct uart_8250_port* @p. The function is idempotent, so it is safe to
+ * call it multiple times.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_init()
+ */
+void serial8250_em485_destroy(struct uart_8250_port *p)
+{
+ if (p->em485 == NULL)
+ return;
+
+ del_timer(&p->em485->start_tx_timer);
+ del_timer(&p->em485->stop_tx_timer);
+
+ kfree(p->em485);
+ p->em485 = NULL;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
+
/*
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
@@ -713,22 +815,16 @@ static int size_fifo(struct uart_8250_port *up)
*/
static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
{
- unsigned char old_dll, old_dlm, old_lcr;
- unsigned int id;
+ unsigned char old_lcr;
+ unsigned int id, old_dl;
old_lcr = serial_in(p, UART_LCR);
serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A);
+ old_dl = serial_dl_read(p);
+ serial_dl_write(p, 0);
+ id = serial_dl_read(p);
+ serial_dl_write(p, old_dl);
- old_dll = serial_in(p, UART_DLL);
- old_dlm = serial_in(p, UART_DLM);
-
- serial_out(p, UART_DLL, 0);
- serial_out(p, UART_DLM, 0);
-
- id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8;
-
- serial_out(p, UART_DLL, old_dll);
- serial_out(p, UART_DLM, old_dlm);
serial_out(p, UART_LCR, old_lcr);
return id;
@@ -1220,8 +1316,7 @@ static void autoconfig(struct uart_8250_port *up)
out_lock:
spin_unlock_irqrestore(&port->lock, flags);
if (up->capabilities != old_capabilities) {
- printk(KERN_WARNING
- "ttyS%d: detected caps %08x should be %08x\n",
+ pr_warn("ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities,
up->capabilities);
}
@@ -1286,7 +1381,69 @@ static void autoconfig_irq(struct uart_8250_port *up)
port->irq = (irq > 0) ? irq : 0;
}
-static inline void __stop_tx(struct uart_8250_port *p)
+static void serial8250_stop_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ serial8250_rpm_get(up);
+
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_port_out(port, UART_IER, up->ier);
+
+ serial8250_rpm_put(up);
+}
+
+static void __do_stop_tx_rs485(struct uart_8250_port *p)
+{
+ if (!p->em485)
+ return;
+
+ serial8250_em485_rts_after_send(p);
+ /*
+ * Empty the RX FIFO, we are not interested in anything
+ * received during the half-duplex transmission.
+ */
+ if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ serial8250_clear_fifos(p);
+}
+
+static void serial8250_em485_handle_stop_tx(unsigned long arg)
+{
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->stop_tx_timer) {
+ __do_stop_tx_rs485(p);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
+static void __stop_tx_rs485(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (!em485)
+ return;
+
+ /*
+ * __do_stop_tx_rs485 is going to set RTS according to config
+ * AND flush RX FIFO if required.
+ */
+ if (p->port.rs485.delay_rts_after_send > 0) {
+ em485->active_timer = &em485->stop_tx_timer;
+ mod_timer(&em485->stop_tx_timer, jiffies +
+ p->port.rs485.delay_rts_after_send * HZ / 1000);
+ } else {
+ __do_stop_tx_rs485(p);
+ }
+}
+
+static inline void __do_stop_tx(struct uart_8250_port *p)
{
if (p->ier & UART_IER_THRI) {
p->ier &= ~UART_IER_THRI;
@@ -1295,6 +1452,28 @@ static inline void __stop_tx(struct uart_8250_port *p)
}
}
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (em485) {
+ unsigned char lsr = serial_in(p, UART_LSR);
+ /*
+ * To provide required timeing and allow FIFO transfer,
+ * __stop_tx_rs485 must be called only when both FIFO and
+ * shift register are empty. It is for device driver to enable
+ * interrupt on TEMT.
+ */
+ if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+ return;
+
+ del_timer(&em485->start_tx_timer);
+ em485->active_timer = NULL;
+ }
+ __do_stop_tx(p);
+ __stop_tx_rs485(p);
+}
+
static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -1312,12 +1491,10 @@ static void serial8250_stop_tx(struct uart_port *port)
serial8250_rpm_put(up);
}
-static void serial8250_start_tx(struct uart_port *port)
+static inline void __start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- serial8250_rpm_get_tx(up);
-
if (up->dma && !up->dma->tx_dma(up))
return;
@@ -1327,6 +1504,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr;
+
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
if (lsr & UART_LSR_THRE)
@@ -1343,33 +1521,83 @@ static void serial8250_start_tx(struct uart_port *port)
}
}
-static void serial8250_throttle(struct uart_port *port)
+static inline void start_tx_rs485(struct uart_port *port)
{
- port->throttle(port);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
+ unsigned char mcr;
+
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ serial8250_stop_rx(&up->port);
+
+ del_timer(&em485->stop_tx_timer);
+ em485->active_timer = NULL;
+
+ mcr = serial_in(up, UART_MCR);
+ if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
+ !!(mcr & UART_MCR_RTS)) {
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(up, UART_MCR, mcr);
+
+ if (up->port.rs485.delay_rts_before_send > 0) {
+ em485->active_timer = &em485->start_tx_timer;
+ mod_timer(&em485->start_tx_timer, jiffies +
+ up->port.rs485.delay_rts_before_send * HZ / 1000);
+ return;
+ }
+ }
+
+ __start_tx(port);
}
-static void serial8250_unthrottle(struct uart_port *port)
+static void serial8250_em485_handle_start_tx(unsigned long arg)
{
- port->unthrottle(port);
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer) {
+ __start_tx(&p->port);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
}
-static void serial8250_stop_rx(struct uart_port *port)
+static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
- serial8250_rpm_get(up);
+ serial8250_rpm_get_tx(up);
- up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_port_out(port, UART_IER, up->ier);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer)
+ return;
- serial8250_rpm_put(up);
+ if (em485)
+ start_tx_rs485(port);
+ else
+ __start_tx(port);
+}
+
+static void serial8250_throttle(struct uart_port *port)
+{
+ port->throttle(port);
+}
+
+static void serial8250_unthrottle(struct uart_port *port)
+{
+ port->unthrottle(port);
}
static void serial8250_disable_ms(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
/* no MSR capabilities */
if (up->bugs & UART_BUG_NOMSR)
@@ -1394,81 +1622,85 @@ static void serial8250_enable_ms(struct uart_port *port)
serial8250_rpm_put(up);
}
+static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
+{
+ struct uart_port *port = &up->port;
+ unsigned char ch;
+ char flag = TTY_NORMAL;
+
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_in(up, UART_RX);
+ else
+ /*
+ * Intel 82571 has a Serial Over Lan device that will
+ * set UART_LSR_BI without setting UART_LSR_DR when
+ * it receives a break. To avoid reading from the
+ * receive buffer without UART_LSR_DR bit set, we
+ * just force the read character to be 0
+ */
+ ch = 0;
+
+ port->icount.rx++;
+
+ lsr |= up->lsr_saved_flags;
+ up->lsr_saved_flags = 0;
+
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+ if (lsr & UART_LSR_BI) {
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ port->icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(port))
+ return;
+ } else if (lsr & UART_LSR_PE)
+ port->icount.parity++;
+ else if (lsr & UART_LSR_FE)
+ port->icount.frame++;
+ if (lsr & UART_LSR_OE)
+ port->icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ lsr &= port->read_status_mask;
+
+ if (lsr & UART_LSR_BI) {
+ DEBUG_INTR("handling break....");
+ flag = TTY_BREAK;
+ } else if (lsr & UART_LSR_PE)
+ flag = TTY_PARITY;
+ else if (lsr & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+ if (uart_handle_sysrq_char(port, ch))
+ return;
+
+ uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+}
+
/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
*/
-unsigned char
-serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
+unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
{
struct uart_port *port = &up->port;
- unsigned char ch;
int max_count = 256;
- char flag;
do {
- if (likely(lsr & UART_LSR_DR))
- ch = serial_in(up, UART_RX);
- else
- /*
- * Intel 82571 has a Serial Over Lan device that will
- * set UART_LSR_BI without setting UART_LSR_DR when
- * it receives a break. To avoid reading from the
- * receive buffer without UART_LSR_DR bit set, we
- * just force the read character to be 0
- */
- ch = 0;
-
- flag = TTY_NORMAL;
- port->icount.rx++;
-
- lsr |= up->lsr_saved_flags;
- up->lsr_saved_flags = 0;
-
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- if (lsr & UART_LSR_BI) {
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);
- port->icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(port))
- goto ignore_char;
- } else if (lsr & UART_LSR_PE)
- port->icount.parity++;
- else if (lsr & UART_LSR_FE)
- port->icount.frame++;
- if (lsr & UART_LSR_OE)
- port->icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- lsr &= port->read_status_mask;
-
- if (lsr & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
- flag = TTY_BREAK;
- } else if (lsr & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (lsr & UART_LSR_FE)
- flag = TTY_FRAME;
- }
- if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
-
- uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
-
-ignore_char:
+ serial8250_read_char(up, lsr);
+ if (--max_count == 0)
+ break;
lsr = serial_in(up, UART_LSR);
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0));
- spin_unlock(&port->lock);
+ } while (lsr & (UART_LSR_DR | UART_LSR_BI));
+
tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
return lsr;
}
EXPORT_SYMBOL_GPL(serial8250_rx_chars);
@@ -1501,11 +1733,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
- if (up->capabilities & UART_CAP_HFIFO) {
- if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
- BOTH_EMPTY)
- break;
- }
+ if ((up->capabilities & UART_CAP_HFIFO) &&
+ (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
+ break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1734,6 +1964,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
unsigned int tmout;
+
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
@@ -1967,23 +2198,23 @@ int serial8250_do_startup(struct uart_port *port)
serial8250_set_mctrl(port, port->mctrl);
- /* Serial over Lan (SoL) hack:
- Intel 8257x Gigabit ethernet chips have a
- 16550 emulation, to be used for Serial Over Lan.
- Those chips take a longer time than a normal
- serial device to signalize that a transmission
- data was queued. Due to that, the above test generally
- fails. One solution would be to delay the reading of
- iir. However, this is not reliable, since the timeout
- is variable. So, let's just don't test if we receive
- TX irq. This way, we'll never enable UART_BUG_TXEN.
+ /*
+ * Serial over Lan (SoL) hack:
+ * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be
+ * used for Serial Over Lan. Those chips take a longer time than a
+ * normal serial device to signalize that a transmission data was
+ * queued. Due to that, the above test generally fails. One solution
+ * would be to delay the reading of iir. However, this is not
+ * reliable, since the timeout is variable. So, let's just don't
+ * test if we receive TX irq. This way, we'll never enable
+ * UART_BUG_TXEN.
*/
if (up->port.flags & UPF_NO_TXEN_TEST)
goto dont_test_tx_en;
/*
- * Do a quick test to see if we receive an
- * interrupt when we enable the TX irq.
+ * Do a quick test to see if we receive an interrupt when we enable
+ * the TX irq.
*/
serial_port_out(port, UART_IER, UART_IER_THRI);
lsr = serial_port_in(port, UART_LSR);
@@ -2066,8 +2297,12 @@ void serial8250_do_shutdown(struct uart_port *port)
/*
* Disable interrupts from this port
*/
+ spin_lock_irqsave(&port->lock, flags);
up->ier = 0;
serial_port_out(port, UART_IER, 0);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ synchronize_irq(port->irq);
if (up->dma)
serial8250_release_dma(up);
@@ -2233,9 +2468,9 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
serial_port_out(port, 0x2, quot_frac);
}
-static unsigned int
-serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static unsigned int serial8250_get_baud_rate(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int tolerance = port->uartclk / 100;
@@ -2252,7 +2487,7 @@ serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+ struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
@@ -2462,6 +2697,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM32BE:
+ case UPIO_MEM16:
case UPIO_MEM:
if (!port->mapbase)
break;
@@ -2499,6 +2735,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM32BE:
+ case UPIO_MEM16:
case UPIO_MEM:
if (!port->mapbase)
break;
@@ -2563,8 +2800,7 @@ static int do_get_rxtrig(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1)
return -EINVAL;
@@ -2600,8 +2836,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
int rxtrig;
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 ||
@@ -2725,8 +2960,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
-static const char *
-serial8250_type(struct uart_port *port)
+static const char *serial8250_type(struct uart_port *port)
{
int type = port->type;
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 245edbb68d4b..1b7bd26555b7 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -13,6 +13,7 @@
*/
#include <linux/clk.h>
+#include <linux/console.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -34,6 +35,29 @@ struct uniphier8250_priv {
spinlock_t atomic_write_lock;
};
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
+static int __init uniphier_early_console_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ /* This hardware always expects MMIO32 register interface. */
+ device->port.iotype = UPIO_MEM32;
+ device->port.regshift = 2;
+
+ /*
+ * Do not touch the divisor register in early_serial8250_setup();
+ * we assume it has been initialized by a boot loader.
+ */
+ device->baud = 0;
+
+ return early_serial8250_setup(device, options);
+}
+OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart",
+ uniphier_early_console_setup);
+#endif
+
/*
* The register map is slightly different from that of 8250.
* IO callbacks must be overridden for correct access to FCR, LCR, and MCR.
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 6412f1455beb..64742a086ae3 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -262,7 +262,12 @@ config SERIAL_8250_RSA
bool "Support RSA serial ports"
depends on SERIAL_8250_EXTENDED
help
- ::: To be written :::
+ Say Y here if you have a IODATA RSA-DV II/S ISA card and
+ would like to use its >115kbps speeds.
+ You will need to provide module parameter "probe_rsa", or boot-time
+ parameter 8250.probe_rsa with I/O addresses of this card then.
+
+ If you don't have such card, or if unsure, say N.
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
@@ -272,6 +277,30 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
+config SERIAL_8250_BCM2835AUX
+ tristate "BCM2835 auxiliar mini UART support"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ
+ help
+ Support for the BCM2835 auxiliar mini UART.
+
+ Features and limitations of the UART are
+ Registers are similar to 16650 registers,
+ set bits in the control registers that are unsupported
+ are ignored and read back as 0
+ 7/8 bit operation with 1 start and 1 stop bit
+ 8 symbols deep fifo for rx and tx
+ SW controlled RTS and SW readable CTS
+ Clock rate derived from system clock
+ Uses 8 times oversampling (compared to 16 times for 16650)
+ Missing break detection (but break generation)
+ Missing framing error detection
+ Missing parity bit
+ Missing receive time-out interrupt
+ Missing DCD, DSR, DTR and RI signals
+
+ If unsure, say N.
+
config SERIAL_8250_FSL
bool
depends on SERIAL_8250_CONSOLE
@@ -295,6 +324,7 @@ config SERIAL_8250_EM
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
depends on SERIAL_8250
+ depends on MIPS || COMPILE_TEST
default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
help
Selecting this option will add support for the alternate register
@@ -346,7 +376,7 @@ config SERIAL_8250_LPC18XX
serial port, say Y to this option. If unsure, say Y.
config SERIAL_8250_MT6577
- bool "Mediatek serial port support"
+ tristate "Mediatek serial port support"
depends on SERIAL_8250 && ARCH_MEDIATEK
help
If you have a Mediatek based board and want to use the
@@ -360,10 +390,10 @@ config SERIAL_8250_UNIPHIER
serial ports, say Y to this option. If unsure, say N.
config SERIAL_8250_INGENIC
- bool "Support for Ingenic SoC serial ports"
- depends on SERIAL_8250_CONSOLE && OF_FLATTREE
- select LIBFDT
- select SERIAL_EARLYCON
+ tristate "Support for Ingenic SoC serial ports"
+ depends on SERIAL_8250
+ depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON
+ depends on MIPS || COMPILE_TEST
help
If you have a system using an Ingenic SoC and wish to make use of
its UARTs, say Y to this option. If unsure, say N.
@@ -372,9 +402,28 @@ config SERIAL_8250_MID
tristate "Support for serial ports on Intel MID platforms"
depends on SERIAL_8250 && PCI
select HSU_DMA if SERIAL_8250_DMA
- select HSU_DMA_PCI if X86_INTEL_MID
+ select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
select RATIONAL
help
Selecting this option will enable handling of the extra features
present on the UART found on Intel Medfield SOC and various other
Intel platforms.
+
+config SERIAL_8250_MOXA
+ tristate "MOXA SmartIO MUE support"
+ depends on SERIAL_8250 && PCI
+ help
+ Say Y here if you have a Moxa SmartIO MUE multiport serial card.
+ If unsure, say N.
+
+ This driver can also be built as a module. The module will be called
+ 8250_moxa. If you want to do that, say M here.
+
+config SERIAL_OF_PLATFORM
+ tristate "Devicetree based probing for 8250 ports"
+ depends on SERIAL_8250 && OF
+ help
+ This option is used for all 8250 compatible serial ports that
+ are probed through devicetree, including Open Firmware based
+ PowerPC systems and embedded systems on architectures using the
+ flattened device tree format.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index e177f8681ada..c9a2d6ed87e9 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
@@ -28,5 +29,7 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
+obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 4d180c9423ef..933c2688dd7e 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -28,7 +28,7 @@
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
-
+
======================================================================*/
#include <linux/module.h>
@@ -257,7 +257,7 @@ static const struct serial_quirk quirks[] = {
};
-static int serial_config(struct pcmcia_device * link);
+static int serial_config(struct pcmcia_device *link);
static void serial_remove(struct pcmcia_device *link)
@@ -309,7 +309,7 @@ static int serial_probe(struct pcmcia_device *link)
dev_dbg(&link->dev, "serial_attach()\n");
/* Create new serial device */
- info = kzalloc(sizeof (*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->p_dev = link;
@@ -339,7 +339,7 @@ static void serial_detach(struct pcmcia_device *link)
/*====================================================================*/
-static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
+static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
unsigned int iobase, int irq)
{
struct uart_8250_port uart;
@@ -441,16 +441,20 @@ static int simple_config(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i = -ENODEV, try;
- /* First pass: look for a config entry that looks normal.
- * Two tries: without IO aliases, then with aliases */
+ /*
+ * First pass: look for a config entry that looks normal.
+ * Two tries: without IO aliases, then with aliases.
+ */
link->config_flags |= CONF_AUTO_SET_VPP;
for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port;
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
+ /*
+ * Second pass: try to find an entry that isn't picky about
+ * its base address, then try to grab any standard serial port
+ * address, and finally try to get any free port.
+ */
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
goto found_port;
@@ -480,8 +484,10 @@ static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
if (p_dev->resource[1]->end)
return -EINVAL;
- /* The quad port cards have bad CIS's, so just look for a
- window larger than 8 ports and assume it will be right */
+ /*
+ * The quad port cards have bad CIS's, so just look for a
+ * window larger than 8 ports and assume it will be right.
+ */
if (p_dev->resource[0]->end <= 8)
return -EINVAL;
@@ -527,8 +533,8 @@ static int multi_config(struct pcmcia_device *link)
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
- dev_warn(&link->dev, "no usable port range "
- "found, giving up\n");
+ dev_warn(&link->dev,
+ "no usable port range found, giving up\n");
return -ENODEV;
}
}
@@ -600,7 +606,7 @@ static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
}
-static int serial_config(struct pcmcia_device * link)
+static int serial_config(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
int i;
@@ -623,8 +629,10 @@ static int serial_config(struct pcmcia_device * link)
break;
}
- /* Another check for dual-serial cards: look for either serial or
- multifunction cards that ask for appropriate IO port ranges */
+ /*
+ * Another check for dual-serial cards: look for either serial or
+ * multifunction cards that ask for appropriate IO port ranges.
+ */
if ((info->multi == 0) &&
(link->has_func_id) &&
(link->socket->pcmcia_pfc == 0) &&
@@ -701,7 +709,7 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
- PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
@@ -797,30 +805,30 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
/* too generic */
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index f38beb28e7ae..13d4ed6caac4 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -115,6 +115,7 @@ config SERIAL_SB1250_DUART_CONSOLE
config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
+ depends on HAS_DMA
depends on ARCH_AT91 || AVR32 || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
@@ -571,9 +572,11 @@ config BFIN_UART3_CTSRTS
config SERIAL_IMX
tristate "IMX serial port support"
+ depends on HAS_DMA
depends on ARCH_MXC || COMPILE_TEST
select SERIAL_CORE
select RATIONAL
+ select SERIAL_MCTRL_GPIO if GPIOLIB
help
If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option.
@@ -607,6 +610,7 @@ config SERIAL_UARTLITE_CONSOLE
bool "Support for console on Xilinx uartlite serial port"
depends on SERIAL_UARTLITE=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Say Y here if you wish to use a Xilinx uartlite as the system
console (the system console is the device which receives all kernel
@@ -729,7 +733,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST
+ depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
@@ -742,6 +746,12 @@ config SERIAL_SH_SCI_CONSOLE
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
+config SERIAL_SH_SCI_EARLYCON
+ bool "Support for early console on SuperH SCI(F)"
+ depends on SERIAL_SH_SCI=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+
config SERIAL_SH_SCI_DMA
bool "DMA support"
depends on SERIAL_SH_SCI && DMA_ENGINE
@@ -790,17 +800,6 @@ config SERIAL_CORE_CONSOLE
config CONSOLE_POLL
bool
-config SERIAL_68328
- bool "68328 serial support"
- depends on M68328 || M68EZ328 || M68VZ328
- help
- This driver supports the built-in serial port of the Motorola 68328
- (standard, EZ and VZ varieties).
-
-config SERIAL_68328_RTS_CTS
- bool "Support RTS/CTS on 68328 serial port"
- depends on SERIAL_68328
-
config SERIAL_MCF
bool "Coldfire serial support"
depends on COLDFIRE
@@ -1044,7 +1043,7 @@ config SERIAL_SGI_IOC3
say Y or M. Otherwise, say N.
config SERIAL_MSM
- bool "MSM on-chip serial port support"
+ tristate "MSM on-chip serial port support"
depends on ARCH_QCOM
select SERIAL_CORE
@@ -1094,16 +1093,6 @@ config SERIAL_NETX_CONSOLE
If you have enabled the serial port on the Hilscher NetX SoC
you can make it the console by answering Y to this option.
-config SERIAL_OF_PLATFORM
- tristate "Serial port on Open Firmware platform bus"
- depends on OF
- depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
- help
- If you have a PowerPC based system that has serial ports
- on a platform specific bus, you should enable this option.
- Currently, only 8250 compatible ports are supported, but
- others can easily be added.
-
config SERIAL_OMAP
tristate "OMAP serial port support"
depends on ARCH_OMAP2PLUS
@@ -1131,23 +1120,6 @@ config SERIAL_OMAP_CONSOLE
your boot loader about how to pass options to the kernel at
boot time.)
-config SERIAL_OF_PLATFORM_NWPSERIAL
- tristate "NWP serial port driver"
- depends on PPC_DCR
- select SERIAL_OF_PLATFORM
- select SERIAL_CORE_CONSOLE
- select SERIAL_CORE
- help
- This driver supports the cell network processor nwp serial
- device.
-
-config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
- bool "Console on NWP serial port"
- depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
- select SERIAL_CORE_CONSOLE
- help
- Support for Console on the NWP serial ports.
-
config SERIAL_LANTIQ
bool "Lantiq serial driver"
depends on LANTIQ
@@ -1409,8 +1381,9 @@ config SERIAL_PCH_UART_CONSOLE
warnings and which allows logins in single user mode).
config SERIAL_MXS_AUART
- depends on ARCH_MXS || COMPILE_TEST
tristate "MXS AUART support"
+ depends on HAS_DMA
+ depends on ARCH_MXS || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
help
@@ -1629,6 +1602,28 @@ config SERIAL_STM32_CONSOLE
depends on SERIAL_STM32=y
select SERIAL_CORE_CONSOLE
+config SERIAL_MVEBU_UART
+ bool "Marvell EBU serial port support"
+ select SERIAL_CORE
+ help
+ This driver is for Marvell EBU SoC's UART. If you have a machine
+ based on the Armada-3700 SoC and wish to use the on-board serial
+ port,
+ say 'Y' here.
+ Otherwise, say 'N'.
+
+config SERIAL_MVEBU_CONSOLE
+ bool "Console on Marvell EBU serial port"
+ depends on SERIAL_MVEBU_UART
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ default y
+ help
+ Say 'Y' here if you wish to use Armada-3700 UART as the system console.
+ (the system console is the device which receives all kernel messages
+ and warnings and which allows logins in single user mode)
+ Otherwise, say 'N'.
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 5ab41119b3dc..8c261adac04e 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
-obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
@@ -63,8 +62,6 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
@@ -93,6 +90,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
+obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 899a77187bde..7c198e0a3178 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -60,6 +60,8 @@
#include <linux/io.h>
#include <linux/acpi.h>
+#include "amba-pl011.h"
+
#define UART_NR 14
#define SERIAL_AMBA_MAJOR 204
@@ -71,11 +73,27 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
+static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
+ [REG_DR] = UART01x_DR,
+ [REG_FR] = UART01x_FR,
+ [REG_LCRH_RX] = UART011_LCRH,
+ [REG_LCRH_TX] = UART011_LCRH,
+ [REG_IBRD] = UART011_IBRD,
+ [REG_FBRD] = UART011_FBRD,
+ [REG_CR] = UART011_CR,
+ [REG_IFLS] = UART011_IFLS,
+ [REG_IMSC] = UART011_IMSC,
+ [REG_RIS] = UART011_RIS,
+ [REG_MIS] = UART011_MIS,
+ [REG_ICR] = UART011_ICR,
+ [REG_DMACR] = UART011_DMACR,
+};
+
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
+ const u16 *reg_offset;
unsigned int ifls;
- unsigned int lcrh_tx;
- unsigned int lcrh_rx;
+ bool access_32b;
bool oversampling;
bool dma_threshold;
bool cts_event_workaround;
@@ -91,9 +109,8 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
}
static struct vendor_data vendor_arm = {
+ .reg_offset = pl011_std_offsets,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
- .lcrh_tx = UART011_LCRH,
- .lcrh_rx = UART011_LCRH,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
@@ -103,6 +120,7 @@ static struct vendor_data vendor_arm = {
};
static struct vendor_data vendor_sbsa = {
+ .reg_offset = pl011_std_offsets,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
@@ -110,15 +128,41 @@ static struct vendor_data vendor_sbsa = {
.fixed_options = true,
};
+static u16 pl011_st_offsets[REG_ARRAY_SIZE] = {
+ [REG_DR] = UART01x_DR,
+ [REG_ST_DMAWM] = ST_UART011_DMAWM,
+ [REG_ST_TIMEOUT] = ST_UART011_TIMEOUT,
+ [REG_FR] = UART01x_FR,
+ [REG_LCRH_RX] = ST_UART011_LCRH_RX,
+ [REG_LCRH_TX] = ST_UART011_LCRH_TX,
+ [REG_IBRD] = UART011_IBRD,
+ [REG_FBRD] = UART011_FBRD,
+ [REG_CR] = UART011_CR,
+ [REG_IFLS] = UART011_IFLS,
+ [REG_IMSC] = UART011_IMSC,
+ [REG_RIS] = UART011_RIS,
+ [REG_MIS] = UART011_MIS,
+ [REG_ICR] = UART011_ICR,
+ [REG_DMACR] = UART011_DMACR,
+ [REG_ST_XFCR] = ST_UART011_XFCR,
+ [REG_ST_XON1] = ST_UART011_XON1,
+ [REG_ST_XON2] = ST_UART011_XON2,
+ [REG_ST_XOFF1] = ST_UART011_XOFF1,
+ [REG_ST_XOFF2] = ST_UART011_XOFF2,
+ [REG_ST_ITCR] = ST_UART011_ITCR,
+ [REG_ST_ITIP] = ST_UART011_ITIP,
+ [REG_ST_ABCR] = ST_UART011_ABCR,
+ [REG_ST_ABIMSC] = ST_UART011_ABIMSC,
+};
+
static unsigned int get_fifosize_st(struct amba_device *dev)
{
return 64;
}
static struct vendor_data vendor_st = {
+ .reg_offset = pl011_st_offsets,
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
- .lcrh_tx = ST_UART011_LCRH_TX,
- .lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
.dma_threshold = true,
.cts_event_workaround = true,
@@ -127,6 +171,29 @@ static struct vendor_data vendor_st = {
.get_fifosize = get_fifosize_st,
};
+static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
+ [REG_DR] = ZX_UART011_DR,
+ [REG_FR] = ZX_UART011_FR,
+ [REG_LCRH_RX] = ZX_UART011_LCRH,
+ [REG_LCRH_TX] = ZX_UART011_LCRH,
+ [REG_IBRD] = ZX_UART011_IBRD,
+ [REG_FBRD] = ZX_UART011_FBRD,
+ [REG_CR] = ZX_UART011_CR,
+ [REG_IFLS] = ZX_UART011_IFLS,
+ [REG_IMSC] = ZX_UART011_IMSC,
+ [REG_RIS] = ZX_UART011_RIS,
+ [REG_MIS] = ZX_UART011_MIS,
+ [REG_ICR] = ZX_UART011_ICR,
+ [REG_DMACR] = ZX_UART011_DMACR,
+};
+
+static struct vendor_data vendor_zte __maybe_unused = {
+ .reg_offset = pl011_zte_offsets,
+ .access_32b = true,
+ .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+ .get_fifosize = get_fifosize_arm,
+};
+
/* Deals with DMA transactions */
struct pl011_sgbuf {
@@ -162,14 +229,13 @@ struct pl011_dmatx_data {
*/
struct uart_amba_port {
struct uart_port port;
+ const u16 *reg_offset;
struct clk *clk;
const struct vendor_data *vendor;
unsigned int dmacr; /* dma control reg */
unsigned int im; /* interrupt mask */
unsigned int old_status;
unsigned int fifosize; /* vendor-specific */
- unsigned int lcrh_tx; /* vendor-specific */
- unsigned int lcrh_rx; /* vendor-specific */
unsigned int old_cr; /* state during shutdown */
bool autorts;
unsigned int fixed_baud; /* vendor-set fixed baud rate */
@@ -184,6 +250,32 @@ struct uart_amba_port {
#endif
};
+static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ return uap->reg_offset[reg];
+}
+
+static unsigned int pl011_read(const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
+
+ return (uap->port.iotype == UPIO_MEM32) ?
+ readl_relaxed(addr) : readw_relaxed(addr);
+}
+
+static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
+
+ if (uap->port.iotype == UPIO_MEM32)
+ writel_relaxed(val, addr);
+ else
+ writew_relaxed(val, addr);
+}
+
/*
* Reads up to 256 characters from the FIFO or until it's empty and
* inserts them into the TTY layer. Returns the number of characters
@@ -196,13 +288,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
int fifotaken = 0;
while (max_count--) {
- status = readw(uap->port.membase + UART01x_FR);
+ status = pl011_read(uap, REG_FR);
if (status & UART01x_FR_RXFE)
break;
/* Take chars from the FIFO and update status */
- ch = readw(uap->port.membase + UART01x_DR) |
- UART_DUMMY_DR_RX;
+ ch = pl011_read(uap, REG_DR) | UART_DUMMY_DR_RX;
flag = TTY_NORMAL;
uap->port.icount.rx++;
fifotaken++;
@@ -284,7 +375,8 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
struct device *dev = uap->port.dev;
struct dma_slave_config tx_conf = {
- .dst_addr = uap->port.mapbase + UART01x_DR,
+ .dst_addr = uap->port.mapbase +
+ pl011_reg_to_offset(uap, REG_DR),
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.direction = DMA_MEM_TO_DEV,
.dst_maxburst = uap->fifosize >> 1,
@@ -328,7 +420,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
/* Optionally make use of an RX channel as well */
chan = dma_request_slave_channel(dev, "rx");
- if (!chan && plat->dma_rx_param) {
+ if (!chan && plat && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
if (!chan) {
@@ -339,7 +431,8 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
if (chan) {
struct dma_slave_config rx_conf = {
- .src_addr = uap->port.mapbase + UART01x_DR,
+ .src_addr = uap->port.mapbase +
+ pl011_reg_to_offset(uap, REG_DR),
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.direction = DMA_DEV_TO_MEM,
.src_maxburst = uap->fifosize >> 2,
@@ -438,7 +531,7 @@ static void pl011_dma_tx_callback(void *data)
dmacr = uap->dmacr;
uap->dmacr = dmacr & ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
/*
* If TX DMA was disabled, it means that we've stopped the DMA for
@@ -552,7 +645,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
dma_dev->device_issue_pending(chan);
uap->dmacr |= UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->dmatx.queued = true;
/*
@@ -588,9 +681,9 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
*/
if (uap->dmatx.queued) {
uap->dmacr |= UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return true;
}
@@ -600,7 +693,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
*/
if (pl011_dma_tx_refill(uap) > 0) {
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return true;
}
return false;
@@ -614,7 +707,7 @@ static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
{
if (uap->dmatx.queued) {
uap->dmacr &= ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
}
@@ -640,14 +733,12 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
if (!uap->dmatx.queued) {
if (pl011_dma_tx_refill(uap) > 0) {
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase +
- UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
} else
ret = false;
} else if (!(uap->dmacr & UART011_TXDMAE)) {
uap->dmacr |= UART011_TXDMAE;
- writew(uap->dmacr,
- uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
return ret;
}
@@ -658,9 +749,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
*/
dmacr = uap->dmacr;
uap->dmacr &= ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
- if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+ if (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) {
/*
* No space in the FIFO, so enable the transmit interrupt
* so we know when there is space. Note that once we've
@@ -669,13 +760,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
return false;
}
- writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+ pl011_write(uap->port.x_char, uap, REG_DR);
uap->port.icount.tx++;
uap->port.x_char = 0;
/* Success - restore the DMA state */
uap->dmacr = dmacr;
- writew(dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(dmacr, uap, REG_DMACR);
return true;
}
@@ -703,7 +794,7 @@ __acquires(&uap->port.lock)
DMA_TO_DEVICE);
uap->dmatx.queued = false;
uap->dmacr &= ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
}
@@ -743,11 +834,11 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
dma_async_issue_pending(rxchan);
uap->dmacr |= UART011_RXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->dmarx.running = true;
uap->im &= ~UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return 0;
}
@@ -805,8 +896,8 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
*/
if (dma_count == pending && readfifo) {
/* Clear any error flags */
- writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
- uap->port.membase + UART011_ICR);
+ pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
+ UART011_FEIS, uap, REG_ICR);
/*
* If we read all the DMA'd characters, and we had an
@@ -854,7 +945,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
/* Disable RX DMA - incoming data will wait in the FIFO */
uap->dmacr &= ~UART011_RXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->dmarx.running = false;
pending = sgbuf->sg.length - state.residue;
@@ -874,7 +965,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
"fall back to interrupt mode\n");
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
}
}
@@ -922,7 +1013,7 @@ static void pl011_dma_rx_callback(void *data)
dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
"fall back to interrupt mode\n");
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
}
}
@@ -935,7 +1026,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
{
/* FIXME. Just disable the DMA enable */
uap->dmacr &= ~UART011_RXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
/*
@@ -979,7 +1070,7 @@ static void pl011_dma_rx_poll(unsigned long args)
spin_lock_irqsave(&uap->port.lock, flags);
pl011_dma_rx_stop(uap);
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
spin_unlock_irqrestore(&uap->port.lock, flags);
uap->dmarx.running = false;
@@ -1041,7 +1132,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
skip_rx:
/* Turn on DMA error (RX/TX will be enabled on demand) */
uap->dmacr |= UART011_DMAONERR;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
/*
* ST Micro variants has some specific dma burst threshold
@@ -1049,8 +1140,8 @@ skip_rx:
* be issued above/below 16 bytes.
*/
if (uap->vendor->dma_threshold)
- writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
- uap->port.membase + ST_UART011_DMAWM);
+ pl011_write(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
+ uap, REG_ST_DMAWM);
if (uap->using_rx_dma) {
if (pl011_dma_rx_trigger_dma(uap))
@@ -1075,12 +1166,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
return;
/* Disable RX and TX DMA */
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
- barrier();
+ while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+ cpu_relax();
spin_lock_irq(&uap->port.lock);
uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
spin_unlock_irq(&uap->port.lock);
if (uap->using_tx_dma) {
@@ -1181,7 +1272,7 @@ static void pl011_stop_tx(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_tx_stop(uap);
}
@@ -1191,7 +1282,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
static void pl011_start_tx_pio(struct uart_amba_port *uap)
{
uap->im |= UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
pl011_tx_chars(uap, false);
}
@@ -1211,7 +1302,7 @@ static void pl011_stop_rx(struct uart_port *port)
uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
UART011_PEIM|UART011_BEIM|UART011_OEIM);
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_rx_stop(uap);
}
@@ -1222,7 +1313,7 @@ static void pl011_enable_ms(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
}
static void pl011_rx_chars(struct uart_amba_port *uap)
@@ -1242,7 +1333,7 @@ __acquires(&uap->port.lock)
dev_dbg(uap->port.dev, "could not trigger RX DMA job "
"fall back to interrupt mode again\n");
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
} else {
#ifdef CONFIG_DMA_ENGINE
/* Start Rx DMA poll */
@@ -1263,10 +1354,10 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
bool from_irq)
{
if (unlikely(!from_irq) &&
- readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
return false; /* unable to transmit character */
- writew(c, uap->port.membase + UART01x_DR);
+ pl011_write(c, uap, REG_DR);
uap->port.icount.tx++;
return true;
@@ -1313,7 +1404,7 @@ static void pl011_modem_status(struct uart_amba_port *uap)
{
unsigned int status, delta;
- status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+ status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
delta = status ^ uap->old_status;
uap->old_status = status;
@@ -1341,15 +1432,15 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
return;
/* workaround to make sure that all bits are unlocked.. */
- writew(0x00, uap->port.membase + UART011_ICR);
+ pl011_write(0x00, uap, REG_ICR);
/*
* WA: introduce 26ns(1 uart clk) delay before W1C;
* single apb access will incur 2 pclk(133.12Mhz) delay,
* so add 2 dummy reads
*/
- dummy_read = readw(uap->port.membase + UART011_ICR);
- dummy_read = readw(uap->port.membase + UART011_ICR);
+ dummy_read = pl011_read(uap, REG_ICR);
+ dummy_read = pl011_read(uap, REG_ICR);
}
static irqreturn_t pl011_int(int irq, void *dev_id)
@@ -1361,15 +1452,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
int handled = 0;
spin_lock_irqsave(&uap->port.lock, flags);
- imsc = readw(uap->port.membase + UART011_IMSC);
- status = readw(uap->port.membase + UART011_RIS) & imsc;
+ imsc = pl011_read(uap, REG_IMSC);
+ status = pl011_read(uap, REG_RIS) & imsc;
if (status) {
do {
check_apply_cts_event_workaround(uap);
- writew(status & ~(UART011_TXIS|UART011_RTIS|
- UART011_RXIS),
- uap->port.membase + UART011_ICR);
+ pl011_write(status & ~(UART011_TXIS|UART011_RTIS|
+ UART011_RXIS),
+ uap, REG_ICR);
if (status & (UART011_RTIS|UART011_RXIS)) {
if (pl011_dma_rx_running(uap))
@@ -1386,7 +1477,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (pass_counter-- == 0)
break;
- status = readw(uap->port.membase + UART011_RIS) & imsc;
+ status = pl011_read(uap, REG_RIS) & imsc;
} while (status != 0);
handled = 1;
}
@@ -1400,7 +1491,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- unsigned int status = readw(uap->port.membase + UART01x_FR);
+ unsigned int status = pl011_read(uap, REG_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
@@ -1409,7 +1500,7 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
unsigned int result = 0;
- unsigned int status = readw(uap->port.membase + UART01x_FR);
+ unsigned int status = pl011_read(uap, REG_FR);
#define TIOCMBIT(uartbit, tiocmbit) \
if (status & uartbit) \
@@ -1429,7 +1520,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
container_of(port, struct uart_amba_port, port);
unsigned int cr;
- cr = readw(uap->port.membase + UART011_CR);
+ cr = pl011_read(uap, REG_CR);
#define TIOCMBIT(tiocmbit, uartbit) \
if (mctrl & tiocmbit) \
@@ -1449,7 +1540,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
}
#undef TIOCMBIT
- writew(cr, uap->port.membase + UART011_CR);
+ pl011_write(cr, uap, REG_CR);
}
static void pl011_break_ctl(struct uart_port *port, int break_state)
@@ -1460,12 +1551,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
unsigned int lcr_h;
spin_lock_irqsave(&uap->port.lock, flags);
- lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+ lcr_h = pl011_read(uap, REG_LCRH_TX);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
- writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+ pl011_write(lcr_h, uap, REG_LCRH_TX);
spin_unlock_irqrestore(&uap->port.lock, flags);
}
@@ -1475,9 +1566,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- unsigned char __iomem *regs = uap->port.membase;
- writew(readw(regs + UART011_MIS), regs + UART011_ICR);
+ pl011_write(pl011_read(uap, REG_MIS), uap, REG_ICR);
/*
* There is no way to clear TXIM as this is "ready to transmit IRQ", so
* we simply mask it. start_tx() will unmask it.
@@ -1491,7 +1581,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
* (including tx queue), so we're also fine with start_tx()'s caller
* side.
*/
- writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC);
+ pl011_write(pl011_read(uap, REG_IMSC) & ~UART011_TXIM, uap,
+ REG_IMSC);
}
static int pl011_get_poll_char(struct uart_port *port)
@@ -1506,11 +1597,11 @@ static int pl011_get_poll_char(struct uart_port *port)
*/
pl011_quiesce_irqs(port);
- status = readw(uap->port.membase + UART01x_FR);
+ status = pl011_read(uap, REG_FR);
if (status & UART01x_FR_RXFE)
return NO_POLL_CHAR;
- return readw(uap->port.membase + UART01x_DR);
+ return pl011_read(uap, REG_DR);
}
static void pl011_put_poll_char(struct uart_port *port,
@@ -1519,10 +1610,10 @@ static void pl011_put_poll_char(struct uart_port *port,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
- barrier();
+ while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
+ cpu_relax();
- writew(ch, uap->port.membase + UART01x_DR);
+ pl011_write(ch, uap, REG_DR);
}
#endif /* CONFIG_CONSOLE_POLL */
@@ -1546,15 +1637,16 @@ static int pl011_hwinit(struct uart_port *port)
uap->port.uartclk = clk_get_rate(uap->clk);
/* Clear pending error and receive interrupts */
- writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
- UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+ pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
+ UART011_FEIS | UART011_RTIS | UART011_RXIS,
+ uap, REG_ICR);
/*
* Save interrupts enable mask, and enable RX interrupts in case if
* the interrupt is used for NMI entry.
*/
- uap->im = readw(uap->port.membase + UART011_IMSC);
- writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+ uap->im = pl011_read(uap, REG_IMSC);
+ pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC);
if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
@@ -1566,24 +1658,30 @@ static int pl011_hwinit(struct uart_port *port)
return 0;
}
+static bool pl011_split_lcrh(const struct uart_amba_port *uap)
+{
+ return pl011_reg_to_offset(uap, REG_LCRH_RX) !=
+ pl011_reg_to_offset(uap, REG_LCRH_TX);
+}
+
static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
{
- writew(lcr_h, uap->port.membase + uap->lcrh_rx);
- if (uap->lcrh_rx != uap->lcrh_tx) {
+ pl011_write(lcr_h, uap, REG_LCRH_RX);
+ if (pl011_split_lcrh(uap)) {
int i;
/*
* Wait 10 PCLKs before writing LCRH_TX register,
* to get this delay write read only register 10 times
*/
for (i = 0; i < 10; ++i)
- writew(0xff, uap->port.membase + UART011_MIS);
- writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+ pl011_write(0xff, uap, REG_MIS);
+ pl011_write(lcr_h, uap, REG_LCRH_TX);
}
}
static int pl011_allocate_irq(struct uart_amba_port *uap)
{
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
}
@@ -1598,12 +1696,11 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
spin_lock_irq(&uap->port.lock);
/* Clear out any spuriously appearing RX interrupts */
- writew(UART011_RTIS | UART011_RXIS,
- uap->port.membase + UART011_ICR);
+ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
spin_unlock_irq(&uap->port.lock);
}
@@ -1622,21 +1719,21 @@ static int pl011_startup(struct uart_port *port)
if (retval)
goto clk_dis;
- writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
+ pl011_write(uap->vendor->ifls, uap, REG_IFLS);
spin_lock_irq(&uap->port.lock);
/* restore RTS and DTR */
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
- writew(cr, uap->port.membase + UART011_CR);
+ pl011_write(cr, uap, REG_CR);
spin_unlock_irq(&uap->port.lock);
/*
* initialise the old status of the modem signals
*/
- uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+ uap->old_status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
/* Startup DMA */
pl011_dma_startup(uap);
@@ -1677,9 +1774,9 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
{
unsigned long val;
- val = readw(uap->port.membase + lcrh);
+ val = pl011_read(uap, lcrh);
val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
- writew(val, uap->port.membase + lcrh);
+ pl011_write(val, uap, lcrh);
}
/*
@@ -1693,19 +1790,19 @@ static void pl011_disable_uart(struct uart_amba_port *uap)
uap->autorts = false;
spin_lock_irq(&uap->port.lock);
- cr = readw(uap->port.membase + UART011_CR);
+ cr = pl011_read(uap, REG_CR);
uap->old_cr = cr;
cr &= UART011_CR_RTS | UART011_CR_DTR;
cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- writew(cr, uap->port.membase + UART011_CR);
+ pl011_write(cr, uap, REG_CR);
spin_unlock_irq(&uap->port.lock);
/*
* disable break condition and fifos
*/
- pl011_shutdown_channel(uap, uap->lcrh_rx);
- if (uap->lcrh_rx != uap->lcrh_tx)
- pl011_shutdown_channel(uap, uap->lcrh_tx);
+ pl011_shutdown_channel(uap, REG_LCRH_RX);
+ if (pl011_split_lcrh(uap))
+ pl011_shutdown_channel(uap, REG_LCRH_TX);
}
static void pl011_disable_interrupts(struct uart_amba_port *uap)
@@ -1714,8 +1811,8 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap)
/* mask all interrupts and clear all pending ones */
uap->im = 0;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ pl011_write(uap->im, uap, REG_IMSC);
+ pl011_write(0xffff, uap, REG_ICR);
spin_unlock_irq(&uap->port.lock);
}
@@ -1850,6 +1947,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
lcr_h |= UART01x_LCRH_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
+ if (termios->c_cflag & CMSPAR)
+ lcr_h |= UART011_LCRH_SPS;
}
if (uap->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
@@ -1867,8 +1966,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
pl011_enable_ms(port);
/* first, disable everything */
- old_cr = readw(port->membase + UART011_CR);
- writew(0, port->membase + UART011_CR);
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write(0, uap, REG_CR);
if (termios->c_cflag & CRTSCTS) {
if (old_cr & UART011_CR_RTS)
@@ -1901,17 +2000,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
quot -= 2;
}
/* Set baud rate */
- writew(quot & 0x3f, port->membase + UART011_FBRD);
- writew(quot >> 6, port->membase + UART011_IBRD);
+ pl011_write(quot & 0x3f, uap, REG_FBRD);
+ pl011_write(quot >> 6, uap, REG_IBRD);
/*
* ----------v----------v----------v----------v-----
- * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
- * UART011_FBRD & UART011_IBRD.
+ * NOTE: REG_LCRH_TX and REG_LCRH_RX MUST BE WRITTEN AFTER
+ * REG_FBRD & REG_IBRD.
* ----------^----------^----------^----------^-----
*/
pl011_write_lcr_h(uap, lcr_h);
- writew(old_cr, port->membase + UART011_CR);
+ pl011_write(old_cr, uap, REG_CR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -2052,16 +2151,16 @@ static void pl011_console_putchar(struct uart_port *port, int ch)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
- barrier();
- writew(ch, uap->port.membase + UART01x_DR);
+ while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
+ cpu_relax();
+ pl011_write(ch, uap, REG_DR);
}
static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int status, old_cr = 0, new_cr;
+ unsigned int old_cr = 0, new_cr;
unsigned long flags;
int locked = 1;
@@ -2079,10 +2178,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* First save the CR then disable the interrupts
*/
if (!uap->vendor->always_enabled) {
- old_cr = readw(uap->port.membase + UART011_CR);
+ old_cr = pl011_read(uap, REG_CR);
new_cr = old_cr & ~UART011_CR_CTSEN;
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- writew(new_cr, uap->port.membase + UART011_CR);
+ pl011_write(new_cr, uap, REG_CR);
}
uart_console_write(&uap->port, s, count, pl011_console_putchar);
@@ -2091,11 +2190,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
- do {
- status = readw(uap->port.membase + UART01x_FR);
- } while (status & UART01x_FR_BUSY);
+ while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+ cpu_relax();
if (!uap->vendor->always_enabled)
- writew(old_cr, uap->port.membase + UART011_CR);
+ pl011_write(old_cr, uap, REG_CR);
if (locked)
spin_unlock(&uap->port.lock);
@@ -2108,10 +2206,10 @@ static void __init
pl011_console_get_options(struct uart_amba_port *uap, int *baud,
int *parity, int *bits)
{
- if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
+ if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, ibrd, fbrd;
- lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+ lcr_h = pl011_read(uap, REG_LCRH_TX);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
@@ -2126,13 +2224,13 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
else
*bits = 8;
- ibrd = readw(uap->port.membase + UART011_IBRD);
- fbrd = readw(uap->port.membase + UART011_FBRD);
+ ibrd = pl011_read(uap, REG_IBRD);
+ fbrd = pl011_read(uap, REG_FBRD);
*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
if (uap->vendor->oversampling) {
- if (readw(uap->port.membase + UART011_CR)
+ if (pl011_read(uap, REG_CR)
& ST_UART011_CR_OVSFACT)
*baud *= 2;
}
@@ -2205,10 +2303,13 @@ static struct 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);
+ cpu_relax();
+ if (port->iotype == UPIO_MEM32)
+ writel(c, port->membase + UART01x_DR);
+ else
+ writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
- ;
+ cpu_relax();
}
static void pl011_early_write(struct console *con, const char *s, unsigned n)
@@ -2227,7 +2328,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
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
@@ -2319,7 +2419,6 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
uap->port.dev = dev;
uap->port.mapbase = mmiobase->start;
uap->port.membase = base;
- uap->port.iotype = UPIO_MEM;
uap->port.fifosize = uap->fifosize;
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = index;
@@ -2334,8 +2433,8 @@ static int pl011_register_port(struct uart_amba_port *uap)
int ret;
/* Ensure interrupts from this UART are masked and cleared */
- writew(0, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ pl011_write(0, uap, REG_IMSC);
+ pl011_write(0xffff, uap, REG_ICR);
if (!amba_reg.state) {
ret = uart_register_driver(&amba_reg);
@@ -2372,10 +2471,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (IS_ERR(uap->clk))
return PTR_ERR(uap->clk);
+ uap->reg_offset = vendor->reg_offset;
uap->vendor = vendor;
- uap->lcrh_rx = vendor->lcrh_rx;
- uap->lcrh_tx = vendor->lcrh_tx;
uap->fifosize = vendor->get_fifosize(dev);
+ uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
uap->port.irq = dev->irq[0];
uap->port.ops = &amba_pl011_pops;
@@ -2453,8 +2552,10 @@ static int sbsa_uart_probe(struct platform_device *pdev)
if (!uap)
return -ENOMEM;
+ uap->reg_offset = vendor_sbsa.reg_offset;
uap->vendor = &vendor_sbsa;
uap->fifosize = 32;
+ uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM;
uap->port.irq = platform_get_irq(pdev, 0);
uap->port.ops = &sbsa_uart_pops;
uap->fixed_baud = baudrate;
diff --git a/drivers/tty/serial/amba-pl011.h b/drivers/tty/serial/amba-pl011.h
new file mode 100644
index 000000000000..411c60e1f9a4
--- /dev/null
+++ b/drivers/tty/serial/amba-pl011.h
@@ -0,0 +1,34 @@
+#ifndef AMBA_PL011_H
+#define AMBA_PL011_H
+
+enum {
+ REG_DR,
+ REG_ST_DMAWM,
+ REG_ST_TIMEOUT,
+ REG_FR,
+ REG_LCRH_RX,
+ REG_LCRH_TX,
+ REG_IBRD,
+ REG_FBRD,
+ REG_CR,
+ REG_IFLS,
+ REG_IMSC,
+ REG_RIS,
+ REG_MIS,
+ REG_ICR,
+ REG_DMACR,
+ REG_ST_XFCR,
+ REG_ST_XON1,
+ REG_ST_XON2,
+ REG_ST_XOFF1,
+ REG_ST_XOFF2,
+ REG_ST_ITCR,
+ REG_ST_ITIP,
+ REG_ST_ABCR,
+ REG_ST_ABIMSC,
+
+ /* The size of the array - must be last */
+ REG_ARRAY_SIZE,
+};
+
+#endif
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 03ebe401fff7..3a1de5c87cb4 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev,
dev->con->write = arc_early_serial_write;
return 0;
}
-EARLYCON_DECLARE(arc_uart, arc_early_console_setup);
OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 94294558943c..d9439e6ab719 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -155,14 +154,14 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct mctrl_gpios *gpios;
- int gpio_irq[UART_GPIO_MAX];
unsigned int tx_done_mask;
u32 fifo_size;
u32 rts_high;
u32 rts_low;
bool ms_irq_enabled;
- bool is_usart; /* usart or uart */
- struct timer_list uart_timer; /* uart timer */
+ u32 rtor; /* address of receiver timeout register if it exists */
+ bool has_hw_timer;
+ struct timer_list uart_timer;
bool suspended;
unsigned int pending;
@@ -190,8 +189,6 @@ static const struct of_device_id atmel_serial_dt_ids[] = {
{ .compatible = "atmel,at91sam9260-usart" },
{ /* sentinel */ }
};
-
-MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
#endif
static inline struct atmel_uart_port *
@@ -550,27 +547,21 @@ static void atmel_enable_ms(struct uart_port *port)
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
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
ier |= ATMEL_US_CTSIC;
- if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR))
ier |= ATMEL_US_DSRIC;
- if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI))
ier |= ATMEL_US_RIIC;
- if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD))
ier |= ATMEL_US_DCDIC;
atmel_uart_writel(port, ATMEL_US_IER, ier);
+
+ mctrl_gpio_enable_ms(atmel_port->gpios);
}
/*
@@ -589,24 +580,18 @@ static void atmel_disable_ms(struct uart_port *port)
atmel_port->ms_irq_enabled = false;
- if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
- else
+ mctrl_gpio_disable_ms(atmel_port->gpios);
+
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
idr |= ATMEL_US_CTSIC;
- if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR))
idr |= ATMEL_US_DSRIC;
- if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI))
idr |= ATMEL_US_RIIC;
- if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD))
idr |= ATMEL_US_DCDIC;
atmel_uart_writel(port, ATMEL_US_IDR, idr);
@@ -1264,7 +1249,6 @@ 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, mask, pass_counter = 0;
- bool gpio_handled = false;
spin_lock(&atmel_port->lock_suspended);
@@ -1272,24 +1256,6 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
status = atmel_get_lines_status(port);
mask = atmel_uart_readl(port, ATMEL_US_IMR);
pending = status & mask;
- 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;
@@ -1745,19 +1711,24 @@ static void atmel_get_ip_name(struct uart_port *port)
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int name = atmel_uart_readl(port, ATMEL_US_NAME);
u32 version;
- int usart, uart;
- /* usart and uart ascii */
- usart = 0x55534152;
- uart = 0x44424755;
-
- atmel_port->is_usart = false;
-
- if (name == usart) {
- dev_dbg(port->dev, "This is usart\n");
- atmel_port->is_usart = true;
- } else if (name == uart) {
- dev_dbg(port->dev, "This is uart\n");
- atmel_port->is_usart = false;
+ u32 usart, dbgu_uart, new_uart;
+ /* ASCII decoding for IP version */
+ usart = 0x55534152; /* USAR(T) */
+ dbgu_uart = 0x44424755; /* DBGU */
+ new_uart = 0x55415254; /* UART */
+
+ atmel_port->has_hw_timer = false;
+
+ if (name == new_uart) {
+ dev_dbg(port->dev, "Uart with hw timer");
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_UA_RTOR;
+ } else if (name == usart) {
+ dev_dbg(port->dev, "Usart\n");
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_US_RTOR;
+ } else if (name == dbgu_uart) {
+ dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
} else {
/* fallback for older SoCs: use version field */
version = atmel_uart_readl(port, ATMEL_US_VERSION);
@@ -1765,12 +1736,12 @@ static void atmel_get_ip_name(struct uart_port *port)
case 0x302:
case 0x10213:
dev_dbg(port->dev, "This version is usart\n");
- atmel_port->is_usart = true;
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_US_RTOR;
break;
case 0x203:
case 0x10202:
dev_dbg(port->dev, "This version is uart\n");
- atmel_port->is_usart = false;
break;
default:
dev_err(port->dev, "Not supported ip name nor version, set to uart\n");
@@ -1778,45 +1749,6 @@ 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
*/
@@ -1846,13 +1778,6 @@ 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;
-
tasklet_enable(&atmel_port->tasklet);
/*
@@ -1916,12 +1841,13 @@ static int atmel_startup(struct uart_port *port)
if (atmel_use_pdc_rx(port)) {
/* set UART timeout */
- if (!atmel_port->is_usart) {
+ if (!atmel_port->has_hw_timer) {
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
} else {
- atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
+ atmel_uart_writel(port, atmel_port->rtor,
+ PDC_RX_TIMEOUT);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
atmel_uart_writel(port, ATMEL_US_IER,
@@ -1931,12 +1857,13 @@ static int atmel_startup(struct uart_port *port)
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
} else if (atmel_use_dma_rx(port)) {
/* set UART timeout */
- if (!atmel_port->is_usart) {
+ if (!atmel_port->has_hw_timer) {
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
} else {
- atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
+ atmel_uart_writel(port, atmel_port->rtor,
+ PDC_RX_TIMEOUT);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
atmel_uart_writel(port, ATMEL_US_IER,
@@ -1948,11 +1875,6 @@ static int atmel_startup(struct uart_port *port)
}
return 0;
-
-free_irq:
- free_irq(port->irq, port);
-
- return retval;
}
/*
@@ -2018,7 +1940,6 @@ static void atmel_shutdown(struct uart_port *port)
* Free the interrupts
*/
free_irq(port->irq, port);
- atmel_free_gpio_irq(port);
atmel_port->ms_irq_enabled = false;
@@ -2565,13 +2486,13 @@ static int __init atmel_console_init(void)
struct atmel_uart_data *pdata =
dev_get_platdata(&atmel_default_console_device->dev);
int id = pdata->num;
- struct atmel_uart_port *port = &atmel_ports[id];
+ struct atmel_uart_port *atmel_port = &atmel_ports[id];
- port->backup_imr = 0;
- port->uart.line = id;
+ atmel_port->backup_imr = 0;
+ atmel_port->uart.line = id;
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
- ret = atmel_init_port(port, atmel_default_console_device);
+ ret = atmel_init_port(atmel_port, atmel_default_console_device);
if (ret)
return ret;
register_console(&atmel_console);
@@ -2686,43 +2607,23 @@ 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_noauto(dev, 0);
- if (IS_ERR(p->gpios))
- return PTR_ERR(p->gpios);
-
- 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 void atmel_serial_probe_fifos(struct atmel_uart_port *port,
+static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
- port->fifo_size = 0;
- port->rts_low = 0;
- port->rts_high = 0;
+ atmel_port->fifo_size = 0;
+ atmel_port->rts_low = 0;
+ atmel_port->rts_high = 0;
if (of_property_read_u32(pdev->dev.of_node,
"atmel,fifo-size",
- &port->fifo_size))
+ &atmel_port->fifo_size))
return;
- if (!port->fifo_size)
+ if (!atmel_port->fifo_size)
return;
- if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
- port->fifo_size = 0;
+ if (atmel_port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
+ atmel_port->fifo_size = 0;
dev_err(&pdev->dev, "Invalid FIFO size\n");
return;
}
@@ -2735,22 +2636,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
* Threshold to a reasonably high value respecting this 16 data
* empirical rule when possible.
*/
- port->rts_high = max_t(int, port->fifo_size >> 1,
- port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
- port->rts_low = max_t(int, port->fifo_size >> 2,
- port->fifo_size - ATMEL_RTS_LOW_OFFSET);
+ atmel_port->rts_high = max_t(int, atmel_port->fifo_size >> 1,
+ atmel_port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
+ atmel_port->rts_low = max_t(int, atmel_port->fifo_size >> 2,
+ atmel_port->fifo_size - ATMEL_RTS_LOW_OFFSET);
dev_info(&pdev->dev, "Using FIFO (%u data)\n",
- port->fifo_size);
+ atmel_port->fifo_size);
dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n",
- port->rts_high);
+ atmel_port->rts_high);
dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n",
- port->rts_low);
+ atmel_port->rts_low);
}
static int atmel_serial_probe(struct platform_device *pdev)
{
- struct atmel_uart_port *port;
+ struct atmel_uart_port *atmel_port;
struct device_node *np = pdev->dev.of_node;
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
void *data;
@@ -2781,91 +2682,101 @@ static int atmel_serial_probe(struct platform_device *pdev)
goto err;
}
- port = &atmel_ports[ret];
- port->backup_imr = 0;
- port->uart.line = ret;
- atmel_serial_probe_fifos(port, pdev);
+ atmel_port = &atmel_ports[ret];
+ atmel_port->backup_imr = 0;
+ atmel_port->uart.line = ret;
+ atmel_serial_probe_fifos(atmel_port, pdev);
- spin_lock_init(&port->lock_suspended);
+ spin_lock_init(&atmel_port->lock_suspended);
- ret = atmel_init_gpios(port, &pdev->dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to initialize GPIOs.");
+ ret = atmel_init_port(atmel_port, pdev);
+ if (ret)
goto err_clear_bit;
- }
- ret = atmel_init_port(port, pdev);
- if (ret)
+ atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0);
+ if (IS_ERR(atmel_port->gpios)) {
+ ret = PTR_ERR(atmel_port->gpios);
goto err_clear_bit;
+ }
- if (!atmel_use_pdc_rx(&port->uart)) {
+ if (!atmel_use_pdc_rx(&atmel_port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
if (!data)
goto err_alloc_ring;
- port->rx_ring.buf = data;
+ atmel_port->rx_ring.buf = data;
}
- rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED;
+ rs485_enabled = atmel_port->uart.rs485.flags & SER_RS485_ENABLED;
- ret = uart_add_one_port(&atmel_uart, &port->uart);
+ ret = uart_add_one_port(&atmel_uart, &atmel_port->uart);
if (ret)
goto err_add_port;
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
- if (atmel_is_console_port(&port->uart)
+ if (atmel_is_console_port(&atmel_port->uart)
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
/*
* The serial core enabled the clock for us, so undo
* the clk_prepare_enable() in atmel_console_setup()
*/
- clk_disable_unprepare(port->clk);
+ clk_disable_unprepare(atmel_port->clk);
}
#endif
device_init_wakeup(&pdev->dev, 1);
- platform_set_drvdata(pdev, port);
+ platform_set_drvdata(pdev, atmel_port);
/*
* The peripheral clock has been disabled by atmel_init_port():
* enable it before accessing I/O registers
*/
- clk_prepare_enable(port->clk);
+ clk_prepare_enable(atmel_port->clk);
if (rs485_enabled) {
- atmel_uart_writel(&port->uart, ATMEL_US_MR,
+ atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR,
ATMEL_US_USMODE_NORMAL);
- atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN);
+ atmel_uart_writel(&atmel_port->uart, ATMEL_US_CR,
+ ATMEL_US_RTSEN);
}
/*
* Get port name of usart or uart
*/
- atmel_get_ip_name(&port->uart);
+ atmel_get_ip_name(&atmel_port->uart);
/*
* The peripheral clock can now safely be disabled till the port
* is used
*/
- clk_disable_unprepare(port->clk);
+ clk_disable_unprepare(atmel_port->clk);
return 0;
err_add_port:
- kfree(port->rx_ring.buf);
- port->rx_ring.buf = NULL;
+ kfree(atmel_port->rx_ring.buf);
+ atmel_port->rx_ring.buf = NULL;
err_alloc_ring:
- if (!atmel_is_console_port(&port->uart)) {
- clk_put(port->clk);
- port->clk = NULL;
+ if (!atmel_is_console_port(&atmel_port->uart)) {
+ clk_put(atmel_port->clk);
+ atmel_port->clk = NULL;
}
err_clear_bit:
- clear_bit(port->uart.line, atmel_ports_in_use);
+ clear_bit(atmel_port->uart.line, atmel_ports_in_use);
err:
return ret;
}
+/*
+ * Even if the driver is not modular, it makes sense to be able to
+ * unbind a device: there can be many bound devices, and there are
+ * situations where dynamic binding and unbinding can be useful.
+ *
+ * For example, a connected device can require a specific firmware update
+ * protocol that needs bitbanging on IO lines, but use the regular serial
+ * port in the normal case.
+ */
static int atmel_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
@@ -2885,6 +2796,7 @@ static int atmel_serial_remove(struct platform_device *pdev)
clear_bit(port->line, atmel_ports_in_use);
clk_put(atmel_port->clk);
+ atmel_port->clk = NULL;
return ret;
}
@@ -2895,8 +2807,8 @@ static struct platform_driver atmel_serial_driver = {
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.driver = {
- .name = "atmel_usart",
- .of_match_table = of_match_ptr(atmel_serial_dt_ids),
+ .name = "atmel_usart",
+ .of_match_table = of_match_ptr(atmel_serial_dt_ids),
},
};
@@ -2914,17 +2826,4 @@ static int __init atmel_serial_init(void)
return ret;
}
-
-static void __exit atmel_serial_exit(void)
-{
- platform_driver_unregister(&atmel_serial_driver);
- uart_unregister_driver(&atmel_uart);
-}
-
-module_init(atmel_serial_init);
-module_exit(atmel_serial_exit);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:atmel_usart");
+device_initcall(atmel_serial_init);
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index a1c0a89d9c7f..c28e5c24da16 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -653,7 +653,7 @@ static struct uart_ops bcm_uart_ops = {
#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
+static void wait_for_xmitr(struct uart_port *port)
{
unsigned int tmout;
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index ae3cf94b146b..293ecbb00684 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -213,7 +213,7 @@ static void bfin_serial_stop_rx(struct uart_port *port)
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
unsigned int status, ch, flg;
- static struct timeval anomaly_start = { .tv_sec = 0 };
+ static u64 anomaly_start;
status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
@@ -246,27 +246,24 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
* character time +/- some percent. So 1.5 sounds good. All other
* Blackfin families operate properly. Woo.
*/
- if (anomaly_start.tv_sec) {
- struct timeval curr;
- suseconds_t usecs;
+ if (anomaly_start > 0) {
+ u64 curr, nsecs, threshold_ns;
if ((~ch & (~ch + 1)) & 0xff)
goto known_good_char;
- do_gettimeofday(&curr);
- if (curr.tv_sec - anomaly_start.tv_sec > 1)
+ curr = ktime_get_ns();
+ nsecs = curr - anomaly_start;
+ if (nsecs >> 32)
goto known_good_char;
- usecs = 0;
- if (curr.tv_sec != anomaly_start.tv_sec)
- usecs += USEC_PER_SEC;
- usecs += curr.tv_usec - anomaly_start.tv_usec;
-
- if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
+ threshold_ns = UART_GET_ANOMALY_THRESHOLD(uart)
+ * NSEC_PER_USEC;
+ if (nsecs > threshold_ns)
goto known_good_char;
if (ch)
- anomaly_start.tv_sec = 0;
+ anomaly_start = 0;
else
anomaly_start = curr;
@@ -274,14 +271,14 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
known_good_char:
status &= ~BI;
- anomaly_start.tv_sec = 0;
+ anomaly_start = 0;
}
}
if (status & BI) {
if (ANOMALY_05000363)
if (bfin_revid() < 5)
- do_gettimeofday(&anomaly_start);
+ anomaly_start = ktime_get_ns();
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b3a4e0cdddaa..5beafd2d2218 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -450,6 +450,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
struct clps711x_port *s;
struct resource *res;
struct clk *uart_clk;
+ int irq;
if (index < 0 || index >= UART_CLPS711X_NR)
return -EINVAL;
@@ -467,12 +468,13 @@ static int uart_clps711x_probe(struct platform_device *pdev)
if (IS_ERR(s->port.membase))
return PTR_ERR(s->port.membase);
- s->port.irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(s->port.irq))
- return s->port.irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ s->port.irq = irq;
s->rx_irq = platform_get_irq(pdev, 1);
- if (IS_ERR_VALUE(s->rx_irq))
+ if (s->rx_irq < 0)
return s->rx_irq;
if (!np) {
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index f13f2ebd215b..c0172bf54a9b 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -1413,9 +1413,8 @@ rs_stop(struct tty_struct *tty)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
- if (tty->termios.c_iflag & IXON ) {
+ if (I_IXON(tty))
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
- }
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
local_irq_restore(flags);
@@ -1436,9 +1435,8 @@ rs_start(struct tty_struct *tty)
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (tty->termios.c_iflag & IXON ) {
+ if (I_IXON(tty))
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
- }
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
if (!info->uses_dma_out &&
@@ -2968,7 +2966,7 @@ static int rs_raw_write(struct tty_struct *tty,
local_save_flags(flags);
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
- DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line, "ldisc\n"));
/* The local_irq_disable/restore_flags pairs below are needed
@@ -3161,13 +3159,12 @@ rs_throttle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("throttle %s: %lu....\n", tty_name(tty),
- (unsigned long)tty->ldisc.chars_in_buffer(tty));
+ printk("throttle %s ....\n", tty_name(tty));
#endif
- DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line,"rs_throttle\n"));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
/* Turn off RTS line */
e100_rts(info, 0);
}
@@ -3181,13 +3178,12 @@ rs_unthrottle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("unthrottle %s: %lu....\n", tty_name(tty),
- (unsigned long)tty->ldisc.chars_in_buffer(tty));
+ printk("unthrottle %s ....\n", tty_name(tty));
#endif
- DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc\n"));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
/* Assert RTS line */
e100_rts(info, 1);
}
@@ -3555,8 +3551,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info);
/* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
rs_start(tty);
}
@@ -3615,7 +3610,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
local_irq_restore(flags);
return;
}
- info->port.flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
@@ -3654,7 +3648,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
schedule_timeout_interruptible(info->port.close_delay);
wake_up_interruptible(&info->port.open_wait);
}
- info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
local_irq_restore(flags);
/* port closed */
@@ -3767,9 +3761,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL) {
- do_clocal = 1;
- }
+ if (C_CLOCAL(tty))
+ do_clocal = 1;
/*
* Block waiting for the carrier detect and the line to become
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index a80cdad114f3..02ad6953b167 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -453,7 +453,7 @@ static struct uart_driver digicolor_uart = {
static int digicolor_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret, index;
+ int irq, ret, index;
struct digicolor_port *dp;
struct resource *res;
struct clk *uart_clk;
@@ -481,9 +481,10 @@ static int digicolor_uart_probe(struct platform_device *pdev)
if (IS_ERR(dp->port.membase))
return PTR_ERR(dp->port.membase);
- dp->port.irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(dp->port.irq))
- return dp->port.irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ dp->port.irq = irq;
dp->port.iotype = UPIO_MEM;
dp->port.uartclk = clk_get_rate(uart_clk);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index b5b2f2be6be7..067783f0523c 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -19,7 +19,8 @@
#include <linux/io.h>
#include <linux/serial_core.h>
#include <linux/sizes.h>
-#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
@@ -28,22 +29,15 @@
#include <asm/serial.h>
static struct console early_con = {
- .name = "uart", /* 8250 console switch requires this name */
+ .name = "uart", /* fixed up at earlycon registration */
.flags = CON_PRINTBUFFER | CON_BOOT,
- .index = -1,
+ .index = 0,
};
static struct earlycon_device early_console_dev = {
.con = &early_con,
};
-extern struct earlycon_id __earlycon_table[];
-static const struct earlycon_id __earlycon_table_sentinel
- __used __section(__earlycon_table_end);
-
-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;
@@ -61,6 +55,39 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
return base;
}
+static void __init earlycon_init(struct earlycon_device *device,
+ const char *name)
+{
+ struct console *earlycon = device->con;
+ struct uart_port *port = &device->port;
+ const char *s;
+ size_t len;
+
+ /* scan backwards from end of string for first non-numeral */
+ for (s = name + strlen(name);
+ s > name && s[-1] >= '0' && s[-1] <= '9';
+ s--)
+ ;
+ if (*s)
+ earlycon->index = simple_strtoul(s, NULL, 10);
+ len = s - name;
+ strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
+ earlycon->data = &early_console_dev;
+
+ if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
+ port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
+ pr_info("%s%d at MMIO%s %pa (options '%s')\n",
+ earlycon->name, earlycon->index,
+ (port->iotype == UPIO_MEM) ? "" :
+ (port->iotype == UPIO_MEM16) ? "16" :
+ (port->iotype == UPIO_MEM32) ? "32" : "32be",
+ &port->mapbase, device->options);
+ else
+ pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
+ earlycon->name, earlycon->index,
+ port->iobase, device->options);
+}
+
static int __init parse_options(struct earlycon_device *device, char *options)
{
struct uart_port *port = &device->port;
@@ -71,10 +98,16 @@ static int __init parse_options(struct earlycon_device *device, char *options)
return -EINVAL;
switch (port->iotype) {
+ case UPIO_MEM:
+ port->mapbase = addr;
+ break;
+ case UPIO_MEM16:
+ port->regshift = 1;
+ port->mapbase = addr;
+ break;
case UPIO_MEM32:
case UPIO_MEM32BE:
- port->regshift = 2; /* fall-through */
- case UPIO_MEM:
+ port->regshift = 2;
port->mapbase = addr;
break;
case UPIO_PORT:
@@ -91,18 +124,6 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length);
}
- if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 ||
- port->iotype == UPIO_MEM32BE)
- pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
- (port->iotype == UPIO_MEM) ? "" :
- (port->iotype == UPIO_MEM32) ? "32" : "32be",
- (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;
}
@@ -120,7 +141,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
- early_console_dev.con->data = &early_console_dev;
+ earlycon_init(&early_console_dev, match->name);
err = match->setup(&early_console_dev, buf);
if (err < 0)
return err;
@@ -159,7 +180,7 @@ int __init setup_earlycon(char *buf)
if (early_con.flags & CON_ENABLED)
return -EALREADY;
- for (match = __earlycon_table; match->name[0]; match++) {
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
size_t len = strlen(match->name);
if (strncmp(buf, match->name, len))
@@ -197,20 +218,62 @@ static int __init param_setup_earlycon(char *buf)
}
early_param("earlycon", param_setup_earlycon);
-int __init of_setup_earlycon(unsigned long addr,
- int (*setup)(struct earlycon_device *, const char *))
+#ifdef CONFIG_OF_EARLY_FLATTREE
+
+int __init of_setup_earlycon(const struct earlycon_id *match,
+ unsigned long node,
+ const char *options)
{
int err;
struct uart_port *port = &early_console_dev.port;
+ const __be32 *val;
+ bool big_endian;
+ u64 addr;
spin_lock_init(&port->lock);
port->iotype = UPIO_MEM;
+ addr = of_flat_dt_translate_address(node);
+ if (addr == OF_BAD_ADDR) {
+ pr_warn("[%s] bad address\n", match->name);
+ return -ENXIO;
+ }
port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
- port->membase = earlycon_map(addr, SZ_4K);
+ port->membase = earlycon_map(port->mapbase, SZ_4K);
+
+ val = of_get_flat_dt_prop(node, "reg-offset", NULL);
+ if (val)
+ port->mapbase += be32_to_cpu(*val);
+ val = of_get_flat_dt_prop(node, "reg-shift", NULL);
+ if (val)
+ port->regshift = be32_to_cpu(*val);
+ big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
+ (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
+ of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
+ val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
+ if (val) {
+ switch (be32_to_cpu(*val)) {
+ case 1:
+ port->iotype = UPIO_MEM;
+ break;
+ case 2:
+ port->iotype = UPIO_MEM16;
+ break;
+ case 4:
+ port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
+ break;
+ default:
+ pr_warn("[%s] unsupported reg-io-width\n", match->name);
+ return -EINVAL;
+ }
+ }
- early_console_dev.con->data = &early_console_dev;
- err = setup(&early_console_dev, NULL);
+ if (options) {
+ strlcpy(early_console_dev.options, options,
+ sizeof(early_console_dev.options));
+ }
+ earlycon_init(&early_console_dev, match->name);
+ err = match->setup(&early_console_dev, options);
if (err < 0)
return err;
if (!early_console_dev.con->write)
@@ -220,3 +283,5 @@ int __init of_setup_earlycon(unsigned long addr,
register_console(early_console_dev.con);
return 0;
}
+
+#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index ffc7cb2585a6..c60a8d5e4020 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#define SERIAL_DO_RESTART
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 88246f7e435a..2085a6cfa44b 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -395,8 +395,10 @@ static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
if (h1 == 0 && h2 == 0) {
*received_cts = 0;
+ *more = 0;
return IFX_SPI_HEADER_0;
} else if (h1 == 0xffff && h2 == 0xffff) {
+ *more = 0;
/* spi_slave_cts remains as it was */
return IFX_SPI_HEADER_F;
}
@@ -688,6 +690,7 @@ static void ifx_spi_complete(void *ctx)
ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
(size_t)actual_length);
} else {
+ more = 0;
dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
ifx_dev->spi_msg.status);
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 016e4be05cec..231e7d5caf6c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -44,6 +44,8 @@
#include <linux/platform_data/serial-imx.h>
#include <linux/platform_data/dma-imx.h>
+#include "serial_mctrl_gpio.h"
+
/* Register definitions */
#define URXD0 0x0 /* Receiver Register */
#define URTX0 0x40 /* Transmitter Register */
@@ -148,8 +150,11 @@
#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
#define USR2_IDLE (1<<12) /* Idle condition */
+#define USR2_RIDELT (1<<10) /* Ring Interrupt Delta */
+#define USR2_RIIN (1<<9) /* Ring Indicator Input */
#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
#define USR2_WAKE (1<<7) /* Wake */
+#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
#define USR2_TXDC (1<<3) /* Transmitter complete */
#define USR2_BRCD (1<<2) /* Break condition */
@@ -206,6 +211,8 @@ struct imx_port {
struct clk *clk_per;
const struct imx_uart_data *devdata;
+ struct mctrl_gpios *gpios;
+
/* DMA fields */
unsigned int dma_is_inited:1;
unsigned int dma_is_enabled:1;
@@ -308,49 +315,24 @@ static void imx_port_ucrs_restore(struct uart_port *port,
}
#endif
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void imx_mctrl_check(struct imx_port *sport)
+static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
{
- unsigned int status, changed;
-
- status = sport->port.ops->get_mctrl(&sport->port);
- changed = status ^ sport->old_status;
-
- if (changed == 0)
- return;
-
- sport->old_status = status;
+ *ucr2 &= ~UCR2_CTSC;
+ *ucr2 |= UCR2_CTS;
- if (changed & TIOCM_RI)
- sport->port.icount.rng++;
- if (changed & TIOCM_DSR)
- sport->port.icount.dsr++;
- if (changed & TIOCM_CAR)
- uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
- if (changed & TIOCM_CTS)
- uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
- wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+ mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS);
}
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void imx_timeout(unsigned long data)
+static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
{
- struct imx_port *sport = (struct imx_port *)data;
- unsigned long flags;
+ *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
- if (sport->port.state) {
- spin_lock_irqsave(&sport->port.lock, flags);
- imx_mctrl_check(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS);
+}
- mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
- }
+static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2)
+{
+ *ucr2 |= UCR2_CTSC;
}
/*
@@ -376,9 +358,9 @@ static void imx_stop_tx(struct uart_port *port)
readl(port->membase + USR2) & USR2_TXDC) {
temp = readl(port->membase + UCR2);
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
- temp &= ~UCR2_CTS;
+ imx_port_rts_inactive(sport, &temp);
else
- temp |= UCR2_CTS;
+ imx_port_rts_active(sport, &temp);
writel(temp, port->membase + UCR2);
temp = readl(port->membase + UCR4);
@@ -420,6 +402,8 @@ static void imx_enable_ms(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
mod_timer(&sport->timer, jiffies);
+
+ mctrl_gpio_enable_ms(sport->gpios);
}
static void imx_dma_tx(struct imx_port *sport);
@@ -579,14 +563,14 @@ static void imx_start_tx(struct uart_port *port)
unsigned long temp;
if (port->rs485.flags & SER_RS485_ENABLED) {
- /* enable transmitter and shifter empty irq */
temp = readl(port->membase + UCR2);
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
- temp &= ~UCR2_CTS;
+ imx_port_rts_inactive(sport, &temp);
else
- temp |= UCR2_CTS;
+ imx_port_rts_active(sport, &temp);
writel(temp, port->membase + UCR2);
+ /* enable transmitter and shifter empty irq */
temp = readl(port->membase + UCR4);
temp |= UCR4_TCEN;
writel(temp, port->membase + UCR4);
@@ -801,23 +785,35 @@ static unsigned int imx_tx_empty(struct uart_port *port)
/*
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
*/
-static unsigned int imx_get_mctrl(struct uart_port *port)
+static unsigned int imx_get_hwmctrl(struct imx_port *sport)
{
- struct imx_port *sport = (struct imx_port *)port;
- unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+ unsigned int tmp = TIOCM_DSR;
+ unsigned usr1 = readl(sport->port.membase + USR1);
- if (readl(sport->port.membase + USR1) & USR1_RTSS)
+ if (usr1 & USR1_RTSS)
tmp |= TIOCM_CTS;
- if (readl(sport->port.membase + UCR2) & UCR2_CTS)
- tmp |= TIOCM_RTS;
+ /* in DCE mode DCDIN is always 0 */
+ if (!(usr1 & USR2_DCDIN))
+ tmp |= TIOCM_CAR;
- if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP)
- tmp |= TIOCM_LOOP;
+ /* in DCE mode RIIN is always 0 */
+ if (readl(sport->port.membase + USR2) & USR2_RIIN)
+ tmp |= TIOCM_RI;
return tmp;
}
+static unsigned int imx_get_mctrl(struct uart_port *port)
+{
+ struct imx_port *sport = (struct imx_port *)port;
+ unsigned int ret = imx_get_hwmctrl(sport);
+
+ mctrl_gpio_get(sport->gpios, &ret);
+
+ return ret;
+}
+
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -831,10 +827,17 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
writel(temp, sport->port.membase + UCR2);
}
+ temp = readl(sport->port.membase + UCR3) & ~UCR3_DSR;
+ if (!(mctrl & TIOCM_DTR))
+ temp |= UCR3_DSR;
+ writel(temp, sport->port.membase + UCR3);
+
temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP;
if (mctrl & TIOCM_LOOP)
temp |= UTS_LOOP;
writel(temp, sport->port.membase + uts_reg(sport));
+
+ mctrl_gpio_set(sport->gpios, mctrl);
}
/*
@@ -857,6 +860,51 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&sport->port.lock, flags);
}
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void imx_mctrl_check(struct imx_port *sport)
+{
+ unsigned int status, changed;
+
+ status = imx_get_hwmctrl(sport);
+ changed = status ^ sport->old_status;
+
+ if (changed == 0)
+ return;
+
+ sport->old_status = status;
+
+ if (changed & TIOCM_RI)
+ sport->port.icount.rng++;
+ if (changed & TIOCM_DSR)
+ sport->port.icount.dsr++;
+ if (changed & TIOCM_CAR)
+ uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+ if (changed & TIOCM_CTS)
+ uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+ wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void imx_timeout(unsigned long data)
+{
+ struct imx_port *sport = (struct imx_port *)data;
+ unsigned long flags;
+
+ if (sport->port.state) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ imx_mctrl_check(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+ }
+}
+
#define RX_BUF_SIZE (PAGE_SIZE)
static void imx_rx_dma_done(struct imx_port *sport)
{
@@ -1207,6 +1255,8 @@ static void imx_shutdown(struct uart_port *port)
imx_uart_dma_exit(sport);
}
+ mctrl_gpio_disable_ms(sport->gpios);
+
spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
@@ -1284,9 +1334,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
- unsigned int ucr2, old_ucr1, old_ucr2, baud, quot;
+ unsigned long ucr2, old_ucr1, old_ucr2;
+ unsigned int baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- unsigned int div, ufcr;
+ unsigned long div, ufcr;
unsigned long num, denom;
uint64_t tdiv64;
@@ -1315,19 +1366,25 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
* it under manual control and keep transmitter
* disabled.
*/
- if (!(port->rs485.flags &
- SER_RS485_RTS_AFTER_SEND))
- ucr2 |= UCR2_CTS;
+ if (port->rs485.flags &
+ SER_RS485_RTS_AFTER_SEND)
+ imx_port_rts_inactive(sport, &ucr2);
+ else
+ imx_port_rts_active(sport, &ucr2);
} else {
- ucr2 |= UCR2_CTSC;
+ imx_port_rts_auto(sport, &ucr2);
}
} else {
termios->c_cflag &= ~CRTSCTS;
}
- } else if (port->rs485.flags & SER_RS485_ENABLED)
+ } else if (port->rs485.flags & SER_RS485_ENABLED) {
/* disable transmitter */
- if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
- ucr2 |= UCR2_CTS;
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ imx_port_rts_inactive(sport, &ucr2);
+ else
+ imx_port_rts_active(sport, &ucr2);
+ }
+
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
@@ -1568,11 +1625,10 @@ static int imx_rs485_config(struct uart_port *port,
/* disable transmitter */
temp = readl(sport->port.membase + UCR2);
- temp &= ~UCR2_CTSC;
if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
- temp &= ~UCR2_CTS;
+ imx_port_rts_inactive(sport, &temp);
else
- temp |= UCR2_CTS;
+ imx_port_rts_active(sport, &temp);
writel(temp, sport->port.membase + UCR2);
}
@@ -1857,11 +1913,10 @@ static int serial_imx_probe_dt(struct imx_port *sport,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *of_id =
- of_match_device(imx_uart_dt_ids, &pdev->dev);
int ret;
- if (!np)
+ sport->devdata = of_device_get_match_data(&pdev->dev);
+ if (!sport->devdata)
/* no device tree device */
return 1;
@@ -1878,8 +1933,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
if (of_get_property(np, "fsl,dte-mode", NULL))
sport->dte_mode = 1;
- sport->devdata = of_id->data;
-
return 0;
}
#else
@@ -1948,6 +2001,10 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
+ sport->gpios = mctrl_gpio_init(&sport->port, 0);
+ if (IS_ERR(sport->gpios))
+ return PTR_ERR(sport->gpios);
+
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
@@ -2109,7 +2166,8 @@ static int imx_serial_port_suspend(struct device *dev)
uart_suspend_port(&imx_reg, &sport->port);
- return 0;
+ /* Needed to enable clock in suspend_noirq */
+ return clk_prepare(sport->clk_ipg);
}
static int imx_serial_port_resume(struct device *dev)
@@ -2122,6 +2180,8 @@ static int imx_serial_port_resume(struct device *dev)
uart_resume_port(&imx_reg, &sport->port);
+ clk_unprepare(sport->clk_ipg);
+
return 0;
}
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index efbd87a76656..a119f11bf2f4 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -70,7 +70,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out;
}
- rc = pci_request_regions(pdev, "jsm");
+ rc = pci_request_regions(pdev, JSM_DRIVER_NAME);
if (rc) {
dev_err(&pdev->dev, "pci_request_region FAILED\n");
goto out_disable_device;
@@ -328,7 +328,7 @@ static struct pci_device_id jsm_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
static struct pci_driver jsm_driver = {
- .name = "jsm",
+ .name = JSM_DRIVER_NAME,
.id_table = jsm_pci_tbl,
.probe = jsm_probe_one,
.remove = jsm_remove_one,
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 932b2accd06f..c6fdd6369534 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -714,7 +714,7 @@ static void neo_clear_break(struct jsm_channel *ch)
/*
* Parse the ISR register.
*/
-static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
+static void neo_parse_isr(struct jsm_board *brd, u32 port)
{
struct jsm_channel *ch;
u8 isr;
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 524e86ab3cae..c5ddfe542451 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -529,7 +529,6 @@ void jsm_input(struct jsm_channel *ch)
int data_len;
unsigned long lock_flags;
int len = 0;
- int n = 0;
int s = 0;
int i = 0;
@@ -569,8 +568,7 @@ void jsm_input(struct jsm_channel *ch)
*If the device is not open, or CREAD is off, flush
*input data and return immediately.
*/
- if (!tp ||
- !(tp->termios.c_cflag & CREAD) ) {
+ if (!tp || !C_CREAD(tp)) {
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"input. dropping %d bytes on port %d...\n",
@@ -598,16 +596,15 @@ void jsm_input(struct jsm_channel *ch)
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
len = tty_buffer_request_room(port, data_len);
- n = len;
/*
- * n now contains the most amount of data we can copy,
+ * len now contains the most amount of data we can copy,
* bounded either by the flip buffer size or the amount
* of data the card actually has pending...
*/
- while (n) {
+ while (len) {
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
- s = min(s, n);
+ s = min(s, len);
if (s <= 0)
break;
@@ -638,7 +635,7 @@ void jsm_input(struct jsm_channel *ch)
tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
}
tail += s;
- n -= s;
+ len -= s;
/* Flip queue if needed */
tail &= rmask;
}
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index 8f7f83a14c93..68765f7c2645 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -47,59 +47,26 @@
#define BAUD_RATE 115200
#include <linux/serial_core.h>
-#include "m32r_sio.h"
#include "m32r_sio_reg.h"
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...) printk(fmt)
-#else
-#define DEBUG_INTR(fmt...) do { } while (0)
-#endif
-
#define PASS_LIMIT 256
-#define BASE_BAUD 115200
-
/* Standard COM flags */
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism. Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
+static const struct {
+ unsigned int port;
+ unsigned int irq;
+} old_serial_port[] = {
#if defined(CONFIG_PLAT_USRV)
-
-#define SERIAL_PORT_DFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
-
-#else /* !CONFIG_PLAT_USRV */
-
-#if defined(CONFIG_SERIAL_M32R_PLDSIO)
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
- STD_COM_FLAGS }, /* ttyS0 */
+ /* PORT IRQ FLAGS */
+ { 0x3F8, PLD_IRQ_UART0 }, /* ttyS0 */
+ { 0x2F8, PLD_IRQ_UART1 }, /* ttyS1 */
+#elif defined(CONFIG_SERIAL_M32R_PLDSIO)
+ { ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV }, /* ttyS0 */
#else
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \
- STD_COM_FLAGS }, /* ttyS0 */
+ { M32R_SIO_OFFSET, M32R_IRQ_SIO0_R }, /* ttyS0 */
#endif
-
-#endif /* !CONFIG_PLAT_USRV */
-
-static struct old_serial_port old_serial_port[] = {
- SERIAL_PORT_DFNS
};
#define UART_NR ARRAY_SIZE(old_serial_port)
@@ -108,19 +75,7 @@ struct uart_sio_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
- unsigned short rev;
- unsigned char acr;
unsigned char ier;
- unsigned char lcr;
- unsigned char mcr_mask; /* mask of user bits */
- unsigned char mcr_force; /* mask of forced bits */
- unsigned char lsr_break_flag;
-
- /*
- * We provide a per-port pm hook.
- */
- void (*pm)(struct uart_port *port,
- unsigned int state, unsigned int old);
};
struct irq_info {
@@ -345,14 +300,8 @@ static void receive_chars(struct uart_sio_port *up, int *status)
*/
*status &= up->port.read_status_mask;
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- *status |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-
if (*status & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
+ pr_debug("handling break....\n");
flag = TTY_BREAK;
} else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
@@ -413,7 +362,7 @@ static void transmit_chars(struct uart_sio_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- DEBUG_INTR("THRE...");
+ pr_debug("THRE...\n");
if (uart_circ_empty(xmit))
m32r_sio_stop_tx(&up->port);
@@ -425,7 +374,7 @@ static void transmit_chars(struct uart_sio_port *up)
static inline void m32r_sio_handle_port(struct uart_sio_port *up,
unsigned int status)
{
- DEBUG_INTR("status = %x...", status);
+ pr_debug("status = %x...\n", status);
if (status & 0x04)
receive_chars(up, &status);
@@ -453,7 +402,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
struct list_head *l, *end = NULL;
int pass_counter = 0;
- DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
+ pr_debug("m32r_sio_interrupt(%d)...\n", irq);
#ifdef CONFIG_SERIAL_M32R_PLDSIO
// if (irq == PLD_IRQ_SIO0_SND)
@@ -493,7 +442,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
spin_unlock(&i->lock);
- DEBUG_INTR("end.\n");
+ pr_debug("end.\n");
return IRQ_HANDLED;
}
@@ -782,20 +731,9 @@ static void m32r_sio_set_termios(struct uart_port *port,
serial_out(up, UART_IER, up->ier);
- up->lcr = cval; /* Save LCR */
spin_unlock_irqrestore(&up->port.lock, flags);
}
-static void m32r_sio_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
- struct uart_sio_port *up =
- container_of(port, struct uart_sio_port, port);
-
- if (up->pm)
- up->pm(port, state, oldstate);
-}
-
/*
* Resource handling. This is complicated by the fact that resources
* depend on the port type. Maybe we should be claiming the standard
@@ -932,7 +870,6 @@ static struct uart_ops m32r_sio_pops = {
.startup = m32r_sio_startup,
.shutdown = m32r_sio_shutdown,
.set_termios = m32r_sio_set_termios,
- .pm = m32r_sio_pm,
.release_port = m32r_sio_release_port,
.request_port = m32r_sio_request_port,
.config_port = m32r_sio_config_port,
@@ -951,15 +888,14 @@ static void __init m32r_sio_init_ports(void)
return;
first = 0;
- for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
- i++, up++) {
+ for (i = 0, up = m32r_sio_ports; i < UART_NR; i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
- up->port.uartclk = old_serial_port[i].baud_base * 16;
- up->port.flags = old_serial_port[i].flags;
- up->port.membase = old_serial_port[i].iomem_base;
- up->port.iotype = old_serial_port[i].io_type;
- up->port.regshift = old_serial_port[i].iomem_reg_shift;
+ up->port.uartclk = BAUD_RATE * 16;
+ up->port.flags = STD_COM_FLAGS;
+ up->port.membase = 0;
+ up->port.iotype = 0;
+ up->port.regshift = 0;
up->port.ops = &m32r_sio_pops;
}
}
@@ -978,9 +914,6 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
init_timer(&up->timer);
up->timer.function = m32r_sio_timeout;
- up->mcr_mask = ~0;
- up->mcr_force = 0;
-
uart_add_one_port(drv, &up->port);
}
}
@@ -990,7 +923,7 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
/*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct uart_sio_port *up)
+static void wait_for_xmitr(struct uart_sio_port *up)
{
unsigned int status, tmout = 10000;
@@ -1112,28 +1045,6 @@ static struct uart_driver m32r_sio_reg = {
.cons = M32R_SIO_CONSOLE,
};
-/**
- * m32r_sio_suspend_port - suspend one serial port
- * @line: serial line number
- *
- * Suspend one serial port.
- */
-void m32r_sio_suspend_port(int line)
-{
- uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-/**
- * m32r_sio_resume_port - resume one serial port
- * @line: serial line number
- *
- * Resume one serial port.
- */
-void m32r_sio_resume_port(int line)
-{
- uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
static int __init m32r_sio_init(void)
{
int ret, i;
@@ -1163,8 +1074,5 @@ static void __exit m32r_sio_exit(void)
module_init(m32r_sio_init);
module_exit(m32r_sio_exit);
-EXPORT_SYMBOL(m32r_sio_suspend_port);
-EXPORT_SYMBOL(m32r_sio_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
deleted file mode 100644
index 8129824496c6..000000000000
--- a/drivers/tty/serial/m32r_sio.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * m32r_sio.h
- *
- * Driver for M32R serial ports
- *
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- * Based on drivers/serial/8250.h.
- *
- * Copyright (C) 2001 Russell King.
- * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/pci.h>
-
-struct m32r_sio_probe {
- struct module *owner;
- int (*pci_init_one)(struct pci_dev *dev);
- void (*pci_remove_one)(struct pci_dev *dev);
- void (*pnp_init)(void);
-};
-
-int m32r_sio_register_probe(struct m32r_sio_probe *probe);
-void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
-void m32r_sio_get_irq_map(unsigned int *map);
-void m32r_sio_suspend_port(int line);
-void m32r_sio_resume_port(int line);
-
-struct old_serial_port {
- unsigned int uart;
- unsigned int baud_base;
- unsigned int port;
- unsigned int irq;
- unsigned int flags;
- unsigned char io_type;
- unsigned char __iomem *iomem_base;
- unsigned short iomem_reg_shift;
-};
-
-#define _INLINE_ inline
-
-#define PROBE_RSA (1 << 0)
-#define PROBE_ANY (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index d45133056f51..3f98165b479c 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1174,7 +1174,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
#ifdef CONFIG_GPIOLIB
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
- s->gpio.dev = dev;
+ s->gpio.parent = dev;
s->gpio.label = dev_name(dev);
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 3141aa20843d..a44290e9b5a8 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -158,7 +158,7 @@ static inline void men_z135_reg_set(struct men_z135_port *uart,
* @addr: Register address
* @val: value to clear
*/
-static inline void men_z135_reg_clr(struct men_z135_port *uart,
+static void men_z135_reg_clr(struct men_z135_port *uart,
u32 addr, u32 val)
{
struct uart_port *port = &uart->port;
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 0fc83c962d10..024445aa0521 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -57,6 +57,7 @@
#define AML_UART_RX_EMPTY BIT(20)
#define AML_UART_TX_FULL BIT(21)
#define AML_UART_TX_EMPTY BIT(22)
+#define AML_UART_XMIT_BUSY BIT(25)
#define AML_UART_ERR (AML_UART_PARITY_ERR | \
AML_UART_FRAME_ERR | \
AML_UART_TX_FIFO_WERR)
@@ -77,6 +78,7 @@
/* AML_UART_REG5 bits */
#define AML_UART_BAUD_MASK 0x7fffff
#define AML_UART_BAUD_USE BIT(23)
+#define AML_UART_BAUD_XTAL BIT(24)
#define AML_UART_PORT_NUM 6
#define AML_UART_DEV_NAME "ttyAML"
@@ -100,7 +102,8 @@ static unsigned int meson_uart_tx_empty(struct uart_port *port)
u32 val;
val = readl(port->membase + AML_UART_STATUS);
- return (val & AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
+ val &= (AML_UART_TX_EMPTY | AML_UART_XMIT_BUSY);
+ return (val == AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
}
static void meson_uart_stop_tx(struct uart_port *port)
@@ -108,7 +111,7 @@ static void meson_uart_stop_tx(struct uart_port *port)
u32 val;
val = readl(port->membase + AML_UART_CONTROL);
- val &= ~AML_UART_TX_EN;
+ val &= ~AML_UART_TX_INT_EN;
writel(val, port->membase + AML_UART_CONTROL);
}
@@ -131,7 +134,7 @@ static void meson_uart_shutdown(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
val = readl(port->membase + AML_UART_CONTROL);
- val &= ~(AML_UART_RX_EN | AML_UART_TX_EN);
+ val &= ~AML_UART_RX_EN;
val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
writel(val, port->membase + AML_UART_CONTROL);
@@ -142,6 +145,7 @@ static void meson_uart_start_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned int ch;
+ u32 val;
if (uart_tx_stopped(port)) {
meson_uart_stop_tx(port);
@@ -165,6 +169,12 @@ static void meson_uart_start_tx(struct uart_port *port)
port->icount.tx++;
}
+ if (!uart_circ_empty(xmit)) {
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= AML_UART_TX_INT_EN;
+ writel(val, port->membase + AML_UART_CONTROL);
+ }
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -228,8 +238,10 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
meson_receive_chars(port);
- if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL))
- meson_uart_start_tx(port);
+ if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
+ if (readl(port->membase + AML_UART_CONTROL) & AML_UART_TX_INT_EN)
+ meson_uart_start_tx(port);
+ }
spin_unlock(&port->lock);
@@ -241,10 +253,9 @@ static const char *meson_uart_type(struct uart_port *port)
return (port->type == PORT_MESON) ? "meson_uart" : NULL;
}
-static int meson_uart_startup(struct uart_port *port)
+static void meson_uart_reset(struct uart_port *port)
{
u32 val;
- int ret = 0;
val = readl(port->membase + AML_UART_CONTROL);
val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
@@ -252,6 +263,18 @@ static int meson_uart_startup(struct uart_port *port)
val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
writel(val, port->membase + AML_UART_CONTROL);
+}
+
+static int meson_uart_startup(struct uart_port *port)
+{
+ u32 val;
+ int ret = 0;
+
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= AML_UART_CLR_ERR;
+ writel(val, port->membase + AML_UART_CONTROL);
+ val &= ~AML_UART_CLR_ERR;
+ writel(val, port->membase + AML_UART_CONTROL);
val |= (AML_UART_RX_EN | AML_UART_TX_EN);
writel(val, port->membase + AML_UART_CONTROL);
@@ -272,12 +295,17 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
{
u32 val;
- while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_EMPTY))
+ while (!meson_uart_tx_empty(port))
cpu_relax();
val = readl(port->membase + AML_UART_REG5);
val &= ~AML_UART_BAUD_MASK;
- val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ if (port->uartclk == 24000000) {
+ val = ((port->uartclk / 3) / baud) - 1;
+ val |= AML_UART_BAUD_XTAL;
+ } else {
+ val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ }
val |= AML_UART_BAUD_USE;
writel(val, port->membase + AML_UART_REG5);
}
@@ -367,9 +395,26 @@ static int meson_uart_verify_port(struct uart_port *port,
return ret;
}
+static int meson_uart_res_size(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(port->dev, "cannot obtain I/O memory region");
+ return -ENODEV;
+ }
+
+ return resource_size(res);
+}
+
static void meson_uart_release_port(struct uart_port *port)
{
+ int size = meson_uart_res_size(port);
+
if (port->flags & UPF_IOREMAP) {
+ devm_release_mem_region(port->dev, port->mapbase, size);
devm_iounmap(port->dev, port->membase);
port->membase = NULL;
}
@@ -377,16 +422,10 @@ static void meson_uart_release_port(struct uart_port *port)
static int meson_uart_request_port(struct uart_port *port)
{
- struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *res;
- int size;
+ int size = meson_uart_res_size(port);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "cannot obtain I/O memory region");
- return -ENODEV;
- }
- size = resource_size(res);
+ if (size < 0)
+ return size;
if (!devm_request_mem_region(port->dev, port->mapbase, size,
dev_name(port->dev))) {
@@ -448,6 +487,7 @@ static void meson_serial_console_write(struct console *co, const char *s,
struct uart_port *port;
unsigned long flags;
int locked;
+ u32 val, tmp;
port = meson_ports[co->index];
if (!port)
@@ -463,7 +503,13 @@ static void meson_serial_console_write(struct console *co, const char *s,
locked = 1;
}
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= AML_UART_TX_EN;
+ tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
+ writel(tmp, port->membase + AML_UART_CONTROL);
+
uart_console_write(port, s, count, meson_console_putchar);
+ writel(val, port->membase + AML_UART_CONTROL);
if (locked)
spin_unlock(&port->lock);
@@ -570,6 +616,12 @@ static int meson_uart_probe(struct platform_device *pdev)
meson_ports[pdev->id] = port;
platform_set_drvdata(pdev, port);
+ /* reset port before registering (and possibly registering console) */
+ if (meson_uart_request_port(port) >= 0) {
+ meson_uart_reset(port);
+ meson_uart_release_port(port);
+ }
+
ret = uart_add_one_port(&meson_uart_driver, port);
if (ret)
meson_ports[pdev->id] = NULL;
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 8c3e51314470..3970d6a9aaca 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -346,7 +346,7 @@ static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
return mpc5xxx_uart_process_int(port);
}
-static struct psc_ops mpc52xx_psc_ops = {
+static const struct psc_ops mpc52xx_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
@@ -376,7 +376,7 @@ static struct psc_ops mpc52xx_psc_ops = {
.get_mr1 = mpc52xx_psc_get_mr1,
};
-static struct psc_ops mpc5200b_psc_ops = {
+static const struct psc_ops mpc5200b_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
@@ -969,7 +969,7 @@ static u8 mpc5125_psc_get_mr1(struct uart_port *port)
return in_8(&PSC_5125(port)->mr1);
}
-static struct psc_ops mpc5125_psc_ops = {
+static const struct psc_ops mpc5125_psc_ops = {
.fifo_init = mpc5125_psc_fifo_init,
.raw_rx_rdy = mpc5125_psc_raw_rx_rdy,
.raw_tx_rdy = mpc5125_psc_raw_tx_rdy,
@@ -1004,7 +1004,7 @@ static struct psc_ops mpc5125_psc_ops = {
.get_mr1 = mpc5125_psc_get_mr1,
};
-static struct psc_ops mpc512x_psc_ops = {
+static const struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
.raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index cadfd1cfae2b..4a3021bcc859 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -137,8 +137,6 @@ struct mpsc_port_info {
/* Internal driver state for this ctlr */
u8 ready;
u8 rcv_data;
- tcflag_t c_iflag; /* save termios->c_iflag */
- tcflag_t c_cflag; /* save termios->c_cflag */
/* Info passed in from platform */
u8 mirror_regs; /* Need to mirror regs? */
@@ -1407,9 +1405,6 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
ulong flags;
u32 chr_bits, stop_bits, par;
- pi->c_iflag = termios->c_iflag;
- pi->c_cflag = termios->c_cflag;
-
switch (termios->c_cflag & CSIZE) {
case CS5:
chr_bits = MPSC_MPCR_CL_5;
@@ -1870,12 +1865,12 @@ static int mpsc_shared_map_regs(struct platform_device *pd)
static void mpsc_shared_unmap_regs(void)
{
- if (!mpsc_shared_regs.mpsc_routing_base) {
+ if (mpsc_shared_regs.mpsc_routing_base) {
iounmap(mpsc_shared_regs.mpsc_routing_base);
release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
MPSC_ROUTING_REG_BLOCK_SIZE);
}
- if (!mpsc_shared_regs.sdma_intr_base) {
+ if (mpsc_shared_regs.sdma_intr_base) {
iounmap(mpsc_shared_regs.sdma_intr_base);
release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
MPSC_SDMA_INTR_REG_BLOCK_SIZE);
@@ -1891,44 +1886,39 @@ static void mpsc_shared_unmap_regs(void)
static int mpsc_shared_drv_probe(struct platform_device *dev)
{
struct mpsc_shared_pdata *pdata;
- int rc = -ENODEV;
-
- if (dev->id == 0) {
- rc = mpsc_shared_map_regs(dev);
- if (!rc) {
- pdata = (struct mpsc_shared_pdata *)
- dev_get_platdata(&dev->dev);
-
- mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
- mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
- mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m =
- pdata->intr_cause_val;
- mpsc_shared_regs.SDMA_INTR_MASK_m =
- pdata->intr_mask_val;
-
- rc = 0;
- }
- }
+ int rc;
- return rc;
+ if (dev->id != 0)
+ return -ENODEV;
+
+ rc = mpsc_shared_map_regs(dev);
+ if (rc)
+ return rc;
+
+ pdata = dev_get_platdata(&dev->dev);
+
+ mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
+ mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
+ mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
+ mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val;
+ mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val;
+
+ return 0;
}
static int mpsc_shared_drv_remove(struct platform_device *dev)
{
- int rc = -ENODEV;
+ if (dev->id != 0)
+ return -ENODEV;
- if (dev->id == 0) {
- mpsc_shared_unmap_regs();
- mpsc_shared_regs.MPSC_MRR_m = 0;
- mpsc_shared_regs.MPSC_RCRR_m = 0;
- mpsc_shared_regs.MPSC_TCRR_m = 0;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
- mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
- rc = 0;
- }
+ mpsc_shared_unmap_regs();
+ mpsc_shared_regs.MPSC_MRR_m = 0;
+ mpsc_shared_regs.MPSC_RCRR_m = 0;
+ mpsc_shared_regs.MPSC_TCRR_m = 0;
+ mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
+ mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
- return rc;
+ return 0;
}
static struct platform_driver mpsc_shared_driver = {
@@ -1979,10 +1969,6 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
pi->sdma_base_p = r->start;
} else {
mpsc_resource_err("SDMA base");
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
goto err;
}
@@ -1993,33 +1979,33 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
pi->brg_base_p = r->start;
} else {
mpsc_resource_err("BRG base");
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
- if (pi->sdma_base) {
- iounmap(pi->sdma_base);
- pi->sdma_base = NULL;
- }
goto err;
}
return 0;
err:
+ if (pi->sdma_base) {
+ iounmap(pi->sdma_base);
+ pi->sdma_base = NULL;
+ }
+ if (pi->mpsc_base) {
+ iounmap(pi->mpsc_base);
+ pi->mpsc_base = NULL;
+ }
return -ENOMEM;
}
static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
{
- if (!pi->mpsc_base) {
+ if (pi->mpsc_base) {
iounmap(pi->mpsc_base);
release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
}
- if (!pi->sdma_base) {
+ if (pi->sdma_base) {
iounmap(pi->sdma_base);
release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
}
- if (!pi->brg_base) {
+ if (pi->brg_base) {
iounmap(pi->brg_base);
release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
}
@@ -2073,36 +2059,37 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
static int mpsc_drv_probe(struct platform_device *dev)
{
- struct mpsc_port_info *pi;
- int rc = -ENODEV;
-
- pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
- if (dev->id < MPSC_NUM_CTLRS) {
- pi = &mpsc_ports[dev->id];
-
- rc = mpsc_drv_map_regs(pi, dev);
- if (!rc) {
- mpsc_drv_get_platform_data(pi, dev, dev->id);
- pi->port.dev = &dev->dev;
-
- rc = mpsc_make_ready(pi);
- if (!rc) {
- spin_lock_init(&pi->tx_lock);
- rc = uart_add_one_port(&mpsc_reg, &pi->port);
- if (!rc) {
- rc = 0;
- } else {
- mpsc_release_port((struct uart_port *)
- pi);
- mpsc_drv_unmap_regs(pi);
- }
- } else {
- mpsc_drv_unmap_regs(pi);
- }
- }
- }
+ struct mpsc_port_info *pi;
+ int rc;
+
+ dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id);
+
+ if (dev->id >= MPSC_NUM_CTLRS)
+ return -ENODEV;
+
+ pi = &mpsc_ports[dev->id];
+
+ rc = mpsc_drv_map_regs(pi, dev);
+ if (rc)
+ return rc;
+ mpsc_drv_get_platform_data(pi, dev, dev->id);
+ pi->port.dev = &dev->dev;
+
+ rc = mpsc_make_ready(pi);
+ if (rc)
+ goto err_unmap;
+
+ spin_lock_init(&pi->tx_lock);
+ rc = uart_add_one_port(&mpsc_reg, &pi->port);
+ if (rc)
+ goto err_relport;
+
+ return 0;
+err_relport:
+ mpsc_release_port(&pi->port);
+err_unmap:
+ mpsc_drv_unmap_regs(pi);
return rc;
}
@@ -2124,19 +2111,22 @@ static int __init mpsc_drv_init(void)
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
rc = uart_register_driver(&mpsc_reg);
- if (!rc) {
- rc = platform_driver_register(&mpsc_shared_driver);
- if (!rc) {
- rc = platform_driver_register(&mpsc_driver);
- if (rc) {
- platform_driver_unregister(&mpsc_shared_driver);
- uart_unregister_driver(&mpsc_reg);
- }
- } else {
- uart_unregister_driver(&mpsc_reg);
- }
- }
+ if (rc)
+ return rc;
+
+ rc = platform_driver_register(&mpsc_shared_driver);
+ if (rc)
+ goto err_unreg_uart;
+ rc = platform_driver_register(&mpsc_driver);
+ if (rc)
+ goto err_unreg_plat;
+
+ return 0;
+err_unreg_plat:
+ platform_driver_unregister(&mpsc_shared_driver);
+err_unreg_uart:
+ uart_unregister_driver(&mpsc_reg);
return rc;
}
device_initcall(mpsc_drv_init);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index dcde955475dc..96d3ce8dc2dc 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1478,7 +1478,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt)
device->con->write = msm_serial_early_write;
return 0;
}
-EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup);
OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart",
msm_serial_early_console_setup);
@@ -1500,7 +1499,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
device->con->write = msm_serial_early_write_dm;
return 0;
}
-EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm);
OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm",
msm_serial_early_console_setup_dm);
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
new file mode 100644
index 000000000000..0ff27818bb87
--- /dev/null
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -0,0 +1,650 @@
+/*
+* ***************************************************************************
+* Copyright (C) 2015 Marvell International Ltd.
+* ***************************************************************************
+* 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 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.
+*
+* 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/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* Register Map */
+#define UART_RBR 0x00
+#define RBR_BRK_DET BIT(15)
+#define RBR_FRM_ERR_DET BIT(14)
+#define RBR_PAR_ERR_DET BIT(13)
+#define RBR_OVR_ERR_DET BIT(12)
+
+#define UART_TSH 0x04
+
+#define UART_CTRL 0x08
+#define CTRL_SOFT_RST BIT(31)
+#define CTRL_TXFIFO_RST BIT(15)
+#define CTRL_RXFIFO_RST BIT(14)
+#define CTRL_ST_MIRR_EN BIT(13)
+#define CTRL_LPBK_EN BIT(12)
+#define CTRL_SND_BRK_SEQ BIT(11)
+#define CTRL_PAR_EN BIT(10)
+#define CTRL_TWO_STOP BIT(9)
+#define CTRL_TX_HFL_INT BIT(8)
+#define CTRL_RX_HFL_INT BIT(7)
+#define CTRL_TX_EMP_INT BIT(6)
+#define CTRL_TX_RDY_INT BIT(5)
+#define CTRL_RX_RDY_INT BIT(4)
+#define CTRL_BRK_DET_INT BIT(3)
+#define CTRL_FRM_ERR_INT BIT(2)
+#define CTRL_PAR_ERR_INT BIT(1)
+#define CTRL_OVR_ERR_INT BIT(0)
+#define CTRL_RX_INT (CTRL_RX_RDY_INT | CTRL_BRK_DET_INT |\
+ CTRL_FRM_ERR_INT | CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT)
+
+#define UART_STAT 0x0c
+#define STAT_TX_FIFO_EMP BIT(13)
+#define STAT_RX_FIFO_EMP BIT(12)
+#define STAT_TX_FIFO_FUL BIT(11)
+#define STAT_TX_FIFO_HFL BIT(10)
+#define STAT_RX_TOGL BIT(9)
+#define STAT_RX_FIFO_FUL BIT(8)
+#define STAT_RX_FIFO_HFL BIT(7)
+#define STAT_TX_EMP BIT(6)
+#define STAT_TX_RDY BIT(5)
+#define STAT_RX_RDY BIT(4)
+#define STAT_BRK_DET BIT(3)
+#define STAT_FRM_ERR BIT(2)
+#define STAT_PAR_ERR BIT(1)
+#define STAT_OVR_ERR BIT(0)
+#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\
+ | STAT_PAR_ERR | STAT_OVR_ERR)
+
+#define UART_BRDV 0x10
+
+#define MVEBU_NR_UARTS 1
+
+#define MVEBU_UART_TYPE "mvebu-uart"
+
+static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
+
+struct mvebu_uart_data {
+ struct uart_port *port;
+ struct clk *clk;
+};
+
+/* Core UART Driver Operations */
+static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int st;
+
+ spin_lock_irqsave(&port->lock, flags);
+ st = readl(port->membase + UART_STAT);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int mvebu_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void mvebu_uart_set_mctrl(struct uart_port *port,
+ unsigned int mctrl)
+{
+/*
+ * Even if we do not support configuring the modem control lines, this
+ * function must be proided to the serial core
+ */
+}
+
+static void mvebu_uart_stop_tx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl &= ~CTRL_TX_RDY_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_start_tx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl |= CTRL_TX_RDY_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_stop_rx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl &= ~CTRL_RX_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_break_ctl(struct uart_port *port, int brk)
+{
+ unsigned int ctl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ctl = readl(port->membase + UART_CTRL);
+ if (brk == -1)
+ ctl |= CTRL_SND_BRK_SEQ;
+ else
+ ctl &= ~CTRL_SND_BRK_SEQ;
+ writel(ctl, port->membase + UART_CTRL);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch = 0;
+ char flag = 0;
+
+ do {
+ if (status & STAT_RX_RDY) {
+ ch = readl(port->membase + UART_RBR);
+ ch &= 0xff;
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & STAT_PAR_ERR)
+ port->icount.parity++;
+ }
+
+ if (status & STAT_BRK_DET) {
+ port->icount.brk++;
+ status &= ~(STAT_FRM_ERR | STAT_PAR_ERR);
+ if (uart_handle_break(port))
+ goto ignore_char;
+ }
+
+ if (status & STAT_OVR_ERR)
+ port->icount.overrun++;
+
+ if (status & STAT_FRM_ERR)
+ port->icount.frame++;
+
+ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ if (status & port->ignore_status_mask & STAT_PAR_ERR)
+ status &= ~STAT_RX_RDY;
+
+ status &= port->read_status_mask;
+
+ if (status & STAT_PAR_ERR)
+ flag = TTY_PARITY;
+
+ status &= ~port->ignore_status_mask;
+
+ if (status & STAT_RX_RDY)
+ tty_insert_flip_char(tport, ch, flag);
+
+ if (status & STAT_BRK_DET)
+ tty_insert_flip_char(tport, 0, TTY_BREAK);
+
+ if (status & STAT_FRM_ERR)
+ tty_insert_flip_char(tport, 0, TTY_FRAME);
+
+ if (status & STAT_OVR_ERR)
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+
+ignore_char:
+ status = readl(port->membase + UART_STAT);
+ } while (status & (STAT_RX_RDY | STAT_BRK_DET));
+
+ tty_flip_buffer_push(tport);
+}
+
+static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int count;
+ unsigned int st;
+
+ if (port->x_char) {
+ writel(port->x_char, port->membase + UART_TSH);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ mvebu_uart_stop_tx(port);
+ return;
+ }
+
+ for (count = 0; count < port->fifosize; count++) {
+ writel(xmit->buf[xmit->tail], port->membase + UART_TSH);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ st = readl(port->membase + UART_STAT);
+ if (st & STAT_TX_FIFO_FUL)
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ mvebu_uart_stop_tx(port);
+}
+
+static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned int st = readl(port->membase + UART_STAT);
+
+ if (st & (STAT_RX_RDY | STAT_OVR_ERR | STAT_FRM_ERR | STAT_BRK_DET))
+ mvebu_uart_rx_chars(port, st);
+
+ if (st & STAT_TX_RDY)
+ mvebu_uart_tx_chars(port, st);
+
+ return IRQ_HANDLED;
+}
+
+static int mvebu_uart_startup(struct uart_port *port)
+{
+ int ret;
+
+ writel(CTRL_TXFIFO_RST | CTRL_RXFIFO_RST,
+ port->membase + UART_CTRL);
+ udelay(1);
+ writel(CTRL_RX_INT, port->membase + UART_CTRL);
+
+ ret = request_irq(port->irq, mvebu_uart_isr, port->irqflags, "serial",
+ port);
+ if (ret) {
+ dev_err(port->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mvebu_uart_shutdown(struct uart_port *port)
+{
+ writel(0, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->read_status_mask = STAT_RX_RDY | STAT_OVR_ERR |
+ STAT_TX_RDY | STAT_TX_FIFO_FUL;
+
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= STAT_FRM_ERR | STAT_PAR_ERR;
+
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ STAT_FRM_ERR | STAT_PAR_ERR | STAT_OVR_ERR;
+
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= STAT_RX_RDY | STAT_BRK_ERR;
+
+ if (old)
+ tty_termios_copy_hw(termios, old);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *mvebu_uart_type(struct uart_port *port)
+{
+ return MVEBU_UART_TYPE;
+}
+
+static void mvebu_uart_release_port(struct uart_port *port)
+{
+ /* Nothing to do here */
+}
+
+static int mvebu_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int mvebu_uart_get_poll_char(struct uart_port *port)
+{
+ unsigned int st = readl(port->membase + UART_STAT);
+
+ if (!(st & STAT_RX_RDY))
+ return NO_POLL_CHAR;
+
+ return readl(port->membase + UART_RBR);
+}
+
+static void mvebu_uart_put_poll_char(struct uart_port *port, unsigned char c)
+{
+ unsigned int st;
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+
+ if (!(st & STAT_TX_FIFO_FUL))
+ break;
+
+ udelay(1);
+ }
+
+ writel(c, port->membase + UART_TSH);
+}
+#endif
+
+static const struct uart_ops mvebu_uart_ops = {
+ .tx_empty = mvebu_uart_tx_empty,
+ .set_mctrl = mvebu_uart_set_mctrl,
+ .get_mctrl = mvebu_uart_get_mctrl,
+ .stop_tx = mvebu_uart_stop_tx,
+ .start_tx = mvebu_uart_start_tx,
+ .stop_rx = mvebu_uart_stop_rx,
+ .break_ctl = mvebu_uart_break_ctl,
+ .startup = mvebu_uart_startup,
+ .shutdown = mvebu_uart_shutdown,
+ .set_termios = mvebu_uart_set_termios,
+ .type = mvebu_uart_type,
+ .release_port = mvebu_uart_release_port,
+ .request_port = mvebu_uart_request_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = mvebu_uart_get_poll_char,
+ .poll_put_char = mvebu_uart_put_poll_char,
+#endif
+};
+
+/* Console Driver Operations */
+
+#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
+/* Early Console */
+static void mvebu_uart_putc(struct uart_port *port, int c)
+{
+ unsigned int st;
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+ if (!(st & STAT_TX_FIFO_FUL))
+ break;
+ }
+
+ writel(c, port->membase + UART_TSH);
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+ if (st & STAT_TX_FIFO_EMP)
+ break;
+ }
+}
+
+static void mvebu_uart_putc_early_write(struct console *con,
+ const char *s,
+ unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, mvebu_uart_putc);
+}
+
+static int __init
+mvebu_uart_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = mvebu_uart_putc_early_write;
+
+ return 0;
+}
+
+EARLYCON_DECLARE(ar3700_uart, mvebu_uart_early_console_setup);
+OF_EARLYCON_DECLARE(ar3700_uart, "marvell,armada-3700-uart",
+ mvebu_uart_early_console_setup);
+
+static void wait_for_xmitr(struct uart_port *port)
+{
+ u32 val;
+
+ readl_poll_timeout_atomic(port->membase + UART_STAT, val,
+ (val & STAT_TX_EMP), 1, 10000);
+}
+
+static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
+{
+ wait_for_xmitr(port);
+ writel(ch, port->membase + UART_TSH);
+}
+
+static void mvebu_uart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &mvebu_uart_ports[co->index];
+ unsigned long flags;
+ unsigned int ier;
+ int locked = 1;
+
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ ier = readl(port->membase + UART_CTRL) &
+ (CTRL_RX_INT | CTRL_TX_RDY_INT);
+ writel(0, port->membase + UART_CTRL);
+
+ uart_console_write(port, s, count, mvebu_uart_console_putchar);
+
+ wait_for_xmitr(port);
+
+ if (ier)
+ writel(ier, port->membase + UART_CTRL);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int mvebu_uart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= MVEBU_NR_UARTS)
+ return -EINVAL;
+
+ port = &mvebu_uart_ports[co->index];
+
+ if (!port->mapbase || !port->membase) {
+ pr_debug("console on ttyMV%i not present\n", co->index);
+ return -ENODEV;
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mvebu_uart_driver;
+
+static struct console mvebu_uart_console = {
+ .name = "ttyMV",
+ .write = mvebu_uart_console_write,
+ .device = uart_console_device,
+ .setup = mvebu_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mvebu_uart_driver,
+};
+
+static int __init mvebu_uart_console_init(void)
+{
+ register_console(&mvebu_uart_console);
+ return 0;
+}
+
+console_initcall(mvebu_uart_console_init);
+
+
+#endif /* CONFIG_SERIAL_MVEBU_CONSOLE */
+
+static struct uart_driver mvebu_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "mvebu_serial",
+ .dev_name = "ttyMV",
+ .nr = MVEBU_NR_UARTS,
+#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
+ .cons = &mvebu_uart_console,
+#endif
+};
+
+static int mvebu_uart_probe(struct platform_device *pdev)
+{
+ struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct uart_port *port;
+ struct mvebu_uart_data *data;
+ int ret;
+
+ if (!reg || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ port = &mvebu_uart_ports[0];
+
+ spin_lock_init(&port->lock);
+
+ port->dev = &pdev->dev;
+ port->type = PORT_MVEBU;
+ port->ops = &mvebu_uart_ops;
+ port->regshift = 0;
+
+ port->fifosize = 32;
+ port->iotype = UPIO_MEM32;
+ port->flags = UPF_FIXED_PORT;
+ port->line = 0; /* single port: force line number to 0 */
+
+ port->irq = irq->start;
+ port->irqflags = 0;
+ port->mapbase = reg->start;
+
+ port->membase = devm_ioremap_resource(&pdev->dev, reg);
+ if (IS_ERR(port->membase))
+ return -PTR_ERR(port->membase);
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->port = port;
+
+ port->private_data = data;
+ platform_set_drvdata(pdev, data);
+
+ ret = uart_add_one_port(&mvebu_uart_driver, port);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static int mvebu_uart_remove(struct platform_device *pdev)
+{
+ struct mvebu_uart_data *data = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&mvebu_uart_driver, data->port);
+ data->port->private_data = NULL;
+ data->port->mapbase = 0;
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id mvebu_uart_of_match[] = {
+ { .compatible = "marvell,armada-3700-uart", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mvebu_uart_of_match);
+
+static struct platform_driver mvebu_uart_platform_driver = {
+ .probe = mvebu_uart_probe,
+ .remove = mvebu_uart_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mvebu-uart",
+ .of_match_table = of_match_ptr(mvebu_uart_of_match),
+ },
+};
+
+static int __init mvebu_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&mvebu_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&mvebu_uart_platform_driver);
+ if (ret)
+ uart_unregister_driver(&mvebu_uart_driver);
+
+ return ret;
+}
+
+static void __exit mvebu_uart_exit(void)
+{
+ platform_driver_unregister(&mvebu_uart_platform_driver);
+ uart_unregister_driver(&mvebu_uart_driver);
+}
+
+arch_initcall(mvebu_uart_init);
+module_exit(mvebu_uart_exit);
+
+MODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>");
+MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
deleted file mode 100644
index 5da7622e88c3..000000000000
--- a/drivers/tty/serial/nwpserial.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Serial Port driver for a NWP uart device
- *
- * Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-#include <linux/init.h>
-#include <linux/export.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/irqreturn.h>
-#include <linux/mutex.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/nwpserial.h>
-#include <linux/delay.h>
-#include <asm/prom.h>
-#include <asm/dcr.h>
-
-#define NWPSERIAL_NR 2
-
-#define NWPSERIAL_STATUS_RXVALID 0x1
-#define NWPSERIAL_STATUS_TXFULL 0x2
-
-struct nwpserial_port {
- struct uart_port port;
- dcr_host_t dcr_host;
- unsigned int ier;
- unsigned int mcr;
-};
-
-static DEFINE_MUTEX(nwpserial_mutex);
-static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
-
-static void wait_for_bits(struct nwpserial_port *up, int bits)
-{
- unsigned int status, tmout = 10000;
-
- /* Wait up to 10ms for the character(s) to be sent. */
- do {
- status = dcr_read(up->dcr_host, UART_LSR);
-
- if (--tmout == 0)
- break;
- udelay(1);
- } while ((status & bits) != bits);
-}
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static void nwpserial_console_putchar(struct uart_port *port, int c)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
- /* check if tx buffer is full */
- wait_for_bits(up, UART_LSR_THRE);
- dcr_write(up->dcr_host, UART_TX, c);
- up->port.icount.tx++;
-}
-
-static void
-nwpserial_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct nwpserial_port *up = &nwpserial_ports[co->index];
- unsigned long flags;
- int locked = 1;
-
- if (oops_in_progress)
- locked = spin_trylock_irqsave(&up->port.lock, flags);
- else
- spin_lock_irqsave(&up->port.lock, flags);
-
- /* save and disable interrupt */
- up->ier = dcr_read(up->dcr_host, UART_IER);
- dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
-
- uart_console_write(&up->port, s, count, nwpserial_console_putchar);
-
- /* wait for transmitter to become empty */
- while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
- cpu_relax();
-
- /* restore interrupt state */
- dcr_write(up->dcr_host, UART_IER, up->ier);
-
- if (locked)
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver nwpserial_reg;
-static struct console nwpserial_console = {
- .name = "ttySQ",
- .write = nwpserial_console_write,
- .device = uart_console_device,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &nwpserial_reg,
-};
-#define NWPSERIAL_CONSOLE (&nwpserial_console)
-#else
-#define NWPSERIAL_CONSOLE NULL
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
-
-/**************************************************************************/
-
-static int nwpserial_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-static void nwpserial_release_port(struct uart_port *port)
-{
- /* N/A */
-}
-
-static void nwpserial_config_port(struct uart_port *port, int flags)
-{
- port->type = PORT_NWPSERIAL;
-}
-
-static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
-{
- struct nwpserial_port *up = dev_id;
- struct tty_port *port = &up->port.state->port;
- irqreturn_t ret;
- unsigned int iir;
- unsigned char ch;
-
- spin_lock(&up->port.lock);
-
- /* check if the uart was the interrupt source. */
- iir = dcr_read(up->dcr_host, UART_IIR);
- if (!iir) {
- ret = IRQ_NONE;
- goto out;
- }
-
- do {
- up->port.icount.rx++;
- ch = dcr_read(up->dcr_host, UART_RX);
- if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
- tty_insert_flip_char(port, ch, TTY_NORMAL);
- } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
-
- spin_unlock(&up->port.lock);
- tty_flip_buffer_push(port);
- spin_lock(&up->port.lock);
-
- ret = IRQ_HANDLED;
-
- /* clear interrupt */
- dcr_write(up->dcr_host, UART_IIR, 1);
-out:
- spin_unlock(&up->port.lock);
- return ret;
-}
-
-static int nwpserial_startup(struct uart_port *port)
-{
- struct nwpserial_port *up;
- int err;
-
- up = container_of(port, struct nwpserial_port, port);
-
- /* disable flow control by default */
- up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
- dcr_write(up->dcr_host, UART_MCR, up->mcr);
-
- /* register interrupt handler */
- err = request_irq(up->port.irq, nwpserial_interrupt,
- IRQF_SHARED, "nwpserial", up);
- if (err)
- return err;
-
- /* enable interrupts */
- up->ier = UART_IER_RDI;
- dcr_write(up->dcr_host, UART_IER, up->ier);
-
- /* enable receiving */
- up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
-
- return 0;
-}
-
-static void nwpserial_shutdown(struct uart_port *port)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
-
- /* disable receiving */
- up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
- /* disable interrupts from this port */
- up->ier = 0;
- dcr_write(up->dcr_host, UART_IER, up->ier);
-
- /* free irq */
- free_irq(up->port.irq, up);
-}
-
-static int nwpserial_verify_port(struct uart_port *port,
- struct serial_struct *ser)
-{
- return -EINVAL;
-}
-
-static const char *nwpserial_type(struct uart_port *port)
-{
- return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
-}
-
-static void nwpserial_set_termios(struct uart_port *port,
- struct ktermios *termios, struct ktermios *old)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
-
- up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
- | NWPSERIAL_STATUS_TXFULL;
-
- up->port.ignore_status_mask = 0;
- /* ignore all characters if CREAD is not set */
- if ((termios->c_cflag & CREAD) == 0)
- up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
- /* Copy back the old hardware settings */
- if (old)
- tty_termios_copy_hw(termios, old);
-}
-
-static void nwpserial_break_ctl(struct uart_port *port, int ctl)
-{
- /* N/A */
-}
-
-static void nwpserial_stop_rx(struct uart_port *port)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
- /* don't forward any more data (like !CREAD) */
- up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
-}
-
-static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
-{
- /* check if tx buffer is full */
- wait_for_bits(up, UART_LSR_THRE);
- dcr_write(up->dcr_host, UART_TX, c);
- up->port.icount.tx++;
-}
-
-static void nwpserial_start_tx(struct uart_port *port)
-{
- struct nwpserial_port *up;
- struct circ_buf *xmit;
- up = container_of(port, struct nwpserial_port, port);
- xmit = &up->port.state->xmit;
-
- if (port->x_char) {
- nwpserial_putchar(up, up->port.x_char);
- port->x_char = 0;
- }
-
- while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
- nwpserial_putchar(up, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
- }
-}
-
-static unsigned int nwpserial_get_mctrl(struct uart_port *port)
-{
- return 0;
-}
-
-static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- /* N/A */
-}
-
-static void nwpserial_stop_tx(struct uart_port *port)
-{
- /* N/A */
-}
-
-static unsigned int nwpserial_tx_empty(struct uart_port *port)
-{
- struct nwpserial_port *up;
- unsigned long flags;
- int ret;
- up = container_of(port, struct nwpserial_port, port);
-
- spin_lock_irqsave(&up->port.lock, flags);
- ret = dcr_read(up->dcr_host, UART_LSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-}
-
-static struct uart_ops nwpserial_pops = {
- .tx_empty = nwpserial_tx_empty,
- .set_mctrl = nwpserial_set_mctrl,
- .get_mctrl = nwpserial_get_mctrl,
- .stop_tx = nwpserial_stop_tx,
- .start_tx = nwpserial_start_tx,
- .stop_rx = nwpserial_stop_rx,
- .break_ctl = nwpserial_break_ctl,
- .startup = nwpserial_startup,
- .shutdown = nwpserial_shutdown,
- .set_termios = nwpserial_set_termios,
- .type = nwpserial_type,
- .release_port = nwpserial_release_port,
- .request_port = nwpserial_request_port,
- .config_port = nwpserial_config_port,
- .verify_port = nwpserial_verify_port,
-};
-
-static struct uart_driver nwpserial_reg = {
- .owner = THIS_MODULE,
- .driver_name = "nwpserial",
- .dev_name = "ttySQ",
- .major = TTY_MAJOR,
- .minor = 68,
- .nr = NWPSERIAL_NR,
- .cons = NWPSERIAL_CONSOLE,
-};
-
-int nwpserial_register_port(struct uart_port *port)
-{
- struct nwpserial_port *up = NULL;
- int ret = -1;
- int i;
- static int first = 1;
- int dcr_len;
- int dcr_base;
- struct device_node *dn;
-
- mutex_lock(&nwpserial_mutex);
-
- dn = port->dev->of_node;
- if (dn == NULL)
- goto out;
-
- /* get dcr base. */
- dcr_base = dcr_resource_start(dn, 0);
-
- /* find matching entry */
- for (i = 0; i < NWPSERIAL_NR; i++)
- if (nwpserial_ports[i].port.iobase == dcr_base) {
- up = &nwpserial_ports[i];
- break;
- }
-
- /* we didn't find a mtching entry, search for a free port */
- if (up == NULL)
- for (i = 0; i < NWPSERIAL_NR; i++)
- if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
- nwpserial_ports[i].port.iobase == 0) {
- up = &nwpserial_ports[i];
- break;
- }
-
- if (up == NULL) {
- ret = -EBUSY;
- goto out;
- }
-
- if (first)
- uart_register_driver(&nwpserial_reg);
- first = 0;
-
- up->port.membase = port->membase;
- up->port.irq = port->irq;
- up->port.uartclk = port->uartclk;
- up->port.fifosize = port->fifosize;
- up->port.regshift = port->regshift;
- up->port.iotype = port->iotype;
- up->port.flags = port->flags;
- up->port.mapbase = port->mapbase;
- up->port.private_data = port->private_data;
-
- if (port->dev)
- up->port.dev = port->dev;
-
- if (up->port.iobase != dcr_base) {
- up->port.ops = &nwpserial_pops;
- up->port.fifosize = 16;
-
- spin_lock_init(&up->port.lock);
-
- up->port.iobase = dcr_base;
- dcr_len = dcr_resource_len(dn, 0);
-
- up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
- if (!DCR_MAP_OK(up->dcr_host)) {
- printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
- goto out;
- }
- }
-
- ret = uart_add_one_port(&nwpserial_reg, &up->port);
- if (ret == 0)
- ret = up->port.line;
-
-out:
- mutex_unlock(&nwpserial_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL(nwpserial_register_port);
-
-void nwpserial_unregister_port(int line)
-{
- struct nwpserial_port *up = &nwpserial_ports[line];
- mutex_lock(&nwpserial_mutex);
- uart_remove_one_port(&nwpserial_reg, &up->port);
-
- up->port.type = PORT_UNKNOWN;
-
- mutex_unlock(&nwpserial_mutex);
-}
-EXPORT_SYMBOL(nwpserial_unregister_port);
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static int __init nwpserial_console_init(void)
-{
- struct nwpserial_port *up = NULL;
- struct device_node *dn;
- const char *name;
- int dcr_base;
- int dcr_len;
- int i;
-
- /* search for a free port */
- for (i = 0; i < NWPSERIAL_NR; i++)
- if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
- up = &nwpserial_ports[i];
- break;
- }
-
- if (up == NULL)
- return -1;
-
- name = of_get_property(of_chosen, "linux,stdout-path", NULL);
- if (name == NULL)
- return -1;
-
- dn = of_find_node_by_path(name);
- if (!dn)
- return -1;
-
- spin_lock_init(&up->port.lock);
- up->port.ops = &nwpserial_pops;
- up->port.type = PORT_NWPSERIAL;
- up->port.fifosize = 16;
-
- dcr_base = dcr_resource_start(dn, 0);
- dcr_len = dcr_resource_len(dn, 0);
- up->port.iobase = dcr_base;
-
- up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
- if (!DCR_MAP_OK(up->dcr_host)) {
- printk("Cannot map DCR resources for SERIAL");
- return -1;
- }
- register_console(&nwpserial_console);
- return 0;
-}
-console_initcall(nwpserial_console_init);
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 9d4c84f7485f..a2a529994ba5 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1165,7 +1165,7 @@ serial_omap_type(struct uart_port *port)
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-static inline void wait_for_xmitr(struct uart_omap_port *up)
+static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
{
unsigned int status, tmout = 10000;
@@ -1343,7 +1343,7 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
/* Enable or disable the rs485 support */
static int
-serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int mode;
@@ -1356,8 +1356,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
up->ier = 0;
serial_out(up, UART_IER, 0);
+ /* Clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
/* store new config */
- port->rs485 = *rs485conf;
+ port->rs485 = *rs485;
/*
* Just as a precaution, only allow rs485
@@ -1866,7 +1870,7 @@ static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
- .name = DRIVER_NAME,
+ .name = OMAP_SERIAL_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 9becba654892..41eab75ba2af 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -603,7 +603,7 @@ static struct uart_driver serial_pxa_reg;
/*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct uart_pxa_port *up)
+static void wait_for_xmitr(struct uart_pxa_port *up)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index d72cd736bdc6..ac7f8df54406 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -601,14 +601,21 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
unsigned int ufcon, ch, flag, ufstat, uerstat;
+ unsigned int fifocnt = 0;
int max_count = port->fifosize;
while (max_count-- > 0) {
- ufcon = rd_regl(port, S3C2410_UFCON);
- ufstat = rd_regl(port, S3C2410_UFSTAT);
-
- if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
- break;
+ /*
+ * Receive all characters known to be in FIFO
+ * before reading FIFO level again
+ */
+ if (fifocnt == 0) {
+ ufstat = rd_regl(port, S3C2410_UFSTAT);
+ fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+ if (fifocnt == 0)
+ break;
+ }
+ fifocnt--;
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
@@ -623,6 +630,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
}
} else {
if (txe) {
+ ufcon = rd_regl(port, S3C2410_UFCON);
ufcon |= S3C2410_UFCON_RESETRX;
wr_regl(port, S3C2410_UFCON, ufcon);
rx_enabled(port) = 1;
@@ -2451,7 +2459,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
}
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
s3c2410_early_console_setup);
-EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
/* S3C2412, S3C2440, S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data = {
@@ -2470,9 +2477,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
/* S5PV210, EXYNOS */
static struct samsung_early_console_data s5pv210_early_console_data = {
@@ -2489,8 +2493,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
-EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
-EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
#endif
MODULE_ALIAS("platform:samsung-uart");
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index edb5305b9d4d..025a4264430e 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -196,14 +196,14 @@
* or (IO6)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */
-#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4)
+#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */
+#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7)
+#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6)
+#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6)
* - only on 75x/76x
*/
#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
@@ -240,7 +240,7 @@
/* IOControl register bits (Only 750/760) */
#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
-#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */
+#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */
#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
/* EFCR register bits */
@@ -389,6 +389,13 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
const u8 line = sc16is7xx_line(port);
u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line;
+ /*
+ * Don't send zero-length data, at least on SPI it confuses the chip
+ * delivering wrong TXLVL data.
+ */
+ if (unlikely(!to_send))
+ return;
+
regcache_cache_bypass(s->regmap, true);
regmap_raw_write(s->regmap, addr, s->buf, to_send);
regcache_cache_bypass(s->regmap, false);
@@ -630,6 +637,12 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
if (likely(to_send)) {
/* Limit to size of TX FIFO */
txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
+ if (txlen > SC16IS7XX_FIFO_SIZE) {
+ dev_err_ratelimited(port->dev,
+ "chip reports %d free bytes in TX fifo, but it only has %d",
+ txlen, SC16IS7XX_FIFO_SIZE);
+ txlen = 0;
+ }
to_send = (to_send > txlen) ? txlen : to_send;
/* Add data to send */
@@ -674,7 +687,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
case SC16IS7XX_IIR_CTSRTS_SRC:
msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
uart_handle_cts_change(port,
- !!(msr & SC16IS7XX_MSR_CTS_BIT));
+ !!(msr & SC16IS7XX_MSR_DCTS_BIT));
break;
case SC16IS7XX_IIR_THRI_SRC:
sc16is7xx_handle_tx(port);
@@ -748,12 +761,20 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
memset(&one->config, 0, sizeof(one->config));
spin_unlock_irqrestore(&one->port.lock, irqflags);
- if (config.flags & SC16IS7XX_RECONF_MD)
+ if (config.flags & SC16IS7XX_RECONF_MD) {
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_LOOP_BIT,
(one->port.mctrl & TIOCM_LOOP) ?
SC16IS7XX_MCR_LOOP_BIT : 0);
-
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_RTS_BIT,
+ (one->port.mctrl & TIOCM_RTS) ?
+ SC16IS7XX_MCR_RTS_BIT : 0);
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_DTR_BIT,
+ (one->port.mctrl & TIOCM_DTR) ?
+ SC16IS7XX_MCR_DTR_BIT : 0);
+ }
if (config.flags & SC16IS7XX_RECONF_IER)
sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
config.ier_clear, 0);
@@ -1180,7 +1201,7 @@ static int sc16is7xx_probe(struct device *dev,
if (devtype->nr_gpio) {
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
- s->gpio.dev = dev;
+ s->gpio.parent = dev;
s->gpio.label = dev_name(dev);
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index def5199ca004..a126a603b083 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -110,7 +110,7 @@ static void uart_start(struct tty_struct *tty)
spin_unlock_irqrestore(&port->lock, flags);
}
-static inline void
+static void
uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
{
unsigned long flags;
@@ -171,14 +171,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
*/
uart_change_speed(tty, state, NULL);
- if (init_hw) {
- /*
- * Setup the RTS and DTR signals once the
- * port is open and ready to respond.
- */
- if (tty->termios.c_cflag & CBAUD)
- uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
- }
+ /*
+ * Setup the RTS and DTR signals once the
+ * port is open and ready to respond.
+ */
+ if (init_hw && C_BAUD(tty))
+ uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
/*
@@ -240,7 +238,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
if (uart_console(uport) && tty)
uport->cons->cflag = tty->termios.c_cflag;
- if (!tty || (tty->termios.c_cflag & HUPCL))
+ if (!tty || C_HUPCL(tty))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_shutdown(port);
@@ -485,12 +483,15 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
spin_unlock_irq(&uport->lock);
}
-static inline int __uart_put_char(struct uart_port *port,
- struct circ_buf *circ, unsigned char c)
+static int uart_put_char(struct tty_struct *tty, unsigned char c)
{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ struct circ_buf *circ;
unsigned long flags;
int ret = 0;
+ circ = &state->xmit;
if (!circ->buf)
return 0;
@@ -504,13 +505,6 @@ static inline int __uart_put_char(struct uart_port *port,
return ret;
}
-static int uart_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct uart_state *state = tty->driver_data;
-
- return __uart_put_char(state->uart_port, &state->xmit, ch);
-}
-
static void uart_flush_chars(struct tty_struct *tty)
{
uart_start(tty);
@@ -639,7 +633,7 @@ static void uart_throttle(struct tty_struct *tty)
if (I_IXOFF(tty))
mask |= UPSTAT_AUTOXOFF;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
mask |= UPSTAT_AUTORTS;
if (port->status & mask) {
@@ -647,11 +641,11 @@ static void uart_throttle(struct tty_struct *tty)
mask &= ~port->status;
}
- if (mask & UPSTAT_AUTOXOFF)
- uart_send_xchar(tty, STOP_CHAR(tty));
-
if (mask & UPSTAT_AUTORTS)
uart_clear_mctrl(port, TIOCM_RTS);
+
+ if (mask & UPSTAT_AUTOXOFF)
+ uart_send_xchar(tty, STOP_CHAR(tty));
}
static void uart_unthrottle(struct tty_struct *tty)
@@ -662,7 +656,7 @@ static void uart_unthrottle(struct tty_struct *tty)
if (I_IXOFF(tty))
mask |= UPSTAT_AUTOXOFF;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
mask |= UPSTAT_AUTORTS;
if (port->status & mask) {
@@ -670,21 +664,25 @@ static void uart_unthrottle(struct tty_struct *tty)
mask &= ~port->status;
}
- if (mask & UPSTAT_AUTOXOFF)
- uart_send_xchar(tty, START_CHAR(tty));
-
if (mask & UPSTAT_AUTORTS)
uart_set_mctrl(port, TIOCM_RTS);
+
+ if (mask & UPSTAT_AUTOXOFF)
+ uart_send_xchar(tty, START_CHAR(tty));
}
-static void do_uart_get_info(struct tty_port *port,
- struct serial_struct *retinfo)
+static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
memset(retinfo, 0, sizeof(*retinfo));
+ /*
+ * Ensure the state we copy is consistent and no hardware changes
+ * occur as we go
+ */
+ mutex_lock(&port->mutex);
retinfo->type = uport->type;
retinfo->line = uport->line;
retinfo->port = uport->iobase;
@@ -703,15 +701,6 @@ static void do_uart_get_info(struct tty_port *port,
retinfo->io_type = uport->iotype;
retinfo->iomem_reg_shift = uport->regshift;
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
-}
-
-static void uart_get_info(struct tty_port *port,
- struct serial_struct *retinfo)
-{
- /* Ensure the state we copy is consistent and no hardware changes
- occur as we go */
- mutex_lock(&port->mutex);
- do_uart_get_info(port, retinfo);
mutex_unlock(&port->mutex);
}
@@ -719,6 +708,7 @@ static int uart_get_info_user(struct tty_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
+
uart_get_info(port, &tmp);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
@@ -1391,8 +1381,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
uport = state->uart_port;
port = &state->port;
-
- pr_debug("uart_close(%d) called\n", uport ? uport->line : -1);
+ pr_debug("uart_close(%d) called\n", tty->index);
if (!port->count || tty_port_close_start(port, tty, filp) == 0)
return;
@@ -1434,7 +1423,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* Wake up anyone trying to open this port.
*/
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
- clear_bit(ASYNCB_CLOSING, &port->flags);
spin_unlock_irq(&port->lock);
wake_up_interruptible(&port->open_wait);
@@ -1510,7 +1498,7 @@ static void uart_hangup(struct tty_struct *tty)
struct tty_port *port = &state->port;
unsigned long flags;
- pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+ pr_debug("uart_hangup(%d)\n", tty->index);
mutex_lock(&port->mutex);
if (port->flags & ASYNC_NORMAL_ACTIVE) {
@@ -1591,7 +1579,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
*/
static int uart_open(struct tty_struct *tty, struct file *filp)
{
- struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
+ struct uart_driver *drv = tty->driver->driver_state;
int retval, line = tty->index;
struct uart_state *state = drv->state + line;
struct tty_port *port = &state->port;
@@ -1633,15 +1621,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If we succeeded, wait until the port is ready.
*/
+err_unlock:
mutex_unlock(&port->mutex);
if (retval == 0)
retval = tty_port_block_til_ready(port, tty, filp);
-
end:
return retval;
-err_unlock:
- mutex_unlock(&port->mutex);
- goto end;
}
static const char *uart_type(struct uart_port *port)
@@ -1700,17 +1685,13 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
seq_printf(m, " tx:%d rx:%d",
uport->icount.tx, uport->icount.rx);
if (uport->icount.frame)
- seq_printf(m, " fe:%d",
- uport->icount.frame);
+ seq_printf(m, " fe:%d", uport->icount.frame);
if (uport->icount.parity)
- seq_printf(m, " pe:%d",
- uport->icount.parity);
+ seq_printf(m, " pe:%d", uport->icount.parity);
if (uport->icount.brk)
- seq_printf(m, " brk:%d",
- uport->icount.brk);
+ seq_printf(m, " brk:%d", uport->icount.brk);
if (uport->icount.overrun)
- seq_printf(m, " oe:%d",
- uport->icount.overrun);
+ seq_printf(m, " oe:%d", uport->icount.overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
@@ -1745,8 +1726,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
struct uart_driver *drv = ttydrv->driver_state;
int i;
- seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
- "", "", "");
+ seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
for (i = 0; i < drv->nr; i++)
uart_line_info(m, drv, i);
return 0;
@@ -1818,8 +1798,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* @options: ptr for <options> field; NULL if not present (out)
*
* Decodes earlycon kernel command line parameters of the form
- * earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
- * console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
+ * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
+ * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
*
* The optional form
* earlycon=<name>,0x<addr>,<options>
@@ -1834,6 +1814,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
+ } else if (strncmp(p, "mmio16,", 7) == 0) {
+ *iotype = UPIO_MEM16;
+ p += 7;
} else if (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32;
p += 7;
@@ -1892,26 +1875,6 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
}
EXPORT_SYMBOL_GPL(uart_parse_options);
-struct baud_rates {
- unsigned int rate;
- unsigned int cflag;
-};
-
-static const struct baud_rates baud_rates[] = {
- { 921600, B921600 },
- { 460800, B460800 },
- { 230400, B230400 },
- { 115200, B115200 },
- { 57600, B57600 },
- { 38400, B38400 },
- { 19200, B19200 },
- { 9600, B9600 },
- { 4800, B4800 },
- { 2400, B2400 },
- { 1200, B1200 },
- { 0, B38400 }
-};
-
/**
* uart_set_options - setup the serial console parameters
* @port: pointer to the serial ports uart_port structure
@@ -1927,7 +1890,6 @@ uart_set_options(struct uart_port *port, struct console *co,
{
struct ktermios termios;
static struct ktermios dummy;
- int i;
/*
* Ensure that the serial console lock is initialised
@@ -1942,16 +1904,8 @@ uart_set_options(struct uart_port *port, struct console *co,
memset(&termios, 0, sizeof(struct ktermios));
- termios.c_cflag = CREAD | HUPCL | CLOCAL;
-
- /*
- * Construct a cflag setting.
- */
- for (i = 0; baud_rates[i].rate; i++)
- if (baud_rates[i].rate <= baud)
- break;
-
- termios.c_cflag |= baud_rates[i].cflag;
+ termios.c_cflag |= CREAD | HUPCL | CLOCAL;
+ tty_termios_encode_baud_rate(&termios, baud, baud);
if (bits == 7)
termios.c_cflag |= CS7;
@@ -2186,6 +2140,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
"I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
+ case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
@@ -2831,6 +2786,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6);
case UPIO_MEM:
+ case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index b4decf8787de..57f152394af5 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -554,7 +554,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
.uartclk = KS8695_CLOCK_RATE * 16,
.fifosize = 16,
.ops = &ks8695uart_pops,
- .flags = ASYNC_BOOT_AUTOCONF,
+ .flags = UPF_BOOT_AUTOCONF,
.line = 0,
}
};
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 3eb57eb532f1..02147361eaa9 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -20,6 +20,7 @@
#include <linux/gpio/consumer.h>
#include <linux/termios.h>
#include <linux/serial_core.h>
+#include <linux/module.h>
#include "serial_mctrl_gpio.h"
@@ -193,6 +194,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
return gpios;
}
+EXPORT_SYMBOL_GPL(mctrl_gpio_init);
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
@@ -247,3 +249,6 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
disable_irq(gpios->irq[i]);
}
}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 51c7507b0444..0130feb069ae 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2,6 +2,7 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
* Copyright (C) 2002 - 2011 Paul Mundt
+ * Copyright (C) 2015 Glider bvba
* Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
*
* based off of the old drivers/char/sh-sci.c by:
@@ -38,7 +39,6 @@
#include <linux/major.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -76,6 +76,30 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0))
+enum SCI_CLKS {
+ SCI_FCK, /* Functional Clock */
+ SCI_SCK, /* Optional External Clock */
+ SCI_BRG_INT, /* Optional BRG Internal Clock Source */
+ SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_NUM_CLKS
+};
+
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
+ SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
+ SCI_SR(19) | SCI_SR(27)
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+/* Iterate over all supported sampling rates, from high to low */
+#define for_each_sr(_sr, _port) \
+ for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
+ if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
+
struct sci_port {
struct uart_port port;
@@ -85,17 +109,16 @@ struct sci_port {
unsigned int overrun_mask;
unsigned int error_mask;
unsigned int error_clear;
- unsigned int sampling_rate;
+ unsigned int sampling_rate_mask;
resource_size_t reg_size;
/* Break timer */
struct timer_list break_timer;
int break_flag;
- /* Interface clock */
- struct clk *iclk;
- /* Function clock */
- struct clk *fclk;
+ /* Clocks */
+ struct clk *clks[SCI_NUM_CLKS];
+ unsigned long clk_rates[SCI_NUM_CLKS];
int irqs[SCIx_NR_IRQS];
char *irqstr[SCIx_NR_IRQS];
@@ -116,8 +139,6 @@ struct sci_port {
struct timer_list rx_timer;
unsigned int rx_timeout;
#endif
-
- struct notifier_block freq_transition;
};
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@@ -163,6 +184,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -185,6 +208,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -206,6 +231,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = { 0x30, 16 },
[SCPDR] = { 0x34, 16 },
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -227,6 +254,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = { 0x30, 16 },
[SCPDR] = { 0x34, 16 },
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -249,6 +278,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -270,6 +301,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -291,6 +324,32 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
+ },
+
+ /*
+ * Common SCIF definitions for ports with a Baud Rate Generator for
+ * External Clock (BRG).
+ */
+ [SCIx_SH4_SCIF_BRG_REGTYPE] = {
+ [SCSMR] = { 0x00, 16 },
+ [SCBRR] = { 0x04, 8 },
+ [SCSCR] = { 0x08, 16 },
+ [SCxTDR] = { 0x0c, 8 },
+ [SCxSR] = { 0x10, 16 },
+ [SCxRDR] = { 0x14, 8 },
+ [SCFCR] = { 0x18, 16 },
+ [SCFDR] = { 0x1c, 16 },
+ [SCTFDR] = sci_reg_invalid,
+ [SCRFDR] = sci_reg_invalid,
+ [SCSPTR] = { 0x20, 16 },
+ [SCLSR] = { 0x24, 16 },
+ [HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
+ [SCDL] = { 0x30, 16 },
+ [SCCKS] = { 0x34, 16 },
},
/*
@@ -312,6 +371,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = { 0x40, 16 },
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = { 0x30, 16 },
+ [SCCKS] = { 0x34, 16 },
},
/*
@@ -334,6 +395,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -356,6 +419,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -378,6 +443,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
};
@@ -452,18 +519,24 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)
static void sci_port_enable(struct sci_port *sci_port)
{
+ unsigned int i;
+
if (!sci_port->port.dev)
return;
pm_runtime_get_sync(sci_port->port.dev);
- clk_prepare_enable(sci_port->iclk);
- sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
- clk_prepare_enable(sci_port->fclk);
+ for (i = 0; i < SCI_NUM_CLKS; i++) {
+ clk_prepare_enable(sci_port->clks[i]);
+ sci_port->clk_rates[i] = clk_get_rate(sci_port->clks[i]);
+ }
+ sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
}
static void sci_port_disable(struct sci_port *sci_port)
{
+ unsigned int i;
+
if (!sci_port->port.dev)
return;
@@ -475,8 +548,8 @@ static void sci_port_disable(struct sci_port *sci_port)
del_timer_sync(&sci_port->break_timer);
sci_port->break_flag = 0;
- clk_disable_unprepare(sci_port->fclk);
- clk_disable_unprepare(sci_port->iclk);
+ for (i = SCI_NUM_CLKS; i-- > 0; )
+ clk_disable_unprepare(sci_port->clks[i]);
pm_runtime_put_sync(sci_port->port.dev);
}
@@ -580,7 +653,8 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
}
}
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
#ifdef CONFIG_CONSOLE_POLL
static int sci_poll_get_char(struct uart_port *port)
@@ -621,7 +695,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
serial_port_out(port, SCxTDR, c);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
-#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
+ CONFIG_SERIAL_SH_SCI_EARLYCON */
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{
@@ -1606,29 +1681,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
return ret;
}
-/*
- * Here we define a transition notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
- unsigned long phase, void *p)
-{
- struct sci_port *sci_port;
- unsigned long flags;
-
- sci_port = container_of(self, struct sci_port, freq_transition);
-
- if (phase == CPUFREQ_POSTCHANGE) {
- struct uart_port *port = &sci_port->port;
-
- spin_lock_irqsave(&port->lock, flags);
- port->uartclk = clk_get_rate(sci_port->iclk);
- spin_unlock_irqrestore(&port->lock, flags);
- }
-
- return NOTIFY_OK;
-}
-
static const struct sci_irq_desc {
const char *desc;
irq_handler_t handler;
@@ -1864,90 +1916,130 @@ static void sci_shutdown(struct uart_port *port)
sci_free_irq(s);
}
-static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned long freq)
+static int sci_sck_calc(struct sci_port *s, unsigned int bps,
+ unsigned int *srr)
{
- if (s->sampling_rate)
- return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;
+ unsigned long freq = s->clk_rates[SCI_SCK];
+ int err, min_err = INT_MAX;
+ unsigned int sr;
+
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- /* Warn, but use a safe default */
- WARN_ON(1);
+ for_each_sr(sr, s) {
+ err = DIV_ROUND_CLOSEST(freq, sr) - bps;
+ if (abs(err) >= abs(min_err))
+ continue;
+
+ min_err = err;
+ *srr = sr - 1;
- return ((freq + 16 * bps) / (32 * bps) - 1);
+ if (!err)
+ break;
+ }
+
+ dev_dbg(s->port.dev, "SCK: %u%+d bps using SR %u\n", bps, min_err,
+ *srr + 1);
+ return min_err;
}
-/* calculate frame length from SMR */
-static int sci_baud_calc_frame_len(unsigned int smr_val)
+static int sci_brg_calc(struct sci_port *s, unsigned int bps,
+ unsigned long freq, unsigned int *dlr,
+ unsigned int *srr)
{
- int len = 10;
+ int err, min_err = INT_MAX;
+ unsigned int sr, dl;
- if (smr_val & SCSMR_CHR)
- len--;
- if (smr_val & SCSMR_PE)
- len++;
- if (smr_val & SCSMR_STOP)
- len++;
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- return len;
-}
+ for_each_sr(sr, s) {
+ dl = DIV_ROUND_CLOSEST(freq, sr * bps);
+ dl = clamp(dl, 1U, 65535U);
+
+ err = DIV_ROUND_CLOSEST(freq, sr * dl) - bps;
+ if (abs(err) >= abs(min_err))
+ continue;
+ min_err = err;
+ *dlr = dl;
+ *srr = sr - 1;
-/* calculate sample rate, BRR, and clock select for HSCIF */
-static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
- int *brr, unsigned int *srr,
- unsigned int *cks, int frame_len)
+ if (!err)
+ break;
+ }
+
+ dev_dbg(s->port.dev, "BRG: %u%+d bps using DL %u SR %u\n", bps,
+ min_err, *dlr, *srr + 1);
+ return min_err;
+}
+
+/* calculate sample rate, BRR, and clock select */
+static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
+ unsigned int *brr, unsigned int *srr,
+ unsigned int *cks)
{
- int sr, c, br, err, recv_margin;
- int min_err = 1000; /* 100% */
- int recv_max_margin = 0;
+ unsigned long freq = s->clk_rates[SCI_FCK];
+ unsigned int sr, br, prediv, scrate, c;
+ int err, min_err = INT_MAX;
- /* Find the combination of sample rate and clock select with the
- smallest deviation from the desired baud rate. */
- for (sr = 8; sr <= 32; sr++) {
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
+
+ /*
+ * Find the combination of sample rate and clock select with the
+ * smallest deviation from the desired baud rate.
+ * Prefer high sample rates to maximise the receive margin.
+ *
+ * M: Receive margin (%)
+ * N: Ratio of bit rate to clock (N = sampling rate)
+ * D: Clock duty (D = 0 to 1.0)
+ * L: Frame length (L = 9 to 12)
+ * F: Absolute value of clock frequency deviation
+ *
+ * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
+ * (|D - 0.5| / N * (1 + F))|
+ * NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
+ */
+ for_each_sr(sr, s) {
for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */
- br = DIV_ROUND_CLOSEST(freq, (sr *
- (1 << (2 * c + 1)) * bps)) - 1;
- br = clamp(br, 0, 255);
- err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr *
- (1 << (2 * c + 1)) / 1000)) -
- 1000;
- /* Calc recv margin
- * M: Receive margin (%)
- * N: Ratio of bit rate to clock (N = sampling rate)
- * D: Clock duty (D = 0 to 1.0)
- * L: Frame length (L = 9 to 12)
- * F: Absolute value of clock frequency deviation
+ prediv = sr * (1 << (2 * c + 1));
+
+ /*
+ * We need to calculate:
+ *
+ * br = freq / (prediv * bps) clamped to [1..256]
+ * err = freq / (br * prediv) - bps
*
- * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
- * (|D - 0.5| / N * (1 + F))|
- * NOTE: Usually, treat D for 0.5, F is 0 by this
- * calculation.
+ * Watch out for overflow when calculating the desired
+ * sampling clock rate!
*/
- recv_margin = abs((500 -
- DIV_ROUND_CLOSEST(1000, sr << 1)) / 10);
- if (abs(min_err) > abs(err)) {
- min_err = err;
- recv_max_margin = recv_margin;
- } else if ((min_err == err) &&
- (recv_margin > recv_max_margin))
- recv_max_margin = recv_margin;
- else
+ if (bps > UINT_MAX / prediv)
+ break;
+
+ scrate = prediv * bps;
+ br = DIV_ROUND_CLOSEST(freq, scrate);
+ br = clamp(br, 1U, 256U);
+
+ err = DIV_ROUND_CLOSEST(freq, br * prediv) - bps;
+ if (abs(err) >= abs(min_err))
continue;
- *brr = br;
+ min_err = err;
+ *brr = br - 1;
*srr = sr - 1;
*cks = c;
+
+ if (!err)
+ goto found;
}
}
- if (min_err == 1000) {
- WARN_ON(1);
- /* use defaults */
- *brr = 255;
- *srr = 15;
- *cks = 0;
- }
+found:
+ dev_dbg(s->port.dev, "BRR: %u%+d bps using N %u SR %u cks %u\n", bps,
+ min_err, *brr, *srr + 1, *cks);
+ return min_err;
}
static void sci_reset(struct uart_port *port)
@@ -1969,11 +2061,14 @@ static void sci_reset(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i;
+ unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
+ unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
struct sci_port *s = to_sci_port(port);
const struct plat_sci_reg *reg;
- unsigned int baud, smr_val = 0, max_baud, cks = 0;
- int t = -1;
- unsigned int srr = 15;
+ int min_err = INT_MAX, err;
+ unsigned long max_freq = 0;
+ int best_clk = -1;
if ((termios->c_cflag & CSIZE) == CS7)
smr_val |= SCSMR_CHR;
@@ -1992,41 +2087,134 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
* that the previous boot loader has enabled required clocks and
* setup the baud rate generator hardware for us already.
*/
- max_baud = port->uartclk ? port->uartclk / 16 : 115200;
-
- baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
- if (likely(baud && port->uartclk)) {
- if (s->cfg->type == PORT_HSCIF) {
- int frame_len = sci_baud_calc_frame_len(smr_val);
- sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,
- &cks, frame_len);
- } else {
- t = sci_scbrr_calc(s, baud, port->uartclk);
- for (cks = 0; t >= 256 && cks <= 3; cks++)
- t >>= 2;
+ if (!port->uartclk) {
+ baud = uart_get_baud_rate(port, termios, old, 0, 115200);
+ goto done;
+ }
+
+ for (i = 0; i < SCI_NUM_CLKS; i++)
+ max_freq = max(max_freq, s->clk_rates[i]);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
+ if (!baud)
+ goto done;
+
+ /*
+ * There can be multiple sources for the sampling clock. Find the one
+ * that gives us the smallest deviation from the desired baud rate.
+ */
+
+ /* Optional Undivided External Clock */
+ if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA &&
+ port->type != PORT_SCIFB) {
+ err = sci_sck_calc(s, baud, &srr1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_SCK;
+ scr_val = SCSCR_CKE1;
+ sccks = SCCKS_CKS;
+ min_err = err;
+ srr = srr1;
+ if (!err)
+ goto done;
+ }
+ }
+
+ /* Optional BRG Frequency Divided External Clock */
+ if (s->clk_rates[SCI_SCIF_CLK] && sci_getreg(port, SCDL)->size) {
+ err = sci_brg_calc(s, baud, s->clk_rates[SCI_SCIF_CLK], &dl1,
+ &srr1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_SCIF_CLK;
+ scr_val = SCSCR_CKE1;
+ sccks = 0;
+ min_err = err;
+ dl = dl1;
+ srr = srr1;
+ if (!err)
+ goto done;
+ }
+ }
+
+ /* Optional BRG Frequency Divided Internal Clock */
+ if (s->clk_rates[SCI_BRG_INT] && sci_getreg(port, SCDL)->size) {
+ err = sci_brg_calc(s, baud, s->clk_rates[SCI_BRG_INT], &dl1,
+ &srr1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_BRG_INT;
+ scr_val = SCSCR_CKE1;
+ sccks = SCCKS_XIN;
+ min_err = err;
+ dl = dl1;
+ srr = srr1;
+ if (!min_err)
+ goto done;
}
}
+ /* Divided Functional Clock using standard Bit Rate Register */
+ err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_FCK;
+ scr_val = 0;
+ min_err = err;
+ brr = brr1;
+ srr = srr1;
+ cks = cks1;
+ }
+
+done:
+ if (best_clk >= 0)
+ dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
+ s->clks[best_clk], baud, min_err);
+
sci_port_enable(s);
- sci_reset(port);
+ /*
+ * Program the optional External Baud Rate Generator (BRG) first.
+ * It controls the mux to select (H)SCK or frequency divided clock.
+ */
+ if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
+ serial_port_out(port, SCDL, dl);
+ serial_port_out(port, SCCKS, sccks);
+ }
- smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+ sci_reset(port);
uart_update_timeout(port, termios->c_cflag, baud);
- dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n",
- __func__, smr_val, cks, t, s->cfg->scscr);
-
- if (t >= 0) {
- serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks);
- serial_port_out(port, SCBRR, t);
- reg = sci_getreg(port, HSSRR);
- if (reg->size)
+ if (best_clk >= 0) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ switch (srr + 1) {
+ case 5: smr_val |= SCSMR_SRC_5; break;
+ case 7: smr_val |= SCSMR_SRC_7; break;
+ case 11: smr_val |= SCSMR_SRC_11; break;
+ case 13: smr_val |= SCSMR_SRC_13; break;
+ case 16: smr_val |= SCSMR_SRC_16; break;
+ case 17: smr_val |= SCSMR_SRC_17; break;
+ case 19: smr_val |= SCSMR_SRC_19; break;
+ case 27: smr_val |= SCSMR_SRC_27; break;
+ }
+ smr_val |= cks;
+ dev_dbg(port->dev,
+ "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
+ scr_val, smr_val, brr, sccks, dl, srr);
+ serial_port_out(port, SCSCR, scr_val);
+ serial_port_out(port, SCSMR, smr_val);
+ serial_port_out(port, SCBRR, brr);
+ if (sci_getreg(port, HSSRR)->size)
serial_port_out(port, HSSRR, srr | HSCIF_SRE);
- udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
- } else
+
+ /* Wait one bit interval */
+ udelay((1000000 + (baud - 1)) / baud);
+ } else {
+ /* Don't touch the bit rate configuration */
+ scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
+ smr_val |= serial_port_in(port, SCSMR) &
+ (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
+ dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
+ serial_port_out(port, SCSCR, scr_val);
serial_port_out(port, SCSMR, smr_val);
+ }
sci_init_pins(port, termios->c_cflag);
@@ -2051,7 +2239,19 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, SCFCR, ctrl);
}
- serial_port_out(port, SCSCR, s->cfg->scscr);
+ scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
+ dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
+ serial_port_out(port, SCSCR, scr_val);
+ if ((srr + 1 == 5) &&
+ (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
+ /*
+ * In asynchronous mode, when the sampling rate is 1/5, first
+ * received data may become invalid on some SCIFA and SCIFB.
+ * To avoid this problem wait more than 1 serial data time (1
+ * bit time x serial data number) after setting SCSCR.RE = 1.
+ */
+ udelay(DIV_ROUND_UP(10 * 1000000, baud));
+ }
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
@@ -2241,6 +2441,63 @@ static struct uart_ops sci_uart_ops = {
#endif
};
+static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
+{
+ const char *clk_names[] = {
+ [SCI_FCK] = "fck",
+ [SCI_SCK] = "sck",
+ [SCI_BRG_INT] = "brg_int",
+ [SCI_SCIF_CLK] = "scif_clk",
+ };
+ struct clk *clk;
+ unsigned int i;
+
+ if (sci_port->cfg->type == PORT_HSCIF)
+ clk_names[SCI_SCK] = "hsck";
+
+ for (i = 0; i < SCI_NUM_CLKS; i++) {
+ clk = devm_clk_get(dev, clk_names[i]);
+ if (PTR_ERR(clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (IS_ERR(clk) && i == SCI_FCK) {
+ /*
+ * "fck" used to be called "sci_ick", and we need to
+ * maintain DT backward compatibility.
+ */
+ clk = devm_clk_get(dev, "sci_ick");
+ if (PTR_ERR(clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (!IS_ERR(clk))
+ goto found;
+
+ /*
+ * Not all SH platforms declare a clock lookup entry
+ * for SCI devices, in which case we need to get the
+ * global "peripheral_clk" clock.
+ */
+ clk = devm_clk_get(dev, "peripheral_clk");
+ if (!IS_ERR(clk))
+ goto found;
+
+ dev_err(dev, "failed to get %s (%ld)\n", clk_names[i],
+ PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+found:
+ if (IS_ERR(clk))
+ dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
+ PTR_ERR(clk));
+ else
+ dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
+ clk, clk);
+ sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
+ }
+ return 0;
+}
+
static int sci_init_single(struct platform_device *dev,
struct sci_port *sci_port, unsigned int index,
struct plat_sci_port *p, bool early)
@@ -2291,37 +2548,37 @@ static int sci_init_single(struct platform_device *dev,
port->fifosize = 256;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_HSCIF:
port->fifosize = 128;
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 0;
+ sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32);
break;
case PORT_SCIFA:
port->fifosize = 64;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_SCIF:
port->fifosize = 16;
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR(16);
} else {
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
}
break;
default:
port->fifosize = 1;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCI_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
break;
}
@@ -2330,25 +2587,12 @@ static int sci_init_single(struct platform_device *dev,
* data override the sampling rate for now.
*/
if (p->sampling_rate)
- sci_port->sampling_rate = p->sampling_rate;
+ sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate);
if (!early) {
- sci_port->iclk = clk_get(&dev->dev, "sci_ick");
- if (IS_ERR(sci_port->iclk)) {
- sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
- if (IS_ERR(sci_port->iclk)) {
- dev_err(&dev->dev, "can't get iclk\n");
- return PTR_ERR(sci_port->iclk);
- }
- }
-
- /*
- * The function clock is optional, ignore it if we can't
- * find it.
- */
- sci_port->fclk = clk_get(&dev->dev, "sci_fck");
- if (IS_ERR(sci_port->fclk))
- sci_port->fclk = NULL;
+ ret = sci_init_clocks(sci_port, &dev->dev);
+ if (ret < 0)
+ return ret;
port->dev = &dev->dev;
@@ -2405,13 +2649,11 @@ static int sci_init_single(struct platform_device *dev,
static void sci_cleanup_single(struct sci_port *port)
{
- clk_put(port->iclk);
- clk_put(port->fclk);
-
pm_runtime_disable(port->port.dev);
}
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, int ch)
{
sci_poll_put_char(port, ch);
@@ -2426,21 +2668,26 @@ static void serial_console_write(struct console *co, const char *s,
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl;
+ unsigned short bits, ctrl, ctrl_temp;
unsigned long flags;
int locked = 1;
local_irq_save(flags);
+#if defined(SUPPORT_SYSRQ)
if (port->sysrq)
locked = 0;
- else if (oops_in_progress)
+ else
+#endif
+ if (oops_in_progress)
locked = spin_trylock(&port->lock);
else
spin_lock(&port->lock);
- /* first save the SCSCR then disable the interrupts */
+ /* first save SCSCR then disable interrupts, keep clock source */
ctrl = serial_port_in(port, SCSCR);
- serial_port_out(port, SCSCR, sci_port->cfg->scscr);
+ ctrl_temp = (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
+ serial_port_out(port, SCSCR, ctrl_temp);
uart_console_write(port, s, count, serial_console_putchar);
@@ -2541,7 +2788,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
#define SCI_CONSOLE NULL
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
@@ -2559,9 +2806,6 @@ static int sci_remove(struct platform_device *dev)
{
struct sci_port *port = platform_get_drvdata(dev);
- cpufreq_unregister_notifier(&port->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-
uart_remove_one_port(&sci_uart_driver, &port->port);
sci_cleanup_single(port);
@@ -2569,42 +2813,44 @@ static int sci_remove(struct platform_device *dev)
return 0;
}
-struct sci_port_info {
- unsigned int type;
- unsigned int regtype;
-};
+
+#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
+#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
+#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
static const struct of_device_id of_sci_match[] = {
+ /* SoC-specific types */
+ {
+ .compatible = "renesas,scif-r7s72100",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+ },
+ /* Family-specific types */
+ {
+ .compatible = "renesas,rcar-gen1-scif",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ }, {
+ .compatible = "renesas,rcar-gen2-scif",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ }, {
+ .compatible = "renesas,rcar-gen3-scif",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ },
+ /* Generic types */
{
.compatible = "renesas,scif",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
}, {
.compatible = "renesas,scifa",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCIFA,
- .regtype = SCIx_SCIFA_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
}, {
.compatible = "renesas,scifb",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCIFB,
- .regtype = SCIx_SCIFB_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
}, {
.compatible = "renesas,hscif",
- .data = &(const struct sci_port_info) {
- .type = PORT_HSCIF,
- .regtype = SCIx_HSCIF_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
}, {
.compatible = "renesas,sci",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCI,
- .regtype = SCIx_SCI_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
}, {
/* Terminator */
},
@@ -2616,24 +2862,21 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
- const struct sci_port_info *info;
struct plat_sci_port *p;
int id;
if (!IS_ENABLED(CONFIG_OF) || !np)
return NULL;
- match = of_match_node(of_sci_match, pdev->dev.of_node);
+ match = of_match_node(of_sci_match, np);
if (!match)
return NULL;
- info = match->data;
-
p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
if (!p)
return NULL;
- /* Get the line number for the aliases node. */
+ /* Get the line number from the aliases node. */
id = of_alias_get_id(np, "serial");
if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
@@ -2643,8 +2886,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
*dev_id = id;
p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
- p->type = info->type;
- p->regtype = info->regtype;
+ p->type = SCI_OF_TYPE(match->data);
+ p->regtype = SCI_OF_REGTYPE(match->data);
p->scscr = SCSCR_RE | SCSCR_TE;
return p;
@@ -2714,16 +2957,6 @@ static int sci_probe(struct platform_device *dev)
if (ret)
return ret;
- sp->freq_transition.notifier_call = sci_notifier;
-
- ret = cpufreq_register_notifier(&sp->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
- if (unlikely(ret < 0)) {
- uart_remove_one_port(&sci_uart_driver, &sp->port);
- sci_cleanup_single(sp);
- return ret;
- }
-
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_gdb_detach();
#endif
@@ -2789,6 +3022,62 @@ static void __exit sci_exit(void)
early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+static struct __init plat_sci_port port_cfg;
+
+static int __init early_console_setup(struct earlycon_device *device,
+ int type)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->port.serial_in = sci_serial_in;
+ device->port.serial_out = sci_serial_out;
+ device->port.type = type;
+ memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
+ sci_ports[0].cfg = &port_cfg;
+ sci_ports[0].cfg->type = type;
+ sci_probe_regmap(sci_ports[0].cfg);
+ port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) |
+ SCSCR_RE | SCSCR_TE;
+ sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr);
+
+ device->con->write = serial_console_write;
+ return 0;
+}
+static int __init sci_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCI);
+}
+static int __init scif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIF);
+}
+static int __init scifa_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFA);
+}
+static int __init scifb_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFB);
+}
+static int __init hscif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_HSCIF);
+}
+
+OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
+OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
+OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
+OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
+#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
+
module_init(sci_init);
module_exit(sci_exit);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index bf69bbdcc1f9..7a4fa185b93e 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -27,18 +27,35 @@ enum {
HSSRR, /* Sampling Rate Register */
SCPCR, /* Serial Port Control Register */
SCPDR, /* Serial Port Data Register */
+ SCDL, /* BRG Frequency Division Register */
+ SCCKS, /* BRG Clock Select Register */
SCIx_NR_REGS,
};
/* SCSMR (Serial Mode Register) */
+#define SCSMR_C_A BIT(7) /* Communication Mode */
+#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
+#define SCSMR_ASYNC 0 /* - Asynchronous mode */
#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
#define SCSMR_PE BIT(5) /* Parity Enable */
#define SCSMR_ODD BIT(4) /* Odd Parity */
#define SCSMR_STOP BIT(3) /* Stop Bit Length */
#define SCSMR_CKS 0x0003 /* Clock Select */
+/* Serial Mode Register, SCIFA/SCIFB only bits */
+#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
+#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
+#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
+#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
+#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
+#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
+#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
+#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
+#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
+#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
+
/* Serial Control Register, SCIFA/SCIFB only bits */
#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
@@ -109,6 +126,14 @@ enum {
#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */
#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */
+/*
+ * BRG Clock Select Register (Some SCIF and HSCIF)
+ * The Baud Rate Generator for external clock can provide a clock source for
+ * the sampling clock. It outputs either its frequency divided clock, or the
+ * (undivided) (H)SCK external clock.
+ */
+#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
+#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 9dbae01d41ce..18971063f95f 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -517,7 +517,7 @@ static struct uart_ops serial_sprd_ops = {
};
#ifdef CONFIG_SERIAL_SPRD_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
+static void wait_for_xmitr(struct uart_port *port)
{
unsigned int status, tmout = 10000;
@@ -624,8 +624,6 @@ static int __init sprd_early_console_setup(
device->con->write = sprd_early_write;
return 0;
}
-
-EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
sprd_early_console_setup);
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index e124d2e88996..9ad98eaa35bf 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1262,7 +1262,7 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up)
/*
* Wait for transmitter & holding register to empty
*/
-static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
+static void wait_for_xmitr(struct uart_sunsu_port *up)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index b1c6bd3d483f..c9fdfc8bf47f 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -28,7 +28,7 @@
#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
-#define ULITE_NR_UARTS 4
+#define ULITE_NR_UARTS 16
/* ---------------------------------------------------------------------
* Register definitions
@@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr)
iowrite32be(val, addr);
}
-static struct uartlite_reg_ops uartlite_be = {
+static const struct uartlite_reg_ops uartlite_be = {
.in = uartlite_inbe32,
.out = uartlite_outbe32,
};
@@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr)
iowrite32(val, addr);
}
-static struct uartlite_reg_ops uartlite_le = {
+static const struct uartlite_reg_ops uartlite_le = {
.in = uartlite_inle32,
.out = uartlite_outle32,
};
static inline u32 uart_in32(u32 offset, struct uart_port *port)
{
- struct uartlite_reg_ops *reg_ops = port->private_data;
+ const struct uartlite_reg_ops *reg_ops = port->private_data;
return reg_ops->in(port->membase + offset);
}
static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
{
- struct uartlite_reg_ops *reg_ops = port->private_data;
+ const struct uartlite_reg_ops *reg_ops = port->private_data;
reg_ops->out(val, port->membase + offset);
}
@@ -193,12 +193,15 @@ static int ulite_transmit(struct uart_port *port, int stat)
static irqreturn_t ulite_isr(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- int busy, n = 0;
+ int stat, busy, n = 0;
+ unsigned long flags;
do {
- int stat = uart_in32(ULITE_STATUS, port);
+ spin_lock_irqsave(&port->lock, flags);
+ stat = uart_in32(ULITE_STATUS, port);
busy = ulite_receive(port, stat);
busy |= ulite_transmit(port, stat);
+ spin_unlock_irqrestore(&port->lock, flags);
n++;
} while (busy);
@@ -259,7 +262,8 @@ static int ulite_startup(struct uart_port *port)
{
int ret;
- ret = request_irq(port->irq, ulite_isr, IRQF_SHARED, "uartlite", port);
+ ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING,
+ "uartlite", port);
if (ret)
return ret;
@@ -519,6 +523,47 @@ static int __init ulite_console_init(void)
console_initcall(ulite_console_init);
+static void early_uartlite_putc(struct uart_port *port, int c)
+{
+ /*
+ * Limit how many times we'll spin waiting for TX FIFO status.
+ * This will prevent lockups if the base address is incorrectly
+ * set, or any other issue on the UARTLITE.
+ * This limit is pretty arbitrary, unless we are at about 10 baud
+ * we'll never timeout on a working UART.
+ */
+
+ unsigned retries = 1000000;
+ /* read status bit - 0x8 offset */
+ while (--retries && (readl(port->membase + 8) & (1 << 3)))
+ ;
+
+ /* Only attempt the iowrite if we didn't timeout */
+ /* write to TX_FIFO - 0x4 offset */
+ if (retries)
+ writel(c & 0xff, port->membase + 4);
+}
+
+static void early_uartlite_write(struct console *console,
+ const char *s, unsigned n)
+{
+ struct earlycon_device *device = console->data;
+ uart_console_write(&device->port, s, n, early_uartlite_putc);
+}
+
+static int __init early_uartlite_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = early_uartlite_write;
+ return 0;
+}
+EARLYCON_DECLARE(uartlite, early_uartlite_setup);
+OF_EARLYCON_DECLARE(uartlite_b, "xlnx,opb-uartlite-1.00.b", early_uartlite_setup);
+OF_EARLYCON_DECLARE(uartlite_a, "xlnx,xps-uartlite-1.00.a", early_uartlite_setup);
+
#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
static struct uart_driver ulite_uart_driver = {
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 73190f5d2832..1a7dc3c590b1 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -31,7 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/fs_uart_pd.h>
-#include <asm/ucc_slow.h>
+#include <soc/fsl/qe/ucc_slow.h>
#include <linux/firmware.h>
#include <asm/reg.h>
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 4079ec56f5f9..b384060e3b1f 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -485,7 +485,7 @@ static struct uart_driver vt8500_uart_driver;
#ifdef CONFIG_SERIAL_VT8500_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
+static void wait_for_xmitr(struct uart_port *port)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 009e0dbc12d2..cd46e64c4255 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -50,24 +50,24 @@ module_param(rx_timeout, uint, S_IRUGO);
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
/* Register offsets for the UART. */
-#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */
-#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */
-#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */
-#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */
-#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */
-#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */
-#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */
-#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */
-#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */
-#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */
-#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */
-#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */
-#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */
-#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */
-#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */
-#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */
-#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */
-#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */
+#define CDNS_UART_CR 0x00 /* Control Register */
+#define CDNS_UART_MR 0x04 /* Mode Register */
+#define CDNS_UART_IER 0x08 /* Interrupt Enable */
+#define CDNS_UART_IDR 0x0C /* Interrupt Disable */
+#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
+#define CDNS_UART_ISR 0x14 /* Interrupt Status */
+#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
+#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
+#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
+#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
+#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
+#define CDNS_UART_SR 0x2C /* Channel Status */
+#define CDNS_UART_FIFO 0x30 /* FIFO */
+#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */
+#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */
+#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
+#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
+#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
/* Control Register Bit Definitions */
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
@@ -126,6 +126,10 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
+#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \
+ CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \
+ CDNS_UART_IXR_TOUT)
+
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
#define CDNS_UART_IXR_BRK 0x80000000
@@ -172,43 +176,22 @@ struct cdns_uart {
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb);
-/**
- * cdns_uart_isr - Interrupt handler
- * @irq: Irq number
- * @dev_id: Id of the port
- *
- * Return: IRQHANDLED
- */
-static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
+static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
{
- struct uart_port *port = (struct uart_port *)dev_id;
- unsigned long flags;
- unsigned int isrstatus, numbytes;
- unsigned int data;
- char status = TTY_NORMAL;
-
- spin_lock_irqsave(&port->lock, flags);
-
- /* Read the interrupt status register to determine which
- * interrupt(s) is/are active.
- */
- isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET);
-
/*
* There is no hardware break detection, so we interpret framing
* error with all-zeros data as a break sequence. Most of the time,
* there's another non-zero byte at the end of the sequence.
*/
if (isrstatus & CDNS_UART_IXR_FRAMING) {
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY)) {
- if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) {
+ if (!readl(port->membase + CDNS_UART_FIFO)) {
port->read_status_mask |= CDNS_UART_IXR_BRK;
isrstatus &= ~CDNS_UART_IXR_FRAMING;
}
}
- writel(CDNS_UART_IXR_FRAMING,
- port->membase + CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR);
}
/* drop byte with parity error if IGNPAR specified */
@@ -218,94 +201,106 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
isrstatus &= port->read_status_mask;
isrstatus &= ~port->ignore_status_mask;
- if ((isrstatus & CDNS_UART_IXR_TOUT) ||
- (isrstatus & CDNS_UART_IXR_RXTRIG)) {
- /* Receive Timeout Interrupt */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_RXEMPTY)) {
- data = readl(port->membase + CDNS_UART_FIFO_OFFSET);
-
- /* Non-NULL byte after BREAK is garbage (99%) */
- if (data && (port->read_status_mask &
- CDNS_UART_IXR_BRK)) {
- port->read_status_mask &= ~CDNS_UART_IXR_BRK;
- port->icount.brk++;
- if (uart_handle_break(port))
- continue;
- }
+ if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
+ return;
-#ifdef SUPPORT_SYSRQ
- /*
- * uart_handle_sysrq_char() doesn't work if
- * spinlocked, for some reason
- */
- if (port->sysrq) {
- spin_unlock(&port->lock);
- if (uart_handle_sysrq_char(port,
- (unsigned char)data)) {
- spin_lock(&port->lock);
- continue;
- }
- spin_lock(&port->lock);
- }
-#endif
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) {
+ u32 data;
+ char status = TTY_NORMAL;
- port->icount.rx++;
+ data = readl(port->membase + CDNS_UART_FIFO);
- if (isrstatus & CDNS_UART_IXR_PARITY) {
- port->icount.parity++;
- status = TTY_PARITY;
- } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
- port->icount.frame++;
- status = TTY_FRAME;
- } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
- port->icount.overrun++;
- }
+ /* Non-NULL byte after BREAK is garbage (99%) */
+ if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
+ port->read_status_mask &= ~CDNS_UART_IXR_BRK;
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ }
+
+ if (uart_handle_sysrq_char(port, data))
+ continue;
+
+ port->icount.rx++;
- uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
- data, status);
+ if (isrstatus & CDNS_UART_IXR_PARITY) {
+ port->icount.parity++;
+ status = TTY_PARITY;
+ } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
+ port->icount.frame++;
+ status = TTY_FRAME;
+ } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
+ port->icount.overrun++;
}
- spin_unlock(&port->lock);
- tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
+
+ uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
+ data, status);
}
+ tty_flip_buffer_push(&port->state->port);
+}
- /* Dispatch an appropriate handler */
- if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
- if (uart_circ_empty(&port->state->xmit)) {
- writel(CDNS_UART_IXR_TXEMPTY,
- port->membase + CDNS_UART_IDR_OFFSET);
- } else {
- numbytes = port->fifosize;
- /* Break if no more data available in the UART buffer */
- while (numbytes--) {
- if (uart_circ_empty(&port->state->xmit))
- break;
- /* Get the data from the UART circular buffer
- * and write it to the cdns_uart's TX_FIFO
- * register.
- */
- writel(port->state->xmit.buf[
- port->state->xmit.tail],
- port->membase + CDNS_UART_FIFO_OFFSET);
-
- port->icount.tx++;
-
- /* Adjust the tail of the UART buffer and wrap
- * the buffer if it reaches limit.
- */
- port->state->xmit.tail =
- (port->state->xmit.tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
+static void cdns_uart_handle_tx(struct uart_port *port)
+{
+ unsigned int numbytes;
- if (uart_circ_chars_pending(
- &port->state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
- }
+ if (uart_circ_empty(&port->state->xmit)) {
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
+ return;
+ }
+
+ numbytes = port->fifosize;
+ while (numbytes && !uart_circ_empty(&port->state->xmit) &&
+ !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
+ /*
+ * Get the data from the UART circular buffer
+ * and write it to the cdns_uart's TX_FIFO
+ * register.
+ */
+ writel(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + CDNS_UART_FIFO);
+ port->icount.tx++;
+
+ /*
+ * Adjust the tail of the UART buffer and wrap
+ * the buffer if it reaches limit.
+ */
+ port->state->xmit.tail =
+ (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
+
+ numbytes--;
}
- writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET);
+ if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+/**
+ * cdns_uart_isr - Interrupt handler
+ * @irq: Irq number
+ * @dev_id: Id of the port
+ *
+ * Return: IRQHANDLED
+ */
+static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned long flags;
+ unsigned int isrstatus;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Read the interrupt status register to determine which
+ * interrupt(s) is/are active.
+ */
+ isrstatus = readl(port->membase + CDNS_UART_ISR);
+
+ if (isrstatus & CDNS_UART_RX_IRQS)
+ cdns_uart_handle_rx(port, isrstatus);
+
+ if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY)
+ cdns_uart_handle_tx(port);
+
+ writel(isrstatus, port->membase + CDNS_UART_ISR);
/* be sure to release the lock and tty before leaving */
spin_unlock_irqrestore(&port->lock, flags);
@@ -395,14 +390,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
&div8);
/* Write new divisors to hardware */
- mreg = readl(port->membase + CDNS_UART_MR_OFFSET);
+ mreg = readl(port->membase + CDNS_UART_MR);
if (div8)
mreg |= CDNS_UART_MR_CLKSEL;
else
mreg &= ~CDNS_UART_MR_CLKSEL;
- writel(mreg, port->membase + CDNS_UART_MR_OFFSET);
- writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET);
- writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET);
+ writel(mreg, port->membase + CDNS_UART_MR);
+ writel(cd, port->membase + CDNS_UART_BAUDGEN);
+ writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
cdns_uart->baud = baud;
return calc_baud;
@@ -449,9 +444,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Disable the TX and RX to set baud rate */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -476,11 +471,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
- while (readl(port->membase + CDNS_UART_CR_OFFSET) &
+ while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
@@ -489,11 +484,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
* enable bit and RX enable bit to enable the transmitter and
* receiver.
*/
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -510,43 +505,28 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
*/
static void cdns_uart_start_tx(struct uart_port *port)
{
- unsigned int status, numbytes = port->fifosize;
+ unsigned int status;
- if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
+ if (uart_tx_stopped(port))
return;
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
- /* Set the TX enable bit and clear the TX disable bit to enable the
+ /*
+ * Set the TX enable bit and clear the TX disable bit to enable the
* transmitter.
*/
- writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
+ status &= ~CDNS_UART_CR_TX_DIS;
+ status |= CDNS_UART_CR_TX_EN;
+ writel(status, port->membase + CDNS_UART_CR);
- while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {
- /* Break if no more data available in the UART buffer */
- if (uart_circ_empty(&port->state->xmit))
- break;
+ if (uart_circ_empty(&port->state->xmit))
+ return;
- /* Get the data from the UART circular buffer and
- * write it to the cdns_uart's TX_FIFO register.
- */
- writel(port->state->xmit.buf[port->state->xmit.tail],
- port->membase + CDNS_UART_FIFO_OFFSET);
- port->icount.tx++;
+ cdns_uart_handle_tx(port);
- /* Adjust the tail of the UART buffer and wrap
- * the buffer if it reaches limit.
- */
- port->state->xmit.tail = (port->state->xmit.tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
/* Enable the TX Empty interrupt */
- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET);
-
- if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
}
/**
@@ -557,10 +537,10 @@ static void cdns_uart_stop_tx(struct uart_port *port)
{
unsigned int regval;
- regval = readl(port->membase + CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR);
regval |= CDNS_UART_CR_TX_DIS;
/* Disable the transmitter */
- writel(regval, port->membase + CDNS_UART_CR_OFFSET);
+ writel(regval, port->membase + CDNS_UART_CR);
}
/**
@@ -571,10 +551,13 @@ static void cdns_uart_stop_rx(struct uart_port *port)
{
unsigned int regval;
- regval = readl(port->membase + CDNS_UART_CR_OFFSET);
- regval |= CDNS_UART_CR_RX_DIS;
+ /* Disable RX IRQs */
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR);
+
/* Disable the receiver */
- writel(regval, port->membase + CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR);
+ regval |= CDNS_UART_CR_RX_DIS;
+ writel(regval, port->membase + CDNS_UART_CR);
}
/**
@@ -587,7 +570,7 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
- status = readl(port->membase + CDNS_UART_SR_OFFSET) &
+ status = readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_TXEMPTY;
return status ? TIOCSER_TEMT : 0;
}
@@ -605,15 +588,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
spin_lock_irqsave(&port->lock, flags);
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
if (ctl == -1)
writel(CDNS_UART_CR_STARTBRK | status,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
else {
if ((status & CDNS_UART_CR_STOPBRK) == 0)
writel(CDNS_UART_CR_STOPBRK | status,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
}
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -636,18 +619,18 @@ static void cdns_uart_set_termios(struct uart_port *port,
spin_lock_irqsave(&port->lock, flags);
/* Wait for the transmit FIFO to empty before making changes */
- if (!(readl(port->membase + CDNS_UART_CR_OFFSET) &
+ if (!(readl(port->membase + CDNS_UART_CR) &
CDNS_UART_CR_TX_DIS)) {
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_TXEMPTY)) {
cpu_relax();
}
}
/* Disable the TX and RX to set baud rate */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
/*
* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
@@ -666,20 +649,20 @@ static void cdns_uart_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
/*
* Clear the RX disable and TX disable bits and then set the TX enable
* bit and RX enable bit to enable the transmitter and receiver.
*/
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
@@ -699,7 +682,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
- mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET);
+ mode_reg = readl(port->membase + CDNS_UART_MR);
/* Handling Data Size */
switch (termios->c_cflag & CSIZE) {
@@ -740,7 +723,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
cval |= CDNS_UART_MR_PARITY_NONE;
}
cval |= mode_reg & 1;
- writel(cval, port->membase + CDNS_UART_MR_OFFSET);
+ writel(cval, port->membase + CDNS_UART_MR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -753,63 +736,67 @@ static void cdns_uart_set_termios(struct uart_port *port,
*/
static int cdns_uart_startup(struct uart_port *port)
{
- unsigned int retval = 0, status = 0;
+ int ret;
+ unsigned long flags;
+ unsigned int status = 0;
- retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME,
- (void *)port);
- if (retval)
- return retval;
+ spin_lock_irqsave(&port->lock, flags);
/* Disable the TX and RX */
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars.
*/
writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
- port->membase + CDNS_UART_CR_OFFSET);
-
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
- /* Clear the RX disable and TX disable bits and then set the TX enable
- * bit and RX enable bit to enable the transmitter and receiver.
+ /*
+ * Clear the RX disable bit and then set the RX enable bit to enable
+ * the receiver.
*/
- writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS))
- | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN |
- CDNS_UART_CR_STOPBRK),
- port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
+ status &= CDNS_UART_CR_RX_DIS;
+ status |= CDNS_UART_CR_RX_EN;
+ writel(status, port->membase + CDNS_UART_CR);
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity.
*/
writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
- port->membase + CDNS_UART_MR_OFFSET);
+ port->membase + CDNS_UART_MR);
/*
* Set the RX FIFO Trigger level to use most of the FIFO, but it
* can be tuned with a module parameter
*/
- writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
/*
* Receive Timeout register is enabled but it
* can be tuned with a module parameter
*/
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
/* Clear out any pending interrupts before enabling them */
- writel(readl(port->membase + CDNS_UART_ISR_OFFSET),
- port->membase + CDNS_UART_ISR_OFFSET);
+ writel(readl(port->membase + CDNS_UART_ISR),
+ port->membase + CDNS_UART_ISR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
+ if (ret) {
+ dev_err(port->dev, "request_irq '%d' failed with %d\n",
+ port->irq, ret);
+ return ret;
+ }
/* Set the Interrupt Registers with desired interrupts */
- writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY |
- CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN |
- CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
- return retval;
+ return 0;
}
/**
@@ -819,14 +806,21 @@ static int cdns_uart_startup(struct uart_port *port)
static void cdns_uart_shutdown(struct uart_port *port)
{
int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
/* Disable interrupts */
- status = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(status, port->membase + CDNS_UART_IDR_OFFSET);
+ status = readl(port->membase + CDNS_UART_IMR);
+ writel(status, port->membase + CDNS_UART_IDR);
+ writel(0xffffffff, port->membase + CDNS_UART_ISR);
/* Disable the TX and RX */
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
free_irq(port->irq, port);
}
@@ -928,7 +922,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 val;
- val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET);
+ val = readl(port->membase + CDNS_UART_MODEMCR);
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
@@ -937,55 +931,46 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_DTR;
- writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET);
+ writel(val, port->membase + CDNS_UART_MODEMCR);
}
#ifdef CONFIG_CONSOLE_POLL
static int cdns_uart_poll_get_char(struct uart_port *port)
{
- u32 imr;
int c;
+ unsigned long flags;
- /* Disable all interrupts */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ spin_lock_irqsave(&port->lock, flags);
/* Check if FIFO is empty */
- if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
+ if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)
c = NO_POLL_CHAR;
else /* Read a character */
- c = (unsigned char) readl(
- port->membase + CDNS_UART_FIFO_OFFSET);
+ c = (unsigned char) readl(port->membase + CDNS_UART_FIFO);
- /* Enable interrupts */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ spin_unlock_irqrestore(&port->lock, flags);
return c;
}
static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
- u32 imr;
+ unsigned long flags;
- /* Disable all interrupts */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ spin_lock_irqsave(&port->lock, flags);
/* Wait until FIFO is empty */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Write a character */
- writel(c, port->membase + CDNS_UART_FIFO_OFFSET);
+ writel(c, port->membase + CDNS_UART_FIFO);
/* Wait until FIFO is empty */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
- /* Enable interrupts */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ spin_unlock_irqrestore(&port->lock, flags);
return;
}
@@ -1059,8 +1044,7 @@ static struct uart_port *cdns_uart_get_port(int id)
*/
static void cdns_uart_console_wait_tx(struct uart_port *port)
{
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
barrier();
}
@@ -1072,7 +1056,7 @@ static void cdns_uart_console_wait_tx(struct uart_port *port)
static void cdns_uart_console_putchar(struct uart_port *port, int ch)
{
cdns_uart_console_wait_tx(port);
- writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
+ writel(ch, port->membase + CDNS_UART_FIFO);
}
static void __init cdns_early_write(struct console *con, const char *s,
@@ -1093,7 +1077,9 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
return 0;
}
-EARLYCON_DECLARE(cdns, cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
/**
* cdns_uart_console_write - perform write operation
@@ -1109,30 +1095,33 @@ static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int imr, ctrl;
int locked = 1;
- if (oops_in_progress)
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
spin_lock_irqsave(&port->lock, flags);
/* save and disable interrupt */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ imr = readl(port->membase + CDNS_UART_IMR);
+ writel(imr, port->membase + CDNS_UART_IDR);
/*
* Make sure that the tx part is enabled. Set the TX enable bit and
* clear the TX disable bit to enable the transmitter.
*/
- ctrl = readl(port->membase + CDNS_UART_CR_OFFSET);
- writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- port->membase + CDNS_UART_CR_OFFSET);
+ ctrl = readl(port->membase + CDNS_UART_CR);
+ ctrl &= ~CDNS_UART_CR_TX_DIS;
+ ctrl |= CDNS_UART_CR_TX_EN;
+ writel(ctrl, port->membase + CDNS_UART_CR);
uart_console_write(port, s, count, cdns_uart_console_putchar);
cdns_uart_console_wait_tx(port);
- writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl, port->membase + CDNS_UART_CR);
/* restore interrupt state */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IER);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
@@ -1244,14 +1233,13 @@ static int cdns_uart_suspend(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY))
- readl(port->membase + CDNS_UART_FIFO_OFFSET);
+ readl(port->membase + CDNS_UART_FIFO);
/* set RX trigger level to 1 */
- writel(1, port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(1, port->membase + CDNS_UART_RXWM);
/* disable RX timeout interrups */
- writel(CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IDR_OFFSET);
+ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1290,30 +1278,28 @@ static int cdns_uart_resume(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
- while (readl(port->membase + CDNS_UART_CR_OFFSET) &
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
+ while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* restore rx timeout value */
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
/* Enable Tx/Rx */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&port->lock, flags);
} else {
spin_lock_irqsave(&port->lock, flags);
/* restore original rx trigger level */
- writel(rx_trigger_level,
- port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
/* enable RX timeout interrupt */
- writel(CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1406,27 +1392,30 @@ static int cdns_uart_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
rc = -ENODEV;
goto err_out_notif_unreg;
- } else {
- /* Register the port.
- * This function also registers this device with the tty layer
- * and triggers invocation of the config_port() entry point.
- */
- port->mapbase = res->start;
- port->irq = irq;
- port->dev = &pdev->dev;
- port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
- port->private_data = cdns_uart_data;
- cdns_uart_data->port = port;
- platform_set_drvdata(pdev, port);
- rc = uart_add_one_port(&cdns_uart_uart_driver, port);
- if (rc) {
- dev_err(&pdev->dev,
- "uart_add_one_port() failed; err=%i\n", rc);
- goto err_out_notif_unreg;
- }
- return 0;
}
+ /*
+ * Register the port.
+ * This function also registers this device with the tty layer
+ * and triggers invocation of the config_port() entry point.
+ */
+ port->mapbase = res->start;
+ port->irq = irq;
+ port->dev = &pdev->dev;
+ port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
+ port->private_data = cdns_uart_data;
+ cdns_uart_data->port = port;
+ platform_set_drvdata(pdev, port);
+
+ rc = uart_add_one_port(&cdns_uart_uart_driver, port);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "uart_add_one_port() failed; err=%i\n", rc);
+ goto err_out_notif_unreg;
+ }
+
+ return 0;
+
err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 2b65bb7ffb8a..eeefd76a30da 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -1181,6 +1181,10 @@ static void zs_console_write(struct console *co, const char *s,
if (txint & TxINT_ENAB) {
zport->regs[1] |= TxINT_ENAB;
write_zsreg(zport, R1, zport->regs[1]);
+
+ /* Resume any transmission as the TxIP bit won't be set. */
+ if (!zport->tx_stopped)
+ zs_raw_transmit_chars(zport);
}
spin_unlock_irqrestore(&scc->zlock, flags);
}
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 6188059fd523..f5476e270734 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -2363,7 +2363,7 @@ static void mgsl_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgsl_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals &= ~SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -2397,7 +2397,7 @@ static void mgsl_unthrottle(struct tty_struct * tty)
mgsl_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -3039,30 +3039,25 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
mgsl_change_params(info);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
-
+
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->serial_signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
-
+
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
mgsl_start(tty);
}
@@ -3281,7 +3276,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL)
+ if (C_CLOCAL(tty))
do_clocal = true;
/* Wait for carrier detect and the line to become
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 6fc39fbfc275..c0a2f5a1b1c2 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -89,7 +89,7 @@
* module identification
*/
static char *driver_name = "SyncLink GT";
-static char *tty_driver_name = "synclink_gt";
+static char *slgt_driver_name = "synclink_gt";
static char *tty_dev_prefix = "ttySLG";
MODULE_LICENSE("GPL");
#define MGSL_MAGIC 0x5401
@@ -774,8 +774,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_params(info);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -783,21 +782,17 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1362,7 +1357,7 @@ static void throttle(struct tty_struct * tty)
DBGINFO(("%s throttle\n", info->device_name));
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1387,7 +1382,7 @@ static void unthrottle(struct tty_struct * tty)
else
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS;
set_signals(info);
@@ -3280,7 +3275,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL)
+ if (C_CLOCAL(tty))
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3799,7 +3794,7 @@ static int __init slgt_init(void)
/* Initialize the tty_driver structure */
- serial_driver->driver_name = tty_driver_name;
+ serial_driver->driver_name = slgt_driver_name;
serial_driver->name = tty_dev_prefix;
serial_driver->major = ttymajor;
serial_driver->minor_start = 64;
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index fb00a06dfa4b..90da0c712262 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -549,8 +549,8 @@ static int tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static int set_break(struct tty_struct *tty, int break_state);
-static void add_device(SLMP_INFO *info);
-static void device_init(int adapter_num, struct pci_dev *pdev);
+static int add_device(SLMP_INFO *info);
+static int device_init(int adapter_num, struct pci_dev *pdev);
static int claim_resources(SLMP_INFO *info);
static void release_resources(SLMP_INFO *info);
@@ -871,8 +871,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_params(info);
/* Handle transition to B0 status */
- if (old_termios->c_cflag & CBAUD &&
- !(tty->termios.c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -880,21 +879,17 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios.c_cflag & CBAUD) {
+ if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
info->serial_signals |= SerialSignal_RTS;
- }
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
/* Handle turning off CRTSCTS */
- if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios.c_cflag & CRTSCTS)) {
+ if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1472,7 +1467,7 @@ static void throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1501,7 +1496,7 @@ static void unthrottle(struct tty_struct * tty)
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -3297,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL)
+ if (C_CLOCAL(tty))
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3693,7 +3688,7 @@ static void release_resources(SLMP_INFO *info)
/* Add the specified device instance data structure to the
* global linked list of devices and increment the device count.
*/
-static void add_device(SLMP_INFO *info)
+static int add_device(SLMP_INFO *info)
{
info->next_device = NULL;
info->line = synclinkmp_device_count;
@@ -3731,7 +3726,9 @@ static void add_device(SLMP_INFO *info)
info->max_frame_size );
#if SYNCLINK_GENERIC_HDLC
- hdlcdev_init(info);
+ return hdlcdev_init(info);
+#else
+ return 0;
#endif
}
@@ -3820,10 +3817,10 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
return info;
}
-static void device_init(int adapter_num, struct pci_dev *pdev)
+static int device_init(int adapter_num, struct pci_dev *pdev)
{
SLMP_INFO *port_array[SCA_MAX_PORTS];
- int port;
+ int port, rc;
/* allocate device instances for up to SCA_MAX_PORTS devices */
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
@@ -3833,14 +3830,16 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
tty_port_destroy(&port_array[port]->port);
kfree(port_array[port]);
}
- return;
+ return -ENOMEM;
}
}
/* give copy of port_array to all ports and add to device list */
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
memcpy(port_array[port]->port_array,port_array,sizeof(port_array));
- add_device( port_array[port] );
+ rc = add_device( port_array[port] );
+ if (rc)
+ goto err_add;
spin_lock_init(&port_array[port]->lock);
}
@@ -3860,21 +3859,30 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
alloc_dma_bufs(port_array[port]);
}
- if ( request_irq(port_array[0]->irq_level,
+ rc = request_irq(port_array[0]->irq_level,
synclinkmp_interrupt,
port_array[0]->irq_flags,
port_array[0]->device_name,
- port_array[0]) < 0 ) {
+ port_array[0]);
+ if ( rc ) {
printk( "%s(%d):%s Can't request interrupt, IRQ=%d\n",
__FILE__,__LINE__,
port_array[0]->device_name,
port_array[0]->irq_level );
+ goto err_irq;
}
- else {
- port_array[0]->irq_requested = true;
- adapter_test(port_array[0]);
- }
+ port_array[0]->irq_requested = true;
+ adapter_test(port_array[0]);
}
+ return 0;
+err_irq:
+ release_resources( port_array[0] );
+err_add:
+ for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+ tty_port_destroy(&port_array[port]->port);
+ kfree(port_array[port]);
+ }
+ return rc;
}
static const struct tty_operations ops = {
@@ -5589,8 +5597,7 @@ static int synclinkmp_init_one (struct pci_dev *dev,
printk("error enabling pci device %p\n", dev);
return -EIO;
}
- device_init( ++synclinkmp_adapter_count, dev );
- return 0;
+ return device_init( ++synclinkmp_adapter_count, dev );
}
static void synclinkmp_remove_one (struct pci_dev *dev)
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 3d245cd3d8e6..df2d735338e2 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -14,16 +14,23 @@
#include <linux/tty.h>
struct tty_audit_buf {
- atomic_t count;
struct mutex mutex; /* Protects all data below */
- int major, minor; /* The TTY which the data is from */
+ dev_t dev; /* The TTY which the data is from */
unsigned icanon:1;
size_t valid;
unsigned char *data; /* Allocated size N_TTY_BUF_SIZE */
};
-static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
- unsigned icanon)
+static struct tty_audit_buf *tty_audit_buf_ref(void)
+{
+ struct tty_audit_buf *buf;
+
+ buf = current->signal->tty_audit_buf;
+ WARN_ON(buf == ERR_PTR(-ESRCH));
+ return buf;
+}
+
+static struct tty_audit_buf *tty_audit_buf_alloc(void)
{
struct tty_audit_buf *buf;
@@ -33,11 +40,9 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!buf->data)
goto err_buf;
- atomic_set(&buf->count, 1);
mutex_init(&buf->mutex);
- buf->major = major;
- buf->minor = minor;
- buf->icanon = icanon;
+ buf->dev = MKDEV(0, 0);
+ buf->icanon = 0;
buf->valid = 0;
return buf;
@@ -54,13 +59,7 @@ static void tty_audit_buf_free(struct tty_audit_buf *buf)
kfree(buf);
}
-static void tty_audit_buf_put(struct tty_audit_buf *buf)
-{
- if (atomic_dec_and_test(&buf->count))
- tty_audit_buf_free(buf);
-}
-
-static void tty_audit_log(const char *description, int major, int minor,
+static void tty_audit_log(const char *description, dev_t dev,
unsigned char *data, size_t size)
{
struct audit_buffer *ab;
@@ -76,7 +75,7 @@ static void tty_audit_log(const char *description, int major, int minor,
audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d"
" minor=%d comm=", description, pid, uid,
- loginuid, sessionid, major, minor);
+ loginuid, sessionid, MAJOR(dev), MINOR(dev));
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
@@ -99,7 +98,7 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf)
buf->valid = 0;
return;
}
- tty_audit_log("tty", buf->major, buf->minor, buf->data, buf->valid);
+ tty_audit_log("tty", buf->dev, buf->data, buf->valid);
buf->valid = 0;
}
@@ -108,21 +107,20 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf)
*
* Make sure all buffered data is written out and deallocate the buffer.
* Only needs to be called if current->signal->tty_audit_buf != %NULL.
+ *
+ * The process is single-threaded at this point; no other threads share
+ * current->signal.
*/
void tty_audit_exit(void)
{
struct tty_audit_buf *buf;
- buf = current->signal->tty_audit_buf;
- current->signal->tty_audit_buf = NULL;
+ buf = xchg(&current->signal->tty_audit_buf, ERR_PTR(-ESRCH));
if (!buf)
return;
- mutex_lock(&buf->mutex);
tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
-
- tty_audit_buf_put(buf);
+ tty_audit_buf_free(buf);
}
/**
@@ -133,7 +131,6 @@ void tty_audit_exit(void)
void tty_audit_fork(struct signal_struct *sig)
{
sig->audit_tty = current->signal->audit_tty;
- sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd;
}
/**
@@ -141,123 +138,62 @@ void tty_audit_fork(struct signal_struct *sig)
*/
void tty_audit_tiocsti(struct tty_struct *tty, char ch)
{
- struct tty_audit_buf *buf;
- int major, minor, should_audit;
- unsigned long flags;
+ dev_t dev;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- should_audit = current->signal->audit_tty;
- buf = current->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-
- major = tty->driver->major;
- minor = tty->driver->minor_start + tty->index;
- if (buf) {
- mutex_lock(&buf->mutex);
- if (buf->major == major && buf->minor == minor)
- tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
- tty_audit_buf_put(buf);
- }
-
- if (should_audit && audit_enabled) {
- kuid_t auid;
- unsigned int sessionid;
+ dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+ if (tty_audit_push())
+ return;
- auid = audit_get_loginuid(current);
- sessionid = audit_get_sessionid(current);
- tty_audit_log("ioctl=TIOCSTI", major, minor, &ch, 1);
- }
+ if (audit_enabled)
+ tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1);
}
/**
- * tty_audit_push_current - Flush current's pending audit data
+ * tty_audit_push - Flush current's pending audit data
*
- * Try to lock sighand and get a reference to the tty audit buffer if available.
- * Flush the buffer or return an appropriate error code.
+ * Returns 0 if success, -EPERM if tty audit is disabled
*/
-int tty_audit_push_current(void)
+int tty_audit_push(void)
{
- struct tty_audit_buf *buf = ERR_PTR(-EPERM);
- struct task_struct *tsk = current;
- unsigned long flags;
+ struct tty_audit_buf *buf;
- if (!lock_task_sighand(tsk, &flags))
- return -ESRCH;
+ if (~current->signal->audit_tty & AUDIT_TTY_ENABLE)
+ return -EPERM;
- if (tsk->signal->audit_tty) {
- buf = tsk->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
+ buf = tty_audit_buf_ref();
+ if (!IS_ERR_OR_NULL(buf)) {
+ mutex_lock(&buf->mutex);
+ tty_audit_buf_push(buf);
+ mutex_unlock(&buf->mutex);
}
- unlock_task_sighand(tsk, &flags);
-
- /*
- * Return 0 when signal->audit_tty set
- * but tsk->signal->tty_audit_buf == NULL.
- */
- if (!buf || IS_ERR(buf))
- return PTR_ERR(buf);
-
- mutex_lock(&buf->mutex);
- tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
-
- tty_audit_buf_put(buf);
return 0;
}
/**
* tty_audit_buf_get - Get an audit buffer.
*
- * Get an audit buffer for @tty, allocate it if necessary. Return %NULL
- * if TTY auditing is disabled or out of memory. Otherwise, return a new
- * reference to the buffer.
+ * Get an audit buffer, allocate it if necessary. Return %NULL
+ * if out of memory or ERR_PTR(-ESRCH) if tty_audit_exit() has already
+ * occurred. Otherwise, return a new reference to the buffer.
*/
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
- unsigned icanon)
+static struct tty_audit_buf *tty_audit_buf_get(void)
{
- struct tty_audit_buf *buf, *buf2;
- unsigned long flags;
-
- buf = NULL;
- buf2 = NULL;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- if (likely(!current->signal->audit_tty))
- goto out;
- buf = current->signal->tty_audit_buf;
- if (buf) {
- atomic_inc(&buf->count);
- goto out;
- }
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ struct tty_audit_buf *buf;
+
+ buf = tty_audit_buf_ref();
+ if (buf)
+ return buf;
- buf2 = tty_audit_buf_alloc(tty->driver->major,
- tty->driver->minor_start + tty->index,
- icanon);
- if (buf2 == NULL) {
+ buf = tty_audit_buf_alloc();
+ if (buf == NULL) {
audit_log_lost("out of memory in TTY auditing");
return NULL;
}
- spin_lock_irqsave(&current->sighand->siglock, flags);
- if (!current->signal->audit_tty)
- goto out;
- buf = current->signal->tty_audit_buf;
- if (!buf) {
- current->signal->tty_audit_buf = buf2;
- buf = buf2;
- buf2 = NULL;
- }
- atomic_inc(&buf->count);
- /* Fall through */
- out:
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- if (buf2)
- tty_audit_buf_free(buf2);
- return buf;
+ /* Race to use this buffer, free it if another wins */
+ if (cmpxchg(&current->signal->tty_audit_buf, NULL, buf) != NULL)
+ tty_audit_buf_free(buf);
+ return tty_audit_buf_ref();
}
/**
@@ -265,39 +201,36 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
*
* Audit @data of @size from @tty, if necessary.
*/
-void tty_audit_add_data(struct tty_struct *tty, const void *data,
- size_t size, unsigned icanon)
+void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size)
{
struct tty_audit_buf *buf;
- int major, minor;
- int audit_log_tty_passwd;
- unsigned long flags;
+ unsigned int icanon = !!L_ICANON(tty);
+ unsigned int audit_tty;
+ dev_t dev;
- if (unlikely(size == 0))
+ audit_tty = READ_ONCE(current->signal->audit_tty);
+ if (~audit_tty & AUDIT_TTY_ENABLE)
return;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- audit_log_tty_passwd = current->signal->audit_tty_log_passwd;
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- if (!audit_log_tty_passwd && icanon && !L_ECHO(tty))
+ if (unlikely(size == 0))
return;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY
&& tty->driver->subtype == PTY_TYPE_MASTER)
return;
- buf = tty_audit_buf_get(tty, icanon);
- if (!buf)
+ if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty))
+ return;
+
+ buf = tty_audit_buf_get();
+ if (IS_ERR_OR_NULL(buf))
return;
mutex_lock(&buf->mutex);
- major = tty->driver->major;
- minor = tty->driver->minor_start + tty->index;
- if (buf->major != major || buf->minor != minor
- || buf->icanon != icanon) {
+ dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+ if (buf->dev != dev || buf->icanon != icanon) {
tty_audit_buf_push(buf);
- buf->major = major;
- buf->minor = minor;
+ buf->dev = dev;
buf->icanon = icanon;
}
do {
@@ -314,38 +247,4 @@ void tty_audit_add_data(struct tty_struct *tty, const void *data,
tty_audit_buf_push(buf);
} while (size != 0);
mutex_unlock(&buf->mutex);
- tty_audit_buf_put(buf);
-}
-
-/**
- * tty_audit_push - Push buffered data out
- *
- * Make sure no audit data is pending for @tty on the current process.
- */
-void tty_audit_push(struct tty_struct *tty)
-{
- struct tty_audit_buf *buf;
- unsigned long flags;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- if (likely(!current->signal->audit_tty)) {
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- return;
- }
- buf = current->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-
- if (buf) {
- int major, minor;
-
- major = tty->driver->major;
- minor = tty->driver->minor_start + tty->index;
- mutex_lock(&buf->mutex);
- if (buf->major == major && buf->minor == minor)
- tty_audit_buf_push(buf);
- mutex_unlock(&buf->mutex);
- tty_audit_buf_put(buf);
- }
}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 3cd31e0d4bd9..a946e49a2626 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -435,25 +435,42 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+/**
+ * tty_ldisc_receive_buf - forward data to line discipline
+ * @ld: line discipline to process input
+ * @p: char buffer
+ * @f: TTY_* flags buffer
+ * @count: number of bytes to process
+ *
+ * Callers other than flush_to_ldisc() need to exclude the kworker
+ * from concurrent use of the line discipline, see paste_selection().
+ *
+ * Returns the number of bytes not processed
+ */
+int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p,
+ char *f, int count)
+{
+ if (ld->ops->receive_buf2)
+ count = ld->ops->receive_buf2(ld->tty, p, f, count);
+ else {
+ count = min_t(int, count, ld->tty->receive_room);
+ if (count && ld->ops->receive_buf)
+ ld->ops->receive_buf(ld->tty, p, f, count);
+ }
+ return count;
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf);
static int
-receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
+receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count)
{
- struct tty_ldisc *disc = tty->ldisc;
unsigned char *p = char_buf_ptr(head, head->read);
char *f = NULL;
if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read);
- if (disc->ops->receive_buf2)
- count = disc->ops->receive_buf2(tty, p, f, count);
- else {
- count = min_t(int, count, tty->receive_room);
- if (count && disc->ops->receive_buf)
- disc->ops->receive_buf(tty, p, f, count);
- }
- return count;
+ return tty_ldisc_receive_buf(ld, p, f, count);
}
/**
@@ -514,7 +531,7 @@ static void flush_to_ldisc(struct work_struct *work)
continue;
}
- count = receive_buf(tty, head, count);
+ count = receive_buf(disc, head, count);
if (!count)
break;
head->read += count;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index bcc8e1e8bb72..8d26ed79bb4c 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -123,7 +123,8 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC,
.c_ispeed = 38400,
- .c_ospeed = 38400
+ .c_ospeed = 38400,
+ /* .c_line = N_TTY, */
};
EXPORT_SYMBOL(tty_std_termios);
@@ -134,13 +135,8 @@ EXPORT_SYMBOL(tty_std_termios);
LIST_HEAD(tty_drivers); /* linked list of tty drivers */
-/* Mutex to protect creating and releasing a tty. This is shared with
- vt.c for deeply disgusting hack reasons */
+/* Mutex to protect creating and releasing a tty */
DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-/* Spinlock to protect the tty->tty_files list */
-DEFINE_SPINLOCK(tty_files_lock);
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
@@ -168,10 +164,9 @@ static void release_tty(struct tty_struct *tty, int idx);
* Locking: none. Must be called after tty is definitely unused
*/
-void free_tty_struct(struct tty_struct *tty)
+static void free_tty_struct(struct tty_struct *tty)
{
- if (!tty)
- return;
+ tty_ldisc_deinit(tty);
put_device(tty->dev);
kfree(tty->write_buf);
tty->magic = 0xDEADDEAD;
@@ -204,9 +199,9 @@ void tty_add_file(struct tty_struct *tty, struct file *file)
priv->tty = tty;
priv->file = file;
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_add(&priv->list, &tty->tty_files);
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
}
/**
@@ -227,10 +222,11 @@ void tty_free_file(struct file *file)
static void tty_del_file(struct file *file)
{
struct tty_file_private *priv = file->private_data;
+ struct tty_struct *tty = priv->tty;
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_del(&priv->list);
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
tty_free_file(file);
}
@@ -256,19 +252,24 @@ const char *tty_name(const struct tty_struct *tty)
EXPORT_SYMBOL(tty_name);
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
+const char *tty_driver_name(const struct tty_struct *tty)
+{
+ if (!tty || !tty->driver)
+ return "";
+ return tty->driver->name;
+}
+
+static int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
const char *routine)
{
#ifdef TTY_PARANOIA_CHECK
if (!tty) {
- printk(KERN_WARNING
- "null TTY for (%d:%d) in %s\n",
+ pr_warn("(%d:%d): %s: NULL tty\n",
imajor(inode), iminor(inode), routine);
return 1;
}
if (tty->magic != TTY_MAGIC) {
- printk(KERN_WARNING
- "bad magic number for tty struct (%d:%d) in %s\n",
+ pr_warn("(%d:%d): %s: bad magic number\n",
imajor(inode), iminor(inode), routine);
return 1;
}
@@ -283,19 +284,18 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
struct list_head *p;
int count = 0;
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_for_each(p, &tty->tty_files) {
count++;
}
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_SLAVE &&
tty->link && tty->link->count)
count++;
if (tty->count != count) {
- printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
- "!= #fd's(%d) in %s\n",
- tty->name, tty->count, count, routine);
+ tty_warn(tty, "%s: tty->count(%d) != #fd's(%d)\n",
+ routine, tty->count, count);
return count;
}
#endif
@@ -379,6 +379,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
EXPORT_SYMBOL_GPL(tty_find_polling_driver);
#endif
+static int is_ignored(int sig)
+{
+ return (sigismember(&current->blocked, sig) ||
+ current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
+}
+
/**
* tty_check_change - check for POSIX terminal changes
* @tty: tty to check
@@ -420,10 +426,8 @@ int __tty_check_change(struct tty_struct *tty, int sig)
}
rcu_read_unlock();
- if (!tty_pgrp) {
- pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n",
- tty_name(tty), sig);
- }
+ if (!tty_pgrp)
+ tty_warn(tty, "sig=%d, tty->pgrp == NULL!\n", sig);
return ret;
}
@@ -464,6 +468,11 @@ static long hung_up_tty_compat_ioctl(struct file *file,
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
+static int hung_up_tty_fasync(int fd, struct file *file, int on)
+{
+ return -ENOTTY;
+}
+
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
@@ -496,6 +505,7 @@ static const struct file_operations hung_up_tty_fops = {
.unlocked_ioctl = hung_up_tty_ioctl,
.compat_ioctl = hung_up_tty_compat_ioctl,
.release = tty_release,
+ .fasync = hung_up_tty_fasync,
};
static DEFINE_SPINLOCK(redirect_lock);
@@ -707,7 +717,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
workqueue with the lock held */
check_tty_count(tty, "tty_hangup");
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
/* This breaks for file handles being sent over AF_UNIX sockets ? */
list_for_each_entry(priv, &tty->tty_files, list) {
filp = priv->file;
@@ -719,14 +729,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
__tty_fasync(-1, filp, 0); /* can't block */
filp->f_op = &hung_up_tty_fops;
}
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
refs = tty_signal_session_leader(tty, exit_session);
/* Account for the p->signal references we killed */
while (refs--)
tty_kref_put(tty);
- tty_ldisc_hangup(tty);
+ tty_ldisc_hangup(tty, cons_filp != NULL);
spin_lock_irq(&tty->ctrl_lock);
clear_bit(TTY_THROTTLED, &tty->flags);
@@ -751,10 +761,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
} else if (tty->ops->hangup)
tty->ops->hangup(tty);
/*
- * We don't want to have driver/ldisc interactions beyond
- * the ones we did here. The driver layer expects no
- * calls after ->hangup() from the ldisc side. However we
- * can't yet guarantee all that.
+ * We don't want to have driver/ldisc interactions beyond the ones
+ * we did here. The driver layer expects no calls after ->hangup()
+ * from the ldisc side, which is now guaranteed.
*/
set_bit(TTY_HUPPED, &tty->flags);
tty_unlock(tty);
@@ -781,7 +790,7 @@ static void do_tty_hangup(struct work_struct *work)
void tty_hangup(struct tty_struct *tty)
{
- tty_debug_hangup(tty, "\n");
+ tty_debug_hangup(tty, "hangup\n");
schedule_work(&tty->hangup_work);
}
@@ -798,7 +807,7 @@ EXPORT_SYMBOL(tty_hangup);
void tty_vhangup(struct tty_struct *tty)
{
- tty_debug_hangup(tty, "\n");
+ tty_debug_hangup(tty, "vhangup\n");
__tty_hangup(tty, 0);
}
@@ -835,7 +844,7 @@ void tty_vhangup_self(void)
static void tty_vhangup_session(struct tty_struct *tty)
{
- tty_debug_hangup(tty, "\n");
+ tty_debug_hangup(tty, "session hangup\n");
__tty_hangup(tty, 1);
}
@@ -1067,6 +1076,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_read(file, buf, count, ppos);
if (ld->ops->read)
i = ld->ops->read(tty, file, buf, count);
else
@@ -1239,9 +1250,10 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
return -EIO;
/* Short term debug to catch buggy drivers */
if (tty->ops->write_room == NULL)
- printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
- tty->driver->name);
+ tty_err(tty, "missing write_room method\n");
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_write(file, buf, count, ppos);
if (!ld->ops->write)
ret = -EIO;
else
@@ -1377,7 +1389,7 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
* the tty_mutex currently so we can be relaxed about ordering.
*/
-int tty_init_termios(struct tty_struct *tty)
+void tty_init_termios(struct tty_struct *tty)
{
struct ktermios *tp;
int idx = tty->index;
@@ -1387,24 +1399,21 @@ int tty_init_termios(struct tty_struct *tty)
else {
/* Check for lazy saved data */
tp = tty->driver->termios[idx];
- if (tp != NULL)
+ if (tp != NULL) {
tty->termios = *tp;
- else
+ tty->termios.c_line = tty->driver->init_termios.c_line;
+ } else
tty->termios = tty->driver->init_termios;
}
/* Compatibility until drivers always set this */
tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
- return 0;
}
EXPORT_SYMBOL_GPL(tty_init_termios);
int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
{
- int ret = tty_init_termios(tty);
- if (ret)
- return ret;
-
+ tty_init_termios(tty);
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[tty->index] = tty;
@@ -1441,7 +1450,7 @@ static int tty_driver_install_tty(struct tty_driver *driver,
*
* Locking: tty_mutex for now
*/
-void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
+static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
{
if (driver->ops->remove)
driver->ops->remove(driver, tty);
@@ -1462,19 +1471,20 @@ static int tty_reopen(struct tty_struct *tty)
{
struct tty_driver *driver = tty->driver;
- if (!tty->count)
- return -EIO;
-
if (driver->type == TTY_DRIVER_TYPE_PTY &&
driver->subtype == PTY_TYPE_MASTER)
return -EIO;
+ if (!tty->count)
+ return -EAGAIN;
+
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
return -EBUSY;
tty->count++;
- WARN_ON(!tty->ldisc);
+ if (!tty->ldisc)
+ return tty_ldisc_reinit(tty, tty->termios.c_line);
return 0;
}
@@ -1528,7 +1538,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
tty_lock(tty);
retval = tty_driver_install_tty(driver, tty);
if (retval < 0)
- goto err_deinit_tty;
+ goto err_free_tty;
if (!tty->port)
tty->port = driver->ports[idx];
@@ -1550,9 +1560,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
/* Return the tty locked so that it cannot vanish under the caller */
return tty;
-err_deinit_tty:
+err_free_tty:
tty_unlock(tty);
- deinitialize_tty_struct(tty);
free_tty_struct(tty);
err_module_put:
module_put(driver->owner);
@@ -1561,13 +1570,13 @@ err_module_put:
/* call the tty release_tty routine to clean out this slot */
err_release_tty:
tty_unlock(tty);
- printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
- "clearing slot %d\n", idx);
+ tty_info_ratelimited(tty, "ldisc open failed (%d), clearing slot %d\n",
+ retval, idx);
release_tty(tty, idx);
return ERR_PTR(retval);
}
-void tty_free_termios(struct tty_struct *tty)
+static void tty_free_termios(struct tty_struct *tty)
{
struct ktermios *tp;
int idx = tty->index;
@@ -1580,15 +1589,12 @@ void tty_free_termios(struct tty_struct *tty)
tp = tty->driver->termios[idx];
if (tp == NULL) {
tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
- if (tp == NULL) {
- pr_warn("tty: no memory to save termios state.\n");
+ if (tp == NULL)
return;
- }
tty->driver->termios[idx] = tp;
}
*tp = tty->termios;
}
-EXPORT_SYMBOL(tty_free_termios);
/**
* tty_flush_works - flush all works of a tty/pty pair
@@ -1635,9 +1641,9 @@ static void release_one_tty(struct work_struct *work)
tty_driver_kref_put(driver);
module_put(owner);
- spin_lock(&tty_files_lock);
+ spin_lock(&tty->files_lock);
list_del_init(&tty->tty_files);
- spin_unlock(&tty_files_lock);
+ spin_unlock(&tty->files_lock);
put_pid(tty->pgrp);
put_pid(tty->session);
@@ -1788,7 +1794,7 @@ int tty_release(struct inode *inode, struct file *filp)
return 0;
}
- tty_debug_hangup(tty, "(tty count=%d)...\n", tty->count);
+ tty_debug_hangup(tty, "releasing (count=%d)\n", tty->count);
if (tty->ops->close)
tty->ops->close(tty, filp);
@@ -1837,8 +1843,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (once) {
once = 0;
- printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
- __func__, tty_name(tty));
+ tty_warn(tty, "read/write wait queue active!\n");
}
schedule_timeout_killable(timeout);
if (timeout < 120 * HZ)
@@ -1849,14 +1854,12 @@ int tty_release(struct inode *inode, struct file *filp)
if (o_tty) {
if (--o_tty->count < 0) {
- printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
- __func__, o_tty->count, tty_name(o_tty));
+ tty_warn(tty, "bad slave count (%d)\n", o_tty->count);
o_tty->count = 0;
}
}
if (--tty->count < 0) {
- printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
- __func__, tty->count, tty_name(tty));
+ tty_warn(tty, "bad tty->count (%d)\n", tty->count);
tty->count = 0;
}
@@ -1907,7 +1910,7 @@ int tty_release(struct inode *inode, struct file *filp)
/* Wait for pending work before tty destruction commmences */
tty_flush_works(tty);
- tty_debug_hangup(tty, "freeing structure...\n");
+ tty_debug_hangup(tty, "freeing structure\n");
/*
* The release_tty function takes care of the details of clearing
* the slots and preserving the termios structure. The tty_unlock_pair
@@ -1971,7 +1974,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
* Locking: tty_mutex protects get_tty_driver
*/
static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
- int *noctty, int *index)
+ int *index)
{
struct tty_driver *driver;
@@ -1981,7 +1984,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
extern struct tty_driver *console_driver;
driver = tty_driver_kref_get(console_driver);
*index = fg_console;
- *noctty = 1;
break;
}
#endif
@@ -1992,7 +1994,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
- *noctty = 1;
break;
}
}
@@ -2008,6 +2009,69 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
}
/**
+ * tty_open_by_driver - open a tty device
+ * @device: dev_t of device to open
+ * @inode: inode of device file
+ * @filp: file pointer to tty
+ *
+ * Performs the driver lookup, checks for a reopen, or otherwise
+ * performs the first-time tty initialization.
+ *
+ * Returns the locked initialized or re-opened &tty_struct
+ *
+ * Claims the global tty_mutex to serialize:
+ * - concurrent first-time tty initialization
+ * - concurrent tty driver removal w/ lookup
+ * - concurrent tty removal from driver table
+ */
+static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
+ struct file *filp)
+{
+ struct tty_struct *tty;
+ struct tty_driver *driver = NULL;
+ int index = -1;
+ int retval;
+
+ mutex_lock(&tty_mutex);
+ driver = tty_lookup_driver(device, filp, &index);
+ if (IS_ERR(driver)) {
+ mutex_unlock(&tty_mutex);
+ return ERR_CAST(driver);
+ }
+
+ /* check whether we're reopening an existing tty */
+ tty = tty_driver_lookup_tty(driver, inode, index);
+ if (IS_ERR(tty)) {
+ mutex_unlock(&tty_mutex);
+ goto out;
+ }
+
+ if (tty) {
+ mutex_unlock(&tty_mutex);
+ retval = tty_lock_interruptible(tty);
+ if (retval) {
+ if (retval == -EINTR)
+ retval = -ERESTARTSYS;
+ tty = ERR_PTR(retval);
+ goto out;
+ }
+ /* safe to drop the kref from tty_driver_lookup_tty() */
+ tty_kref_put(tty);
+ retval = tty_reopen(tty);
+ if (retval < 0) {
+ tty_unlock(tty);
+ tty = ERR_PTR(retval);
+ }
+ } else { /* Returns with the tty_lock held for now */
+ tty = tty_init_dev(driver, index);
+ mutex_unlock(&tty_mutex);
+ }
+out:
+ tty_driver_kref_put(driver);
+ return tty;
+}
+
+/**
* tty_open - open a tty device
* @inode: inode of device file
* @filp: file pointer to tty
@@ -2035,8 +2099,6 @@ static int tty_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
int noctty, retval;
- struct tty_driver *driver = NULL;
- int index;
dev_t device = inode->i_rdev;
unsigned saved_flags = filp->f_flags;
@@ -2047,57 +2109,23 @@ retry_open:
if (retval)
return -ENOMEM;
- noctty = filp->f_flags & O_NOCTTY;
- index = -1;
- retval = 0;
-
tty = tty_open_current_tty(device, filp);
- if (!tty) {
- mutex_lock(&tty_mutex);
- driver = tty_lookup_driver(device, filp, &noctty, &index);
- if (IS_ERR(driver)) {
- retval = PTR_ERR(driver);
- goto err_unlock;
- }
-
- /* check whether we're reopening an existing tty */
- tty = tty_driver_lookup_tty(driver, inode, index);
- if (IS_ERR(tty)) {
- retval = PTR_ERR(tty);
- goto err_unlock;
- }
-
- if (tty) {
- mutex_unlock(&tty_mutex);
- tty_lock(tty);
- /* safe to drop the kref from tty_driver_lookup_tty() */
- tty_kref_put(tty);
- retval = tty_reopen(tty);
- if (retval < 0) {
- tty_unlock(tty);
- tty = ERR_PTR(retval);
- }
- } else { /* Returns with the tty_lock held for now */
- tty = tty_init_dev(driver, index);
- mutex_unlock(&tty_mutex);
- }
-
- tty_driver_kref_put(driver);
- }
+ if (!tty)
+ tty = tty_open_by_driver(device, inode, filp);
if (IS_ERR(tty)) {
+ tty_free_file(filp);
retval = PTR_ERR(tty);
- goto err_file;
+ if (retval != -EAGAIN || signal_pending(current))
+ return retval;
+ schedule();
+ goto retry_open;
}
tty_add_file(tty, filp);
check_tty_count(tty, __func__);
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER)
- noctty = 1;
-
- tty_debug_hangup(tty, "(tty count=%d)\n", tty->count);
+ tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
if (tty->ops->open)
retval = tty->ops->open(tty, filp);
@@ -2106,7 +2134,7 @@ retry_open:
filp->f_flags = saved_flags;
if (retval) {
- tty_debug_hangup(tty, "error %d, releasing...\n", retval);
+ tty_debug_hangup(tty, "open error %d, releasing\n", retval);
tty_unlock(tty); /* need to call tty_release without BTM */
tty_release(inode, filp);
@@ -2129,6 +2157,12 @@ retry_open:
read_lock(&tasklist_lock);
spin_lock_irq(&current->sighand->siglock);
+ noctty = (filp->f_flags & O_NOCTTY) ||
+ device == MKDEV(TTY_MAJOR, 0) ||
+ device == MKDEV(TTYAUX_MAJOR, 1) ||
+ (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver->subtype == PTY_TYPE_MASTER);
+
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
@@ -2154,14 +2188,6 @@ retry_open:
read_unlock(&tasklist_lock);
tty_unlock(tty);
return 0;
-err_unlock:
- mutex_unlock(&tty_mutex);
- /* after locks to avoid deadlock */
- if (!IS_ERR_OR_NULL(driver))
- tty_driver_kref_put(driver);
-err_file:
- tty_free_file(filp);
- return retval;
}
@@ -2188,6 +2214,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
return 0;
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_poll(filp, wait);
if (ld->ops->poll)
ret = ld->ops->poll(tty, filp, wait);
tty_ldisc_deref(ld);
@@ -2197,7 +2225,6 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
static int __tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty = file_tty(filp);
- struct tty_ldisc *ldisc;
unsigned long flags;
int retval = 0;
@@ -2208,13 +2235,6 @@ static int __tty_fasync(int fd, struct file *filp, int on)
if (retval <= 0)
goto out;
- ldisc = tty_ldisc_ref(tty);
- if (ldisc) {
- if (ldisc->ops->fasync)
- ldisc->ops->fasync(tty, on);
- tty_ldisc_deref(ldisc);
- }
-
if (on) {
enum pid_type type;
struct pid *pid;
@@ -2240,10 +2260,11 @@ out:
static int tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty = file_tty(filp);
- int retval;
+ int retval = -ENOTTY;
tty_lock(tty);
- retval = __tty_fasync(fd, filp, on);
+ if (!tty_hung_up_p(filp))
+ retval = __tty_fasync(fd, filp, on);
tty_unlock(tty);
return retval;
@@ -2277,6 +2298,8 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
return -EFAULT;
tty_audit_tiocsti(tty, ch);
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO;
ld->ops->receive_buf(tty, &ch, &mbz, 1);
tty_ldisc_deref(ld);
return 0;
@@ -2641,18 +2664,42 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
- int ldisc;
+ int disc;
int ret;
- if (get_user(ldisc, p))
+ if (get_user(disc, p))
return -EFAULT;
- ret = tty_set_ldisc(tty, ldisc);
+ ret = tty_set_ldisc(tty, disc);
return ret;
}
/**
+ * tiocgetd - get line discipline
+ * @tty: tty device
+ * @p: pointer to user data
+ *
+ * Retrieves the line discipline id directly from the ldisc.
+ *
+ * Locking: waits for ldisc reference (in case the line discipline
+ * is changing or the tty is being hungup)
+ */
+
+static int tiocgetd(struct tty_struct *tty, int __user *p)
+{
+ struct tty_ldisc *ld;
+ int ret;
+
+ ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO;
+ ret = put_user(ld->ops->num, p);
+ tty_ldisc_deref(ld);
+ return ret;
+}
+
+/**
* send_break - performed time break
* @tty: device to break on
* @duration: timeout in mS
@@ -2870,7 +2917,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
no_tty();
return 0;
case TIOCSCTTY:
- return tiocsctty(tty, file, arg);
+ return tiocsctty(real_tty, file, arg);
case TIOCGPGRP:
return tiocgpgrp(tty, real_tty, p);
case TIOCSPGRP:
@@ -2878,7 +2925,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
- return put_user(tty->ldisc->ops->num, (int __user *)p);
+ return tiocgetd(tty, p);
case TIOCSETD:
return tiocsetd(tty, p);
case TIOCVHANGUP:
@@ -2944,6 +2991,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return retval;
}
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_ioctl(file, cmd, arg);
retval = -EINVAL;
if (ld->ops->ioctl) {
retval = ld->ops->ioctl(tty, file, cmd, arg);
@@ -2972,6 +3021,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
}
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_compat_ioctl(file, cmd, arg);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
else
@@ -3028,28 +3079,24 @@ void __do_SAK(struct tty_struct *tty)
read_lock(&tasklist_lock);
/* Kill the entire session */
do_each_pid_task(session, PIDTYPE_SID, p) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): task_session(p)==tty->session\n",
- task_pid_nr(p), p->comm);
+ tty_notice(tty, "SAK: killed process %d (%s): by session\n",
+ task_pid_nr(p), p->comm);
send_sig(SIGKILL, p, 1);
} while_each_pid_task(session, PIDTYPE_SID, p);
- /* Now kill any processes that happen to have the
- * tty open.
- */
+
+ /* Now kill any processes that happen to have the tty open */
do_each_thread(g, p) {
if (p->signal->tty == tty) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): task_session(p)==tty->session\n",
- task_pid_nr(p), p->comm);
+ tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n",
+ task_pid_nr(p), p->comm);
send_sig(SIGKILL, p, 1);
continue;
}
task_lock(p);
i = iterate_fd(p->files, 0, this_tty, tty);
if (i != 0) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): fd#%d opened to the tty\n",
- task_pid_nr(p), p->comm, i - 1);
+ tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n",
+ task_pid_nr(p), p->comm, i - 1);
force_sig(SIGKILL, p);
}
task_unlock(p);
@@ -3126,6 +3173,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->ctrl_lock);
spin_lock_init(&tty->flow_lock);
+ spin_lock_init(&tty->files_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
@@ -3139,20 +3187,6 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
}
/**
- * deinitialize_tty_struct
- * @tty: tty to deinitialize
- *
- * This subroutine deinitializes a tty structure that has been newly
- * allocated but tty_release cannot be called on that yet.
- *
- * Locking: none - tty in question must not be exposed at this point
- */
-void deinitialize_tty_struct(struct tty_struct *tty)
-{
- tty_ldisc_deinit(tty);
-}
-
-/**
* tty_put_char - write one character to a tty
* @tty: tty
* @ch: character
@@ -3219,7 +3253,7 @@ EXPORT_SYMBOL(tty_register_device);
static void tty_device_create_release(struct device *dev)
{
- pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
+ dev_dbg(dev, "releasing...\n");
kfree(dev);
}
@@ -3255,8 +3289,8 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
bool cdev = false;
if (index >= driver->num) {
- printk(KERN_ERR "Attempt to register invalid tty line number "
- " (%d).\n", index);
+ pr_err("%s: Attempt to register invalid tty line number (%d)\n",
+ driver->name, index);
return ERR_PTR(-EINVAL);
}
@@ -3546,7 +3580,7 @@ void __init console_init(void)
initcall_t *call;
/* Setup the default TTY line discipline. */
- tty_ldisc_begin();
+ n_tty_init();
/*
* set up the console device so that later boot sequences can
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 1445dd39aa62..23bf5bb1d8bf 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -216,7 +216,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
void tty_wait_until_sent(struct tty_struct *tty, long timeout)
{
- tty_debug_wait_until_sent(tty, "\n");
+ tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
@@ -239,19 +239,14 @@ EXPORT_SYMBOL(tty_wait_until_sent);
* Termios Helper Methods
*/
-static void unset_locked_termios(struct ktermios *termios,
- struct ktermios *old,
- struct ktermios *locked)
+static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
{
+ struct ktermios *termios = &tty->termios;
+ struct ktermios *locked = &tty->termios_locked;
int i;
#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
- if (!locked) {
- printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
- return;
- }
-
NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
@@ -463,10 +458,8 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
#else
- if (ifound == -1 || ofound == -1) {
- printk_once(KERN_WARNING "tty: Unable to return correct "
- "speed data as your architecture needs updating.\n");
- }
+ if (ifound == -1 || ofound == -1)
+ pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
#endif
}
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
@@ -556,7 +549,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
down_write(&tty->termios_rwsem);
old_termios = tty->termios;
tty->termios = *new_termios;
- unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
+ unset_locked_termios(tty, &old_termios);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
@@ -726,16 +719,16 @@ static int get_sgflags(struct tty_struct *tty)
{
int flags = 0;
- if (!(tty->termios.c_lflag & ICANON)) {
- if (tty->termios.c_lflag & ISIG)
+ if (!L_ICANON(tty)) {
+ if (L_ISIG(tty))
flags |= 0x02; /* cbreak */
else
flags |= 0x20; /* raw */
}
- if (tty->termios.c_lflag & ECHO)
+ if (L_ECHO(tty))
flags |= 0x08; /* echo */
- if (tty->termios.c_oflag & OPOST)
- if (tty->termios.c_oflag & ONLCR)
+ if (O_OPOST(tty))
+ if (O_ONLCR(tty))
flags |= 0x10; /* crmod */
return flags;
}
@@ -915,7 +908,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
tty->termios.c_cflag |= bit;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old);
- if ((tty->termios.c_cflag & CLOCAL) != bit)
+ if (C_CLOCAL(tty) != bit)
ret = -EINVAL;
up_write(&tty->termios_rwsem);
return ret;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 629e3c865072..68947f6de5ad 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -140,9 +140,16 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
* @disc: ldisc number
*
* Takes a reference to a line discipline. Deals with refcounts and
- * module locking counts. Returns NULL if the discipline is not available.
- * Returns a pointer to the discipline and bumps the ref count if it is
- * available
+ * module locking counts.
+ *
+ * Returns: -EINVAL if the discipline index is not [N_TTY..NR_LDISCS] or
+ * if the discipline is not registered
+ * -EAGAIN if request_module() failed to load or register the
+ * the discipline
+ * -ENOMEM if allocation failure
+ *
+ * Otherwise, returns a pointer to the discipline and bumps the
+ * ref count
*
* Locking:
* takes tty_ldiscs_lock to guard against ldisc races
@@ -185,7 +192,7 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
*
* Complement of tty_ldisc_get().
*/
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
+static void tty_ldisc_put(struct tty_ldisc *ld)
{
if (WARN_ON_ONCE(!ld))
return;
@@ -250,19 +257,23 @@ const struct file_operations tty_ldiscs_proc_fops = {
* reference to it. If the line discipline is in flux then
* wait patiently until it changes.
*
+ * Returns: NULL if the tty has been hungup and not re-opened with
+ * a new file descriptor, otherwise valid ldisc reference
+ *
* Note: Must not be called from an IRQ/timer context. The caller
* must also be careful not to hold other locks that will deadlock
* against a discipline change, such as an existing ldisc reference
* (which we check for)
*
- * Note: only callable from a file_operations routine (which
- * guarantees tty->ldisc != NULL when the lock is acquired).
+ * Note: a file_operations routine (read/poll/write) should use this
+ * function to wait for any ldisc lifetime events to finish.
*/
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
- WARN_ON(!tty->ldisc);
+ if (!tty->ldisc)
+ ldsem_up_read(&tty->ldisc_sem);
return tty->ldisc;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
@@ -304,13 +315,13 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-static inline int __lockfunc
+static inline int
__tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
return ldsem_down_write(&tty->ldisc_sem, timeout);
}
-static inline int __lockfunc
+static inline int
__tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
{
return ldsem_down_write_nested(&tty->ldisc_sem,
@@ -322,8 +333,7 @@ static inline void __tty_ldisc_unlock(struct tty_struct *tty)
ldsem_up_write(&tty->ldisc_sem);
}
-static int __lockfunc
-tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
int ret;
@@ -340,7 +350,7 @@ static void tty_ldisc_unlock(struct tty_struct *tty)
__tty_ldisc_unlock(tty);
}
-static int __lockfunc
+static int
tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
unsigned long timeout)
{
@@ -376,14 +386,13 @@ tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
return 0;
}
-static void __lockfunc
-tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
+static void tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
{
tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
}
-static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
- struct tty_struct *tty2)
+static void tty_ldisc_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
{
__tty_ldisc_unlock(tty);
if (tty2)
@@ -411,20 +420,27 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
/**
* tty_set_termios_ldisc - set ldisc field
* @tty: tty structure
- * @num: line discipline number
+ * @disc: line discipline number
*
* This is probably overkill for real world processors but
* they are not on hot paths so a little discipline won't do
* any harm.
*
+ * The line discipline-related tty_struct fields are reset to
+ * prevent the ldisc driver from re-using stale information for
+ * the new ldisc instance.
+ *
* Locking: takes termios_rwsem
*/
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+static void tty_set_termios_ldisc(struct tty_struct *tty, int disc)
{
down_write(&tty->termios_rwsem);
- tty->termios.c_line = num;
+ tty->termios.c_line = disc;
up_write(&tty->termios_rwsem);
+
+ tty->disc_data = NULL;
+ tty->receive_room = 0;
}
/**
@@ -448,7 +464,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
if (ret)
clear_bit(TTY_LDISC_OPEN, &tty->flags);
- tty_ldisc_debug(tty, "%p: opened\n", tty->ldisc);
+ tty_ldisc_debug(tty, "%p: opened\n", ld);
return ret;
}
return 0;
@@ -469,7 +485,7 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close)
ld->ops->close(tty);
- tty_ldisc_debug(tty, "%p: closed\n", tty->ldisc);
+ tty_ldisc_debug(tty, "%p: closed\n", ld);
}
/**
@@ -518,51 +534,43 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
* the close of one side of a tty/pty pair, and eventually hangup.
*/
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+int tty_set_ldisc(struct tty_struct *tty, int disc)
{
int retval;
struct tty_ldisc *old_ldisc, *new_ldisc;
- new_ldisc = tty_ldisc_get(tty, ldisc);
+ new_ldisc = tty_ldisc_get(tty, disc);
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
tty_lock(tty);
retval = tty_ldisc_lock(tty, 5 * HZ);
- if (retval) {
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return retval;
- }
-
- /*
- * Check the no-op case
- */
+ if (retval)
+ goto err;
- if (tty->ldisc->ops->num == ldisc) {
- tty_ldisc_unlock(tty);
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return 0;
+ if (!tty->ldisc) {
+ retval = -EIO;
+ goto out;
}
- old_ldisc = tty->ldisc;
+ /* Check the no-op case */
+ if (tty->ldisc->ops->num == disc)
+ goto out;
if (test_bit(TTY_HUPPED, &tty->flags)) {
- /* We were raced by the hangup method. It will have stomped
- the ldisc data and closed the ldisc down */
- tty_ldisc_unlock(tty);
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return -EIO;
+ /* We were raced by hangup */
+ retval = -EIO;
+ goto out;
}
+ old_ldisc = tty->ldisc;
+
/* Shutdown the old discipline. */
tty_ldisc_close(tty, old_ldisc);
/* Now set up the new line discipline. */
tty->ldisc = new_ldisc;
- tty_set_termios_ldisc(tty, ldisc);
+ tty_set_termios_ldisc(tty, disc);
retval = tty_ldisc_open(tty, new_ldisc);
if (retval < 0) {
@@ -582,23 +590,39 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
the old ldisc (if it was restored as part of error cleanup
above). In either case, releasing a single reference from
the old ldisc is correct. */
-
- tty_ldisc_put(old_ldisc);
-
- /*
- * Allow ldisc referencing to occur again
- */
+ new_ldisc = old_ldisc;
+out:
tty_ldisc_unlock(tty);
/* Restart the work queue in case no characters kick it off. Safe if
already running */
tty_buffer_restart_work(tty->port);
-
+err:
+ tty_ldisc_put(new_ldisc); /* drop the extra reference */
tty_unlock(tty);
return retval;
}
/**
+ * tty_ldisc_kill - teardown ldisc
+ * @tty: tty being released
+ *
+ * Perform final close of the ldisc and reset tty->ldisc
+ */
+static void tty_ldisc_kill(struct tty_struct *tty)
+{
+ if (!tty->ldisc)
+ return;
+ /*
+ * Now kill off the ldisc
+ */
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
+}
+
+/**
* tty_reset_termios - reset terminal state
* @tty: tty to reset
*
@@ -618,28 +642,44 @@ static void tty_reset_termios(struct tty_struct *tty)
/**
* tty_ldisc_reinit - reinitialise the tty ldisc
* @tty: tty to reinit
- * @ldisc: line discipline to reinitialize
+ * @disc: line discipline to reinitialize
+ *
+ * Completely reinitialize the line discipline state, by closing the
+ * current instance, if there is one, and opening a new instance. If
+ * an error occurs opening the new non-N_TTY instance, the instance
+ * is dropped and tty->ldisc reset to NULL. The caller can then retry
+ * with N_TTY instead.
*
- * Switch the tty to a line discipline and leave the ldisc
- * state closed
+ * Returns 0 if successful, otherwise error code < 0
*/
-static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+int tty_ldisc_reinit(struct tty_struct *tty, int disc)
{
- struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
+ struct tty_ldisc *ld;
+ int retval;
- if (IS_ERR(ld))
- return -1;
+ ld = tty_ldisc_get(tty, disc);
+ if (IS_ERR(ld)) {
+ BUG_ON(disc == N_TTY);
+ return PTR_ERR(ld);
+ }
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /*
- * Switch the line discipline back
- */
- tty->ldisc = ld;
- tty_set_termios_ldisc(tty, ldisc);
+ if (tty->ldisc) {
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ }
- return 0;
+ /* switch the line discipline */
+ tty->ldisc = ld;
+ tty_set_termios_ldisc(tty, disc);
+ retval = tty_ldisc_open(tty, tty->ldisc);
+ if (retval) {
+ if (!WARN_ON(disc == N_TTY)) {
+ tty_ldisc_put(tty->ldisc);
+ tty->ldisc = NULL;
+ }
+ }
+ return retval;
}
/**
@@ -657,13 +697,11 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
* tty itself so we must be careful about locking rules.
*/
-void tty_ldisc_hangup(struct tty_struct *tty)
+void tty_ldisc_hangup(struct tty_struct *tty, bool reinit)
{
struct tty_ldisc *ld;
- int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
- int err = 0;
- tty_ldisc_debug(tty, "%p: closing\n", tty->ldisc);
+ tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc);
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
@@ -689,31 +727,17 @@ void tty_ldisc_hangup(struct tty_struct *tty)
*/
tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
- if (tty->ldisc) {
-
- /* At this point we have a halted ldisc; we want to close it and
- reopen a new ldisc. We could defer the reopen to the next
- open but it means auditing a lot of other paths so this is
- a FIXME */
- if (reset == 0) {
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ tty_reset_termios(tty);
- if (!tty_ldisc_reinit(tty, tty->termios.c_line))
- err = tty_ldisc_open(tty, tty->ldisc);
- else
- err = 1;
- }
- /* If the re-open fails or we reset then go to N_TTY. The
- N_TTY open cannot fail */
- if (reset || err) {
- BUG_ON(tty_ldisc_reinit(tty, N_TTY));
- WARN_ON(tty_ldisc_open(tty, tty->ldisc));
- }
+ if (tty->ldisc) {
+ if (reinit) {
+ if (tty_ldisc_reinit(tty, tty->termios.c_line) < 0)
+ tty_ldisc_reinit(tty, N_TTY);
+ } else
+ tty_ldisc_kill(tty);
}
tty_ldisc_unlock(tty);
- if (reset)
- tty_reset_termios(tty);
-
- tty_ldisc_debug(tty, "%p: re-opened\n", tty->ldisc);
}
/**
@@ -728,44 +752,26 @@ void tty_ldisc_hangup(struct tty_struct *tty)
int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
{
- struct tty_ldisc *ld = tty->ldisc;
- int retval;
-
- retval = tty_ldisc_open(tty, ld);
+ int retval = tty_ldisc_open(tty, tty->ldisc);
if (retval)
return retval;
if (o_tty) {
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
if (retval) {
- tty_ldisc_close(tty, ld);
+ tty_ldisc_close(tty, tty->ldisc);
return retval;
}
}
return 0;
}
-static void tty_ldisc_kill(struct tty_struct *tty)
-{
- /*
- * Now kill off the ldisc
- */
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /* Force an oops if we mess this up */
- tty->ldisc = NULL;
-
- /* Ensure the next open requests the N_TTY ldisc */
- tty_set_termios_ldisc(tty, N_TTY);
-}
-
/**
* tty_ldisc_release - release line discipline
* @tty: tty being shut down (or one end of pty pair)
*
* Called during the final close of a tty or a pty pair in order to shut
- * down the line discpline layer. On exit, each ldisc assigned is N_TTY and
- * each ldisc has not been opened.
+ * down the line discpline layer. On exit, each tty's ldisc is NULL.
*/
void tty_ldisc_release(struct tty_struct *tty)
@@ -806,7 +812,7 @@ void tty_ldisc_init(struct tty_struct *tty)
}
/**
- * tty_ldisc_init - ldisc cleanup for new tty
+ * tty_ldisc_deinit - ldisc cleanup for new tty
* @tty: tty that was allocated recently
*
* The tty structure must not becompletely set up (tty_ldisc_setup) when
@@ -814,12 +820,7 @@ void tty_ldisc_init(struct tty_struct *tty)
*/
void tty_ldisc_deinit(struct tty_struct *tty)
{
- tty_ldisc_put(tty->ldisc);
+ if (tty->ldisc)
+ tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;
}
-
-void tty_ldisc_begin(void)
-{
- /* Setup the default TTY line discipline. */
- (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-}
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
index ad7eba5ca380..1bf8ed13f827 100644
--- a/drivers/tty/tty_ldsem.c
+++ b/drivers/tty/tty_ldsem.c
@@ -319,7 +319,7 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
-static inline int __ldsem_down_read_nested(struct ld_semaphore *sem,
+static int __ldsem_down_read_nested(struct ld_semaphore *sem,
int subclass, long timeout)
{
long count;
@@ -338,7 +338,7 @@ static inline int __ldsem_down_read_nested(struct ld_semaphore *sem,
return 1;
}
-static inline int __ldsem_down_write_nested(struct ld_semaphore *sem,
+static int __ldsem_down_write_nested(struct ld_semaphore *sem,
int subclass, long timeout)
{
long count;
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 0efcf713b756..d8bae67a6174 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -10,37 +10,44 @@
* Getting the big tty mutex.
*/
-void __lockfunc tty_lock(struct tty_struct *tty)
+void tty_lock(struct tty_struct *tty)
{
- if (tty->magic != TTY_MAGIC) {
- pr_err("L Bad %p\n", tty);
- WARN_ON(1);
+ if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
return;
- }
tty_kref_get(tty);
mutex_lock(&tty->legacy_mutex);
}
EXPORT_SYMBOL(tty_lock);
-void __lockfunc tty_unlock(struct tty_struct *tty)
+int tty_lock_interruptible(struct tty_struct *tty)
{
- if (tty->magic != TTY_MAGIC) {
- pr_err("U Bad %p\n", tty);
- WARN_ON(1);
+ int ret;
+
+ if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
+ return -EIO;
+ tty_kref_get(tty);
+ ret = mutex_lock_interruptible(&tty->legacy_mutex);
+ if (ret)
+ tty_kref_put(tty);
+ return ret;
+}
+
+void tty_unlock(struct tty_struct *tty)
+{
+ if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty))
return;
- }
mutex_unlock(&tty->legacy_mutex);
tty_kref_put(tty);
}
EXPORT_SYMBOL(tty_unlock);
-void __lockfunc tty_lock_slave(struct tty_struct *tty)
+void tty_lock_slave(struct tty_struct *tty)
{
if (tty && tty != tty->link)
tty_lock(tty);
}
-void __lockfunc tty_unlock_slave(struct tty_struct *tty)
+void tty_unlock_slave(struct tty_struct *tty)
{
if (tty && tty != tty->link)
tty_unlock(tty);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 482f33f20043..dbcca30a54b1 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -370,7 +370,7 @@ int tty_port_block_til_ready(struct tty_port *port,
}
if (filp->f_flags & O_NONBLOCK) {
/* Indicate we are open */
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty))
tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
@@ -462,14 +462,13 @@ int tty_port_close_start(struct tty_port *port,
spin_lock_irqsave(&port->lock, flags);
if (tty->count == 1 && port->count != 1) {
- printk(KERN_WARNING
- "tty_port_close_start: tty->count = 1 port count = %d.\n",
- port->count);
+ tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
+ port->count);
port->count = 1;
}
if (--port->count < 0) {
- printk(KERN_WARNING "tty_port_close_start: count = %d\n",
- port->count);
+ tty_warn(tty, "%s: bad port count (%d)\n", __func__,
+ port->count);
port->count = 0;
}
@@ -477,7 +476,6 @@ int tty_port_close_start(struct tty_port *port,
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
- set_bit(ASYNCB_CLOSING, &port->flags);
spin_unlock_irqrestore(&port->lock, flags);
tty->closing = 1;
@@ -511,14 +509,12 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags);
- if (port->close_delay) {
- msleep_interruptible(
- jiffies_to_msecs(port->close_delay));
- }
+ if (port->close_delay)
+ msleep_interruptible(jiffies_to_msecs(port->close_delay));
spin_lock_irqsave(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
}
- port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ port->flags &= ~ASYNC_NORMAL_ACTIVE;
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_close_end);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 6f0336fff501..f973bfce5d08 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1706,16 +1706,12 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL;
if (ct) {
- dia = kmalloc(sizeof(struct kbdiacr) * ct,
- GFP_KERNEL);
- if (!dia)
- return -ENOMEM;
- if (copy_from_user(dia, a->kbdiacr,
- sizeof(struct kbdiacr) * ct)) {
- kfree(dia);
- return -EFAULT;
- }
+ dia = memdup_user(a->kbdiacr,
+ sizeof(struct kbdiacr) * ct);
+ if (IS_ERR(dia))
+ return PTR_ERR(dia);
+
}
spin_lock_irqsave(&kbd_event_lock, flags);
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 381a2b13682c..4dd9dd2270a0 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -347,6 +347,8 @@ int paste_selection(struct tty_struct *tty)
console_unlock();
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO; /* ldisc was hung up */
tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 4462d167900c..3e3c7575e92d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -568,7 +568,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
vc->vc_cols - vc->vc_x);
}
-static int softcursor_original;
+static int softcursor_original = -1;
static void add_softcursor(struct vc_data *vc)
{
@@ -634,7 +634,7 @@ static void set_origin(struct vc_data *vc)
vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
}
-static inline void save_screen(struct vc_data *vc)
+static void save_screen(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
@@ -4250,6 +4250,7 @@ unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
{
return screenpos(vc, 2 * w_offset, viewed);
}
+EXPORT_SYMBOL_GPL(screen_pos);
void getconsxy(struct vc_data *vc, unsigned char *p)
{
OpenPOWER on IntegriCloud