Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (65 commits)
  tty: serial: imx: move del_timer_sync() to avoid potential deadlock
  imx: add polled io uart methods
  imx: Add save/restore functions for UART control regs
  serial/imx: let probing fail for the dt case without a valid alias
  serial/imx: propagate error from of_alias_get_id instead of using -ENODEV
  tty: serial: imx: Allow UART to be a source for wakeup
  serial: driver for m32 arch should not have DEC alpha errata
  serial/documentation: fix documented name of DCD cpp symbol
  atmel_serial: fix spinlock lockup in RS485 code
  tty: Fix memory leak in virtual console when enable unicode translation
  serial: use DIV_ROUND_CLOSEST instead of open coding it
  serial: add support for 400 and 800 v3 series Titan cards
  serial: bfin-uart: Remove ASYNC_CTS_FLOW flag for hardware automatic CTS.
  serial: bfin-uart: Enable hardware automatic CTS only when CTS pin is available.
  serial: make FSL errata depend on 8250_CONSOLE, not just 8250
  serial: add irq handler for Freescale 16550 errata.
  serial: manually inline serial8250_handle_port
  serial: make 8250 timeout use the specified IRQ handler
  serial: export the key functions for an 8250 IRQ handler
  serial: clean up parameter passing for 8250 Rx IRQ handling
  ...
This commit is contained in:
Linus Torvalds 2012-01-09 12:09:24 -08:00
commit 5983faf942
45 changed files with 1989 additions and 658 deletions

View File

@ -101,7 +101,7 @@ hardware.
Returns the current state of modem control inputs. The state Returns the current state of modem control inputs. The state
of the outputs should not be returned, since the core keeps of the outputs should not be returned, since the core keeps
track of their state. The state information should include: track of their state. The state information should include:
- TIOCM_DCD state of DCD signal - TIOCM_CAR state of DCD signal
- TIOCM_CTS state of CTS signal - TIOCM_CTS state of CTS signal
- TIOCM_DSR state of DSR signal - TIOCM_DSR state of DSR signal
- TIOCM_RI state of RI signal - TIOCM_RI state of RI signal

View File

@ -441,6 +441,9 @@ static void __init fixup_port_irq(int index,
return; return;
port->irq = virq; port->irq = virq;
if (of_device_is_compatible(np, "fsl,ns16550"))
port->handle_irq = fsl8250_handle_irq;
} }
static void __init fixup_port_pio(int index, static void __init fixup_port_pio(int index,

View File

@ -67,7 +67,7 @@ extern struct console early_mrst_console;
extern void mrst_early_console_init(void); extern void mrst_early_console_init(void);
extern struct console early_hsu_console; extern struct console early_hsu_console;
extern void hsu_early_console_init(void); extern void hsu_early_console_init(const char *);
extern void intel_scu_devices_create(void); extern void intel_scu_devices_create(void);
extern void intel_scu_devices_destroy(void); extern void intel_scu_devices_destroy(void);

View File

@ -247,7 +247,7 @@ static int __init setup_early_printk(char *buf)
} }
if (!strncmp(buf, "hsu", 3)) { if (!strncmp(buf, "hsu", 3)) {
hsu_early_console_init(); hsu_early_console_init(buf + 3);
early_console_register(&early_hsu_console, keep); early_console_register(&early_hsu_console, keep);
} }
#endif #endif

View File

@ -245,16 +245,24 @@ struct console early_mrst_console = {
* Following is the early console based on Medfield HSU (High * Following is the early console based on Medfield HSU (High
* Speed UART) device. * Speed UART) device.
*/ */
#define HSU_PORT2_PADDR 0xffa28180 #define HSU_PORT_BASE 0xffa28080
static void __iomem *phsu; static void __iomem *phsu;
void hsu_early_console_init(void) void hsu_early_console_init(const char *s)
{ {
unsigned long paddr, port = 0;
u8 lcr; u8 lcr;
phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, /*
HSU_PORT2_PADDR); * Select the early HSU console port if specified by user in the
* kernel command line.
*/
if (*s && !kstrtoul(s, 10, &port))
port = clamp_val(port, 0, 2);
paddr = HSU_PORT_BASE + port * 0x80;
phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
/* Disable FIFO */ /* Disable FIFO */
writeb(0x0, phsu + UART_FCR); writeb(0x0, phsu + UART_FCR);

View File

@ -420,18 +420,7 @@ static struct platform_driver axdrv = {
.resume = parport_ax88796_resume, .resume = parport_ax88796_resume,
}; };
static int __init parport_ax88796_init(void) module_platform_driver(axdrv);
{
return platform_driver_register(&axdrv);
}
static void __exit parport_ax88796_exit(void)
{
platform_driver_unregister(&axdrv);
}
module_init(parport_ax88796_init)
module_exit(parport_ax88796_exit)
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("AX88796 Parport parallel port driver"); MODULE_DESCRIPTION("AX88796 Parport parallel port driver");

View File

@ -391,21 +391,10 @@ static struct platform_driver bpp_sbus_driver = {
.remove = __devexit_p(bpp_remove), .remove = __devexit_p(bpp_remove),
}; };
static int __init parport_sunbpp_init(void) module_platform_driver(bpp_sbus_driver);
{
return platform_driver_register(&bpp_sbus_driver);
}
static void __exit parport_sunbpp_exit(void)
{
platform_driver_unregister(&bpp_sbus_driver);
}
MODULE_AUTHOR("Derrick J Brashear"); MODULE_AUTHOR("Derrick J Brashear");
MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port"); MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port"); MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
MODULE_VERSION("2.0"); MODULE_VERSION("2.0");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(parport_sunbpp_init)
module_exit(parport_sunbpp_exit)

View File

@ -417,7 +417,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
__FILE__,__LINE__,tbuf,tbuf->count); __FILE__,__LINE__,tbuf,tbuf->count);
/* Send the next block of data to device */ /* Send the next block of data to device */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
actual = tty->ops->write(tty, tbuf->buf, tbuf->count); actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
/* rollback was possible and has been done */ /* rollback was possible and has been done */
@ -459,7 +459,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
} }
if (!tbuf) if (!tbuf)
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
/* Clear the re-entry flag */ /* Clear the re-entry flag */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
@ -491,7 +491,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
return; return;
if (tty != n_hdlc->tty) { if (tty != n_hdlc->tty) {
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
return; return;
} }

View File

@ -446,19 +446,8 @@ static inline void legacy_pty_init(void) { }
int pty_limit = NR_UNIX98_PTY_DEFAULT; int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min; static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX; static int pty_limit_max = NR_UNIX98_PTY_MAX;
static int tty_count;
static int pty_count; static int pty_count;
static inline void pty_inc_count(void)
{
pty_count = (++tty_count) / 2;
}
static inline void pty_dec_count(void)
{
pty_count = (--tty_count) / 2;
}
static struct cdev ptmx_cdev; static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = { static struct ctl_table pty_table[] = {
@ -600,8 +589,7 @@ 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_inc_count(); /* tty */ pty_count++;
pty_inc_count(); /* tty->link */
return 0; return 0;
err_free_mem: err_free_mem:
deinitialize_tty_struct(o_tty); deinitialize_tty_struct(o_tty);
@ -613,15 +601,19 @@ err_free_tty:
return -ENOMEM; return -ENOMEM;
} }
static void pty_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)
{ {
pty_dec_count();
} }
static const struct tty_operations ptm_unix98_ops = { static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup, .lookup = ptm_unix98_lookup,
.install = pty_unix98_install, .install = pty_unix98_install,
.remove = pty_unix98_remove, .remove = ptm_unix98_remove,
.open = pty_open, .open = pty_open,
.close = pty_close, .close = pty_close,
.write = pty_write, .write = pty_write,
@ -638,7 +630,7 @@ static const struct tty_operations ptm_unix98_ops = {
static const struct tty_operations pty_unix98_ops = { static const struct tty_operations pty_unix98_ops = {
.lookup = pts_unix98_lookup, .lookup = pts_unix98_lookup,
.install = pty_unix98_install, .install = pty_unix98_install,
.remove = pty_unix98_remove, .remove = pts_unix98_remove,
.open = pty_open, .open = pty_open,
.close = pty_close, .close = pty_close,
.write = pty_write, .write = pty_write,

View File

@ -129,32 +129,6 @@ static unsigned long probe_rsa[PORT_RSA_MAX];
static unsigned int probe_rsa_count; static unsigned int probe_rsa_count;
#endif /* CONFIG_SERIAL_8250_RSA */ #endif /* CONFIG_SERIAL_8250_RSA */
struct uart_8250_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
unsigned short capabilities; /* port capabilities */
unsigned short bugs; /* port bugs */
unsigned int tx_loadsz; /* transmit fifo load size */
unsigned char acr;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
unsigned char cur_iotype; /* Running I/O type */
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
};
struct irq_info { struct irq_info {
struct hlist_node node; struct hlist_node node;
int irq; int irq;
@ -1326,8 +1300,6 @@ static void serial8250_stop_tx(struct uart_port *port)
} }
} }
static void transmit_chars(struct uart_8250_port *up);
static void serial8250_start_tx(struct uart_port *port) static void serial8250_start_tx(struct uart_port *port)
{ {
struct uart_8250_port *up = struct uart_8250_port *up =
@ -1344,7 +1316,7 @@ static void serial8250_start_tx(struct uart_port *port)
if ((up->port.type == PORT_RM9000) ? if ((up->port.type == PORT_RM9000) ?
(lsr & UART_LSR_THRE) : (lsr & UART_LSR_THRE) :
(lsr & UART_LSR_TEMT)) (lsr & UART_LSR_TEMT))
transmit_chars(up); serial8250_tx_chars(up);
} }
} }
@ -1401,11 +1373,16 @@ static void clear_rx_fifo(struct uart_8250_port *up)
} while (1); } while (1);
} }
static void /*
receive_chars(struct uart_8250_port *up, unsigned int *status) * serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
*/
unsigned char
serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
{ {
struct tty_struct *tty = up->port.state->port.tty; struct tty_struct *tty = up->port.state->port.tty;
unsigned char ch, lsr = *status; unsigned char ch;
int max_count = 256; int max_count = 256;
char flag; char flag;
@ -1481,10 +1458,11 @@ ignore_char:
spin_unlock(&up->port.lock); spin_unlock(&up->port.lock);
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
spin_lock(&up->port.lock); spin_lock(&up->port.lock);
*status = lsr; return lsr;
} }
EXPORT_SYMBOL_GPL(serial8250_rx_chars);
static void transmit_chars(struct uart_8250_port *up) void serial8250_tx_chars(struct uart_8250_port *up)
{ {
struct circ_buf *xmit = &up->port.state->xmit; struct circ_buf *xmit = &up->port.state->xmit;
int count; int count;
@ -1521,8 +1499,9 @@ static void transmit_chars(struct uart_8250_port *up)
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
__stop_tx(up); __stop_tx(up);
} }
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
static unsigned int check_modem_status(struct uart_8250_port *up) unsigned int serial8250_modem_status(struct uart_8250_port *up)
{ {
unsigned int status = serial_in(up, UART_MSR); unsigned int status = serial_in(up, UART_MSR);
@ -1544,14 +1523,20 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
return status; return status;
} }
EXPORT_SYMBOL_GPL(serial8250_modem_status);
/* /*
* This handles the interrupt from one port. * This handles the interrupt from one port.
*/ */
static void serial8250_handle_port(struct uart_8250_port *up) int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{ {
unsigned int status; unsigned char status;
unsigned long flags; unsigned long flags;
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
if (iir & UART_IIR_NO_INT)
return 0;
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
@ -1560,26 +1545,14 @@ static void serial8250_handle_port(struct uart_8250_port *up)
DEBUG_INTR("status = %x...", status); DEBUG_INTR("status = %x...", status);
if (status & (UART_LSR_DR | UART_LSR_BI)) if (status & (UART_LSR_DR | UART_LSR_BI))
receive_chars(up, &status); status = serial8250_rx_chars(up, status);
check_modem_status(up); serial8250_modem_status(up);
if (status & UART_LSR_THRE) if (status & UART_LSR_THRE)
transmit_chars(up); serial8250_tx_chars(up);
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
}
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
if (!(iir & UART_IIR_NO_INT)) {
serial8250_handle_port(up);
return 1; return 1;
} }
return 0;
}
EXPORT_SYMBOL_GPL(serial8250_handle_irq); EXPORT_SYMBOL_GPL(serial8250_handle_irq);
static int serial8250_default_handle_irq(struct uart_port *port) static int serial8250_default_handle_irq(struct uart_port *port)
@ -1619,11 +1592,13 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
do { do {
struct uart_8250_port *up; struct uart_8250_port *up;
struct uart_port *port; struct uart_port *port;
bool skip;
up = list_entry(l, struct uart_8250_port, list); up = list_entry(l, struct uart_8250_port, list);
port = &up->port; port = &up->port;
skip = pass_counter && up->port.flags & UPF_IIR_ONCE;
if (port->handle_irq(port)) { if (!skip && port->handle_irq(port)) {
handled = 1; handled = 1;
end = NULL; end = NULL;
} else if (end == NULL) } else if (end == NULL)
@ -1758,11 +1733,8 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
static void serial8250_timeout(unsigned long data) static void serial8250_timeout(unsigned long data)
{ {
struct uart_8250_port *up = (struct uart_8250_port *)data; struct uart_8250_port *up = (struct uart_8250_port *)data;
unsigned int iir;
iir = serial_in(up, UART_IIR); up->port.handle_irq(&up->port);
if (!(iir & UART_IIR_NO_INT))
serial8250_handle_port(up);
mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
} }
@ -1801,7 +1773,7 @@ static void serial8250_backup_timeout(unsigned long data)
} }
if (!(iir & UART_IIR_NO_INT)) if (!(iir & UART_IIR_NO_INT))
transmit_chars(up); serial8250_tx_chars(up);
if (is_real_interrupt(up->port.irq)) if (is_real_interrupt(up->port.irq))
serial_out(up, UART_IER, ier); serial_out(up, UART_IER, ier);
@ -1835,7 +1807,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
unsigned int status; unsigned int status;
unsigned int ret; unsigned int ret;
status = check_modem_status(up); status = serial8250_modem_status(up);
ret = 0; ret = 0;
if (status & UART_MSR_DCD) if (status & UART_MSR_DCD)
@ -2000,7 +1972,7 @@ static int serial8250_startup(struct uart_port *port)
serial_outp(up, UART_IER, 0); serial_outp(up, UART_IER, 0);
serial_outp(up, UART_LCR, 0); serial_outp(up, UART_LCR, 0);
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
serial_outp(up, UART_LCR, 0xBF); serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(up, UART_EFR, UART_EFR_ECB); serial_outp(up, UART_EFR, UART_EFR_ECB);
serial_outp(up, UART_LCR, 0); serial_outp(up, UART_LCR, 0);
} }
@ -2848,7 +2820,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
local_irq_save(flags); local_irq_save(flags);
if (up->port.sysrq) { if (up->port.sysrq) {
/* serial8250_handle_port() already took the lock */ /* serial8250_handle_irq() already took the lock */
locked = 0; locked = 0;
} else if (oops_in_progress) { } else if (oops_in_progress) {
locked = spin_trylock(&up->port.lock); locked = spin_trylock(&up->port.lock);
@ -2882,7 +2854,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
* while processing with interrupts off. * while processing with interrupts off.
*/ */
if (up->msr_saved_flags) if (up->msr_saved_flags)
check_modem_status(up); serial8250_modem_status(up);
if (locked) if (locked)
spin_unlock(&up->port.lock); spin_unlock(&up->port.lock);

View File

@ -13,6 +13,32 @@
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
struct uart_8250_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
unsigned short capabilities; /* port capabilities */
unsigned short bugs; /* port bugs */
unsigned int tx_loadsz; /* transmit fifo load size */
unsigned char acr;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
unsigned char cur_iotype; /* Running I/O type */
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
};
struct old_serial_port { struct old_serial_port {
unsigned int uart; unsigned int uart;
unsigned int baud_base; unsigned int baud_base;

View File

@ -177,17 +177,7 @@ static struct platform_driver dw8250_platform_driver = {
.remove = __devexit_p(dw8250_remove), .remove = __devexit_p(dw8250_remove),
}; };
static int __init dw8250_init(void) module_platform_driver(dw8250_platform_driver);
{
return platform_driver_register(&dw8250_platform_driver);
}
module_init(dw8250_init);
static void __exit dw8250_exit(void)
{
platform_driver_unregister(&dw8250_platform_driver);
}
module_exit(dw8250_exit);
MODULE_AUTHOR("Jamie Iles"); MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -0,0 +1,63 @@
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
#include "8250.h"
/*
* Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This isn't a full driver; it just provides an alternate IRQ
* handler to deal with an errata. Everything else is just
* using the bog standard 8250 support.
*
* We follow code flow of serial8250_default_handle_irq() but add
* a check for a break and insert a dummy read on the Rx for the
* immediately following IRQ event.
*
* We re-use the already existing "bug handling" lsr_saved_flags
* field to carry the "what we just did" information from the one
* IRQ event to the next one.
*/
int fsl8250_handle_irq(struct uart_port *port)
{
unsigned char lsr, orig_lsr;
unsigned long flags;
unsigned int iir;
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
spin_lock_irqsave(&up->port.lock, flags);
iir = port->serial_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT) {
spin_unlock_irqrestore(&up->port.lock, flags);
return 0;
}
/* This is the WAR; if last event was BRK, then read and return */
if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
up->lsr_saved_flags &= ~UART_LSR_BI;
port->serial_in(port, UART_RX);
spin_unlock_irqrestore(&up->port.lock, flags);
return 1;
}
lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
if (lsr & (UART_LSR_DR | UART_LSR_BI))
lsr = serial8250_rx_chars(up, lsr);
serial8250_modem_status(up);
if (lsr & UART_LSR_THRE)
serial8250_tx_chars(up);
up->lsr_saved_flags = orig_lsr;
spin_unlock_irqrestore(&up->port.lock, flags);
return 1;
}

