summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2013-01-29 13:48:30 +0400
committerJiri Kosina <jkosina@suse.cz>2013-01-29 13:48:30 +0400
commit617677295b53a40d0e54aac4cbbc216ffbc755dd (patch)
tree51b9e87213243ed5efff252c8e8d8fec4eebc588 /drivers/tty
parent5c8d1b68e01a144813e38795fe6dbe7ebb506131 (diff)
parent6abb7c25775b7fb2225ad0508236d63ca710e65f (diff)
downloadlinux-617677295b53a40d0e54aac4cbbc216ffbc755dd.tar.xz
Merge branch 'master' into for-next
Conflicts: drivers/devfreq/exynos4_bus.c Sync with Linus' tree to be able to apply patches that are against newer code (mvneta).
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Kconfig1
-rw-r--r--drivers/tty/amiserial.c2
-rw-r--r--drivers/tty/bfin_jtag_comm.c6
-rw-r--r--drivers/tty/cyclades.c28
-rw-r--r--drivers/tty/ehv_bytechan.c4
-rw-r--r--drivers/tty/hvc/hvc_console.c7
-rw-r--r--drivers/tty/hvc/hvc_opal.c8
-rw-r--r--drivers/tty/hvc/hvc_vio.c6
-rw-r--r--drivers/tty/hvc/hvc_xen.c2
-rw-r--r--drivers/tty/hvc/hvcs.c20
-rw-r--r--drivers/tty/hvc/hvsi.c1
-rw-r--r--drivers/tty/ipwireless/network.c5
-rw-r--r--drivers/tty/ipwireless/tty.c1
-rw-r--r--drivers/tty/isicom.c35
-rw-r--r--drivers/tty/moxa.c12
-rw-r--r--drivers/tty/mxser.c35
-rw-r--r--drivers/tty/n_gsm.c11
-rw-r--r--drivers/tty/n_tty.c752
-rw-r--r--drivers/tty/nozomi.c23
-rw-r--r--drivers/tty/pty.c83
-rw-r--r--drivers/tty/rocket.c4
-rw-r--r--drivers/tty/serial/68328serial.c2
-rw-r--r--drivers/tty/serial/8250/8250.c109
-rw-r--r--drivers/tty/serial/8250/8250.h37
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c6
-rw-r--r--drivers/tty/serial/8250/8250_dw.c33
-rw-r--r--drivers/tty/serial/8250/8250_early.c46
-rw-r--r--drivers/tty/serial/8250/8250_em.c8
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c10
-rw-r--r--drivers/tty/serial/8250/8250_pci.c390
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c14
-rw-r--r--drivers/tty/serial/Kconfig48
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/altera_jtaguart.c6
-rw-r--r--drivers/tty/serial/altera_uart.c6
-rw-r--r--drivers/tty/serial/amba-pl011.c25
-rw-r--r--drivers/tty/serial/apbuart.c2
-rw-r--r--drivers/tty/serial/ar933x_uart.c96
-rw-r--r--drivers/tty/serial/arc_uart.c746
-rw-r--r--drivers/tty/serial/atmel_serial.c39
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c6
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c6
-rw-r--r--drivers/tty/serial/bfin_uart.c20
-rw-r--r--drivers/tty/serial/clps711x.c595
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c4
-rw-r--r--drivers/tty/serial/efm32-uart.c6
-rw-r--r--drivers/tty/serial/icom.c14
-rw-r--r--drivers/tty/serial/ifx6x60.c172
-rw-r--r--drivers/tty/serial/ifx6x60.h2
-rw-r--r--drivers/tty/serial/ioc3_serial.c2
-rw-r--r--drivers/tty/serial/jsm/jsm.h8
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c9
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c116
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c104
-rw-r--r--drivers/tty/serial/kgdb_nmi.c2
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c6
-rw-r--r--drivers/tty/serial/max3100.c6
-rw-r--r--drivers/tty/serial/max310x.c12
-rw-r--r--drivers/tty/serial/mcf.c6
-rw-r--r--drivers/tty/serial/mfd.c7
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c2
-rw-r--r--drivers/tty/serial/mrst_max3110.c6
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/msm_serial_hs.c8
-rw-r--r--drivers/tty/serial/mux.c6
-rw-r--r--drivers/tty/serial/mxs-auart.c380
-rw-r--r--drivers/tty/serial/of_serial.c38
-rw-r--r--drivers/tty/serial/omap-serial.c260
-rw-r--r--drivers/tty/serial/pch_uart.c4
-rw-r--r--drivers/tty/serial/pxa.c55
-rw-r--r--drivers/tty/serial/sa1100.c4
-rw-r--r--drivers/tty/serial/samsung.c50
-rw-r--r--drivers/tty/serial/sc26xx.c6
-rw-r--r--drivers/tty/serial/sccnxp.c6
-rw-r--r--drivers/tty/serial/serial_core.c257
-rw-r--r--drivers/tty/serial/serial_txx9.c16
-rw-r--r--drivers/tty/serial/sh-sci.c154
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c4
-rw-r--r--drivers/tty/serial/sunhv.c6
-rw-r--r--drivers/tty/serial/sunsab.c8
-rw-r--r--drivers/tty/serial/sunsu.c10
-rw-r--r--drivers/tty/serial/sunzilog.c14
-rw-r--r--drivers/tty/serial/timbuart.c6
-rw-r--r--drivers/tty/serial/uartlite.c14
-rw-r--r--drivers/tty/serial/vr41xx_siu.c8
-rw-r--r--drivers/tty/serial/vt8500_serial.c16
-rw-r--r--drivers/tty/serial/xilinx_uartps.c15
-rw-r--r--drivers/tty/synclink.c7
-rw-r--r--drivers/tty/synclink_gt.c11
-rw-r--r--drivers/tty/synclinkmp.c11
-rw-r--r--drivers/tty/sysrq.c3
-rw-r--r--drivers/tty/tty_audit.c15
-rw-r--r--drivers/tty/tty_buffer.c228
-rw-r--r--drivers/tty/tty_io.c24
-rw-r--r--drivers/tty/tty_ioctl.c21
-rw-r--r--drivers/tty/tty_ldisc.c47
-rw-r--r--drivers/tty/tty_mutex.c4
-rw-r--r--drivers/tty/tty_port.c18
-rw-r--r--drivers/tty/vt/consolemap.c6
-rw-r--r--drivers/tty/vt/selection.c9
-rw-r--r--drivers/tty/vt/vt.c13
-rw-r--r--drivers/tty/vt/vt_ioctl.c1
102 files changed, 3890 insertions, 1656 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index d8e05eeab232..0ecf22b6a38e 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -357,6 +357,7 @@ config TRACE_SINK
config PPC_EPAPR_HV_BYTECHAN
tristate "ePAPR hypervisor byte channel driver"
depends on PPC
+ select EPAPR_PARAVIRT
help
This driver creates /dev entries for each ePAPR hypervisor byte
channel, thereby allowing applications to communicate with byte
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 42d0a2581a87..9d7d00cdfecb 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1771,6 +1771,7 @@ fail_free_irq:
fail_unregister:
tty_unregister_driver(serial_driver);
fail_put_tty_driver:
+ tty_port_destroy(&state->tport);
put_tty_driver(serial_driver);
return error;
}
@@ -1785,6 +1786,7 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
printk("SERIAL: failed to unregister serial driver (%d)\n",
error);
put_tty_driver(serial_driver);
+ tty_port_destroy(&state->tport);
free_irq(IRQ_AMIGA_TBE, state);
free_irq(IRQ_AMIGA_RBF, state);
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 02b7d3a09696..1cfcdbf1d0cc 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -240,8 +240,6 @@ static int __init bfin_jc_init(void)
{
int ret;
- tty_port_init(&port);
-
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
@@ -257,6 +255,8 @@ static int __init bfin_jc_init(void)
if (!bfin_jc_driver)
goto err_driver;
+ tty_port_init(&port);
+
bfin_jc_driver->driver_name = DRV_NAME;
bfin_jc_driver->name = DEV_NAME;
bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL;
@@ -274,6 +274,7 @@ static int __init bfin_jc_init(void)
return 0;
err:
+ tty_port_destroy(&port);
put_tty_driver(bfin_jc_driver);
err_driver:
kfree(bfin_jc_write_buf.buf);
@@ -289,6 +290,7 @@ static void __exit bfin_jc_exit(void)
kfree(bfin_jc_write_buf.buf);
tty_unregister_driver(bfin_jc_driver);
put_tty_driver(bfin_jc_driver);
+ tty_port_destroy(&port);
}
module_exit(bfin_jc_exit);
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index 0a6a0bc1b598..b09c8d1f9a66 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -3099,7 +3099,7 @@ static const struct tty_port_operations cyz_port_ops = {
* ---------------------------------------------------------------------
*/
-static int __devinit cy_init_card(struct cyclades_card *cinfo)
+static int cy_init_card(struct cyclades_card *cinfo)
{
struct cyclades_port *info;
unsigned int channel, port;
@@ -3196,7 +3196,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
-static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
+static unsigned short cyy_init_card(void __iomem *true_base_addr,
int index)
{
unsigned int chip_number;
@@ -3405,7 +3405,7 @@ static int __init cy_detect_isa(void)
} /* cy_detect_isa */
#ifdef CONFIG_PCI
-static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
+static inline int cyc_isfwstr(const char *str, unsigned int size)
{
unsigned int a;
@@ -3420,7 +3420,7 @@ static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
return 0;
}
-static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
+static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
unsigned int size)
{
for (; size > 0; size--) {
@@ -3429,7 +3429,7 @@ static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
}
}
-static void __devinit plx_init(struct pci_dev *pdev, int irq,
+static void plx_init(struct pci_dev *pdev, int irq,
struct RUNTIME_9060 __iomem *addr)
{
/* Reset PLX */
@@ -3449,7 +3449,7 @@ static void __devinit plx_init(struct pci_dev *pdev, int irq,
pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
}
-static int __devinit __cyz_load_fw(const struct firmware *fw,
+static int __cyz_load_fw(const struct firmware *fw,
const char *name, const u32 mailbox, void __iomem *base,
void __iomem *fpga)
{
@@ -3526,7 +3526,7 @@ static int __devinit __cyz_load_fw(const struct firmware *fw,
return 0;
}
-static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
+static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
struct RUNTIME_9060 __iomem *ctl_addr, int irq)
{
const struct firmware *fw;
@@ -3692,7 +3692,7 @@ err:
return retval;
}
-static int __devinit cy_pci_probe(struct pci_dev *pdev,
+static int cy_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct cyclades_card *card;
@@ -3931,10 +3931,10 @@ err:
return retval;
}
-static void __devexit cy_pci_remove(struct pci_dev *pdev)
+static void cy_pci_remove(struct pci_dev *pdev)
{
struct cyclades_card *cinfo = pci_get_drvdata(pdev);
- unsigned int i;
+ unsigned int i, channel;
/* non-Z with old PLX */
if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
@@ -3960,9 +3960,11 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
cinfo->base_addr = NULL;
- for (i = cinfo->first_line; i < cinfo->first_line +
- cinfo->nports; i++)
+ for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
+ cinfo->nports; i++, channel++) {
tty_unregister_device(cy_serial_driver, i);
+ tty_port_destroy(&cinfo->ports[channel].port);
+ }
cinfo->nports = 0;
kfree(cinfo->ports);
}
@@ -3971,7 +3973,7 @@ static struct pci_driver cy_pci_driver = {
.name = "cyclades",
.id_table = cy_pci_dev_id,
.probe = cy_pci_probe,
- .remove = __devexit_p(cy_pci_remove)
+ .remove = cy_pci_remove
};
#endif
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 4ab936b7aac6..c117d775a22f 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -699,7 +699,7 @@ static const struct tty_port_operations ehv_bc_tty_port_ops = {
.shutdown = ehv_bc_tty_port_shutdown,
};
-static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
+static int ehv_bc_tty_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct ehv_bc_data *bc;
@@ -757,6 +757,7 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
return 0;
error:
+ tty_port_destroy(&bc->port);
irq_dispose_mapping(bc->tx_irq);
irq_dispose_mapping(bc->rx_irq);
@@ -770,6 +771,7 @@ static int ehv_bc_tty_remove(struct platform_device *pdev)
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);
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index a5dec1ca1b82..13ee53bd0bf6 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -424,7 +424,6 @@ static void hvc_hangup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
- int temp_open_count;
if (!hp)
return;
@@ -444,7 +443,6 @@ static void hvc_hangup(struct tty_struct *tty)
return;
}
- temp_open_count = hp->port.count;
hp->port.count = 0;
spin_unlock_irqrestore(&hp->port.lock, flags);
tty_port_tty_set(&hp->port, NULL);
@@ -453,11 +451,6 @@ static void hvc_hangup(struct tty_struct *tty)
if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data);
-
- while(temp_open_count) {
- --temp_open_count;
- tty_port_put(&hp->port);
- }
}
/*
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index a4f488fa9579..cd69b48f6dfd 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -41,7 +41,7 @@
static const char hvc_opal_name[] = "hvc_opal";
-static struct of_device_id hvc_opal_match[] __devinitdata = {
+static struct of_device_id hvc_opal_match[] = {
{ .name = "serial", .compatible = "ibm,opal-console-raw" },
{ .name = "serial", .compatible = "ibm,opal-console-hvsi" },
{ },
@@ -161,7 +161,7 @@ static const struct hv_ops hvc_opal_hvsi_ops = {
.tiocmset = hvc_opal_hvsi_tiocmset,
};
-static int __devinit hvc_opal_probe(struct platform_device *dev)
+static int hvc_opal_probe(struct platform_device *dev)
{
const struct hv_ops *ops;
struct hvc_struct *hp;
@@ -222,7 +222,7 @@ static int __devinit hvc_opal_probe(struct platform_device *dev)
return 0;
}
-static int __devexit hvc_opal_remove(struct platform_device *dev)
+static int hvc_opal_remove(struct platform_device *dev)
{
struct hvc_struct *hp = dev_get_drvdata(&dev->dev);
int rc, termno;
@@ -239,7 +239,7 @@ static int __devexit hvc_opal_remove(struct platform_device *dev)
static struct platform_driver hvc_opal_driver = {
.probe = hvc_opal_probe,
- .remove = __devexit_p(hvc_opal_remove),
+ .remove = hvc_opal_remove,
.driver = {
.name = hvc_opal_name,
.owner = THIS_MODULE,
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 1a5894c6dfa4..0c629807610e 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -53,7 +53,7 @@
static const char hvc_driver_name[] = "hvc_console";
-static struct vio_device_id hvc_driver_table[] __devinitdata = {
+static struct vio_device_id hvc_driver_table[] = {
{"serial", "hvterm1"},
#ifndef HVC_OLD_HVSI
{"serial", "hvterm-protocol"},
@@ -293,7 +293,7 @@ static int udbg_hvc_getc(void)
}
}
-static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+static int hvc_vio_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
const struct hv_ops *ops;
@@ -362,7 +362,7 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev,
return 0;
}
-static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+static int hvc_vio_remove(struct vio_dev *vdev)
{
struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
int rc, termno;
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index f4abfe238f98..19843ec3f80a 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -422,7 +422,7 @@ static int xencons_connect_backend(struct xenbus_device *dev,
return ret;
}
-static int __devinit xencons_probe(struct xenbus_device *dev,
+static int xencons_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
int ret, devid;
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index cab5c7adf8e8..877635733952 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -330,12 +330,12 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp);
static void hvcs_close(struct tty_struct *tty, struct file *filp);
static void hvcs_hangup(struct tty_struct * tty);
-static int __devinit hvcs_probe(struct vio_dev *dev,
+static int hvcs_probe(struct vio_dev *dev,
const struct vio_device_id *id);
-static int __devexit hvcs_remove(struct vio_dev *dev);
+static int hvcs_remove(struct vio_dev *dev);
static int __init hvcs_module_init(void);
static void __exit hvcs_module_exit(void);
-static int __devinit hvcs_initialize(void);
+static int hvcs_initialize(void);
#define HVCS_SCHED_READ 0x00000001
#define HVCS_QUICK_READ 0x00000002
@@ -676,7 +676,7 @@ static int khvcsd(void *unused)
return 0;
}
-static struct vio_device_id hvcs_driver_table[] __devinitdata= {
+static struct vio_device_id hvcs_driver_table[] = {
{"serial-server", "hvterm2"},
{ "", "" }
};
@@ -756,7 +756,7 @@ static int hvcs_get_index(void)
return -1;
}
-static int __devinit hvcs_probe(
+static int hvcs_probe(
struct vio_dev *dev,
const struct vio_device_id *id)
{
@@ -835,7 +835,7 @@ static int __devinit hvcs_probe(
return 0;
}
-static int __devexit hvcs_remove(struct vio_dev *dev)
+static int hvcs_remove(struct vio_dev *dev)
{
struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
unsigned long flags;
@@ -874,7 +874,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
static struct vio_driver hvcs_vio_driver = {
.id_table = hvcs_driver_table,
.probe = hvcs_probe,
- .remove = __devexit_p(hvcs_remove),
+ .remove = hvcs_remove,
.name = hvcs_driver_name,
};
@@ -1478,7 +1478,7 @@ static void hvcs_free_index_list(void)
hvcs_index_count = 0;
}
-static int __devinit hvcs_initialize(void)
+static int hvcs_initialize(void)
{
int rc, num_ttys_to_alloc;
@@ -1496,8 +1496,10 @@ static int __devinit hvcs_initialize(void)
num_ttys_to_alloc = hvcs_parm_num_devs;
hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
- if (!hvcs_tty_driver)
+ if (!hvcs_tty_driver) {
+ mutex_unlock(&hvcs_init_mutex);
return -ENOMEM;
+ }
if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
rc = -ENOMEM;
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index 5b95b4f28cf3..68357a6e4de9 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1218,6 +1218,7 @@ static int __init hvsi_console_init(void)
if (hp->virq == 0) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
__func__, irq[0]);
+ tty_port_destroy(&hp->port);
continue;
}
diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c
index 57102e66165a..c0dfb642383b 100644
--- a/drivers/tty/ipwireless/network.c
+++ b/drivers/tty/ipwireless/network.c
@@ -352,6 +352,8 @@ static struct sk_buff *ipw_packet_received_skb(unsigned char *data,
}
skb = dev_alloc_skb(length + 4);
+ if (skb == NULL)
+ return NULL;
skb_reserve(skb, 2);
memcpy(skb_put(skb, length), data, length);
@@ -397,7 +399,8 @@ void ipwireless_network_packet_received(struct ipw_network *network,
/* Send the data to the ppp_generic module. */
skb = ipw_packet_received_skb(data, length);
- ppp_input(network->ppp_channel, skb);
+ if (skb)
+ ppp_input(network->ppp_channel, skb);
} else
spin_unlock_irqrestore(&network->lock,
flags);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 160f0ad9589d..2cde13ddf9fc 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -566,6 +566,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
tty_unregister_device(ipw_tty_driver, j);
+ tty_port_destroy(&ttyj->port);
ttys[j] = NULL;
mutex_unlock(&ttyj->ipw_tty_mutex);
kfree(ttyj);
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index d7492e183607..3205b2e9090b 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -148,7 +148,7 @@
#endif
static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
-static void __devexit isicom_remove(struct pci_dev *);
+static void isicom_remove(struct pci_dev *);
static struct pci_device_id isicom_pci_tbl[] = {
{ PCI_DEVICE(VENDOR_ID, 0x2028) },
@@ -168,7 +168,7 @@ static struct pci_driver isicom_driver = {
.name = "isicom",
.id_table = isicom_pci_tbl,
.probe = isicom_probe,
- .remove = __devexit_p(isicom_remove)
+ .remove = isicom_remove
};
static int prev_card = 3; /* start servicing isi_card[0] */
@@ -603,7 +603,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (header & ISI_CTS) {
- port->port.tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
/* start tx ing */
port->status |= (ISI_TXOK
| ISI_CTS);
@@ -1307,7 +1307,7 @@ static const struct tty_port_operations isicom_port_ops = {
.shutdown = isicom_shutdown,
};
-static int __devinit reset_card(struct pci_dev *pdev,
+static int reset_card(struct pci_dev *pdev,
const unsigned int card, unsigned int *signature)
{
struct isi_board *board = pci_get_drvdata(pdev);
@@ -1368,7 +1368,7 @@ end:
return retval;
}
-static int __devinit load_firmware(struct pci_dev *pdev,
+static int load_firmware(struct pci_dev *pdev,
const unsigned int index, const unsigned int signature)
{
struct isi_board *board = pci_get_drvdata(pdev);
@@ -1548,7 +1548,7 @@ end:
*/
static unsigned int card_count;
-static int __devinit isicom_probe(struct pci_dev *pdev,
+static int isicom_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
unsigned int uninitialized_var(signature), index;
@@ -1610,10 +1610,15 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
if (retval < 0)
goto errunri;
- for (index = 0; index < board->port_count; index++)
- tty_port_register_device(&board->ports[index].port,
- isicom_normal, board->index * 16 + index,
- &pdev->dev);
+ for (index = 0; index < board->port_count; index++) {
+ struct tty_port *tport = &board->ports[index].port;
+ tty_port_init(tport);
+ tport->ops = &isicom_port_ops;
+ tport->close_delay = 50 * HZ/100;
+ tport->closing_wait = 3000 * HZ/100;
+ tty_port_register_device(tport, isicom_normal,
+ board->index * 16 + index, &pdev->dev);
+ }
return 0;
@@ -1630,13 +1635,15 @@ err:
return retval;
}
-static void __devexit isicom_remove(struct pci_dev *pdev)
+static void isicom_remove(struct pci_dev *pdev)
{
struct isi_board *board = pci_get_drvdata(pdev);
unsigned int i;
- for (i = 0; i < board->port_count; i++)
+ for (i = 0; i < board->port_count; i++) {
tty_unregister_device(isicom_normal, board->index * 16 + i);
+ tty_port_destroy(&board->ports[i].port);
+ }
free_irq(board->irq, board);
pci_release_region(pdev, 3);
@@ -1655,13 +1662,9 @@ static int __init isicom_init(void)
isi_card[idx].ports = port;
spin_lock_init(&isi_card[idx].card_lock);
for (channel = 0; channel < 16; channel++, port++) {
- tty_port_init(&port->port);
- port->port.ops = &isicom_port_ops;
port->magic = ISICOM_MAGIC;
port->card = &isi_card[idx];
port->channel = channel;
- port->port.close_delay = 50 * HZ/100;
- port->port.closing_wait = 3000 * HZ/100;
port->status = 0;
/* . . . */
}
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 56e616b9109a..f9d28503bdec 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -895,6 +895,8 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
return 0;
err_free:
+ for (i = 0; i < MAX_PORTS_PER_BOARD; i++)
+ tty_port_destroy(&brd->ports[i].port);
kfree(brd->ports);
err:
return ret;
@@ -919,6 +921,8 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
tty_kref_put(tty);
}
}
+ for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
+ tty_port_destroy(&brd->ports[a].port);
while (1) {
opened = 0;
for (a = 0; a < brd->numPorts; a++)
@@ -941,7 +945,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
}
#ifdef CONFIG_PCI
-static int __devinit moxa_pci_probe(struct pci_dev *pdev,
+static int moxa_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct moxa_board_conf *board;
@@ -1016,7 +1020,7 @@ err:
return retval;
}
-static void __devexit moxa_pci_remove(struct pci_dev *pdev)
+static void moxa_pci_remove(struct pci_dev *pdev)
{
struct moxa_board_conf *brd = pci_get_drvdata(pdev);
@@ -1029,7 +1033,7 @@ static struct pci_driver moxa_pci_driver = {
.name = "moxa",
.id_table = moxa_pcibrds,
.probe = moxa_pci_probe,
- .remove = __devexit_p(moxa_pci_remove)
+ .remove = moxa_pci_remove
};
#endif /* CONFIG_PCI */
@@ -1370,7 +1374,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
p->DCDState = dcd;
spin_unlock_irqrestore(&p->port.lock, flags);
tty = tty_port_tty_get(&p->port);
- if (tty && C_CLOCAL(tty) && !dcd)
+ if (tty && !C_CLOCAL(tty) && !dcd)
tty_hangup(tty);
tty_kref_put(tty);
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index cfda47dabd28..40113868bec2 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -487,7 +487,7 @@ static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
}
#ifdef CONFIG_PCI
-static int __devinit CheckIsMoxaMust(unsigned long io)
+static int CheckIsMoxaMust(unsigned long io)
{
u8 oldmcr, hwid;
int i;
@@ -2369,7 +2369,7 @@ static void mxser_release_ISA_res(struct mxser_board *brd)
mxser_release_vector(brd);
}
-static int __devinit mxser_initbrd(struct mxser_board *brd,
+static int mxser_initbrd(struct mxser_board *brd,
struct pci_dev *pdev)
{
struct mxser_port *info;
@@ -2411,14 +2411,27 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
brd);
- if (retval)
+ if (retval) {
+ for (i = 0; i < brd->info->nports; i++)
+ tty_port_destroy(&brd->ports[i].port);
printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
"conflict with another device.\n",
brd->info->name, brd->irq);
+ }
return retval;
}
+static void mxser_board_remove(struct mxser_board *brd)
+{
+ unsigned int i;
+
+ for (i = 0; i < brd->info->nports; i++) {
+ tty_unregister_device(mxvar_sdriver, brd->idx + i);
+ tty_port_destroy(&brd->ports[i].port);
+ }
+}
+
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
{
int id, i, bits, ret;
@@ -2534,7 +2547,7 @@ err_irqconflict:
return -EIO;
}
-static int __devinit mxser_probe(struct pci_dev *pdev,
+static int mxser_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
#ifdef CONFIG_PCI
@@ -2645,14 +2658,12 @@ err:
#endif
}
-static void __devexit mxser_remove(struct pci_dev *pdev)
+static void mxser_remove(struct pci_dev *pdev)
{
#ifdef CONFIG_PCI
struct mxser_board *brd = pci_get_drvdata(pdev);
- unsigned int i;
- for (i = 0; i < brd->info->nports; i++)
- tty_unregister_device(mxvar_sdriver, brd->idx + i);
+ mxser_board_remove(brd);
free_irq(pdev->irq, brd);
pci_release_region(pdev, 2);
@@ -2666,7 +2677,7 @@ static struct pci_driver mxser_driver = {
.name = "mxser",
.id_table = mxser_pcibrds,
.probe = mxser_probe,
- .remove = __devexit_p(mxser_remove)
+ .remove = mxser_remove
};
static int __init mxser_module_init(void)
@@ -2748,15 +2759,13 @@ err_put:
static void __exit mxser_module_exit(void)
{
- unsigned int i, j;
+ unsigned int i;
pci_unregister_driver(&mxser_driver);
for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
if (mxser_boards[i].info != NULL)
- for (j = 0; j < mxser_boards[i].info->nports; j++)
- tty_unregister_device(mxvar_sdriver,
- mxser_boards[i].idx + j);
+ mxser_board_remove(&mxser_boards[i]);
tty_unregister_driver(mxvar_sdriver);
put_tty_driver(mxvar_sdriver);
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 1e8e8ce55959..dcc0430a49c8 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -134,7 +134,6 @@ struct gsm_dlci {
#define DLCI_OPENING 1 /* Sending SABM not seen UA */
#define DLCI_OPEN 2 /* SABM/UA complete */
#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */
- struct kref ref; /* freed from port or mux close */
struct mutex mutex;
/* Link layer */
@@ -1635,7 +1634,6 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
if (dlci == NULL)
return NULL;
spin_lock_init(&dlci->lock);
- kref_init(&dlci->ref);
mutex_init(&dlci->mutex);
dlci->fifo = &dlci->_fifo;
if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
@@ -1669,9 +1667,9 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
*
* Can sleep.
*/
-static void gsm_dlci_free(struct kref *ref)
+static void gsm_dlci_free(struct tty_port *port)
{
- struct gsm_dlci *dlci = container_of(ref, struct gsm_dlci, ref);
+ struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
del_timer_sync(&dlci->t1);
dlci->gsm->dlci[dlci->addr] = NULL;
@@ -1683,12 +1681,12 @@ static void gsm_dlci_free(struct kref *ref)
static inline void dlci_get(struct gsm_dlci *dlci)
{
- kref_get(&dlci->ref);
+ tty_port_get(&dlci->port);
}
static inline void dlci_put(struct gsm_dlci *dlci)
{
- kref_put(&dlci->ref, gsm_dlci_free);
+ tty_port_put(&dlci->port);
}
/**
@@ -2874,6 +2872,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff)
static const struct tty_port_operations gsm_port_ops = {
.carrier_raised = gsm_carrier_raised,
.dtr_rts = gsm_dtr_rts,
+ .destruct = gsm_dlci_free,
};
static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 8c0b7b42319c..19083efa2314 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -73,10 +73,42 @@
#define ECHO_OP_SET_CANON_COL 0x81
#define ECHO_OP_ERASE_TAB 0x82
+struct n_tty_data {
+ unsigned int column;
+ unsigned long overrun_time;
+ int num_overrun;
+
+ unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+ unsigned char echo_overrun:1;
+
+ DECLARE_BITMAP(process_char_map, 256);
+ DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
+
+ char *read_buf;
+ int read_head;
+ int read_tail;
+ int read_cnt;
+
+ unsigned char *echo_buf;
+ unsigned int echo_pos;
+ unsigned int echo_cnt;
+
+ int canon_data;
+ unsigned long canon_head;
+ unsigned int canon_column;
+
+ struct mutex atomic_read_lock;
+ struct mutex output_lock;
+ struct mutex echo_lock;
+ spinlock_t read_lock;
+};
+
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
unsigned char __user *ptr)
{
- tty_audit_add_data(tty, &x, 1);
+ struct n_tty_data *ldata = tty->disc_data;
+
+ tty_audit_add_data(tty, &x, 1, ldata->icanon);
return put_user(x, ptr);
}
@@ -92,17 +124,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
static void n_tty_set_room(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
int left;
int old_left;
- /* tty->read_cnt is not read locked ? */
+ /* ldata->read_cnt is not read locked ? */
if (I_PARMRK(tty)) {
/* Multiply read_cnt by 3, since each byte might take up to
* three times as many spaces when PARMRK is set (depending on
* its flags, e.g. parity error). */
- left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+ left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1;
} else
- left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+ left = N_TTY_BUF_SIZE - ldata->read_cnt - 1;
/*
* If we are doing input canonicalization, and there are no
@@ -111,44 +144,47 @@ static void n_tty_set_room(struct tty_struct *tty)
* characters will be beeped.
*/
if (left <= 0)
- left = tty->icanon && !tty->canon_data;
+ left = ldata->icanon && !ldata->canon_data;
old_left = tty->receive_room;
tty->receive_room = left;
/* Did this open up the receive buffer? We may need to flip */
- if (left && !old_left)
- schedule_work(&tty->buf.work);
+ if (left && !old_left) {
+ WARN_RATELIMIT(tty->port->itty == NULL,
+ "scheduling with invalid itty\n");
+ schedule_work(&tty->port->buf.work);
+ }
}
-static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
+static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata)
{
- if (tty->read_cnt < N_TTY_BUF_SIZE) {
- tty->read_buf[tty->read_head] = c;
- tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt++;
+ if (ldata->read_cnt < N_TTY_BUF_SIZE) {
+ ldata->read_buf[ldata->read_head] = c;
+ ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt++;
}
}
/**
* put_tty_queue - add character to tty
* @c: character
- * @tty: tty device
+ * @ldata: n_tty data
*
* Add a character to the tty read_buf queue. This is done under the
* read_lock to serialize character addition and also to protect us
* against parallel reads or flushes
*/
-static void put_tty_queue(unsigned char c, struct tty_struct *tty)
+static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
{
unsigned long flags;
/*
* The problem of stomping on the buffers ends here.
* Why didn't anyone see this one coming? --AJK
*/
- spin_lock_irqsave(&tty->read_lock, flags);
- put_tty_queue_nolock(c, tty);
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ put_tty_queue_nolock(c, ldata);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
}
/**
@@ -179,18 +215,19 @@ static void check_unthrottle(struct tty_struct *tty)
static void reset_buffer_flags(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_head = tty->read_tail = tty->read_cnt = 0;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
- mutex_lock(&tty->echo_lock);
- tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
- mutex_unlock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
+ ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
+ mutex_unlock(&ldata->echo_lock);
- tty->canon_head = tty->canon_data = tty->erasing = 0;
- memset(&tty->read_flags, 0, sizeof tty->read_flags);
+ ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
+ bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
n_tty_set_room(tty);
}
@@ -235,18 +272,19 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
ssize_t n = 0;
- spin_lock_irqsave(&tty->read_lock, flags);
- if (!tty->icanon) {
- n = tty->read_cnt;
- } else if (tty->canon_data) {
- n = (tty->canon_head > tty->read_tail) ?
- tty->canon_head - tty->read_tail :
- tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ if (!ldata->icanon) {
+ n = ldata->read_cnt;
+ } else if (ldata->canon_data) {
+ n = (ldata->canon_head > ldata->read_tail) ?
+ ldata->canon_head - ldata->read_tail :
+ ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
return n;
}
@@ -301,6 +339,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty)
static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
{
+ struct n_tty_data *ldata = tty->disc_data;
int spaces;
if (!space)
@@ -309,48 +348,48 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
switch (c) {
case '\n':
if (O_ONLRET(tty))
- tty->column = 0;
+ ldata->column = 0;
if (O_ONLCR(tty)) {
if (space < 2)
return -1;
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
tty->ops->write(tty, "\r\n", 2);
return 2;
}
- tty->canon_column = tty->column;
+ ldata->canon_column = ldata->column;
break;
case '\r':
- if (O_ONOCR(tty) && tty->column == 0)
+ if (O_ONOCR(tty) && ldata->column == 0)
return 0;
if (O_OCRNL(tty)) {
c = '\n';
if (O_ONLRET(tty))
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
break;
}
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
break;
case '\t':
- spaces = 8 - (tty->column & 7);
+ spaces = 8 - (ldata->column & 7);
if (O_TABDLY(tty) == XTABS) {
if (space < spaces)
return -1;
- tty->column += spaces;
+ ldata->column += spaces;
tty->ops->write(tty, " ", spaces);
return spaces;
}
- tty->column += spaces;
+ ldata->column += spaces;
break;
case '\b':
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
break;
default:
if (!iscntrl(c)) {
if (O_OLCUC(tty))
c = toupper(c);
if (!is_continuation(c, tty))
- tty->column++;
+ ldata->column++;
}
break;
}
@@ -375,14 +414,15 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
static int process_output(unsigned char c, struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
int space, retval;
- mutex_lock(&tty->output_lock);
+ mutex_lock(&ldata->output_lock);
space = tty_write_room(tty);
retval = do_output_char(c, tty, space);
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->output_lock);
if (retval < 0)
return -1;
else
@@ -411,15 +451,16 @@ static int process_output(unsigned char c, struct tty_struct *tty)
static ssize_t process_output_block(struct tty_struct *tty,
const unsigned char *buf, unsigned int nr)
{
+ struct n_tty_data *ldata = tty->disc_data;
int space;
int i;
const unsigned char *cp;
- mutex_lock(&tty->output_lock);
+ mutex_lock(&ldata->output_lock);
space = tty_write_room(tty);
if (!space) {
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->output_lock);
return 0;
}
if (nr > space)
@@ -431,30 +472,30 @@ static ssize_t process_output_block(struct tty_struct *tty,
switch (c) {
case '\n':
if (O_ONLRET(tty))
- tty->column = 0;
+ ldata->column = 0;
if (O_ONLCR(tty))
goto break_out;
- tty->canon_column = tty->column;
+ ldata->canon_column = ldata->column;
break;
case '\r':
- if (O_ONOCR(tty) && tty->column == 0)
+ if (O_ONOCR(tty) && ldata->column == 0)
goto break_out;
if (O_OCRNL(tty))
goto break_out;
- tty->canon_column = tty->column = 0;
+ ldata->canon_column = ldata->column = 0;
break;
case '\t':
goto break_out;
case '\b':
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
break;
default:
if (!iscntrl(c)) {
if (O_OLCUC(tty))
goto break_out;
if (!is_continuation(c, tty))
- tty->column++;
+ ldata->column++;
}
break;
}
@@ -462,7 +503,7 @@ static ssize_t process_output_block(struct tty_struct *tty,
break_out:
i = tty->ops->write(tty, buf, i);
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->output_lock);
return i;
}
@@ -494,21 +535,22 @@ break_out:
static void process_echoes(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
int space, nr;
unsigned char c;
unsigned char *cp, *buf_end;
- if (!tty->echo_cnt)
+ if (!ldata->echo_cnt)
return;
- mutex_lock(&tty->output_lock);
- mutex_lock(&tty->echo_lock);
+ mutex_lock(&ldata->output_lock);
+ mutex_lock(&ldata->echo_lock);
space = tty_write_room(tty);
- buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
- cp = tty->echo_buf + tty->echo_pos;
- nr = tty->echo_cnt;
+ buf_end = ldata->echo_buf + N_TTY_BUF_SIZE;
+ cp = ldata->echo_buf + ldata->echo_pos;
+ nr = ldata->echo_cnt;
while (nr > 0) {
c = *cp;
if (c == ECHO_OP_START) {
@@ -545,7 +587,7 @@ static void process_echoes(struct tty_struct *tty)
* Otherwise, tab spacing is normal.
*/
if (!(num_chars & 0x80))
- num_chars += tty->canon_column;
+ num_chars += ldata->canon_column;
num_bs = 8 - (num_chars & 7);
if (num_bs > space) {
@@ -555,22 +597,22 @@ static void process_echoes(struct tty_struct *tty)
space -= num_bs;
while (num_bs--) {
tty_put_char(tty, '\b');
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
}
cp += 3;
nr -= 3;
break;
case ECHO_OP_SET_CANON_COL:
- tty->canon_column = tty->column;
+ ldata->canon_column = ldata->column;
cp += 2;
nr -= 2;
break;
case ECHO_OP_MOVE_BACK_COL:
- if (tty->column > 0)
- tty->column--;
+ if (ldata->column > 0)
+ ldata->column--;
cp += 2;
nr -= 2;
break;
@@ -582,7 +624,7 @@ static void process_echoes(struct tty_struct *tty)
break;
}
tty_put_char(tty, ECHO_OP_START);
- tty->column++;
+ ldata->column++;
space--;
cp += 2;
nr -= 2;
@@ -604,7 +646,7 @@ static void process_echoes(struct tty_struct *tty)
}
tty_put_char(tty, '^');
tty_put_char(tty, op ^ 0100);
- tty->column += 2;
+ ldata->column += 2;
space -= 2;
cp += 2;
nr -= 2;
@@ -635,20 +677,20 @@ static void process_echoes(struct tty_struct *tty)
}
if (nr == 0) {
- tty->echo_pos = 0;
- tty->echo_cnt = 0;
- tty->echo_overrun = 0;
+ ldata->echo_pos = 0;
+ ldata->echo_cnt = 0;
+ ldata->echo_overrun = 0;
} else {
- int num_processed = tty->echo_cnt - nr;
- tty->echo_pos += num_processed;
- tty->echo_pos &= N_TTY_BUF_SIZE - 1;
- tty->echo_cnt = nr;
+ int num_processed = ldata->echo_cnt - nr;
+ ldata->echo_pos += num_processed;
+ ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
+ ldata->echo_cnt = nr;
if (num_processed > 0)
- tty->echo_overrun = 0;
+ ldata->echo_overrun = 0;
}
- mutex_unlock(&tty->echo_lock);
- mutex_unlock(&tty->output_lock);
+ mutex_unlock(&ldata->echo_lock);
+ mutex_unlock(&ldata->output_lock);
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
@@ -657,72 +699,70 @@ static void process_echoes(struct tty_struct *tty)
/**
* add_echo_byte - add a byte to the echo buffer
* @c: unicode byte to echo
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add a character or operation byte to the echo buffer.
*
* Should be called under the echo lock to protect the echo buffer.
*/
-static void add_echo_byte(unsigned char c, struct tty_struct *tty)
+static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
{
int new_byte_pos;
- if (tty->echo_cnt == N_TTY_BUF_SIZE) {
+ if (ldata->echo_cnt == N_TTY_BUF_SIZE) {
/* Circular buffer is already at capacity */
- new_byte_pos = tty->echo_pos;
+ new_byte_pos = ldata->echo_pos;
/*
* Since the buffer start position needs to be advanced,
* be sure to step by a whole operation byte group.
*/
- if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
- if (tty->echo_buf[(tty->echo_pos + 1) &
+ if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) {
+ if (ldata->echo_buf[(ldata->echo_pos + 1) &
(N_TTY_BUF_SIZE - 1)] ==
ECHO_OP_ERASE_TAB) {
- tty->echo_pos += 3;
- tty->echo_cnt -= 2;
+ ldata->echo_pos += 3;
+ ldata->echo_cnt -= 2;
} else {
- tty->echo_pos += 2;
- tty->echo_cnt -= 1;
+ ldata->echo_pos += 2;
+ ldata->echo_cnt -= 1;
}
} else {
- tty->echo_pos++;
+ ldata->echo_pos++;
}
- tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+ ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
- tty->echo_overrun = 1;
+ ldata->echo_overrun = 1;
} else {
- new_byte_pos = tty->echo_pos + tty->echo_cnt;
+ new_byte_pos = ldata->echo_pos + ldata->echo_cnt;
new_byte_pos &= N_TTY_BUF_SIZE - 1;
- tty->echo_cnt++;
+ ldata->echo_cnt++;
}
- tty->echo_buf[new_byte_pos] = c;
+ ldata->echo_buf[new_byte_pos] = c;
}
/**
* echo_move_back_col - add operation to move back a column
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add an operation to the echo buffer to move back one column.
*
* Locking: echo_lock to protect the echo buffer
*/
-static void echo_move_back_col(struct tty_struct *tty)
+static void echo_move_back_col(struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
-
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
-
- mutex_unlock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
+ mutex_unlock(&ldata->echo_lock);
}
/**
* echo_set_canon_col - add operation to set the canon column
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add an operation to the echo buffer to set the canon column
* to the current column.
@@ -730,21 +770,19 @@ static void echo_move_back_col(struct tty_struct *tty)
* Locking: echo_lock to protect the echo buffer
*/
-static void echo_set_canon_col(struct tty_struct *tty)
+static void echo_set_canon_col(struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
-
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
-
- mutex_unlock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
+ mutex_unlock(&ldata->echo_lock);
}
/**
* echo_erase_tab - add operation to erase a tab
* @num_chars: number of character columns already used
* @after_tab: true if num_chars starts after a previous tab
- * @tty: terminal device
+ * @ldata: n_tty data
*
* Add an operation to the echo buffer to erase a tab.
*
@@ -758,12 +796,12 @@ static void echo_set_canon_col(struct tty_struct *tty)
*/
static void echo_erase_tab(unsigned int num_chars, int after_tab,
- struct tty_struct *tty)
+ struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
+ mutex_lock(&ldata->echo_lock);
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_ERASE_TAB, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
/* We only need to know this modulo 8 (tab spacing) */
num_chars &= 7;
@@ -772,9 +810,9 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,
if (after_tab)
num_chars |= 0x80;
- add_echo_byte(num_chars, tty);
+ add_echo_byte(num_chars, ldata);
- mutex_unlock(&tty->echo_lock);
+ mutex_unlock(&ldata->echo_lock);
}
/**
@@ -790,18 +828,16 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,
* Locking: echo_lock to protect the echo buffer
*/
-static void echo_char_raw(unsigned char c, struct tty_struct *tty)
+static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
{
- mutex_lock(&tty->echo_lock);
-
+ mutex_lock(&ldata->echo_lock);
if (c == ECHO_OP_START) {
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_START, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_START, ldata);
} else {
- add_echo_byte(c, tty);
+ add_echo_byte(c, ldata);
}
-
- mutex_unlock(&tty->echo_lock);
+ mutex_unlock(&ldata->echo_lock);
}
/**
@@ -820,30 +856,32 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty)
static void echo_char(unsigned char c, struct tty_struct *tty)
{
- mutex_lock(&tty->echo_lock);
+ struct n_tty_data *ldata = tty->disc_data;
+
+ mutex_lock(&ldata->echo_lock);
if (c == ECHO_OP_START) {
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(ECHO_OP_START, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_START, ldata);
} else {
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
- add_echo_byte(ECHO_OP_START, tty);
- add_echo_byte(c, tty);
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(c, ldata);
}
- mutex_unlock(&tty->echo_lock);
+ mutex_unlock(&ldata->echo_lock);
}
/**
* finish_erasing - complete erase
- * @tty: tty doing the erase
+ * @ldata: n_tty data
*/
-static inline void finish_erasing(struct tty_struct *tty)
+static inline void finish_erasing(struct n_tty_data *ldata)
{
- if (tty->erasing) {
- echo_char_raw('/', tty);
- tty->erasing = 0;
+ if (ldata->erasing) {
+ echo_char_raw('/', ldata);
+ ldata->erasing = 0;
}
}
@@ -861,12 +899,13 @@ static inline void finish_erasing(struct tty_struct *tty)
static void eraser(unsigned char c, struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
enum { ERASE, WERASE, KILL } kill_type;
int head, seen_alnums, cnt;
unsigned long flags;
/* FIXME: locking needed ? */
- if (tty->read_head == tty->canon_head) {
+ if (ldata->read_head == ldata->canon_head) {
/* process_output('\a', tty); */ /* what do you think? */
return;
}
@@ -876,24 +915,24 @@ static void eraser(unsigned char c, struct tty_struct *tty)
kill_type = WERASE;
else {
if (!L_ECHO(tty)) {
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
(N_TTY_BUF_SIZE - 1));
- tty->read_head = tty->canon_head;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ ldata->read_head = ldata->canon_head;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
return;
}
if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
(N_TTY_BUF_SIZE - 1));
- tty->read_head = tty->canon_head;
- spin_unlock_irqrestore(&tty->read_lock, flags);
- finish_erasing(tty);
+ ldata->read_head = ldata->canon_head;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
+ finish_erasing(ldata);
echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on and ECHOKE is off. */
if (L_ECHOK(tty))
- echo_char_raw('\n', tty);
+ echo_char_raw('\n', ldata);
return;
}
kill_type = KILL;
@@ -901,14 +940,14 @@ static void eraser(unsigned char c, struct tty_struct *tty)
seen_alnums = 0;
/* FIXME: Locking ?? */
- while (tty->read_head != tty->canon_head) {
- head = tty->read_head;
+ while (ldata->read_head != ldata->canon_head) {
+ head = ldata->read_head;
/* erase a single possibly multibyte character */
do {
head = (head - 1) & (N_TTY_BUF_SIZE-1);
- c = tty->read_buf[head];
- } while (is_continuation(c, tty) && head != tty->canon_head);
+ c = ldata->read_buf[head];
+ } while (is_continuation(c, tty) && head != ldata->canon_head);
/* do not partially erase */
if (is_continuation(c, tty))
@@ -921,30 +960,31 @@ static void eraser(unsigned char c, struct tty_struct *tty)
else if (seen_alnums)
break;
}
- cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_head = head;
- tty->read_cnt -= cnt;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_head = head;
+ ldata->read_cnt -= cnt;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
- if (!tty->erasing) {
- echo_char_raw('\\', tty);
- tty->erasing = 1;
+ if (!ldata->erasing) {
+ echo_char_raw('\\', ldata);
+ ldata->erasing = 1;
}
/* if cnt > 1, output a multi-byte character */
echo_char(c, tty);
while (--cnt > 0) {
head = (head+1) & (N_TTY_BUF_SIZE-1);
- echo_char_raw(tty->read_buf[head], tty);
- echo_move_back_col(tty);
+ echo_char_raw(ldata->read_buf[head],
+ ldata);
+ echo_move_back_col(ldata);
}
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
} else if (c == '\t') {
unsigned int num_chars = 0;
int after_tab = 0;
- unsigned long tail = tty->read_head;
+ unsigned long tail = ldata->read_head;
/*
* Count the columns used for characters
@@ -953,9 +993,9 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* This info is used to go back the correct
* number of columns.
*/
- while (tail != tty->canon_head) {
+ while (tail != ldata->canon_head) {
tail = (tail-1) & (N_TTY_BUF_SIZE-1);
- c = tty->read_buf[tail];
+ c = ldata->read_buf[tail];
if (c == '\t') {
after_tab = 1;
break;
@@ -966,25 +1006,25 @@ static void eraser(unsigned char c, struct tty_struct *tty)
num_chars++;
}
}
- echo_erase_tab(num_chars, after_tab, tty);
+ echo_erase_tab(num_chars, after_tab, ldata);
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
- echo_char_raw('\b', tty);
- echo_char_raw(' ', tty);
- echo_char_raw('\b', tty);
+ echo_char_raw('\b', ldata);
+ echo_char_raw(' ', ldata);
+ echo_char_raw('\b', ldata);
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
- echo_char_raw('\b', tty);
- echo_char_raw(' ', tty);
- echo_char_raw('\b', tty);
+ echo_char_raw('\b', ldata);
+ echo_char_raw(' ', ldata);
+ echo_char_raw('\b', ldata);
}
}
}
if (kill_type == ERASE)
break;
}
- if (tty->read_head == tty->canon_head && L_ECHO(tty))
- finish_erasing(tty);
+ if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
+ finish_erasing(ldata);
}
/**
@@ -1023,6 +1063,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
static inline void n_tty_receive_break(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
if (I_IGNBRK(tty))
return;
if (I_BRKINT(tty)) {
@@ -1030,10 +1072,10 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
return;
}
if (I_PARMRK(tty)) {
- put_tty_queue('\377', tty);
- put_tty_queue('\0', tty);
+ put_tty_queue('\377', ldata);
+ put_tty_queue('\0', ldata);
}
- put_tty_queue('\0', tty);
+ put_tty_queue('\0', ldata);
wake_up_interruptible(&tty->read_wait);
}
@@ -1052,16 +1094,17 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
static inline void n_tty_receive_overrun(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
char buf[64];
- tty->num_overrun++;
- if (time_before(tty->overrun_time, jiffies - HZ) ||
- time_after(tty->overrun_time, jiffies)) {
+ 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, buf),
- tty->num_overrun);
- tty->overrun_time = jiffies;
- tty->num_overrun = 0;
+ ldata->num_overrun);
+ ldata->overrun_time = jiffies;
+ ldata->num_overrun = 0;
}
}
@@ -1076,16 +1119,18 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)
static inline void n_tty_receive_parity_error(struct tty_struct *tty,
unsigned char c)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
if (I_IGNPAR(tty))
return;
if (I_PARMRK(tty)) {
- put_tty_queue('\377', tty);
- put_tty_queue('\0', tty);
- put_tty_queue(c, tty);
+ put_tty_queue('\377', ldata);
+ put_tty_queue('\0', ldata);
+ put_tty_queue(c, ldata);
} else if (I_INPCK(tty))
- put_tty_queue('\0', tty);
+ put_tty_queue('\0', ldata);
else
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
wake_up_interruptible(&tty->read_wait);
}
@@ -1101,11 +1146,12 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
int parmrk;
- if (tty->raw) {
- put_tty_queue(c, tty);
+ if (ldata->raw) {
+ put_tty_queue(c, ldata);
return;
}
@@ -1115,7 +1161,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
c = tolower(c);
if (L_EXTPROC(tty)) {
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
return;
}
@@ -1143,26 +1189,26 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
* handle specially, do shortcut processing to speed things
* up.
*/
- if (!test_bit(c, tty->process_char_map) || tty->lnext) {
- tty->lnext = 0;
+ if (!test_bit(c, ldata->process_char_map) || ldata->lnext) {
+ ldata->lnext = 0;
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
- if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+ if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
/* beep if no space */
if (L_ECHO(tty))
process_output('\a', tty);
return;
}
if (L_ECHO(tty)) {
- finish_erasing(tty);
+ finish_erasing(ldata);
/* Record the column of first canon char. */
- if (tty->canon_head == tty->read_head)
- echo_set_canon_col(tty);
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
echo_char(c, tty);
process_echoes(tty);
}
if (parmrk)
- put_tty_queue(c, tty);
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
+ put_tty_queue(c, ldata);
return;
}
@@ -1218,7 +1264,7 @@ send_signal:
} else if (c == '\n' && I_INLCR(tty))
c = '\r';
- if (tty->icanon) {
+ if (ldata->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
@@ -1226,12 +1272,12 @@ send_signal:
return;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
- tty->lnext = 1;
+ ldata->lnext = 1;
if (L_ECHO(tty)) {
- finish_erasing(tty);
+ finish_erasing(ldata);
if (L_ECHOCTL(tty)) {
- echo_char_raw('^', tty);
- echo_char_raw('\b', tty);
+ echo_char_raw('^', ldata);
+ echo_char_raw('\b', ldata);
process_echoes(tty);
}
}
@@ -1239,34 +1285,34 @@ send_signal:
}
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
L_IEXTEN(tty)) {
- unsigned long tail = tty->canon_head;
+ unsigned long tail = ldata->canon_head;
- finish_erasing(tty);
+ finish_erasing(ldata);
echo_char(c, tty);
- echo_char_raw('\n', tty);
- while (tail != tty->read_head) {
- echo_char(tty->read_buf[tail], tty);
+ echo_char_raw('\n', ldata);
+ while (tail != ldata->read_head) {
+ echo_char(ldata->read_buf[tail], tty);
tail = (tail+1) & (N_TTY_BUF_SIZE-1);
}
process_echoes(tty);
return;
}
if (c == '\n') {
- if (tty->read_cnt >= N_TTY_BUF_SIZE) {
+ if (ldata->read_cnt >= N_TTY_BUF_SIZE) {
if (L_ECHO(tty))
process_output('\a', tty);
return;
}
if (L_ECHO(tty) || L_ECHONL(tty)) {
- echo_char_raw('\n', tty);
+ echo_char_raw('\n', ldata);
process_echoes(tty);
}
goto handle_newline;
}
if (c == EOF_CHAR(tty)) {
- if (tty->read_cnt >= N_TTY_BUF_SIZE)
+ if (ldata->read_cnt >= N_TTY_BUF_SIZE)
return;
- if (tty->canon_head != tty->read_head)
+ if (ldata->canon_head != ldata->read_head)
set_bit(TTY_PUSH, &tty->flags);
c = __DISABLED_CHAR;
goto handle_newline;
@@ -1275,7 +1321,7 @@ send_signal:
(c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
? 1 : 0;
- if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
+ if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
if (L_ECHO(tty))
process_output('\a', tty);
return;
@@ -1285,8 +1331,8 @@ send_signal:
*/
if (L_ECHO(tty)) {
/* Record the column of first canon char. */
- if (tty->canon_head == tty->read_head)
- echo_set_canon_col(tty);
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
echo_char(c, tty);
process_echoes(tty);
}
@@ -1295,15 +1341,15 @@ send_signal:
* EOL_CHAR and EOL2_CHAR?
*/
if (parmrk)
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
handle_newline:
- spin_lock_irqsave(&tty->read_lock, flags);
- set_bit(tty->read_head, tty->read_flags);
- put_tty_queue_nolock(c, tty);
- tty->canon_head = tty->read_head;
- tty->canon_data++;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ set_bit(ldata->read_head, ldata->read_flags);
+ put_tty_queue_nolock(c, ldata);
+ ldata->canon_head = ldata->read_head;
+ ldata->canon_data++;
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
@@ -1312,29 +1358,29 @@ handle_newline:
}
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
- if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+ if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
/* beep if no space */
if (L_ECHO(tty))
process_output('\a', tty);
return;
}
if (L_ECHO(tty)) {
- finish_erasing(tty);
+ finish_erasing(ldata);
if (c == '\n')
- echo_char_raw('\n', tty);
+ echo_char_raw('\n', ldata);
else {
/* Record the column of first canon char. */
- if (tty->canon_head == tty->read_head)
- echo_set_canon_col(tty);
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
echo_char(c, tty);
}
process_echoes(tty);
}
if (parmrk)
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
- put_tty_queue(c, tty);
+ put_tty_queue(c, ldata);
}
@@ -1369,33 +1415,31 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
+ struct n_tty_data *ldata = tty->disc_data;
const unsigned char *p;
char *f, flags = TTY_NORMAL;
int i;
char buf[64];
unsigned long cpuflags;
- if (!tty->read_buf)
- return;
-
- if (tty->real_raw) {
- spin_lock_irqsave(&tty->read_lock, cpuflags);
- i = min(N_TTY_BUF_SIZE - tty->read_cnt,
- N_TTY_BUF_SIZE - tty->read_head);
+ if (ldata->real_raw) {
+ spin_lock_irqsave(&ldata->read_lock, cpuflags);
+ i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
+ N_TTY_BUF_SIZE - ldata->read_head);
i = min(count, i);
- memcpy(tty->read_buf + tty->read_head, cp, i);
- tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt += i;
+ memcpy(ldata->read_buf + ldata->read_head, cp, i);
+ ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt += i;
cp += i;
count -= i;
- i = min(N_TTY_BUF_SIZE - tty->read_cnt,
- N_TTY_BUF_SIZE - tty->read_head);
+ i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
+ N_TTY_BUF_SIZE - ldata->read_head);
i = min(count, i);
- memcpy(tty->read_buf + tty->read_head, cp, i);
- tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt += i;
- spin_unlock_irqrestore(&tty->read_lock, cpuflags);
+ memcpy(ldata->read_buf + ldata->read_head, cp, i);
+ ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt += i;
+ spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
} else {
for (i = count, p = cp, f = fp; i; i--, p++) {
if (f)
@@ -1426,7 +1470,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
n_tty_set_room(tty);
- if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
+ if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) ||
L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
@@ -1470,25 +1514,25 @@ int is_ignored(int sig)
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
+ struct n_tty_data *ldata = tty->disc_data;
int canon_change = 1;
- BUG_ON(!tty);
if (old)
canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
if (canon_change) {
- memset(&tty->read_flags, 0, sizeof tty->read_flags);
- tty->canon_head = tty->read_tail;
- tty->canon_data = 0;
- tty->erasing = 0;
+ bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
+ ldata->canon_head = ldata->read_tail;
+ ldata->canon_data = 0;
+ ldata->erasing = 0;
}
- if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+ if (canon_change && !L_ICANON(tty) && ldata->read_cnt)
wake_up_interruptible(&tty->read_wait);
- tty->icanon = (L_ICANON(tty) != 0);
+ ldata->icanon = (L_ICANON(tty) != 0);
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
- tty->raw = 1;
- tty->real_raw = 1;
+ ldata->raw = 1;
+ ldata->real_raw = 1;
n_tty_set_room(tty);
return;
}
@@ -1496,51 +1540,51 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
I_PARMRK(tty)) {
- memset(tty->process_char_map, 0, 256/8);
+ bitmap_zero(ldata->process_char_map, 256);
if (I_IGNCR(tty) || I_ICRNL(tty))
- set_bit('\r', tty->process_char_map);
+ set_bit('\r', ldata->process_char_map);
if (I_INLCR(tty))
- set_bit('\n', tty->process_char_map);
+ set_bit('\n', ldata->process_char_map);
if (L_ICANON(tty)) {
- set_bit(ERASE_CHAR(tty), tty->process_char_map);
- set_bit(KILL_CHAR(tty), tty->process_char_map);
- set_bit(EOF_CHAR(tty), tty->process_char_map);
- set_bit('\n', tty->process_char_map);
- set_bit(EOL_CHAR(tty), tty->process_char_map);
+ set_bit(ERASE_CHAR(tty), ldata->process_char_map);
+ set_bit(KILL_CHAR(tty), ldata->process_char_map);
+ set_bit(EOF_CHAR(tty), ldata->process_char_map);
+ set_bit('\n', ldata->process_char_map);
+ set_bit(EOL_CHAR(tty), ldata->process_char_map);
if (L_IEXTEN(tty)) {
set_bit(WERASE_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
set_bit(LNEXT_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
set_bit(EOL2_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
if (L_ECHO(tty))
set_bit(REPRINT_CHAR(tty),
- tty->process_char_map);
+ ldata->process_char_map);
}
}
if (I_IXON(tty)) {
- set_bit(START_CHAR(tty), tty->process_char_map);
- set_bit(STOP_CHAR(tty), tty->process_char_map);
+ set_bit(START_CHAR(tty), ldata->process_char_map);
+ set_bit(STOP_CHAR(tty), ldata->process_char_map);
}
if (L_ISIG(tty)) {
- set_bit(INTR_CHAR(tty), tty->process_char_map);
- set_bit(QUIT_CHAR(tty), tty->process_char_map);
- set_bit(SUSP_CHAR(tty), tty->process_char_map);
+ set_bit(INTR_CHAR(tty), ldata->process_char_map);
+ set_bit(QUIT_CHAR(tty), ldata->process_char_map);
+ set_bit(SUSP_CHAR(tty), ldata->process_char_map);
}
- clear_bit(__DISABLED_CHAR, tty->process_char_map);
- tty->raw = 0;
- tty->real_raw = 0;
+ clear_bit(__DISABLED_CHAR, ldata->process_char_map);
+ ldata->raw = 0;
+ ldata->real_raw = 0;
} else {
- tty->raw = 1;
+ ldata->raw = 1;
if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
(I_IGNPAR(tty) || !I_INPCK(tty)) &&
(tty->driver->flags & TTY_DRIVER_REAL_RAW))
- tty->real_raw = 1;
+ ldata->real_raw = 1;
else
- tty->real_raw = 0;
+ ldata->real_raw = 0;
}
n_tty_set_room(tty);
/* The termios change make the tty ready for I/O */
@@ -1560,15 +1604,13 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
static void n_tty_close(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
n_tty_flush_buffer(tty);
- if (tty->read_buf) {
- kfree(tty->read_buf);
- tty->read_buf = NULL;
- }
- if (tty->echo_buf) {
- kfree(tty->echo_buf);
- tty->echo_buf = NULL;
- }
+ kfree(ldata->read_buf);
+ kfree(ldata->echo_buf);
+ kfree(ldata);
+ tty->disc_data = NULL;
}
/**
@@ -1583,37 +1625,50 @@ static void n_tty_close(struct tty_struct *tty)
static int n_tty_open(struct tty_struct *tty)
{
- if (!tty)
- return -EINVAL;
+ struct n_tty_data *ldata;
+
+ ldata = kzalloc(sizeof(*ldata), GFP_KERNEL);
+ if (!ldata)
+ goto err;
+
+ ldata->overrun_time = jiffies;
+ mutex_init(&ldata->atomic_read_lock);
+ mutex_init(&ldata->output_lock);
+ mutex_init(&ldata->echo_lock);
+ spin_lock_init(&ldata->read_lock);
/* These are ugly. Currently a malloc failure here can panic */
- if (!tty->read_buf) {
- tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
- if (!tty->read_buf)
- return -ENOMEM;
- }
- if (!tty->echo_buf) {
- tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ if (!ldata->read_buf || !ldata->echo_buf)
+ goto err_free_bufs;
- if (!tty->echo_buf)
- return -ENOMEM;
- }
+ tty->disc_data = ldata;
reset_buffer_flags(tty);
tty_unthrottle(tty);
- tty->column = 0;
+ ldata->column = 0;
n_tty_set_termios(tty, NULL);
tty->minimum_to_wake = 1;
tty->closing = 0;
+
return 0;
+err_free_bufs:
+ kfree(ldata->read_buf);
+ kfree(ldata->echo_buf);
+ kfree(ldata);
+err:
+ return -ENOMEM;
}
static inline int input_available_p(struct tty_struct *tty, int amt)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
tty_flush_to_ldisc(tty);
- if (tty->icanon && !L_EXTPROC(tty)) {
- if (tty->canon_data)
+ if (ldata->icanon && !L_EXTPROC(tty)) {
+ if (ldata->canon_data)
return 1;
- } else if (tty->read_cnt >= (amt ? amt : 1))
+ } else if (ldata->read_cnt >= (amt ? amt : 1))
return 1;
return 0;
@@ -1632,7 +1687,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
* buffer, and once to drain the space from the (physical) beginning of
* the buffer to head pointer.
*
- * Called under the tty->atomic_read_lock sem
+ * Called under the ldata->atomic_read_lock sem
*
*/
@@ -1641,29 +1696,31 @@ static int copy_from_read_buf(struct tty_struct *tty,
size_t *nr)
{
+ struct n_tty_data *ldata = tty->disc_data;
int retval;
size_t n;
unsigned long flags;
bool is_eof;
retval = 0;
- spin_lock_irqsave(&tty->read_lock, flags);
- n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
n = min(*nr, n);
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (n) {
- retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+ retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
n -= retval;
is_eof = n == 1 &&
- tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
- tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt -= n;
+ ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
+ tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
+ ldata->icanon);
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
+ ldata->read_cnt -= n;
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+ if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
n = 0;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
*b += n;
*nr -= n;
}
@@ -1730,6 +1787,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t nr)
{
+ struct n_tty_data *ldata = tty->disc_data;
unsigned char __user *b = buf;
DECLARE_WAITQUEUE(wait, current);
int c;
@@ -1741,17 +1799,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
int packet;
do_it_again:
-
- if (WARN_ON(!tty->read_buf))
- return -EAGAIN;
-
c = job_control(tty, file);
if (c < 0)
return c;
minimum = time = 0;
timeout = MAX_SCHEDULE_TIMEOUT;
- if (!tty->icanon) {
+ if (!ldata->icanon) {
time = (HZ / 10) * TIME_CHAR(tty);
minimum = MIN_CHAR(tty);
if (minimum) {
@@ -1774,10 +1828,10 @@ do_it_again:
* Internal serialization of reads.
*/
if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&tty->atomic_read_lock))
+ if (!mutex_trylock(&ldata->atomic_read_lock))
return -EAGAIN;
} else {
- if (mutex_lock_interruptible(&tty->atomic_read_lock))
+ if (mutex_lock_interruptible(&ldata->atomic_read_lock))
return -ERESTARTSYS;
}
packet = tty->packet;
@@ -1830,7 +1884,6 @@ do_it_again:
/* FIXME: does n_tty_set_room need locking ? */
n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
- BUG_ON(!tty->read_buf);
continue;
}
__set_current_state(TASK_RUNNING);
@@ -1845,45 +1898,45 @@ do_it_again:
nr--;
}
- if (tty->icanon && !L_EXTPROC(tty)) {
+ if (ldata->icanon && !L_EXTPROC(tty)) {
/* N.B. avoid overrun if nr == 0 */
- spin_lock_irqsave(&tty->read_lock, flags);
- while (nr && tty->read_cnt) {
+ spin_lock_irqsave(&ldata->read_lock, flags);
+ while (nr && ldata->read_cnt) {
int eol;
- eol = test_and_clear_bit(tty->read_tail,
- tty->read_flags);
- c = tty->read_buf[tty->read_tail];
- tty->read_tail = ((tty->read_tail+1) &
+ eol = test_and_clear_bit(ldata->read_tail,
+ ldata->read_flags);
+ c = ldata->read_buf[ldata->read_tail];
+ ldata->read_tail = ((ldata->read_tail+1) &
(N_TTY_BUF_SIZE-1));
- tty->read_cnt--;
+ ldata->read_cnt--;
if (eol) {
/* this test should be redundant:
* we shouldn't be reading data if
* canon_data is 0
*/
- if (--tty->canon_data < 0)
- tty->canon_data = 0;
+ if (--ldata->canon_data < 0)
+ ldata->canon_data = 0;
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
if (tty_put_user(tty, c, b++)) {
retval = -EFAULT;
b--;
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
break;
}
nr--;
}
if (eol) {
tty_audit_push(tty);
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
break;
}
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&ldata->read_lock, flags);
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&ldata->read_lock, flags);
if (retval)
break;
} else {
@@ -1915,7 +1968,7 @@ do_it_again:
if (time)
timeout = time;
}
- mutex_unlock(&tty->atomic_read_lock);
+ mutex_unlock(&ldata->atomic_read_lock);
remove_wait_queue(&tty->read_wait, &wait);
if (!waitqueue_active(&tty->read_wait))
@@ -2076,19 +2129,19 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
return mask;
}
-static unsigned long inq_canon(struct tty_struct *tty)
+static unsigned long inq_canon(struct n_tty_data *ldata)
{
int nr, head, tail;
- if (!tty->canon_data)
+ if (!ldata->canon_data)
return 0;
- head = tty->canon_head;
- tail = tty->read_tail;
+ head = ldata->canon_head;
+ tail = ldata->read_tail;
nr = (head - tail) & (N_TTY_BUF_SIZE-1);
/* Skip EOF-chars.. */
while (head != tail) {
- if (test_bit(tail, tty->read_flags) &&
- tty->read_buf[tail] == __DISABLED_CHAR)
+ if (test_bit(tail, ldata->read_flags) &&
+ ldata->read_buf[tail] == __DISABLED_CHAR)
nr--;
tail = (tail+1) & (N_TTY_BUF_SIZE-1);
}
@@ -2098,6 +2151,7 @@ static unsigned long inq_canon(struct tty_struct *tty)
static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct n_tty_data *ldata = tty->disc_data;
int retval;
switch (cmd) {
@@ -2105,9 +2159,9 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
/* FIXME: Locking */
- retval = tty->read_cnt;
+ retval = ldata->read_cnt;
if (L_ICANON(tty))
- retval = inq_canon(tty);
+ retval = inq_canon(ldata);
return put_user(retval, (unsigned int __user *) arg);
default:
return n_tty_ioctl_helper(tty, file, cmd, arg);
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index b917c9424954..a0c69ab04399 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -400,7 +400,7 @@ struct buffer {
} __attribute__ ((packed));
/* Global variables */
-static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = {
+static const struct pci_device_id nozomi_pci_tbl[] = {
{PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */
{},
};
@@ -1360,7 +1360,7 @@ static void remove_sysfs_files(struct nozomi *dc)
}
/* Allocate memory for one device */
-static int __devinit nozomi_card_init(struct pci_dev *pdev,
+static int nozomi_card_init(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
resource_size_t start;
@@ -1479,6 +1479,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);
dev_err(&pdev->dev, "Could not allocate tty?\n");
+ tty_port_destroy(&port->port);
goto err_free_tty;
}
}
@@ -1486,8 +1487,10 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
return 0;
err_free_tty:
- for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
- tty_unregister_device(ntty_driver, i);
+ for (i = 0; i < MAX_PORT; ++i) {
+ tty_unregister_device(ntty_driver, dc->index_start + i);
+ tty_port_destroy(&dc->port[i].port);
+ }
err_free_kfifo:
for (i = 0; i < MAX_PORT; i++)
kfifo_free(&dc->port[i].fifo_ul);
@@ -1504,7 +1507,7 @@ err:
return ret;
}
-static void __devexit tty_exit(struct nozomi *dc)
+static void tty_exit(struct nozomi *dc)
{
unsigned int i;
@@ -1520,12 +1523,14 @@ static void __devexit tty_exit(struct nozomi *dc)
complete off a hangup method ? */
while (dc->open_ttys)
msleep(1);
- for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
- tty_unregister_device(ntty_driver, i);
+ for (i = 0; i < MAX_PORT; ++i) {
+ tty_unregister_device(ntty_driver, dc->index_start + i);
+ tty_port_destroy(&dc->port[i].port);
+ }
}
/* Deallocate memory for one device */
-static void __devexit nozomi_card_exit(struct pci_dev *pdev)
+static void nozomi_card_exit(struct pci_dev *pdev)
{
int i;
struct ctrl_ul ctrl;
@@ -1903,7 +1908,7 @@ static struct pci_driver nozomi_driver = {
.name = NOZOMI_NAME,
.id_table = nozomi_pci_tbl,
.probe = nozomi_card_init,
- .remove = __devexit_p(nozomi_card_exit),
+ .remove = nozomi_card_exit,
};
static __init int nozomi_init(void)
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a82b39939a9c..79ff3a5e925d 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -4,9 +4,6 @@
* Added support for a Unix98-style ptmx device.
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
*
- * When reading this code see also fs/devpts. In particular note that the
- * driver_data field is used by the devpts side as a binding to the devpts
- * inode.
*/
#include <linux/module.h>
@@ -59,7 +56,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
#ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver) {
mutex_lock(&devpts_mutex);
- devpts_pty_kill(tty->link);
+ devpts_pty_kill(tty->link->driver_data);
mutex_unlock(&devpts_mutex);
}
#endif
@@ -96,7 +93,7 @@ static void pty_unthrottle(struct tty_struct *tty)
static int pty_space(struct tty_struct *to)
{
- int n = 8192 - to->buf.memory_used;
+ int n = 8192 - to->port->buf.memory_used;
if (n < 0)
return 0;
return n;
@@ -174,6 +171,41 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg)
return 0;
}
+static int pty_get_lock(struct tty_struct *tty, int __user *arg)
+{
+ int locked = test_bit(TTY_PTY_LOCK, &tty->flags);
+ return put_user(locked, arg);
+}
+
+/* Set the packet mode on a pty */
+static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
+{
+ unsigned long flags;
+ int pktmode;
+
+ if (get_user(pktmode, arg))
+ return -EFAULT;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (pktmode) {
+ if (!tty->packet) {
+ tty->packet = 1;
+ tty->link->ctrl_status = 0;
+ }
+ } else
+ tty->packet = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ return 0;
+}
+
+/* Get the packet mode of a pty */
+static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
+{
+ int pktmode = tty->packet;
+ return put_user(pktmode, arg);
+}
+
/* Send a signal to the slave */
static int pty_signal(struct tty_struct *tty, int sig)
{
@@ -245,7 +277,7 @@ static void pty_set_termios(struct tty_struct *tty,
* peform a terminal resize correctly
*/
-int pty_resize(struct tty_struct *tty, struct winsize *ws)
+static int pty_resize(struct tty_struct *tty, struct winsize *ws)
{
struct pid *pgrp, *rpgrp;
unsigned long flags;
@@ -348,6 +380,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
tty_port_init(ports[1]);
o_tty->port = ports[0];
tty->port = ports[1];
+ o_tty->port->itty = o_tty;
tty_driver_kref_get(driver);
tty->count++;
@@ -366,9 +399,16 @@ err:
return retval;
}
+/* 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);
+}
+
static void pty_cleanup(struct tty_struct *tty)
{
- kfree(tty->port);
+ tty->port->itty = NULL;
+ tty_port_put(tty->port);
}
/* Traditional BSD devices */
@@ -393,8 +433,16 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
switch (cmd) {
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
return pty_set_lock(tty, (int __user *) arg);
+ case TIOCGPTLCK: /* Get PT Lock status */
+ return pty_get_lock(tty, (int __user *)arg);
+ case TIOCPKT: /* Set PT packet mode */
+ return pty_set_pktmode(tty, (int __user *)arg);
+ case TIOCGPKT: /* Get PT packet mode */
+ return pty_get_pktmode(tty, (int __user *)arg);
case TIOCSIG: /* Send signal to other side of pty */
return pty_signal(tty, (int) arg);
+ case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */
+ return -EINVAL;
}
return -ENOIOCTLCMD;
}
@@ -507,6 +555,12 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
switch (cmd) {
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
return pty_set_lock(tty, (int __user *)arg);
+ case TIOCGPTLCK: /* Get PT Lock status */
+ return pty_get_lock(tty, (int __user *)arg);
+ case TIOCPKT: /* Set PT packet mode */
+ return pty_set_pktmode(tty, (int __user *)arg);
+ case TIOCGPKT: /* Get PT packet mode */
+ return pty_get_pktmode(tty, (int __user *)arg);
case TIOCGPTN: /* Get PT Number */
return put_user(tty->index, (unsigned int __user *)arg);
case TIOCSIG: /* Send signal to other side of pty */
@@ -547,7 +601,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct tty_struct *tty;
mutex_lock(&devpts_mutex);
- tty = devpts_get_tty(pts_inode, idx);
+ tty = devpts_get_priv(pts_inode);
mutex_unlock(&devpts_mutex);
/* Master must be open before slave */
if (!tty)
@@ -581,6 +635,7 @@ static const struct tty_operations ptm_unix98_ops = {
.set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
.resize = pty_resize,
+ .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup
};
@@ -596,6 +651,7 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
+ .shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup,
};
@@ -614,6 +670,7 @@ static const struct tty_operations pty_unix98_ops = {
static int ptmx_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
+ struct inode *slave_inode;
int retval;
int index;
@@ -650,15 +707,21 @@ static int ptmx_open(struct inode *inode, struct file *filp)
tty_add_file(tty, filp);
- retval = devpts_pty_new(inode, tty->link);
- if (retval)
+ slave_inode = devpts_pty_new(inode,
+ MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
+ tty->link);
+ if (IS_ERR(slave_inode)) {
+ retval = PTR_ERR(slave_inode);
goto err_release;
+ }
retval = ptm_driver->ops->open(tty, filp);
if (retval)
goto err_release;
tty_unlock(tty);
+ tty->driver_data = inode;
+ tty->link->driver_data = slave_inode;
return 0;
err_release:
tty_unlock(tty);
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 9700d34b20a3..e42009a00529 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -673,6 +673,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
board, aiop, chan);
+ tty_port_destroy(&info->port);
kfree(info);
return;
}
@@ -1757,7 +1758,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
#ifdef CONFIG_PCI
-static struct pci_device_id __devinitdata __used rocket_pci_ids[] = {
+static struct pci_device_id __used rocket_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
{ }
};
@@ -2357,6 +2358,7 @@ static void rp_cleanup_module(void)
for (i = 0; i < MAX_RP_PORTS; i++)
if (rp_table[i]) {
tty_unregister_device(rocket_driver, i);
+ tty_port_destroy(&rp_table[i]->port);
kfree(rp_table[i]);
}
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 66c38a3f74ce..f99a84526f82 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -1225,6 +1225,8 @@ rs68328_init(void)
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;
}
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 3ba4234592bc..f9320437a649 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -280,7 +280,17 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 64,
.tx_loadsz = 64,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
- .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
+ .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR |
+ UART_CAP_SLEEP,
+ },
+ [PORT_XR17V35X] = {
+ .name = "XR17V35X",
+ .fifo_size = 256,
+ .tx_loadsz = 256,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 |
+ UART_FCR_T_TRIG_11,
+ .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR |
+ UART_CAP_SLEEP,
},
[PORT_LPC3220] = {
.name = "LPC3220",
@@ -290,6 +300,12 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
.flags = UART_CAP_FIFO,
},
+ [PORT_BRCM_TRUMANAGE] = {
+ .name = "TruManage",
+ .fifo_size = 1,
+ .tx_loadsz = 1024,
+ .flags = UART_CAP_HFIFO,
+ },
[PORT_8250_CIR] = {
.name = "CIR port"
}
@@ -455,6 +471,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
}
static int serial8250_default_handle_irq(struct uart_port *port);
+static int exar_handle_irq(struct uart_port *port);
static void set_io_from_upio(struct uart_port *p)
{
@@ -574,6 +591,19 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
*/
static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
{
+ /*
+ * Exar UARTs have a SLEEP register that enables or disables
+ * each UART to enter sleep mode separately. On the XR17V35x the
+ * register is accessible to each UART at the UART_EXAR_SLEEP
+ * offset but the UART channel may only write to the corresponding
+ * bit.
+ */
+ if ((p->port.type == PORT_XR17V35X) ||
+ (p->port.type == PORT_XR17D15X)) {
+ serial_out(p, UART_EXAR_SLEEP, 0xff);
+ return;
+ }
+
if (p->capabilities & UART_CAP_SLEEP) {
if (p->capabilities & UART_CAP_EFR) {
serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -882,6 +912,27 @@ static void autoconfig_16550a(struct uart_8250_port *up)
up->capabilities |= UART_CAP_FIFO;
/*
+ * XR17V35x UARTs have an extra divisor register, DLD
+ * that gets enabled with when DLAB is set which will
+ * cause the device to incorrectly match and assign
+ * port type to PORT_16650. The EFR for this UART is
+ * found at offset 0x09. Instead check the Deice ID (DVID)
+ * register for a 2, 4 or 8 port UART.
+ */
+ if (up->port.flags & UPF_EXAR_EFR) {
+ status1 = serial_in(up, UART_EXAR_DVID);
+ if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) {
+ DEBUG_AUTOCONF("Exar XR17V35x ");
+ up->port.type = PORT_XR17V35X;
+ up->capabilities |= UART_CAP_AFE | UART_CAP_EFR |
+ UART_CAP_SLEEP;
+
+ return;
+ }
+
+ }
+
+ /*
* Check for presence of the EFR when DLAB is set.
* Only ST16C650V1 UARTs pass this test.
*/
@@ -1013,8 +1064,12 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* Exar uarts have EFR in a weird location
*/
if (up->port.flags & UPF_EXAR_EFR) {
+ DEBUG_AUTOCONF("Exar XR17D15x ");
up->port.type = PORT_XR17D15X;
- up->capabilities |= UART_CAP_AFE | UART_CAP_EFR;
+ up->capabilities |= UART_CAP_AFE | UART_CAP_EFR |
+ UART_CAP_SLEEP;
+
+ return;
}
/*
@@ -1441,6 +1496,11 @@ 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;
+ }
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1516,6 +1576,31 @@ static int serial8250_default_handle_irq(struct uart_port *port)
}
/*
+ * These Exar UARTs have an extra interrupt indicator that could
+ * fire for a few unimplemented interrupts. One of which is a
+ * wakeup event when coming out of sleep. Put this here just
+ * to be on the safe side that these interrupts don't go unhandled.
+ */
+static int exar_handle_irq(struct uart_port *port)
+{
+ unsigned char int0, int1, int2, int3;
+ unsigned int iir = serial_port_in(port, UART_IIR);
+ int ret;
+
+ ret = serial8250_handle_irq(port, iir);
+
+ if ((port->type == PORT_XR17V35X) ||
+ (port->type == PORT_XR17D15X)) {
+ int0 = serial_port_in(port, 0x80);
+ int1 = serial_port_in(port, 0x81);
+ int2 = serial_port_in(port, 0x82);
+ int3 = serial_port_in(port, 0x83);
+ }
+
+ return ret;
+}
+
+/*
* This is the serial driver's interrupt routine.
*
* Arjan thinks the old way was overly complex, so it got simplified.
@@ -2349,16 +2434,14 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
-#ifdef CONFIG_ARCH_OMAP1
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
- if (cpu_is_omap1510() && is_omap_port(up)) {
+ if (is_omap1510_8250(up)) {
if (baud == 115200) {
quot = 1;
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
} else
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
}
-#endif
/*
* For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
@@ -2439,10 +2522,9 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
if (pt->port.iotype == UPIO_AU)
return 0x1000;
-#ifdef CONFIG_ARCH_OMAP1
- if (is_omap_port(pt))
+ if (is_omap1_8250(pt))
return 0x16 << pt->port.regshift;
-#endif
+
return 8 << pt->port.regshift;
}
@@ -2617,6 +2699,11 @@ static void serial8250_config_port(struct uart_port *port, int flags)
serial8250_release_rsa_resource(up);
if (port->type == PORT_UNKNOWN)
serial8250_release_std_resource(up);
+
+ /* Fixme: probably not the best place for this */
+ if ((port->type == PORT_XR17V35X) ||
+ (port->type == PORT_XR17D15X))
+ port->handle_irq = exar_handle_irq;
}
static int
@@ -2992,7 +3079,7 @@ void serial8250_resume_port(int line)
* list is terminated with a zero flags entry, which means we expect
* all entries to have at least UPF_BOOT_AUTOCONF set.
*/
-static int __devinit serial8250_probe(struct platform_device *dev)
+static int serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev->dev.platform_data;
struct uart_8250_port uart;
@@ -3038,7 +3125,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
/*
* Remove serial ports registered against a platform device.
*/
-static int __devexit serial8250_remove(struct platform_device *dev)
+static int serial8250_remove(struct platform_device *dev)
{
int i;
@@ -3081,7 +3168,7 @@ static int serial8250_resume(struct platform_device *dev)
static struct platform_driver serial8250_isa_driver = {
.probe = serial8250_probe,
- .remove = __devexit_p(serial8250_remove),
+ .remove = serial8250_remove,
.suspend = serial8250_suspend,
.resume = serial8250_resume,
.driver = {
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 5a76f9c8d36b..12caa1292b75 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -40,6 +40,7 @@ struct serial8250_config {
#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */
#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */
#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */
+#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
@@ -106,3 +107,39 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif
+#ifdef CONFIG_ARCH_OMAP1
+static inline int is_omap1_8250(struct uart_8250_port *pt)
+{
+ int res;
+
+ switch (pt->port.mapbase) {
+ case OMAP1_UART1_BASE:
+ case OMAP1_UART2_BASE:
+ case OMAP1_UART3_BASE:
+ res = 1;
+ break;
+ default:
+ res = 0;
+ break;
+ }
+
+ return res;
+}
+
+static inline int is_omap1510_8250(struct uart_8250_port *pt)
+{
+ if (!cpu_is_omap1510())
+ return 0;
+
+ return is_omap1_8250(pt);
+}
+#else
+static inline int is_omap1_8250(struct uart_8250_port *pt)
+{
+ return 0;
+}
+static inline int is_omap1510_8250(struct uart_8250_port *pt)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index 857498312a9a..549aa07c0d27 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -38,7 +38,7 @@ struct serial_card_info {
void __iomem *vaddr;
};
-static int __devinit
+static int
serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct serial_card_info *info;
@@ -80,7 +80,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
return 0;
}
-static void __devexit serial_card_remove(struct expansion_card *ec)
+static void serial_card_remove(struct expansion_card *ec)
{
struct serial_card_info *info = ecard_get_drvdata(ec);
int i;
@@ -116,7 +116,7 @@ static const struct ecard_id serial_cids[] = {
static struct ecard_driver serial_card_driver = {
.probe = serial_card_probe,
- .remove = __devexit_p(serial_card_remove),
+ .remove = serial_card_remove,
.id_table = serial_cids,
.drv = {
.name = "8250_acorn",
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index c3b2ec0c8c0b..096d2ef48b32 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -79,7 +79,7 @@ static int dw8250_handle_irq(struct uart_port *p)
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR and write the LCR again. */
(void)p->serial_in(p, UART_USR);
- p->serial_out(p, d->last_lcr, UART_LCR);
+ p->serial_out(p, UART_LCR, d->last_lcr);
return 1;
}
@@ -87,7 +87,7 @@ static int dw8250_handle_irq(struct uart_port *p)
return 0;
}
-static int __devinit dw8250_probe(struct platform_device *pdev)
+static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -152,7 +152,7 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit dw8250_remove(struct platform_device *pdev)
+static int dw8250_remove(struct platform_device *pdev)
{
struct dw8250_data *data = platform_get_drvdata(pdev);
@@ -161,6 +161,29 @@ static int __devexit dw8250_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct dw8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+}
+
+static int dw8250_resume(struct platform_device *pdev)
+{
+ struct dw8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+#else
+#define dw8250_suspend NULL
+#define dw8250_resume NULL
+#endif /* CONFIG_PM */
+
static const struct of_device_id dw8250_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ /* Sentinel */ }
@@ -174,7 +197,9 @@ static struct platform_driver dw8250_platform_driver = {
.of_match_table = dw8250_match,
},
.probe = dw8250_probe,
- .remove = __devexit_p(dw8250_remove),
+ .remove = dw8250_remove,
+ .suspend = dw8250_suspend,
+ .resume = dw8250_resume,
};
module_platform_driver(dw8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index eaafb98debed..f53a7db4350d 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -48,7 +48,7 @@ struct early_serial8250_device {
static struct early_serial8250_device early_device;
-static unsigned int __init serial_in(struct uart_port *port, int offset)
+unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
{
switch (port->iotype) {
case UPIO_MEM:
@@ -62,7 +62,7 @@ static unsigned int __init serial_in(struct uart_port *port, int offset)
}
}
-static void __init serial_out(struct uart_port *port, int offset, int value)
+void __weak __init serial8250_early_out(struct uart_port *port, int offset, int value)
{
switch (port->iotype) {
case UPIO_MEM:
@@ -84,7 +84,7 @@ static void __init wait_for_xmitr(struct uart_port *port)
unsigned int status;
for (;;) {
- status = serial_in(port, UART_LSR);
+ status = serial8250_early_in(port, UART_LSR);
if ((status & BOTH_EMPTY) == BOTH_EMPTY)
return;
cpu_relax();
@@ -94,7 +94,7 @@ static void __init wait_for_xmitr(struct uart_port *port)
static void __init serial_putc(struct uart_port *port, int c)
{
wait_for_xmitr(port);
- serial_out(port, UART_TX, c);
+ serial8250_early_out(port, UART_TX, c);
}
static void __init early_serial8250_write(struct console *console,
@@ -104,14 +104,14 @@ static void __init early_serial8250_write(struct console *console,
unsigned int ier;
/* Save the IER and disable interrupts */
- ier = serial_in(port, UART_IER);
- serial_out(port, UART_IER, 0);
+ ier = serial8250_early_in(port, UART_IER);
+ serial8250_early_out(port, UART_IER, 0);
uart_console_write(port, s, count, serial_putc);
/* Wait for transmitter to become empty and restore the IER */
wait_for_xmitr(port);
- serial_out(port, UART_IER, ier);
+ serial8250_early_out(port, UART_IER, ier);
}
static unsigned int __init probe_baud(struct uart_port *port)
@@ -119,11 +119,11 @@ static unsigned int __init probe_baud(struct uart_port *port)
unsigned char lcr, dll, dlm;
unsigned int quot;
- lcr = serial_in(port, UART_LCR);
- serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
- dll = serial_in(port, UART_DLL);
- dlm = serial_in(port, UART_DLM);
- serial_out(port, UART_LCR, lcr);
+ lcr = serial8250_early_in(port, UART_LCR);
+ serial8250_early_out(port, UART_LCR, lcr | UART_LCR_DLAB);
+ dll = serial8250_early_in(port, UART_DLL);
+ dlm = serial8250_early_in(port, UART_DLM);
+ serial8250_early_out(port, UART_LCR, lcr);
quot = (dlm << 8) | dll;
return (port->uartclk / 16) / quot;
@@ -135,17 +135,17 @@ static void __init init_port(struct early_serial8250_device *device)
unsigned int divisor;
unsigned char c;
- serial_out(port, UART_LCR, 0x3); /* 8n1 */
- serial_out(port, UART_IER, 0); /* no interrupt */
- serial_out(port, UART_FCR, 0); /* no fifo */
- serial_out(port, UART_MCR, 0x3); /* DTR + RTS */
-
- divisor = port->uartclk / (16 * device->baud);
- c = serial_in(port, UART_LCR);
- serial_out(port, UART_LCR, c | UART_LCR_DLAB);
- serial_out(port, UART_DLL, divisor & 0xff);
- serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
- serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+ serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */
+ serial8250_early_out(port, UART_IER, 0); /* no interrupt */
+ serial8250_early_out(port, UART_FCR, 0); /* no fifo */
+ serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
+
+ divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
+ c = serial8250_early_in(port, UART_LCR);
+ serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
+ serial8250_early_out(port, UART_DLL, divisor & 0xff);
+ serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
+ serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
static int __init parse_options(struct early_serial8250_device *device,
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index 3a0363e7f3a7..916cc19fbbda 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -89,7 +89,7 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
}
-static int __devinit serial8250_em_probe(struct platform_device *pdev)
+static int serial8250_em_probe(struct platform_device *pdev)
{
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -152,7 +152,7 @@ static int __devinit serial8250_em_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit serial8250_em_remove(struct platform_device *pdev)
+static int serial8250_em_remove(struct platform_device *pdev)
{
struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
@@ -163,7 +163,7 @@ static int __devexit serial8250_em_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
+static const struct of_device_id serial8250_em_dt_ids[] = {
{ .compatible = "renesas,em-uart", },
{},
};
@@ -176,7 +176,7 @@ static struct platform_driver serial8250_em_platform_driver = {
.owner = THIS_MODULE,
},
.probe = serial8250_em_probe,
- .remove = __devexit_p(serial8250_em_remove),
+ .remove = serial8250_em_remove,
};
module_platform_driver(serial8250_em_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index f3d0edf46644..5bdaf271d395 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -36,9 +36,9 @@ static struct hp300_port *hp300_ports;
#ifdef CONFIG_HPDCA
-static int __devinit hpdca_init_one(struct dio_dev *d,
+static int hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent);
-static void __devexit hpdca_remove_one(struct dio_dev *d);
+static void hpdca_remove_one(struct dio_dev *d);
static struct dio_device_id hpdca_dio_tbl[] = {
{ DIO_ID_DCA0 },
@@ -52,7 +52,7 @@ static struct dio_driver hpdca_driver = {
.name = "hpdca",
.id_table = hpdca_dio_tbl,
.probe = hpdca_init_one,
- .remove = __devexit_p(hpdca_remove_one),
+ .remove = hpdca_remove_one,
};
#endif
@@ -159,7 +159,7 @@ int __init hp300_setup_serial_console(void)
#endif /* CONFIG_SERIAL_8250_CONSOLE */
#ifdef CONFIG_HPDCA
-static int __devinit hpdca_init_one(struct dio_dev *d,
+static int hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent)
{
struct uart_8250_port uart;
@@ -288,7 +288,7 @@ static int __init hp300_8250_init(void)
}
#ifdef CONFIG_HPDCA
-static void __devexit hpdca_remove_one(struct dio_dev *d)
+static void hpdca_remove_one(struct dio_dev *d)
{
int line;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 17b7d26abf41..a27a98e1b066 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -288,7 +288,7 @@ static int pci_plx9050_init(struct pci_dev *dev)
return 0;
}
-static void __devexit pci_plx9050_exit(struct pci_dev *dev)
+static void pci_plx9050_exit(struct pci_dev *dev)
{
u8 __iomem *p;
@@ -313,7 +313,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
#define NI8420_INT_ENABLE_REG 0x38
#define NI8420_INT_ENABLE_BIT 0x2000
-static void __devexit pci_ni8420_exit(struct pci_dev *dev)
+static void pci_ni8420_exit(struct pci_dev *dev)
{
void __iomem *p;
unsigned long base, len;
@@ -345,7 +345,7 @@ static void __devexit pci_ni8420_exit(struct pci_dev *dev)
#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
-static void __devexit pci_ni8430_exit(struct pci_dev *dev)
+static void pci_ni8430_exit(struct pci_dev *dev)
{
void __iomem *p;
unsigned long base, len;
@@ -422,7 +422,7 @@ static int sbs_init(struct pci_dev *dev)
* Disables the global interrupt of PMC-OctalPro
*/
-static void __devexit sbs_exit(struct pci_dev *dev)
+static void sbs_exit(struct pci_dev *dev)
{
u8 __iomem *p;
@@ -991,7 +991,7 @@ static int pci_ite887x_init(struct pci_dev *dev)
return ret;
}
-static void __devexit pci_ite887x_exit(struct pci_dev *dev)
+static void pci_ite887x_exit(struct pci_dev *dev)
{
u32 ioport;
/* the ioport is bit 0-15 in POSIO0R */
@@ -1068,7 +1068,7 @@ ce4100_serial_setup(struct serial_private *priv,
{
int ret;
- ret = setup_port(priv, port, 0, 0, board->reg_shift);
+ ret = setup_port(priv, port, idx, 0, board->reg_shift);
port->port.iotype = UPIO_MEM32;
port->port.type = PORT_XSCALE;
port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
@@ -1085,6 +1085,18 @@ pci_omegapci_setup(struct serial_private *priv,
return setup_port(priv, port, 2, idx * 8, 0);
}
+static int
+pci_brcm_trumanage_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ int ret = pci_default_setup(priv, board, port, idx);
+
+ port->port.type = PORT_BRCM_TRUMANAGE;
+ port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+ return ret;
+}
+
static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
@@ -1165,6 +1177,94 @@ pci_xr17c154_setup(struct serial_private *priv,
}
static int
+pci_xr17v35x_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ u8 __iomem *p;
+
+ p = pci_ioremap_bar(priv->dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ port->port.flags |= UPF_EXAR_EFR;
+
+ /*
+ * Setup Multipurpose Input/Output pins.
+ */
+ if (idx == 0) {
+ writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/
+ writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/
+ writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/
+ writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/
+ writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/
+ writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/
+ writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/
+ writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/
+ writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/
+ writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/
+ writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/
+ writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/
+ }
+ writeb(0x00, p + UART_EXAR_8XMODE);
+ writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
+ writeb(128, p + UART_EXAR_TXTRG);
+ writeb(128, p + UART_EXAR_RXTRG);
+ iounmap(p);
+
+ return pci_default_setup(priv, board, port, idx);
+}
+
+#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004
+#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002
+#define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a
+#define PCI_DEVICE_ID_COMMTECH_2328PCI335 0x000b
+
+static int
+pci_fastcom335_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ u8 __iomem *p;
+
+ p = pci_ioremap_bar(priv->dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ port->port.flags |= UPF_EXAR_EFR;
+
+ /*
+ * Setup Multipurpose Input/Output pins.
+ */
+ if (idx == 0) {
+ switch (priv->dev->device) {
+ case PCI_DEVICE_ID_COMMTECH_4222PCI335:
+ case PCI_DEVICE_ID_COMMTECH_4224PCI335:
+ writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */
+ writeb(0x00, p + 0x92); /* MPIOINV[7:0] */
+ writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */
+ break;
+ case PCI_DEVICE_ID_COMMTECH_2324PCI335:
+ case PCI_DEVICE_ID_COMMTECH_2328PCI335:
+ writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */
+ writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */
+ writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */
+ break;
+ }
+ writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */
+ writeb(0x00, p + 0x91); /* MPIO3T[7:0] */
+ writeb(0x00, p + 0x94); /* MPIOOD[7:0] */
+ }
+ writeb(0x00, p + UART_EXAR_8XMODE);
+ writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
+ writeb(32, p + UART_EXAR_TXTRG);
+ writeb(32, p + UART_EXAR_RXTRG);
+ iounmap(p);
+
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int
pci_wch_ch353_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
@@ -1213,6 +1313,11 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
#define PCI_VENDOR_ID_ASIX 0x9710
+#define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020
+#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
+#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
+#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
+
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@@ -1314,7 +1419,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ite887x_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ite887x_exit),
+ .exit = pci_ite887x_exit,
},
/*
* National Instruments
@@ -1326,7 +1431,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1335,7 +1440,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1344,7 +1449,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1353,7 +1458,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1362,7 +1467,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1371,7 +1476,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1380,7 +1485,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1389,7 +1494,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1398,7 +1503,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1407,7 +1512,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1416,7 +1521,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1425,7 +1530,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8420_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_ni8420_exit),
+ .exit = pci_ni8420_exit,
},
{
.vendor = PCI_VENDOR_ID_NI,
@@ -1434,7 +1539,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_ni8430_init,
.setup = pci_ni8430_setup,
- .exit = __devexit_p(pci_ni8430_exit),
+ .exit = pci_ni8430_exit,
},
/*
* Panacom
@@ -1446,7 +1551,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_plx9050_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_plx9050_exit),
+ .exit = pci_plx9050_exit,
},
{
.vendor = PCI_VENDOR_ID_PANACOM,
@@ -1455,7 +1560,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.init = pci_plx9050_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_plx9050_exit),
+ .exit = pci_plx9050_exit,
},
/*
* PLX
@@ -1474,7 +1579,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_EXSYS_4055,
.init = pci_plx9050_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_plx9050_exit),
+ .exit = pci_plx9050_exit,
},
{
.vendor = PCI_VENDOR_ID_PLX,
@@ -1483,7 +1588,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
.init = pci_plx9050_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_plx9050_exit),
+ .exit = pci_plx9050_exit,
},
{
.vendor = PCI_VENDOR_ID_PLX,
@@ -1492,7 +1597,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
.init = pci_plx9050_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_plx9050_exit),
+ .exit = pci_plx9050_exit,
},
{
.vendor = PCI_VENDOR_ID_PLX,
@@ -1501,7 +1606,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_DEVICE_ID_PLX_ROMULUS,
.init = pci_plx9050_init,
.setup = pci_default_setup,
- .exit = __devexit_p(pci_plx9050_exit),
+ .exit = pci_plx9050_exit,
},
/*
* SBS Technologies, Inc., PMC-OCTALPRO 232
@@ -1513,7 +1618,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_OCTPRO232,
.init = sbs_init,
.setup = sbs_setup,
- .exit = __devexit_p(sbs_exit),
+ .exit = sbs_exit,
},
/*
* SBS Technologies, Inc., PMC-OCTALPRO 422
@@ -1525,7 +1630,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_OCTPRO422,
.init = sbs_init,
.setup = sbs_setup,
- .exit = __devexit_p(sbs_exit),
+ .exit = sbs_exit,
},
/*
* SBS Technologies, Inc., P-Octal 232
@@ -1537,7 +1642,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_POCTAL232,
.init = sbs_init,
.setup = sbs_setup,
- .exit = __devexit_p(sbs_exit),
+ .exit = sbs_exit,
},
/*
* SBS Technologies, Inc., P-Octal 422
@@ -1549,7 +1654,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_SUBDEVICE_ID_POCTAL422,
.init = sbs_init,
.setup = sbs_setup,
- .exit = __devexit_p(sbs_exit),
+ .exit = sbs_exit,
},
/*
* SIIG cards - these may be called via parport_serial
@@ -1622,6 +1727,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_xr17c154_setup,
},
+ {
+ .vendor = PCI_VENDOR_ID_EXAR,
+ .device = PCI_DEVICE_ID_EXAR_XR17V352,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_EXAR,
+ .device = PCI_DEVICE_ID_EXAR_XR17V354,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_EXAR,
+ .device = PCI_DEVICE_ID_EXAR_XR17V358,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
/*
* Xircom cards
*/
@@ -1788,6 +1914,70 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_asix_setup,
},
/*
+ * Commtech, Inc. Fastcom adapters
+ *
+ */
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_4222PCI335,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fastcom335_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_4224PCI335,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fastcom335_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_2324PCI335,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fastcom335_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_2328PCI335,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fastcom335_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_4222PCIE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_4224PCIE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_COMMTECH,
+ .device = PCI_DEVICE_ID_COMMTECH_4228PCIE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ /*
+ * Broadcom TruManage (NetXtreme)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_BROADCOM,
+ .device = PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_brcm_trumanage_setup,
+ },
+
+ /*
* Default "match everything" terminator entry
*/
{
@@ -1863,6 +2053,10 @@ enum pci_board_num_t {
pbn_b0_4_1152000,
+ pbn_b0_2_1152000_200,
+ pbn_b0_4_1152000_200,
+ pbn_b0_8_1152000_200,
+
pbn_b0_2_1843200,
pbn_b0_4_1843200,
@@ -1962,6 +2156,9 @@ enum pci_board_num_t {
pbn_exar_XR17C152,
pbn_exar_XR17C154,
pbn_exar_XR17C158,
+ pbn_exar_XR17V352,
+ pbn_exar_XR17V354,
+ pbn_exar_XR17V358,
pbn_exar_ibm_saturn,
pbn_pasemi_1682M,
pbn_ni8430_2,
@@ -1975,6 +2172,7 @@ enum pci_board_num_t {
pbn_ce4100_1_115200,
pbn_omegapci,
pbn_NETMOS9900_2s_115200,
+ pbn_brcm_trumanage,
};
/*
@@ -1987,7 +2185,7 @@ enum pci_board_num_t {
* see first lines of serial_in() and serial_out() in 8250.c
*/
-static struct pciserial_board pci_boards[] __devinitdata = {
+static struct pciserial_board pci_boards[] = {
[pbn_default] = {
.flags = FL_BASE0,
.num_ports = 1,
@@ -2057,6 +2255,27 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.uart_offset = 8,
},
+ [pbn_b0_2_1152000_200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 1152000,
+ .uart_offset = 0x200,
+ },
+
+ [pbn_b0_4_1152000_200] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1152000,
+ .uart_offset = 0x200,
+ },
+
+ [pbn_b0_8_1152000_200] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 1152000,
+ .uart_offset = 0x200,
+ },
+
[pbn_b0_2_1843200] = {
.flags = FL_BASE0,
.num_ports = 2,
@@ -2580,6 +2799,30 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 921600,
.uart_offset = 0x200,
},
+ [pbn_exar_XR17V352] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 7812500,
+ .uart_offset = 0x400,
+ .reg_shift = 0,
+ .first_offset = 0,
+ },
+ [pbn_exar_XR17V354] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 7812500,
+ .uart_offset = 0x400,
+ .reg_shift = 0,
+ .first_offset = 0,
+ },
+ [pbn_exar_XR17V358] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 7812500,
+ .uart_offset = 0x400,
+ .reg_shift = 0,
+ .first_offset = 0,
+ },
[pbn_exar_ibm_saturn] = {
.flags = FL_BASE0,
.num_ports = 1,
@@ -2658,8 +2901,8 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.first_offset = 0x1000,
},
[pbn_ce4100_1_115200] = {
- .flags = FL_BASE0,
- .num_ports = 1,
+ .flags = FL_BASE_BARS,
+ .num_ports = 2,
.base_baud = 921600,
.reg_shift = 2,
},
@@ -2674,6 +2917,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.num_ports = 2,
.base_baud = 115200,
},
+ [pbn_brcm_trumanage] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .reg_shift = 2,
+ .base_baud = 115200,
+ },
};
static const struct pci_device_id blacklist[] = {
@@ -2691,7 +2940,7 @@ static const struct pci_device_id blacklist[] = {
* guess what the configuration might be, based on the pitiful PCI
* serial specs. Returns 0 on success, 1 on failure.
*/
-static int __devinit
+static int
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{
const struct pci_device_id *bldev;
@@ -2917,7 +3166,7 @@ EXPORT_SYMBOL_GPL(pciserial_resume_ports);
* Probe one serial board. Unfortunately, there is no rhyme nor reason
* to the arrangement of serial ports on a PCI card.
*/
-static int __devinit
+static int
pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct pci_serial_quirk *quirk;
@@ -2988,7 +3237,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
return rc;
}
-static void __devexit pciserial_remove_one(struct pci_dev *dev)
+static void pciserial_remove_one(struct pci_dev *dev)
{
struct serial_private *priv = pci_get_drvdata(dev);
@@ -3826,6 +4075,21 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_exar_XR17C158 },
+ /*
+ * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs
+ */
+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V352 },
+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V354,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V354 },
+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V358,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V358 },
/*
* Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
@@ -4238,6 +4502,13 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_omegapci },
/*
+ * Broadcom TruManage
+ */
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_brcm_trumanage },
+
+ /*
* AgeStar as-prs2-009
*/
{ PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
@@ -4257,6 +4528,38 @@ static struct pci_device_id serial_pci_tbl[] = {
0, 0, pbn_b0_bt_2_115200 },
/*
+ * Commtech, Inc. Fastcom adapters
+ */
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCI335,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_b0_2_1152000_200 },
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCI335,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_b0_4_1152000_200 },
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2324PCI335,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_b0_4_1152000_200 },
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2328PCI335,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_b0_8_1152000_200 },
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCIE,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V352 },
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCIE,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V354 },
+ { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4228PCIE,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V358 },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
@@ -4323,7 +4626,7 @@ static const struct pci_error_handlers serial8250_err_handler = {
static struct pci_driver serial_pci_driver = {
.name = "serial",
.probe = pciserial_init_one,
- .remove = __devexit_p(pciserial_remove_one),
+ .remove = pciserial_remove_one,
#ifdef CONFIG_PM
.suspend = pciserial_suspend_one,
.resume = pciserial_resume_one,
@@ -4332,18 +4635,7 @@ static struct pci_driver serial_pci_driver = {
.err_handler = &serial8250_err_handler,
};
-static int __init serial8250_pci_init(void)
-{
- return pci_register_driver(&serial_pci_driver);
-}
-
-static void __exit serial8250_pci_exit(void)
-{
- pci_unregister_driver(&serial_pci_driver);
-}
-
-module_init(serial8250_pci_init);
-module_exit(serial8250_pci_exit);
+module_pci_driver(serial_pci_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index f8ee25001dd0..35d9ab95c5cb 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -370,14 +370,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-static char *modem_names[] __devinitdata = {
+static 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 __devinit check_name(char *name)
+static int check_name(char *name)
{
char **tmp;
@@ -388,7 +388,7 @@ static int __devinit check_name(char *name)
return 0;
}
-static int __devinit check_resources(struct pnp_dev *dev)
+static int check_resources(struct pnp_dev *dev)
{
resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
int i;
@@ -412,7 +412,7 @@ static int __devinit check_resources(struct pnp_dev *dev)
* PnP modems, alternatively we must hardcode all modems in pnp_devices[]
* table.
*/
-static int __devinit serial_pnp_guess_board(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))))
@@ -424,7 +424,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
return -ENODEV;
}
-static int __devinit
+static int
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart;
@@ -476,7 +476,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
return 0;
}
-static void __devexit serial_pnp_remove(struct pnp_dev *dev)
+static void serial_pnp_remove(struct pnp_dev *dev)
{
long line = (long)pnp_get_drvdata(dev);
if (line)
@@ -511,7 +511,7 @@ static int serial_pnp_resume(struct pnp_dev *dev)
static struct pnp_driver serial_pnp_driver = {
.name = "serial",
.probe = serial_pnp_probe,
- .remove = __devexit_p(serial_pnp_remove),
+ .remove = serial_pnp_remove,
.suspend = serial_pnp_suspend,
.resume = serial_pnp_resume,
.id_table = pnp_dev_table,
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2a53be5f010d..59c23d038106 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -93,7 +93,7 @@ config SERIAL_SB1250_DUART_CONSOLE
config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
- depends on (ARM && ARCH_AT91) || AVR32
+ depends on ARCH_AT91 || AVR32
select SERIAL_CORE
help
This enables the driver for the on-chip UARTs of the Atmel
@@ -198,7 +198,7 @@ config SERIAL_CLPS711X_CONSOLE
config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
- depends on ARM && PLAT_SAMSUNG
+ depends on PLAT_SAMSUNG
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -208,14 +208,14 @@ config SERIAL_SAMSUNG
config SERIAL_SAMSUNG_UARTS_4
bool
- depends on ARM && PLAT_SAMSUNG
+ depends on PLAT_SAMSUNG
default y if !(CPU_S3C2410 || SERIAL_S3C2412 || CPU_S3C2440 || CPU_S3C2442)
help
Internal node for the common case of 4 Samsung compatible UARTs
config SERIAL_SAMSUNG_UARTS
int
- depends on ARM && PLAT_SAMSUNG
+ depends on PLAT_SAMSUNG
default 6 if ARCH_S5P6450
default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416
default 3
@@ -249,7 +249,7 @@ config SERIAL_SAMSUNG_CONSOLE
config SERIAL_SIRFSOC
tristate "SiRF SoC Platform Serial port support"
- depends on ARM && ARCH_PRIMA2
+ depends on ARCH_PRIMA2
select SERIAL_CORE
help
Support for the on-chip UART on the CSR SiRFprimaII series,
@@ -347,7 +347,7 @@ config SERIAL_ZS_CONSOLE
config SERIAL_21285
tristate "DC21285 serial port support"
- depends on ARM && FOOTBRIDGE
+ depends on FOOTBRIDGE
select SERIAL_CORE
help
If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
@@ -371,7 +371,7 @@ config SERIAL_21285_CONSOLE
config SERIAL_MPSC
bool "Marvell MPSC serial port support"
- depends on PPC32 && MV64X60
+ depends on MV64X60
select SERIAL_CORE
help
Say Y here if you want to use the Marvell MPSC serial controller.
@@ -408,7 +408,7 @@ config SERIAL_PXA_CONSOLE
config SERIAL_SA1100
bool "SA1100 serial port support"
- depends on ARM && ARCH_SA1100
+ depends on ARCH_SA1100
select SERIAL_CORE
help
If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
@@ -716,7 +716,7 @@ config SERIAL_SH_SCI_DMA
config SERIAL_PNX8XXX
bool "Enable PNX8XXX SoCs' UART Support"
- depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
+ depends on SOC_PNX8550 || SOC_PNX833X
select SERIAL_CORE
help
If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
@@ -1013,7 +1013,7 @@ config SERIAL_SGI_IOC3
config SERIAL_MSM
bool "MSM on-chip serial port support"
- depends on ARM && ARCH_MSM
+ depends on ARCH_MSM
select SERIAL_CORE
config SERIAL_MSM_CONSOLE
@@ -1035,7 +1035,7 @@ config SERIAL_MSM_HS
config SERIAL_VT8500
bool "VIA VT8500 on-chip serial port support"
- depends on ARM && ARCH_VT8500
+ depends on ARCH_VT8500
select SERIAL_CORE
config SERIAL_VT8500_CONSOLE
@@ -1045,7 +1045,7 @@ config SERIAL_VT8500_CONSOLE
config SERIAL_NETX
tristate "NetX serial port support"
- depends on ARM && ARCH_NETX
+ depends on ARCH_NETX
select SERIAL_CORE
help
If you have a machine based on a Hilscher NetX SoC you
@@ -1376,6 +1376,7 @@ config SERIAL_MXS_AUART_CONSOLE
config SERIAL_XILINX_PS_UART
tristate "Xilinx PS UART support"
+ depends on OF
select SERIAL_CORE
help
This driver supports the Xilinx PS UART port.
@@ -1423,4 +1424,27 @@ config SERIAL_EFM32_UART_CONSOLE
depends on SERIAL_EFM32_UART=y
select SERIAL_CORE_CONSOLE
+config SERIAL_ARC
+ tristate "ARC UART driver support"
+ select SERIAL_CORE
+ help
+ Driver for on-chip UART for ARC(Synopsys) for the legacy
+ FPGA Boards (ML50x/ARCAngel4)
+
+config SERIAL_ARC_CONSOLE
+ bool "Console on ARC UART"
+ depends on SERIAL_ARC=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Enable system Console on ARC UART
+
+config SERIAL_ARC_NR_PORTS
+ int "Number of ARC UART ports"
+ depends on SERIAL_ARC
+ range 1 3
+ default "1"
+ help
+ Set this to the number of serial ports you want the driver
+ to support.
+
endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 4f694dafa719..df1b998c436b 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -82,3 +82,4 @@ obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
+obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 530181e49f6b..872f14ae43d2 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -406,7 +406,7 @@ static struct uart_driver altera_jtaguart_driver = {
.cons = ALTERA_JTAGUART_CONSOLE,
};
-static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
+static int altera_jtaguart_probe(struct platform_device *pdev)
{
struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
@@ -453,7 +453,7 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
+static int altera_jtaguart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i = pdev->id;
@@ -477,7 +477,7 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
- .remove = __devexit_p(altera_jtaguart_remove),
+ .remove = altera_jtaguart_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 15d80b9fb303..684a0808e1c7 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -532,7 +532,7 @@ static int altera_uart_get_of_uartclk(struct platform_device *pdev,
}
#endif /* CONFIG_OF */
-static int __devinit altera_uart_probe(struct platform_device *pdev)
+static int altera_uart_probe(struct platform_device *pdev)
{
struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
@@ -598,7 +598,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit altera_uart_remove(struct platform_device *pdev)
+static int altera_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
@@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, altera_uart_match);
static struct platform_driver altera_uart_platform_driver = {
.probe = altera_uart_probe,
- .remove = __devexit_p(altera_uart_remove),
+ .remove = altera_uart_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d7e1edec50b5..7fca4022a8b2 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -56,8 +56,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#define UART_NR 14
@@ -1973,7 +1972,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto out;
}
- uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+ uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
if (uap == NULL) {
ret = -ENOMEM;
goto out;
@@ -1981,16 +1981,17 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
i = pl011_probe_dt_alias(i, &dev->dev);
- base = ioremap(dev->res.start, resource_size(&dev->res));
+ base = devm_ioremap(&dev->dev, dev->res.start,
+ resource_size(&dev->res));
if (!base) {
ret = -ENOMEM;
- goto free;
+ goto out;
}
uap->pinctrl = devm_pinctrl_get(&dev->dev);
if (IS_ERR(uap->pinctrl)) {
ret = PTR_ERR(uap->pinctrl);
- goto unmap;
+ goto out;
}
uap->pins_default = pinctrl_lookup_state(uap->pinctrl,
PINCTRL_STATE_DEFAULT);
@@ -2002,10 +2003,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (IS_ERR(uap->pins_sleep))
dev_dbg(&dev->dev, "could not get sleep pinstate\n");
- uap->clk = clk_get(&dev->dev, NULL);
+ uap->clk = devm_clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
- goto unmap;
+ goto out;
}
uap->vendor = vendor;
@@ -2038,11 +2039,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
pl011_dma_remove(uap);
- clk_put(uap->clk);
- unmap:
- iounmap(base);
- free:
- kfree(uap);
}
out:
return ret;
@@ -2062,9 +2058,6 @@ static int pl011_remove(struct amba_device *dev)
amba_ports[i] = NULL;
pl011_dma_remove(uap);
- iounmap(uap->port.membase);
- clk_put(uap->clk);
- kfree(uap);
return 0;
}
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 7162f70d9260..59ae2b53e765 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -554,7 +554,7 @@ static struct uart_driver grlib_apbuart_driver = {
/* OF Platform Driver */
/* ======================================================================== */
-static int __devinit apbuart_probe(struct platform_device *op)
+static int apbuart_probe(struct platform_device *op)
{
int i;
struct uart_port *port = NULL;
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index e4f60e2b87f3..505c490c0b44 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -25,11 +25,19 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <asm/div64.h>
+
#include <asm/mach-ath79/ar933x_uart.h>
#include <asm/mach-ath79/ar933x_uart_platform.h>
#define DRIVER_NAME "ar933x-uart"
+#define AR933X_UART_MAX_SCALE 0xff
+#define AR933X_UART_MAX_STEP 0xffff
+
+#define AR933X_UART_MIN_BAUD 300
+#define AR933X_UART_MAX_BAUD 3000000
+
#define AR933X_DUMMY_STATUS_RD 0x01
static struct uart_driver ar933x_uart_driver;
@@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_driver;
struct ar933x_uart_port {
struct uart_port port;
unsigned int ier; /* shadow Interrupt Enable Register */
+ unsigned int min_baud;
+ unsigned int max_baud;
};
static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
@@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct uart_port *port)
{
}
+/*
+ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
+ */
+static unsigned long ar933x_uart_get_baud(unsigned int clk,
+ unsigned int scale,
+ unsigned int step)
+{
+ u64 t;
+ u32 div;
+
+ div = (2 << 16) * (scale + 1);
+ t = clk;
+ t *= step;
+ t += (div / 2);
+ do_div(t, div);
+
+ return t;
+}
+
+static void ar933x_uart_get_scale_step(unsigned int clk,
+ unsigned int baud,
+ unsigned int *scale,
+ unsigned int *step)
+{
+ unsigned int tscale;
+ long min_diff;
+
+ *scale = 0;
+ *step = 0;
+
+ min_diff = baud;
+ for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
+ u64 tstep;
+ int diff;
+
+ tstep = baud * (tscale + 1);
+ tstep *= (2 << 16);
+ do_div(tstep, clk);
+
+ if (tstep > AR933X_UART_MAX_STEP)
+ break;
+
+ diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
+ if (diff < min_diff) {
+ min_diff = diff;
+ *scale = tscale;
+ *step = tstep;
+ }
+ }
+}
+
static void ar933x_uart_set_termios(struct uart_port *port,
struct ktermios *new,
struct ktermios *old)
@@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(struct uart_port *port,
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
unsigned int cs;
unsigned long flags;
- unsigned int baud, scale;
+ unsigned int baud, scale, step;
/* Only CS8 is supported */
new->c_cflag &= ~CSIZE;
@@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(struct uart_port *port,
/* Mark/space parity is not supported */
new->c_cflag &= ~CMSPAR;
- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
- scale = (port->uartclk / (16 * baud)) - 1;
+ baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
+ ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
/*
* Ok, we're now changing the port state. Do it with
@@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(struct uart_port *port,
*/
spin_lock_irqsave(&up->port.lock, flags);
+ /* disable the UART */
+ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
+ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
+
/* Update the per-port timeout. */
uart_update_timeout(port, new->c_cflag, baud);
@@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(struct uart_port *port,
up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
- scale << AR933X_UART_CLOCK_SCALE_S | 8192);
+ scale << AR933X_UART_CLOCK_SCALE_S | step);
/* setup configuration register */
ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
@@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(struct uart_port *port,
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_HOST_INT_EN);
+ /* reenable the UART */
+ ar933x_uart_rmw(up, AR933X_UART_CS_REG,
+ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
+ AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
+
spin_unlock_irqrestore(&up->port.lock, flags);
if (tty_termios_baud_rate(new))
@@ -401,6 +471,8 @@ static void ar933x_uart_config_port(struct uart_port *port, int flags)
static int ar933x_uart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
+ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
if (ser->type != PORT_UNKNOWN &&
ser->type != PORT_AR933X)
return -EINVAL;
@@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struct uart_port *port,
if (ser->irq < 0 || ser->irq >= NR_IRQS)
return -EINVAL;
- if (ser->baud_base < 28800)
+ if (ser->baud_base < up->min_baud ||
+ ser->baud_base > up->max_baud)
return -EINVAL;
return 0;
@@ -554,13 +627,14 @@ static struct uart_driver ar933x_uart_driver = {
.cons = AR933X_SERIAL_CONSOLE,
};
-static int __devinit ar933x_uart_probe(struct platform_device *pdev)
+static int ar933x_uart_probe(struct platform_device *pdev)
{
struct ar933x_uart_platform_data *pdata;
struct ar933x_uart_port *up;
struct uart_port *port;
struct resource *mem_res;
struct resource *irq_res;
+ unsigned int baud;
int id;
int ret;
@@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(struct platform_device *pdev)
port->fifosize = AR933X_UART_FIFO_SIZE;
port->ops = &ar933x_uart_ops;
+ baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
+ up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
+
+ baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
+ up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
+
ar933x_uart_add_console_port(up);
ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
@@ -627,7 +707,7 @@ err_free_up:
return ret;
}
-static int __devexit ar933x_uart_remove(struct platform_device *pdev)
+static int ar933x_uart_remove(struct platform_device *pdev)
{
struct ar933x_uart_port *up;
@@ -645,7 +725,7 @@ static int __devexit ar933x_uart_remove(struct platform_device *pdev)
static struct platform_driver ar933x_uart_platform_driver = {
.probe = ar933x_uart_probe,
- .remove = __devexit_p(ar933x_uart_remove),
+ .remove = ar933x_uart_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
new file mode 100644
index 000000000000..3e0b3fac6a0e
--- /dev/null
+++ b/drivers/tty/serial/arc_uart.c
@@ -0,0 +1,746 @@
+/*
+ * ARC On-Chip(fpga) UART Driver
+ *
+ * Copyright (C) 2010-2012 Synopsys, Inc. (www.synopsys.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.
+ *
+ * vineetg: July 10th 2012
+ * -Decoupled the driver from arch/arc
+ * +Using platform_get_resource() for irq/membase (thx to bfin_uart.c)
+ * +Using early_platform_xxx() for early console (thx to mach-shmobile/xxx)
+ *
+ * Vineetg: Aug 21st 2010
+ * -Is uart_tx_stopped() not done in tty write path as it has already been
+ * taken care of, in serial core
+ *
+ * Vineetg: Aug 18th 2010
+ * -New Serial Core based ARC UART driver
+ * -Derived largely from blackfin driver albiet with some major tweaks
+ *
+ * TODO:
+ * -check if sysreq works
+ */
+
+#if defined(CONFIG_SERIAL_ARC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+/*************************************
+ * ARC UART Hardware Specs
+ ************************************/
+#define ARC_UART_TX_FIFO_SIZE 1
+
+/*
+ * UART Register set (this is not a Standards Compliant IP)
+ * Also each reg is Word aligned, but only 8 bits wide
+ */
+#define R_ID0 0
+#define R_ID1 4
+#define R_ID2 8
+#define R_ID3 12
+#define R_DATA 16
+#define R_STS 20
+#define R_BAUDL 24
+#define R_BAUDH 28
+
+/* Bits for UART Status Reg (R/W) */
+#define RXIENB 0x04 /* Receive Interrupt Enable */
+#define TXIENB 0x40 /* Transmit Interrupt Enable */
+
+#define RXEMPTY 0x20 /* Receive FIFO Empty: No char receivede */
+#define TXEMPTY 0x80 /* Transmit FIFO Empty, thus char can be written into */
+
+#define RXFULL 0x08 /* Receive FIFO full */
+#define RXFULL1 0x10 /* Receive FIFO has space for 1 char (tot space=4) */
+
+#define RXFERR 0x01 /* Frame Error: Stop Bit not detected */
+#define RXOERR 0x02 /* OverFlow Err: Char recv but RXFULL still set */
+
+/* Uart bit fiddling helpers: lowest level */
+#define RBASE(uart, reg) (uart->port.membase + reg)
+#define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r))
+#define UART_REG_GET(u, r) readb(RBASE(u, r))
+
+#define UART_REG_OR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) | (v))
+#define UART_REG_CLR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) & ~(v))
+
+/* Uart bit fiddling helpers: API level */
+#define UART_SET_DATA(uart, val) UART_REG_SET(uart, R_DATA, val)
+#define UART_GET_DATA(uart) UART_REG_GET(uart, R_DATA)
+
+#define UART_SET_BAUDH(uart, val) UART_REG_SET(uart, R_BAUDH, val)
+#define UART_SET_BAUDL(uart, val) UART_REG_SET(uart, R_BAUDL, val)
+
+#define UART_CLR_STATUS(uart, val) UART_REG_CLR(uart, R_STS, val)
+#define UART_GET_STATUS(uart) UART_REG_GET(uart, R_STS)
+
+#define UART_ALL_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB|TXIENB)
+#define UART_RX_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB)
+#define UART_TX_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, TXIENB)
+
+#define UART_ALL_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, RXIENB|TXIENB)
+#define UART_RX_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, RXIENB)
+#define UART_TX_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, TXIENB)
+
+#define ARC_SERIAL_DEV_NAME "ttyARC"
+
+struct arc_uart_port {
+ struct uart_port port;
+ unsigned long baud;
+ int is_emulated; /* H/w vs. Instruction Set Simulator */
+};
+
+#define to_arc_port(uport) container_of(uport, struct arc_uart_port, port)
+
+static struct arc_uart_port arc_uart_ports[CONFIG_SERIAL_ARC_NR_PORTS];
+
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+static struct console arc_console;
+#endif
+
+#define DRIVER_NAME "arc-uart"
+
+static struct uart_driver arc_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = DRIVER_NAME,
+ .dev_name = ARC_SERIAL_DEV_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = CONFIG_SERIAL_ARC_NR_PORTS,
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+ .cons = &arc_console,
+#endif
+};
+
+static void arc_serial_stop_rx(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ UART_RX_IRQ_DISABLE(uart);
+}
+
+static void arc_serial_stop_tx(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ while (!(UART_GET_STATUS(uart) & TXEMPTY))
+ cpu_relax();
+
+ UART_TX_IRQ_DISABLE(uart);
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int arc_serial_tx_empty(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+ unsigned int stat;
+
+ stat = UART_GET_STATUS(uart);
+ if (stat & TXEMPTY)
+ return TIOCSER_TEMT;
+
+ return 0;
+}
+
+/*
+ * Driver internal routine, used by both tty(serial core) as well as tx-isr
+ * -Called under spinlock in either cases
+ * -also tty->stopped / tty->hw_stopped has already been checked
+ * = by uart_start( ) before calling us
+ * = tx_ist checks that too before calling
+ */
+static void arc_serial_tx_chars(struct arc_uart_port *uart)
+{
+ struct circ_buf *xmit = &uart->port.state->xmit;
+ int sent = 0;
+ unsigned char ch;
+
+ if (unlikely(uart->port.x_char)) {
+ UART_SET_DATA(uart, uart->port.x_char);
+ uart->port.icount.tx++;
+ uart->port.x_char = 0;
+ sent = 1;
+ } else if (xmit->tail != xmit->head) { /* TODO: uart_circ_empty */
+ ch = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx++;
+ while (!(UART_GET_STATUS(uart) & TXEMPTY))
+ cpu_relax();
+ UART_SET_DATA(uart, ch);
+ sent = 1;
+ }
+
+ /*
+ * If num chars in xmit buffer are too few, ask tty layer for more.
+ * By Hard ISR to schedule processing in software interrupt part
+ */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&uart->port);
+
+ if (sent)
+ UART_TX_IRQ_ENABLE(uart);
+}
+
+/*
+ * port is locked and interrupts are disabled
+ * uart_start( ) calls us under the port spinlock irqsave
+ */
+static void arc_serial_start_tx(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ arc_serial_tx_chars(uart);
+}
+
+static void arc_serial_rx_chars(struct arc_uart_port *uart)
+{
+ struct tty_struct *tty = tty_port_tty_get(&uart->port.state->port);
+ unsigned int status, ch, flg = 0;
+
+ if (!tty)
+ return;
+
+ /*
+ * UART has 4 deep RX-FIFO. Driver's recongnition of this fact
+ * is very subtle. Here's how ...
+ * Upon getting a RX-Intr, such that RX-EMPTY=0, meaning data available,
+ * driver reads the DATA Reg and keeps doing that in a loop, until
+ * RX-EMPTY=1. Multiple chars being avail, with a single Interrupt,
+ * before RX-EMPTY=0, implies some sort of buffering going on in the
+ * controller, which is indeed the Rx-FIFO.
+ */
+ while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) {
+
+ ch = UART_GET_DATA(uart);
+ uart->port.icount.rx++;
+
+ if (unlikely(status & (RXOERR | RXFERR))) {
+ if (status & RXOERR) {
+ uart->port.icount.overrun++;
+ flg = TTY_OVERRUN;
+ UART_CLR_STATUS(uart, RXOERR);
+ }
+
+ if (status & RXFERR) {
+ uart->port.icount.frame++;
+ flg = TTY_FRAME;
+ UART_CLR_STATUS(uart, RXFERR);
+ }
+ } else
+ flg = TTY_NORMAL;
+
+ if (unlikely(uart_handle_sysrq_char(&uart->port, ch)))
+ goto done;
+
+ uart_insert_char(&uart->port, status, RXOERR, ch, flg);
+
+done:
+ tty_flip_buffer_push(tty);
+ }
+
+ tty_kref_put(tty);
+}
+
+/*
+ * A note on the Interrupt handling state machine of this driver
+ *
+ * kernel printk writes funnel thru the console driver framework and in order
+ * to keep things simple as well as efficient, it writes to UART in polled
+ * mode, in one shot, and exits.
+ *
+ * OTOH, Userland output (via tty layer), uses interrupt based writes as there
+ * can be undeterministic delay between char writes.
+ *
+ * Thus Rx-interrupts are always enabled, while tx-interrupts are by default
+ * disabled.
+ *
+ * When tty has some data to send out, serial core calls driver's start_tx
+ * which
+ * -checks-if-tty-buffer-has-char-to-send
+ * -writes-data-to-uart
+ * -enable-tx-intr
+ *
+ * Once data bits are pushed out, controller raises the Tx-room-avail-Interrupt.
+ * The first thing Tx ISR does is disable further Tx interrupts (as this could
+ * be the last char to send, before settling down into the quiet polled mode).
+ * It then calls the exact routine used by tty layer write to send out any
+ * more char in tty buffer. In case of sending, it re-enables Tx-intr. In case
+ * of no data, it remains disabled.
+ * This is how the transmit state machine is dynamically switched on/off
+ */
+
+static irqreturn_t arc_serial_isr(int irq, void *dev_id)
+{
+ struct arc_uart_port *uart = dev_id;
+ unsigned int status;
+
+ status = UART_GET_STATUS(uart);
+
+ /*
+ * Single IRQ for both Rx (data available) Tx (room available) Interrupt
+ * notifications from the UART Controller.
+ * To demultiplex between the two, we check the relevant bits
+ */
+ if ((status & RXIENB) && !(status & RXEMPTY)) {
+
+ /* already in ISR, no need of xx_irqsave */
+ spin_lock(&uart->port.lock);
+ arc_serial_rx_chars(uart);
+ spin_unlock(&uart->port.lock);
+ }
+
+ if ((status & TXIENB) && (status & TXEMPTY)) {
+
+ /* Unconditionally disable further Tx-Interrupts.
+ * will be enabled by tx_chars() if needed.
+ */
+ UART_TX_IRQ_DISABLE(uart);
+
+ spin_lock(&uart->port.lock);
+
+ if (!uart_tx_stopped(&uart->port))
+ arc_serial_tx_chars(uart);
+
+ spin_unlock(&uart->port.lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int arc_serial_get_mctrl(struct uart_port *port)
+{
+ /*
+ * Pretend we have a Modem status reg and following bits are
+ * always set, to satify the serial core state machine
+ * (DSR) Data Set Ready
+ * (CTS) Clear To Send
+ * (CAR) Carrier Detect
+ */
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void arc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* MCR not present */
+}
+
+/* Enable Modem Status Interrupts */
+
+static void arc_serial_enable_ms(struct uart_port *port)
+{
+ /* MSR not present */
+}
+
+static void arc_serial_break_ctl(struct uart_port *port, int break_state)
+{
+ /* ARC UART doesn't support sending Break signal */
+}
+
+static int arc_serial_startup(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ /* Before we hook up the ISR, Disable all UART Interrupts */
+ UART_ALL_IRQ_DISABLE(uart);
+
+ if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx",
+ uart)) {
+ dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n");
+ return -EBUSY;
+ }
+
+ UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */
+
+ return 0;
+}
+
+/* This is not really needed */
+static void arc_serial_shutdown(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+ free_irq(uart->port.irq, uart);
+}
+
+static void
+arc_serial_set_termios(struct uart_port *port, struct ktermios *new,
+ struct ktermios *old)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+ unsigned int baud, uartl, uarth, hw_val;
+ unsigned long flags;
+
+ /*
+ * Use the generic handler so that any specially encoded baud rates
+ * such as SPD_xx flags or "%B0" can be handled
+ * Max Baud I suppose will not be more than current 115K * 4
+ * Formula for ARC UART is: hw-val = ((CLK/(BAUD*4)) -1)
+ * spread over two 8-bit registers
+ */
+ baud = uart_get_baud_rate(port, new, old, 0, 460800);
+
+ hw_val = port->uartclk / (uart->baud * 4) - 1;
+ uartl = hw_val & 0xFF;
+ uarth = (hw_val >> 8) & 0xFF;
+
+ /*
+ * UART ISS(Instruction Set simulator) emulation has a subtle bug:
+ * A existing value of Baudh = 0 is used as a indication to startup
+ * it's internal state machine.
+ * Thus if baudh is set to 0, 2 times, it chokes.
+ * This happens with BAUD=115200 and the formaula above
+ * Until that is fixed, when running on ISS, we will set baudh to !0
+ */
+ if (uart->is_emulated)
+ uarth = 1;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ UART_ALL_IRQ_DISABLE(uart);
+
+ UART_SET_BAUDL(uart, uartl);
+ UART_SET_BAUDH(uart, uarth);
+
+ UART_RX_IRQ_ENABLE(uart);
+
+ /*
+ * UART doesn't support Parity/Hardware Flow Control;
+ * Only supports 8N1 character size
+ */
+ new->c_cflag &= ~(CMSPAR|CRTSCTS|CSIZE);
+ new->c_cflag |= CS8;
+
+ if (old)
+ tty_termios_copy_hw(new, old);
+
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(new))
+ tty_termios_encode_baud_rate(new, baud, baud);
+
+ uart_update_timeout(port, new->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *arc_serial_type(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL;
+}
+
+static void arc_serial_release_port(struct uart_port *port)
+{
+}
+
+static int arc_serial_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int
+arc_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if (port->type != PORT_UNKNOWN && ser->type != PORT_ARC)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void arc_serial_config_port(struct uart_port *port, int flags)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ if (flags & UART_CONFIG_TYPE)
+ uart->port.type = PORT_ARC;
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE)
+
+static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+
+ while (!(UART_GET_STATUS(uart) & TXEMPTY))
+ cpu_relax();
+
+ UART_SET_DATA(uart, chr);
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+static int arc_serial_poll_getchar(struct uart_port *port)
+{
+ struct arc_uart_port *uart = to_arc_port(port);
+ unsigned char chr;
+
+ while (!(UART_GET_STATUS(uart) & RXEMPTY))
+ cpu_relax();
+
+ chr = UART_GET_DATA(uart);
+ return chr;
+}
+#endif
+
+static struct uart_ops arc_serial_pops = {
+ .tx_empty = arc_serial_tx_empty,
+ .set_mctrl = arc_serial_set_mctrl,
+ .get_mctrl = arc_serial_get_mctrl,
+ .stop_tx = arc_serial_stop_tx,
+ .start_tx = arc_serial_start_tx,
+ .stop_rx = arc_serial_stop_rx,
+ .enable_ms = arc_serial_enable_ms,
+ .break_ctl = arc_serial_break_ctl,
+ .startup = arc_serial_startup,
+ .shutdown = arc_serial_shutdown,
+ .set_termios = arc_serial_set_termios,
+ .type = arc_serial_type,
+ .release_port = arc_serial_release_port,
+ .request_port = arc_serial_request_port,
+ .config_port = arc_serial_config_port,
+ .verify_port = arc_serial_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_put_char = arc_serial_poll_putchar,
+ .poll_get_char = arc_serial_poll_getchar,
+#endif
+};
+
+static int
+arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
+{
+ struct resource *res, *res2;
+ unsigned long *plat_data;
+
+ if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_ARC_NR_PORTS) {
+ dev_err(&pdev->dev, "Wrong uart platform device id.\n");
+ return -ENOENT;
+ }
+
+ plat_data = ((unsigned long *)(pdev->dev.platform_data));
+ uart->baud = plat_data[0];
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ uart->port.mapbase = res->start;
+ uart->port.membase = ioremap_nocache(res->start, resource_size(res));
+ if (!uart->port.membase)
+ /* No point of dev_err since UART itself is hosed here */
+ return -ENXIO;
+
+ uart->port.irq = res2->start;
+ uart->port.dev = &pdev->dev;
+ uart->port.iotype = UPIO_MEM;
+ uart->port.flags = UPF_BOOT_AUTOCONF;
+ uart->port.line = pdev->id;
+ uart->port.ops = &arc_serial_pops;
+
+ uart->port.uartclk = plat_data[1];
+ uart->port.fifosize = ARC_UART_TX_FIFO_SIZE;
+
+ /*
+ * uart_insert_char( ) uses it in decideding whether to ignore a
+ * char or not. Explicitly setting it here, removes the subtelty
+ */
+ uart->port.ignore_status_mask = 0;
+
+ /* Real Hardware vs. emulated to work around a bug */
+ uart->is_emulated = !!plat_data[2];
+
+ return 0;
+}
+
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+
+static int arc_serial_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= CONFIG_SERIAL_ARC_NR_PORTS)
+ return -ENODEV;
+
+ /*
+ * The uart port backing the console (e.g. ttyARC1) might not have been
+ * init yet. If so, defer the console setup to after the port.
+ */
+ port = &arc_uart_ports[co->index].port;
+ if (!port->membase)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ /*
+ * Serial core will call port->ops->set_termios( )
+ * which will set the baud reg
+ */
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static void arc_serial_console_putchar(struct uart_port *port, int ch)
+{
+ arc_serial_poll_putchar(port, (unsigned char)ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void arc_serial_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &arc_uart_ports[co->index].port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ uart_console_write(port, s, count, arc_serial_console_putchar);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static struct console arc_console = {
+ .name = ARC_SERIAL_DEV_NAME,
+ .write = arc_serial_console_write,
+ .device = uart_console_device,
+ .setup = arc_serial_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &arc_uart_driver
+};
+
+static __init void early_serial_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ struct uart_port *port = &arc_uart_ports[con->index].port;
+ unsigned int i;
+
+ for (i = 0; i < n; i++, s++) {
+ if (*s == '\n')
+ arc_serial_poll_putchar(port, '\r');
+ arc_serial_poll_putchar(port, *s);
+ }
+}
+
+static struct __initdata console arc_early_serial_console = {
+ .name = "early_ARCuart",
+ .write = early_serial_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1
+};
+
+static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
+{
+ arc_early_serial_console.index = pdev->id;
+
+ arc_uart_init_one(pdev, &arc_uart_ports[pdev->id]);
+
+ arc_serial_console_setup(&arc_early_serial_console, NULL);
+
+ register_console(&arc_early_serial_console);
+ return 0;
+}
+#else
+static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
+
+static int arc_serial_probe(struct platform_device *pdev)
+{
+ struct arc_uart_port *uart;
+ int rc;
+
+ if (is_early_platform_device(pdev))
+ return arc_serial_probe_earlyprintk(pdev);
+
+ uart = &arc_uart_ports[pdev->id];
+ rc = arc_uart_init_one(pdev, uart);
+ if (rc)
+ return rc;
+
+ return uart_add_one_port(&arc_uart_driver, &uart->port);
+}
+
+static int arc_serial_remove(struct platform_device *pdev)
+{
+ /* This will never be called */
+ return 0;
+}
+
+static struct platform_driver arc_platform_driver = {
+ .probe = arc_serial_probe,
+ .remove = arc_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+/*
+ * Register an early platform driver of "earlyprintk" class.
+ * ARCH platform code installs the driver and probes the early devices
+ * The installation could rely on user specifying earlyprintk=xyx in cmd line
+ * or it could be done independently, for all "earlyprintk" class drivers.
+ * [see arch/arc/plat-arcfpga/platform.c]
+ */
+early_platform_init("earlyprintk", &arc_platform_driver);
+
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
+
+static int __init arc_serial_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&arc_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&arc_platform_driver);
+ if (ret)
+ uart_unregister_driver(&arc_uart_driver);
+
+ return ret;
+}
+
+static void __exit arc_serial_exit(void)
+{
+ platform_driver_unregister(&arc_platform_driver);
+ uart_unregister_driver(&arc_uart_driver);
+}
+
+module_init(arc_serial_init);
+module_exit(arc_serial_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_AUTHOR("Vineet Gupta");
+MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 3d7e1ee2fa57..922e85aeb63a 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -39,13 +39,12 @@
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
#include <linux/uaccess.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/atmel.h>
#include <asm/io.h>
#include <asm/ioctls.h>
-#include <asm/mach/serial_at91.h>
-#include <mach/board.h>
-
#ifdef CONFIG_ARM
#include <mach/cpu.h>
#include <asm/gpio.h>
@@ -1423,7 +1422,7 @@ static struct uart_ops atmel_pops = {
#endif
};
-static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
+static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
struct device_node *np)
{
u32 rs485_delay[2];
@@ -1458,7 +1457,7 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
/*
* Configure the port from the platform device resource info.
*/
-static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+static void atmel_init_port(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
struct uart_port *port = &atmel_port->uart;
@@ -1513,23 +1512,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
}
}
-/*
- * Register board-specific modem-control line handlers.
- */
-void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
-{
- if (fns->enable_ms)
- atmel_pops.enable_ms = fns->enable_ms;
- if (fns->get_mctrl)
- atmel_pops.get_mctrl = fns->get_mctrl;
- if (fns->set_mctrl)
- atmel_pops.set_mctrl = fns->set_mctrl;
- atmel_open_hook = fns->open;
- atmel_close_hook = fns->close;
- atmel_pops.pm = fns->pm;
- atmel_pops.set_wake = fns->set_wake;
-}
-
struct platform_device *atmel_default_console_device; /* the serial console device */
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
@@ -1766,13 +1748,14 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
-static int __devinit atmel_serial_probe(struct platform_device *pdev)
+static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
struct device_node *np = pdev->dev.of_node;
struct atmel_uart_data *pdata = pdev->dev.platform_data;
void *data;
int ret = -ENODEV;
+ struct pinctrl *pinctrl;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
@@ -1805,6 +1788,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
atmel_init_port(port, pdev);
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto err;
+ }
+
if (!atmel_use_dma_rx(&port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
@@ -1851,7 +1840,7 @@ err:
return ret;
}
-static int __devexit atmel_serial_remove(struct platform_device *pdev)
+static int atmel_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -1876,7 +1865,7 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
- .remove = __devexit_p(atmel_serial_remove),
+ .remove = atmel_serial_remove,
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.driver = {
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index c0b68b9cad91..c76a226080f2 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -801,7 +801,7 @@ static struct uart_driver bcm_uart_driver = {
/*
* platform driver probe/remove callback
*/
-static int __devinit bcm_uart_probe(struct platform_device *pdev)
+static int bcm_uart_probe(struct platform_device *pdev)
{
struct resource *res_mem, *res_irq;
struct uart_port *port;
@@ -848,7 +848,7 @@ static int __devinit bcm_uart_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit bcm_uart_remove(struct platform_device *pdev)
+static int bcm_uart_remove(struct platform_device *pdev)
{
struct uart_port *port;
@@ -865,7 +865,7 @@ static int __devexit bcm_uart_remove(struct platform_device *pdev)
*/
static struct platform_driver bcm_uart_platform_driver = {
.probe = bcm_uart_probe,
- .remove = __devexit_p(bcm_uart_remove),
+ .remove = bcm_uart_remove,
.driver = {
.owner = THIS_MODULE,
.name = "bcm63xx_uart",
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
index 7fbc3a08f10d..f5d117379b60 100644
--- a/drivers/tty/serial/bfin_sport_uart.c
+++ b/drivers/tty/serial/bfin_sport_uart.c
@@ -740,7 +740,7 @@ static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
};
#endif
-static int __devinit sport_uart_probe(struct platform_device *pdev)
+static int sport_uart_probe(struct platform_device *pdev)
{
struct resource *res;
struct sport_uart_port *sport;
@@ -850,7 +850,7 @@ out_error_free_mem:
return ret;
}
-static int __devexit sport_uart_remove(struct platform_device *pdev)
+static int sport_uart_remove(struct platform_device *pdev)
{
struct sport_uart_port *sport = platform_get_drvdata(pdev);
@@ -871,7 +871,7 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
static struct platform_driver sport_uart_driver = {
.probe = sport_uart_probe,
- .remove = __devexit_p(sport_uart_remove),
+ .remove = sport_uart_remove,
.driver = {
.name = DRV_NAME,
#ifdef CONFIG_PM
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 9b11c3f23eae..2e2b2c1cb722 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -477,9 +477,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
int x_pos, pos;
+ unsigned long flags;
- dma_disable_irq_nosync(uart->rx_dma_channel);
- spin_lock_bh(&uart->rx_lock);
+ spin_lock_irqsave(&uart->rx_lock, flags);
/* 2D DMA RX buffer ring is used. Because curr_y_count and
* curr_x_count can't be read as an atomic operation,
@@ -510,8 +510,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
- spin_unlock_bh(&uart->rx_lock);
- dma_enable_irq(uart->rx_dma_channel);
+ spin_unlock_irqrestore(&uart->rx_lock, flags);
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
}
@@ -800,6 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags;
unsigned int baud, quot;
unsigned int ier, lcr = 0;
+ unsigned long timeout;
switch (termios->c_cflag & CSIZE) {
case CS8:
@@ -869,6 +869,14 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
+ /* Wait till the transfer buffer is empty */
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (UART_GET_GCTL(uart) & UCEN && !(UART_GET_LSR(uart) & TEMT))
+ if (time_after(jiffies, timeout)) {
+ dev_warn(port->dev, "timeout waiting for TX buffer empty\n");
+ break;
+ }
+
/* Disable UART */
ier = UART_GET_IER(uart);
UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
@@ -1390,7 +1398,7 @@ out_error_free_mem:
return ret;
}
-static int __devexit bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *pdev)
{
struct bfin_serial_port *uart = platform_get_drvdata(pdev);
@@ -1410,7 +1418,7 @@ static int __devexit bfin_serial_remove(struct platform_device *pdev)
static struct platform_driver bfin_serial_driver = {
.probe = bfin_serial_probe,
- .remove = __devexit_p(bfin_serial_remove),
+ .remove = bfin_serial_remove,
.suspend = bfin_serial_suspend,
.resume = bfin_serial_resume,
.driver = {
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index d0f719fafc84..3fd2526d121e 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -26,172 +17,169 @@
#endif
#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/spinlock.h>
#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
+#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#define UART_NR 2
-
-#define SERIAL_CLPS711X_MAJOR 204
-#define SERIAL_CLPS711X_MINOR 40
-#define SERIAL_CLPS711X_NR UART_NR
-
-/*
- * We use the relevant SYSCON register as a base address for these ports.
- */
-#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1)
-#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1)
-#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1)
-#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1)
-
-#define TX_IRQ(port) ((port)->irq)
-#define RX_IRQ(port) ((port)->irq + 1)
-#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
-#define tx_enabled(port) ((port)->unused[0])
+#define UART_CLPS711X_NAME "uart-clps711x"
+#define UART_CLPS711X_NR 2
+#define UART_CLPS711X_MAJOR 204
+#define UART_CLPS711X_MINOR 40
+
+#define UBRLCR(port) ((port)->line ? UBRLCR2 : UBRLCR1)
+#define UARTDR(port) ((port)->line ? UARTDR2 : UARTDR1)
+#define SYSFLG(port) ((port)->line ? SYSFLG2 : SYSFLG1)
+#define SYSCON(port) ((port)->line ? SYSCON2 : SYSCON1)
+#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
+#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
+
+struct clps711x_port {
+ struct uart_driver uart;
+ struct clk *uart_clk;
+ struct uart_port port[UART_CLPS711X_NR];
+ int tx_enabled[UART_CLPS711X_NR];
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+ struct console console;
+#endif
+};
-static void clps711xuart_stop_tx(struct uart_port *port)
+static void uart_clps711x_stop_tx(struct uart_port *port)
{
- if (tx_enabled(port)) {
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+ if (s->tx_enabled[port->line]) {
disable_irq(TX_IRQ(port));
- tx_enabled(port) = 0;
+ s->tx_enabled[port->line] = 0;
}
}
-static void clps711xuart_start_tx(struct uart_port *port)
+static void uart_clps711x_start_tx(struct uart_port *port)
{
- if (!tx_enabled(port)) {
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+ if (!s->tx_enabled[port->line]) {
enable_irq(TX_IRQ(port));
- tx_enabled(port) = 1;
+ s->tx_enabled[port->line] = 1;
}
}
-static void clps711xuart_stop_rx(struct uart_port *port)
+static void uart_clps711x_stop_rx(struct uart_port *port)
{
disable_irq(RX_IRQ(port));
}
-static void clps711xuart_enable_ms(struct uart_port *port)
+static void uart_clps711x_enable_ms(struct uart_port *port)
{
+ /* Do nothing */
}
-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
+static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- struct tty_struct *tty = port->state->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
unsigned int status, ch, flg;
- status = clps_readl(SYSFLG(port));
- while (!(status & SYSFLG_URXFE)) {
- ch = clps_readl(UARTDR(port));
+ if (!tty)
+ return IRQ_HANDLED;
- port->icount.rx++;
+ for (;;) {
+ status = clps_readl(SYSFLG(port));
+ if (status & SYSFLG_URXFE)
+ break;
+
+ ch = clps_readw(UARTDR(port));
+ status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
+ ch &= 0xff;
+ port->icount.rx++;
flg = TTY_NORMAL;
- /*
- * Note that the error handling code is
- * out of the main execution path
- */
- if (unlikely(ch & UART_ANY_ERR)) {
- if (ch & UARTDR_PARERR)
+ if (unlikely(status)) {
+ if (status & UARTDR_PARERR)
port->icount.parity++;
- else if (ch & UARTDR_FRMERR)
+ else if (status & UARTDR_FRMERR)
port->icount.frame++;
- if (ch & UARTDR_OVERR)
+ else if (status & UARTDR_OVERR)
port->icount.overrun++;
- ch &= port->read_status_mask;
+ status &= port->read_status_mask;
- if (ch & UARTDR_PARERR)
+ if (status & UARTDR_PARERR)
flg = TTY_PARITY;
- else if (ch & UARTDR_FRMERR)
+ else if (status & UARTDR_FRMERR)
flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
- port->sysrq = 0;
-#endif
+ else if (status & UARTDR_OVERR)
+ flg = TTY_OVERRUN;
}
if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
+ continue;
- /*
- * CHECK: does overrun affect the current character?
- * ASSUMPTION: it does not.
- */
- uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+ if (status & port->ignore_status_mask)
+ continue;
- ignore_char:
- status = clps_readl(SYSFLG(port));
+ uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
}
+
tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+
return IRQ_HANDLED;
}
-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
+static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
struct circ_buf *xmit = &port->state->xmit;
- int count;
if (port->x_char) {
- clps_writel(port->x_char, UARTDR(port));
+ clps_writew(port->x_char, UARTDR(port));
port->icount.tx++;
port->x_char = 0;
return IRQ_HANDLED;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- goto disable_tx_irq;
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ disable_irq_nosync(TX_IRQ(port));
+ s->tx_enabled[port->line] = 0;
+ return IRQ_HANDLED;
+ }
- count = port->fifosize >> 1;
- do {
- clps_writel(xmit->buf[xmit->tail], UARTDR(port));
+ while (!uart_circ_empty(xmit)) {
+ clps_writew(xmit->buf[xmit->tail], UARTDR(port));
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
- if (uart_circ_empty(xmit))
+ if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF))
break;
- } while (--count > 0);
+ }
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
- disable_tx_irq:
- disable_irq_nosync(TX_IRQ(port));
- tx_enabled(port) = 0;
- }
-
return IRQ_HANDLED;
}
-static unsigned int clps711xuart_tx_empty(struct uart_port *port)
+static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
{
- unsigned int status = clps_readl(SYSFLG(port));
- return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
+ return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT;
}
-static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
+static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
{
- unsigned int port_addr;
- unsigned int result = 0;
- unsigned int status;
+ unsigned int status, result = 0;
- port_addr = SYSFLG(port);
- if (port_addr == SYSFLG1) {
+ if (port->line == 0) {
status = clps_readl(SYSFLG1);
if (status & SYSFLG1_DCD)
result |= TIOCM_CAR;
@@ -199,104 +187,86 @@ static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
result |= TIOCM_DSR;
if (status & SYSFLG1_CTS)
result |= TIOCM_CTS;
- }
+ } else
+ result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
return result;
}
-static void
-clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ /* Do nothing */
}
-static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
+static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int ubrlcr;
spin_lock_irqsave(&port->lock, flags);
+
ubrlcr = clps_readl(UBRLCR(port));
- if (break_state == -1)
+ if (break_state)
ubrlcr |= UBRLCR_BREAK;
else
ubrlcr &= ~UBRLCR_BREAK;
clps_writel(ubrlcr, UBRLCR(port));
+
spin_unlock_irqrestore(&port->lock, flags);
}
-static int clps711xuart_startup(struct uart_port *port)
+static int uart_clps711x_startup(struct uart_port *port)
{
- unsigned int syscon;
- int retval;
-
- tx_enabled(port) = 1;
-
- /*
- * Allocate the IRQs
- */
- retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
- "clps711xuart_tx", port);
- if (retval)
- return retval;
-
- retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
- "clps711xuart_rx", port);
- if (retval) {
- free_irq(TX_IRQ(port), port);
- return retval;
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
+ int ret;
+
+ s->tx_enabled[port->line] = 1;
+ /* Allocate the IRQs */
+ ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx,
+ 0, UART_CLPS711X_NAME " TX", port);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx,
+ 0, UART_CLPS711X_NAME " RX", port);
+ if (ret) {
+ devm_free_irq(port->dev, TX_IRQ(port), port);
+ return ret;
}
- /*
- * enable the port
- */
- syscon = clps_readl(SYSCON(port));
- syscon |= SYSCON_UARTEN;
- clps_writel(syscon, SYSCON(port));
+ /* Disable break */
+ clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port));
+
+ /* Enable the port */
+ clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port));
return 0;
}
-static void clps711xuart_shutdown(struct uart_port *port)
+static void uart_clps711x_shutdown(struct uart_port *port)
{
- unsigned int ubrlcr, syscon;
+ /* Free the interrupts */
+ devm_free_irq(port->dev, TX_IRQ(port), port);
+ devm_free_irq(port->dev, RX_IRQ(port), port);
- /*
- * Free the interrupt
- */
- free_irq(TX_IRQ(port), port); /* TX interrupt */
- free_irq(RX_IRQ(port), port); /* RX interrupt */
-
- /*
- * disable the port
- */
- syscon = clps_readl(SYSCON(port));
- syscon &= ~SYSCON_UARTEN;
- clps_writel(syscon, SYSCON(port));
-
- /*
- * disable break condition and fifos
- */
- ubrlcr = clps_readl(UBRLCR(port));
- ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
- clps_writel(ubrlcr, UBRLCR(port));
+ /* Disable the port */
+ clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port));
}
-static void
-clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static void uart_clps711x_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int ubrlcr, baud, quot;
unsigned long flags;
- /*
- * We don't implement CREAD.
- */
- termios->c_cflag |= CREAD;
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+ termios->c_iflag &= ~(BRKINT | IGNBRK);
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ /* Ask the core to calculate the divisor for us */
+ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096,
+ port->uartclk / 16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
@@ -309,160 +279,117 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
case CS7:
ubrlcr = UBRLCR_WRDLEN7;
break;
- default: // CS8
+ case CS8:
+ default:
ubrlcr = UBRLCR_WRDLEN8;
break;
}
+
if (termios->c_cflag & CSTOPB)
ubrlcr |= UBRLCR_XSTOP;
+
if (termios->c_cflag & PARENB) {
ubrlcr |= UBRLCR_PRTEN;
if (!(termios->c_cflag & PARODD))
ubrlcr |= UBRLCR_EVENPRT;
}
- if (port->fifosize > 1)
- ubrlcr |= UBRLCR_FIFOEN;
- spin_lock_irqsave(&port->lock, flags);
+ /* Enable FIFO */
+ ubrlcr |= UBRLCR_FIFOEN;
- /*
- * Update the per-port timeout.
- */
- uart_update_timeout(port, termios->c_cflag, baud);
+ spin_lock_irqsave(&port->lock, flags);
+ /* Set read status mask */
port->read_status_mask = UARTDR_OVERR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
- /*
- * Characters to ignore
- */
+ /* Set status ignore mask */
port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
- if (termios->c_iflag & IGNBRK) {
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns to (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UARTDR_OVERR;
- }
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= UARTDR_OVERR | UARTDR_PARERR |
+ UARTDR_FRMERR;
- quot -= 1;
+ uart_update_timeout(port, termios->c_cflag, baud);
- clps_writel(ubrlcr | quot, UBRLCR(port));
+ clps_writel(ubrlcr | (quot - 1), UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags);
}
-static const char *clps711xuart_type(struct uart_port *port)
+static const char *uart_clps711x_type(struct uart_port *port)
{
- return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
+ return (port->type == PORT_CLPS711X) ? "CLPS711X" : NULL;
}
-/*
- * Configure/autoconfigure the port.
- */
-static void clps711xuart_config_port(struct uart_port *port, int flags)
+static void uart_clps711x_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_CLPS711X;
}
-static void clps711xuart_release_port(struct uart_port *port)
+static void uart_clps711x_release_port(struct uart_port *port)
{
+ /* Do nothing */
}
-static int clps711xuart_request_port(struct uart_port *port)
+static int uart_clps711x_request_port(struct uart_port *port)
{
+ /* Do nothing */
return 0;
}
-static struct uart_ops clps711x_pops = {
- .tx_empty = clps711xuart_tx_empty,
- .set_mctrl = clps711xuart_set_mctrl_null,
- .get_mctrl = clps711xuart_get_mctrl,
- .stop_tx = clps711xuart_stop_tx,
- .start_tx = clps711xuart_start_tx,
- .stop_rx = clps711xuart_stop_rx,
- .enable_ms = clps711xuart_enable_ms,
- .break_ctl = clps711xuart_break_ctl,
- .startup = clps711xuart_startup,
- .shutdown = clps711xuart_shutdown,
- .set_termios = clps711xuart_set_termios,
- .type = clps711xuart_type,
- .config_port = clps711xuart_config_port,
- .release_port = clps711xuart_release_port,
- .request_port = clps711xuart_request_port,
-};
-
-static struct uart_port clps711x_ports[UART_NR] = {
- {
- .iobase = SYSCON1,
- .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
- .uartclk = 3686400,
- .fifosize = 16,
- .ops = &clps711x_pops,
- .line = 0,
- .flags = UPF_BOOT_AUTOCONF,
- },
- {
- .iobase = SYSCON2,
- .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */
- .uartclk = 3686400,
- .fifosize = 16,
- .ops = &clps711x_pops,
- .line = 1,
- .flags = UPF_BOOT_AUTOCONF,
- }
+static const struct uart_ops uart_clps711x_ops = {
+ .tx_empty = uart_clps711x_tx_empty,
+ .set_mctrl = uart_clps711x_set_mctrl,
+ .get_mctrl = uart_clps711x_get_mctrl,
+ .stop_tx = uart_clps711x_stop_tx,
+ .start_tx = uart_clps711x_start_tx,
+ .stop_rx = uart_clps711x_stop_rx,
+ .enable_ms = uart_clps711x_enable_ms,
+ .break_ctl = uart_clps711x_break_ctl,
+ .startup = uart_clps711x_startup,
+ .shutdown = uart_clps711x_shutdown,
+ .set_termios = uart_clps711x_set_termios,
+ .type = uart_clps711x_type,
+ .config_port = uart_clps711x_config_port,
+ .release_port = uart_clps711x_release_port,
+ .request_port = uart_clps711x_request_port,
};
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-static void clps711xuart_console_putchar(struct uart_port *port, int ch)
+static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
{
while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
barrier();
- clps_writel(ch, UARTDR(port));
+
+ clps_writew(ch, UARTDR(port));
}
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console_lock must be held when we get here.
- *
- * Note that this is called with interrupts already disabled
- */
-static void
-clps711xuart_console_write(struct console *co, const char *s,
- unsigned int count)
+static void uart_clps711x_console_write(struct console *co, const char *c,
+ unsigned n)
{
- struct uart_port *port = clps711x_ports + co->index;
- unsigned int status, syscon;
+ struct clps711x_port *s = (struct clps711x_port *)co->data;
+ struct uart_port *port = &s->port[co->index];
+ u32 syscon;
- /*
- * Ensure that the port is enabled.
- */
+ /* Ensure that the port is enabled */
syscon = clps_readl(SYSCON(port));
clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
- uart_console_write(port, s, count, clps711xuart_console_putchar);
+ uart_console_write(port, c, n, uart_clps711x_console_putchar);
- /*
- * Finally, wait for transmitter to become empty
- * and restore the uart state.
- */
- do {
- status = clps_readl(SYSFLG(port));
- } while (status & SYSFLG_UBUSY);
+ /* Wait for transmitter to become empty */
+ while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY)
+ barrier();
+ /* Restore the uart state */
clps_writel(syscon, SYSCON(port));
}
-static void __init
-clps711xuart_console_get_options(struct uart_port *port, int *baud,
- int *parity, int *bits)
+static void uart_clps711x_console_get_options(struct uart_port *port,
+ int *baud, int *parity,
+ int *bits)
{
if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
unsigned int ubrlcr, quot;
@@ -487,92 +414,124 @@ clps711xuart_console_get_options(struct uart_port *port, int *baud,
}
}
-static int __init clps711xuart_console_setup(struct console *co, char *options)
+static int uart_clps711x_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
- int baud = 38400;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- /*
- * Check whether an invalid uart number has been specified, and
- * if so, search for the first available port that does have
- * console support.
- */
- port = uart_get_console(clps711x_ports, UART_NR, co);
+ int baud = 38400, bits = 8, parity = 'n', flow = 'n';
+ struct clps711x_port *s = (struct clps711x_port *)co->data;
+ struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- clps711xuart_console_get_options(port, &baud, &parity, &bits);
+ uart_clps711x_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
+#endif
-static struct uart_driver clps711x_reg;
-static struct console clps711x_console = {
- .name = "ttyCL",
- .write = clps711xuart_console_write,
- .device = uart_console_device,
- .setup = clps711xuart_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &clps711x_reg,
-};
-
-static int __init clps711xuart_console_init(void)
+static int uart_clps711x_probe(struct platform_device *pdev)
{
- register_console(&clps711x_console);
- return 0;
-}
-console_initcall(clps711xuart_console_init);
+ struct clps711x_port *s;
+ int ret, i;
+
+ s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL);
+ if (!s) {
+ dev_err(&pdev->dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, s);
-#define CLPS711X_CONSOLE &clps711x_console
-#else
-#define CLPS711X_CONSOLE NULL
+ s->uart_clk = devm_clk_get(&pdev->dev, "uart");
+ if (IS_ERR(s->uart_clk)) {
+ dev_err(&pdev->dev, "Can't get UART clocks\n");
+ ret = PTR_ERR(s->uart_clk);
+ goto err_out;
+ }
+
+ s->uart.owner = THIS_MODULE;
+ s->uart.dev_name = "ttyCL";
+ s->uart.major = UART_CLPS711X_MAJOR;
+ s->uart.minor = UART_CLPS711X_MINOR;
+ s->uart.nr = UART_CLPS711X_NR;
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+ s->uart.cons = &s->console;
+ s->uart.cons->device = uart_console_device;
+ s->uart.cons->write = uart_clps711x_console_write;
+ s->uart.cons->setup = uart_clps711x_console_setup;
+ s->uart.cons->flags = CON_PRINTBUFFER;
+ s->uart.cons->index = -1;
+ s->uart.cons->data = s;
+ strcpy(s->uart.cons->name, "ttyCL");
#endif
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering UART driver failed\n");
+ devm_clk_put(&pdev->dev, s->uart_clk);
+ goto err_out;
+ }
-static struct uart_driver clps711x_reg = {
- .driver_name = "ttyCL",
- .dev_name = "ttyCL",
- .major = SERIAL_CLPS711X_MAJOR,
- .minor = SERIAL_CLPS711X_MINOR,
- .nr = UART_NR,
+ for (i = 0; i < UART_CLPS711X_NR; i++) {
+ s->port[i].line = i;
+ s->port[i].dev = &pdev->dev;
+ s->port[i].irq = TX_IRQ(&s->port[i]);
+ s->port[i].iobase = SYSCON(&s->port[i]);
+ s->port[i].type = PORT_CLPS711X;
+ s->port[i].fifosize = 16;
+ s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+ s->port[i].uartclk = clk_get_rate(s->uart_clk);
+ s->port[i].ops = &uart_clps711x_ops;
+ WARN_ON(uart_add_one_port(&s->uart, &s->port[i]));
+ }
- .cons = CLPS711X_CONSOLE,
-};
+ return 0;
-static int __init clps711xuart_init(void)
-{
- int ret, i;
+err_out:
+ platform_set_drvdata(pdev, NULL);
- printk(KERN_INFO "Serial: CLPS711x driver\n");
+ return ret;
+}
- ret = uart_register_driver(&clps711x_reg);
- if (ret)
- return ret;
+static int uart_clps711x_remove(struct platform_device *pdev)
+{
+ struct clps711x_port *s = platform_get_drvdata(pdev);
+ int i;
- for (i = 0; i < UART_NR; i++)
- uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
+ for (i = 0; i < UART_CLPS711X_NR; i++)
+ uart_remove_one_port(&s->uart, &s->port[i]);
+
+ devm_clk_put(&pdev->dev, s->uart_clk);
+ uart_unregister_driver(&s->uart);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
-static void __exit clps711xuart_exit(void)
-{
- int i;
+static struct platform_driver clps711x_uart_driver = {
+ .driver = {
+ .name = UART_CLPS711X_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = uart_clps711x_probe,
+ .remove = uart_clps711x_remove,
+};
+module_platform_driver(clps711x_uart_driver);
- for (i = 0; i < UART_NR; i++)
- uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
+static struct platform_device clps711x_uart_device = {
+ .name = UART_CLPS711X_NAME,
+};
- uart_unregister_driver(&clps711x_reg);
+static int __init uart_clps711x_init(void)
+{
+ return platform_device_register(&clps711x_uart_device);
}
+module_init(uart_clps711x_init);
-module_init(clps711xuart_init);
-module_exit(clps711xuart_exit);
+static void __exit uart_clps711x_exit(void)
+{
+ platform_device_unregister(&clps711x_uart_device);
+}
+module_exit(uart_clps711x_exit);
MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("CLPS-711x generic serial driver");
+MODULE_DESCRIPTION("CLPS711X serial driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index d0dd9194cecc..ad0caf176808 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1373,7 +1373,7 @@ static struct uart_driver cpm_reg = {
static int probe_index;
-static int __devinit cpm_uart_probe(struct platform_device *ofdev)
+static int cpm_uart_probe(struct platform_device *ofdev)
{
int index = probe_index++;
struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
@@ -1396,7 +1396,7 @@ static int __devinit cpm_uart_probe(struct platform_device *ofdev)
return uart_add_one_port(&cpm_reg, &pinfo->port);
}
-static int __devexit cpm_uart_remove(struct platform_device *ofdev)
+static int cpm_uart_remove(struct platform_device *ofdev)
{
struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
return uart_remove_one_port(&cpm_reg, &pinfo->port);
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
index 615e46470491..a8cbb2670521 100644
--- a/drivers/tty/serial/efm32-uart.c
+++ b/drivers/tty/serial/efm32-uart.c
@@ -690,7 +690,7 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,
}
-static int __devinit efm32_uart_probe(struct platform_device *pdev)
+static int efm32_uart_probe(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port;
struct resource *res;
@@ -764,7 +764,7 @@ err_get_base:
return ret;
}
-static int __devexit efm32_uart_remove(struct platform_device *pdev)
+static int efm32_uart_remove(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
@@ -791,7 +791,7 @@ MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
static struct platform_driver efm32_uart_driver = {
.probe = efm32_uart_probe,
- .remove = __devexit_p(efm32_uart_remove),
+ .remove = efm32_uart_remove,
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 613151677df0..72b6334bcf1a 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -175,7 +175,7 @@ static void free_port_memory(struct icom_port *icom_port)
}
}
-static int __devinit get_port_memory(struct icom_port *icom_port)
+static int get_port_memory(struct icom_port *icom_port)
{
int index;
unsigned long stgAddr;
@@ -1314,7 +1314,7 @@ static struct uart_driver icom_uart_driver = {
.cons = ICOM_CONSOLE,
};
-static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
+static int icom_init_ports(struct icom_adapter *icom_adapter)
{
u32 subsystem_id = icom_adapter->subsystem_id;
int i;
@@ -1381,7 +1381,7 @@ static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *i
0x8024 + 2 - 2 * (icom_port->port - 2);
}
}
-static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
+static int icom_load_ports(struct icom_adapter *icom_adapter)
{
struct icom_port *icom_port;
int port_num;
@@ -1407,7 +1407,7 @@ static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
return 0;
}
-static int __devinit icom_alloc_adapter(struct icom_adapter
+static int icom_alloc_adapter(struct icom_adapter
**icom_adapter_ref)
{
int adapter_count = 0;
@@ -1487,7 +1487,7 @@ static void icom_kref_release(struct kref *kref)
icom_remove_adapter(icom_adapter);
}
-static int __devinit icom_probe(struct pci_dev *dev,
+static int icom_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
int index;
@@ -1596,7 +1596,7 @@ probe_exit0:
return retval;
}
-static void __devexit icom_remove(struct pci_dev *dev)
+static void icom_remove(struct pci_dev *dev)
{
struct icom_adapter *icom_adapter;
struct list_head *tmp;
@@ -1617,7 +1617,7 @@ static struct pci_driver icom_pci_driver = {
.name = ICOM_DRIVER_NAME,
.id_table = icom_pci_table,
.probe = icom_probe,
- .remove = __devexit_p(icom_remove),
+ .remove = icom_remove,
};
static int __init icom_init(void)
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 5b9bc19ed134..8cb6d8d66a13 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -60,20 +60,27 @@
#include <linux/pm_runtime.h>
#include <linux/spi/ifx_modem.h>
#include <linux/delay.h>
+#include <linux/reboot.h>
#include "ifx6x60.h"
#define IFX_SPI_MORE_MASK 0x10
-#define IFX_SPI_MORE_BIT 12 /* bit position in u16 */
-#define IFX_SPI_CTS_BIT 13 /* bit position in u16 */
+#define IFX_SPI_MORE_BIT 4 /* bit position in u8 */
+#define IFX_SPI_CTS_BIT 6 /* bit position in u8 */
#define IFX_SPI_MODE SPI_MODE_1
#define IFX_SPI_TTY_ID 0
#define IFX_SPI_TIMEOUT_SEC 2
#define IFX_SPI_HEADER_0 (-1)
#define IFX_SPI_HEADER_F (-2)
+#define PO_POST_DELAY 200
+#define IFX_MDM_RST_PMU 4
+
/* forward reference */
static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
+static int ifx_modem_reboot_callback(struct notifier_block *nfb,
+ unsigned long event, void *data);
+static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev);
/* local variables */
static int spi_bpw = 16; /* 8, 16 or 32 bit word length */
@@ -81,6 +88,29 @@ static struct tty_driver *tty_drv;
static struct ifx_spi_device *saved_ifx_dev;
static struct lock_class_key ifx_spi_key;
+static struct notifier_block ifx_modem_reboot_notifier_block = {
+ .notifier_call = ifx_modem_reboot_callback,
+};
+
+static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev)
+{
+ gpio_set_value(IFX_MDM_RST_PMU, 1);
+ msleep(PO_POST_DELAY);
+
+ return 0;
+}
+
+static int ifx_modem_reboot_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ if (saved_ifx_dev)
+ ifx_modem_power_off(saved_ifx_dev);
+ else
+ pr_warn("no ifx modem active;\n");
+
+ return NOTIFY_OK;
+}
+
/* GPIO/GPE settings */
/**
@@ -152,26 +182,67 @@ ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
}
/**
- * swap_buf
+ * swap_buf_8
* @buf: our buffer
* @len : number of bytes (not words) in the buffer
* @end: end of buffer
*
* Swap the contents of a buffer into big endian format
*/
-static inline void swap_buf(u16 *buf, int len, void *end)
+static inline void swap_buf_8(unsigned char *buf, int len, void *end)
+{
+ /* don't swap buffer if SPI word width is 8 bits */
+ return;
+}
+
+/**
+ * swap_buf_16
+ * @buf: our buffer
+ * @len : number of bytes (not words) in the buffer
+ * @end: end of buffer
+ *
+ * Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf_16(unsigned char *buf, int len, void *end)
{
int n;
+ u16 *buf_16 = (u16 *)buf;
len = ((len + 1) >> 1);
- if ((void *)&buf[len] > end) {
- pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
- &buf[len], end);
+ if ((void *)&buf_16[len] > end) {
+ pr_err("swap_buf_16: swap exceeds boundary (%p > %p)!",
+ &buf_16[len], end);
+ return;
+ }
+ for (n = 0; n < len; n++) {
+ *buf_16 = cpu_to_be16(*buf_16);
+ buf_16++;
+ }
+}
+
+/**
+ * swap_buf_32
+ * @buf: our buffer
+ * @len : number of bytes (not words) in the buffer
+ * @end: end of buffer
+ *
+ * Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf_32(unsigned char *buf, int len, void *end)
+{
+ int n;
+
+ u32 *buf_32 = (u32 *)buf;
+ len = (len + 3) >> 2;
+
+ if ((void *)&buf_32[len] > end) {
+ pr_err("swap_buf_32: swap exceeds boundary (%p > %p)!\n",
+ &buf_32[len], end);
return;
}
for (n = 0; n < len; n++) {
- *buf = cpu_to_be16(*buf);
- buf++;
+ *buf_32 = cpu_to_be32(*buf_32);
+ buf_32++;
}
}
@@ -190,9 +261,7 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)
if (!val) {
if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
&ifx_dev->flags)) {
- ifx_dev->spi_timer.expires =
- jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
- add_timer(&ifx_dev->spi_timer);
+ mod_timer(&ifx_dev->spi_timer,jiffies + IFX_SPI_TIMEOUT_SEC*HZ);
}
}
@@ -449,7 +518,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
tx_count-IFX_SPI_HEADER_OVERHEAD,
ifx_dev->spi_more);
/* swap actual data in the buffer */
- swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
+ ifx_dev->swap_buf((ifx_dev->tx_buffer), tx_count,
&ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
return tx_count;
}
@@ -469,9 +538,17 @@ static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
{
struct ifx_spi_device *ifx_dev = tty->driver_data;
unsigned char *tmp_buf = (unsigned char *)buf;
- int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
- &ifx_dev->fifo_lock);
- mrdy_assert(ifx_dev);
+ unsigned long flags;
+ bool is_fifo_empty;
+ int tx_count;
+
+ spin_lock_irqsave(&ifx_dev->fifo_lock, flags);
+ is_fifo_empty = kfifo_is_empty(&ifx_dev->tx_fifo);
+ tx_count = kfifo_in(&ifx_dev->tx_fifo, tmp_buf, count);
+ spin_unlock_irqrestore(&ifx_dev->fifo_lock, flags);
+ if (is_fifo_empty)
+ mrdy_assert(ifx_dev);
+
return tx_count;
}
@@ -530,12 +607,19 @@ static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
/* clear any old data; can't do this in 'close' */
kfifo_reset(&ifx_dev->tx_fifo);
+ /* clear any flag which may be set in port shutdown procedure */
+ clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
+ clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
+
/* put port data into this tty */
tty->driver_data = ifx_dev;
/* allows flip string push from int context */
tty->low_latency = 1;
+ /* set flag to allows data transfer */
+ set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
+
return 0;
}
@@ -551,7 +635,9 @@ static void ifx_port_shutdown(struct tty_port *port)
struct ifx_spi_device *ifx_dev =
container_of(port, struct ifx_spi_device, tty_port);
+ clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
mrdy_set_low(ifx_dev);
+ del_timer(&ifx_dev->spi_timer);
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
tasklet_kill(&ifx_dev->io_work_tasklet);
}
@@ -617,7 +703,7 @@ static void ifx_spi_complete(void *ctx)
if (!ifx_dev->spi_msg.status) {
/* check header validity, get comm flags */
- swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
+ ifx_dev->swap_buf(ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
&ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
&length, &more, &cts);
@@ -636,7 +722,8 @@ static void ifx_spi_complete(void *ctx)
actual_length = min((unsigned int)length,
ifx_dev->spi_msg.actual_length);
- swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
+ ifx_dev->swap_buf(
+ (ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
actual_length,
&ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
ifx_spi_insert_flip_string(
@@ -705,7 +792,8 @@ static void ifx_spi_io(unsigned long data)
int retval;
struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
- if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
+ if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags) &&
+ test_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags)) {
if (ifx_dev->gpio.unack_srdy_int_nb > 0)
ifx_dev->gpio.unack_srdy_int_nb--;
@@ -723,7 +811,8 @@ static void ifx_spi_io(unsigned long data)
ifx_dev->spi_xfer.cs_change = 0;
ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz;
/* ifx_dev->spi_xfer.speed_hz = 390625; */
- ifx_dev->spi_xfer.bits_per_word = spi_bpw;
+ ifx_dev->spi_xfer.bits_per_word =
+ ifx_dev->spi_dev->bits_per_word;
ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
@@ -773,6 +862,7 @@ static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
{
if (ifx_dev->tty_dev)
tty_unregister_device(tty_drv, ifx_dev->minor);
+ tty_port_destroy(&ifx_dev->tty_port);
kfifo_free(&ifx_dev->tx_fifo);
}
@@ -806,10 +896,12 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
dev_dbg(&ifx_dev->spi_dev->dev,
"%s: registering tty device failed", __func__);
ret = PTR_ERR(ifx_dev->tty_dev);
- goto error_ret;
+ goto error_port;
}
return 0;
+error_port:
+ tty_port_destroy(pport);
error_ret:
ifx_spi_free_port(ifx_dev);
return ret;
@@ -826,7 +918,7 @@ error_ret:
static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
{
if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
- del_timer_sync(&ifx_dev->spi_timer);
+ del_timer(&ifx_dev->spi_timer);
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
}
@@ -1001,6 +1093,14 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
return -ENODEV;
}
+ /* init swap_buf function according to word width configuration */
+ if (spi->bits_per_word == 32)
+ ifx_dev->swap_buf = swap_buf_32;
+ else if (spi->bits_per_word == 16)
+ ifx_dev->swap_buf = swap_buf_16;
+ else
+ ifx_dev->swap_buf = swap_buf_8;
+
/* ensure SPI protocol flags are initialized to enable transfer */
ifx_dev->spi_more = 0;
ifx_dev->spi_slave_cts = 0;
@@ -1219,6 +1319,9 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
static void ifx_spi_spi_shutdown(struct spi_device *spi)
{
+ struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+
+ ifx_modem_power_off(ifx_dev);
}
/*
@@ -1338,7 +1441,7 @@ static struct spi_driver ifx_spi_driver = {
.owner = THIS_MODULE},
.probe = ifx_spi_spi_probe,
.shutdown = ifx_spi_spi_shutdown,
- .remove = __devexit_p(ifx_spi_spi_remove),
+ .remove = ifx_spi_spi_remove,
.suspend = ifx_spi_spi_suspend,
.resume = ifx_spi_spi_resume,
.id_table = ifx_id_table
@@ -1354,7 +1457,9 @@ static void __exit ifx_spi_exit(void)
{
/* unregister */
tty_unregister_driver(tty_drv);
+ put_tty_driver(tty_drv);
spi_unregister_driver((void *)&ifx_spi_driver);
+ unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
}
/**
@@ -1389,16 +1494,31 @@ static int __init ifx_spi_init(void)
if (result) {
pr_err("%s: tty_register_driver failed(%d)",
DRVNAME, result);
- put_tty_driver(tty_drv);
- return result;
+ goto err_free_tty;
}
result = spi_register_driver((void *)&ifx_spi_driver);
if (result) {
pr_err("%s: spi_register_driver failed(%d)",
DRVNAME, result);
- tty_unregister_driver(tty_drv);
+ goto err_unreg_tty;
}
+
+ result = register_reboot_notifier(&ifx_modem_reboot_notifier_block);
+ if (result) {
+ pr_err("%s: register ifx modem reboot notifier failed(%d)",
+ DRVNAME, result);
+ goto err_unreg_spi;
+ }
+
+ return 0;
+err_unreg_spi:
+ spi_unregister_driver((void *)&ifx_spi_driver);
+err_unreg_tty:
+ tty_unregister_driver(tty_drv);
+err_free_tty:
+ put_tty_driver(tty_drv);
+
return result;
}
diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h
index e8464baf9e75..4fbddc297839 100644
--- a/drivers/tty/serial/ifx6x60.h
+++ b/drivers/tty/serial/ifx6x60.h
@@ -41,6 +41,7 @@
#define IFX_SPI_STATE_IO_IN_PROGRESS 1
#define IFX_SPI_STATE_IO_READY 2
#define IFX_SPI_STATE_TIMER_PENDING 3
+#define IFX_SPI_STATE_IO_AVAILABLE 4
/* flow control bitfields */
#define IFX_SPI_DCD 0
@@ -124,6 +125,7 @@ struct ifx_spi_device {
#define MR_INPROGRESS 1
#define MR_COMPLETE 2
wait_queue_head_t mdm_reset_wait;
+ void (*swap_buf)(unsigned char *buf, int len, void *end);
};
#endif /* _IFX6X60_H */
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index 5ac52898a0bb..d8f1d1d54471 100644
--- a/drivers/tty/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
@@ -2010,7 +2010,7 @@ static int ioc3uart_remove(struct ioc3_submodule *is,
* @idd: ioc3 driver data for this card
*/
-static int __devinit
+static int
ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
{
struct pci_dev *pdev = idd->pdev;
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index 529bec6edaf8..844d5e4eb1aa 100644
--- a/drivers/tty/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
@@ -57,9 +57,11 @@ enum {
DBG_CARR = 0x10000,
};
-#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \
- if ((DBG_##nlevel & jsm_debug)) \
- dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
+#define jsm_dbg(nlevel, pdev, fmt, ...) \
+do { \
+ if (DBG_##nlevel & jsm_debug) \
+ dev_dbg(pdev->dev, fmt, ##__VA_ARGS__); \
+} while (0)
#define MAXLINES 256
#define MAXPORTS 8
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 5ab3c3b595e4..a47d882d6743 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -64,7 +64,7 @@ int jsm_debug;
module_param(jsm_debug, int, 0);
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
-static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc = 0;
struct jsm_board *brd;
@@ -107,8 +107,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
brd->irq = pdev->irq;
- jsm_printk(INIT, INFO, &brd->pci_dev,
- "jsm_found_board - NEO adapter\n");
+ jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n");
/* get the PCI Base Address Registers */
brd->membase = pci_resource_start(pdev, 0);
@@ -179,7 +178,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
return rc;
}
-static void __devexit jsm_remove_one(struct pci_dev *pdev)
+static void jsm_remove_one(struct pci_dev *pdev)
{
struct jsm_board *brd = pci_get_drvdata(pdev);
int i = 0;
@@ -218,7 +217,7 @@ static struct pci_driver jsm_driver = {
.name = "jsm",
.id_table = jsm_pci_tbl,
.probe = jsm_probe_one,
- .remove = __devexit_p(jsm_remove_one),
+ .remove = jsm_remove_one,
.err_handler = &jsm_err_handler,
};
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 81dfafa11b0b..dfaf48826417 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -52,7 +52,7 @@ static void neo_set_cts_flow_control(struct jsm_channel *ch)
ier = readb(&ch->ch_neo_uart->ier);
efr = readb(&ch->ch_neo_uart->efr);
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
/* Turn on auto CTS flow control */
ier |= (UART_17158_IER_CTSDSR);
@@ -83,7 +83,7 @@ static void neo_set_rts_flow_control(struct jsm_channel *ch)
ier = readb(&ch->ch_neo_uart->ier);
efr = readb(&ch->ch_neo_uart->efr);
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
/* Turn on auto RTS flow control */
ier |= (UART_17158_IER_RTSDTR);
@@ -123,7 +123,7 @@ static void neo_set_ixon_flow_control(struct jsm_channel *ch)
ier = readb(&ch->ch_neo_uart->ier);
efr = readb(&ch->ch_neo_uart->efr);
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
/* Turn off auto CTS flow control */
ier &= ~(UART_17158_IER_CTSDSR);
@@ -160,7 +160,7 @@ static void neo_set_ixoff_flow_control(struct jsm_channel *ch)
ier = readb(&ch->ch_neo_uart->ier);
efr = readb(&ch->ch_neo_uart->efr);
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
/* Turn off auto RTS flow control */
ier &= ~(UART_17158_IER_RTSDTR);
@@ -198,7 +198,7 @@ static void neo_set_no_input_flow_control(struct jsm_channel *ch)
ier = readb(&ch->ch_neo_uart->ier);
efr = readb(&ch->ch_neo_uart->efr);
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
/* Turn off auto RTS flow control */
ier &= ~(UART_17158_IER_RTSDTR);
@@ -237,7 +237,7 @@ static void neo_set_no_output_flow_control(struct jsm_channel *ch)
ier = readb(&ch->ch_neo_uart->ier);
efr = readb(&ch->ch_neo_uart->efr);
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
/* Turn off auto CTS flow control */
ier &= ~(UART_17158_IER_CTSDSR);
@@ -276,7 +276,7 @@ static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
if (ch->ch_c_cflag & CRTSCTS)
return;
- jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n");
+ jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "start\n");
/* Tell UART what start/stop chars it should be looking for */
writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
@@ -455,7 +455,7 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
* I hope thats okay with everyone? Yes? Good.
*/
while (qleft < 1) {
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Queue full, dropping DATA:%x LSR:%x\n",
ch->ch_rqueue[tail], ch->ch_equeue[tail]);
@@ -467,8 +467,8 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
ch->ch_equeue[head] = (u8) linestatus;
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]);
+ jsm_dbg(READ, &ch->ch_bd->pci_dev, "DATA/LSR pair: %x %x\n",
+ ch->ch_rqueue[head], ch->ch_equeue[head]);
/* Ditch any remaining linestatus value. */
linestatus = 0;
@@ -521,8 +521,8 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
ch->ch_cached_lsr &= ~(UART_LSR_THRE);
writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
- jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
- "Tx data: %x\n", circ->buf[circ->tail]);
+ jsm_dbg(WRITE, &ch->ch_bd->pci_dev,
+ "Tx data: %x\n", circ->buf[circ->tail]);
circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
ch->ch_txcount++;
}
@@ -575,8 +575,9 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
{
u8 msignals = signals;
- jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
- "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
+ jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
+ "neo_parse_modem: port: %d msignals: %x\n",
+ ch->ch_portnum, msignals);
/* Scrub off lower bits. They signify delta's, which I don't care about */
/* Keep DDCD and DDSR though */
@@ -606,8 +607,8 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
else
ch->ch_mistat &= ~UART_MSR_CTS;
- jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
- "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+ jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
+ "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
ch->ch_portnum,
!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
@@ -649,8 +650,8 @@ static void neo_flush_uart_write(struct jsm_channel *ch)
/* Check to see if the UART feels it completely flushed the FIFO. */
tmp = readb(&ch->ch_neo_uart->isr_fcr);
if (tmp & 4) {
- jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
- "Still flushing TX UART... i: %d\n", i);
+ jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
+ "Still flushing TX UART... i: %d\n", i);
udelay(10);
}
else
@@ -681,8 +682,8 @@ static void neo_flush_uart_read(struct jsm_channel *ch)
/* Check to see if the UART feels it completely flushed the FIFO. */
tmp = readb(&ch->ch_neo_uart->isr_fcr);
if (tmp & 2) {
- jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
- "Still flushing RX UART... i: %d\n", i);
+ jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
+ "Still flushing RX UART... i: %d\n", i);
udelay(10);
}
else
@@ -705,8 +706,9 @@ static void neo_clear_break(struct jsm_channel *ch, int force)
writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
ch->ch_flags &= ~(CH_BREAK_SENDING);
- jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev,
- "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies);
+ jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
+ "clear break Finishing UART_LCR_SBC! finished: %lx\n",
+ jiffies);
/* flush write operation */
neo_pci_posting_flush(ch->ch_bd);
@@ -748,8 +750,8 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
*/
isr &= ~(UART_17158_IIR_FIFO_ENABLED);
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "%s:%d isr: %x\n", __FILE__, __LINE__, isr);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d isr: %x\n",
+ __FILE__, __LINE__, isr);
if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
/* Read data from uart -> queue */
@@ -772,8 +774,9 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
if (isr & UART_17158_IIR_XONXOFF) {
cause = readb(&ch->ch_neo_uart->xoffchar1);
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "Port %d. Got ISR_XONXOFF: cause:%x\n",
+ port, cause);
/*
* Since the UART detected either an XON or
@@ -786,17 +789,19 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
if (brd->channels[port]->ch_flags & CH_STOP) {
ch->ch_flags &= ~(CH_STOP);
}
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "Port %d. XON detected in incoming data\n", port);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "Port %d. XON detected in incoming data\n",
+ port);
}
else if (cause == UART_17158_XOFF_DETECT) {
if (!(brd->channels[port]->ch_flags & CH_STOP)) {
ch->ch_flags |= CH_STOP;
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "Setting CH_STOP\n");
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "Setting CH_STOP\n");
}
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "Port: %d. XOFF detected in incoming data\n", port);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "Port: %d. XOFF detected in incoming data\n",
+ port);
}
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
}
@@ -825,8 +830,8 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
}
/* Parse any modem signal changes */
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "MOD_STAT: sending to parse_modem_sigs\n");
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "MOD_STAT: sending to parse_modem_sigs\n");
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
}
}
@@ -849,8 +854,8 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
linestatus = readb(&ch->ch_neo_uart->lsr);
- jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev,
- "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d port: %d linestatus: %x\n",
+ __FILE__, __LINE__, port, linestatus);
ch->ch_cached_lsr |= linestatus;
@@ -869,7 +874,7 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
*to do the special RX+LSR read for this FIFO load.
*/
if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
- jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
"%s:%d Port: %d Got an RX error, need to parse LSR\n",
__FILE__, __LINE__, port);
@@ -880,20 +885,21 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
if (linestatus & UART_LSR_PE) {
ch->ch_err_parity++;
- jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
- "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. PAR ERR!\n",
+ __FILE__, __LINE__, port);
}
if (linestatus & UART_LSR_FE) {
ch->ch_err_frame++;
- jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
- "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. FRM ERR!\n",
+ __FILE__, __LINE__, port);
}
if (linestatus & UART_LSR_BI) {
ch->ch_err_break++;
- jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
- "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "%s:%d Port: %d. BRK INTR!\n",
+ __FILE__, __LINE__, port);
}
if (linestatus & UART_LSR_OE) {
@@ -904,8 +910,9 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
* Probably we should eventually have an orun stat in our driver...
*/
ch->ch_err_overrun++;
- jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev,
- "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port);
+ jsm_dbg(INTR, &ch->ch_bd->pci_dev,
+ "%s:%d Port: %d. Rx Overrun!\n",
+ __FILE__, __LINE__, port);
}
if (linestatus & UART_LSR_THRE) {
@@ -1128,11 +1135,11 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
*/
uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
- jsm_printk(INTR, INFO, &brd->pci_dev,
- "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll);
+ jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n",
+ __FILE__, __LINE__, uart_poll);
if (!uart_poll) {
- jsm_printk(INTR, INFO, &brd->pci_dev,
+ jsm_dbg(INTR, &brd->pci_dev,
"Kernel interrupted to me, but no pending interrupts...\n");
spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
return IRQ_NONE;
@@ -1158,15 +1165,15 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
continue;
}
- jsm_printk(INTR, INFO, &brd->pci_dev,
- "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type);
+ jsm_dbg(INTR, &brd->pci_dev, "%s:%d port: %x type: %x\n",
+ __FILE__, __LINE__, port, type);
/* Remove this port + type from uart_poll */
uart_poll &= ~(jsm_offset_table[port]);
if (!type) {
/* If no type, just ignore it, and move onto next port */
- jsm_printk(INTR, ERR, &brd->pci_dev,
+ jsm_dbg(INTR, &brd->pci_dev,
"Interrupt with no type! port: %d\n", port);
continue;
}
@@ -1231,15 +1238,16 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
* these once and awhile.
* Its harmless, just ignore it and move on.
*/
- jsm_printk(INTR, ERR, &brd->pci_dev,
- "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type);
+ jsm_dbg(INTR, &brd->pci_dev,
+ "%s:%d Unknown Interrupt type: %x\n",
+ __FILE__, __LINE__, type);
continue;
}
}
spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
- jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n");
+ jsm_dbg(INTR, &brd->pci_dev, "finish\n");
return IRQ_HANDLED;
}
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 71397961773c..4c00c5550b1a 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -43,7 +43,7 @@ static inline int jsm_get_mstat(struct jsm_channel *ch)
unsigned char mstat;
unsigned result;
- jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n");
+ jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "start\n");
mstat = (ch->ch_mostat | ch->ch_mistat);
@@ -62,7 +62,7 @@ static inline int jsm_get_mstat(struct jsm_channel *ch)
if (mstat & UART_MSR_DCD)
result |= TIOCM_CD;
- jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
return result;
}
@@ -79,14 +79,14 @@ static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
int result;
struct jsm_channel *channel = (struct jsm_channel *)port;
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
result = jsm_get_mstat(channel);
if (result < 0)
return -ENXIO;
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
return result;
}
@@ -100,7 +100,7 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
if (mctrl & TIOCM_RTS)
channel->ch_mostat |= UART_MCR_RTS;
@@ -114,7 +114,7 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
channel->ch_bd->bd_ops->assert_modem_signals(channel);
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
udelay(10);
}
@@ -135,23 +135,23 @@ static void jsm_tty_start_tx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
channel->ch_flags &= ~(CH_STOP);
jsm_tty_write(port);
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_stop_tx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
channel->ch_flags |= (CH_STOP);
- jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_send_xchar(struct uart_port *port, char ch)
@@ -216,16 +216,16 @@ static int jsm_tty_open(struct uart_port *port)
if (!channel->ch_rqueue) {
channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
if (!channel->ch_rqueue) {
- jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
- "unable to allocate read queue buf");
+ jsm_dbg(INIT, &channel->ch_bd->pci_dev,
+ "unable to allocate read queue buf\n");
return -ENOMEM;
}
}
if (!channel->ch_equeue) {
channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
if (!channel->ch_equeue) {
- jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
- "unable to allocate error queue buf");
+ jsm_dbg(INIT, &channel->ch_bd->pci_dev,
+ "unable to allocate error queue buf\n");
return -ENOMEM;
}
}
@@ -234,7 +234,7 @@ static int jsm_tty_open(struct uart_port *port)
/*
* Initialize if neither terminal is open.
*/
- jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev,
+ jsm_dbg(OPEN, &channel->ch_bd->pci_dev,
"jsm_open: initializing channel in open...\n");
/*
@@ -270,7 +270,7 @@ static int jsm_tty_open(struct uart_port *port)
channel->ch_open_count++;
- jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n");
return 0;
}
@@ -280,7 +280,7 @@ static void jsm_tty_close(struct uart_port *port)
struct ktermios *ts;
struct jsm_channel *channel = (struct jsm_channel *)port;
- jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
+ jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
ts = &port->state->port.tty->termios;
@@ -293,7 +293,7 @@ static void jsm_tty_close(struct uart_port *port)
* If we have HUPCL set, lower DTR and RTS
*/
if (channel->ch_c_cflag & HUPCL) {
- jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev,
+ jsm_dbg(CLOSE, &channel->ch_bd->pci_dev,
"Close. HUPCL set, dropping DTR/RTS\n");
/* Drop RTS/DTR */
@@ -304,7 +304,7 @@ static void jsm_tty_close(struct uart_port *port)
/* Turn off UART interrupts for this port */
channel->ch_bd->bd_ops->uart_off(channel);
- jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_set_termios(struct uart_port *port,
@@ -371,7 +371,7 @@ static struct uart_ops jsm_ops = {
* Init the tty subsystem. Called once per board after board has been
* downloaded and init'ed.
*/
-int __devinit jsm_tty_init(struct jsm_board *brd)
+int jsm_tty_init(struct jsm_board *brd)
{
int i;
void __iomem *vaddr;
@@ -380,7 +380,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
if (!brd)
return -ENXIO;
- jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+ jsm_dbg(INIT, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
@@ -401,9 +401,9 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
*/
brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
if (!brd->channels[i]) {
- jsm_printk(CORE, ERR, &brd->pci_dev,
+ jsm_dbg(CORE, &brd->pci_dev,
"%s:%d Unable to allocate memory for channel struct\n",
- __FILE__, __LINE__);
+ __FILE__, __LINE__);
}
}
}
@@ -431,7 +431,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
init_waitqueue_head(&ch->ch_flags_wait);
}
- jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+ jsm_dbg(INIT, &brd->pci_dev, "finish\n");
return 0;
}
@@ -444,7 +444,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
if (!brd)
return -ENXIO;
- jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+ jsm_dbg(INIT, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
@@ -481,7 +481,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
printk(KERN_INFO "jsm: Port %d added\n", i);
}
- jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+ jsm_dbg(INIT, &brd->pci_dev, "finish\n");
return 0;
}
@@ -493,7 +493,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
if (!brd)
return -ENXIO;
- jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
+ jsm_dbg(INIT, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
@@ -513,7 +513,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
}
- jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
+ jsm_dbg(INIT, &brd->pci_dev, "finish\n");
return 0;
}
@@ -531,7 +531,7 @@ void jsm_input(struct jsm_channel *ch)
int s = 0;
int i = 0;
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+ jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
if (!ch)
return;
@@ -560,7 +560,7 @@ void jsm_input(struct jsm_channel *ch)
return;
}
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
+ jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
/*
*If the device is not open, or CREAD is off, flush
@@ -569,8 +569,9 @@ void jsm_input(struct jsm_channel *ch)
if (!tp ||
!(tp->termios.c_cflag & CREAD) ) {
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
+ "input. dropping %d bytes on port %d...\n",
+ data_len, ch->ch_portnum);
ch->ch_r_head = tail;
/* Force queue flow control to be released, if needed */
@@ -585,17 +586,17 @@ void jsm_input(struct jsm_channel *ch)
*/
if (ch->ch_flags & CH_STOPI) {
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Port %d throttled, not reading any data. head: %x tail: %x\n",
ch->ch_portnum, head, tail);
return;
}
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
+ jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
if (data_len <= 0) {
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+ jsm_dbg(READ, &ch->ch_bd->pci_dev, "jsm_input 1\n");
return;
}
@@ -653,7 +654,7 @@ void jsm_input(struct jsm_channel *ch)
/* Tell the tty layer its okay to "eat" the data now */
tty_flip_buffer_push(tp);
- jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
+ jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
}
static void jsm_carrier(struct jsm_channel *ch)
@@ -663,7 +664,7 @@ static void jsm_carrier(struct jsm_channel *ch)
int virt_carrier = 0;
int phys_carrier = 0;
- jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
+ jsm_dbg(CARR, &ch->ch_bd->pci_dev, "start\n");
if (!ch)
return;
@@ -673,16 +674,16 @@ static void jsm_carrier(struct jsm_channel *ch)
return;
if (ch->ch_mistat & UART_MSR_DCD) {
- jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
- "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
+ jsm_dbg(CARR, &ch->ch_bd->pci_dev, "mistat: %x D_CD: %x\n",
+ ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
phys_carrier = 1;
}
if (ch->ch_c_cflag & CLOCAL)
virt_carrier = 1;
- jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
- "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier);
+ jsm_dbg(CARR, &ch->ch_bd->pci_dev, "DCD: physical: %d virt: %d\n",
+ phys_carrier, virt_carrier);
/*
* Test for a VIRTUAL carrier transition to HIGH.
@@ -694,8 +695,7 @@ static void jsm_carrier(struct jsm_channel *ch)
* for carrier in the open routine.
*/
- jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
- "carrier: virt DCD rose\n");
+ jsm_dbg(CARR, &ch->ch_bd->pci_dev, "carrier: virt DCD rose\n");
if (waitqueue_active(&(ch->ch_flags_wait)))
wake_up_interruptible(&ch->ch_flags_wait);
@@ -711,7 +711,7 @@ static void jsm_carrier(struct jsm_channel *ch)
* for carrier in the open routine.
*/
- jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev,
+ jsm_dbg(CARR, &ch->ch_bd->pci_dev,
"carrier: physical DCD rose\n");
if (waitqueue_active(&(ch->ch_flags_wait)))
@@ -790,8 +790,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
bd_ops->disable_receiver(ch);
ch->ch_flags |= (CH_RECEIVER_OFF);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
+ "Internal queue hit hilevel mark (%d)! Turning off interrupts\n",
qleft);
}
}
@@ -800,8 +800,9 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
bd_ops->send_stop_character(ch);
ch->ch_stops_sent++;
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
+ "Sending stop char! Times sent: %x\n",
+ ch->ch_stops_sent);
}
}
}
@@ -827,8 +828,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
if (ch->ch_flags & CH_RECEIVER_OFF) {
bd_ops->enable_receiver(ch);
ch->ch_flags &= ~(CH_RECEIVER_OFF);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
+ "Internal queue hit lowlevel mark (%d)! Turning on interrupts\n",
qleft);
}
}
@@ -836,7 +837,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
ch->ch_stops_sent = 0;
bd_ops->send_start_character(ch);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
+ jsm_dbg(READ, &ch->ch_bd->pci_dev,
+ "Sending start char!\n");
}
}
}
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index d185247ba1aa..6ac2b797a764 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -266,6 +266,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
}
return 0;
err:
+ tty_port_destroy(&priv->port);
kfree(priv);
return ret;
}
@@ -275,6 +276,7 @@ static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
tty->driver_data = NULL;
+ tty_port_destroy(&priv->port);
kfree(priv);
}
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index ba3af3bf6d43..0e86bff3fe2a 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -686,7 +686,7 @@ static struct uart_ops serial_lpc32xx_pops = {
/*
* Register a set of serial devices attached to a platform device
*/
-static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
{
struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
int ret = 0;
@@ -740,7 +740,7 @@ static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
/*
* Remove serial ports registered against a platform device.
*/
-static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+static int serial_hs_lpc32xx_remove(struct platform_device *pdev)
{
struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
@@ -783,7 +783,7 @@ MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
static struct platform_driver serial_hs_lpc32xx_driver = {
.probe = serial_hs_lpc32xx_probe,
- .remove = __devexit_p(serial_hs_lpc32xx_remove),
+ .remove = serial_hs_lpc32xx_remove,
.suspend = serial_hs_lpc32xx_suspend,
.resume = serial_hs_lpc32xx_resume,
.driver = {
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 0f24486be532..7ce3197087bb 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -742,7 +742,7 @@ static struct uart_driver max3100_uart_driver = {
};
static int uart_driver_registered;
-static int __devinit max3100_probe(struct spi_device *spi)
+static int max3100_probe(struct spi_device *spi)
{
int i, retval;
struct plat_max3100 *pdata;
@@ -818,7 +818,7 @@ static int __devinit max3100_probe(struct spi_device *spi)
return 0;
}
-static int __devexit max3100_remove(struct spi_device *spi)
+static int max3100_remove(struct spi_device *spi)
{
struct max3100_port *s = dev_get_drvdata(&spi->dev);
int i;
@@ -907,7 +907,7 @@ static struct spi_driver max3100_driver = {
},
.probe = max3100_probe,
- .remove = __devexit_p(max3100_remove),
+ .remove = max3100_remove,
.suspend = max3100_suspend,
.resume = max3100_resume,
};
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 2bc28a59d385..a801f6872cad 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -378,7 +378,7 @@ static void max310x_wait_pll(struct max310x_port *s)
}
}
-static int __devinit max310x_update_best_err(unsigned long f, long *besterr)
+static int max310x_update_best_err(unsigned long f, long *besterr)
{
/* Use baudrate 115200 for calculate error */
long err = f % (115200 * 16);
@@ -391,7 +391,7 @@ static int __devinit max310x_update_best_err(unsigned long f, long *besterr)
return 1;
}
-static int __devinit max310x_set_ref_clk(struct max310x_port *s)
+static int max310x_set_ref_clk(struct max310x_port *s)
{
unsigned int div, clksrc, pllcfg = 0;
long besterr = -1;
@@ -995,7 +995,7 @@ static struct max310x_pdata generic_plat_data = {
.frequency = 26000000,
};
-static int __devinit max310x_probe(struct spi_device *spi)
+static int max310x_probe(struct spi_device *spi)
{
struct max310x_port *s;
struct device *dev = &spi->dev;
@@ -1178,6 +1178,7 @@ static int __devinit max310x_probe(struct spi_device *spi)
s->gpio.set = max310x_gpio_set;
s->gpio.base = pdata->gpio_base;
s->gpio.ngpio = s->nr_gpio;
+ s->gpio.can_sleep = 1;
if (gpiochip_add(&s->gpio)) {
/* Indicate that we should not call gpiochip_remove */
s->gpio.base = 0;
@@ -1202,7 +1203,7 @@ err_out:
return ret;
}
-static int __devexit max310x_remove(struct spi_device *spi)
+static int max310x_remove(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct max310x_port *s = dev_get_drvdata(dev);
@@ -1239,6 +1240,7 @@ static int __devexit max310x_remove(struct spi_device *spi)
static const struct spi_device_id max310x_id_table[] = {
{ "max3107", MAX310X_TYPE_MAX3107 },
{ "max3108", MAX310X_TYPE_MAX3108 },
+ { }
};
MODULE_DEVICE_TABLE(spi, max310x_id_table);
@@ -1248,7 +1250,7 @@ static struct spi_driver max310x_driver = {
.owner = THIS_MODULE,
},
.probe = max310x_probe,
- .remove = __devexit_p(max310x_remove),
+ .remove = max310x_remove,
.suspend = max310x_suspend,
.resume = max310x_resume,
.id_table = max310x_id_table,
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 9afca093d6ec..fcd56ab6053f 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -571,7 +571,7 @@ static struct uart_driver mcf_driver = {
/****************************************************************************/
-static int __devinit mcf_probe(struct platform_device *pdev)
+static int mcf_probe(struct platform_device *pdev)
{
struct mcf_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
@@ -599,7 +599,7 @@ static int __devinit mcf_probe(struct platform_device *pdev)
/****************************************************************************/
-static int __devexit mcf_remove(struct platform_device *pdev)
+static int mcf_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
@@ -617,7 +617,7 @@ static int __devexit mcf_remove(struct platform_device *pdev)
static struct platform_driver mcf_platform_driver = {
.probe = mcf_probe,
- .remove = __devexit_p(mcf_remove),
+ .remove = mcf_remove,
.driver = {
.name = "mcfuart",
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index c4b50af46c44..2c01344dc332 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -36,6 +36,7 @@
#include <linux/serial_mfd.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
+#include <linux/nmi.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
@@ -1113,6 +1114,8 @@ serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
unsigned int ier;
int locked = 1;
+ touch_nmi_watchdog();
+
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
@@ -1456,7 +1459,7 @@ static void serial_hsu_remove(struct pci_dev *pdev)
}
/* First 3 are UART ports, and the 4th is the DMA */
-static const struct pci_device_id pci_ids[] __devinitconst = {
+static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
@@ -1468,7 +1471,7 @@ static struct pci_driver hsu_pci_driver = {
.name = "HSU serial",
.id_table = pci_ids,
.probe = serial_hsu_probe,
- .remove = __devexit_p(serial_hsu_remove),
+ .remove = serial_hsu_remove,
.suspend = serial_hsu_suspend,
.resume = serial_hsu_resume,
.driver = {
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 8cf577008ad7..7c23c4f4c58d 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1308,7 +1308,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
{},
};
-static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
+static int mpc52xx_uart_of_probe(struct platform_device *op)
{
int idx = -1;
unsigned int uartclk;
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index df2a2240a3ae..58734d7e746d 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -773,7 +773,7 @@ static int serial_m3110_resume(struct spi_device *spi)
#define serial_m3110_resume NULL
#endif
-static int __devinit serial_m3110_probe(struct spi_device *spi)
+static int serial_m3110_probe(struct spi_device *spi)
{
struct uart_max3110 *max;
void *buffer;
@@ -855,7 +855,7 @@ err_get_page:
return ret;
}
-static int __devexit serial_m3110_remove(struct spi_device *dev)
+static int serial_m3110_remove(struct spi_device *dev)
{
struct uart_max3110 *max = spi_get_drvdata(dev);
@@ -879,7 +879,7 @@ static struct spi_driver uart_max3110_driver = {
.owner = THIS_MODULE,
},
.probe = serial_m3110_probe,
- .remove = __devexit_p(serial_m3110_remove),
+ .remove = serial_m3110_remove,
.suspend = serial_m3110_suspend,
.resume = serial_m3110_resume,
};
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 033e0bc9ebab..95fd39be2934 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -917,7 +917,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
return uart_add_one_port(&msm_uart_driver, port);
}
-static int __devexit msm_serial_remove(struct platform_device *pdev)
+static int msm_serial_remove(struct platform_device *pdev)
{
struct msm_port *msm_port = platform_get_drvdata(pdev);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index fca13dc73e23..1fa92284ade0 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -401,7 +401,7 @@ static int msm_hs_request_port(struct uart_port *port)
return 0;
}
-static int __devexit msm_hs_remove(struct platform_device *pdev)
+static int msm_hs_remove(struct platform_device *pdev)
{
struct msm_hs_port *msm_uport;
@@ -1521,7 +1521,7 @@ err_msm_hs_init_clk:
}
/* Initialize tx and rx data structures */
-static int __devinit uartdm_init_port(struct uart_port *uport)
+static int uartdm_init_port(struct uart_port *uport)
{
int ret = 0;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
@@ -1614,7 +1614,7 @@ err_tx_command_ptr_ptr:
return ret;
}
-static int __devinit msm_hs_probe(struct platform_device *pdev)
+static int msm_hs_probe(struct platform_device *pdev)
{
int ret;
struct uart_port *uport;
@@ -1838,7 +1838,7 @@ static const struct dev_pm_ops msm_hs_dev_pm_ops = {
static struct platform_driver msm_serial_hs_platform_driver = {
.probe = msm_hs_probe,
- .remove = __devexit_p(msm_hs_remove),
+ .remove = msm_hs_remove,
.driver = {
.name = "msm_serial_hs",
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 7ea8a263fd9e..e2775b6df5a5 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -520,7 +520,7 @@ static int __init mux_probe(struct parisc_device *dev)
return 0;
}
-static int __devexit mux_remove(struct parisc_device *dev)
+static int mux_remove(struct parisc_device *dev)
{
int i, j;
int port_count = (long)dev_get_drvdata(&dev->dev);
@@ -571,14 +571,14 @@ static struct parisc_driver builtin_serial_mux_driver = {
.name = "builtin_serial_mux",
.id_table = builtin_mux_tbl,
.probe = mux_probe,
- .remove = __devexit_p(mux_remove),
+ .remove = mux_remove,
};
static struct parisc_driver serial_mux_driver = {
.name = "serial_mux",
.id_table = mux_tbl,
.probe = mux_probe,
- .remove = __devexit_p(mux_remove),
+ .remove = mux_remove,
};
/**
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 6db3baa39a97..e55615eb34ad 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -34,6 +34,8 @@
#include <linux/io.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl/mxs-dma.h>
#include <asm/cacheflush.h>
@@ -71,6 +73,15 @@
#define AUART_CTRL0_SFTRST (1 << 31)
#define AUART_CTRL0_CLKGATE (1 << 30)
+#define AUART_CTRL0_RXTO_ENABLE (1 << 27)
+#define AUART_CTRL0_RXTIMEOUT(v) (((v) & 0x7ff) << 16)
+#define AUART_CTRL0_XFER_COUNT(v) ((v) & 0xffff)
+
+#define AUART_CTRL1_XFER_COUNT(v) ((v) & 0xffff)
+
+#define AUART_CTRL2_DMAONERR (1 << 26)
+#define AUART_CTRL2_TXDMAE (1 << 25)
+#define AUART_CTRL2_RXDMAE (1 << 24)
#define AUART_CTRL2_CTSEN (1 << 15)
#define AUART_CTRL2_RTSEN (1 << 14)
@@ -111,29 +122,170 @@
#define AUART_STAT_BERR (1 << 18)
#define AUART_STAT_PERR (1 << 17)
#define AUART_STAT_FERR (1 << 16)
+#define AUART_STAT_RXCOUNT_MASK 0xffff
static struct uart_driver auart_driver;
+enum mxs_auart_type {
+ IMX23_AUART,
+ IMX28_AUART,
+};
+
struct mxs_auart_port {
struct uart_port port;
- unsigned int flags;
+#define MXS_AUART_DMA_CONFIG 0x1
+#define MXS_AUART_DMA_ENABLED 0x2
+#define MXS_AUART_DMA_TX_SYNC 2 /* bit 2 */
+#define MXS_AUART_DMA_RX_READY 3 /* bit 3 */
+ unsigned long flags;
unsigned int ctrl;
+ enum mxs_auart_type devtype;
unsigned int irq;
struct clk *clk;
struct device *dev;
+
+ /* for DMA */
+ struct mxs_dma_data dma_data;
+ int dma_channel_rx, dma_channel_tx;
+ int dma_irq_rx, dma_irq_tx;
+ int dma_channel;
+
+ struct scatterlist tx_sgl;
+ struct dma_chan *tx_dma_chan;
+ void *tx_dma_buf;
+
+ struct scatterlist rx_sgl;
+ struct dma_chan *rx_dma_chan;
+ void *rx_dma_buf;
+};
+
+static struct platform_device_id mxs_auart_devtype[] = {
+ { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
+ { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, mxs_auart_devtype);
+
+static struct of_device_id mxs_auart_dt_ids[] = {
+ {
+ .compatible = "fsl,imx28-auart",
+ .data = &mxs_auart_devtype[IMX28_AUART]
+ }, {
+ .compatible = "fsl,imx23-auart",
+ .data = &mxs_auart_devtype[IMX23_AUART]
+ }, { /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);
+
+static inline int is_imx28_auart(struct mxs_auart_port *s)
+{
+ return s->devtype == IMX28_AUART;
+}
+
+static inline bool auart_dma_enabled(struct mxs_auart_port *s)
+{
+ return s->flags & MXS_AUART_DMA_ENABLED;
+}
static void mxs_auart_stop_tx(struct uart_port *u);
#define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
-static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
+static void mxs_auart_tx_chars(struct mxs_auart_port *s);
+
+static void dma_tx_callback(void *param)
{
+ struct mxs_auart_port *s = param;
struct circ_buf *xmit = &s->port.state->xmit;
+ dma_unmap_sg(s->dev, &s->tx_sgl, 1, DMA_TO_DEVICE);
+
+ /* clear the bit used to serialize the DMA tx. */
+ clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
+ smp_mb__after_clear_bit();
+
+ /* wake up the possible processes. */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&s->port);
+
+ mxs_auart_tx_chars(s);
+}
+
+static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sgl = &s->tx_sgl;
+ struct dma_chan *channel = s->tx_dma_chan;
+ u32 pio;
+
+ /* [1] : send PIO. Note, the first pio word is CTRL1. */
+ pio = AUART_CTRL1_XFER_COUNT(size);
+ desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)&pio,
+ 1, DMA_TRANS_NONE, 0);
+ if (!desc) {
+ dev_err(s->dev, "step 1 error\n");
+ return -EINVAL;
+ }
+
+ /* [2] : set DMA buffer. */
+ sg_init_one(sgl, s->tx_dma_buf, size);
+ dma_map_sg(s->dev, sgl, 1, DMA_TO_DEVICE);
+ desc = dmaengine_prep_slave_sg(channel, sgl,
+ 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(s->dev, "step 2 error\n");
+ return -EINVAL;
+ }
+
+ /* [3] : submit the DMA */
+ desc->callback = dma_tx_callback;
+ desc->callback_param = s;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(channel);
+ return 0;
+}
+
+static void mxs_auart_tx_chars(struct mxs_auart_port *s)
+{
+ struct circ_buf *xmit = &s->port.state->xmit;
+
+ if (auart_dma_enabled(s)) {
+ u32 i = 0;
+ int size;
+ void *buffer = s->tx_dma_buf;
+
+ if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags))
+ return;
+
+ while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
+ size = min_t(u32, UART_XMIT_SIZE - i,
+ CIRC_CNT_TO_END(xmit->head,
+ xmit->tail,
+ UART_XMIT_SIZE));
+ memcpy(buffer + i, xmit->buf + xmit->tail, size);
+ xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);
+
+ i += size;
+ if (i >= UART_XMIT_SIZE)
+ break;
+ }
+
+ if (uart_tx_stopped(&s->port))
+ mxs_auart_stop_tx(&s->port);
+
+ if (i) {
+ mxs_auart_dma_tx(s, i);
+ } else {
+ clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
+ smp_mb__after_clear_bit();
+ }
+ return;
+ }
+
+
while (!(readl(s->port.membase + AUART_STAT) &
AUART_STAT_TXFF)) {
if (s->port.x_char) {
@@ -260,10 +412,12 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
u32 ctrl = readl(u->membase + AUART_CTRL2);
- ctrl &= ~AUART_CTRL2_RTSEN;
+ ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS);
if (mctrl & TIOCM_RTS) {
if (tty_port_cts_enabled(&u->state->port))
ctrl |= AUART_CTRL2_RTSEN;
+ else
+ ctrl |= AUART_CTRL2_RTS;
}
s->ctrl = mctrl;
@@ -287,10 +441,159 @@ static u32 mxs_auart_get_mctrl(struct uart_port *u)
return mctrl;
}
+static bool mxs_auart_dma_filter(struct dma_chan *chan, void *param)
+{
+ struct mxs_auart_port *s = param;
+
+ if (!mxs_dma_is_apbx(chan))
+ return false;
+
+ if (s->dma_channel == chan->chan_id) {
+ chan->private = &s->dma_data;
+ return true;
+ }
+ return false;
+}
+
+static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
+static void dma_rx_callback(void *arg)
+{
+ struct mxs_auart_port *s = (struct mxs_auart_port *) arg;
+ struct tty_struct *tty = s->port.state->port.tty;
+ int count;
+ u32 stat;
+
+ dma_unmap_sg(s->dev, &s->rx_sgl, 1, DMA_FROM_DEVICE);
+
+ stat = readl(s->port.membase + AUART_STAT);
+ stat &= ~(AUART_STAT_OERR | AUART_STAT_BERR |
+ AUART_STAT_PERR | AUART_STAT_FERR);
+
+ count = stat & AUART_STAT_RXCOUNT_MASK;
+ tty_insert_flip_string(tty, s->rx_dma_buf, count);
+
+ writel(stat, s->port.membase + AUART_STAT);
+ tty_flip_buffer_push(tty);
+
+ /* start the next DMA for RX. */
+ mxs_auart_dma_prep_rx(s);
+}
+
+static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sgl = &s->rx_sgl;
+ struct dma_chan *channel = s->rx_dma_chan;
+ u32 pio[1];
+
+ /* [1] : send PIO */
+ pio[0] = AUART_CTRL0_RXTO_ENABLE
+ | AUART_CTRL0_RXTIMEOUT(0x80)
+ | AUART_CTRL0_XFER_COUNT(UART_XMIT_SIZE);
+ desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
+ 1, DMA_TRANS_NONE, 0);
+ if (!desc) {
+ dev_err(s->dev, "step 1 error\n");
+ return -EINVAL;
+ }
+
+ /* [2] : send DMA request */
+ sg_init_one(sgl, s->rx_dma_buf, UART_XMIT_SIZE);
+ dma_map_sg(s->dev, sgl, 1, DMA_FROM_DEVICE);
+ desc = dmaengine_prep_slave_sg(channel, sgl, 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(s->dev, "step 2 error\n");
+ return -1;
+ }
+
+ /* [3] : submit the DMA, but do not issue it. */
+ desc->callback = dma_rx_callback;
+ desc->callback_param = s;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(channel);
+ return 0;
+}
+
+static void mxs_auart_dma_exit_channel(struct mxs_auart_port *s)
+{
+ if (s->tx_dma_chan) {
+ dma_release_channel(s->tx_dma_chan);
+ s->tx_dma_chan = NULL;
+ }
+ if (s->rx_dma_chan) {
+ dma_release_channel(s->rx_dma_chan);
+ s->rx_dma_chan = NULL;
+ }
+
+ kfree(s->tx_dma_buf);
+ kfree(s->rx_dma_buf);
+ s->tx_dma_buf = NULL;
+ s->rx_dma_buf = NULL;
+}
+
+static void mxs_auart_dma_exit(struct mxs_auart_port *s)
+{
+
+ writel(AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR,
+ s->port.membase + AUART_CTRL2_CLR);
+
+ mxs_auart_dma_exit_channel(s);
+ s->flags &= ~MXS_AUART_DMA_ENABLED;
+ clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
+ clear_bit(MXS_AUART_DMA_RX_READY, &s->flags);
+}
+
+static int mxs_auart_dma_init(struct mxs_auart_port *s)
+{
+ dma_cap_mask_t mask;
+
+ if (auart_dma_enabled(s))
+ return 0;
+
+ /* We do not get the right DMA channels. */
+ if (s->dma_channel_rx == -1 || s->dma_channel_rx == -1)
+ return -EINVAL;
+
+ /* init for RX */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ s->dma_channel = s->dma_channel_rx;
+ s->dma_data.chan_irq = s->dma_irq_rx;
+ s->rx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s);
+ if (!s->rx_dma_chan)
+ goto err_out;
+ s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!s->rx_dma_buf)
+ goto err_out;
+
+ /* init for TX */
+ s->dma_channel = s->dma_channel_tx;
+ s->dma_data.chan_irq = s->dma_irq_tx;
+ s->tx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s);
+ if (!s->tx_dma_chan)
+ goto err_out;
+ s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!s->tx_dma_buf)
+ goto err_out;
+
+ /* set the flags */
+ s->flags |= MXS_AUART_DMA_ENABLED;
+ dev_dbg(s->dev, "enabled the DMA support.");
+
+ return 0;
+
+err_out:
+ mxs_auart_dma_exit_channel(s);
+ return -EINVAL;
+
+}
+
static void mxs_auart_settermios(struct uart_port *u,
struct ktermios *termios,
struct ktermios *old)
{
+ struct mxs_auart_port *s = to_auart_port(u);
u32 bm, ctrl, ctrl2, div;
unsigned int cflag, baud;
@@ -362,10 +665,23 @@ static void mxs_auart_settermios(struct uart_port *u,
ctrl |= AUART_LINECTRL_STP2;
/* figure out the hardware flow control settings */
- if (cflag & CRTSCTS)
+ if (cflag & CRTSCTS) {
+ /*
+ * The DMA has a bug(see errata:2836) in mx23.
+ * So we can not implement the DMA for auart in mx23,
+ * we can only implement the DMA support for auart
+ * in mx28.
+ */
+ if (is_imx28_auart(s) && (s->flags & MXS_AUART_DMA_CONFIG)) {
+ if (!mxs_auart_dma_init(s))
+ /* enable DMA tranfer */
+ ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE
+ | AUART_CTRL2_DMAONERR;
+ }
ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN;
- else
+ } else {
ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
+ }
/* set baud rate */
baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
@@ -377,6 +693,19 @@ static void mxs_auart_settermios(struct uart_port *u,
writel(ctrl2, u->membase + AUART_CTRL2);
uart_update_timeout(u, termios->c_cflag, baud);
+
+ /* prepare for the DMA RX. */
+ if (auart_dma_enabled(s) &&
+ !test_and_set_bit(MXS_AUART_DMA_RX_READY, &s->flags)) {
+ if (!mxs_auart_dma_prep_rx(s)) {
+ /* Disable the normal RX interrupt. */
+ writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN,
+ u->membase + AUART_INTR_CLR);
+ } else {
+ mxs_auart_dma_exit(s);
+ dev_err(s->dev, "We can not start up the DMA.\n");
+ }
+ }
}
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
@@ -395,7 +724,8 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
}
if (istat & (AUART_INTR_RTIS | AUART_INTR_RXIS)) {
- mxs_auart_rx_chars(s);
+ if (!auart_dma_enabled(s))
+ mxs_auart_rx_chars(s);
istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS);
}
@@ -455,6 +785,9 @@ static void mxs_auart_shutdown(struct uart_port *u)
{
struct mxs_auart_port *s = to_auart_port(u);
+ if (auart_dma_enabled(s))
+ mxs_auart_dma_exit(s);
+
writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
@@ -688,6 +1021,7 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ u32 dma_channel[2];
int ret;
if (!np)
@@ -701,11 +1035,27 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
}
s->port.line = ret;
+ s->dma_irq_rx = platform_get_irq(pdev, 1);
+ s->dma_irq_tx = platform_get_irq(pdev, 2);
+
+ ret = of_property_read_u32_array(np, "fsl,auart-dma-channel",
+ dma_channel, 2);
+ if (ret == 0) {
+ s->dma_channel_rx = dma_channel[0];
+ s->dma_channel_tx = dma_channel[1];
+
+ s->flags |= MXS_AUART_DMA_CONFIG;
+ } else {
+ s->dma_channel_rx = -1;
+ s->dma_channel_tx = -1;
+ }
return 0;
}
-static int __devinit mxs_auart_probe(struct platform_device *pdev)
+static int mxs_auart_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id =
+ of_match_device(mxs_auart_dt_ids, &pdev->dev);
struct mxs_auart_port *s;
u32 version;
int ret = 0;
@@ -730,6 +1080,11 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
goto out_free;
}
+ if (of_id) {
+ pdev->id_entry = of_id->data;
+ s->devtype = pdev->id_entry->driver_data;
+ }
+
s->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(s->clk)) {
ret = PTR_ERR(s->clk);
@@ -751,7 +1106,6 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
s->port.type = PORT_IMX;
s->port.dev = s->dev = get_device(&pdev->dev);
- s->flags = 0;
s->ctrl = 0;
s->irq = platform_get_irq(pdev, 0);
@@ -789,7 +1143,7 @@ out:
return ret;
}
-static int __devexit mxs_auart_remove(struct platform_device *pdev)
+static int mxs_auart_remove(struct platform_device *pdev)
{
struct mxs_auart_port *s = platform_get_drvdata(pdev);
@@ -805,15 +1159,9 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id mxs_auart_dt_ids[] = {
- { .compatible = "fsl,imx23-auart", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);
-
static struct platform_driver mxs_auart_driver = {
.probe = mxs_auart_probe,
- .remove = __devexit_p(mxs_auart_remove),
+ .remove = mxs_auart_remove,
.driver = {
.name = "mxs-auart",
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index df443b908ca3..e7cae1c2d7d2 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -21,8 +21,10 @@
#include <linux/of_serial.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
+#include <linux/clk.h>
struct of_serial_info {
+ struct clk *clk;
int type;
int line;
};
@@ -50,8 +52,9 @@ EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
/*
* Fill a struct uart_port for a given device node
*/
-static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
- int type, struct uart_port *port)
+static int of_platform_serial_setup(struct platform_device *ofdev,
+ int type, struct uart_port *port,
+ struct of_serial_info *info)
{
struct resource resource;
struct device_node *np = ofdev->dev.of_node;
@@ -60,8 +63,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
memset(port, 0, sizeof *port);
if (of_property_read_u32(np, "clock-frequency", &clk)) {
- dev_warn(&ofdev->dev, "no clock-frequency property set\n");
- return -ENODEV;
+
+ /* Get clk rate through clk driver if present */
+ info->clk = clk_get(&ofdev->dev, NULL);
+ if (IS_ERR(info->clk)) {
+ dev_warn(&ofdev->dev,
+ "clk or clock-frequency not defined\n");
+ return PTR_ERR(info->clk);
+ }
+
+ clk_prepare_enable(info->clk);
+ clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
if (of_property_read_u32(np, "current-speed", &spd) == 0)
@@ -70,7 +82,7 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
dev_warn(&ofdev->dev, "invalid address\n");
- return ret;
+ goto out;
}
spin_lock_init(&port->lock);
@@ -97,7 +109,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
default:
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
prop);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
}
@@ -115,13 +128,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
port->handle_break = tegra_serial_handle_break;
return 0;
+out:
+ if (info->clk)
+ clk_disable_unprepare(info->clk);
+ return ret;
}
/*
* Try to register a serial port
*/
static struct of_device_id of_platform_serial_table[];
-static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
+static int of_platform_serial_probe(struct platform_device *ofdev)
{
const struct of_device_id *match;
struct of_serial_info *info;
@@ -141,7 +158,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
return -ENOMEM;
port_type = (unsigned long)match->data;
- ret = of_platform_serial_setup(ofdev, port_type, &port);
+ ret = of_platform_serial_setup(ofdev, port_type, &port, info);
if (ret)
goto out;
@@ -204,6 +221,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
/* need to add code for these */
break;
}
+
+ if (info->clk)
+ clk_disable_unprepare(info->clk);
kfree(info);
return 0;
}
@@ -211,7 +231,7 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
/*
* A few common types, add more as needed.
*/
-static struct of_device_id __devinitdata of_platform_serial_table[] = {
+static struct of_device_id of_platform_serial_table[] = {
{ .compatible = "ns8250", .data = (void *)PORT_8250, },
{ .compatible = "ns16450", .data = (void *)PORT_16450, },
{ .compatible = "ns16550a", .data = (void *)PORT_16550A, },
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6d3d26a607b9..57d6b29c039c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -41,8 +41,9 @@
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/serial-omap.h>
-#include <plat/omap-serial.h>
+#define OMAP_MAX_HSUART_PORTS 6
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
@@ -51,10 +52,14 @@
#define OMAP_UART_REV_52 0x0502
#define OMAP_UART_REV_63 0x0603
+#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
+#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
+
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
/* SCR register bitmasks */
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
+#define OMAP_UART_SCR_TX_EMPTY (1 << 3)
/* FCR register bitmasks */
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
@@ -71,6 +76,52 @@
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
+#define OMAP_UART_DMA_CH_FREE -1
+
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+#define OMAP_MODE13X_SPEED 230400
+
+/* WER = 0x7F
+ * Enable module level wakeup in WER reg
+ */
+#define OMAP_UART_WER_MOD_WKUP 0X7F
+
+/* Enable XON/XOFF flow control on output */
+#define OMAP_UART_SW_TX 0x08
+
+/* Enable XON/XOFF flow control on input */
+#define OMAP_UART_SW_RX 0x02
+
+#define OMAP_UART_SW_CLR 0xF0
+
+#define OMAP_UART_TCR_TRIG 0x0F
+
+struct uart_omap_dma {
+ u8 uart_dma_tx;
+ u8 uart_dma_rx;
+ int rx_dma_channel;
+ int tx_dma_channel;
+ dma_addr_t rx_buf_dma_phys;
+ dma_addr_t tx_buf_dma_phys;
+ unsigned int uart_base;
+ /*
+ * Buffer for rx dma.It is not required for tx because the buffer
+ * comes from port structure.
+ */
+ unsigned char *rx_buf;
+ unsigned int prev_rx_dma_pos;
+ int tx_buf_size;
+ int tx_dma_used;
+ int rx_dma_used;
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+ /* timer to poll activity on rx dma */
+ struct timer_list rx_timer;
+ unsigned int rx_buf_size;
+ unsigned int rx_poll_rate;
+ unsigned int rx_timeout;
+};
+
struct uart_omap_port {
struct uart_port port;
struct uart_omap_dma uart_dma;
@@ -96,10 +147,9 @@ struct uart_omap_port {
unsigned char msr_saved_flags;
char name[20];
unsigned long port_activity;
- u32 context_loss_cnt;
+ int context_loss_cnt;
u32 errata;
u8 wakeups_enabled;
- unsigned int irq_pending:1;
int DTR_gpio;
int DTR_inverted;
@@ -303,6 +353,34 @@ static void serial_omap_start_tx(struct uart_port *port)
pm_runtime_put_autosuspend(up->dev);
}
+static void serial_omap_throttle(struct uart_port *port)
+{
+ struct uart_omap_port *up = to_uart_omap_port(port);
+ unsigned long flags;
+
+ pm_runtime_get_sync(up->dev);
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
+ serial_out(up, UART_IER, up->ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+}
+
+static void serial_omap_unthrottle(struct uart_port *port)
+{
+ struct uart_omap_port *up = to_uart_omap_port(port);
+ unsigned long flags;
+
+ pm_runtime_get_sync(up->dev);
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+}
+
static unsigned int check_modem_status(struct uart_omap_port *up)
{
unsigned int status;
@@ -504,7 +582,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned char mcr = 0;
+ unsigned char mcr = 0, old_mcr;
dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
if (mctrl & TIOCM_RTS)
@@ -519,8 +597,10 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
mcr |= UART_MCR_LOOP;
pm_runtime_get_sync(up->dev);
- up->mcr = serial_in(up, UART_MCR);
- up->mcr |= mcr;
+ old_mcr = serial_in(up, UART_MCR);
+ old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 |
+ UART_MCR_DTR | UART_MCR_RTS);
+ up->mcr = old_mcr | mcr;
serial_out(up, UART_MCR, up->mcr);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
@@ -654,65 +734,6 @@ static void serial_omap_shutdown(struct uart_port *port)
free_irq(up->port.irq, up);
}
-static inline void
-serial_omap_configure_xonxoff
- (struct uart_omap_port *up, struct ktermios *termios)
-{
- up->lcr = serial_in(up, UART_LCR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- up->efr = serial_in(up, UART_EFR);
- serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
-
- serial_out(up, UART_XON1, termios->c_cc[VSTART]);
- serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
-
- /* clear SW control mode bits */
- up->efr &= OMAP_UART_SW_CLR;
-
- /*
- * IXON Flag:
- * Enable XON/XOFF flow control on output.
- * Transmit XON1, XOFF1
- */
- if (termios->c_iflag & IXON)
- up->efr |= OMAP_UART_SW_TX;
-
- /*
- * IXOFF Flag:
- * Enable XON/XOFF flow control on input.
- * Receiver compares XON1, XOFF1.
- */
- if (termios->c_iflag & IXOFF)
- up->efr |= OMAP_UART_SW_RX;
-
- serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
- up->mcr = serial_in(up, UART_MCR);
-
- /*
- * IXANY Flag:
- * Enable any character to restart output.
- * Operation resumes after receiving any
- * character after recognition of the XOFF character
- */
- if (termios->c_iflag & IXANY)
- up->mcr |= UART_MCR_XONANY;
-
- serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- /* Enable special char function UARTi.EFR_REG[5] and
- * load the new software flow control mode IXON or IXOFF
- * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
- */
- serial_out(up, UART_EFR, up->efr | UART_EFR_SCD);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
- serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, up->lcr);
-}
-
static void serial_omap_uart_qos_work(struct work_struct *work)
{
struct uart_omap_port *up = container_of(work, struct uart_omap_port,
@@ -730,7 +751,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char cval = 0;
- unsigned char efr = 0;
unsigned long flags = 0;
unsigned int baud, quot;
@@ -840,11 +860,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- up->efr = serial_in(up, UART_EFR);
+ up->efr = serial_in(up, UART_EFR) & ~UART_EFR_ECB;
+ up->efr &= ~UART_EFR_SCD;
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- up->mcr = serial_in(up, UART_MCR);
+ up->mcr = serial_in(up, UART_MCR) & ~UART_MCR_TCRTLR;
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
/* FIFO ENABLE, DMA MODE */
@@ -863,9 +884,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_OMAP_SCR, up->scr);
- serial_out(up, UART_EFR, up->efr);
+ /* Reset UART_MCR_TCRTLR: this must be done with the EFR_ECB bit set */
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
/* Protocol, Baud Rate, and Interrupt Settings */
@@ -875,8 +899,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_OMAP_MDR1, up->mdr1);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-
- up->efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, 0);
@@ -903,29 +925,68 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);
- /* Hardware Flow Control Configuration */
+ /* Configure flow control */
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- if (termios->c_cflag & CRTSCTS) {
- efr |= (UART_EFR_CTS | UART_EFR_RTS);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+ /* XON1/XOFF1 accessible mode B, TCRTLR=0, ECB=0 */
+ serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+ serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
- up->mcr = serial_in(up, UART_MCR);
- serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+ /* Enable access to TCR/TLR */
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+
+ serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+
+ if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+ /* Enable AUTORTS and AUTOCTS */
+ up->efr |= UART_EFR_CTS | UART_EFR_RTS;
+
+ /* Ensure MCR RTS is asserted */
+ up->mcr |= UART_MCR_RTS;
+ } else {
+ /* Disable AUTORTS and AUTOCTS */
+ up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
+ }
+
+ if (up->port.flags & UPF_SOFT_FLOW) {
+ /* clear SW control mode bits */
+ up->efr &= OMAP_UART_SW_CLR;
+
+ /*
+ * IXON Flag:
+ * Enable XON/XOFF flow control on input.
+ * Receiver compares XON1, XOFF1.
+ */
+ if (termios->c_iflag & IXON)
+ up->efr |= OMAP_UART_SW_RX;
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- up->efr = serial_in(up, UART_EFR);
- serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ /*
+ * IXOFF Flag:
+ * Enable XON/XOFF flow control on output.
+ * Transmit XON1, XOFF1
+ */
+ if (termios->c_iflag & IXOFF)
+ up->efr |= OMAP_UART_SW_TX;
- serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
- serial_out(up, UART_LCR, cval);
+ /*
+ * IXANY Flag:
+ * Enable any character to restart output.
+ * Operation resumes after receiving any
+ * character after recognition of the XOFF character
+ */
+ if (termios->c_iflag & IXANY)
+ up->mcr |= UART_MCR_XONANY;
+ else
+ up->mcr &= ~UART_MCR_XONANY;
}
+ serial_out(up, UART_MCR, up->mcr);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, up->lcr);
serial_omap_set_mctrl(&up->port, up->port.mctrl);
- /* Software Flow Control Configuration */
- serial_omap_configure_xonxoff(up, termios);
spin_unlock_irqrestore(&up->port.lock, flags);
pm_runtime_mark_last_busy(up->dev);
@@ -991,6 +1052,7 @@ static void serial_omap_config_port(struct uart_port *port, int flags)
dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
up->port.line);
up->port.type = PORT_OMAP;
+ up->port.flags |= UPF_SOFT_FLOW | UPF_HARD_FLOW;
}
static int
@@ -1081,7 +1143,7 @@ out:
#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-static struct uart_omap_port *serial_omap_console_ports[4];
+static struct uart_omap_port *serial_omap_console_ports[OMAP_MAX_HSUART_PORTS];
static struct uart_driver serial_omap_reg;
@@ -1194,6 +1256,8 @@ static struct uart_ops serial_omap_pops = {
.get_mctrl = serial_omap_get_mctrl,
.stop_tx = serial_omap_stop_tx,
.start_tx = serial_omap_start_tx,
+ .throttle = serial_omap_throttle,
+ .unthrottle = serial_omap_unthrottle,
.stop_rx = serial_omap_stop_rx,
.enable_ms = serial_omap_enable_ms,
.break_ctl = serial_omap_break_ctl,
@@ -1242,7 +1306,7 @@ static int serial_omap_resume(struct device *dev)
}
#endif
-static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up)
+static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
u32 mvr, scheme;
u16 revision, major, minor;
@@ -1295,7 +1359,7 @@ static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *u
}
}
-static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
+static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{
struct omap_uart_port_info *omap_up_info;
@@ -1308,7 +1372,7 @@ static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device
return omap_up_info;
}
-static int __devinit serial_omap_probe(struct platform_device *pdev)
+static int serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
struct resource *mem, *irq;
@@ -1445,7 +1509,7 @@ err_port_line:
return ret;
}
-static int __devexit serial_omap_remove(struct platform_device *dev)
+static int serial_omap_remove(struct platform_device *dev)
{
struct uart_omap_port *up = platform_get_drvdata(dev);
@@ -1556,11 +1620,15 @@ static int serial_omap_runtime_resume(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
- u32 loss_cnt = serial_omap_get_context_loss_count(up);
+ int loss_cnt = serial_omap_get_context_loss_count(up);
- if (up->context_loss_cnt != loss_cnt)
+ if (loss_cnt < 0) {
+ dev_err(dev, "serial_omap_get_context_loss_count failed : %d\n",
+ loss_cnt);
serial_omap_restore_context(up);
-
+ } else if (up->context_loss_cnt != loss_cnt) {
+ serial_omap_restore_context(up);
+ }
up->latency = up->calc_latency;
schedule_work(&up->qos_work);
@@ -1586,7 +1654,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match);
static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
- .remove = __devexit_p(serial_omap_remove),
+ .remove = serial_omap_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 4cd6c2381528..8318925fbf6b 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1839,7 +1839,7 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
{0,},
};
-static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
+static int pch_uart_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
@@ -1869,7 +1869,7 @@ static struct pci_driver pch_uart_pci_driver = {
.name = "pch_uart",
.id_table = pch_uart_pci_id,
.probe = pch_uart_pci_probe,
- .remove = __devexit_p(pch_uart_pci_remove),
+ .remove = pch_uart_pci_remove,
.suspend = pch_uart_pci_suspend,
.resume = pch_uart_pci_resume,
};
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 9033fc6e0e4e..2764828251f5 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -705,6 +705,57 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
clk_disable_unprepare(up->clk);
}
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial_pxa_get_poll_char(struct uart_port *port)
+{
+ struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+ unsigned char lsr = serial_in(up, UART_LSR);
+
+ while (!(lsr & UART_LSR_DR))
+ lsr = serial_in(up, UART_LSR);
+
+ return serial_in(up, UART_RX);
+}
+
+
+static void serial_pxa_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ unsigned int ier;
+ struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+ /*
+ * First save the IER then disable the interrupts
+ */
+ ier = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, UART_IER_UUE);
+
+ wait_for_xmitr(up);
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
+ serial_out(up, UART_TX, c);
+ if (c == 10) {
+ wait_for_xmitr(up);
+ serial_out(up, UART_TX, 13);
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the IER
+ */
+ wait_for_xmitr(up);
+ serial_out(up, UART_IER, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
static int __init
serial_pxa_console_setup(struct console *co, char *options)
{
@@ -759,6 +810,10 @@ struct uart_ops serial_pxa_pops = {
.request_port = serial_pxa_request_port,
.config_port = serial_pxa_config_port,
.verify_port = serial_pxa_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = serial_pxa_get_poll_char,
+ .poll_put_char = serial_pxa_put_poll_char,
+#endif
};
static struct uart_driver serial_pxa_reg = {
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 2ca5959ec3fa..5d4b9b449b4a 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
+#include <linux/platform_data/sa11x0-serial.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -39,7 +40,6 @@
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
-#include <asm/mach/serial_sa1100.h>
/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_SA1100_MAJOR 204
@@ -637,7 +637,7 @@ static void __init sa1100_init_ports(void)
PPSR |= PPC_TXD1 | PPC_TXD3;
}
-void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns)
+void sa1100_register_uart_fns(struct sa1100_port_fns *fns)
{
if (fns->get_mctrl)
sa1100_pops.get_mctrl = fns->get_mctrl;
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 7f04717176aa..e514b3a4dc57 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -223,8 +223,11 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
struct uart_port *port = &ourport->port;
struct tty_struct *tty = port->state->port.tty;
unsigned int ufcon, ch, flag, ufstat, uerstat;
+ unsigned long flags;
int max_count = 64;
+ spin_lock_irqsave(&port->lock, flags);
+
while (max_count-- > 0) {
ufcon = rd_regl(port, S3C2410_UFCON);
ufstat = rd_regl(port, S3C2410_UFSTAT);
@@ -299,6 +302,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
tty_flip_buffer_push(tty);
out:
+ spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
@@ -307,8 +311,11 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
+ unsigned long flags;
int count = 256;
+ spin_lock_irqsave(&port->lock, flags);
+
if (port->x_char) {
wr_regb(port, S3C2410_UTXH, port->x_char);
port->icount.tx++;
@@ -336,13 +343,17 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
port->icount.tx++;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+ spin_unlock(&port->lock);
uart_write_wakeup(port);
+ spin_lock(&port->lock);
+ }
if (uart_circ_empty(xmit))
s3c24xx_serial_stop_tx(port);
out:
+ spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
@@ -352,10 +363,8 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
unsigned int pend = rd_regl(port, S3C64XX_UINTP);
- unsigned long flags;
irqreturn_t ret = IRQ_HANDLED;
- spin_lock_irqsave(&port->lock, flags);
if (pend & S3C64XX_UINTM_RXD_MSK) {
ret = s3c24xx_serial_rx_chars(irq, id);
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
@@ -364,7 +373,6 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
ret = s3c24xx_serial_tx_chars(irq, id);
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
}
- spin_unlock_irqrestore(&port->lock, flags);
return ret;
}
@@ -530,16 +538,16 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
switch (level) {
case 3:
if (!IS_ERR(ourport->baudclk))
- clk_disable(ourport->baudclk);
+ clk_disable_unprepare(ourport->baudclk);
- clk_disable(ourport->clk);
+ clk_disable_unprepare(ourport->clk);
break;
case 0:
- clk_enable(ourport->clk);
+ clk_prepare_enable(ourport->clk);
if (!IS_ERR(ourport->baudclk))
- clk_enable(ourport->baudclk);
+ clk_prepare_enable(ourport->baudclk);
break;
default:
@@ -713,11 +721,11 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
s3c24xx_serial_setsource(port, clk_sel);
if (!IS_ERR(ourport->baudclk)) {
- clk_disable(ourport->baudclk);
+ clk_disable_unprepare(ourport->baudclk);
ourport->baudclk = ERR_PTR(-EINVAL);
}
- clk_enable(clk);
+ clk_prepare_enable(clk);
ourport->baudclk = clk;
ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
@@ -998,7 +1006,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
ucon &= ucon_mask;
wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
- wr_regl(port, S3C2410_ULCON, cfg->ulcon);
/* reset both fifos */
wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
@@ -1256,7 +1263,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit s3c24xx_serial_remove(struct platform_device *dev)
+static int s3c24xx_serial_remove(struct platform_device *dev)
{
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
@@ -1287,9 +1294,9 @@ static int s3c24xx_serial_resume(struct device *dev)
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (port) {
- clk_enable(ourport->clk);
+ clk_prepare_enable(ourport->clk);
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
- clk_disable(ourport->clk);
+ clk_disable_unprepare(ourport->clk);
uart_resume_port(&s3c24xx_uart_drv, port);
}
@@ -1646,7 +1653,8 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
#endif
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) || \
- defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250)
+ defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250) || \
+ defined(CONFIG_SOC_EXYNOS5440)
static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
.info = &(struct s3c24xx_uart_info) {
.name = "Samsung Exynos4 UART",
@@ -1701,6 +1709,16 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);
#ifdef CONFIG_OF
static const struct of_device_id s3c24xx_uart_dt_match[] = {
+ { .compatible = "samsung,s3c2410-uart",
+ .data = (void *)S3C2410_SERIAL_DRV_DATA },
+ { .compatible = "samsung,s3c2412-uart",
+ .data = (void *)S3C2412_SERIAL_DRV_DATA },
+ { .compatible = "samsung,s3c2440-uart",
+ .data = (void *)S3C2440_SERIAL_DRV_DATA },
+ { .compatible = "samsung,s3c6400-uart",
+ .data = (void *)S3C6400_SERIAL_DRV_DATA },
+ { .compatible = "samsung,s5pv210-uart",
+ .data = (void *)S5PV210_SERIAL_DRV_DATA },
{ .compatible = "samsung,exynos4210-uart",
.data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
{},
@@ -1712,7 +1730,7 @@ MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
static struct platform_driver samsung_serial_driver = {
.probe = s3c24xx_serial_probe,
- .remove = __devexit_p(s3c24xx_serial_remove),
+ .remove = s3c24xx_serial_remove,
.id_table = s3c24xx_serial_driver_ids,
.driver = {
.name = "samsung-uart",
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index 9d664242b312..aced1dd923d8 100644
--- a/drivers/tty/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
@@ -621,7 +621,7 @@ static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
return bit ? (1 << (bit - 1)) : 0;
}
-static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+static void sc26xx_init_masks(struct uart_sc26xx_port *up,
int line, unsigned int data)
{
up->dtr_mask[line] = sc26xx_flags2mask(data, 0);
@@ -632,7 +632,7 @@ static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
up->ri_mask[line] = sc26xx_flags2mask(data, 20);
}
-static int __devinit sc26xx_probe(struct platform_device *dev)
+static int sc26xx_probe(struct platform_device *dev)
{
struct resource *res;
struct uart_sc26xx_port *up;
@@ -733,7 +733,7 @@ static int __exit sc26xx_driver_remove(struct platform_device *dev)
static struct platform_driver sc26xx_driver = {
.probe = sc26xx_probe,
- .remove = __devexit_p(sc26xx_driver_remove),
+ .remove = sc26xx_driver_remove,
.driver = {
.name = "SC26xx",
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index e821068cd95b..418b495e3233 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -740,7 +740,7 @@ static int sccnxp_console_setup(struct console *co, char *options)
}
#endif
-static int __devinit sccnxp_probe(struct platform_device *pdev)
+static int sccnxp_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int chiptype = pdev->id_entry->driver_data;
@@ -943,7 +943,7 @@ err_out:
return ret;
}
-static int __devexit sccnxp_remove(struct platform_device *pdev)
+static int sccnxp_remove(struct platform_device *pdev)
{
int i;
struct sccnxp_port *s = platform_get_drvdata(pdev);
@@ -981,7 +981,7 @@ static struct platform_driver sccnxp_uart_driver = {
.owner = THIS_MODULE,
},
.probe = sccnxp_probe,
- .remove = __devexit_p(sccnxp_remove),
+ .remove = sccnxp_remove,
.id_table = sccnxp_id_table,
};
module_platform_driver(sccnxp_uart_driver);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 0fcfd98a9566..2c7230aaefd4 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -610,34 +610,57 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
static void uart_throttle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ uint32_t mask = 0;
if (I_IXOFF(tty))
+ mask |= UPF_SOFT_FLOW;
+ if (tty->termios.c_cflag & CRTSCTS)
+ mask |= UPF_HARD_FLOW;
+
+ if (port->flags & mask) {
+ port->ops->throttle(port);
+ mask &= ~port->flags;
+ }
+
+ if (mask & UPF_SOFT_FLOW)
uart_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS)
- uart_clear_mctrl(state->uart_port, TIOCM_RTS);
+ if (mask & UPF_HARD_FLOW)
+ uart_clear_mctrl(port, TIOCM_RTS);
}
static void uart_unthrottle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
+ uint32_t mask = 0;
+
+ if (I_IXOFF(tty))
+ mask |= UPF_SOFT_FLOW;
+ if (tty->termios.c_cflag & CRTSCTS)
+ mask |= UPF_HARD_FLOW;
- if (I_IXOFF(tty)) {
+ if (port->flags & mask) {
+ port->ops->unthrottle(port);
+ mask &= ~port->flags;
+ }
+
+ if (mask & UPF_SOFT_FLOW) {
if (port->x_char)
port->x_char = 0;
else
uart_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS)
+ if (mask & UPF_HARD_FLOW)
uart_set_mctrl(port, TIOCM_RTS);
}
-static void uart_get_info(struct tty_port *port,
- struct uart_state *state,
+static void do_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));
@@ -662,17 +685,21 @@ static void uart_get_info(struct tty_port *port,
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
}
-static int uart_get_info_user(struct uart_state *state,
- struct serial_struct __user *retinfo)
+static void uart_get_info(struct tty_port *port,
+ struct serial_struct *retinfo)
{
- struct tty_port *port = &state->port;
- struct serial_struct tmp;
-
/* Ensure the state we copy is consistent and no hardware changes
occur as we go */
mutex_lock(&port->mutex);
- uart_get_info(port, state, &tmp);
+ do_uart_get_info(port, retinfo);
mutex_unlock(&port->mutex);
+}
+
+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)))
return -EFAULT;
@@ -1131,7 +1158,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
*/
switch (cmd) {
case TIOCGSERIAL:
- ret = uart_get_info_user(state, uarg);
+ ret = uart_get_info_user(port, uarg);
break;
case TIOCSSERIAL:
@@ -1210,9 +1237,22 @@ static void uart_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct uart_state *state = tty->driver_data;
+ struct uart_port *uport = state->uart_port;
unsigned long flags;
unsigned int cflag = tty->termios.c_cflag;
+ unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
+ bool sw_changed = false;
+ /*
+ * Drivers doing software flow control also need to know
+ * about changes to these input settings.
+ */
+ if (uport->flags & UPF_SOFT_FLOW) {
+ iflag_mask |= IXANY|IXON|IXOFF;
+ sw_changed =
+ tty->termios.c_cc[VSTART] != old_termios->c_cc[VSTART] ||
+ tty->termios.c_cc[VSTOP] != old_termios->c_cc[VSTOP];
+ }
/*
* These are the bits that are used to setup various
@@ -1220,11 +1260,11 @@ static void uart_set_termios(struct tty_struct *tty,
* bits in c_cflag; c_[io]speed will always be set
* appropriately by set_termios() in tty_ioctl.c
*/
-#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if ((cflag ^ old_termios->c_cflag) == 0 &&
tty->termios.c_ospeed == old_termios->c_ospeed &&
tty->termios.c_ispeed == old_termios->c_ispeed &&
- RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) {
+ ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
+ !sw_changed) {
return;
}
@@ -1232,31 +1272,38 @@ static void uart_set_termios(struct tty_struct *tty,
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
- uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
+ uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
/* Handle transition away from B0 status */
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
unsigned int mask = TIOCM_DTR;
if (!(cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags))
mask |= TIOCM_RTS;
- uart_set_mctrl(state->uart_port, mask);
+ uart_set_mctrl(uport, mask);
}
+ /*
+ * If the port is doing h/w assisted flow control, do nothing.
+ * We assume that tty->hw_stopped has never been set.
+ */
+ if (uport->flags & UPF_HARD_FLOW)
+ return;
+
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- spin_lock_irqsave(&state->uart_port->lock, flags);
+ spin_lock_irqsave(&uport->lock, flags);
tty->hw_stopped = 0;
__uart_start(tty);
- spin_unlock_irqrestore(&state->uart_port->lock, flags);
+ spin_unlock_irqrestore(&uport->lock, flags);
}
/* Handle turning on CRTSCTS */
else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
- spin_lock_irqsave(&state->uart_port->lock, flags);
- if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
+ spin_lock_irqsave(&uport->lock, flags);
+ if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
tty->hw_stopped = 1;
- state->uart_port->ops->stop_tx(state->uart_port);
+ uport->ops->stop_tx(uport);
}
- spin_unlock_irqrestore(&state->uart_port->lock, flags);
+ spin_unlock_irqrestore(&uport->lock, flags);
}
}
@@ -2293,6 +2340,8 @@ int uart_register_driver(struct uart_driver *drv)
if (retval >= 0)
return retval;
+ for (i = 0; i < drv->nr; i++)
+ tty_port_destroy(&drv->state[i].port);
put_tty_driver(normal);
out_kfree:
kfree(drv->state);
@@ -2312,8 +2361,12 @@ out:
void uart_unregister_driver(struct uart_driver *drv)
{
struct tty_driver *p = drv->tty_driver;
+ unsigned int i;
+
tty_unregister_driver(p);
put_tty_driver(p);
+ for (i = 0; i < drv->nr; i++)
+ tty_port_destroy(&drv->state[i].port);
kfree(drv->state);
drv->state = NULL;
drv->tty_driver = NULL;
@@ -2329,21 +2382,166 @@ struct tty_driver *uart_console_device(struct console *co, int *index)
static ssize_t uart_get_attr_uartclk(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int ret;
+ struct serial_struct tmp;
struct tty_port *port = dev_get_drvdata(dev);
- struct uart_state *state = container_of(port, struct uart_state, port);
- mutex_lock(&state->port.mutex);
- ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk);
- mutex_unlock(&state->port.mutex);
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16);
+}
- return ret;
+static ssize_t uart_get_attr_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type);
+}
+static ssize_t uart_get_attr_line(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line);
+}
+
+static ssize_t uart_get_attr_port(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+ unsigned long ioaddr;
+
+ uart_get_info(port, &tmp);
+ ioaddr = tmp.port;
+ if (HIGH_BITS_OFFSET)
+ ioaddr |= (unsigned long)tmp.port_high << HIGH_BITS_OFFSET;
+ return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr);
}
+static ssize_t uart_get_attr_irq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq);
+}
+
+static ssize_t uart_get_attr_flags(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags);
+}
+
+static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size);
+}
+
+
+static ssize_t uart_get_attr_close_delay(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay);
+}
+
+
+static ssize_t uart_get_attr_closing_wait(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait);
+}
+
+static ssize_t uart_get_attr_custom_divisor(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor);
+}
+
+static ssize_t uart_get_attr_io_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type);
+}
+
+static ssize_t uart_get_attr_iomem_base(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base);
+}
+
+static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct serial_struct tmp;
+ struct tty_port *port = dev_get_drvdata(dev);
+
+ uart_get_info(port, &tmp);
+ return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift);
+}
+
+static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL);
+static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL);
+static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL);
+static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL);
+static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL);
+static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL);
static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL);
+static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL);
+static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL);
+static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL);
+static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL);
+static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL);
+static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL);
static struct attribute *tty_dev_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_line.attr,
+ &dev_attr_port.attr,
+ &dev_attr_irq.attr,
+ &dev_attr_flags.attr,
+ &dev_attr_xmit_fifo_size.attr,
&dev_attr_uartclk.attr,
+ &dev_attr_close_delay.attr,
+ &dev_attr_closing_wait.attr,
+ &dev_attr_custom_divisor.attr,
+ &dev_attr_io_type.attr,
+ &dev_attr_iomem_base.attr,
+ &dev_attr_iomem_reg_shift.attr,
NULL,
};
@@ -2356,6 +2554,7 @@ static const struct attribute_group *tty_dev_attr_groups[] = {
NULL
};
+
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index 6ae2a58d62f2..b52b21aeb250 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -1030,7 +1030,7 @@ static DEFINE_MUTEX(serial_txx9_mutex);
*
* On success the port is ready to use and the line number is returned.
*/
-static int __devinit serial_txx9_register_port(struct uart_port *port)
+static int serial_txx9_register_port(struct uart_port *port)
{
int i;
struct uart_txx9_port *uart;
@@ -1078,7 +1078,7 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to the our control.
*/
-static void __devexit serial_txx9_unregister_port(int line)
+static void serial_txx9_unregister_port(int line)
{
struct uart_txx9_port *uart = &serial_txx9_ports[line];
@@ -1096,7 +1096,7 @@ static void __devexit serial_txx9_unregister_port(int line)
/*
* Register a set of serial devices attached to a platform device.
*/
-static int __devinit serial_txx9_probe(struct platform_device *dev)
+static int serial_txx9_probe(struct platform_device *dev)
{
struct uart_port *p = dev->dev.platform_data;
struct uart_port port;
@@ -1126,7 +1126,7 @@ static int __devinit serial_txx9_probe(struct platform_device *dev)
/*
* Remove serial ports registered against a platform device.
*/
-static int __devexit serial_txx9_remove(struct platform_device *dev)
+static int serial_txx9_remove(struct platform_device *dev)
{
int i;
@@ -1171,7 +1171,7 @@ static int serial_txx9_resume(struct platform_device *dev)
static struct platform_driver serial_txx9_plat_driver = {
.probe = serial_txx9_probe,
- .remove = __devexit_p(serial_txx9_remove),
+ .remove = serial_txx9_remove,
#ifdef CONFIG_PM
.suspend = serial_txx9_suspend,
.resume = serial_txx9_resume,
@@ -1187,7 +1187,7 @@ static struct platform_driver serial_txx9_plat_driver = {
* Probe one serial board. Unfortunately, there is no rhyme nor reason
* to the arrangement of serial ports on a PCI card.
*/
-static int __devinit
+static int
pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct uart_port port;
@@ -1217,7 +1217,7 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
return 0;
}
-static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
+static void pciserial_txx9_remove_one(struct pci_dev *dev)
{
struct uart_txx9_port *up = pci_get_drvdata(dev);
@@ -1261,7 +1261,7 @@ static const struct pci_device_id serial_txx9_pci_tbl[] = {
static struct pci_driver serial_txx9_pci_driver = {
.name = "serial_txx9",
.probe = pciserial_txx9_init_one,
- .remove = __devexit_p(pciserial_txx9_remove_one),
+ .remove = pciserial_txx9_remove_one,
#ifdef CONFIG_PM
.suspend = pciserial_txx9_suspend_one,
.resume = pciserial_txx9_resume_one,
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 6ee59001d61d..61477567423f 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -99,12 +99,6 @@ struct sci_port {
#endif
struct notifier_block freq_transition;
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
- unsigned short saved_smr;
- unsigned short saved_fcr;
- unsigned char saved_brr;
-#endif
};
/* Function prototypes */
@@ -202,9 +196,9 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCxSR] = { 0x14, 16 },
[SCxRDR] = { 0x60, 8 },
[SCFCR] = { 0x18, 16 },
- [SCFDR] = { 0x1c, 16 },
- [SCTFDR] = sci_reg_invalid,
- [SCRFDR] = sci_reg_invalid,
+ [SCFDR] = sci_reg_invalid,
+ [SCTFDR] = { 0x38, 16 },
+ [SCRFDR] = { 0x3c, 16 },
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
},
@@ -491,7 +485,7 @@ static int sci_txfill(struct uart_port *port)
reg = sci_getreg(port, SCTFDR);
if (reg->size)
- return serial_port_in(port, SCTFDR) & 0xff;
+ return serial_port_in(port, SCTFDR) & ((port->fifosize << 1) - 1);
reg = sci_getreg(port, SCFDR);
if (reg->size)
@@ -511,7 +505,7 @@ static int sci_rxfill(struct uart_port *port)
reg = sci_getreg(port, SCRFDR);
if (reg->size)
- return serial_port_in(port, SCRFDR) & 0xff;
+ return serial_port_in(port, SCRFDR) & ((port->fifosize << 1) - 1);
reg = sci_getreg(port, SCFDR);
if (reg->size)
@@ -1132,7 +1126,7 @@ static const char *sci_gpio_str(unsigned int index)
return sci_gpio_names[index];
}
-static void __devinit sci_init_gpios(struct sci_port *port)
+static void sci_init_gpios(struct sci_port *port)
{
struct uart_port *up = &port->port;
int i;
@@ -1749,22 +1743,21 @@ static inline void sci_free_dma(struct uart_port *port)
static int sci_startup(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ unsigned long flags;
int ret;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
- pm_runtime_put_noidle(port->dev);
-
- sci_port_enable(s);
-
ret = sci_request_irq(s);
if (unlikely(ret < 0))
return ret;
sci_request_dma(port);
+ spin_lock_irqsave(&port->lock, flags);
sci_start_tx(port);
sci_start_rx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
@@ -1772,18 +1765,17 @@ static int sci_startup(struct uart_port *port)
static void sci_shutdown(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ unsigned long flags;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ spin_lock_irqsave(&port->lock, flags);
sci_stop_rx(port);
sci_stop_tx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
sci_free_dma(port);
sci_free_irq(s);
-
- sci_port_disable(s);
-
- pm_runtime_get_noresume(port->dev);
}
static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
@@ -1829,7 +1821,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct sci_port *s = to_sci_port(port);
struct plat_sci_reg *reg;
- unsigned int baud, smr_val, max_baud;
+ unsigned int baud, smr_val, max_baud, cks;
int t = -1;
/*
@@ -1863,21 +1855,18 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
uart_update_timeout(port, termios->c_cflag, baud);
- serial_port_out(port, SCSMR, smr_val);
-
- dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
- s->cfg->scscr);
+ for (cks = 0; t >= 256 && cks <= 3; cks++)
+ t >>= 2;
- if (t > 0) {
- if (t >= 256) {
- serial_port_out(port, SCSMR, (serial_port_in(port, SCSMR) & ~3) | 1);
- t >>= 2;
- } else
- serial_port_out(port, SCSMR, serial_port_in(port, SCSMR) & ~3);
+ 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 & ~3) | cks);
serial_port_out(port, SCBRR, t);
udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
- }
+ } else
+ serial_port_out(port, SCSMR, smr_val);
sci_init_pins(port, termios->c_cflag);
@@ -1932,6 +1921,21 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_port_disable(s);
}
+static void sci_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct sci_port *sci_port = to_sci_port(port);
+
+ switch (state) {
+ case 3:
+ sci_port_disable(sci_port);
+ break;
+ default:
+ sci_port_enable(sci_port);
+ break;
+ }
+}
+
static const char *sci_type(struct uart_port *port)
{
switch (port->type) {
@@ -2053,6 +2057,7 @@ static struct uart_ops sci_uart_ops = {
.startup = sci_startup,
.shutdown = sci_shutdown,
.set_termios = sci_set_termios,
+ .pm = sci_pm,
.type = sci_type,
.release_port = sci_release_port,
.request_port = sci_request_port,
@@ -2064,7 +2069,7 @@ static struct uart_ops sci_uart_ops = {
#endif
};
-static int __devinit sci_init_single(struct platform_device *dev,
+static int sci_init_single(struct platform_device *dev,
struct sci_port *sci_port,
unsigned int index,
struct plat_sci_port *p)
@@ -2121,8 +2126,6 @@ static int __devinit sci_init_single(struct platform_device *dev,
sci_init_gpios(sci_port);
- pm_runtime_irq_safe(&dev->dev);
- pm_runtime_get_noresume(&dev->dev);
pm_runtime_enable(&dev->dev);
}
@@ -2206,9 +2209,21 @@ 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;
+ unsigned short bits, ctrl;
+ unsigned long flags;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&port->lock);
+ else
+ spin_lock(&port->lock);
- sci_port_enable(sci_port);
+ /* first save the SCSCR then disable the interrupts */
+ ctrl = serial_port_in(port, SCSCR);
+ serial_port_out(port, SCSCR, sci_port->cfg->scscr);
uart_console_write(port, s, count, serial_console_putchar);
@@ -2217,10 +2232,15 @@ static void serial_console_write(struct console *co, const char *s,
while ((serial_port_in(port, SCxSR) & bits) != bits)
cpu_relax();
- sci_port_disable(sci_port);
+ /* restore the SCSCR */
+ serial_port_out(port, SCSCR, ctrl);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
}
-static int __devinit serial_console_setup(struct console *co, char *options)
+static int serial_console_setup(struct console *co, char *options)
{
struct sci_port *sci_port;
struct uart_port *port;
@@ -2249,13 +2269,9 @@ static int __devinit serial_console_setup(struct console *co, char *options)
if (unlikely(ret != 0))
return ret;
- sci_port_enable(sci_port);
-
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- sci_port_disable(sci_port);
-
return uart_set_options(port, co, baud, parity, bits, flow);
}
@@ -2278,7 +2294,7 @@ static struct console early_serial_console = {
static char early_serial_buf[32];
-static int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
+static int sci_probe_earlyprintk(struct platform_device *pdev)
{
struct plat_sci_port *cfg = pdev->dev.platform_data;
@@ -2298,57 +2314,15 @@ static int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
return 0;
}
-#define uart_console(port) ((port)->cons->index == (port)->line)
-
-static int sci_runtime_suspend(struct device *dev)
-{
- struct sci_port *sci_port = dev_get_drvdata(dev);
- struct uart_port *port = &sci_port->port;
-
- if (uart_console(port)) {
- struct plat_sci_reg *reg;
-
- sci_port->saved_smr = serial_port_in(port, SCSMR);
- sci_port->saved_brr = serial_port_in(port, SCBRR);
-
- reg = sci_getreg(port, SCFCR);
- if (reg->size)
- sci_port->saved_fcr = serial_port_in(port, SCFCR);
- else
- sci_port->saved_fcr = 0;
- }
- return 0;
-}
-
-static int sci_runtime_resume(struct device *dev)
-{
- struct sci_port *sci_port = dev_get_drvdata(dev);
- struct uart_port *port = &sci_port->port;
-
- if (uart_console(port)) {
- sci_reset(port);
- serial_port_out(port, SCSMR, sci_port->saved_smr);
- serial_port_out(port, SCBRR, sci_port->saved_brr);
-
- if (sci_port->saved_fcr)
- serial_port_out(port, SCFCR, sci_port->saved_fcr);
-
- serial_port_out(port, SCSCR, sci_port->cfg->scscr);
- }
- return 0;
-}
-
#define SCI_CONSOLE (&serial_console)
#else
-static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
+static inline int sci_probe_earlyprintk(struct platform_device *pdev)
{
return -EINVAL;
}
#define SCI_CONSOLE NULL
-#define sci_runtime_suspend NULL
-#define sci_runtime_resume NULL
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
@@ -2379,7 +2353,7 @@ static int sci_remove(struct platform_device *dev)
return 0;
}
-static int __devinit sci_probe_single(struct platform_device *dev,
+static int sci_probe_single(struct platform_device *dev,
unsigned int index,
struct plat_sci_port *p,
struct sci_port *sciport)
@@ -2409,7 +2383,7 @@ static int __devinit sci_probe_single(struct platform_device *dev,
return 0;
}
-static int __devinit sci_probe(struct platform_device *dev)
+static int sci_probe(struct platform_device *dev)
{
struct plat_sci_port *p = dev->dev.platform_data;
struct sci_port *sp = &sci_ports[dev->id];
@@ -2466,8 +2440,6 @@ static int sci_resume(struct device *dev)
}
static const struct dev_pm_ops sci_dev_pm_ops = {
- .runtime_suspend = sci_runtime_suspend,
- .runtime_resume = sci_runtime_resume,
.suspend = sci_suspend,
.resume = sci_resume,
};
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index a9e2bd1ab534..5da5cb962769 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -727,7 +727,7 @@ static int sirfsoc_uart_resume(struct platform_device *pdev)
return 0;
}
-static struct of_device_id sirfsoc_uart_ids[] __devinitdata = {
+static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,prima2-uart", },
{}
};
@@ -735,7 +735,7 @@ MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
static struct platform_driver sirfsoc_uart_driver = {
.probe = sirfsoc_uart_probe,
- .remove = __devexit_p(sirfsoc_uart_remove),
+ .remove = sirfsoc_uart_remove,
.suspend = sirfsoc_uart_suspend,
.resume = sirfsoc_uart_resume,
.driver = {
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 505961cfd934..b9bf9c53f7fd 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -519,7 +519,7 @@ static struct console sunhv_console = {
.data = &sunhv_reg,
};
-static int __devinit hv_probe(struct platform_device *op)
+static int hv_probe(struct platform_device *op)
{
struct uart_port *port;
unsigned long minor;
@@ -598,7 +598,7 @@ out_free_port:
return err;
}
-static int __devexit hv_remove(struct platform_device *dev)
+static int hv_remove(struct platform_device *dev)
{
struct uart_port *port = dev_get_drvdata(&dev->dev);
@@ -636,7 +636,7 @@ static struct platform_driver hv_driver = {
.of_match_table = hv_match,
},
.probe = hv_probe,
- .remove = __devexit_p(hv_remove),
+ .remove = hv_remove,
};
static int __init sunhv_init(void)
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index f0d93eb7e6ec..bd8b3b634103 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -954,7 +954,7 @@ static inline struct console *SUNSAB_CONSOLE(void)
#define sunsab_console_init() do { } while (0)
#endif
-static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
+static int sunsab_init_one(struct uart_sunsab_port *up,
struct platform_device *op,
unsigned long offset,
int line)
@@ -1007,7 +1007,7 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
return 0;
}
-static int __devinit sab_probe(struct platform_device *op)
+static int sab_probe(struct platform_device *op)
{
static int inst;
struct uart_sunsab_port *up;
@@ -1063,7 +1063,7 @@ out:
return err;
}
-static int __devexit sab_remove(struct platform_device *op)
+static int sab_remove(struct platform_device *op)
{
struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
@@ -1100,7 +1100,7 @@ static struct platform_driver sab_driver = {
.of_match_table = sab_match,
},
.probe = sab_probe,
- .remove = __devexit_p(sab_remove),
+ .remove = sab_remove,
};
static int __init sunsab_init(void)
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index b97913dcdbff..220da3f9724f 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1185,7 +1185,7 @@ static struct uart_driver sunsu_reg = {
.major = TTY_MAJOR,
};
-static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
+static int sunsu_kbd_ms_init(struct uart_sunsu_port *up)
{
int quot, baud;
#ifdef CONFIG_SERIO
@@ -1391,7 +1391,7 @@ static inline struct console *SUNSU_CONSOLE(void)
#define sunsu_serial_console_init() do { } while (0)
#endif
-static enum su_type __devinit su_get_type(struct device_node *dp)
+static enum su_type su_get_type(struct device_node *dp)
{
struct device_node *ap = of_find_node_by_path("/aliases");
@@ -1412,7 +1412,7 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
return SU_PORT_PORT;
}
-static int __devinit su_probe(struct platform_device *op)
+static int su_probe(struct platform_device *op)
{
static int inst;
struct device_node *dp = op->dev.of_node;
@@ -1503,7 +1503,7 @@ out_unmap:
return err;
}
-static int __devexit su_remove(struct platform_device *op)
+static int su_remove(struct platform_device *op)
{
struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
bool kbdms = false;
@@ -1556,7 +1556,7 @@ static struct platform_driver su_driver = {
.of_match_table = su_match,
},
.probe = su_probe,
- .remove = __devexit_p(su_remove),
+ .remove = su_remove,
};
static int __init sunsu_init(void)
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index babd9470982b..aef4fab957c3 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -1282,7 +1282,7 @@ static inline struct console *SUNZILOG_CONSOLE(void)
#define SUNZILOG_CONSOLE() (NULL)
#endif
-static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
+static void sunzilog_init_kbdms(struct uart_sunzilog_port *up)
{
int baud, brg;
@@ -1302,7 +1302,7 @@ static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
}
#ifdef CONFIG_SERIO
-static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
+static void sunzilog_register_serio(struct uart_sunzilog_port *up)
{
struct serio *serio = &up->serio;
@@ -1331,7 +1331,7 @@ static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
}
#endif
-static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
+static void sunzilog_init_hw(struct uart_sunzilog_port *up)
{
struct zilog_channel __iomem *channel;
unsigned long flags;
@@ -1400,7 +1400,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
static int zilog_irq;
-static int __devinit zs_probe(struct platform_device *op)
+static int zs_probe(struct platform_device *op)
{
static int kbm_inst, uart_inst;
int inst;
@@ -1507,7 +1507,7 @@ static int __devinit zs_probe(struct platform_device *op)
return 0;
}
-static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
+static void zs_remove_one(struct uart_sunzilog_port *up)
{
if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
#ifdef CONFIG_SERIO
@@ -1517,7 +1517,7 @@ static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
uart_remove_one_port(&sunzilog_reg, &up->port);
}
-static int __devexit zs_remove(struct platform_device *op)
+static int zs_remove(struct platform_device *op)
{
struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
struct zilog_layout __iomem *regs;
@@ -1548,7 +1548,7 @@ static struct platform_driver zs_driver = {
.of_match_table = zs_match,
},
.probe = zs_probe,
- .remove = __devexit_p(zs_remove),
+ .remove = zs_remove,
};
static int __init sunzilog_init(void)
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index 70f97491d8f2..5be0d68feceb 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -426,7 +426,7 @@ static struct uart_driver timbuart_driver = {
.nr = 1
};
-static int __devinit timbuart_probe(struct platform_device *dev)
+static int timbuart_probe(struct platform_device *dev)
{
int err, irq;
struct timbuart_port *uart;
@@ -492,7 +492,7 @@ err_mem:
return err;
}
-static int __devexit timbuart_remove(struct platform_device *dev)
+static int timbuart_remove(struct platform_device *dev)
{
struct timbuart_port *uart = platform_get_drvdata(dev);
@@ -510,7 +510,7 @@ static struct platform_driver timbuart_platform_driver = {
.owner = THIS_MODULE,
},
.probe = timbuart_probe,
- .remove = __devexit_p(timbuart_remove),
+ .remove = timbuart_remove,
};
module_platform_driver(timbuart_platform_driver);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 6579ffdd8e9b..89eee43c4e2d 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -408,7 +408,7 @@ static void ulite_console_write(struct console *co, const char *s,
spin_unlock_irqrestore(&port->lock, flags);
}
-static int __devinit ulite_console_setup(struct console *co, char *options)
+static int ulite_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
@@ -486,7 +486,7 @@ static struct uart_driver ulite_uart_driver = {
*
* Returns: 0 on success, <0 otherwise
*/
-static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
+static int ulite_assign(struct device *dev, int id, u32 base, int irq)
{
struct uart_port *port;
int rc;
@@ -542,7 +542,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
*
* @dev: pointer to device structure
*/
-static int __devexit ulite_release(struct device *dev)
+static int ulite_release(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
int rc = 0;
@@ -562,7 +562,7 @@ static int __devexit ulite_release(struct device *dev)
#if defined(CONFIG_OF)
/* Match table for of_platform binding */
-static struct of_device_id ulite_of_match[] __devinitdata = {
+static struct of_device_id ulite_of_match[] = {
{ .compatible = "xlnx,opb-uartlite-1.00.b", },
{ .compatible = "xlnx,xps-uartlite-1.00.a", },
{}
@@ -570,7 +570,7 @@ static struct of_device_id ulite_of_match[] __devinitdata = {
MODULE_DEVICE_TABLE(of, ulite_of_match);
#endif /* CONFIG_OF */
-static int __devinit ulite_probe(struct platform_device *pdev)
+static int ulite_probe(struct platform_device *pdev)
{
struct resource *res, *res2;
int id = pdev->id;
@@ -593,7 +593,7 @@ static int __devinit ulite_probe(struct platform_device *pdev)
return ulite_assign(&pdev->dev, id, res->start, res2->start);
}
-static int __devexit ulite_remove(struct platform_device *pdev)
+static int ulite_remove(struct platform_device *pdev)
{
return ulite_release(&pdev->dev);
}
@@ -603,7 +603,7 @@ MODULE_ALIAS("platform:uartlite");
static struct platform_driver ulite_platform_driver = {
.probe = ulite_probe,
- .remove = __devexit_p(ulite_remove),
+ .remove = ulite_remove,
.driver = {
.owner = THIS_MODULE,
.name = "uartlite",
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index cf0d9485ec08..62ee0166bc65 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -823,7 +823,7 @@ static struct console siu_console = {
.data = &siu_uart_driver,
};
-static int __devinit siu_console_init(void)
+static int siu_console_init(void)
{
struct uart_port *port;
int i;
@@ -867,7 +867,7 @@ static struct uart_driver siu_uart_driver = {
.cons = SERIAL_VR41XX_CONSOLE,
};
-static int __devinit siu_probe(struct platform_device *dev)
+static int siu_probe(struct platform_device *dev)
{
struct uart_port *port;
int num, i, retval;
@@ -901,7 +901,7 @@ static int __devinit siu_probe(struct platform_device *dev)
return 0;
}
-static int __devexit siu_remove(struct platform_device *dev)
+static int siu_remove(struct platform_device *dev)
{
struct uart_port *port;
int i;
@@ -952,7 +952,7 @@ static int siu_resume(struct platform_device *dev)
static struct platform_driver siu_device_driver = {
.probe = siu_probe,
- .remove = __devexit_p(siu_remove),
+ .remove = siu_remove,
.suspend = siu_suspend,
.resume = siu_resume,
.driver = {
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 205d4cf4a063..d5ed9f613005 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -554,7 +554,7 @@ static struct uart_driver vt8500_uart_driver = {
.cons = VT8500_CONSOLE,
};
-static int __devinit vt8500_serial_probe(struct platform_device *pdev)
+static int vt8500_serial_probe(struct platform_device *pdev)
{
struct vt8500_port *vt8500_port;
struct resource *mmres, *irqres;
@@ -567,10 +567,6 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev)
if (!mmres || !irqres)
return -ENODEV;
- vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
- if (!vt8500_port)
- return -ENOMEM;
-
if (np)
port = of_alias_get_id(np, "serial");
if (port > VT8500_MAX_PORTS)
@@ -593,6 +589,10 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev)
return -EBUSY;
}
+ vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
+ if (!vt8500_port)
+ return -ENOMEM;
+
vt8500_port->uart.type = PORT_VT8500;
vt8500_port->uart.iotype = UPIO_MEM;
vt8500_port->uart.mapbase = mmres->start;
@@ -604,7 +604,7 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev)
vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);
- if (vt8500_port->clk) {
+ if (!IS_ERR(vt8500_port->clk)) {
vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk);
} else {
/* use the default of 24Mhz if not specified and warn */
@@ -634,7 +634,7 @@ err:
return ret;
}
-static int __devexit vt8500_serial_remove(struct platform_device *pdev)
+static int vt8500_serial_remove(struct platform_device *pdev)
{
struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
@@ -652,7 +652,7 @@ static const struct of_device_id wmt_dt_ids[] = {
static struct platform_driver vt8500_platform_driver = {
.probe = vt8500_serial_probe,
- .remove = __devexit_p(vt8500_serial_remove),
+ .remove = vt8500_serial_remove,
.driver = {
.name = "vt8500_serial",
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index b627363352e5..9ab910370c56 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -939,22 +939,18 @@ static struct uart_driver xuartps_uart_driver = {
*
* Returns 0 on success, negative error otherwise
**/
-static int __devinit xuartps_probe(struct platform_device *pdev)
+static int xuartps_probe(struct platform_device *pdev)
{
int rc;
struct uart_port *port;
struct resource *res, *res2;
int clk = 0;
-#ifdef CONFIG_OF
const unsigned int *prop;
prop = of_get_property(pdev->dev.of_node, "clock", NULL);
if (prop)
clk = be32_to_cpup(prop);
-#else
- clk = *((unsigned int *)(pdev->dev.platform_data));
-#endif
if (!clk) {
dev_err(&pdev->dev, "no clock specified\n");
return -ENODEV;
@@ -1001,7 +997,7 @@ static int __devinit xuartps_probe(struct platform_device *pdev)
*
* Returns 0 on success, negative error otherwise
**/
-static int __devexit xuartps_remove(struct platform_device *pdev)
+static int xuartps_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
int rc = 0;
@@ -1044,16 +1040,11 @@ static int xuartps_resume(struct platform_device *pdev)
}
/* Match table for of_platform binding */
-
-#ifdef CONFIG_OF
-static struct of_device_id xuartps_of_match[] __devinitdata = {
+static struct of_device_id xuartps_of_match[] = {
{ .compatible = "xlnx,xuartps", },
{}
};
MODULE_DEVICE_TABLE(of, xuartps_of_match);
-#else
-#define xuartps_of_match NULL
-#endif
static struct platform_driver xuartps_platform_driver = {
.probe = xuartps_probe, /* Probe method */
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 70e3a525bc82..9e071f6985f6 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -898,7 +898,7 @@ static struct pci_driver synclink_pci_driver = {
.name = "synclink",
.id_table = synclink_pci_tbl,
.probe = synclink_init_one,
- .remove = __devexit_p(synclink_remove_one),
+ .remove = synclink_remove_one,
};
static struct tty_driver *serial_driver;
@@ -4425,6 +4425,7 @@ static void synclink_cleanup(void)
mgsl_release_resources(info);
tmp = info;
info = info->next_device;
+ tty_port_destroy(&tmp->port);
kfree(tmp);
}
@@ -8064,7 +8065,7 @@ static void hdlcdev_exit(struct mgsl_struct *info)
#endif /* CONFIG_HDLC */
-static int __devinit synclink_init_one (struct pci_dev *dev,
+static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent)
{
struct mgsl_struct *info;
@@ -8116,7 +8117,7 @@ static int __devinit synclink_init_one (struct pci_dev *dev,
return 0;
}
-static void __devexit synclink_remove_one (struct pci_dev *dev)
+static void synclink_remove_one (struct pci_dev *dev)
{
}
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index b38e954eedd3..aba1e59f4a88 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -110,7 +110,7 @@ static struct pci_driver pci_driver = {
.name = "synclink_gt",
.id_table = pci_table,
.probe = init_one,
- .remove = __devexit_p(remove_one),
+ .remove = remove_one,
};
static bool pci_registered;
@@ -3645,8 +3645,10 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
for (i=0; i < port_count; ++i) {
port_array[i] = alloc_dev(adapter_num, i, pdev);
if (port_array[i] == NULL) {
- for (--i; i >= 0; --i)
+ for (--i; i >= 0; --i) {
+ tty_port_destroy(&port_array[i]->port);
kfree(port_array[i]);
+ }
return;
}
}
@@ -3696,7 +3698,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
}
-static int __devinit init_one(struct pci_dev *dev,
+static int init_one(struct pci_dev *dev,
const struct pci_device_id *ent)
{
if (pci_enable_device(dev)) {
@@ -3708,7 +3710,7 @@ static int __devinit init_one(struct pci_dev *dev,
return 0;
}
-static void __devexit remove_one(struct pci_dev *dev)
+static void remove_one(struct pci_dev *dev)
{
}
@@ -3773,6 +3775,7 @@ static void slgt_cleanup(void)
release_resources(info);
tmp = info;
info = info->next_device;
+ tty_port_destroy(&tmp->port);
kfree(tmp);
}
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index f17d9f3d84a2..fd43fb6f7cee 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -492,7 +492,7 @@ static struct pci_driver synclinkmp_pci_driver = {
.name = "synclinkmp",
.id_table = synclinkmp_pci_tbl,
.probe = synclinkmp_init_one,
- .remove = __devexit_p(synclinkmp_remove_one),
+ .remove = synclinkmp_remove_one,
};
@@ -3843,8 +3843,10 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
port_array[port] = alloc_dev(adapter_num,port,pdev);
if( port_array[port] == NULL ) {
- for ( --port; port >= 0; --port )
+ for (--port; port >= 0; --port) {
+ tty_port_destroy(&port_array[port]->port);
kfree(port_array[port]);
+ }
return;
}
}
@@ -3953,6 +3955,7 @@ static void synclinkmp_cleanup(void)
}
tmp = info;
info = info->next_device;
+ tty_port_destroy(&tmp->port);
kfree(tmp);
}
@@ -5592,7 +5595,7 @@ static void write_control_reg(SLMP_INFO * info)
}
-static int __devinit synclinkmp_init_one (struct pci_dev *dev,
+static int synclinkmp_init_one (struct pci_dev *dev,
const struct pci_device_id *ent)
{
if (pci_enable_device(dev)) {
@@ -5603,6 +5606,6 @@ static int __devinit synclinkmp_init_one (struct pci_dev *dev,
return 0;
}
-static void __devexit synclinkmp_remove_one (struct pci_dev *dev)
+static void synclinkmp_remove_one (struct pci_dev *dev)
{
}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 16ee6cee07da..b3c4a250ff86 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -346,7 +346,8 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(struct work_struct *ignored)
{
- out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL, true);
+ out_of_memory(node_zonelist(first_online_node, GFP_KERNEL), GFP_KERNEL,
+ 0, NULL, true);
}
static DECLARE_WORK(moom_work, moom_callback);
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index b0b39b823ccf..6953dc82850c 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -23,7 +23,7 @@ struct tty_audit_buf {
};
static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
- int icanon)
+ unsigned icanon)
{
struct tty_audit_buf *buf;
@@ -239,7 +239,8 @@ int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
* if TTY auditing is disabled or out of memory. Otherwise, return a new
* reference to the buffer.
*/
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
+static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
+ unsigned icanon)
{
struct tty_audit_buf *buf, *buf2;
@@ -257,7 +258,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
buf2 = tty_audit_buf_alloc(tty->driver->major,
tty->driver->minor_start + tty->index,
- tty->icanon);
+ icanon);
if (buf2 == NULL) {
audit_log_lost("out of memory in TTY auditing");
return NULL;
@@ -287,7 +288,7 @@ 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, unsigned char *data,
- size_t size)
+ size_t size, unsigned icanon)
{
struct tty_audit_buf *buf;
int major, minor;
@@ -299,7 +300,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
&& tty->driver->subtype == PTY_TYPE_MASTER)
return;
- buf = tty_audit_buf_get(tty);
+ buf = tty_audit_buf_get(tty, icanon);
if (!buf)
return;
@@ -307,11 +308,11 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
major = tty->driver->major;
minor = tty->driver->minor_start + tty->index;
if (buf->major != major || buf->minor != minor
- || buf->icanon != tty->icanon) {
+ || buf->icanon != icanon) {
tty_audit_buf_push_current(buf);
buf->major = major;
buf->minor = minor;
- buf->icanon = tty->icanon;
+ buf->icanon = icanon;
}
do {
size_t run;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 91e326ffe7db..45d916198f78 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -27,19 +27,21 @@
* Locking: none
*/
-void tty_buffer_free_all(struct tty_struct *tty)
+void tty_buffer_free_all(struct tty_port *port)
{
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *thead;
- while ((thead = tty->buf.head) != NULL) {
- tty->buf.head = thead->next;
+
+ while ((thead = buf->head) != NULL) {
+ buf->head = thead->next;
kfree(thead);
}
- while ((thead = tty->buf.free) != NULL) {
- tty->buf.free = thead->next;
+ while ((thead = buf->free) != NULL) {
+ buf->free = thead->next;
kfree(thead);
}
- tty->buf.tail = NULL;
- tty->buf.memory_used = 0;
+ buf->tail = NULL;
+ buf->memory_used = 0;
}
/**
@@ -54,11 +56,11 @@ void tty_buffer_free_all(struct tty_struct *tty)
* Locking: Caller must hold tty->buf.lock
*/
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
{
struct tty_buffer *p;
- if (tty->buf.memory_used + size > 65536)
+ if (port->buf.memory_used + size > 65536)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if (p == NULL)
@@ -70,7 +72,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
p->read = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
- tty->buf.memory_used += size;
+ port->buf.memory_used += size;
return p;
}
@@ -85,17 +87,19 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
* Locking: Caller must hold tty->buf.lock
*/
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
{
+ struct tty_bufhead *buf = &port->buf;
+
/* Dumb strategy for now - should keep some stats */
- tty->buf.memory_used -= b->size;
- WARN_ON(tty->buf.memory_used < 0);
+ buf->memory_used -= b->size;
+ WARN_ON(buf->memory_used < 0);
if (b->size >= 512)
kfree(b);
else {
- b->next = tty->buf.free;
- tty->buf.free = b;
+ b->next = buf->free;
+ buf->free = b;
}
}
@@ -110,15 +114,16 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
* Locking: Caller must hold tty->buf.lock
*/
-static void __tty_buffer_flush(struct tty_struct *tty)
+static void __tty_buffer_flush(struct tty_port *port)
{
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *thead;
- while ((thead = tty->buf.head) != NULL) {
- tty->buf.head = thead->next;
- tty_buffer_free(tty, thead);
+ while ((thead = buf->head) != NULL) {
+ buf->head = thead->next;
+ tty_buffer_free(port, thead);
}
- tty->buf.tail = NULL;
+ buf->tail = NULL;
}
/**
@@ -134,21 +139,24 @@ static void __tty_buffer_flush(struct tty_struct *tty)
void tty_buffer_flush(struct tty_struct *tty)
{
+ struct tty_port *port = tty->port;
+ struct tty_bufhead *buf = &port->buf;
unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
+
+ spin_lock_irqsave(&buf->lock, flags);
/* If the data is being pushed to the tty layer then we can't
process it here. Instead set a flag and the flush_to_ldisc
path will process the flush request before it exits */
- if (test_bit(TTY_FLUSHING, &tty->flags)) {
- set_bit(TTY_FLUSHPENDING, &tty->flags);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ if (test_bit(TTYP_FLUSHING, &port->iflags)) {
+ set_bit(TTYP_FLUSHPENDING, &port->iflags);
+ spin_unlock_irqrestore(&buf->lock, flags);
wait_event(tty->read_wait,
- test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+ test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0);
return;
} else
- __tty_buffer_flush(tty);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ __tty_buffer_flush(port);
+ spin_unlock_irqrestore(&buf->lock, flags);
}
/**
@@ -163,9 +171,9 @@ void tty_buffer_flush(struct tty_struct *tty)
* Locking: Caller must hold tty->buf.lock
*/
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
{
- struct tty_buffer **tbh = &tty->buf.free;
+ struct tty_buffer **tbh = &port->buf.free;
while ((*tbh) != NULL) {
struct tty_buffer *t = *tbh;
if (t->size >= size) {
@@ -174,14 +182,14 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
t->used = 0;
t->commit = 0;
t->read = 0;
- tty->buf.memory_used += t->size;
+ port->buf.memory_used += t->size;
return t;
}
tbh = &((*tbh)->next);
}
/* Round the buffer size out */
size = (size + 0xFF) & ~0xFF;
- return tty_buffer_alloc(tty, size);
+ return tty_buffer_alloc(port, size);
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
@@ -192,29 +200,31 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- * Locking: Caller must hold tty->buf.lock
+ * Locking: Caller must hold port->buf.lock
*/
-static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_port *port, size_t size)
{
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *b, *n;
int left;
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
- if ((b = tty->buf.tail) != NULL)
+ b = buf->tail;
+ if (b != NULL)
left = b->size - b->used;
else
left = 0;
if (left < size) {
/* This is the slow path - looking for new buffers to use */
- if ((n = tty_buffer_find(tty, size)) != NULL) {
+ if ((n = tty_buffer_find(port, size)) != NULL) {
if (b != NULL) {
b->next = n;
b->commit = b->used;
} else
- tty->buf.head = n;
- tty->buf.tail = n;
+ buf->head = n;
+ buf->tail = n;
} else
size = left;
}
@@ -231,16 +241,17 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
- * Locking: Takes tty->buf.lock
+ * Locking: Takes port->buf.lock
*/
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
+ struct tty_port *port = tty->port;
unsigned long flags;
int length;
- spin_lock_irqsave(&tty->buf.lock, flags);
- length = __tty_buffer_request_room(tty, size);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_lock_irqsave(&port->buf.lock, flags);
+ length = __tty_buffer_request_room(port, size);
+ spin_unlock_irqrestore(&port->buf.lock, flags);
return length;
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
@@ -255,12 +266,13 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* Queue a series of bytes to the tty buffering. All the characters
* passed are marked with the supplied flag. Returns the number added.
*
- * Locking: Called functions may take tty->buf.lock
+ * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
const unsigned char *chars, char flag, size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
@@ -268,18 +280,18 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
unsigned long flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, flags);
- space = __tty_buffer_request_room(tty, goal);
- tb = tty->buf.tail;
+ spin_lock_irqsave(&buf->lock, flags);
+ space = __tty_buffer_request_room(tty->port, goal);
+ tb = buf->tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0)) {
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
@@ -300,12 +312,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
* the flags array indicates the status of the character. Returns the
* number added.
*
- * Locking: Called functions may take tty->buf.lock
+ * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_flags(struct tty_struct *tty,
const unsigned char *chars, const char *flags, size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
@@ -313,18 +326,18 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
unsigned long __flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, __flags);
- space = __tty_buffer_request_room(tty, goal);
- tb = tty->buf.tail;
+ spin_lock_irqsave(&buf->lock, __flags);
+ space = __tty_buffer_request_room(tty->port, goal);
+ tb = buf->tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0)) {
- spin_unlock_irqrestore(&tty->buf.lock, __flags);
+ spin_unlock_irqrestore(&buf->lock, __flags);
break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space;
- spin_unlock_irqrestore(&tty->buf.lock, __flags);
+ spin_unlock_irqrestore(&buf->lock, __flags);
copied += space;
chars += space;
flags += space;
@@ -342,18 +355,23 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
* Takes any pending buffers and transfers their ownership to the
* ldisc side of the queue. It then schedules those characters for
* processing by the line discipline.
+ * Note that this function can only be used when the low_latency flag
+ * is unset. Otherwise the workqueue won't be flushed.
*
- * Locking: Takes tty->buf.lock
+ * Locking: Takes port->buf.lock
*/
void tty_schedule_flip(struct tty_struct *tty)
{
+ struct tty_bufhead *buf = &tty->port->buf;
unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL)
- tty->buf.tail->commit = tty->buf.tail->used;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- schedule_work(&tty->buf.work);
+ WARN_ON(tty->low_latency);
+
+ spin_lock_irqsave(&buf->lock, flags);
+ if (buf->tail != NULL)
+ buf->tail->commit = buf->tail->used;
+ spin_unlock_irqrestore(&buf->lock, flags);
+ schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_schedule_flip);
@@ -369,26 +387,27 @@ EXPORT_SYMBOL(tty_schedule_flip);
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*
- * Locking: May call functions taking tty->buf.lock
+ * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
- size_t size)
+ size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int space;
unsigned long flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, flags);
- space = __tty_buffer_request_room(tty, size);
+ spin_lock_irqsave(&buf->lock, flags);
+ space = __tty_buffer_request_room(tty->port, size);
- tb = tty->buf.tail;
+ tb = buf->tail;
if (likely(space)) {
*chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space;
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -406,26 +425,27 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*
- * Locking: May call functions taking tty->buf.lock
+ * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
+ struct tty_bufhead *buf = &tty->port->buf;
int space;
unsigned long __flags;
struct tty_buffer *tb;
- spin_lock_irqsave(&tty->buf.lock, __flags);
- space = __tty_buffer_request_room(tty, size);
+ spin_lock_irqsave(&buf->lock, __flags);
+ space = __tty_buffer_request_room(tty->port, size);
- tb = tty->buf.tail;
+ tb = buf->tail;
if (likely(space)) {
*chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used;
tb->used += space;
}
- spin_unlock_irqrestore(&tty->buf.lock, __flags);
+ spin_unlock_irqrestore(&buf->lock, __flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
@@ -446,20 +466,25 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
static void flush_to_ldisc(struct work_struct *work)
{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, buf.work);
+ struct tty_port *port = container_of(work, struct tty_port, buf.work);
+ struct tty_bufhead *buf = &port->buf;
+ struct tty_struct *tty;
unsigned long flags;
struct tty_ldisc *disc;
+ tty = port->itty;
+ if (WARN_RATELIMIT(tty == NULL, "tty is NULL\n"))
+ return;
+
disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */
return;
- spin_lock_irqsave(&tty->buf.lock, flags);
+ spin_lock_irqsave(&buf->lock, flags);
- if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+ if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
struct tty_buffer *head;
- while ((head = tty->buf.head) != NULL) {
+ while ((head = buf->head) != NULL) {
int count;
char *char_buf;
unsigned char *flag_buf;
@@ -468,14 +493,14 @@ static void flush_to_ldisc(struct work_struct *work)
if (!count) {
if (head->next == NULL)
break;
- tty->buf.head = head->next;
- tty_buffer_free(tty, head);
+ buf->head = head->next;
+ tty_buffer_free(port, head);
continue;
}
/* Ldisc or user is trying to flush the buffers
we are feeding to the ldisc, stop feeding the
line discipline as we want to empty the queue */
- if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+ if (test_bit(TTYP_FLUSHPENDING, &port->iflags))
break;
if (!tty->receive_room)
break;
@@ -484,22 +509,22 @@ static void flush_to_ldisc(struct work_struct *work)
char_buf = head->char_buf_ptr + head->read;
flag_buf = head->flag_buf_ptr + head->read;
head->read += count;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
disc->ops->receive_buf(tty, char_buf,
flag_buf, count);
- spin_lock_irqsave(&tty->buf.lock, flags);
+ spin_lock_irqsave(&buf->lock, flags);
}
- clear_bit(TTY_FLUSHING, &tty->flags);
+ clear_bit(TTYP_FLUSHING, &port->iflags);
}
/* We may have a deferred request to flush the input buffer,
if so pull the chain under the lock and empty the queue */
- if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
- __tty_buffer_flush(tty);
- clear_bit(TTY_FLUSHPENDING, &tty->flags);
+ if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
+ __tty_buffer_flush(port);
+ clear_bit(TTYP_FLUSHPENDING, &port->iflags);
wake_up(&tty->read_wait);
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_unlock_irqrestore(&buf->lock, flags);
tty_ldisc_deref(disc);
}
@@ -514,7 +539,8 @@ static void flush_to_ldisc(struct work_struct *work)
*/
void tty_flush_to_ldisc(struct tty_struct *tty)
{
- flush_work(&tty->buf.work);
+ if (!tty->low_latency)
+ flush_work(&tty->port->buf.work);
}
/**
@@ -532,16 +558,18 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
void tty_flip_buffer_push(struct tty_struct *tty)
{
+ struct tty_bufhead *buf = &tty->port->buf;
unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL)
- tty->buf.tail->commit = tty->buf.tail->used;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+ spin_lock_irqsave(&buf->lock, flags);
+ if (buf->tail != NULL)
+ buf->tail->commit = buf->tail->used;
+ spin_unlock_irqrestore(&buf->lock, flags);
if (tty->low_latency)
- flush_to_ldisc(&tty->buf.work);
+ flush_to_ldisc(&buf->work);
else
- schedule_work(&tty->buf.work);
+ schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_flip_buffer_push);
@@ -555,13 +583,15 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
* Locking: none
*/
-void tty_buffer_init(struct tty_struct *tty)
+void tty_buffer_init(struct tty_port *port)
{
- spin_lock_init(&tty->buf.lock);
- tty->buf.head = NULL;
- tty->buf.tail = NULL;
- tty->buf.free = NULL;
- tty->buf.memory_used = 0;
- INIT_WORK(&tty->buf.work, flush_to_ldisc);
+ struct tty_bufhead *buf = &port->buf;
+
+ spin_lock_init(&buf->lock);
+ buf->head = NULL;
+ buf->tail = NULL;
+ buf->free = NULL;
+ buf->memory_used = 0;
+ INIT_WORK(&buf->work, flush_to_ldisc);
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 2ea176b2280e..da9fde850754 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -186,7 +186,6 @@ void free_tty_struct(struct tty_struct *tty)
if (tty->dev)
put_device(tty->dev);
kfree(tty->write_buf);
- tty_buffer_free_all(tty);
tty->magic = 0xDEADDEAD;
kfree(tty);
}
@@ -237,7 +236,7 @@ void tty_free_file(struct file *file)
}
/* Delete file from its tty */
-void tty_del_file(struct file *file)
+static void tty_del_file(struct file *file)
{
struct tty_file_private *priv = file->private_data;
@@ -555,7 +554,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
* tasklist_lock to walk task list for hangup event
* ->siglock to protect ->signal/->sighand
*/
-void __tty_hangup(struct tty_struct *tty)
+static void __tty_hangup(struct tty_struct *tty)
{
struct file *cons_filp = NULL;
struct file *filp, *f = NULL;
@@ -1417,6 +1416,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
"%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
__func__, tty->driver->name);
+ tty->port->itty = tty;
+
/*
* Structures all installed ... call the ldisc open routines.
* If we fail here just call release_tty to clean up. No need
@@ -1552,6 +1553,7 @@ static void release_tty(struct tty_struct *tty, int idx)
tty->ops->shutdown(tty);
tty_free_termios(tty);
tty_driver_remove_tty(tty->driver, tty);
+ tty->port->itty = NULL;
if (tty->link)
tty_kref_put(tty->link);
@@ -1625,7 +1627,6 @@ int tty_release(struct inode *inode, struct file *filp)
struct tty_struct *tty = file_tty(filp);
struct tty_struct *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep;
- int devpts;
int idx;
char buf[64];
@@ -1640,7 +1641,6 @@ int tty_release(struct inode *inode, struct file *filp)
idx = tty->index;
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER);
- devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
/* Review: parallel close */
o_tty = tty->link;
@@ -1799,9 +1799,6 @@ int tty_release(struct inode *inode, struct file *filp)
release_tty(tty, idx);
mutex_unlock(&tty_mutex);
- /* Make this pty number available for reallocation */
- if (devpts)
- devpts_kill_index(inode, idx);
return 0;
}
@@ -2690,6 +2687,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCNXCL:
clear_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
+ case TIOCGEXCL:
+ {
+ int excl = test_bit(TTY_EXCLUSIVE, &tty->flags);
+ return put_user(excl, (int __user *)p);
+ }
case TIOCNOTTY:
if (current->signal->tty != tty)
return -ENOTTY;
@@ -2937,19 +2939,13 @@ void initialize_tty_struct(struct tty_struct *tty,
tty_ldisc_init(tty);
tty->session = NULL;
tty->pgrp = NULL;
- tty->overrun_time = jiffies;
- tty_buffer_init(tty);
mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
- mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
- mutex_init(&tty->output_lock);
- mutex_init(&tty->echo_lock);
- spin_lock_init(&tty->read_lock);
spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 12b1fa0f4f86..8481b29d5b3a 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -1118,7 +1118,6 @@ EXPORT_SYMBOL_GPL(tty_perform_flush);
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned long flags;
int retval;
switch (cmd) {
@@ -1153,26 +1152,6 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
return 0;
case TCFLSH:
return tty_perform_flush(tty, arg);
- case TIOCPKT:
- {
- int pktmode;
-
- if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
- tty->driver->subtype != PTY_TYPE_MASTER)
- return -ENOTTY;
- if (get_user(pktmode, (int __user *) arg))
- return -EFAULT;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (pktmode) {
- if (!tty->packet) {
- tty->packet = 1;
- tty->link->ctrl_status = 0;
- }
- } else
- tty->packet = 0;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- return 0;
- }
default:
/* Try the mode commands */
return tty_mode_ioctl(tty, file, cmd, arg);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 0f2a2c5e704c..c5782294e532 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -26,7 +26,7 @@
* callers who will do ldisc lookups and cannot sleep.
*/
-static DEFINE_SPINLOCK(tty_ldisc_lock);
+static DEFINE_RAW_SPINLOCK(tty_ldisc_lock);
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
@@ -49,21 +49,21 @@ static void put_ldisc(struct tty_ldisc *ld)
* If this is the last user, free the ldisc, and
* release the ldisc ops.
*
- * We really want an "atomic_dec_and_lock_irqsave()",
+ * We really want an "atomic_dec_and_raw_lock_irqsave()",
* but we don't have it, so this does it by hand.
*/
- local_irq_save(flags);
- if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+ if (atomic_dec_and_test(&ld->users)) {
struct tty_ldisc_ops *ldo = ld->ops;
ldo->refcount--;
module_put(ldo->owner);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
kfree(ld);
return;
}
- local_irq_restore(flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
wake_up(&ld->wq_idle);
}
@@ -88,11 +88,11 @@ int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
tty_ldiscs[disc] = new_ldisc;
new_ldisc->num = disc;
new_ldisc->refcount = 0;
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ret;
}
@@ -118,12 +118,12 @@ int tty_unregister_ldisc(int disc)
if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
if (tty_ldiscs[disc]->refcount)
ret = -EBUSY;
else
tty_ldiscs[disc] = NULL;
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ret;
}
@@ -134,7 +134,7 @@ static struct tty_ldisc_ops *get_ldops(int disc)
unsigned long flags;
struct tty_ldisc_ops *ldops, *ret;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
ret = ERR_PTR(-EINVAL);
ldops = tty_ldiscs[disc];
if (ldops) {
@@ -144,7 +144,7 @@ static struct tty_ldisc_ops *get_ldops(int disc)
ret = ldops;
}
}
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ret;
}
@@ -152,10 +152,10 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
{
unsigned long flags;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
ldops->refcount--;
module_put(ldops->owner);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
}
/**
@@ -287,11 +287,11 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
unsigned long flags;
struct tty_ldisc *ld;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
ld = NULL;
if (test_bit(TTY_LDISC, &tty->flags))
ld = get_ldisc(tty->ldisc);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ld;
}
@@ -512,7 +512,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
static int tty_ldisc_halt(struct tty_struct *tty)
{
clear_bit(TTY_LDISC, &tty->flags);
- return cancel_work_sync(&tty->buf.work);
+ return cancel_work_sync(&tty->port->buf.work);
}
/**
@@ -525,7 +525,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
{
flush_work(&tty->hangup_work);
flush_work(&tty->SAK_work);
- flush_work(&tty->buf.work);
+ flush_work(&tty->port->buf.work);
}
/**
@@ -704,9 +704,9 @@ enable:
/* Restart the work queue in case no characters kick it off. Safe if
already running */
if (work)
- schedule_work(&tty->buf.work);
+ schedule_work(&tty->port->buf.work);
if (o_work)
- schedule_work(&o_tty->buf.work);
+ schedule_work(&o_tty->port->buf.work);
mutex_unlock(&tty->ldisc_mutex);
tty_unlock(tty);
return retval;
@@ -817,7 +817,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
*/
clear_bit(TTY_LDISC, &tty->flags);
tty_unlock(tty);
- cancel_work_sync(&tty->buf.work);
+ cancel_work_sync(&tty->port->buf.work);
mutex_unlock(&tty->ldisc_mutex);
retry:
tty_lock(tty);
@@ -897,6 +897,11 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
static void tty_ldisc_kill(struct tty_struct *tty)
{
+ /* There cannot be users from userspace now. But there still might be
+ * drivers holding a reference via tty_ldisc_ref. Do not steal them the
+ * ldisc until they are done. */
+ tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT);
+
mutex_lock(&tty->ldisc_mutex);
/*
* Now kill off the ldisc
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 67feac9e6ebb..2e41abebbcba 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -19,7 +19,7 @@ static void __lockfunc tty_lock_nested(struct tty_struct *tty,
unsigned int subclass)
{
if (tty->magic != TTY_MAGIC) {
- printk(KERN_ERR "L Bad %p\n", tty);
+ pr_err("L Bad %p\n", tty);
WARN_ON(1);
return;
}
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(tty_lock);
void __lockfunc tty_unlock(struct tty_struct *tty)
{
if (tty->magic != TTY_MAGIC) {
- printk(KERN_ERR "U Bad %p\n", tty);
+ pr_err("U Bad %p\n", tty);
WARN_ON(1);
return;
}
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index d7bdd8d0c23f..b7ff59d3db88 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -21,6 +21,7 @@
void tty_port_init(struct tty_port *port)
{
memset(port, 0, sizeof(*port));
+ tty_buffer_init(port);
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
init_waitqueue_head(&port->delta_msr_wait);
@@ -121,12 +122,27 @@ void tty_port_free_xmit_buf(struct tty_port *port)
}
EXPORT_SYMBOL(tty_port_free_xmit_buf);
+/**
+ * tty_port_destroy -- destroy inited port
+ * @port: tty port to be doestroyed
+ *
+ * When a port was initialized using tty_port_init, one has to destroy the
+ * port by this function. Either indirectly by using tty_port refcounting
+ * (tty_port_put) or directly if refcounting is not used.
+ */
+void tty_port_destroy(struct tty_port *port)
+{
+ tty_buffer_free_all(port);
+}
+EXPORT_SYMBOL(tty_port_destroy);
+
static void tty_port_destructor(struct kref *kref)
{
struct tty_port *port = container_of(kref, struct tty_port, kref);
if (port->xmit_buf)
free_page((unsigned long)port->xmit_buf);
- if (port->ops->destruct)
+ tty_port_destroy(port);
+ if (port->ops && port->ops->destruct)
port->ops->destruct(port);
else
kfree(port);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 2aaa0c228409..248381b30722 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -410,10 +410,8 @@ static void con_release_unimap(struct uni_pagedir *p)
kfree(p->inverse_translations[i]);
p->inverse_translations[i] = NULL;
}
- if (p->inverse_trans_unicode) {
- kfree(p->inverse_trans_unicode);
- p->inverse_trans_unicode = NULL;
- }
+ kfree(p->inverse_trans_unicode);
+ p->inverse_trans_unicode = NULL;
}
/* Caller must hold the console lock */
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 8e9b4be97a2d..60b7b6926059 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -341,15 +341,11 @@ int paste_selection(struct tty_struct *tty)
struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current);
-
console_lock();
poke_blanked_console();
console_unlock();
- /* FIXME: wtf is this supposed to achieve ? */
- ld = tty_ldisc_ref(tty);
- if (!ld)
- ld = tty_ldisc_ref_wait(tty);
+ ld = tty_ldisc_ref_wait(tty);
/* FIXME: this is completely unsafe */
add_wait_queue(&vc->paste_wait, &wait);
@@ -361,8 +357,7 @@ int paste_selection(struct tty_struct *tty)
}
count = sel_buffer_lth - pasted;
count = min(count, tty->receive_room);
- tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
- NULL, count);
+ ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count);
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f87d7e8964bf..8fd89687d068 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -539,25 +539,25 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
+ scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
- (vc->vc_cols - vc->vc_x) / 2 + 1);
+ vc->vc_cols - vc->vc_x);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
+ scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2);
scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
- (vc->vc_cols - vc->vc_x) / 2);
+ vc->vc_cols - vc->vc_x);
}
static int softcursor_original;
@@ -779,6 +779,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
con_set_default_unimap(vc);
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
+ tty_port_destroy(&vc->port);
kfree(vc);
vc_cons[currcons].d = NULL;
return -ENOMEM;
@@ -999,8 +1000,10 @@ void vc_deallocate(unsigned int currcons)
put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
kfree(vc->vc_screenbuf);
- if (currcons >= MIN_NR_CONSOLES)
+ if (currcons >= MIN_NR_CONSOLES) {
+ tty_port_destroy(&vc->port);
kfree(vc);
+ }
vc_cons[currcons].d = NULL;
}
}
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index b841f56d2e66..98ff1735eafc 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -25,6 +25,7 @@
#include <linux/console.h>
#include <linux/consolemap.h>
#include <linux/signal.h>
+#include <linux/suspend.h>
#include <linux/timex.h>
#include <asm/io.h>