Merge tag 'tty-3.3-rc3' tty-next

This is needed to handle the 8250 file merge mess properly for future
patches.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2012-02-10 10:23:43 -08:00
commit 5a22e30def
34 changed files with 1152 additions and 230 deletions

View File

@ -0,0 +1,14 @@
* Energymicro efm32 UART
Required properties:
- compatible : Should be "efm32,uart"
- reg : Address and length of the register set
- interrupts : Should contain uart interrupt
Example:
uart@0x4000c400 {
compatible = "efm32,uart";
reg = <0x4000c400 0x400>;
interrupts = <15>;
};

View File

@ -1015,14 +1015,11 @@ capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
int idx = tty->index; int idx = tty->index;
struct capiminor *mp = capiminor_get(idx); struct capiminor *mp = capiminor_get(idx);
int ret = tty_init_termios(tty); int ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0)
tty_driver_kref_get(driver);
tty->count++;
tty->driver_data = mp; tty->driver_data = mp;
driver->ttys[idx] = tty; else
} else
capiminor_put(mp); capiminor_put(mp);
return ret; return ret;
} }

View File

@ -481,13 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
int idx = tty->index; int idx = tty->index;
struct pti_tty *pti_tty_data; struct pti_tty *pti_tty_data;
int ret = tty_init_termios(tty); int ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0) {
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[idx] = tty;
pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL); pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
if (pti_tty_data == NULL) if (pti_tty_data == NULL)
return -ENOMEM; return -ENOMEM;

View File

@ -750,15 +750,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
int idx = tty->index; int idx = tty->index;
struct sdio_uart_port *port = sdio_uart_port_get(idx); struct sdio_uart_port *port = sdio_uart_port_get(idx);
int ret = tty_init_termios(tty); int ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0)
tty_driver_kref_get(driver);
tty->count++;
/* This is the ref sdio_uart_port get provided */ /* This is the ref sdio_uart_port get provided */
tty->driver_data = port; tty->driver_data = port;
driver->ttys[idx] = tty; else
} else
sdio_uart_port_put(port); sdio_uart_port_put(port);
return ret; return ret;
} }

View File

@ -113,7 +113,7 @@ static int __init hvc_beat_init(void)
if (!firmware_has_feature(FW_FEATURE_BEAT)) if (!firmware_has_feature(FW_FEATURE_BEAT))
return -ENODEV; return -ENODEV;
hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
if (IS_ERR(hp)) if (IS_ERR(hp))
return PTR_ERR(hp); return PTR_ERR(hp);
hvc_beat_dev = hp; hvc_beat_dev = hp;

View File

@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void)
/* Allocate an hvc_struct for the console device we instantiated /* Allocate an hvc_struct for the console device we instantiated
* earlier. Save off hp so that we can return it on exit */ * earlier. Save off hp so that we can return it on exit */
hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
if (IS_ERR(hp)) if (IS_ERR(hp))
return PTR_ERR(hp); return PTR_ERR(hp);

View File

@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void)
BUG_ON(hvc_udbg_dev); BUG_ON(hvc_udbg_dev);
hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
if (IS_ERR(hp)) if (IS_ERR(hp))
return PTR_ERR(hp); return PTR_ERR(hp);

View File

@ -176,7 +176,7 @@ static int __init xen_hvc_init(void)
xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
} }
if (xencons_irq < 0) if (xencons_irq < 0)
xencons_irq = 0; /* NO_IRQ */ xencons_irq = 0;
else else
irq_set_noprobe(xencons_irq); irq_set_noprobe(xencons_irq);

View File

@ -1203,7 +1203,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
{ {
struct hvcs_struct *hvcsd; struct hvcs_struct *hvcsd;
unsigned long flags; unsigned long flags;
int irq = NO_IRQ; int irq;
/* /*
* Is someone trying to close the file associated with this device after * Is someone trying to close the file associated with this device after
@ -1264,7 +1264,7 @@ static void hvcs_hangup(struct tty_struct * tty)
struct hvcs_struct *hvcsd = tty->driver_data; struct hvcs_struct *hvcsd = tty->driver_data;
unsigned long flags; unsigned long flags;
int temp_open_count; int temp_open_count;
int irq = NO_IRQ; int irq;
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */ /* Preserve this so that we know how many kref refs to put */

View File

@ -1237,7 +1237,7 @@ static int __init hvsi_console_init(void)
hp->state = HVSI_CLOSED; hp->state = HVSI_CLOSED;
hp->vtermno = *vtermno; hp->vtermno = *vtermno;
hp->virq = irq_create_mapping(NULL, irq[0]); hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) { if (hp->virq == 0) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
__func__, irq[0]); __func__, irq[0]);
continue; continue;

View File

@ -1602,13 +1602,9 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
int ret; int ret;
if (!port || !dc || dc->state != NOZOMI_STATE_READY) if (!port || !dc || dc->state != NOZOMI_STATE_READY)
return -ENODEV; return -ENODEV;
ret = tty_init_termios(tty); ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0)
tty_driver_kref_get(driver);
tty->count++;
tty->driver_data = port; tty->driver_data = port;
driver->ttys[tty->index] = tty;
}
return ret; return ret;
} }

View File