View File

@ -1092,6 +1092,14 @@ static int skip_tx_en_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx); return pci_default_setup(priv, board, port, idx);
} }
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
port->flags |= UPF_IIR_ONCE;
return skip_tx_en_setup(priv, board, port, idx);
}
static int pci_eg20t_init(struct pci_dev *dev) static int pci_eg20t_init(struct pci_dev *dev)
{ {
#if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE)
@ -1110,7 +1118,18 @@ pci_xr17c154_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx); return pci_default_setup(priv, board, port, idx);
} }
/* This should be in linux/pci_ids.h */ static int try_enable_msi(struct pci_dev *dev)
{
/* use msi if available, but fallback to legacy otherwise */
pci_enable_msi(dev);
return 0;
}
static void disable_msi(struct pci_dev *dev)
{
pci_disable_msi(dev);
}
#define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_VENDOR_ID_SBSMODULARIO 0x124B
#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
#define PCI_DEVICE_ID_OCTPRO 0x0001 #define PCI_DEVICE_ID_OCTPRO 0x0001
@ -1133,9 +1152,14 @@ pci_xr17c154_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_TITAN_800E 0xA014 #define PCI_DEVICE_ID_TITAN_800E 0xA014
#define PCI_DEVICE_ID_TITAN_200EI 0xA016 #define PCI_DEVICE_ID_TITAN_200EI 0xA016
#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 #define PCI_DEVICE_ID_TITAN_200EISI 0xA017
#define PCI_DEVICE_ID_TITAN_400V3 0xA310
#define PCI_DEVICE_ID_TITAN_410V3 0xA312
#define PCI_DEVICE_ID_TITAN_800V3 0xA314
#define PCI_DEVICE_ID_TITAN_800V3B 0xA315
#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 #define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538
#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */ /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@ -1220,6 +1244,15 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.setup = ce4100_serial_setup, .setup = ce4100_serial_setup,
}, },
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_PATSBURG_KT,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = try_enable_msi,
.setup = kt_serial_setup,
.exit = disable_msi,
},
/* /*
* ITE * ITE
*/ */
@ -3414,6 +3447,18 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_2_4000000 }, pbn_oxsemi_2_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_410V3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3B,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,

View File

@ -97,6 +97,11 @@ config SERIAL_8250_PNP
This builds standard PNP serial support. You may be able to This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support. disable this feature if you only need legacy serial support.
config SERIAL_8250_FSL
bool
depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550
default PPC
config SERIAL_8250_HP300 config SERIAL_8250_HP300
tristate tristate
depends on SERIAL_8250 && HP300 depends on SERIAL_8250 && HP300
@ -535,6 +540,27 @@ config SERIAL_S5PV210
help help
Serial port support for Samsung's S5P Family of SoC's Serial port support for Samsung's S5P Family of SoC's
config SERIAL_SIRFSOC
tristate "SiRF SoC Platform Serial port support"
depends on ARM && ARCH_PRIMA2
select SERIAL_CORE
help
Support for the on-chip UART on the CSR SiRFprimaII series,
providing /dev/ttySiRF0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured).
config SERIAL_SIRFSOC_CONSOLE
bool "Support for console on SiRF SoC serial port"
depends on SERIAL_SIRFSOC=y
select SERIAL_CORE_CONSOLE
help
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySiRFx". (Try "man bootparam" or see the documentation of
your boot loader about how to pass options to the kernel at
boot time.)
config SERIAL_MAX3100 config SERIAL_MAX3100
tristate "MAX3100 support" tristate "MAX3100 support"
@ -1324,7 +1350,7 @@ config SERIAL_OF_PLATFORM
config SERIAL_OMAP config SERIAL_OMAP
tristate "OMAP serial port support" tristate "OMAP serial port support"
depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 depends on ARCH_OMAP2PLUS
select SERIAL_CORE select SERIAL_CORE
help help
If you have a machine based on an Texas Instruments OMAP CPU you If you have a machine based on an Texas Instruments OMAP CPU you
@ -1575,6 +1601,15 @@ config SERIAL_PCH_UART
ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
config SERIAL_PCH_UART_CONSOLE
bool "Support for console on Intel EG20T PCH UART/OKI SEMICONDUCTOR ML7213 IOH"
depends on SERIAL_PCH_UART=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use the PCH UART as the system console
(the system console is the device which receives all kernel messages and
warnings and which allows logins in single user mode).
config SERIAL_MSM_SMD config SERIAL_MSM_SMD
bool "Enable tty device interface for some SMD ports" bool "Enable tty device interface for some SMD ports"
default n default n

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
@ -94,3 +95,4 @@ obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o 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

View File

@ -212,8 +212,9 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int mode; unsigned int mode;
unsigned long flags;
spin_lock(&port->lock); spin_lock_irqsave(&port->lock, flags);
/* Disable interrupts */ /* Disable interrupts */
UART_PUT_IDR(port, atmel_port->tx_done_mask); UART_PUT_IDR(port, atmel_port->tx_done_mask);
@ -244,7 +245,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
/* Enable interrupts */ /* Enable interrupts */
UART_PUT_IER(port, atmel_port->tx_done_mask); UART_PUT_IER(port, atmel_port->tx_done_mask);
spin_unlock(&port->lock); spin_unlock_irqrestore(&port->lock, flags);
} }
@ -1256,12 +1257,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
static void atmel_set_ldisc(struct uart_port *port, int new) static void atmel_set_ldisc(struct uart_port *port, int new)
{ {
int line = port->line; if (new == N_PPS) {
if (line >= port->state->port.tty->driver->num)
return;
if (port->state->port.tty->ldisc->ops->num == N_PPS) {
port->flags |= UPF_HARDPPS_CD; port->flags |= UPF_HARDPPS_CD;
atmel_enable_ms(port); atmel_enable_ms(port);
} else { } else {

View File

@ -299,8 +299,13 @@ static int sport_startup(struct uart_port *port)
dev_info(port->dev, "Unable to attach BlackFin UART over SPORT CTS interrupt. So, disable it.\n"); dev_info(port->dev, "Unable to attach BlackFin UART over SPORT CTS interrupt. So, disable it.\n");
} }
} }
if (up->rts_pin >= 0) if (up->rts_pin >= 0) {
if (gpio_request(up->rts_pin, DRV_NAME)) {
dev_info(port->dev, "fail to request RTS PIN at GPIO_%d\n", up->rts_pin);
up->rts_pin = -1;
} else
gpio_direction_output(up->rts_pin, 0); gpio_direction_output(up->rts_pin, 0);
}
#endif #endif
return 0; return 0;
@ -445,6 +450,8 @@ static void sport_shutdown(struct uart_port *port)
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS #ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
if (up->cts_pin >= 0) if (up->cts_pin >= 0)
free_irq(gpio_to_irq(up->cts_pin), up); free_irq(gpio_to_irq(up->cts_pin), up);
if (up->rts_pin >= 0)
gpio_free(up->rts_pin);
#endif #endif
} }
@ -803,17 +810,16 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IO, 0); res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL) if (res == NULL)
sport->cts_pin = -1; sport->cts_pin = -1;
else else {
sport->cts_pin = res->start; sport->cts_pin = res->start;
sport->port.flags |= ASYNC_CTS_FLOW;
}
res = platform_get_resource(pdev, IORESOURCE_IO, 1); res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (res == NULL) if (res == NULL)
sport->rts_pin = -1; sport->rts_pin = -1;
else else
sport->rts_pin = res->start; sport->rts_pin = res->start;
if (sport->rts_pin >= 0)
gpio_request(sport->rts_pin, DRV_NAME);
#endif #endif
} }
@ -853,10 +859,6 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
if (sport) { if (sport) {
uart_remove_one_port(&sport_uart_reg, &sport->port); uart_remove_one_port(&sport_uart_reg, &sport->port);
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (sport->rts_pin >= 0)
gpio_free(sport->rts_pin);
#endif
iounmap(sport->port.membase); iounmap(sport->port.membase);
peripheral_free_list( peripheral_free_list(
(unsigned short *)pdev->dev.platform_data); (unsigned short *)pdev->dev.platform_data);

View File

@ -45,11 +45,12 @@
#define SPORT_GET_RX32(sport) \ #define SPORT_GET_RX32(sport) \
({ \ ({ \
unsigned int __ret; \ unsigned int __ret; \
unsigned long flags; \
if (ANOMALY_05000473) \ if (ANOMALY_05000473) \
local_irq_disable(); \ local_irq_save(flags); \
__ret = bfin_read32((sport)->port.membase + OFFSET_RX); \ __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
if (ANOMALY_05000473) \ if (ANOMALY_05000473) \
local_irq_enable(); \ local_irq_restore(flags); \
__ret; \ __ret; \
}) })
#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1)) #define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))

View File

@ -116,15 +116,22 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
{ {
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
unsigned int status; unsigned int status = bfin_serial_get_mctrl(&uart->port);
status = bfin_serial_get_mctrl(&uart->port);
uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
uart->scts = 1; struct tty_struct *tty = uart->port.state->port.tty;
UART_CLEAR_SCTS(uart); UART_CLEAR_SCTS(uart);
UART_CLEAR_IER(uart, EDSSI); if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
uart_write_wakeup(&uart->port);
}
} else {
if (!status)
tty->hw_stopped = 1;
}
#endif #endif
uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -175,13 +182,6 @@ static void bfin_serial_start_tx(struct uart_port *port)
struct bfin_serial_port *uart = (struct bfin_serial_port *)port; struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
struct tty_struct *tty = uart->port.state->port.tty; struct tty_struct *tty = uart->port.state->port.tty;
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
uart->scts = 0;
uart_handle_cts_change(&uart->port, uart->scts);
}
#endif
/* /*
* To avoid losting RX interrupt, we reset IR function * To avoid losting RX interrupt, we reset IR function
* before sending data. * before sending data.
@ -380,12 +380,6 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
{ {
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
uart->scts = 0;
uart_handle_cts_change(&uart->port, uart->scts);
}
#endif
spin_lock(&uart->port.lock); spin_lock(&uart->port.lock);
if (UART_GET_LSR(uart) & THRE) if (UART_GET_LSR(uart) & THRE)
bfin_serial_tx_chars(uart); bfin_serial_tx_chars(uart);
@ -531,13 +525,6 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
struct circ_buf *xmit = &uart->port.state->xmit; struct circ_buf *xmit = &uart->port.state->xmit;
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
uart->scts = 0;
uart_handle_cts_change(&uart->port, uart->scts);
}
#endif
spin_lock(&uart->port.lock); spin_lock(&uart->port.lock);
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
disable_dma(uart->tx_dma_channel); disable_dma(uart->tx_dma_channel);
@ -739,20 +726,26 @@ static int bfin_serial_startup(struct uart_port *port)
pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n"); pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
} }
} }
if (uart->rts_pin >= 0) if (uart->rts_pin >= 0) {
if (gpio_request(uart->rts_pin, DRIVER_NAME)) {
pr_info("fail to request RTS PIN at GPIO_%d\n", uart->rts_pin);
uart->rts_pin = -1;
} else
gpio_direction_output(uart->rts_pin, 0); gpio_direction_output(uart->rts_pin, 0);
}
#endif #endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0 && request_irq(uart->status_irq, if (uart->cts_pin >= 0) {
bfin_serial_mctrl_cts_int, if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
0, "BFIN_UART_MODEM_STATUS", uart)) { IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
uart->cts_pin = -1; uart->cts_pin = -1;
pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n"); dev_info(port->dev, "Unable to attach BlackFin UART Modem Status interrupt.\n");
} }
/* CTS RTS PINs are negative assertive. */ /* CTS RTS PINs are negative assertive. */
UART_PUT_MCR(uart, ACTS); UART_PUT_MCR(uart, ACTS);
UART_SET_IER(uart, EDSSI); UART_SET_IER(uart, EDSSI);
}
#endif #endif
UART_SET_IER(uart, ERBFI); UART_SET_IER(uart, ERBFI);
@ -792,6 +785,8 @@ static void bfin_serial_shutdown(struct uart_port *port)
#ifdef CONFIG_SERIAL_BFIN_CTSRTS #ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0) if (uart->cts_pin >= 0)
free_irq(gpio_to_irq(uart->cts_pin), uart); free_irq(gpio_to_irq(uart->cts_pin), uart);
if (uart->rts_pin >= 0)
gpio_free(uart->rts_pin);
#endif #endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0) if (uart->cts_pin >= 0)
@ -1370,18 +1365,18 @@ static int bfin_serial_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IO, 0); res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL) if (res == NULL)
uart->cts_pin = -1; uart->cts_pin = -1;
else else {
uart->cts_pin = res->start; uart->cts_pin = res->start;
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
uart->port.flags |= ASYNC_CTS_FLOW;
#endif
}
res = platform_get_resource(pdev, IORESOURCE_IO, 1); res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (res == NULL) if (res == NULL)
uart->rts_pin = -1; uart->rts_pin = -1;
else else
uart->rts_pin = res->start; uart->rts_pin = res->start;
# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
if (uart->rts_pin >= 0)
gpio_request(uart->rts_pin, DRIVER_NAME);
# endif
#endif #endif
} }
@ -1421,10 +1416,6 @@ static int __devexit bfin_serial_remove(struct platform_device *pdev)
if (uart) { if (uart) {
uart_remove_one_port(&bfin_serial_reg, &uart->port); uart_remove_one_port(&bfin_serial_reg, &uart->port);
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (uart->rts_pin >= 0)
gpio_free(uart->rts_pin);
#endif
iounmap(uart->port.membase); iounmap(uart->port.membase);
peripheral_free_list( peripheral_free_list(
(unsigned short *)pdev->dev.platform_data); (unsigned short *)pdev->dev.platform_data);

View File

@ -1334,7 +1334,6 @@ MODULE_DEVICE_TABLE(spi, ifx_id_table);
static const struct spi_driver ifx_spi_driver = { static const struct spi_driver ifx_spi_driver = {
.driver = { .driver = {
.name = DRVNAME, .name = DRVNAME,
.bus = &spi_bus_type,
.pm = &ifx_spi_pm, .pm = &ifx_spi_pm,
.owner = THIS_MODULE}, .owner = THIS_MODULE},
.probe = ifx_spi_spi_probe, .probe = ifx_spi_spi_probe,

View File

@ -102,6 +102,7 @@
#define UCR2_STPB (1<<6) /* Stop */ #define UCR2_STPB (1<<6) /* Stop */
#define UCR2_WS (1<<5) /* Word size */ #define UCR2_WS (1<<5) /* Word size */
#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ #define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
#define UCR2_ATEN (1<<3) /* Aging Timer Enable */
#define UCR2_TXEN (1<<2) /* Transmitter enabled */ #define UCR2_TXEN (1<<2) /* Transmitter enabled */
#define UCR2_RXEN (1<<1) /* Receiver enabled */ #define UCR2_RXEN (1<<1) /* Receiver enabled */
#define UCR2_SRST (1<<0) /* SW reset */ #define UCR2_SRST (1<<0) /* SW reset */
@ -207,6 +208,12 @@ struct imx_port {
struct imx_uart_data *devdata; struct imx_uart_data *devdata;
}; };
struct imx_port_ucrs {
unsigned int ucr1;
unsigned int ucr2;
unsigned int ucr3;
};
#ifdef CONFIG_IRDA #ifdef CONFIG_IRDA
#define USE_IRDA(sport) ((sport)->use_irda) #define USE_IRDA(sport) ((sport)->use_irda)
#else #else
@ -259,6 +266,27 @@ static inline int is_imx21_uart(struct imx_port *sport)
return sport->devdata->devtype == IMX21_UART; return sport->devdata->devtype == IMX21_UART;
} }
/*
* Save and restore functions for UCR1, UCR2 and UCR3 registers
*/
static void imx_port_ucrs_save(struct uart_port *port,
struct imx_port_ucrs *ucr)
{
/* save control registers */
ucr->ucr1 = readl(port->membase + UCR1);
ucr->ucr2 = readl(port->membase + UCR2);
ucr->ucr3 = readl(port->membase + UCR3);
}
static void imx_port_ucrs_restore(struct uart_port *port,
struct imx_port_ucrs *ucr)
{
/* restore control registers */
writel(ucr->ucr1, port->membase + UCR1);
writel(ucr->ucr2, port->membase + UCR2);
writel(ucr->ucr3, port->membase + UCR3);
}
/* /*
* Handle any change of modem status signal since we were last called. * Handle any change of modem status signal since we were last called.
*/ */
@ -566,6 +594,9 @@ static irqreturn_t imx_int(int irq, void *dev_id)
if (sts & USR1_RTSD) if (sts & USR1_RTSD)
imx_rtsint(irq, dev_id); imx_rtsint(irq, dev_id);
if (sts & USR1_AWAKE)
writel(USR1_AWAKE, sport->port.membase + USR1);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -901,6 +932,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
ucr2 |= UCR2_PROE; ucr2 |= UCR2_PROE;
} }
del_timer_sync(&sport->timer);
/* /*
* Ask the core to calculate the divisor for us. * Ask the core to calculate the divisor for us.
*/ */
@ -931,8 +964,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.ignore_status_mask |= URXD_OVRRUN; sport->port.ignore_status_mask |= URXD_OVRRUN;
} }
del_timer_sync(&sport->timer);
/* /*
* Update the per-port timeout. * Update the per-port timeout.
*/ */
@ -1079,6 +1110,70 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
return ret; return ret;
} }
#if defined(CONFIG_CONSOLE_POLL)
static int imx_poll_get_char(struct uart_port *port)
{
struct imx_port_ucrs old_ucr;
unsigned int status;
unsigned char c;
/* save control registers */
imx_port_ucrs_save(port, &old_ucr);
/* disable interrupts */
writel(UCR1_UARTEN, port->membase + UCR1);
writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
port->membase + UCR2);
writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
port->membase + UCR3);
/* poll */
do {
status = readl(port->membase + USR2);
} while (~status & USR2_RDR);
/* read */
c = readl(port->membase + URXD0);
/* restore control registers */
imx_port_ucrs_restore(port, &old_ucr);
return c;
}
static void imx_poll_put_char(struct uart_port *port, unsigned char c)
{
struct imx_port_ucrs old_ucr;
unsigned int status;
/* save control registers */
imx_port_ucrs_save(port, &old_ucr);
/* disable interrupts */
writel(UCR1_UARTEN, port->membase + UCR1);
writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
port->membase + UCR2);
writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
port->membase + UCR3);
/* drain */
do {
status = readl(port->membase + USR1);
} while (~status & USR1_TRDY);
/* write */
writel(c, port->membase + URTX0);
/* flush */
do {
status = readl(port->membase + USR2);
} while (~status & USR2_TXDC);
/* restore control registers */
imx_port_ucrs_restore(port, &old_ucr);
}
#endif
static struct uart_ops imx_pops = { static struct uart_ops imx_pops = {
.tx_empty = imx_tx_empty, .tx_empty = imx_tx_empty,
.set_mctrl = imx_set_mctrl, .set_mctrl = imx_set_mctrl,
@ -1096,6 +1191,10 @@ static struct uart_ops imx_pops = {
.request_port = imx_request_port, .request_port = imx_request_port,
.config_port = imx_config_port, .config_port = imx_config_port,
.verify_port = imx_verify_port, .verify_port = imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
.poll_get_char = imx_poll_get_char,
.poll_put_char = imx_poll_put_char,
#endif
}; };
static struct imx_port *imx_ports[UART_NR]; static struct imx_port *imx_ports[UART_NR];
@ -1118,13 +1217,14 @@ static void
imx_console_write(struct console *co, const char *s, unsigned int count) imx_console_write(struct console *co, const char *s, unsigned int count)
{ {
struct imx_port *sport = imx_ports[co->index]; struct imx_port *sport = imx_ports[co->index];
unsigned int old_ucr1, old_ucr2, ucr1; struct imx_port_ucrs old_ucr;
unsigned int ucr1;
/* /*
* First, save UCR1/2 and then disable interrupts * First, save UCR1/2/3 and then disable interrupts
*/ */
ucr1 = old_ucr1 = readl(sport->port.membase + UCR1); imx_port_ucrs_save(&sport->port, &old_ucr);
old_ucr2 = readl(sport->port.membase + UCR2); ucr1 = old_ucr.ucr1;
if (is_imx1_uart(sport)) if (is_imx1_uart(sport))
ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= IMX1_UCR1_UARTCLKEN;
@ -1133,18 +1233,17 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
writel(ucr1, sport->port.membase + UCR1); writel(ucr1, sport->port.membase + UCR1);
writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2); writel(old_ucr.ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
uart_console_write(&sport->port, s, count, imx_console_putchar); uart_console_write(&sport->port, s, count, imx_console_putchar);
/* /*
* Finally, wait for transmitter to become empty * Finally, wait for transmitter to become empty
* and restore UCR1/2 * and restore UCR1/2/3
*/ */
while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
writel(old_ucr1, sport->port.membase + UCR1); imx_port_ucrs_restore(&sport->port, &old_ucr);
writel(old_ucr2, sport->port.membase + UCR2);
} }
/* /*
@ -1269,6 +1368,12 @@ static struct uart_driver imx_reg = {
static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
{ {
struct imx_port *sport = platform_get_drvdata(dev); struct imx_port *sport = platform_get_drvdata(dev);
unsigned int val;
/* enable wakeup from i.MX UART */
val = readl(sport->port.membase + UCR3);
val |= UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
if (sport) if (sport)
uart_suspend_port(&imx_reg, &sport->port); uart_suspend_port(&imx_reg, &sport->port);
@ -1279,6 +1384,12 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
static int serial_imx_resume(struct platform_device *dev) static int serial_imx_resume(struct platform_device *dev)
{ {
struct imx_port *sport = platform_get_drvdata(dev); struct imx_port *sport = platform_get_drvdata(dev);
unsigned int val;
/* disable wakeup from i.MX UART */
val = readl(sport->port.membase + UCR3);
val &= ~UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
if (sport) if (sport)
uart_resume_port(&imx_reg, &sport->port); uart_resume_port(&imx_reg, &sport->port);
@ -1287,6 +1398,10 @@ static int serial_imx_resume(struct platform_device *dev)
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
/*
* This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it
* could successfully get all information from dt or a negative errno.
*/
static int serial_imx_probe_dt(struct imx_port *sport, static int serial_imx_probe_dt(struct imx_port *sport,
struct platform_device *pdev) struct platform_device *pdev)
{ {
@ -1296,12 +1411,13 @@ static int serial_imx_probe_dt(struct imx_port *sport,
int ret; int ret;
if (!np) if (!np)
return -ENODEV; /* no device tree device */
return 1;
ret = of_alias_get_id(np, "serial"); ret = of_alias_get_id(np, "serial");
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return -ENODEV; return ret;
} }
sport->port.line = ret; sport->port.line = ret;
@ -1319,7 +1435,7 @@ static int serial_imx_probe_dt(struct imx_port *sport,
static inline int serial_imx_probe_dt(struct imx_port *sport, static inline int serial_imx_probe_dt(struct imx_port *sport,
struct platform_device *pdev) struct platform_device *pdev)
{ {
return -ENODEV; return 1;
} }
#endif #endif
@ -1354,8 +1470,10 @@ static int serial_imx_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
ret = serial_imx_probe_dt(sport, pdev); ret = serial_imx_probe_dt(sport, pdev);
if (ret == -ENODEV) if (ret > 0)
serial_imx_probe_pdata(sport, pdev); serial_imx_probe_pdata(sport, pdev);
else if (ret < 0)
goto free;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
@ -1476,7 +1594,7 @@ static int __init imx_serial_init(void)
if (ret != 0) if (ret != 0)
uart_unregister_driver(&imx_reg); uart_unregister_driver(&imx_reg);
return 0; return ret;
} }
static void __exit imx_serial_exit(void) static void __exit imx_serial_exit(void)

View File

@ -1000,11 +1000,8 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
init_timer(&up->timer); init_timer(&up->timer);
up->timer.function = m32r_sio_timeout; up->timer.function = m32r_sio_timeout;
/* up->mcr_mask = ~0;
* ALPHA_KLUDGE_MCR needs to be killed. up->mcr_force = 0;
*/
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR;
uart_add_one_port(drv, &up->port); uart_add_one_port(drv, &up->port);
} }

View File

@ -901,7 +901,6 @@ static int max3100_resume(struct spi_device *spi)
static struct spi_driver max3100_driver = { static struct spi_driver max3100_driver = {
.driver = { .driver = {
.name = "max3100", .name = "max3100",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },

View File

@ -315,7 +315,6 @@ static int __devinit max3107_probe_aava(struct spi_device *spi)
static struct spi_driver max3107_driver = { static struct spi_driver max3107_driver = {
.driver = { .driver = {
.name = "aava-max3107", .name = "aava-max3107",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = max3107_probe_aava, .probe = max3107_probe_aava,

View File

@ -1181,7 +1181,6 @@ static int max3107_probe_generic(struct spi_device *spi)
static struct spi_driver max3107_driver = { static struct spi_driver max3107_driver = {
.driver = { .driver = {
.name = "max3107", .name = "max3107",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = max3107_probe_generic, .probe = max3107_probe_generic,

View File

@ -1154,7 +1154,6 @@ serial_hsu_console_setup(struct console *co, char *options)
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
int flow = 'n'; int flow = 'n';
int ret;
if (co->index == -1 || co->index >= serial_hsu_reg.nr) if (co->index == -1 || co->index >= serial_hsu_reg.nr)
co->index = 0; co->index = 0;
@ -1165,9 +1164,7 @@ serial_hsu_console_setup(struct console *co, char *options)
if (options) if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow); uart_parse_options(options, &baud, &parity, &bits, &flow);
ret = uart_set_options(&up->port, co, baud, parity, bits, flow); return uart_set_options(&up->port, co, baud, parity, bits, flow);
return ret;
} }
static struct console serial_hsu_console = { static struct console serial_hsu_console = {
@ -1176,9 +1173,13 @@ static struct console serial_hsu_console = {
.device = uart_console_device, .device = uart_console_device,
.setup = serial_hsu_console_setup, .setup = serial_hsu_console_setup,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.index = 2, .index = -1,
.data = &serial_hsu_reg, .data = &serial_hsu_reg,
}; };
#define SERIAL_HSU_CONSOLE (&serial_hsu_console)
#else
#define SERIAL_HSU_CONSOLE NULL
#endif #endif
struct uart_ops serial_hsu_pops = { struct uart_ops serial_hsu_pops = {
@ -1208,6 +1209,7 @@ static struct uart_driver serial_hsu_reg = {
.major = TTY_MAJOR, .major = TTY_MAJOR,
.minor = 128, .minor = 128,
.nr = 3, .nr = 3,
.cons = SERIAL_HSU_CONSOLE,
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -1342,12 +1344,6 @@ static int serial_hsu_probe(struct pci_dev *pdev,
} }
uart_add_one_port(&serial_hsu_reg, &uport->port); uart_add_one_port(&serial_hsu_reg, &uport->port);
#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
if (index == 2) {
register_console(&serial_hsu_console);
uport->port.cons = &serial_hsu_console;
}
#endif
pci_set_drvdata(pdev, uport); pci_set_drvdata(pdev, uport);
} }

View File

@ -876,7 +876,6 @@ static int __devexit serial_m3110_remove(struct spi_device *dev)
static struct spi_driver uart_max3110_driver = { static struct spi_driver uart_max3110_driver = {
.driver = { .driver = {
.name = "spi_max3111", .name = "spi_max3111",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = serial_m3110_probe, .probe = serial_m3110_probe,

View File

@ -422,9 +422,9 @@ static int __devexit msm_hs_remove(struct platform_device *pdev)
msm_uport->rx.rbuffer); msm_uport->rx.rbuffer);
dma_pool_destroy(msm_uport->rx.pool); dma_pool_destroy(msm_uport->rx.pool);
dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32 *), dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32),
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32 *), dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32),
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box), dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
DMA_TO_DEVICE); DMA_TO_DEVICE);
@ -812,7 +812,7 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport)
*tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr); *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr, dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
sizeof(u32 *), DMA_TO_DEVICE); sizeof(u32), DMA_TO_DEVICE);
/* Save tx_count to use in Callback */ /* Save tx_count to use in Callback */
tx->tx_count = tx_count; tx->tx_count = tx_count;
@ -1087,12 +1087,10 @@ static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
} }
/* Handle CTS changes (Called from interrupt handler) */ /* Handle CTS changes (Called from interrupt handler) */
static void msm_hs_handle_delta_cts(struct uart_port *uport) static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
{ {
unsigned long flags;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
spin_lock_irqsave(&uport->lock, flags);
clk_enable(msm_uport->clk); clk_enable(msm_uport->clk);
/* clear interrupt */ /* clear interrupt */
@ -1100,7 +1098,6 @@ static void msm_hs_handle_delta_cts(struct uart_port *uport)
uport->icount.cts++; uport->icount.cts++;
clk_disable(msm_uport->clk); clk_disable(msm_uport->clk);
spin_unlock_irqrestore(&uport->lock, flags);
/* clear the IOCTL TIOCMIWAIT if called */ /* clear the IOCTL TIOCMIWAIT if called */
wake_up_interruptible(&uport->state->port.delta_msr_wait); wake_up_interruptible(&uport->state->port.delta_msr_wait);
@ -1248,7 +1245,7 @@ static irqreturn_t msm_hs_isr(int irq, void *dev)
/* Change in CTS interrupt */ /* Change in CTS interrupt */
if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK) if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK)
msm_hs_handle_delta_cts(uport); msm_hs_handle_delta_cts_locked(uport);
spin_unlock_irqrestore(&uport->lock, flags); spin_unlock_irqrestore(&uport->lock, flags);
@ -1537,7 +1534,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
if (!tx->command_ptr) if (!tx->command_ptr)
return -ENOMEM; return -ENOMEM;
tx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA); tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!tx->command_ptr_ptr) { if (!tx->command_ptr_ptr) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_tx_command_ptr_ptr; goto err_tx_command_ptr_ptr;
@ -1547,7 +1544,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
sizeof(dmov_box), DMA_TO_DEVICE); sizeof(dmov_box), DMA_TO_DEVICE);
tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev, tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
tx->command_ptr_ptr, tx->command_ptr_ptr,
sizeof(u32 *), DMA_TO_DEVICE); sizeof(u32), DMA_TO_DEVICE);
tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr); tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
init_waitqueue_head(&rx->wait); init_waitqueue_head(&rx->wait);
@ -1575,7 +1572,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
goto err_rx_command_ptr; goto err_rx_command_ptr;
} }
rx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA); rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!rx->command_ptr_ptr) { if (!rx->command_ptr_ptr) {
pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__); pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
ret = -ENOMEM; ret = -ENOMEM;
@ -1593,7 +1590,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
*rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr); *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr, rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
sizeof(u32 *), DMA_TO_DEVICE); sizeof(u32), DMA_TO_DEVICE);
rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr); rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work); INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work);
@ -1609,7 +1606,7 @@ err_dma_pool_alloc:
dma_pool_destroy(msm_uport->rx.pool); dma_pool_destroy(msm_uport->rx.pool);
err_dma_pool_create: err_dma_pool_create:
dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr, dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
sizeof(u32 *), DMA_TO_DEVICE); sizeof(u32), DMA_TO_DEVICE);
dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr, dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
sizeof(dmov_box), DMA_TO_DEVICE); sizeof(dmov_box), DMA_TO_DEVICE);
kfree(msm_uport->tx.command_ptr_ptr); kfree(msm_uport->tx.command_ptr_ptr);