@ -21,7 +21,6 @@
#include <linux/major.h> #include <linux/major.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sysctl.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/bitops.h> #include <linux/bitops.h>
@ -55,11 +54,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->link->write_wait); wake_up_interruptible(&tty->link->write_wait);
if (tty->driver->subtype == PTY_TYPE_MASTER) { if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags); set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver)
devpts_pty_kill(tty->link);
#endif
tty_unlock(); tty_unlock();
devpts_pty_kill(tty->link);
tty_vhangup(tty->link); tty_vhangup(tty->link);
tty_lock(); tty_lock();
} }
@ -439,55 +435,9 @@ static inline void legacy_pty_init(void) { }
/* Unix98 devices */ /* Unix98 devices */
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
/*
* sysctl support for setting limits on the number of Unix98 ptys allocated.
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
*/
int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
static int pty_count;
static struct cdev ptmx_cdev; static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = {
{
.procname = "max",
.maxlen = sizeof(int),
.mode = 0644,
.data = &pty_limit,
.proc_handler = proc_dointvec_minmax,
.extra1 = &pty_limit_min,
.extra2 = &pty_limit_max,
}, {
.procname = "nr",
.maxlen = sizeof(int),
.mode = 0444,
.data = &pty_count,
.proc_handler = proc_dointvec,
},
{}
};
static struct ctl_table pty_kern_table[] = {
{
.procname = "pty",
.mode = 0555,
.child = pty_table,
},
{}
};
static struct ctl_table pty_root_table[] = {
{
.procname = "kernel",
.mode = 0555,
.child = pty_kern_table,
},
{}
};
static int pty_unix98_ioctl(struct tty_struct *tty, static int pty_unix98_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
@ -515,10 +465,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
struct inode *ptm_inode, int idx) struct inode *ptm_inode, int idx)
{ {
struct tty_struct *tty = devpts_get_tty(ptm_inode, idx); /* Master must be open via /dev/ptmx */
if (tty) return ERR_PTR(-EIO);
tty = tty->link;
return tty;
} }
/** /**
@ -589,7 +537,6 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
*/ */
tty_driver_kref_get(driver); tty_driver_kref_get(driver);
tty->count++; tty->count++;
pty_count++;
return 0; return 0;
err_free_mem: err_free_mem:
deinitialize_tty_struct(o_tty); deinitialize_tty_struct(o_tty);
@ -603,7 +550,6 @@ err_free_tty:
static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{ {
pty_count--;
} }
static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
@ -667,9 +613,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval; return retval;
/* find a device that is not in use. */ /* find a device that is not in use. */
tty_lock();
index = devpts_new_index(inode); index = devpts_new_index(inode);
tty_unlock();
if (index < 0) { if (index < 0) {
retval = index; retval = index;
goto err_file; goto err_file;
@ -677,7 +621,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
tty_lock(); tty_lock();
tty = tty_init_dev(ptm_driver, index, 1); tty = tty_init_dev(ptm_driver, index);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
@ -704,8 +648,8 @@ err_release:
tty_release(inode, filp); tty_release(inode, filp);
return retval; return retval;
out: out:
devpts_kill_index(inode, index);
tty_unlock(); tty_unlock();
devpts_kill_index(inode, index);
err_file: err_file:
tty_free_file(filp); tty_free_file(filp);
return retval; return retval;
@ -762,8 +706,6 @@ static void __init unix98_pty_init(void)
if (tty_register_driver(pts_driver)) if (tty_register_driver(pts_driver))
panic("Couldn't register Unix98 pts driver"); panic("Couldn't register Unix98 pts driver");
register_sysctl_table(pty_root_table);
/* Now create the /dev/ptmx special device */ /* Now create the /dev/ptmx special device */
tty_default_fops(&ptmx_fops); tty_default_fops(&ptmx_fops);
ptmx_fops.open = ptmx_open; ptmx_fops.open = ptmx_open;

View File

@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct
int ret = 0; int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
ret = -EINVAL; ret = -EINVAL;
if (ser->irq != NO_IRQ) if (ser->irq <= 0)
ret = -EINVAL; ret = -EINVAL;
if (ser->baud_base != port->uartclk / 16) if (ser->baud_base != port->uartclk / 16)
ret = -EINVAL; ret = -EINVAL;
@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = {
static struct uart_port serial21285_port = { static struct uart_port serial21285_port = {
.mapbase = 0x42000160, .mapbase = 0x42000160,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.irq = NO_IRQ, .irq = 0,
.fifosize = 16, .fifosize = 16,
.ops = &serial21285_ops, .ops = &serial21285_ops,
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,

View File

@ -86,13 +86,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* We default to IRQ0 for the "no irq" hack. Some
* machine types want others as well - they're free
* to redefine this in their header file.
*/
#define is_real_interrupt(irq) ((irq) != 0)
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ #ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define CONFIG_SERIAL_DETECT_IRQ 1 #define CONFIG_SERIAL_DETECT_IRQ 1
#endif #endif
@ -1750,7 +1743,7 @@ static void serial8250_backup_timeout(unsigned long data)
* Must disable interrupts or else we risk racing with the interrupt * Must disable interrupts or else we risk racing with the interrupt
* based handler. * based handler.
*/ */
if (is_real_interrupt(up->port.irq)) { if (up->port.irq) {
ier = serial_in(up, UART_IER); ier = serial_in(up, UART_IER);
serial_out(up, UART_IER, 0); serial_out(up, UART_IER, 0);
} }
@ -1775,7 +1768,7 @@ static void serial8250_backup_timeout(unsigned long data)
if (!(iir & UART_IIR_NO_INT)) if (!(iir & UART_IIR_NO_INT))
serial8250_tx_chars(up); serial8250_tx_chars(up);
if (is_real_interrupt(up->port.irq)) if (up->port.irq)
serial_out(up, UART_IER, ier); serial_out(up, UART_IER, ier);
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
@ -2028,7 +2021,7 @@ static int serial8250_startup(struct uart_port *port)
serial_outp(up, UART_LCR, 0); serial_outp(up, UART_LCR, 0);
} }
if (is_real_interrupt(up->port.irq)) { if (up->port.irq) {
unsigned char iir1; unsigned char iir1;
/* /*
* Test for UARTs that do not reassert THRE when the * Test for UARTs that do not reassert THRE when the
@ -2083,7 +2076,7 @@ static int serial8250_startup(struct uart_port *port)
* hardware interrupt, we use a timer-based system. The original * hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0. * driver used to do this with IRQ0.
*/ */
if (!is_real_interrupt(up->port.irq)) { if (!up->port.irq) {
up->timer.data = (unsigned long)up; up->timer.data = (unsigned long)up;
mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
} else { } else {
@ -2099,13 +2092,13 @@ static int serial8250_startup(struct uart_port *port)
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
if (up->port.flags & UPF_FOURPORT) { if (up->port.flags & UPF_FOURPORT) {
if (!is_real_interrupt(up->port.irq)) if (!up->port.irq)
up->port.mctrl |= TIOCM_OUT1; up->port.mctrl |= TIOCM_OUT1;
} else } else
/* /*
* Most PC uarts need OUT2 raised to enable interrupts. * Most PC uarts need OUT2 raised to enable interrupts.
*/ */
if (is_real_interrupt(up->port.irq)) if (up->port.irq)
up->port.mctrl |= TIOCM_OUT2; up->port.mctrl |= TIOCM_OUT2;
serial8250_set_mctrl(&up->port, up->port.mctrl); serial8250_set_mctrl(&up->port, up->port.mctrl);
@ -2223,7 +2216,7 @@ static void serial8250_shutdown(struct uart_port *port)
del_timer_sync(&up->timer); del_timer_sync(&up->timer);
up->timer.function = serial8250_timeout; up->timer.function = serial8250_timeout;
if (is_real_interrupt(up->port.irq)) if (up->port.irq)
serial_unlink_irq_chain(up); serial_unlink_irq_chain(up);
} }

View File

@ -1347,4 +1347,17 @@ config SERIAL_AR933X_NR_UARTS
Set this to the number of serial ports you want the driver Set this to the number of serial ports you want the driver
to support. to support.
config SERIAL_EFM32_UART
tristate "EFM32 UART/USART port."
depends on ARCH_EFM32
select SERIAL_CORE
help
This driver support the USART and UART ports on
Energy Micro's efm32 SoCs.
config SERIAL_EFM32_UART_CONSOLE
bool "EFM32 UART/USART console support"
depends on SERIAL_EFM32_UART=y
select SERIAL_CORE_CONSOLE
endmenu endmenu

View File

@ -61,12 +61,12 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
@ -78,3 +78,4 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o

View File

@ -377,6 +377,26 @@ static int altera_uart_verify_port(struct uart_port *port,
return 0; return 0;
} }
#ifdef CONFIG_CONSOLE_POLL
static int altera_uart_poll_get_char(struct uart_port *port)
{
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_RRDY_MSK))
cpu_relax();
return altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
}
static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK))
cpu_relax();
altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
}
#endif
/* /*
* Define the basic serial functions we support. * Define the basic serial functions we support.
*/ */
@ -397,35 +417,16 @@ static struct uart_ops altera_uart_ops = {
.release_port = altera_uart_release_port, .release_port = altera_uart_release_port,
.config_port = altera_uart_config_port, .config_port = altera_uart_config_port,
.verify_port = altera_uart_verify_port, .verify_port = altera_uart_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = altera_uart_poll_get_char,
.poll_put_char = altera_uart_poll_put_char,
#endif
}; };
static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
{
struct uart_port *port;
int i;
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_uart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_UART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = platp[i].uartclk;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &altera_uart_ops;
port->private_data = platp;
}
return 0;
}
static void altera_uart_console_putc(struct uart_port *port, const char c) static void altera_uart_console_putc(struct uart_port *port, const char c)
{ {
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &

View File

@ -0,0 +1,830 @@
#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/serial_core.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_data/efm32-uart.h>
#define DRIVER_NAME "efm32-uart"
#define DEV_NAME "ttyefm"
#define UARTn_CTRL 0x00
#define UARTn_CTRL_SYNC 0x0001
#define UARTn_CTRL_TXBIL 0x1000
#define UARTn_FRAME 0x04
#define UARTn_FRAME_DATABITS__MASK 0x000f
#define UARTn_FRAME_DATABITS(n) ((n) - 3)
#define UARTn_FRAME_PARITY_NONE 0x0000
#define UARTn_FRAME_PARITY_EVEN 0x0200
#define UARTn_FRAME_PARITY_ODD 0x0300
#define UARTn_FRAME_STOPBITS_HALF 0x0000
#define UARTn_FRAME_STOPBITS_ONE 0x1000
#define UARTn_FRAME_STOPBITS_TWO 0x3000
#define UARTn_CMD 0x0c
#define UARTn_CMD_RXEN 0x0001
#define UARTn_CMD_RXDIS 0x0002
#define UARTn_CMD_TXEN 0x0004
#define UARTn_CMD_TXDIS 0x0008
#define UARTn_STATUS 0x10
#define UARTn_STATUS_TXENS 0x0002
#define UARTn_STATUS_TXC 0x0020
#define UARTn_STATUS_TXBL 0x0040
#define UARTn_STATUS_RXDATAV 0x0080
#define UARTn_CLKDIV 0x14
#define UARTn_RXDATAX 0x18
#define UARTn_RXDATAX_RXDATA__MASK 0x01ff
#define UARTn_RXDATAX_PERR 0x4000
#define UARTn_RXDATAX_FERR 0x8000
/*
* This is a software only flag used for ignore_status_mask and
* read_status_mask! It's used for breaks that the hardware doesn't report
* explicitly.
*/
#define SW_UARTn_RXDATAX_BERR 0x2000
#define UARTn_TXDATA 0x34
#define UARTn_IF 0x40
#define UARTn_IF_TXC 0x0001
#define UARTn_IF_TXBL 0x0002
#define UARTn_IF_RXDATAV 0x0004
#define UARTn_IF_RXOF 0x0010
#define UARTn_IFS 0x44
#define UARTn_IFC 0x48
#define UARTn_IEN 0x4c
#define UARTn_ROUTE 0x54
#define UARTn_ROUTE_LOCATION__MASK 0x0700
#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
#define UARTn_ROUTE_RXPEN 0x0001
#define UARTn_ROUTE_TXPEN 0x0002
struct efm32_uart_port {
struct uart_port port;
unsigned int txirq;
struct clk *clk;
};
#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
#define efm_debug(efm_port, format, arg...) \
dev_dbg(efm_port->port.dev, format, ##arg)
static void efm32_uart_write32(struct efm32_uart_port *efm_port,
u32 value, unsigned offset)
{
writel_relaxed(value, efm_port->port.membase + offset);
}
static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
unsigned offset)
{
return readl_relaxed(efm_port->port.membase + offset);
}
static unsigned int efm32_uart_tx_empty(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
if (status & UARTn_STATUS_TXC)
return TIOCSER_TEMT;
else
return 0;
}
static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* sorry, neither handshaking lines nor loop functionallity */
}
static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
{
/* sorry, no handshaking lines available */
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
}
static void efm32_uart_stop_tx(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 ien = efm32_uart_read32(efm_port, UARTn_IEN);
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
efm32_uart_write32(efm_port, ien, UARTn_IEN);
}
static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
{
struct uart_port *port = &efm_port->port;
struct circ_buf *xmit = &port->state->xmit;
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
UARTn_STATUS_TXBL) {
if (port->x_char) {
port->icount.tx++;
efm32_uart_write32(efm_port, port->x_char,
UARTn_TXDATA);
port->x_char = 0;
continue;
}
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
port->icount.tx++;
efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
UARTn_TXDATA);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
} else
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (!port->x_char && uart_circ_empty(xmit) &&
efm32_uart_read32(efm_port, UARTn_STATUS) &
UARTn_STATUS_TXC)
efm32_uart_stop_tx(port);
}
static void efm32_uart_start_tx(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 ien;
efm32_uart_write32(efm_port,
UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
ien = efm32_uart_read32(efm_port, UARTn_IEN);
efm32_uart_write32(efm_port,
ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
efm32_uart_tx_chars(efm_port);
}
static void efm32_uart_stop_rx(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
}
static void efm32_uart_enable_ms(struct uart_port *port)
{
/* no handshake lines, no modem status interrupts */
}
static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
{
/* not possible without fiddling with gpios */
}
static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
struct tty_struct *tty)
{
struct uart_port *port = &efm_port->port;
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
UARTn_STATUS_RXDATAV) {
u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
int flag = 0;
/*
* This is a reserved bit and I only saw it read as 0. But to be
* sure not to be confused too much by new devices adhere to the
* warning in the reference manual that reserverd bits might
* read as 1 in the future.
*/
rxdata &= ~SW_UARTn_RXDATAX_BERR;
port->icount.rx++;
if ((rxdata & UARTn_RXDATAX_FERR) &&
!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
rxdata |= SW_UARTn_RXDATAX_BERR;
port->icount.brk++;
if (uart_handle_break(port))
continue;
} else if (rxdata & UARTn_RXDATAX_PERR)
port->icount.parity++;
else if (rxdata & UARTn_RXDATAX_FERR)
port->icount.frame++;
rxdata &= port->read_status_mask;
if (rxdata & SW_UARTn_RXDATAX_BERR)
flag = TTY_BREAK;
else if (rxdata & UARTn_RXDATAX_PERR)
flag = TTY_PARITY;
else if (rxdata & UARTn_RXDATAX_FERR)
flag = TTY_FRAME;
else if (uart_handle_sysrq_char(port,
rxdata & UARTn_RXDATAX_RXDATA__MASK))
continue;
if (tty && (rxdata & port->ignore_status_mask) == 0)
tty_insert_flip_char(tty,
rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
}
}
static irqreturn_t efm32_uart_rxirq(int irq, void *data)
{
struct efm32_uart_port *efm_port = data;
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
int handled = IRQ_NONE;
struct uart_port *port = &efm_port->port;
struct tty_struct *tty;
spin_lock(&port->lock);
tty = tty_kref_get(port->state->port.tty);
if (irqflag & UARTn_IF_RXDATAV) {
efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
efm32_uart_rx_chars(efm_port, tty);
handled = IRQ_HANDLED;
}
if (irqflag & UARTn_IF_RXOF) {
efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
port->icount.overrun++;
if (tty)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
handled = IRQ_HANDLED;
}
if (tty) {
tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
spin_unlock(&port->lock);
return handled;
}
static irqreturn_t efm32_uart_txirq(int irq, void *data)
{
struct efm32_uart_port *efm_port = data;
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
/* TXBL doesn't need to be cleared */
if (irqflag & UARTn_IF_TXC)
efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
efm32_uart_tx_chars(efm_port);
return IRQ_HANDLED;
} else
return IRQ_NONE;
}
static int efm32_uart_startup(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 location = 0;
struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
int ret;
if (pdata)
location = UARTn_ROUTE_LOCATION(pdata->location);
ret = clk_enable(efm_port->clk);
if (ret) {
efm_debug(efm_port, "failed to enable clk\n");
goto err_clk_enable;
}
port->uartclk = clk_get_rate(efm_port->clk);
/* Enable pins at configured location */
efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
UARTn_ROUTE);
ret = request_irq(port->irq, efm32_uart_rxirq, 0,
DRIVER_NAME, efm_port);
if (ret) {
efm_debug(efm_port, "failed to register rxirq\n");
goto err_request_irq_rx;
}
/* disable all irqs */
efm32_uart_write32(efm_port, 0, UARTn_IEN);
ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
DRIVER_NAME, efm_port);
if (ret) {
efm_debug(efm_port, "failed to register txirq\n");
free_irq(port->irq, efm_port);
err_request_irq_rx:
clk_disable(efm_port->clk);
} else {
efm32_uart_write32(efm_port,
UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
}
err_clk_enable:
return ret;
}
static void efm32_uart_shutdown(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
efm32_uart_write32(efm_port, 0, UARTn_IEN);
free_irq(port->irq, efm_port);
clk_disable(efm_port->clk);
}
static void efm32_uart_set_termios(struct uart_port *port,
struct ktermios *new, struct ktermios *old)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
unsigned long flags;
unsigned baud;
u32 clkdiv;
u32 frame = 0;
/* no modem control lines */
new->c_cflag &= ~(CRTSCTS | CMSPAR);
baud = uart_get_baud_rate(port, new, old,
DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
DIV_ROUND_CLOSEST(port->uartclk, 16));
switch (new->c_cflag & CSIZE) {
case CS5:
frame |= UARTn_FRAME_DATABITS(5);
break;
case CS6:
frame |= UARTn_FRAME_DATABITS(6);
break;
case CS7:
frame |= UARTn_FRAME_DATABITS(7);
break;
case CS8:
frame |= UARTn_FRAME_DATABITS(8);
break;
}
if (new->c_cflag & CSTOPB)
/* the receiver only verifies the first stop bit */
frame |= UARTn_FRAME_STOPBITS_TWO;
else
frame |= UARTn_FRAME_STOPBITS_ONE;
if (new->c_cflag & PARENB) {
if (new->c_cflag & PARODD)
frame |= UARTn_FRAME_PARITY_ODD;
else
frame |= UARTn_FRAME_PARITY_EVEN;
} else
frame |= UARTn_FRAME_PARITY_NONE;
/*
* the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
* port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
*/
clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
spin_lock_irqsave(&port->lock, flags);
efm32_uart_write32(efm_port,
UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
if (new->c_iflag & INPCK)
port->read_status_mask |=
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
if (new->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
port->ignore_status_mask = 0;
if (new->c_iflag & IGNPAR)
port->ignore_status_mask |=
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
if (new->c_iflag & IGNBRK)
port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
uart_update_timeout(port, new->c_cflag, baud);
efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
efm32_uart_write32(efm_port, frame, UARTn_FRAME);
efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
UARTn_CMD);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *efm32_uart_type(struct uart_port *port)
{
return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
}
static void efm32_uart_release_port(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
clk_unprepare(efm_port->clk);
clk_put(efm_port->clk);
iounmap(port->membase);
}
static int efm32_uart_request_port(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
int ret;
port->membase = ioremap(port->mapbase, 60);
if (!efm_port->port.membase) {
ret = -ENOMEM;
efm_debug(efm_port, "failed to remap\n");
goto err_ioremap;
}
efm_port->clk = clk_get(port->dev, NULL);
if (IS_ERR(efm_port->clk)) {
ret = PTR_ERR(efm_port->clk);
efm_debug(efm_port, "failed to get clock\n");
goto err_clk_get;
}
ret = clk_prepare(efm_port->clk);
if (ret) {
clk_put(efm_port->clk);
err_clk_get:
iounmap(port->membase);
err_ioremap:
return ret;
}
return 0;
}
static void efm32_uart_config_port(struct uart_port *port, int type)
{
if (type & UART_CONFIG_TYPE &&
!efm32_uart_request_port(port))
port->type = PORT_EFMUART;
}
static int efm32_uart_verify_port(struct uart_port *port,
struct serial_struct *serinfo)
{
int ret = 0;
if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
ret = -EINVAL;
return ret;
}
static struct uart_ops efm32_uart_pops = {
.tx_empty = efm32_uart_tx_empty,
.set_mctrl = efm32_uart_set_mctrl,
.get_mctrl = efm32_uart_get_mctrl,
.stop_tx = efm32_uart_stop_tx,
.start_tx = efm32_uart_start_tx,
.stop_rx = efm32_uart_stop_rx,
.enable_ms = efm32_uart_enable_ms,
.break_ctl = efm32_uart_break_ctl,
.startup = efm32_uart_startup,
.shutdown = efm32_uart_shutdown,
.set_termios = efm32_uart_set_termios,
.type = efm32_uart_type,
.release_port = efm32_uart_release_port,
.request_port = efm32_uart_request_port,
.config_port = efm32_uart_config_port,
.verify_port = efm32_uart_verify_port,
};
static struct efm32_uart_port *efm32_uart_ports[5];
#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
static void efm32_uart_console_putchar(struct uart_port *port, int ch)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
unsigned int timeout = 0x400;
u32 status;
while (1) {
status = efm32_uart_read32(efm_port, UARTn_STATUS);
if (status & UARTn_STATUS_TXBL)
break;
if (!timeout--)
return;
}
efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
}
static void efm32_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
unsigned int timeout = 0x400;
if (!(status & UARTn_STATUS_TXENS))
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
uart_console_write(&efm_port->port, s, count,
efm32_uart_console_putchar);
/* Wait for the transmitter to become empty */
while (1) {
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
if (status & UARTn_STATUS_TXC)
break;
if (!timeout--)
break;
}
if (!(status & UARTn_STATUS_TXENS))
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
}
static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
int *baud, int *parity, int *bits)
{
u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
u32 route, clkdiv, frame;
if (ctrl & UARTn_CTRL_SYNC)
/* not operating in async mode */
return;
route = efm32_uart_read32(efm_port, UARTn_ROUTE);
if (!(route & UARTn_ROUTE_TXPEN))
/* tx pin not routed */
return;
clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
16 * (4 + (clkdiv >> 6)));
frame = efm32_uart_read32(efm_port, UARTn_FRAME);
if (frame & UARTn_FRAME_PARITY_ODD)
*parity = 'o';
else if (frame & UARTn_FRAME_PARITY_EVEN)
*parity = 'e';
else
*parity = 'n';
*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
UARTn_FRAME_DATABITS(4) + 4;
efm_debug(efm_port, "get_opts: options=%d%c%d\n",
*baud, *parity, *bits);
}
static int efm32_uart_console_setup(struct console *co, char *options)
{
struct efm32_uart_port *efm_port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
unsigned i;
for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
if (efm32_uart_ports[i]) {
pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
i, co->index);
co->index = i;
break;
}
}
}
efm_port = efm32_uart_ports[co->index];
if (!efm_port) {
pr_warn("efm32-console: No port at %d\n", co->index);
return -ENODEV;
}
ret = clk_prepare(efm_port->clk);
if (ret) {
dev_warn(efm_port->port.dev,
"console: clk_prepare failed: %d\n", ret);
return ret;
}
efm_port->port.uartclk = clk_get_rate(efm_port->clk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
efm32_uart_console_get_options(efm_port,
&baud, &parity, &bits);
return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
}
static struct uart_driver efm32_uart_reg;
static struct console efm32_uart_console = {
.name = DEV_NAME,
.write = efm32_uart_console_write,
.device = uart_console_device,
.setup = efm32_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &efm32_uart_reg,
};
#else
#define efm32_uart_console (*(struct console *)NULL)
#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
static struct uart_driver efm32_uart_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = DEV_NAME,
.nr = ARRAY_SIZE(efm32_uart_ports),
.cons = &efm32_uart_console,
};
static int efm32_uart_probe_dt(struct platform_device *pdev,
struct efm32_uart_port *efm_port)
{
struct device_node *np = pdev->dev.of_node;
int ret;
if (!np)
return 1;
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
return ret;
} else {
efm_port->port.line = ret;
return 0;
}
}
static int __devinit efm32_uart_probe(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port;
struct resource *res;
int ret;
efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
if (!efm_port) {
dev_dbg(&pdev->dev, "failed to allocate private data\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
dev_dbg(&pdev->dev, "failed to determine base address\n");
goto err_get_base;
}
if (resource_size(res) < 60) {
ret = -EINVAL;
dev_dbg(&pdev->dev, "memory resource too small\n");
goto err_too_small;
}
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_dbg(&pdev->dev, "failed to get rx irq\n");
goto err_get_rxirq;
}
efm_port->port.irq = ret;
ret = platform_get_irq(pdev, 1);
if (ret <= 0)
ret = efm_port->port.irq + 1;
efm_port->txirq = ret;
efm_port->port.dev = &pdev->dev;
efm_port->port.mapbase = res->start;
efm_port->port.type = PORT_EFMUART;
efm_port->port.iotype = UPIO_MEM32;
efm_port->port.fifosize = 2;
efm_port->port.ops = &efm32_uart_pops;
efm_port->port.flags = UPF_BOOT_AUTOCONF;
ret = efm32_uart_probe_dt(pdev, efm_port);
if (ret > 0)
/* not created by device tree */
efm_port->port.line = pdev->id;
if (efm_port->port.line >= 0 &&
efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
efm32_uart_ports[efm_port->port.line] = efm_port;
ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
if (ret) {
dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
efm32_uart_ports[pdev->id] = NULL;
err_get_rxirq:
err_too_small:
err_get_base:
kfree(efm_port);
} else {
platform_set_drvdata(pdev, efm_port);
dev_dbg(&pdev->dev, "\\o/\n");
}
return ret;
}
static int __devexit efm32_uart_remove(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
efm32_uart_ports[pdev->id] = NULL;
kfree(efm_port);
return 0;
}
static struct of_device_id efm32_uart_dt_ids[] = {
{
.compatible = "efm32,uart",
}, {
/* sentinel */
}
};
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),
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = efm32_uart_dt_ids,
},
};
static int __init efm32_uart_init(void)
{
int ret;
ret = uart_register_driver(&efm32_uart_reg);
if (ret)
return ret;
ret = platform_driver_register(&efm32_uart_driver);
if (ret)
uart_unregister_driver(&efm32_uart_reg);
pr_info("EFM32 UART/USART driver\n");
return ret;
}
module_init(efm32_uart_init);
static void __exit efm32_uart_exit(void)
{
platform_driver_unregister(&efm32_uart_driver);
uart_unregister_driver(&efm32_uart_reg);
}
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 UART/USART driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