View File

@ -145,11 +145,12 @@ static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
writel(xmit->buf[xmit->tail], writel(xmit->buf[xmit->tail],
s->port.membase + AUART_DATA); s->port.membase + AUART_DATA);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&s->port);
} else } else
break; break;
} }
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&s->port);
if (uart_circ_empty(&(s->port.state->xmit))) if (uart_circ_empty(&(s->port.state->xmit)))
writel(AUART_INTR_TXIEN, writel(AUART_INTR_TXIEN,
s->port.membase + AUART_INTR_CLR); s->port.membase + AUART_INTR_CLR);

View File

@ -399,7 +399,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
static unsigned int serial_omap_get_mctrl(struct uart_port *port) static unsigned int serial_omap_get_mctrl(struct uart_port *port)
{ {
struct uart_omap_port *up = (struct uart_omap_port *)port; struct uart_omap_port *up = (struct uart_omap_port *)port;
unsigned char status; unsigned int status;
unsigned int ret = 0; unsigned int ret = 0;
status = check_modem_status(up); status = check_modem_status(up);

View File

@ -25,6 +25,9 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/console.h>
#include <linux/nmi.h>
#include <linux/delay.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/pch_dma.h> #include <linux/pch_dma.h>
@ -198,6 +201,10 @@ enum {
#define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_VENDOR_ID_ROHM 0x10DB
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */
struct pch_uart_buffer { struct pch_uart_buffer {
unsigned char *buf; unsigned char *buf;
int size; int size;
@ -276,6 +283,9 @@ static struct pch_uart_driver_data drv_dat[] = {
[pch_ml7831_uart1] = {PCH_UART_2LINE, 1}, [pch_ml7831_uart1] = {PCH_UART_2LINE, 1},
}; };
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
#endif
static unsigned int default_baud = 9600; static unsigned int default_baud = 9600;
static const int trigger_level_256[4] = { 1, 64, 128, 224 }; static const int trigger_level_256[4] = { 1, 64, 128, 224 };
static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_64[4] = { 1, 16, 32, 56 };
@ -1385,6 +1395,143 @@ static struct uart_ops pch_uart_ops = {
.verify_port = pch_uart_verify_port .verify_port = pch_uart_verify_port
}; };
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
/*
* Wait for transmitter & holding register to empty
*/
static void wait_for_xmitr(struct eg20t_port *up, int bits)
{
unsigned int status, tmout = 10000;
/* Wait up to 10ms for the character(s) to be sent. */
for (;;) {
status = ioread8(up->membase + UART_LSR);
if ((status & bits) == bits)
break;
if (--tmout == 0)
break;
udelay(1);
}
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
unsigned int tmout;
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = ioread8(up->membase + UART_MSR);
if (msr & UART_MSR_CTS)
break;
udelay(1);
touch_nmi_watchdog();
}
}
}
static void pch_console_putchar(struct uart_port *port, int ch)
{
struct eg20t_port *priv =
container_of(port, struct eg20t_port, port);
wait_for_xmitr(priv, UART_LSR_THRE);
iowrite8(ch, priv->membase + PCH_UART_THR);
}
/*
* 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.
*/
static void
pch_console_write(struct console *co, const char *s, unsigned int count)
{
struct eg20t_port *priv;
unsigned long flags;
u8 ier;
int locked = 1;
priv = pch_uart_ports[co->index];
touch_nmi_watchdog();
local_irq_save(flags);
if (priv->port.sysrq) {
/* serial8250_handle_port() already took the lock */
locked = 0;
} else if (oops_in_progress) {
locked = spin_trylock(&priv->port.lock);
} else
spin_lock(&priv->port.lock);
/*
* First save the IER then disable the interrupts
*/
ier = ioread8(priv->membase + UART_IER);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
uart_console_write(&priv->port, s, count, pch_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(priv, BOTH_EMPTY);
iowrite8(ier, priv->membase + UART_IER);
if (locked)
spin_unlock(&priv->port.lock);
local_irq_restore(flags);
}
static int __init pch_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
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.
*/
if (co->index >= PCH_UART_NR)
co->index = 0;
port = &pch_uart_ports[co->index]->port;
if (!port || (!port->iobase && !port->membase))
return -ENODEV;
/* setup uartclock */
port->uartclk = DEFAULT_BAUD_RATE;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver pch_uart_driver;
static struct console pch_console = {
.name = PCH_UART_DRIVER_DEVICE,
.write = pch_console_write,
.device = uart_console_device,
.setup = pch_console_setup,
.flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
.data = &pch_uart_driver,
};
#define PCH_CONSOLE (&pch_console)
#else
#define PCH_CONSOLE NULL
#endif
static struct uart_driver pch_uart_driver = { static struct uart_driver pch_uart_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.driver_name = KBUILD_MODNAME, .driver_name = KBUILD_MODNAME,
@ -1392,6 +1539,7 @@ static struct uart_driver pch_uart_driver = {
.major = 0, .major = 0,
.minor = 0, .minor = 0,
.nr = PCH_UART_NR, .nr = PCH_UART_NR,
.cons = PCH_CONSOLE,
}; };
static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
@ -1418,7 +1566,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (!rxbuf) if (!rxbuf)
goto init_port_free_txbuf; goto init_port_free_txbuf;
base_baud = 1843200; /* 1.8432MHz */ base_baud = DEFAULT_BAUD_RATE;
/* quirk for CM-iTC board */ /* quirk for CM-iTC board */
board_name = dmi_get_system_info(DMI_BOARD_NAME); board_name = dmi_get_system_info(DMI_BOARD_NAME);
@ -1468,6 +1616,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
pci_set_drvdata(pdev, priv); pci_set_drvdata(pdev, priv);
pch_uart_hal_request(pdev, fifosize, base_baud); pch_uart_hal_request(pdev, fifosize, base_baud);
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[board->line_no] = priv;
#endif
ret = uart_add_one_port(&pch_uart_driver, &priv->port); ret = uart_add_one_port(&pch_uart_driver, &priv->port);
if (ret < 0) if (ret < 0)
goto init_port_hal_free; goto init_port_hal_free;
@ -1475,6 +1626,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
return priv; return priv;
init_port_hal_free: init_port_hal_free:
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[board->line_no] = NULL;
#endif
free_page((unsigned long)rxbuf); free_page((unsigned long)rxbuf);
init_port_free_txbuf: init_port_free_txbuf:
kfree(priv); kfree(priv);
@ -1497,6 +1651,10 @@ static void pch_uart_pci_remove(struct pci_dev *pdev)
priv = (struct eg20t_port *)pci_get_drvdata(pdev); priv = (struct eg20t_port *)pci_get_drvdata(pdev);
pci_disable_msi(pdev); pci_disable_msi(pdev);
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[priv->port.line] = NULL;
#endif
pch_uart_exit_port(priv); pch_uart_exit_port(priv);
pci_disable_device(pdev); pci_disable_device(pdev);
kfree(priv); kfree(priv);

View File

@ -736,19 +736,7 @@ static struct platform_driver sc26xx_driver = {
}, },
}; };
static int __init sc26xx_init(void) module_platform_driver(sc26xx_driver);
{
return platform_driver_register(&sc26xx_driver);
}
static void __exit sc26xx_exit(void)
{
platform_driver_unregister(&sc26xx_driver);
}
module_init(sc26xx_init);
module_exit(sc26xx_exit);
MODULE_AUTHOR("Thomas Bogendörfer"); MODULE_AUTHOR("Thomas Bogendörfer");
MODULE_DESCRIPTION("SC681/SC2692 serial driver"); MODULE_DESCRIPTION("SC681/SC2692 serial driver");

View File

@ -22,6 +22,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/console.h> #include <linux/console.h>
@ -60,6 +61,8 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
static void uart_change_pm(struct uart_state *state, int pm_state); static void uart_change_pm(struct uart_state *state, int pm_state);
static void uart_port_shutdown(struct tty_port *port);
/* /*
* This routine is used by the interrupt handler to schedule processing in * This routine is used by the interrupt handler to schedule processing in
* the software interrupt portion of the driver. * the software interrupt portion of the driver.
@ -128,25 +131,16 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
* Startup the port. This will be called once per open. All calls * Startup the port. This will be called once per open. All calls
* will be serialised by the per-port mutex. * will be serialised by the per-port mutex.
*/ */
static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
{ {
struct uart_port *uport = state->uart_port; struct uart_port *uport = state->uart_port;
struct tty_port *port = &state->port; struct tty_port *port = &state->port;
unsigned long page; unsigned long page;
int retval = 0; int retval = 0;
if (port->flags & ASYNC_INITIALIZED)
return 0;
/*
* Set the TTY IO error marker - we will only clear this
* once we have successfully opened the port. Also set
* up the tty->alt_speed kludge
*/
set_bit(TTY_IO_ERROR, &tty->flags);
if (uport->type == PORT_UNKNOWN) if (uport->type == PORT_UNKNOWN)
return 0; return 1;
/* /*
* Initialise and allocate the transmit and temporary * Initialise and allocate the transmit and temporary
@ -188,10 +182,6 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in
tty->hw_stopped = 1; tty->hw_stopped = 1;
spin_unlock_irq(&uport->lock); spin_unlock_irq(&uport->lock);
} }
set_bit(ASYNCB_INITIALIZED, &port->flags);
clear_bit(TTY_IO_ERROR, &tty->flags);
} }
/* /*
@ -200,6 +190,31 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in
* now. * now.
*/ */
if (retval && capable(CAP_SYS_ADMIN)) if (retval && capable(CAP_SYS_ADMIN))
return 1;
return retval;
}
static int uart_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
{
struct tty_port *port = &state->port;
int retval;
if (port->flags & ASYNC_INITIALIZED)
return 0;
/*
* Set the TTY IO error marker - we will only clear this
* once we have successfully opened the port.
*/
set_bit(TTY_IO_ERROR, &tty->flags);
retval = uart_port_startup(tty, state, init_hw);
if (!retval) {
set_bit(ASYNCB_INITIALIZED, &port->flags);
clear_bit(TTY_IO_ERROR, &tty->flags);
} else if (retval > 0)
retval = 0; retval = 0;
return retval; return retval;
@ -228,24 +243,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
if (!tty || (tty->termios->c_cflag & HUPCL)) if (!tty || (tty->termios->c_cflag & HUPCL))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
/* uart_port_shutdown(port);
* clear delta_msr_wait queue to avoid mem leaks: we may free
* the irq here so the queue might never be woken up. Note
* that we won't end up waiting on delta_msr_wait again since
* any outstanding file descriptors should be pointing at
* hung_up_tty_fops now.
*/
wake_up_interruptible(&port->delta_msr_wait);
/*
* Free the IRQ and disable the port.
*/
uport->ops->shutdown(uport);
/*
* Ensure that the IRQ handler isn't running on another CPU.
*/
synchronize_irq(uport->irq);
} }
/* /*
@ -423,7 +421,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor; quot = port->custom_divisor;
else else
quot = (port->uartclk + (8 * baud)) / (16 * baud); quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
return quot; return quot;
} }
@ -658,10 +656,10 @@ static int uart_get_info(struct uart_state *state,
tmp.flags = uport->flags; tmp.flags = uport->flags;
tmp.xmit_fifo_size = uport->fifosize; tmp.xmit_fifo_size = uport->fifosize;
tmp.baud_base = uport->uartclk / 16; tmp.baud_base = uport->uartclk / 16;
tmp.close_delay = port->close_delay / 10; tmp.close_delay = jiffies_to_msecs(port->close_delay) / 10;
tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE : ASYNC_CLOSING_WAIT_NONE :
port->closing_wait / 10; jiffies_to_msecs(port->closing_wait) / 10;
tmp.custom_divisor = uport->custom_divisor; tmp.custom_divisor = uport->custom_divisor;
tmp.hub6 = uport->hub6; tmp.hub6 = uport->hub6;
tmp.io_type = uport->iotype; tmp.io_type = uport->iotype;
@ -695,9 +693,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
new_serial.irq = irq_canonicalize(new_serial.irq); new_serial.irq = irq_canonicalize(new_serial.irq);
close_delay = new_serial.close_delay * 10; close_delay = msecs_to_jiffies(new_serial.close_delay * 10);
closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; ASYNC_CLOSING_WAIT_NONE :
msecs_to_jiffies(new_serial.closing_wait * 10);
/* /*
* This semaphore protects port->count. It is also * This semaphore protects port->count. It is also
@ -1265,47 +1264,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
pr_debug("uart_close(%d) called\n", uport->line); pr_debug("uart_close(%d) called\n", uport->line);
spin_lock_irqsave(&port->lock, flags); if (tty_port_close_start(port, tty, filp) == 0)
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&port->lock, flags);
return; return;
}
if ((tty->count == 1) && (port->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. port->count should always
* be one in these conditions. If it's greater than
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, "
"port->count is %d\n", port->count);
port->count = 1;
}
if (--port->count < 0) {
printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n",
tty->name, port->count);
port->count = 0;
}
if (port->count) {
spin_unlock_irqrestore(&port->lock, flags);
return;
}
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters by
* setting tty->closing.
*/
set_bit(ASYNCB_CLOSING, &port->flags);
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent_from_close(tty,
msecs_to_jiffies(port->closing_wait));
/* /*
* At this point, we stop accepting input. To do this, we * At this point, we stop accepting input. To do this, we
@ -1337,7 +1297,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
if (port->blocked_open) { if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
if (port->close_delay) if (port->close_delay)
msleep_interruptible(port->close_delay); msleep_interruptible(
jiffies_to_msecs(port->close_delay));
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
} else if (!uart_console(uport)) { } else if (!uart_console(uport)) {
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
@ -1441,6 +1402,36 @@ static void uart_hangup(struct tty_struct *tty)
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
} }
static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
{
return 0;
}
static void uart_port_shutdown(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free
* the irq here so the queue might never be woken up. Note
* that we won't end up waiting on delta_msr_wait again since
* any outstanding file descriptors should be pointing at
* hung_up_tty_fops now.
*/
wake_up_interruptible(&port->delta_msr_wait);
/*
* Free the IRQ and disable the port.
*/
uport->ops->shutdown(uport);
/*
* Ensure that the IRQ handler isn't running on another CPU.
*/
synchronize_irq(uport->irq);
}
static int uart_carrier_raised(struct tty_port *port) static int uart_carrier_raised(struct tty_port *port)
{ {
struct uart_state *state = container_of(port, struct uart_state, port); struct uart_state *state = container_of(port, struct uart_state, port);
@ -1466,33 +1457,6 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
} }
static struct uart_state *uart_get(struct uart_driver *drv, int line)
{
struct uart_state *state;
struct tty_port *port;
int ret = 0;
state = drv->state + line;
port = &state->port;
if (mutex_lock_interruptible(&port->mutex)) {
ret = -ERESTARTSYS;
goto err;
}
port->count++;
if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
ret = -ENXIO;
goto err_unlock;
}
return state;
err_unlock:
port->count--;
mutex_unlock(&port->mutex);
err:
return ERR_PTR(ret);
}
/* /*
* calls to uart_open are serialised by the BKL in * calls to uart_open are serialised by the BKL in
* fs/char_dev.c:chrdev_open() * fs/char_dev.c:chrdev_open()
@ -1506,26 +1470,29 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
static int uart_open(struct tty_struct *tty, struct file *filp) static int uart_open(struct tty_struct *tty, struct file *filp)
{ {
struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
struct uart_state *state;
struct tty_port *port;
int retval, line = tty->index; int retval, line = tty->index;
struct uart_state *state = drv->state + line;
struct tty_port *port = &state->port;
pr_debug("uart_open(%d) called\n", line); pr_debug("uart_open(%d) called\n", line);
/* /*
* We take the semaphore inside uart_get to guarantee that we won't * We take the semaphore here to guarantee that we won't be re-entered
* be re-entered while allocating the state structure, or while we * while allocating the state structure, or while we request any IRQs
* request any IRQs that the driver may need. This also has the nice * that the driver may need. This also has the nice side-effect that
* side-effect that it delays the action of uart_hangup, so we can * it delays the action of uart_hangup, so we can guarantee that
* guarantee that state->port.tty will always contain something * state->port.tty will always contain something reasonable.
* reasonable.
*/ */
state = uart_get(drv, line); if (mutex_lock_interruptible(&port->mutex)) {
if (IS_ERR(state)) { retval = -ERESTARTSYS;
retval = PTR_ERR(state); goto end;
goto fail; }
port->count++;
if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
retval = -ENXIO;
goto err_dec_count;
} }
port = &state->port;
/* /*
* Once we set tty->driver_data here, we are guaranteed that * Once we set tty->driver_data here, we are guaranteed that
@ -1535,7 +1502,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
tty->driver_data = state; tty->driver_data = state;
state->uart_port->state = state; state->uart_port->state = state;
tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
tty_port_tty_set(port, tty); tty_port_tty_set(port, tty);
/* /*
@ -1543,9 +1509,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
*/ */
if (tty_hung_up_p(filp)) { if (tty_hung_up_p(filp)) {
retval = -EAGAIN; retval = -EAGAIN;
port->count--; goto err_dec_count;
mutex_unlock(&port->mutex);
goto fail;
} }
/* /*
@ -1566,8 +1530,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
if (retval == 0) if (retval == 0)
retval = tty_port_block_til_ready(port, tty, filp); retval = tty_port_block_til_ready(port, tty, filp);
fail: end:
return retval; return retval;
err_dec_count:
port->count--;
mutex_unlock(&port->mutex);
goto end;
} }
static const char *uart_type(struct uart_port *port) static const char *uart_type(struct uart_port *port)
@ -1858,6 +1826,14 @@ uart_set_options(struct uart_port *port, struct console *co,
EXPORT_SYMBOL_GPL(uart_set_options); EXPORT_SYMBOL_GPL(uart_set_options);
#endif /* CONFIG_SERIAL_CORE_CONSOLE */ #endif /* CONFIG_SERIAL_CORE_CONSOLE */
/**
* uart_change_pm - set power state of the port
*
* @state: port descriptor
* @pm_state: new state
*
* Locking: port->mutex has to be held
*/
static void uart_change_pm(struct uart_state *state, int pm_state) static void uart_change_pm(struct uart_state *state, int pm_state)
{ {
struct uart_port *port = state->uart_port; struct uart_port *port = state->uart_port;
@ -2214,6 +2190,8 @@ static const struct tty_operations uart_ops = {
}; };
static const struct tty_port_operations uart_port_ops = { static const struct tty_port_operations uart_port_ops = {
.activate = uart_port_activate,
.shutdown = uart_port_shutdown,
.carrier_raised = uart_carrier_raised, .carrier_raised = uart_carrier_raised,
.dtr_rts = uart_dtr_rts, .dtr_rts = uart_dtr_rts,
}; };
@ -2275,8 +2253,8 @@ int uart_register_driver(struct uart_driver *drv)
tty_port_init(port); tty_port_init(port);
port->ops = &uart_port_ops; port->ops = &uart_port_ops;
port->close_delay = 500; /* .5 seconds */ port->close_delay = HZ / 2; /* .5 seconds */
port->closing_wait = 30000; /* 30 seconds */ port->closing_wait = 30 * HZ;/* 30 seconds */
} }
retval = tty_register_driver(normal); retval = tty_register_driver(normal);
@ -2467,6 +2445,99 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
} }
EXPORT_SYMBOL(uart_match_port); EXPORT_SYMBOL(uart_match_port);
/**
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
* @status: new carrier detect status, nonzero if active
*/
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
{
struct uart_state *state = uport->state;
struct tty_port *port = &state->port;
struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
struct pps_event_time ts;
if (ld && ld->ops->dcd_change)
pps_get_ts(&ts);
uport->icount.dcd++;
#ifdef CONFIG_HARD_PPS
if ((uport->flags & UPF_HARDPPS_CD) && status)
hardpps();
#endif
if (port->flags & ASYNC_CHECK_CD) {
if (status)
wake_up_interruptible(&port->open_wait);
else if (port->tty)
tty_hangup(port->tty);
}
if (ld && ld->ops->dcd_change)
ld->ops->dcd_change(port->tty, status, &ts);
if (ld)
tty_ldisc_deref(ld);
}
EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
/**
* uart_handle_cts_change - handle a change of clear-to-send state
* @uport: uart_port structure for the open port
* @status: new clear to send status, nonzero if active
*/
void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
{
struct tty_port *port = &uport->state->port;
struct tty_struct *tty = port->tty;
uport->icount.cts++;
if (port->flags & ASYNC_CTS_FLOW) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
uport->ops->start_tx(uport);
uart_write_wakeup(uport);
}
} else {
if (!status) {
tty->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
}
}
}
EXPORT_SYMBOL_GPL(uart_handle_cts_change);
/**
* uart_insert_char - push a char to the uart layer
*
* User is responsible to call tty_flip_buffer_push when they are done with
* insertion.
*
* @port: corresponding port
* @status: state of the serial port RX buffer (LSR for 8250)
* @overrun: mask of overrun bits in @status
* @ch: character to push
* @flag: flag for the character (see TTY_NORMAL and friends)
*/
void uart_insert_char(struct uart_port *port, unsigned int status,
unsigned int overrun, unsigned int ch, unsigned int flag)
{
struct tty_struct *tty = port->state->port.tty;
if ((status & port->ignore_status_mask & ~overrun) == 0)
tty_insert_flip_char(tty, ch, flag);
/*
* Overrun is special. Since it's reported immediately,
* it doesn't affect the current character.
*/
if (status & ~port->ignore_status_mask & overrun)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
EXPORT_SYMBOL_GPL(uart_insert_char);
EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_write_wakeup);
EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_register_driver);
EXPORT_SYMBOL(uart_unregister_driver); EXPORT_SYMBOL(uart_unregister_driver);

View File