View File

@ -70,13 +70,6 @@
#define PASS_LIMIT 256 #define PASS_LIMIT 256
/*
* We default to IRQ0 for the "no irq" hack. Some
* machine types want others as well - they're free
* to redefine this in their header file.
*/
#define is_real_interrupt(irq) ((irq) != 0)
#define BASE_BAUD 115200 #define BASE_BAUD 115200
/* Standard COM flags */ /* Standard COM flags */
@ -640,7 +633,7 @@ static int m32r_sio_startup(struct uart_port *port)
* hardware interrupt, we use a timer-based system. The original * hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0. * driver used to do this with IRQ0.
*/ */
if (!is_real_interrupt(up->port.irq)) { if (!up->port.irq) {
unsigned int timeout = up->port.timeout; unsigned int timeout = up->port.timeout;
timeout = timeout > 6 ? (timeout / 2 - 2) : 1; timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@ -687,7 +680,7 @@ static void m32r_sio_shutdown(struct uart_port *port)
sio_init(); sio_init();
if (!is_real_interrupt(up->port.irq)) if (!up->port.irq)
del_timer_sync(&up->timer); del_timer_sync(&up->timer);
else else
serial_unlink_irq_chain(up); serial_unlink_irq_chain(up);

View File

@ -507,7 +507,7 @@ static int __init mpc512x_psc_fifoc_init(void)
psc_fifoc_irq = irq_of_parse_and_map(np, 0); psc_fifoc_irq = irq_of_parse_and_map(np, 0);
of_node_put(np); of_node_put(np);
if (psc_fifoc_irq == NO_IRQ) { if (psc_fifoc_irq == 0) {
pr_err("%s: Can't get FIFOC irq\n", __func__); pr_err("%s: Can't get FIFOC irq\n", __func__);
iounmap(psc_fifoc); iounmap(psc_fifoc);
return -ENODEV; return -ENODEV;
@ -1354,7 +1354,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
} }
psc_ops->get_irq(port, op->dev.of_node); psc_ops->get_irq(port, op->dev.of_node);
if (port->irq == NO_IRQ) { if (port->irq == 0) {
dev_dbg(&op->dev, "Could not get irq\n"); dev_dbg(&op->dev, "Could not get irq\n");
return -EINVAL; return -EINVAL;
} }

View File

@ -499,7 +499,7 @@ static int __init mux_probe(struct parisc_device *dev)
port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
port->iotype = UPIO_MEM; port->iotype = UPIO_MEM;
port->type = PORT_MUX; port->type = PORT_MUX;
port->irq = NO_IRQ; port->irq = 0;
port->uartclk = 0; port->uartclk = 0;
port->fifosize = MUX_FIFO_SIZE; port->fifosize = MUX_FIFO_SIZE;
port->ops = &mux_pops; port->ops = &mux_pops;

View File

@ -29,6 +29,7 @@
#include <linux/nmi.h> #include <linux/nmi.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/pch_dma.h> #include <linux/pch_dma.h>
@ -144,6 +145,8 @@ enum {
#define PCH_UART_DLL 0x00 #define PCH_UART_DLL 0x00
#define PCH_UART_DLM 0x01 #define PCH_UART_DLM 0x01
#define PCH_UART_BRCSR 0x0E
#define PCH_UART_IID_RLS (PCH_UART_IIR_REI) #define PCH_UART_IID_RLS (PCH_UART_IIR_REI)
#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI) #define PCH_UART_IID_RDR (PCH_UART_IIR_RRI)
#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI) #define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
@ -243,6 +246,8 @@ struct eg20t_port {
int tx_dma_use; int tx_dma_use;
void *rx_buf_virt; void *rx_buf_virt;
dma_addr_t rx_buf_dma; dma_addr_t rx_buf_dma;
struct dentry *debugfs;
}; };
/** /**
@ -292,23 +297,73 @@ static const int trigger_level_64[4] = { 1, 16, 32, 56 };
static const int trigger_level_16[4] = { 1, 4, 8, 14 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 };
static const int trigger_level_1[4] = { 1, 1, 1, 1 }; static const int trigger_level_1[4] = { 1, 1, 1, 1 };
static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, #ifdef CONFIG_DEBUG_FS
int base_baud)
{
struct eg20t_port *priv = pci_get_drvdata(pdev);
priv->trigger_level = 1; #define PCH_REGS_BUFSIZE 1024
priv->fcr = 0; static int pch_show_regs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
} }
static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base) static ssize_t port_show_regs(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{ {
unsigned int msr = ioread8(base + UART_MSR); struct eg20t_port *priv = file->private_data;
priv->dmsr |= msr & PCH_UART_MSR_DELTA; char *buf;
u32 len = 0;
ssize_t ret;
unsigned char lcr;
return msr; buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL);
if (!buf)
return 0;
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"PCH EG20T port[%d] regs:\n", priv->port.line);
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"=================================\n");
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"BRCSR: \t0x%02x\n",
ioread8(priv->membase + PCH_UART_BRCSR));
lcr = ioread8(priv->membase + UART_LCR);
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
iowrite8(lcr, priv->membase + UART_LCR);
if (len > PCH_REGS_BUFSIZE)
len = PCH_REGS_BUFSIZE;
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return ret;
} }
static const struct file_operations port_regs_ops = {
.owner = THIS_MODULE,
.open = pch_show_regs_open,
.read = port_show_regs,
.llseek = default_llseek,
};
#endif /* CONFIG_DEBUG_FS */
static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
unsigned int flag) unsigned int flag)
{ {
@ -442,8 +497,9 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
{ {
priv->dmsr = 0; unsigned int msr = ioread8(priv->membase + UART_MSR);
return get_msr(priv, priv->membase); priv->dmsr = msr & PCH_UART_MSR_DELTA;
return (u8)msr;
} }
static void pch_uart_hal_write(struct eg20t_port *priv, static void pch_uart_hal_write(struct eg20t_port *priv,
@ -524,7 +580,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
{ {
int ret; int ret = 0;
struct uart_port *port = &priv->port; struct uart_port *port = &priv->port;
if (port->x_char) { if (port->x_char) {
@ -533,8 +589,6 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
buf[0] = port->x_char; buf[0] = port->x_char;
port->x_char = 0; port->x_char = 0;
ret = 1; ret = 1;
} else {
ret = 0;
} }
return ret; return ret;
@ -1032,14 +1086,12 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
static unsigned int pch_uart_tx_empty(struct uart_port *port) static unsigned int pch_uart_tx_empty(struct uart_port *port)
{ {
struct eg20t_port *priv; struct eg20t_port *priv;
int ret;
priv = container_of(port, struct eg20t_port, port); priv = container_of(port, struct eg20t_port, port);
if (priv->tx_empty) if (priv->tx_empty)
ret = TIOCSER_TEMT; return TIOCSER_TEMT;
else else
ret = 0; return 0;
return ret;
} }
/* Returns the current state of modem control inputs. */ /* Returns the current state of modem control inputs. */
@ -1273,9 +1325,8 @@ static void pch_uart_set_termios(struct uart_port *port,
else else
parity = PCH_UART_HAL_PARITY_EVEN; parity = PCH_UART_HAL_PARITY_EVEN;
} else { } else
parity = PCH_UART_HAL_PARITY_NONE; parity = PCH_UART_HAL_PARITY_NONE;
}
/* Only UART0 has auto hardware flow function */ /* Only UART0 has auto hardware flow function */
if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256)) if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
@ -1447,7 +1498,6 @@ static void
pch_console_write(struct console *co, const char *s, unsigned int count) pch_console_write(struct console *co, const char *s, unsigned int count)
{ {
struct eg20t_port *priv; struct eg20t_port *priv;
unsigned long flags; unsigned long flags;
u8 ier; u8 ier;
int locked = 1; int locked = 1;
@ -1554,6 +1604,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
int port_type; int port_type;
struct pch_uart_driver_data *board; struct pch_uart_driver_data *board;
const char *board_name; const char *board_name;
char name[32]; /* for debugfs file name */
board = &drv_dat[id->driver_data]; board = &drv_dat[id->driver_data];
port_type = board->port_type; port_type = board->port_type;
@ -1614,7 +1665,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
spin_lock_init(&priv->port.lock); spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv); pci_set_drvdata(pdev, priv);
pch_uart_hal_request(pdev, fifosize, base_baud); priv->trigger_level = 1;
priv->fcr = 0;
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[board->line_no] = priv; pch_uart_ports[board->line_no] = priv;
@ -1623,6 +1675,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (ret < 0) if (ret < 0)
goto init_port_hal_free; goto init_port_hal_free;
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "uart%d_regs", board->line_no);
priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
NULL, priv, &port_regs_ops);
#endif
return priv; return priv;
init_port_hal_free: init_port_hal_free:
@ -1639,6 +1697,11 @@ init_port_alloc_err:
static void pch_uart_exit_port(struct eg20t_port *priv) static void pch_uart_exit_port(struct eg20t_port *priv)
{ {
#ifdef CONFIG_DEBUG_FS
if (priv->debugfs)
debugfs_remove(priv->debugfs);
#endif
uart_remove_one_port(&pch_uart_driver, &priv->port); uart_remove_one_port(&pch_uart_driver, &priv->port);
pci_set_drvdata(priv->pdev, NULL); pci_set_drvdata(priv->pdev, NULL);
free_page((unsigned long)priv->rxbuf.buf); free_page((unsigned long)priv->rxbuf.buf);
@ -1646,9 +1709,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
static void pch_uart_pci_remove(struct pci_dev *pdev) static void pch_uart_pci_remove(struct pci_dev *pdev)
{ {
struct eg20t_port *priv; struct eg20t_port *priv = pci_get_drvdata(pdev);
priv = (struct eg20t_port *)pci_get_drvdata(pdev);
pci_disable_msi(pdev); pci_disable_msi(pdev);

View File

@ -1506,7 +1506,7 @@ no_dma:
* fixed up interrupt info, but we use the device-tree directly * fixed up interrupt info, but we use the device-tree directly
* here due to early probing so we need the fixup too. * here due to early probing so we need the fixup too.
*/ */
if (uap->port.irq == NO_IRQ && if (uap->port.irq == 0 &&
np->parent && np->parent->parent && np->parent && np->parent->parent &&
of_device_is_compatible(np->parent->parent, "gatwick")) { of_device_is_compatible(np->parent->parent, "gatwick")) {
/* IRQs on gatwick are offset by 64 */ /* IRQs on gatwick are offset by 64 */

View File

@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
#endif #endif
} }
static int zilog_irq = -1; static int zilog_irq;
static int __devinit zs_probe(struct platform_device *op) static int __devinit zs_probe(struct platform_device *op)
{ {
@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op)
rp = sunzilog_chip_regs[inst]; rp = sunzilog_chip_regs[inst];
if (zilog_irq == -1) if (!zilog_irq)
zilog_irq = op->archdata.irqs[0]; zilog_irq = op->archdata.irqs[0];
up = &sunzilog_port_table[inst * 2]; up = &sunzilog_port_table[inst * 2];
@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void)
if (err) if (err)
goto out_unregister_uart; goto out_unregister_uart;
if (zilog_irq != -1) { if (!zilog_irq) {
struct uart_sunzilog_port *up = sunzilog_irq_chain; struct uart_sunzilog_port *up = sunzilog_irq_chain;
err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
"zs", sunzilog_irq_chain); "zs", sunzilog_irq_chain);
@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void)
{ {
platform_driver_unregister(&zs_driver); platform_driver_unregister(&zs_driver);
if (zilog_irq != -1) { if (!zilog_irq) {
struct uart_sunzilog_port *up = sunzilog_irq_chain; struct uart_sunzilog_port *up = sunzilog_irq_chain;
/* Disable Interrupts */ /* Disable Interrupts */
@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void)
} }
free_irq(zilog_irq, sunzilog_irq_chain); free_irq(zilog_irq, sunzilog_irq_chain);
zilog_irq = -1; zilog_irq = 0;
} }
if (sunzilog_reg.nr) { if (sunzilog_reg.nr) {

View File

@ -1360,7 +1360,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
} }
qe_port->port.irq = irq_of_parse_and_map(np, 0); qe_port->port.irq = irq_of_parse_and_map(np, 0);
if (qe_port->port.irq == NO_IRQ) { if (qe_port->port.irq == 0) {
dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
qe_port->ucc_num + 1); qe_port->ucc_num + 1);
ret = -EINVAL; ret = -EINVAL;

View File

@ -61,7 +61,7 @@
static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
[0 ... SIU_PORTS_MAX-1] = { [0 ... SIU_PORTS_MAX-1] = {
.lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
.irq = -1, .irq = 0,
}, },
}; };
@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port)
{ {
if (port->line == 0) if (port->line == 0)
return PORT_VR41XX_SIU; return PORT_VR41XX_SIU;
if (port->line == 1 && port->irq != -1) if (port->line == 1 && port->irq)
return PORT_VR41XX_DSIU; return PORT_VR41XX_DSIU;
return PORT_UNKNOWN; return PORT_UNKNOWN;

View File

@ -322,11 +322,16 @@ static void send_sig_all(int sig)
{ {
struct task_struct *p; struct task_struct *p;
read_lock(&tasklist_lock);
for_each_process(p) { for_each_process(p) {
if (p->mm && !is_global_init(p)) if (p->flags & PF_KTHREAD)
/* Not swapper, init nor kernel thread */ continue;
if (is_global_init(p))
continue;
force_sig(sig, p); force_sig(sig, p);
} }
read_unlock(&tasklist_lock);
} }
static void sysrq_handle_term(int key) static void sysrq_handle_term(int key)

View File

@ -1271,6 +1271,19 @@ int tty_init_termios(struct tty_struct *tty)
} }
EXPORT_SYMBOL_GPL(tty_init_termios); EXPORT_SYMBOL_GPL(tty_init_termios);
int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
{
int ret = tty_init_termios(tty);
if (ret)
return ret;
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[tty->index] = tty;
return 0;
}
EXPORT_SYMBOL_GPL(tty_standard_install);
/** /**
* tty_driver_install_tty() - install a tty entry in the driver * tty_driver_install_tty() - install a tty entry in the driver
* @driver: the driver for the tty * @driver: the driver for the tty
@ -1286,21 +1299,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios);
static int tty_driver_install_tty(struct tty_driver *driver, static int tty_driver_install_tty(struct tty_driver *driver,
struct tty_struct *tty) struct tty_struct *tty)
{ {
int idx = tty->index; return driver->ops->install ? driver->ops->install(driver, tty) :
int ret; tty_standard_install(driver, tty);
if (driver->ops->install) {
ret = driver->ops->install(driver, tty);
return ret;
}
if (tty_init_termios(tty) == 0) {
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[idx] = tty;
return 0;
}
return -ENOMEM;
} }
/** /**
@ -1365,7 +1365,6 @@ static int tty_reopen(struct tty_struct *tty)
* @driver: tty driver we are opening a device on * @driver: tty driver we are opening a device on
* @idx: device index * @idx: device index
* @ret_tty: returned tty structure * @ret_tty: returned tty structure
* @first_ok: ok to open a new device (used by ptmx)
* *
* Prepare a tty device. This may not be a "new" clean device but * Prepare a tty device. This may not be a "new" clean device but
* could also be an active device. The pty drivers require special * could also be an active device. The pty drivers require special
@ -1385,18 +1384,11 @@ static int tty_reopen(struct tty_struct *tty)
* relaxed for the (most common) case of reopening a tty. * relaxed for the (most common) case of reopening a tty.
*/ */
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
int first_ok)
{ {
struct tty_struct *tty; struct tty_struct *tty;
int retval; int retval;
/* Check if pty master is being opened multiple times */
if (driver->subtype == PTY_TYPE_MASTER &&
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
return ERR_PTR(-EIO);
}
/* /*
* First time open is complex, especially for PTY devices. * First time open is complex, especially for PTY devices.
* This code guarantees that either everything succeeds and the * This code guarantees that either everything succeeds and the
@ -1797,11 +1789,11 @@ int tty_release(struct inode *inode, struct file *filp)
* the slots and preserving the termios structure. * the slots and preserving the termios structure.
*/ */
release_tty(tty, idx); release_tty(tty, idx);
tty_unlock();
/* Make this pty number available for reallocation */ /* Make this pty number available for reallocation */
if (devpts) if (devpts)
devpts_kill_index(inode, idx); devpts_kill_index(inode, idx);
tty_unlock();
return 0; return 0;
} }
@ -1950,7 +1942,7 @@ retry_open:
if (retval) if (retval)
tty = ERR_PTR(retval); tty = ERR_PTR(retval);
} else } else
tty = tty_init_dev(driver, index, 0); tty = tty_init_dev(driver, index);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
if (driver) if (driver)