@ -317,7 +317,7 @@ static int serial_probe(struct pcmcia_device *link)
info->p_dev = link; info->p_dev = link;
link->priv = info; link->priv = info;
link->config_flags |= CONF_ENABLE_IRQ; link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
if (do_sound) if (do_sound)
link->config_flags |= CONF_ENABLE_SPKR; link->config_flags |= CONF_ENABLE_SPKR;
@ -445,7 +445,7 @@ static int simple_config(struct pcmcia_device *link)
/* First pass: look for a config entry that looks normal. /* First pass: look for a config entry that looks normal.
* Two tries: without IO aliases, then with aliases */ * Two tries: without IO aliases, then with aliases */
link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO; link->config_flags |= CONF_AUTO_SET_VPP;
for (try = 0; try < 4; try++) for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try)) if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port; goto found_port;
@ -501,7 +501,8 @@ static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
{ {
int *base2 = priv_data; int *base2 = priv_data;
if (!p_dev->resource[0]->end || !p_dev->resource[1]->end) if (!p_dev->resource[0]->end || !p_dev->resource[1]->end ||
p_dev->resource[0]->start + 8 != p_dev->resource[1]->start)
return -ENODEV; return -ENODEV;
p_dev->resource[0]->end = p_dev->resource[1]->end = 8; p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
@ -520,7 +521,6 @@ static int multi_config(struct pcmcia_device *link)
struct serial_info *info = link->priv; struct serial_info *info = link->priv;
int i, base2 = 0; int i, base2 = 0;
link->config_flags |= CONF_AUTO_SET_IO;
/* First, look for a generic full-sized window */ /* First, look for a generic full-sized window */
if (!pcmcia_loop_config(link, multi_config_check, &info->multi)) if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
base2 = link->resource[0]->start + 8; base2 = link->resource[0]->start + 8;

View File

@ -0,0 +1,783 @@
/*
* Driver for CSR SiRFprimaII onboard UARTs.
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/sysrq.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <linux/pinctrl/pinmux.h>
#include "sirfsoc_uart.h"
static unsigned int
sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count);
static unsigned int
sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
static struct uart_driver sirfsoc_uart_drv;
static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
{4000000, 2359296},
{3500000, 1310721},
{3000000, 1572865},
{2500000, 1245186},
{2000000, 1572866},
{1500000, 1245188},
{1152000, 1638404},
{1000000, 1572869},
{921600, 1114120},
{576000, 1245196},
{500000, 1245198},
{460800, 1572876},
{230400, 1310750},
{115200, 1310781},
{57600, 1310843},
{38400, 1114328},
{19200, 1114545},
{9600, 1114979},
};
static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
[0] = {
.port = {
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
},
},
[1] = {
.port = {
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
},
},
[2] = {
.port = {
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
},
},
};
static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
{
return container_of(port, struct sirfsoc_uart_port, port);
}
static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
{
unsigned long reg;
reg = rd_regl(port, SIRFUART_TX_FIFO_STATUS);
if (reg & SIRFUART_FIFOEMPTY_MASK(port))
return TIOCSER_TEMT;
else
return 0;
}
static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
if (!(sirfport->ms_enabled)) {
goto cts_asserted;
} else if (sirfport->hw_flow_ctrl) {
if (!(rd_regl(port, SIRFUART_AFC_CTRL) &
SIRFUART_CTS_IN_STATUS))
goto cts_asserted;
else
goto cts_deasserted;
}
cts_deasserted:
return TIOCM_CAR | TIOCM_DSR;
cts_asserted:
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned int assert = mctrl & TIOCM_RTS;
unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
unsigned int current_val;
if (sirfport->hw_flow_ctrl) {
current_val = rd_regl(port, SIRFUART_AFC_CTRL) & ~0xFF;
val |= current_val;
wr_regl(port, SIRFUART_AFC_CTRL, val);
}
}
static void sirfsoc_uart_stop_tx(struct uart_port *port)
{
unsigned int regv;
regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
}
void sirfsoc_uart_start_tx(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long regv;
sirfsoc_uart_pio_tx_chars(sirfport, 1);
wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
}
static void sirfsoc_uart_stop_rx(struct uart_port *port)
{
unsigned long regv;
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
}
static void sirfsoc_uart_disable_ms(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long reg;
sirfport->ms_enabled = 0;
if (!sirfport->hw_flow_ctrl)
return;
reg = rd_regl(port, SIRFUART_AFC_CTRL);
wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
reg = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
}
static void sirfsoc_uart_enable_ms(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long reg;
unsigned long flg;
if (!sirfport->hw_flow_ctrl)
return;
flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
reg = rd_regl(port, SIRFUART_AFC_CTRL);
wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
reg = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
uart_handle_cts_change(port,
!(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
sirfport->ms_enabled = 1;
}
static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
{
unsigned long ulcon = rd_regl(port, SIRFUART_LINE_CTRL);
if (break_state)
ulcon |= SIRFUART_SET_BREAK;
else
ulcon &= ~SIRFUART_SET_BREAK;
wr_regl(port, SIRFUART_LINE_CTRL, ulcon);
}
static unsigned int
sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
{
unsigned int ch, rx_count = 0;
struct tty_struct *tty;
tty = tty_port_tty_get(&port->state->port);
if (!tty)
return -ENODEV;
while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) &
SIRFUART_FIFOEMPTY_MASK(port))) {
ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ;
if (unlikely(uart_handle_sysrq_char(port, ch)))
continue;
uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
rx_count++;
if (rx_count >= max_rx_count)
break;
}
port->icount.rx += rx_count;
tty_flip_buffer_push(tty);
tty_kref_put(tty);
return rx_count;
}
static unsigned int
sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
{
struct uart_port *port = &sirfport->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned int num_tx = 0;
while (!uart_circ_empty(xmit) &&
!(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
SIRFUART_FIFOFULL_MASK(port)) &&
count--) {
wr_regl(port, SIRFUART_TX_FIFO_DATA, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
num_tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
return num_tx;
}
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
unsigned long intr_status;
unsigned long cts_status;
unsigned long flag = TTY_NORMAL;
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
struct uart_port *port = &sirfport->port;
struct uart_state *state = port->state;
struct circ_buf *xmit = &port->state->xmit;
intr_status = rd_regl(port, SIRFUART_INT_STATUS);
wr_regl(port, SIRFUART_INT_STATUS, intr_status);
intr_status &= rd_regl(port, SIRFUART_INT_EN);
if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) {
if (intr_status & SIRFUART_RXD_BREAK) {
if (uart_handle_break(port))
goto recv_char;
uart_insert_char(port, intr_status,
SIRFUART_RX_OFLOW, 0, TTY_BREAK);
return IRQ_HANDLED;
}
if (intr_status & SIRFUART_RX_OFLOW)
port->icount.overrun++;
if (intr_status & SIRFUART_FRM_ERR) {
port->icount.frame++;
flag = TTY_FRAME;
}
if (intr_status & SIRFUART_PARITY_ERR)
flag = TTY_PARITY;
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
intr_status &= port->read_status_mask;
uart_insert_char(port, intr_status,
SIRFUART_RX_OFLOW_INT, 0, flag);
}
recv_char:
if (intr_status & SIRFUART_CTS_INT_EN) {
cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) &
SIRFUART_CTS_IN_STATUS);
if (cts_status != 0) {
uart_handle_cts_change(port, 1);
} else {
uart_handle_cts_change(port, 0);
wake_up_interruptible(&state->port.delta_msr_wait);
}
}
if (intr_status & SIRFUART_RX_IO_INT_EN)
sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
if (intr_status & SIRFUART_TX_INT_EN) {
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
return IRQ_HANDLED;
} else {
sirfsoc_uart_pio_tx_chars(sirfport,
SIRFSOC_UART_IO_TX_REASONABLE_CNT);
if ((uart_circ_empty(xmit)) &&
(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
SIRFUART_FIFOEMPTY_MASK(port)))
sirfsoc_uart_stop_tx(port);
}
}
return IRQ_HANDLED;
}
static void sirfsoc_uart_start_rx(struct uart_port *port)
{
unsigned long regv;
regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
}
static unsigned int
sirfsoc_calc_sample_div(unsigned long baud_rate,
unsigned long ioclk_rate, unsigned long *setted_baud)
{
unsigned long min_delta = ~0UL;
unsigned short sample_div;
unsigned int regv = 0;
unsigned long ioclk_div;
unsigned long baud_tmp;
int temp_delta;
for (sample_div = SIRF_MIN_SAMPLE_DIV;
sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1;
if (ioclk_div > SIRF_IOCLK_DIV_MAX)
continue;
baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1));
temp_delta = baud_tmp - baud_rate;
temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
if (temp_delta < min_delta) {
regv = regv & (~SIRF_IOCLK_DIV_MASK);
regv = regv | ioclk_div;
regv = regv & (~SIRF_SAMPLE_DIV_MASK);
regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
min_delta = temp_delta;
*setted_baud = baud_tmp;
}
}
return regv;
}
static void sirfsoc_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long ioclk_rate;
unsigned long config_reg = 0;
unsigned long baud_rate;
unsigned long setted_baud;
unsigned long flags;
unsigned long ic;
unsigned int clk_div_reg = 0;
unsigned long temp_reg_val;
unsigned long rx_time_out;
int threshold_div;
int temp;
ioclk_rate = 150000000;
switch (termios->c_cflag & CSIZE) {
default:
case CS8:
config_reg |= SIRFUART_DATA_BIT_LEN_8;
break;
case CS7:
config_reg |= SIRFUART_DATA_BIT_LEN_7;
break;
case CS6:
config_reg |= SIRFUART_DATA_BIT_LEN_6;
break;
case CS5:
config_reg |= SIRFUART_DATA_BIT_LEN_5;
break;
}
if (termios->c_cflag & CSTOPB)
config_reg |= SIRFUART_STOP_BIT_LEN_2;
baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
spin_lock_irqsave(&port->lock, flags);
port->read_status_mask = SIRFUART_RX_OFLOW_INT;
port->ignore_status_mask = 0;
/* read flags */
if (termios->c_iflag & INPCK)
port->read_status_mask |=
SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= SIRFUART_RXD_BREAK_INT;
/* ignore flags */
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |=
SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= SIRFUART_DUMMY_READ;
/* enable parity if PARENB is set*/
if (termios->c_cflag & PARENB) {
if (termios->c_cflag & CMSPAR) {
if (termios->c_cflag & PARODD)
config_reg |= SIRFUART_STICK_BIT_MARK;
else
config_reg |= SIRFUART_STICK_BIT_SPACE;
} else if (termios->c_cflag & PARODD) {
config_reg |= SIRFUART_STICK_BIT_ODD;
} else {
config_reg |= SIRFUART_STICK_BIT_EVEN;
}
}
/* Hardware Flow Control Settings */
if (UART_ENABLE_MS(port, termios->c_cflag)) {
if (!sirfport->ms_enabled)
sirfsoc_uart_enable_ms(port);
} else {
if (sirfport->ms_enabled)
sirfsoc_uart_disable_ms(port);
}
/* common rate: fast calculation */
for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
if (baud_rate == baudrate_to_regv[ic].baud_rate)
clk_div_reg = baudrate_to_regv[ic].reg_val;
setted_baud = baud_rate;
/* arbitary rate setting */
if (unlikely(clk_div_reg == 0))
clk_div_reg = sirfsoc_calc_sample_div(baud_rate, ioclk_rate,
&setted_baud);
wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, setted_baud, setted_baud);
/* set receive timeout */
rx_time_out = SIRFSOC_UART_RX_TIMEOUT(baud_rate, 20000);
rx_time_out = (rx_time_out > 0xFFFF) ? 0xFFFF : rx_time_out;
config_reg |= SIRFUART_RECV_TIMEOUT(rx_time_out);
temp_reg_val = rd_regl(port, SIRFUART_TX_FIFO_OP);
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
wr_regl(port, SIRFUART_TX_FIFO_OP,
temp_reg_val & ~SIRFUART_TX_FIFO_START);
wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, SIRFUART_TX_MODE_IO);
wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, SIRFUART_RX_MODE_IO);
wr_regl(port, SIRFUART_LINE_CTRL, config_reg);
/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
if (baud_rate < 1000000)
threshold_div = 1;
else
threshold_div = 2;
temp = port->line == 1 ? 16 : 64;
wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp / threshold_div);
wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp / threshold_div);
temp_reg_val |= SIRFUART_TX_FIFO_START;
wr_regl(port, SIRFUART_TX_FIFO_OP, temp_reg_val);
uart_update_timeout(port, termios->c_cflag, baud_rate);
sirfsoc_uart_start_rx(port);
wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_TX_EN | SIRFUART_RX_EN);
spin_unlock_irqrestore(&port->lock, flags);
}
static void startup_uart_controller(struct uart_port *port)
{
unsigned long temp_regv;
int temp;
temp_regv = rd_regl(port, SIRFUART_TX_DMA_IO_CTRL);
wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, temp_regv | SIRFUART_TX_MODE_IO);
temp_regv = rd_regl(port, SIRFUART_RX_DMA_IO_CTRL);
wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, temp_regv | SIRFUART_RX_MODE_IO);
wr_regl(port, SIRFUART_TX_DMA_IO_LEN, 0);
wr_regl(port, SIRFUART_RX_DMA_IO_LEN, 0);
wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_RX_EN | SIRFUART_TX_EN);
wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_RESET);
wr_regl(port, SIRFUART_TX_FIFO_OP, 0);
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
temp = port->line == 1 ? 16 : 64;
wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp);
wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp);
}
static int sirfsoc_uart_startup(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned int index = port->line;
int ret;
set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
ret = request_irq(port->irq,
sirfsoc_uart_isr,
0,
SIRFUART_PORT_NAME,
sirfport);
if (ret != 0) {
dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
index, port->irq);
goto irq_err;
}
startup_uart_controller(port);
enable_irq(port->irq);
irq_err:
return ret;
}
static void sirfsoc_uart_shutdown(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
wr_regl(port, SIRFUART_INT_EN, 0);
free_irq(port->irq, sirfport);
if (sirfport->ms_enabled) {
sirfsoc_uart_disable_ms(port);
sirfport->ms_enabled = 0;
}
}
static const char *sirfsoc_uart_type(struct uart_port *port)
{
return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL;
}
static int sirfsoc_uart_request_port(struct uart_port *port)
{
void *ret;
ret = request_mem_region(port->mapbase,
SIRFUART_MAP_SIZE, SIRFUART_PORT_NAME);
return ret ? 0 : -EBUSY;
}
static void sirfsoc_uart_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, SIRFUART_MAP_SIZE);
}
static void sirfsoc_uart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = SIRFSOC_PORT_TYPE;
sirfsoc_uart_request_port(port);
}
}
static struct uart_ops sirfsoc_uart_ops = {
.tx_empty = sirfsoc_uart_tx_empty,
.get_mctrl = sirfsoc_uart_get_mctrl,
.set_mctrl = sirfsoc_uart_set_mctrl,
.stop_tx = sirfsoc_uart_stop_tx,
.start_tx = sirfsoc_uart_start_tx,
.stop_rx = sirfsoc_uart_stop_rx,
.enable_ms = sirfsoc_uart_enable_ms,
.break_ctl = sirfsoc_uart_break_ctl,
.startup = sirfsoc_uart_startup,
.shutdown = sirfsoc_uart_shutdown,
.set_termios = sirfsoc_uart_set_termios,
.type = sirfsoc_uart_type,
.release_port = sirfsoc_uart_release_port,
.request_port = sirfsoc_uart_request_port,
.config_port = sirfsoc_uart_config_port,
};
#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
static int __init sirfsoc_uart_console_setup(struct console *co, char *options)
{
unsigned int baud = 115200;
unsigned int bits = 8;
unsigned int parity = 'n';
unsigned int flow = 'n';
struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
return -EINVAL;
if (!port->mapbase)
return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
port->cons = co;
return uart_set_options(port, co, baud, parity, bits, flow);
}
static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
{
while (rd_regl(port,
SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOFULL_MASK(port))
cpu_relax();
wr_regb(port, SIRFUART_TX_FIFO_DATA, ch);
}
static void sirfsoc_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
}
static struct console sirfsoc_uart_console = {
.name = SIRFSOC_UART_NAME,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -1,
.write = sirfsoc_uart_console_write,
.setup = sirfsoc_uart_console_setup,
.data = &sirfsoc_uart_drv,
};
static int __init sirfsoc_uart_console_init(void)
{
register_console(&sirfsoc_uart_console);
return 0;
}
console_initcall(sirfsoc_uart_console_init);
#endif
static struct uart_driver sirfsoc_uart_drv = {
.owner = THIS_MODULE,
.driver_name = SIRFUART_PORT_NAME,
.nr = SIRFSOC_UART_NR,
.dev_name = SIRFSOC_UART_NAME,
.major = SIRFSOC_UART_MAJOR,
.minor = SIRFSOC_UART_MINOR,
#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
.cons = &sirfsoc_uart_console,
#else
.cons = NULL,
#endif
};
int sirfsoc_uart_probe(struct platform_device *pdev)
{
struct sirfsoc_uart_port *sirfport;
struct uart_port *port;
struct resource *res;
int ret;
if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
dev_err(&pdev->dev,
"Unable to find cell-index in uart node.\n");
ret = -EFAULT;
goto err;
}
sirfport = &sirfsoc_uart_ports[pdev->id];
port = &sirfport->port;
port->dev = &pdev->dev;
port->private_data = sirfport;
if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
sirfport->hw_flow_ctrl = 1;
if (of_property_read_u32(pdev->dev.of_node,
"fifosize",
&port->fifosize)) {
dev_err(&pdev->dev,
"Unable to find fifosize in uart node.\n");
ret = -EFAULT;
goto err;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "Insufficient resources.\n");
ret = -EFAULT;
goto err;
}
port->mapbase = res->start;
port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!port->membase) {
dev_err(&pdev->dev, "Cannot remap resource.\n");
ret = -ENOMEM;
goto err;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&pdev->dev, "Insufficient resources.\n");
ret = -EFAULT;
goto irq_err;
}
port->irq = res->start;
if (sirfport->hw_flow_ctrl) {
sirfport->pmx = pinmux_get(&pdev->dev, NULL);
ret = IS_ERR(sirfport->pmx);
if (ret)
goto pmx_err;
pinmux_enable(sirfport->pmx);
}
port->ops = &sirfsoc_uart_ops;
spin_lock_init(&port->lock);
platform_set_drvdata(pdev, sirfport);
ret = uart_add_one_port(&sirfsoc_uart_drv, port);
if (ret != 0) {
dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
goto port_err;
}
return 0;
port_err:
platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl) {
pinmux_disable(sirfport->pmx);
pinmux_put(sirfport->pmx);
}
pmx_err:
irq_err:
devm_iounmap(&pdev->dev, port->membase);
err:
return ret;
}
static int sirfsoc_uart_remove(struct platform_device *pdev)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl) {
pinmux_disable(sirfport->pmx);
pinmux_put(sirfport->pmx);
}
devm_iounmap(&pdev->dev, port->membase);
uart_remove_one_port(&sirfsoc_uart_drv, port);
return 0;
}
static int
sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
uart_suspend_port(&sirfsoc_uart_drv, port);
return 0;
}
static int sirfsoc_uart_resume(struct platform_device *pdev)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
uart_resume_port(&sirfsoc_uart_drv, port);
return 0;
}
static struct of_device_id sirfsoc_uart_ids[] __devinitdata = {
{ .compatible = "sirf,prima2-uart", },
{}
};
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),
.suspend = sirfsoc_uart_suspend,
.resume = sirfsoc_uart_resume,
.driver = {
.name = SIRFUART_PORT_NAME,
.owner = THIS_MODULE,
.of_match_table = sirfsoc_uart_ids,
},
};
static int __init sirfsoc_uart_init(void)
{
int ret = 0;
ret = uart_register_driver(&sirfsoc_uart_drv);
if (ret)
goto out;
ret = platform_driver_register(&sirfsoc_uart_driver);
if (ret)
uart_unregister_driver(&sirfsoc_uart_drv);
out:
return ret;
}
module_init(sirfsoc_uart_init);
static void __exit sirfsoc_uart_exit(void)
{
platform_driver_unregister(&sirfsoc_uart_driver);
uart_unregister_driver(&sirfsoc_uart_drv);
}
module_exit(sirfsoc_uart_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>");
MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver");

View File

@ -0,0 +1,185 @@
/*
* Drivers for CSR SiRFprimaII onboard UARTs.
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/bitops.h>
/* UART Register Offset Define */
#define SIRFUART_LINE_CTRL 0x0040
#define SIRFUART_TX_RX_EN 0x004c
#define SIRFUART_DIVISOR 0x0050
#define SIRFUART_INT_EN 0x0054
#define SIRFUART_INT_STATUS 0x0058
#define SIRFUART_TX_DMA_IO_CTRL 0x0100
#define SIRFUART_TX_DMA_IO_LEN 0x0104
#define SIRFUART_TX_FIFO_CTRL 0x0108
#define SIRFUART_TX_FIFO_LEVEL_CHK 0x010C
#define SIRFUART_TX_FIFO_OP 0x0110
#define SIRFUART_TX_FIFO_STATUS 0x0114
#define SIRFUART_TX_FIFO_DATA 0x0118
#define SIRFUART_RX_DMA_IO_CTRL 0x0120
#define SIRFUART_RX_DMA_IO_LEN 0x0124
#define SIRFUART_RX_FIFO_CTRL 0x0128
#define SIRFUART_RX_FIFO_LEVEL_CHK 0x012C
#define SIRFUART_RX_FIFO_OP 0x0130
#define SIRFUART_RX_FIFO_STATUS 0x0134
#define SIRFUART_RX_FIFO_DATA 0x0138
#define SIRFUART_AFC_CTRL 0x0140
#define SIRFUART_SWH_DMA_IO 0x0148
/* UART Line Control Register */
#define SIRFUART_DATA_BIT_LEN_MASK 0x3
#define SIRFUART_DATA_BIT_LEN_5 BIT(0)
#define SIRFUART_DATA_BIT_LEN_6 1
#define SIRFUART_DATA_BIT_LEN_7 2
#define SIRFUART_DATA_BIT_LEN_8 3
#define SIRFUART_STOP_BIT_LEN_1 0
#define SIRFUART_STOP_BIT_LEN_2 BIT(2)
#define SIRFUART_PARITY_EN BIT(3)
#define SIRFUART_EVEN_BIT BIT(4)
#define SIRFUART_STICK_BIT_MASK (7 << 3)
#define SIRFUART_STICK_BIT_NONE (0 << 3)
#define SIRFUART_STICK_BIT_EVEN BIT(3)
#define SIRFUART_STICK_BIT_ODD (3 << 3)
#define SIRFUART_STICK_BIT_MARK (5 << 3)
#define SIRFUART_STICK_BIT_SPACE (7 << 3)
#define SIRFUART_SET_BREAK BIT(6)
#define SIRFUART_LOOP_BACK BIT(7)
#define SIRFUART_PARITY_MASK (7 << 3)
#define SIRFUART_DUMMY_READ BIT(16)
#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
#define SIRFUART_RECV_TIMEOUT_MASK (0xFFFF << 16)
#define SIRFUART_RECV_TIMEOUT(x) (((x) & 0xFFFF) << 16)
/* UART Auto Flow Control */
#define SIRFUART_AFC_RX_THD_MASK 0x000000FF
#define SIRFUART_AFC_RX_EN BIT(8)
#define SIRFUART_AFC_TX_EN BIT(9)
#define SIRFUART_CTS_CTRL BIT(10)
#define SIRFUART_RTS_CTRL BIT(11)
#define SIRFUART_CTS_IN_STATUS BIT(12)
#define SIRFUART_RTS_OUT_STATUS BIT(13)
/* UART Interrupt Enable Register */
#define SIRFUART_RX_DONE_INT BIT(0)
#define SIRFUART_TX_DONE_INT BIT(1)
#define SIRFUART_RX_OFLOW_INT BIT(2)
#define SIRFUART_TX_ALLOUT_INT BIT(3)
#define SIRFUART_RX_IO_DMA_INT BIT(4)
#define SIRFUART_TX_IO_DMA_INT BIT(5)
#define SIRFUART_RXFIFO_FULL_INT BIT(6)
#define SIRFUART_TXFIFO_EMPTY_INT BIT(7)
#define SIRFUART_RXFIFO_THD_INT BIT(8)
#define SIRFUART_TXFIFO_THD_INT BIT(9)
#define SIRFUART_FRM_ERR_INT BIT(10)
#define SIRFUART_RXD_BREAK_INT BIT(11)
#define SIRFUART_RX_TIMEOUT_INT BIT(12)
#define SIRFUART_PARITY_ERR_INT BIT(13)
#define SIRFUART_CTS_INT_EN BIT(14)
#define SIRFUART_RTS_INT_EN BIT(15)
/* UART Interrupt Status Register */
#define SIRFUART_RX_DONE BIT(0)
#define SIRFUART_TX_DONE BIT(1)
#define SIRFUART_RX_OFLOW BIT(2)
#define SIRFUART_TX_ALL_EMPTY BIT(3)
#define SIRFUART_DMA_IO_RX_DONE BIT(4)
#define SIRFUART_DMA_IO_TX_DONE BIT(5)
#define SIRFUART_RXFIFO_FULL BIT(6)
#define SIRFUART_TXFIFO_EMPTY BIT(7)
#define SIRFUART_RXFIFO_THD_REACH BIT(8)
#define SIRFUART_TXFIFO_THD_REACH BIT(9)
#define SIRFUART_FRM_ERR BIT(10)
#define SIRFUART_RXD_BREAK BIT(11)
#define SIRFUART_RX_TIMEOUT BIT(12)
#define SIRFUART_PARITY_ERR BIT(13)
#define SIRFUART_CTS_CHANGE BIT(14)
#define SIRFUART_RTS_CHANGE BIT(15)
#define SIRFUART_PLUG_IN BIT(16)
#define SIRFUART_ERR_INT_STAT \
(SIRFUART_RX_OFLOW | \
SIRFUART_FRM_ERR | \
SIRFUART_RXD_BREAK | \
SIRFUART_PARITY_ERR)
#define SIRFUART_ERR_INT_EN \
(SIRFUART_RX_OFLOW_INT | \
SIRFUART_FRM_ERR_INT | \
SIRFUART_RXD_BREAK_INT | \
SIRFUART_PARITY_ERR_INT)
#define SIRFUART_TX_INT_EN SIRFUART_TXFIFO_EMPTY_INT
#define SIRFUART_RX_IO_INT_EN \
(SIRFUART_RX_TIMEOUT_INT | \
SIRFUART_RXFIFO_THD_INT | \
SIRFUART_RXFIFO_FULL_INT | \
SIRFUART_ERR_INT_EN)
/* UART FIFO Register */
#define SIRFUART_TX_FIFO_STOP 0x0
#define SIRFUART_TX_FIFO_RESET 0x1
#define SIRFUART_TX_FIFO_START 0x2
#define SIRFUART_RX_FIFO_STOP 0x0
#define SIRFUART_RX_FIFO_RESET 0x1
#define SIRFUART_RX_FIFO_START 0x2
#define SIRFUART_TX_MODE_DMA 0
#define SIRFUART_TX_MODE_IO 1
#define SIRFUART_RX_MODE_DMA 0
#define SIRFUART_RX_MODE_IO 1
#define SIRFUART_RX_EN 0x1
#define SIRFUART_TX_EN 0x2
/* Generic Definitions */
#define SIRFSOC_UART_NAME "ttySiRF"
#define SIRFSOC_UART_MAJOR 0
#define SIRFSOC_UART_MINOR 0
#define SIRFUART_PORT_NAME "sirfsoc-uart"
#define SIRFUART_MAP_SIZE 0x200
#define SIRFSOC_UART_NR 3
#define SIRFSOC_PORT_TYPE 0xa5
/* Baud Rate Calculation */
#define SIRF_MIN_SAMPLE_DIV 0xf
#define SIRF_MAX_SAMPLE_DIV 0x3f
#define SIRF_IOCLK_DIV_MAX 0xffff
#define SIRF_SAMPLE_DIV_SHIFT 16
#define SIRF_IOCLK_DIV_MASK 0xffff
#define SIRF_SAMPLE_DIV_MASK 0x3f0000
#define SIRF_BAUD_RATE_SUPPORT_NR 18
/* For Fast Baud Rate Calculation */
struct sirfsoc_baudrate_to_regv {
unsigned int baud_rate;
unsigned int reg_val;
};
struct sirfsoc_uart_port {
unsigned char hw_flow_ctrl;
unsigned char ms_enabled;
struct uart_port port;
struct pinmux *pmx;
};
/* Hardware Flow Control */
#define SIRFUART_AFC_CTRL_RX_THD 0x70
/* Register Access Control */
#define portaddr(port, reg) ((port)->membase + (reg))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
/* UART Port Mask */
#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f))
#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80))
#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100))
/* I/O Mode */
#define SIRFSOC_UART_IO_RX_MAX_CNT 256
#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 6

View File

@ -513,20 +513,7 @@ static struct platform_driver timbuart_platform_driver = {
.remove = __devexit_p(timbuart_remove), .remove = __devexit_p(timbuart_remove),
}; };
/*--------------------------------------------------------------------------*/ module_platform_driver(timbuart_platform_driver);
static int __init timbuart_init(void)
{
return platform_driver_register(&timbuart_platform_driver);
}
static void __exit timbuart_exit(void)
{
platform_driver_unregister(&timbuart_platform_driver);
}
module_init(timbuart_init);
module_exit(timbuart_exit);
MODULE_DESCRIPTION("Timberdale UART driver"); MODULE_DESCRIPTION("Timberdale UART driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -961,18 +961,7 @@ static struct platform_driver siu_device_driver = {
}, },
}; };
static int __init vr41xx_siu_init(void) module_platform_driver(siu_device_driver);
{
return platform_driver_register(&siu_device_driver);
}
static void __exit vr41xx_siu_exit(void)
{
platform_driver_unregister(&siu_device_driver);
}
module_init(vr41xx_siu_init);
module_exit(vr41xx_siu_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:SIU"); MODULE_ALIAS("platform:SIU");

View File

@ -790,19 +790,24 @@ static void session_clear_tty(struct pid *session)
void disassociate_ctty(int on_exit) void disassociate_ctty(int on_exit)
{ {
struct tty_struct *tty; struct tty_struct *tty;
struct pid *tty_pgrp = NULL;
if (!current->signal->leader) if (!current->signal->leader)
return; return;
tty = get_current_tty(); tty = get_current_tty();
if (tty) { if (tty) {
tty_pgrp = get_pid(tty->pgrp); struct pid *tty_pgrp = get_pid(tty->pgrp);
if (on_exit) { if (on_exit) {
if (tty->driver->type != TTY_DRIVER_TYPE_PTY) if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty); tty_vhangup(tty);
} }
tty_kref_put(tty); tty_kref_put(tty);
if (tty_pgrp) {
kill_pgrp(tty_pgrp, SIGHUP, on_exit);
if (!on_exit)
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
put_pid(tty_pgrp);
}
} else if (on_exit) { } else if (on_exit) {
struct pid *old_pgrp; struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
@ -816,12 +821,6 @@ void disassociate_ctty(int on_exit)
} }
return; return;
} }
if (tty_pgrp) {
kill_pgrp(tty_pgrp, SIGHUP, on_exit);
if (!on_exit)
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
put_pid(tty_pgrp);
}
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
put_pid(current->signal->tty_old_pgrp); put_pid(current->signal->tty_old_pgrp);
@ -1557,6 +1556,59 @@ static void release_tty(struct tty_struct *tty, int idx)
tty_kref_put(tty); tty_kref_put(tty);
} }
/**
* tty_release_checks - check a tty before real release
* @tty: tty to check
* @o_tty: link of @tty (if any)
* @idx: index of the tty
*
* Performs some paranoid checking before true release of the @tty.
* This is a no-op unless TTY_PARANOIA_CHECK is defined.
*/
static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
int idx)
{
#ifdef TTY_PARANOIA_CHECK
if (idx < 0 || idx >= tty->driver->num) {
printk(KERN_DEBUG "%s: bad idx when trying to free (%s)\n",
__func__, tty->name);
return -1;
}
/* not much to check for devpts */
if (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)
return 0;
if (tty != tty->driver->ttys[idx]) {
printk(KERN_DEBUG "%s: driver.table[%d] not tty for (%s)\n",
__func__, idx, tty->name);
return -1;
}
if (tty->termios != tty->driver->termios[idx]) {
printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n",
__func__, idx, tty->name);
return -1;
}
if (tty->driver->other) {
if (o_tty != tty->driver->other->ttys[idx]) {
printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n",
__func__, idx, tty->name);
return -1;
}
if (o_tty->termios != tty->driver->other->termios[idx]) {
printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n",
__func__, idx, tty->name);
return -1;
}
if (o_tty->link != tty) {
printk(KERN_DEBUG "%s: bad pty pointers\n", __func__);
return -1;
}
}
#endif
return 0;
}
/** /**
* tty_release - vfs callback for close * tty_release - vfs callback for close
* @inode: inode of tty * @inode: inode of tty
@ -1585,11 +1637,11 @@ int tty_release(struct inode *inode, struct file *filp)
int idx; int idx;
char buf[64]; char buf[64];
if (tty_paranoia_check(tty, inode, "tty_release_dev")) if (tty_paranoia_check(tty, inode, __func__))
return 0; return 0;
tty_lock(); tty_lock();
check_tty_count(tty, "tty_release_dev"); check_tty_count(tty, __func__);
__tty_fasync(-1, filp, 0); __tty_fasync(-1, filp, 0);
@ -1599,59 +1651,16 @@ int tty_release(struct inode *inode, struct file *filp)
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
o_tty = tty->link; o_tty = tty->link;
#ifdef TTY_PARANOIA_CHECK if (tty_release_checks(tty, o_tty, idx)) {
if (idx < 0 || idx >= tty->driver->num) {
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
"free (%s)\n", tty->name);
tty_unlock(); tty_unlock();
return 0; return 0;
} }
if (!devpts) {
if (tty != tty->driver->ttys[idx]) {
tty_unlock();
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
"for (%s)\n", idx, tty->name);
return 0;
}
if (tty->termios != tty->driver->termios[idx]) {
tty_unlock();
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
"for (%s)\n",
idx, tty->name);
return 0;
}
}
#endif
#ifdef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...", printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__,
tty_name(tty, buf), tty->count); tty_name(tty, buf), tty->count);
#endif #endif
#ifdef TTY_PARANOIA_CHECK
if (tty->driver->other &&
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (o_tty != tty->driver->other->ttys[idx]) {
tty_unlock();
printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
"not o_tty for (%s)\n",
idx, tty->name);
return 0 ;
}
if (o_tty->termios != tty->driver->other->termios[idx]) {
tty_unlock();
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
"not o_termios for (%s)\n",
idx, tty->name);
return 0;
}
if (o_tty->link != tty) {
tty_unlock();
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
return 0;
}
}
#endif
if (tty->ops->close) if (tty->ops->close)
tty->ops->close(tty, filp); tty->ops->close(tty, filp);
@ -1707,8 +1716,8 @@ int tty_release(struct inode *inode, struct file *filp)
if (!do_sleep) if (!do_sleep)
break; break;
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
"active!\n", tty_name(tty, buf)); __func__, tty_name(tty, buf));
tty_unlock(); tty_unlock();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
schedule(); schedule();
@ -1721,15 +1730,14 @@ int tty_release(struct inode *inode, struct file *filp)
*/ */
if (pty_master) { if (pty_master) {
if (--o_tty->count < 0) { if (--o_tty->count < 0) {
printk(KERN_WARNING "tty_release_dev: bad pty slave count " printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
"(%d) for %s\n", __func__, o_tty->count, tty_name(o_tty, buf));
o_tty->count, tty_name(o_tty, buf));
o_tty->count = 0; o_tty->count = 0;
} }
} }
if (--tty->count < 0) { if (--tty->count < 0) {
printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n", printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
tty->count, tty_name(tty, buf)); __func__, tty->count, tty_name(tty, buf));
tty->count = 0; tty->count = 0;
} }
@ -1778,7 +1786,7 @@ int tty_release(struct inode *inode, struct file *filp)
} }
#ifdef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "freeing tty structure..."); printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
#endif #endif
/* /*
* Ask the line discipline code to release its structures * Ask the line discipline code to release its structures
@ -1797,6 +1805,83 @@ int tty_release(struct inode *inode, struct file *filp)
return 0; return 0;
} }
/**
* tty_open_current_tty - get tty of current task for open
* @device: device number
* @filp: file pointer to tty
* @return: tty of the current task iff @device is /dev/tty
*
* We cannot return driver and index like for the other nodes because
* devpts will not work then. It expects inodes to be from devpts FS.
*/
static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
{
struct tty_struct *tty;
if (device != MKDEV(TTYAUX_MAJOR, 0))
return NULL;
tty = get_current_tty();
if (!tty)
return ERR_PTR(-ENXIO);
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */
tty_kref_put(tty);
/* FIXME: we put a reference and return a TTY! */
return tty;
}
/**
* tty_lookup_driver - lookup a tty driver for a given device file
* @device: device number
* @filp: file pointer to tty
* @noctty: set if the device should not become a controlling tty
* @index: index for the device in the @return driver
* @return: driver for this inode (with increased refcount)
*
* If @return is not erroneous, the caller is responsible to decrement the
* refcount by tty_driver_kref_put.
*
* Locking: tty_mutex protects get_tty_driver
*/
static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
int *noctty, int *index)
{
struct tty_driver *driver;
switch (device) {
#ifdef CONFIG_VT
case MKDEV(TTY_MAJOR, 0): {
extern struct tty_driver *console_driver;
driver = tty_driver_kref_get(console_driver);
*index = fg_console;
*noctty = 1;
break;
}
#endif
case MKDEV(TTYAUX_MAJOR, 1): {
struct tty_driver *console_driver = console_device(index);
if (console_driver) {
driver = tty_driver_kref_get(console_driver);
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
*noctty = 1;
break;
}
}
return ERR_PTR(-ENODEV);
}
default:
driver = get_tty_driver(device, index);
if (!driver)
return ERR_PTR(-ENODEV);
break;
}
return driver;
}
/** /**
* tty_open - open a tty device * tty_open - open a tty device
* @inode: inode of device file * @inode: inode of device file
@ -1813,16 +1898,16 @@ int tty_release(struct inode *inode, struct file *filp)
* The termios state of a pty is reset on first open so that * The termios state of a pty is reset on first open so that
* settings don't persist across reuse. * settings don't persist across reuse.
* *
* Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work. * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
* tty->count should protect the rest. * tty->count should protect the rest.
* ->siglock protects ->signal/->sighand * ->siglock protects ->signal/->sighand
*/ */
static int tty_open(struct inode *inode, struct file *filp) static int tty_open(struct inode *inode, struct file *filp)
{ {
struct tty_struct *tty = NULL; struct tty_struct *tty;
int noctty, retval; int noctty, retval;
struct tty_driver *driver; struct tty_driver *driver = NULL;
int index; int index;
dev_t device = inode->i_rdev; dev_t device = inode->i_rdev;
unsigned saved_flags = filp->f_flags; unsigned saved_flags = filp->f_flags;
@ -1841,66 +1926,22 @@ retry_open:
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
tty_lock(); tty_lock();
if (device == MKDEV(TTYAUX_MAJOR, 0)) { tty = tty_open_current_tty(device, filp);
tty = get_current_tty(); if (IS_ERR(tty)) {
if (!tty) { retval = PTR_ERR(tty);
tty_unlock(); goto err_unlock;
mutex_unlock(&tty_mutex); } else if (!tty) {
tty_free_file(filp); driver = tty_lookup_driver(device, filp, &noctty, &index);
return -ENXIO; if (IS_ERR(driver)) {
} retval = PTR_ERR(driver);
driver = tty_driver_kref_get(tty->driver); goto err_unlock;
index = tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */
/* FIXME: Should we take a driver reference ? */
tty_kref_put(tty);
goto got_driver;
}
#ifdef CONFIG_VT
if (device == MKDEV(TTY_MAJOR, 0)) {
extern struct tty_driver *console_driver;
driver = tty_driver_kref_get(console_driver);
index = fg_console;
noctty = 1;
goto got_driver;
}
#endif
if (device == MKDEV(TTYAUX_MAJOR, 1)) {
struct tty_driver *console_driver = console_device(&index);
if (console_driver) {
driver = tty_driver_kref_get(console_driver);
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
noctty = 1;
goto got_driver;
}
}
tty_unlock();
mutex_unlock(&tty_mutex);
tty_free_file(filp);
return -ENODEV;
} }
driver = get_tty_driver(device, &index);
if (!driver) {
tty_unlock();
mutex_unlock(&tty_mutex);
tty_free_file(filp);
return -ENODEV;
}
got_driver:
if (!tty) {
/* check whether we're reopening an existing tty */ /* check whether we're reopening an existing tty */
tty = tty_driver_lookup_tty(driver, inode, index); tty = tty_driver_lookup_tty(driver, inode, index);
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
tty_unlock(); retval = PTR_ERR(tty);
mutex_unlock(&tty_mutex); goto err_unlock;
tty_driver_kref_put(driver);
tty_free_file(filp);
return PTR_ERR(tty);
} }
} }
@ -1912,21 +1953,22 @@ got_driver:
tty = tty_init_dev(driver, index, 0); tty = tty_init_dev(driver, index, 0);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
if (driver)
tty_driver_kref_put(driver); tty_driver_kref_put(driver);
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
tty_unlock(); tty_unlock();
tty_free_file(filp); retval = PTR_ERR(tty);
return PTR_ERR(tty); goto err_file;
} }
tty_add_file(tty, filp); tty_add_file(tty, filp);
check_tty_count(tty, "tty_open"); check_tty_count(tty, __func__);
if (tty->driver->type == TTY_DRIVER_TYPE_PTY && if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER) tty->driver->subtype == PTY_TYPE_MASTER)
noctty = 1; noctty = 1;
#ifdef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "opening %s...", tty->name); printk(KERN_DEBUG "%s: opening %s...\n", __func__, tty->name);
#endif #endif
if (tty->ops->open) if (tty->ops->open)
retval = tty->ops->open(tty, filp); retval = tty->ops->open(tty, filp);
@ -1940,8 +1982,8 @@ got_driver:
if (retval) { if (retval) {
#ifdef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "error %d in opening %s...", retval, printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
tty->name); retval, tty->name);
#endif #endif
tty_unlock(); /* need to call tty_release without BTM */ tty_unlock(); /* need to call tty_release without BTM */
tty_release(inode, filp); tty_release(inode, filp);
@ -1976,6 +2018,15 @@ got_driver:
tty_unlock(); tty_unlock();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return 0; return 0;
err_unlock:
tty_unlock();
mutex_unlock(&tty_mutex);
/* after locks to avoid deadlock */
if (!IS_ERR_OR_NULL(driver))
tty_driver_kref_put(driver);
err_file:
tty_free_file(filp);
return retval;
} }

View File

@ -1,19 +1,11 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/major.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/signal.h> #include <linux/kmod.h>
#include <linux/fcntl.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_driver.h> #include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/kd.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -24,18 +16,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/system.h>
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/kmod.h>
#include <linux/nsproxy.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
/* /*
@ -558,8 +540,6 @@ static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
long ret; long ret;
ret = wait_event_timeout(tty_ldisc_idle, ret = wait_event_timeout(tty_ldisc_idle,
atomic_read(&tty->ldisc->users) == 1, timeout); atomic_read(&tty->ldisc->users) == 1, timeout);
if (ret < 0)
return ret;
return ret > 0 ? 0 : -EBUSY; return ret > 0 ? 0 : -EBUSY;
} }

View File

@ -584,7 +584,7 @@ int con_set_default_unimap(struct vc_data *vc)
return 0; return 0;
dflt->refcount++; dflt->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)dflt; *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
if (p && --p->refcount) { if (p && !--p->refcount) {
con_release_unimap(p); con_release_unimap(p);
kfree(p); kfree(p);
} }

View File

@ -66,6 +66,7 @@ enum {
* dependent on the 8250 driver. * dependent on the 8250 driver.
*/ */
struct uart_port; struct uart_port;
struct uart_8250_port;
int serial8250_register_port(struct uart_port *); int serial8250_register_port(struct uart_port *);
void serial8250_unregister_port(int line); void serial8250_unregister_port(int line);
@ -81,7 +82,11 @@ extern void serial8250_do_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old); struct ktermios *termios, struct ktermios *old);
extern void serial8250_do_pm(struct uart_port *port, unsigned int state, extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate); unsigned int oldstate);
extern int fsl8250_handle_irq(struct uart_port *port);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir); int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
void serial8250_tx_chars(struct uart_8250_port *up);
unsigned int serial8250_modem_status(struct uart_8250_port *up);
extern void serial8250_set_isa_configurator(void (*v) extern void serial8250_set_isa_configurator(void (*v)
(int port, struct uart_port *up, (int port, struct uart_port *up,

View File

@ -351,6 +351,7 @@ struct uart_port {
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
#define UPF_EXAR_EFR ((__force upf_t) (1 << 25)) #define UPF_EXAR_EFR ((__force upf_t) (1 << 25))
#define UPF_IIR_ONCE ((__force upf_t) (1 << 26))
/* The exact UART type is known and should not be probed. */ /* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
@ -483,10 +484,19 @@ static inline int uart_tx_stopped(struct uart_port *port)
/* /*
* The following are helper functions for the low level drivers. * The following are helper functions for the low level drivers.
*/ */
extern void uart_handle_dcd_change(struct uart_port *uport,
unsigned int status);
extern void uart_handle_cts_change(struct uart_port *uport,
unsigned int status);
extern void uart_insert_char(struct uart_port *port, unsigned int status,
unsigned int overrun, unsigned int ch, unsigned int flag);
#ifdef SUPPORT_SYSRQ
static inline int static inline int
uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
{ {
#ifdef SUPPORT_SYSRQ
if (port->sysrq) { if (port->sysrq) {
if (ch && time_before(jiffies, port->sysrq)) { if (ch && time_before(jiffies, port->sysrq)) {
handle_sysrq(ch); handle_sysrq(ch);
@ -495,11 +505,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
} }
port->sysrq = 0; port->sysrq = 0;
} }
#endif
return 0; return 0;
} }
#ifndef SUPPORT_SYSRQ #else
#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0) #define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
#endif #endif
/* /*
@ -522,89 +531,6 @@ static inline int uart_handle_break(struct uart_port *port)
return 0; return 0;
} }
/**
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
* @status: new carrier detect status, nonzero if active
*/
static inline void
uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
{
struct uart_state *state = uport->state;
struct tty_port *port = &state->port;
struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
struct pps_event_time ts;
if (ld && ld->ops->dcd_change)
pps_get_ts(&ts);
uport->icount.dcd++;
#ifdef CONFIG_HARD_PPS
if ((uport->flags & UPF_HARDPPS_CD) && status)
hardpps();
#endif
if (port->flags & ASYNC_CHECK_CD) {
if (status)
wake_up_interruptible(&port->open_wait);
else if (port->tty)
tty_hangup(port->tty);
}
if (ld && ld->ops->dcd_change)
ld->ops->dcd_change(port->tty, status, &ts);
if (ld)
tty_ldisc_deref(ld);
}
/**
* uart_handle_cts_change - handle a change of clear-to-send state
* @uport: uart_port structure for the open port
* @status: new clear to send status, nonzero if active
*/
static inline void
uart_handle_cts_change(struct uart_port *uport, unsigned int status)
{
struct tty_port *port = &uport->state->port;
struct tty_struct *tty = port->tty;
uport->icount.cts++;
if (port->flags & ASYNC_CTS_FLOW) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
uport->ops->start_tx(uport);
uart_write_wakeup(uport);
}
} else {
if (!status) {
tty->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
}
}
}
#include <linux/tty_flip.h>
static inline void
uart_insert_char(struct uart_port *port, unsigned int status,
unsigned int overrun, unsigned int ch, unsigned int flag)
{
struct tty_struct *tty = port->state->port.tty;
if ((status & port->ignore_status_mask & ~overrun) == 0)
tty_insert_flip_char(tty, ch, flag);
/*
* Overrun is special. Since it's reported immediately,
* it doesn't affect the current character.
*/
if (status & ~port->ignore_status_mask & overrun)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
/* /*
* UART_ENABLE_MS - determine if port should enable modem status irqs * UART_ENABLE_MS - determine if port should enable modem status irqs
*/ */