View File

@ -214,15 +214,14 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
if (!try_module_get(serial->type->driver.owner)) if (!try_module_get(serial->type->driver.owner))
goto error_module_get; goto error_module_get;
/* perform the standard setup */
retval = tty_init_termios(tty);
if (retval)
goto error_init_termios;
retval = usb_autopm_get_interface(serial->interface); retval = usb_autopm_get_interface(serial->interface);
if (retval) if (retval)
goto error_get_interface; goto error_get_interface;
retval = tty_standard_install(driver, tty);
if (retval)
goto error_init_termios;
mutex_unlock(&serial->disc_mutex); mutex_unlock(&serial->disc_mutex);
/* allow the driver to update the settings */ /* allow the driver to update the settings */
@ -231,14 +230,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
tty->driver_data = port; tty->driver_data = port;
/* Final install (we use the default method) */
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[idx] = tty;
return retval; return retval;
error_get_interface:
error_init_termios: error_init_termios:
usb_autopm_put_interface(serial->interface);
error_get_interface:
module_put(serial->type->driver.owner); module_put(serial->type->driver.owner);
error_module_get: error_module_get:
error_no_port: error_no_port:

View File

@ -36,7 +36,61 @@
#define DEVPTS_DEFAULT_PTMX_MODE 0000 #define DEVPTS_DEFAULT_PTMX_MODE 0000
#define PTMX_MINOR 2 #define PTMX_MINOR 2
extern int pty_limit; /* Config limit on Unix98 ptys */ /*
* sysctl support for setting limits on the number of Unix98 ptys allocated.
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
*/
static int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_reserve = NR_UNIX98_PTY_RESERVE;
static int pty_limit_min;
static int pty_limit_max = INT_MAX;
static int pty_count;
static struct ctl_table pty_table[] = {
{
.procname = "max",
.maxlen = sizeof(int),
.mode = 0644,
.data = &pty_limit,
.proc_handler = proc_dointvec_minmax,
.extra1 = &pty_limit_min,
.extra2 = &pty_limit_max,
}, {
.procname = "reserve",
.maxlen = sizeof(int),
.mode = 0644,
.data = &pty_reserve,
.proc_handler = proc_dointvec_minmax,
.extra1 = &pty_limit_min,
.extra2 = &pty_limit_max,
}, {
.procname = "nr",
.maxlen = sizeof(int),
.mode = 0444,
.data = &pty_count,
.proc_handler = proc_dointvec,
},
{}
};
static struct ctl_table pty_kern_table[] = {
{
.procname = "pty",
.mode = 0555,
.child = pty_table,
},
{}
};
static struct ctl_table pty_root_table[] = {
{
.procname = "kernel",
.mode = 0555,
.child = pty_kern_table,
},
{}
};
static DEFINE_MUTEX(allocated_ptys_lock); static DEFINE_MUTEX(allocated_ptys_lock);
static struct vfsmount *devpts_mnt; static struct vfsmount *devpts_mnt;
@ -49,10 +103,11 @@ struct pts_mount_opts {
umode_t mode; umode_t mode;
umode_t ptmxmode; umode_t ptmxmode;
int newinstance; int newinstance;
int max;
}; };
enum { enum {
Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max,
Opt_err Opt_err
}; };
@ -63,6 +118,7 @@ static const match_table_t tokens = {
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
{Opt_ptmxmode, "ptmxmode=%o"}, {Opt_ptmxmode, "ptmxmode=%o"},
{Opt_newinstance, "newinstance"}, {Opt_newinstance, "newinstance"},
{Opt_max, "max=%d"},
#endif #endif
{Opt_err, NULL} {Opt_err, NULL}
}; };
@ -109,6 +165,7 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
opts->gid = 0; opts->gid = 0;
opts->mode = DEVPTS_DEFAULT_MODE; opts->mode = DEVPTS_DEFAULT_MODE;
opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
opts->max = NR_UNIX98_PTY_MAX;
/* newinstance makes sense only on initial mount */ /* newinstance makes sense only on initial mount */
if (op == PARSE_MOUNT) if (op == PARSE_MOUNT)
@ -152,6 +209,12 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
if (op == PARSE_MOUNT) if (op == PARSE_MOUNT)
opts->newinstance = 1; opts->newinstance = 1;
break; break;
case Opt_max:
if (match_int(&args[0], &option) ||
option < 0 || option > NR_UNIX98_PTY_MAX)
return -EINVAL;
opts->max = option;
break;
#endif #endif
default: default:
printk(KERN_ERR "devpts: called with bogus options\n"); printk(KERN_ERR "devpts: called with bogus options\n");
@ -258,6 +321,8 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root)
seq_printf(seq, ",mode=%03o", opts->mode); seq_printf(seq, ",mode=%03o", opts->mode);
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
if (opts->max < NR_UNIX98_PTY_MAX)
seq_printf(seq, ",max=%d", opts->max);
#endif #endif
return 0; return 0;
@ -438,6 +503,12 @@ retry:
return -ENOMEM; return -ENOMEM;
mutex_lock(&allocated_ptys_lock); mutex_lock(&allocated_ptys_lock);
if (pty_count >= pty_limit -
(fsi->mount_opts.newinstance ? pty_reserve : 0)) {
mutex_unlock(&allocated_ptys_lock);
return -ENOSPC;
}
ida_ret = ida_get_new(&fsi->allocated_ptys, &index); ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
if (ida_ret < 0) { if (ida_ret < 0) {
mutex_unlock(&allocated_ptys_lock); mutex_unlock(&allocated_ptys_lock);
@ -446,11 +517,12 @@ retry:
return -EIO; return -EIO;
} }
if (index >= pty_limit) { if (index >= fsi->mount_opts.max) {
ida_remove(&fsi->allocated_ptys, index); ida_remove(&fsi->allocated_ptys, index);
mutex_unlock(&allocated_ptys_lock); mutex_unlock(&allocated_ptys_lock);
return -EIO; return -ENOSPC;
} }
pty_count++;
mutex_unlock(&allocated_ptys_lock); mutex_unlock(&allocated_ptys_lock);
return index; return index;
} }
@ -462,6 +534,7 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
mutex_lock(&allocated_ptys_lock); mutex_lock(&allocated_ptys_lock);
ida_remove(&fsi->allocated_ptys, idx); ida_remove(&fsi->allocated_ptys, idx);
pty_count--;
mutex_unlock(&allocated_ptys_lock); mutex_unlock(&allocated_ptys_lock);
} }
@ -558,11 +631,15 @@ void devpts_pty_kill(struct tty_struct *tty)
static int __init init_devpts_fs(void) static int __init init_devpts_fs(void)
{ {
int err = register_filesystem(&devpts_fs_type); int err = register_filesystem(&devpts_fs_type);
struct ctl_table_header *table;
if (!err) { if (!err) {
table = register_sysctl_table(pty_root_table);
devpts_mnt = kern_mount(&devpts_fs_type); devpts_mnt = kern_mount(&devpts_fs_type);
if (IS_ERR(devpts_mnt)) { if (IS_ERR(devpts_mnt)) {
err = PTR_ERR(devpts_mnt); err = PTR_ERR(devpts_mnt);
unregister_filesystem(&devpts_fs_type); unregister_filesystem(&devpts_fs_type);
unregister_sysctl_table(table);
} }
} }
return err; return err;

View File

@ -5,8 +5,6 @@
#ifndef __ALTUART_H #ifndef __ALTUART_H
#define __ALTUART_H #define __ALTUART_H
#include <linux/init.h>
struct altera_uart_platform_uart { struct altera_uart_platform_uart {
unsigned long mapbase; /* Physical address base */ unsigned long mapbase; /* Physical address base */
unsigned int irq; /* Interrupt vector */ unsigned int irq; /* Interrupt vector */
@ -14,6 +12,4 @@ struct altera_uart_platform_uart {
unsigned int bus_shift; /* Bus shift (address stride) */ unsigned int bus_shift; /* Bus shift (address stride) */
}; };
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp);
#endif /* __ALTUART_H */ #endif /* __ALTUART_H */

View File

@ -0,0 +1,18 @@
/*
*
*
*/
#ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__
#define __LINUX_PLATFORM_DATA_EFM32_UART_H__
#include <linux/types.h>
/**
* struct efm32_uart_pdata
* @location: pinmux location for the I/O pins (to be written to the ROUTE
* register)
*/
struct efm32_uart_pdata {
u8 location;
};
#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ */

View File

@ -210,6 +210,8 @@
/* Atheros AR933X SoC */ /* Atheros AR933X SoC */
#define PORT_AR933X 99 #define PORT_AR933X 99
/* Energy Micro efm32 SoC */
#define PORT_EFMUART 100
#ifdef __KERNEL__ #ifdef __KERNEL__

View File

@ -52,6 +52,7 @@
* hardcoded at present.) * hardcoded at present.)
*/ */
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
#define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
/* /*
@ -480,10 +481,11 @@ extern void free_tty_struct(struct tty_struct *tty);
extern void initialize_tty_struct(struct tty_struct *tty, extern void initialize_tty_struct(struct tty_struct *tty,
struct tty_driver *driver, int idx); struct tty_driver *driver, int idx);
extern void deinitialize_tty_struct(struct tty_struct *tty); extern void deinitialize_tty_struct(struct tty_struct *tty);
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
int first_ok);
extern int tty_release(struct inode *inode, struct file *filp); extern int tty_release(struct inode *inode, struct file *filp);
extern int tty_init_termios(struct tty_struct *tty); extern int tty_init_termios(struct tty_struct *tty);
extern int tty_standard_install(struct tty_driver *driver,
struct tty_struct *tty);
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);