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:
commit
5983faf942
|
@ -101,7 +101,7 @@ hardware.
|
|||
Returns the current state of modem control inputs. The state
|
||||
of the outputs should not be returned, since the core keeps
|
||||
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_DSR state of DSR signal
|
||||
- TIOCM_RI state of RI signal
|
||||
|
|
|
@ -441,6 +441,9 @@ static void __init fixup_port_irq(int index,
|
|||
return;
|
||||
|
||||
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,
|
||||
|
|
|
@ -67,7 +67,7 @@ extern struct console early_mrst_console;
|
|||
extern void mrst_early_console_init(void);
|
||||
|
||||
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_destroy(void);
|
||||
|
|
|
@ -247,7 +247,7 @@ static int __init setup_early_printk(char *buf)
|
|||
}
|
||||
|
||||
if (!strncmp(buf, "hsu", 3)) {
|
||||
hsu_early_console_init();
|
||||
hsu_early_console_init(buf + 3);
|
||||
early_console_register(&early_hsu_console, keep);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -245,16 +245,24 @@ struct console early_mrst_console = {
|
|||
* Following is the early console based on Medfield HSU (High
|
||||
* Speed UART) device.
|
||||
*/
|
||||
#define HSU_PORT2_PADDR 0xffa28180
|
||||
#define HSU_PORT_BASE 0xffa28080
|
||||
|
||||
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;
|
||||
|
||||
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 */
|
||||
writeb(0x0, phsu + UART_FCR);
|
||||
|
|
|
@ -420,18 +420,7 @@ static struct platform_driver axdrv = {
|
|||
.resume = parport_ax88796_resume,
|
||||
};
|
||||
|
||||
static int __init parport_ax88796_init(void)
|
||||
{
|
||||
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_platform_driver(axdrv);
|
||||
|
||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
|
||||
MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
|
||||
|
|
|
@ -391,21 +391,10 @@ static struct platform_driver bpp_sbus_driver = {
|
|||
.remove = __devexit_p(bpp_remove),
|
||||
};
|
||||
|
||||
static int __init parport_sunbpp_init(void)
|
||||
{
|
||||
return platform_driver_register(&bpp_sbus_driver);
|
||||
}
|
||||
|
||||
static void __exit parport_sunbpp_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bpp_sbus_driver);
|
||||
}
|
||||
module_platform_driver(bpp_sbus_driver);
|
||||
|
||||
MODULE_AUTHOR("Derrick J Brashear");
|
||||
MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
|
||||
MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
|
||||
MODULE_VERSION("2.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(parport_sunbpp_init)
|
||||
module_exit(parport_sunbpp_exit)
|
||||
|
|
|
@ -417,7 +417,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
|
|||
__FILE__,__LINE__,tbuf,tbuf->count);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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)
|
||||
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
|
||||
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
|
||||
/* Clear the re-entry flag */
|
||||
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;
|
||||
|
||||
if (tty != n_hdlc->tty) {
|
||||
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
|
||||
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -446,19 +446,8 @@ static inline void legacy_pty_init(void) { }
|
|||
int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
||||
static int pty_limit_min;
|
||||
static int pty_limit_max = NR_UNIX98_PTY_MAX;
|
||||
static int tty_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 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->count++;
|
||||
pty_inc_count(); /* tty */
|
||||
pty_inc_count(); /* tty->link */
|
||||
pty_count++;
|
||||
return 0;
|
||||
err_free_mem:
|
||||
deinitialize_tty_struct(o_tty);
|
||||
|
@ -613,15 +601,19 @@ err_free_tty:
|
|||
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 = {
|
||||
.lookup = ptm_unix98_lookup,
|
||||
.install = pty_unix98_install,
|
||||
.remove = pty_unix98_remove,
|
||||
.remove = ptm_unix98_remove,
|
||||
.open = pty_open,
|
||||
.close = pty_close,
|
||||
.write = pty_write,
|
||||
|
@ -638,7 +630,7 @@ static const struct tty_operations ptm_unix98_ops = {
|
|||
static const struct tty_operations pty_unix98_ops = {
|
||||
.lookup = pts_unix98_lookup,
|
||||
.install = pty_unix98_install,
|
||||
.remove = pty_unix98_remove,
|
||||
.remove = pts_unix98_remove,
|
||||
.open = pty_open,
|
||||
.close = pty_close,
|
||||
.write = pty_write,
|
||||
|
|
|
@ -129,32 +129,6 @@ static unsigned long probe_rsa[PORT_RSA_MAX];
|
|||
static unsigned int probe_rsa_count;
|
||||
#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 hlist_node node;
|
||||
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)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
|
@ -1344,7 +1316,7 @@ static void serial8250_start_tx(struct uart_port *port)
|
|||
if ((up->port.type == PORT_RM9000) ?
|
||||
(lsr & UART_LSR_THRE) :
|
||||
(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);
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned char ch, lsr = *status;
|
||||
unsigned char ch;
|
||||
int max_count = 256;
|
||||
char flag;
|
||||
|
||||
|
@ -1481,10 +1458,11 @@ ignore_char:
|
|||
spin_unlock(&up->port.lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
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;
|
||||
int count;
|
||||
|
@ -1521,8 +1499,9 @@ static void transmit_chars(struct uart_8250_port *up)
|
|||
if (uart_circ_empty(xmit))
|
||||
__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);
|
||||
|
||||
|
@ -1544,14 +1523,20 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
|
|||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_modem_status);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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);
|
||||
|
||||
|
@ -1560,26 +1545,14 @@ static void serial8250_handle_port(struct uart_8250_port *up)
|
|||
DEBUG_INTR("status = %x...", status);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI))
|
||||
receive_chars(up, &status);
|
||||
check_modem_status(up);
|
||||
status = serial8250_rx_chars(up, status);
|
||||
serial8250_modem_status(up);
|
||||
if (status & UART_LSR_THRE)
|
||||
transmit_chars(up);
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
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 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_handle_irq);
|
||||
|
||||
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 {
|
||||
struct uart_8250_port *up;
|
||||
struct uart_port *port;
|
||||
bool skip;
|
||||
|
||||
up = list_entry(l, struct uart_8250_port, list);
|
||||
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;
|
||||
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)
|
||||
{
|
||||
struct uart_8250_port *up = (struct uart_8250_port *)data;
|
||||
unsigned int iir;
|
||||
|
||||
iir = serial_in(up, UART_IIR);
|
||||
if (!(iir & UART_IIR_NO_INT))
|
||||
serial8250_handle_port(up);
|
||||
up->port.handle_irq(&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))
|
||||
transmit_chars(up);
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
if (is_real_interrupt(up->port.irq))
|
||||
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 ret;
|
||||
|
||||
status = check_modem_status(up);
|
||||
status = serial8250_modem_status(up);
|
||||
|
||||
ret = 0;
|
||||
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_LCR, 0);
|
||||
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_LCR, 0);
|
||||
}
|
||||
|
@ -2848,7 +2820,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
|||
|
||||
local_irq_save(flags);
|
||||
if (up->port.sysrq) {
|
||||
/* serial8250_handle_port() already took the lock */
|
||||
/* serial8250_handle_irq() already took the lock */
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
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.
|
||||
*/
|
||||
if (up->msr_saved_flags)
|
||||
check_modem_status(up);
|
||||
serial8250_modem_status(up);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&up->port.lock);
|
||||
|
|
|
@ -13,6 +13,32 @@
|
|||
|
||||
#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 {
|
||||
unsigned int uart;
|
||||
unsigned int baud_base;
|
||||
|
|
|
@ -177,17 +177,7 @@ static struct platform_driver dw8250_platform_driver = {
|
|||
.remove = __devexit_p(dw8250_remove),
|
||||
};
|
||||
|
||||
static int __init dw8250_init(void)
|
||||
{
|
||||
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_platform_driver(dw8250_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Jamie Iles");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -1092,6 +1092,14 @@ static int skip_tx_en_setup(struct serial_private *priv,
|
|||
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)
|
||||
{
|
||||
#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);
|
||||
}
|
||||
|
||||
/* 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_SUBVENDOR_ID_SBSMODULARIO 0x124B
|
||||
#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_200EI 0xA016
|
||||
#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 PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
|
||||
#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 */
|
||||
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
|
||||
|
@ -1220,6 +1244,15 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.subdevice = PCI_ANY_ID,
|
||||
.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
|
||||
*/
|
||||
|
@ -3414,6 +3447,18 @@ static struct pci_device_id serial_pci_tbl[] = {
|
|||
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
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_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
|
|
|
@ -97,6 +97,11 @@ config SERIAL_8250_PNP
|
|||
This builds standard PNP serial support. You may be able to
|
||||
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
|
||||
tristate
|
||||
depends on SERIAL_8250 && HP300
|
||||
|
@ -535,6 +540,27 @@ config SERIAL_S5PV210
|
|||
help
|
||||
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
|
||||
tristate "MAX3100 support"
|
||||
|
@ -1324,7 +1350,7 @@ config SERIAL_OF_PLATFORM
|
|||
|
||||
config SERIAL_OMAP
|
||||
tristate "OMAP serial port support"
|
||||
depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
|
||||
depends on ARCH_OMAP2PLUS
|
||||
select SERIAL_CORE
|
||||
help
|
||||
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 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
|
||||
bool "Enable tty device interface for some SMD ports"
|
||||
default n
|
||||
|
|
|
@ -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_HUB6) += 8250_hub6.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_AMBA_PL010) += amba-pl010.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_LANTIQ) += lantiq.o
|
||||
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
|
||||
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
|
||||
|
|
|
@ -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);
|
||||
unsigned int mode;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Disable interrupts */
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
int line = port->line;
|
||||
|
||||
if (line >= port->state->port.tty->driver->num)
|
||||
return;
|
||||
|
||||
if (port->state->port.tty->ldisc->ops->num == N_PPS) {
|
||||
if (new == N_PPS) {
|
||||
port->flags |= UPF_HARDPPS_CD;
|
||||
atmel_enable_ms(port);
|
||||
} else {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -445,6 +450,8 @@ static void sport_shutdown(struct uart_port *port)
|
|||
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
|
||||
if (up->cts_pin >= 0)
|
||||
free_irq(gpio_to_irq(up->cts_pin), up);
|
||||
if (up->rts_pin >= 0)
|
||||
gpio_free(up->rts_pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -803,17 +810,16 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
|
|||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL)
|
||||
sport->cts_pin = -1;
|
||||
else
|
||||
else {
|
||||
sport->cts_pin = res->start;
|
||||
sport->port.flags |= ASYNC_CTS_FLOW;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 1);
|
||||
if (res == NULL)
|
||||
sport->rts_pin = -1;
|
||||
else
|
||||
sport->rts_pin = res->start;
|
||||
|
||||
if (sport->rts_pin >= 0)
|
||||
gpio_request(sport->rts_pin, DRV_NAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -853,10 +859,6 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
|
|||
|
||||
if (sport) {
|
||||
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);
|
||||
peripheral_free_list(
|
||||
(unsigned short *)pdev->dev.platform_data);
|
||||
|
|
|
@ -45,11 +45,12 @@
|
|||
#define SPORT_GET_RX32(sport) \
|
||||
({ \
|
||||
unsigned int __ret; \
|
||||
unsigned long flags; \
|
||||
if (ANOMALY_05000473) \
|
||||
local_irq_disable(); \
|
||||
local_irq_save(flags); \
|
||||
__ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
|
||||
if (ANOMALY_05000473) \
|
||||
local_irq_enable(); \
|
||||
local_irq_restore(flags); \
|
||||
__ret; \
|
||||
})
|
||||
#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
struct bfin_serial_port *uart = dev_id;
|
||||
unsigned int status;
|
||||
|
||||
status = bfin_serial_get_mctrl(&uart->port);
|
||||
uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
|
||||
unsigned int status = bfin_serial_get_mctrl(&uart->port);
|
||||
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
uart->scts = 1;
|
||||
struct tty_struct *tty = uart->port.state->port.tty;
|
||||
|
||||
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
|
||||
uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
|
||||
|
||||
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 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
|
||||
* 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;
|
||||
|
||||
#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);
|
||||
if (UART_GET_LSR(uart) & THRE)
|
||||
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 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);
|
||||
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
|
||||
bfin_serial_mctrl_cts_int,
|
||||
0, "BFIN_UART_MODEM_STATUS", uart)) {
|
||||
if (uart->cts_pin >= 0) {
|
||||
if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
|
||||
IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
|
||||
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. */
|
||||
UART_PUT_MCR(uart, ACTS);
|
||||
UART_SET_IER(uart, EDSSI);
|
||||
}
|
||||
#endif
|
||||
|
||||
UART_SET_IER(uart, ERBFI);
|
||||
|
@ -792,6 +785,8 @@ static void bfin_serial_shutdown(struct uart_port *port)
|
|||
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
|
||||
if (uart->cts_pin >= 0)
|
||||
free_irq(gpio_to_irq(uart->cts_pin), uart);
|
||||
if (uart->rts_pin >= 0)
|
||||
gpio_free(uart->rts_pin);
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
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);
|
||||
if (res == NULL)
|
||||
uart->cts_pin = -1;
|
||||
else
|
||||
else {
|
||||
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);
|
||||
if (res == NULL)
|
||||
uart->rts_pin = -1;
|
||||
else
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -1421,10 +1416,6 @@ static int __devexit bfin_serial_remove(struct platform_device *pdev)
|
|||
|
||||
if (uart) {
|
||||
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);
|
||||
peripheral_free_list(
|
||||
(unsigned short *)pdev->dev.platform_data);
|
||||
|
|
|
@ -1334,7 +1334,6 @@ MODULE_DEVICE_TABLE(spi, ifx_id_table);
|
|||
static const struct spi_driver ifx_spi_driver = {
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.bus = &spi_bus_type,
|
||||
.pm = &ifx_spi_pm,
|
||||
.owner = THIS_MODULE},
|
||||
.probe = ifx_spi_spi_probe,
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
#define UCR2_STPB (1<<6) /* Stop */
|
||||
#define UCR2_WS (1<<5) /* Word size */
|
||||
#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_RXEN (1<<1) /* Receiver enabled */
|
||||
#define UCR2_SRST (1<<0) /* SW reset */
|
||||
|
@ -207,6 +208,12 @@ struct imx_port {
|
|||
struct imx_uart_data *devdata;
|
||||
};
|
||||
|
||||
struct imx_port_ucrs {
|
||||
unsigned int ucr1;
|
||||
unsigned int ucr2;
|
||||
unsigned int ucr3;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IRDA
|
||||
#define USE_IRDA(sport) ((sport)->use_irda)
|
||||
#else
|
||||
|
@ -259,6 +266,27 @@ static inline int is_imx21_uart(struct imx_port *sport)
|
|||
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.
|
||||
*/
|
||||
|
@ -566,6 +594,9 @@ static irqreturn_t imx_int(int irq, void *dev_id)
|
|||
if (sts & USR1_RTSD)
|
||||
imx_rtsint(irq, dev_id);
|
||||
|
||||
if (sts & USR1_AWAKE)
|
||||
writel(USR1_AWAKE, sport->port.membase + USR1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -901,6 +932,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
ucr2 |= UCR2_PROE;
|
||||
}
|
||||
|
||||
del_timer_sync(&sport->timer);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
del_timer_sync(&sport->timer);
|
||||
|
||||
/*
|
||||
* Update the per-port timeout.
|
||||
*/
|
||||
|
@ -1079,6 +1110,70 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
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 = {
|
||||
.tx_empty = imx_tx_empty,
|
||||
.set_mctrl = imx_set_mctrl,
|
||||
|
@ -1096,6 +1191,10 @@ static struct uart_ops imx_pops = {
|
|||
.request_port = imx_request_port,
|
||||
.config_port = imx_config_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];
|
||||
|
@ -1118,13 +1217,14 @@ static void
|
|||
imx_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
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);
|
||||
old_ucr2 = readl(sport->port.membase + UCR2);
|
||||
imx_port_ucrs_save(&sport->port, &old_ucr);
|
||||
ucr1 = old_ucr.ucr1;
|
||||
|
||||
if (is_imx1_uart(sport))
|
||||
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(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);
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore UCR1/2
|
||||
* and restore UCR1/2/3
|
||||
*/
|
||||
while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
|
||||
|
||||
writel(old_ucr1, sport->port.membase + UCR1);
|
||||
writel(old_ucr2, sport->port.membase + UCR2);
|
||||
imx_port_ucrs_restore(&sport->port, &old_ucr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1269,6 +1368,12 @@ static struct uart_driver imx_reg = {
|
|||
static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
uart_resume_port(&imx_reg, &sport->port);
|
||||
|
@ -1287,6 +1398,10 @@ static int serial_imx_resume(struct platform_device *dev)
|
|||
}
|
||||
|
||||
#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,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
|
@ -1296,12 +1411,13 @@ static int serial_imx_probe_dt(struct imx_port *sport,
|
|||
int ret;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
/* no device tree device */
|
||||
return 1;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
|
||||
return -ENODEV;
|
||||
return 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,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return -ENODEV;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1354,8 +1470,10 @@ static int serial_imx_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
ret = serial_imx_probe_dt(sport, pdev);
|
||||
if (ret == -ENODEV)
|
||||
if (ret > 0)
|
||||
serial_imx_probe_pdata(sport, pdev);
|
||||
else if (ret < 0)
|
||||
goto free;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
|
@ -1476,7 +1594,7 @@ static int __init imx_serial_init(void)
|
|||
if (ret != 0)
|
||||
uart_unregister_driver(&imx_reg);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit imx_serial_exit(void)
|
||||
|
|
|
@ -1000,11 +1000,8 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
|
|||
init_timer(&up->timer);
|
||||
up->timer.function = m32r_sio_timeout;
|
||||
|
||||
/*
|
||||
* ALPHA_KLUDGE_MCR needs to be killed.
|
||||
*/
|
||||
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
|
||||
up->mcr_force = ALPHA_KLUDGE_MCR;
|
||||
up->mcr_mask = ~0;
|
||||
up->mcr_force = 0;
|
||||
|
||||
uart_add_one_port(drv, &up->port);
|
||||
}
|
||||
|
|
|
@ -901,7 +901,6 @@ static int max3100_resume(struct spi_device *spi)
|
|||
static struct spi_driver max3100_driver = {
|
||||
.driver = {
|
||||
.name = "max3100",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
|
|
|
@ -315,7 +315,6 @@ static int __devinit max3107_probe_aava(struct spi_device *spi)
|
|||
static struct spi_driver max3107_driver = {
|
||||
.driver = {
|
||||
.name = "aava-max3107",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max3107_probe_aava,
|
||||
|
|
|
@ -1181,7 +1181,6 @@ static int max3107_probe_generic(struct spi_device *spi)
|
|||
static struct spi_driver max3107_driver = {
|
||||
.driver = {
|
||||
.name = "max3107",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max3107_probe_generic,
|
||||
|
|
|
@ -1154,7 +1154,6 @@ serial_hsu_console_setup(struct console *co, char *options)
|
|||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int ret;
|
||||
|
||||
if (co->index == -1 || co->index >= serial_hsu_reg.nr)
|
||||
co->index = 0;
|
||||
|
@ -1165,9 +1164,7 @@ serial_hsu_console_setup(struct console *co, char *options)
|
|||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
|
||||
|
||||
return ret;
|
||||
return uart_set_options(&up->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct console serial_hsu_console = {
|
||||
|
@ -1176,9 +1173,13 @@ static struct console serial_hsu_console = {
|
|||
.device = uart_console_device,
|
||||
.setup = serial_hsu_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = 2,
|
||||
.index = -1,
|
||||
.data = &serial_hsu_reg,
|
||||
};
|
||||
|
||||
#define SERIAL_HSU_CONSOLE (&serial_hsu_console)
|
||||
#else
|
||||
#define SERIAL_HSU_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
struct uart_ops serial_hsu_pops = {
|
||||
|
@ -1208,6 +1209,7 @@ static struct uart_driver serial_hsu_reg = {
|
|||
.major = TTY_MAJOR,
|
||||
.minor = 128,
|
||||
.nr = 3,
|
||||
.cons = SERIAL_HSU_CONSOLE,
|
||||
};
|
||||
|
||||
#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);
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
|
@ -876,7 +876,6 @@ static int __devexit serial_m3110_remove(struct spi_device *dev)
|
|||
static struct spi_driver uart_max3110_driver = {
|
||||
.driver = {
|
||||
.name = "spi_max3111",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = serial_m3110_probe,
|
||||
|
|
|
@ -422,9 +422,9 @@ static int __devexit msm_hs_remove(struct platform_device *pdev)
|
|||
msm_uport->rx.rbuffer);
|
||||
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_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_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
|
||||
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);
|
||||
|
||||
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 */
|
||||
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) */
|
||||
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);
|
||||
|
||||
spin_lock_irqsave(&uport->lock, flags);
|
||||
clk_enable(msm_uport->clk);
|
||||
|
||||
/* clear interrupt */
|
||||
|
@ -1100,7 +1098,6 @@ static void msm_hs_handle_delta_cts(struct uart_port *uport)
|
|||
uport->icount.cts++;
|
||||
|
||||
clk_disable(msm_uport->clk);
|
||||
spin_unlock_irqrestore(&uport->lock, flags);
|
||||
|
||||
/* clear the IOCTL TIOCMIWAIT if called */
|
||||
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 */
|
||||
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);
|
||||
|
||||
|
@ -1537,7 +1534,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
|
|||
if (!tx->command_ptr)
|
||||
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) {
|
||||
ret = -ENOMEM;
|
||||
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);
|
||||
tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
|
||||
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);
|
||||
|
||||
init_waitqueue_head(&rx->wait);
|
||||
|
@ -1575,7 +1572,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
|
|||
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) {
|
||||
pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
|
||||
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->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);
|
||||
|
||||
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);
|
||||
err_dma_pool_create:
|
||||
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,
|
||||
sizeof(dmov_box), DMA_TO_DEVICE);
|
||||
kfree(msm_uport->tx.command_ptr_ptr);
|
||||
|
|
|
@ -145,11 +145,12 @@ static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
|
|||
writel(xmit->buf[xmit->tail],
|
||||
s->port.membase + AUART_DATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&s->port);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&s->port);
|
||||
|
||||
if (uart_circ_empty(&(s->port.state->xmit)))
|
||||
writel(AUART_INTR_TXIEN,
|
||||
s->port.membase + AUART_INTR_CLR);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
struct uart_omap_port *up = (struct uart_omap_port *)port;
|
||||
unsigned char status;
|
||||
unsigned int status;
|
||||
unsigned int ret = 0;
|
||||
|
||||
status = check_modem_status(up);
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pch_dma.h>
|
||||
|
@ -198,6 +201,10 @@ enum {
|
|||
|
||||
#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 {
|
||||
unsigned char *buf;
|
||||
int size;
|
||||
|
@ -276,6 +283,9 @@ static struct pch_uart_driver_data drv_dat[] = {
|
|||
[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 const int trigger_level_256[4] = { 1, 64, 128, 224 };
|
||||
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
|
||||
};
|
||||
|
||||
#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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
|
@ -1392,6 +1539,7 @@ static struct uart_driver pch_uart_driver = {
|
|||
.major = 0,
|
||||
.minor = 0,
|
||||
.nr = PCH_UART_NR,
|
||||
.cons = PCH_CONSOLE,
|
||||
};
|
||||
|
||||
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)
|
||||
goto init_port_free_txbuf;
|
||||
|
||||
base_baud = 1843200; /* 1.8432MHz */
|
||||
base_baud = DEFAULT_BAUD_RATE;
|
||||
|
||||
/* quirk for CM-iTC board */
|
||||
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);
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto init_port_hal_free;
|
||||
|
@ -1475,6 +1626,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
return priv;
|
||||
|
||||
init_port_hal_free:
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
pch_uart_ports[board->line_no] = NULL;
|
||||
#endif
|
||||
free_page((unsigned long)rxbuf);
|
||||
init_port_free_txbuf:
|
||||
kfree(priv);
|
||||
|
@ -1497,6 +1651,10 @@ static void pch_uart_pci_remove(struct pci_dev *pdev)
|
|||
priv = (struct eg20t_port *)pci_get_drvdata(pdev);
|
||||
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
pch_uart_ports[priv->port.line] = NULL;
|
||||
#endif
|
||||
pch_uart_exit_port(priv);
|
||||
pci_disable_device(pdev);
|
||||
kfree(priv);
|
||||
|
|
|
@ -736,19 +736,7 @@ static struct platform_driver sc26xx_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init sc26xx_init(void)
|
||||
{
|
||||
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_platform_driver(sc26xx_driver);
|
||||
|
||||
MODULE_AUTHOR("Thomas Bogendörfer");
|
||||
MODULE_DESCRIPTION("SC681/SC2692 serial driver");
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.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_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
|
||||
* 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
|
||||
* 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 tty_port *port = &state->port;
|
||||
unsigned long page;
|
||||
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)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
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))
|
||||
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
uart_port_shutdown(port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
quot = port->custom_divisor;
|
||||
else
|
||||
quot = (port->uartclk + (8 * baud)) / (16 * baud);
|
||||
quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
|
||||
|
||||
return quot;
|
||||
}
|
||||
|
@ -658,10 +656,10 @@ static int uart_get_info(struct uart_state *state,
|
|||
tmp.flags = uport->flags;
|
||||
tmp.xmit_fifo_size = uport->fifosize;
|
||||
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 ?
|
||||
ASYNC_CLOSING_WAIT_NONE :
|
||||
port->closing_wait / 10;
|
||||
jiffies_to_msecs(port->closing_wait) / 10;
|
||||
tmp.custom_divisor = uport->custom_divisor;
|
||||
tmp.hub6 = uport->hub6;
|
||||
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_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 ?
|
||||
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
|
||||
|
@ -1265,47 +1264,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
pr_debug("uart_close(%d) called\n", uport->line);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
if (tty_hung_up_p(filp)) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
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
|
||||
|
@ -1337,7 +1297,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
if (port->blocked_open) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (port->close_delay)
|
||||
msleep_interruptible(port->close_delay);
|
||||
msleep_interruptible(
|
||||
jiffies_to_msecs(port->close_delay));
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
} else if (!uart_console(uport)) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
@ -1441,6 +1402,36 @@ static void uart_hangup(struct tty_struct *tty)
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
|
||||
struct uart_state *state;
|
||||
struct tty_port *port;
|
||||
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);
|
||||
|
||||
/*
|
||||
* We take the semaphore inside uart_get to guarantee that we won't
|
||||
* be re-entered while allocating the state structure, or while we
|
||||
* request any IRQs that the driver may need. This also has the nice
|
||||
* side-effect that it delays the action of uart_hangup, so we can
|
||||
* guarantee that state->port.tty will always contain something
|
||||
* reasonable.
|
||||
* We take the semaphore here to guarantee that we won't be re-entered
|
||||
* while allocating the state structure, or while we request any IRQs
|
||||
* that the driver may need. This also has the nice side-effect that
|
||||
* it delays the action of uart_hangup, so we can guarantee that
|
||||
* state->port.tty will always contain something reasonable.
|
||||
*/
|
||||
state = uart_get(drv, line);
|
||||
if (IS_ERR(state)) {
|
||||
retval = PTR_ERR(state);
|
||||
goto fail;
|
||||
if (mutex_lock_interruptible(&port->mutex)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto end;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1535,7 +1502,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
|||
tty->driver_data = state;
|
||||
state->uart_port->state = state;
|
||||
tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
tty->alt_speed = 0;
|
||||
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)) {
|
||||
retval = -EAGAIN;
|
||||
port->count--;
|
||||
mutex_unlock(&port->mutex);
|
||||
goto fail;
|
||||
goto err_dec_count;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1566,8 +1530,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
|||
if (retval == 0)
|
||||
retval = tty_port_block_til_ready(port, tty, filp);
|
||||
|
||||
fail:
|
||||
end:
|
||||
return retval;
|
||||
err_dec_count:
|
||||
port->count--;
|
||||
mutex_unlock(&port->mutex);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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);
|
||||
#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)
|
||||
{
|
||||
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 = {
|
||||
.activate = uart_port_activate,
|
||||
.shutdown = uart_port_shutdown,
|
||||
.carrier_raised = uart_carrier_raised,
|
||||
.dtr_rts = uart_dtr_rts,
|
||||
};
|
||||
|
@ -2275,8 +2253,8 @@ int uart_register_driver(struct uart_driver *drv)
|
|||
|
||||
tty_port_init(port);
|
||||
port->ops = &uart_port_ops;
|
||||
port->close_delay = 500; /* .5 seconds */
|
||||
port->closing_wait = 30000; /* 30 seconds */
|
||||
port->close_delay = HZ / 2; /* .5 seconds */
|
||||
port->closing_wait = 30 * HZ;/* 30 seconds */
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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_register_driver);
|
||||
EXPORT_SYMBOL(uart_unregister_driver);
|
||||
|
|
|
@ -317,7 +317,7 @@ static int serial_probe(struct pcmcia_device *link)
|
|||
info->p_dev = link;
|
||||
link->priv = info;
|
||||
|
||||
link->config_flags |= CONF_ENABLE_IRQ;
|
||||
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
|
||||
if (do_sound)
|
||||
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.
|
||||
* 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++)
|
||||
if (!pcmcia_loop_config(link, simple_config_check, &try))
|
||||
goto found_port;
|
||||
|
@ -501,7 +501,8 @@ static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
|
|||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
int i, base2 = 0;
|
||||
|
||||
link->config_flags |= CONF_AUTO_SET_IO;
|
||||
/* First, look for a generic full-sized window */
|
||||
if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
|
||||
base2 = link->resource[0]->start + 8;
|
||||
|
|
|
@ -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");
|
|
@ -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
|
|
@ -513,20 +513,7 @@ static struct platform_driver timbuart_platform_driver = {
|
|||
.remove = __devexit_p(timbuart_remove),
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
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_platform_driver(timbuart_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Timberdale UART driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -961,18 +961,7 @@ static struct platform_driver siu_device_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init vr41xx_siu_init(void)
|
||||
{
|
||||
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_platform_driver(siu_device_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:SIU");
|
||||
|
|
|
@ -790,19 +790,24 @@ static void session_clear_tty(struct pid *session)
|
|||
void disassociate_ctty(int on_exit)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct pid *tty_pgrp = NULL;
|
||||
|
||||
if (!current->signal->leader)
|
||||
return;
|
||||
|
||||
tty = get_current_tty();
|
||||
if (tty) {
|
||||
tty_pgrp = get_pid(tty->pgrp);
|
||||
struct pid *tty_pgrp = get_pid(tty->pgrp);
|
||||
if (on_exit) {
|
||||
if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
|
||||
tty_vhangup(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) {
|
||||
struct pid *old_pgrp;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
|
@ -816,12 +821,6 @@ void disassociate_ctty(int on_exit)
|
|||
}
|
||||
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(¤t->sighand->siglock);
|
||||
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_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
|
||||
* @inode: inode of tty
|
||||
|
@ -1585,11 +1637,11 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
int idx;
|
||||
char buf[64];
|
||||
|
||||
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
|
||||
if (tty_paranoia_check(tty, inode, __func__))
|
||||
return 0;
|
||||
|
||||
tty_lock();
|
||||
check_tty_count(tty, "tty_release_dev");
|
||||
check_tty_count(tty, __func__);
|
||||
|
||||
__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;
|
||||
o_tty = tty->link;
|
||||
|
||||
#ifdef TTY_PARANOIA_CHECK
|
||||
if (idx < 0 || idx >= tty->driver->num) {
|
||||
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
|
||||
"free (%s)\n", tty->name);
|
||||
if (tty_release_checks(tty, o_tty, idx)) {
|
||||
tty_unlock();
|
||||
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
|
||||
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);
|
||||
#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)
|
||||
tty->ops->close(tty, filp);
|
||||
|
||||
|
@ -1707,8 +1716,8 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
if (!do_sleep)
|
||||
break;
|
||||
|
||||
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
|
||||
"active!\n", tty_name(tty, buf));
|
||||
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
|
||||
__func__, tty_name(tty, buf));
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
schedule();
|
||||
|
@ -1721,15 +1730,14 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
*/
|
||||
if (pty_master) {
|
||||
if (--o_tty->count < 0) {
|
||||
printk(KERN_WARNING "tty_release_dev: bad pty slave count "
|
||||
"(%d) for %s\n",
|
||||
o_tty->count, tty_name(o_tty, buf));
|
||||
printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
|
||||
__func__, o_tty->count, tty_name(o_tty, buf));
|
||||
o_tty->count = 0;
|
||||
}
|
||||
}
|
||||
if (--tty->count < 0) {
|
||||
printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
|
||||
tty->count, tty_name(tty, buf));
|
||||
printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
|
||||
__func__, tty->count, tty_name(tty, buf));
|
||||
tty->count = 0;
|
||||
}
|
||||
|
||||
|
@ -1778,7 +1786,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
}
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "freeing tty structure...");
|
||||
printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
|
||||
#endif
|
||||
/*
|
||||
* Ask the line discipline code to release its structures
|
||||
|
@ -1797,6 +1805,83 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
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
|
||||
* @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
|
||||
* 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.
|
||||
* ->siglock protects ->signal/->sighand
|
||||
*/
|
||||
|
||||
static int tty_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct tty_struct *tty = NULL;
|
||||
struct tty_struct *tty;
|
||||
int noctty, retval;
|
||||
struct tty_driver *driver;
|
||||
struct tty_driver *driver = NULL;
|
||||
int index;
|
||||
dev_t device = inode->i_rdev;
|
||||
unsigned saved_flags = filp->f_flags;
|
||||
|
@ -1841,66 +1926,22 @@ retry_open:
|
|||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
|
||||
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
|
||||
tty = get_current_tty();
|
||||
if (!tty) {
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_free_file(filp);
|
||||
return -ENXIO;
|
||||
}
|
||||
driver = tty_driver_kref_get(tty->driver);
|
||||
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;
|
||||
tty = tty_open_current_tty(device, filp);
|
||||
if (IS_ERR(tty)) {
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_unlock;
|
||||
} else if (!tty) {
|
||||
driver = tty_lookup_driver(device, filp, &noctty, &index);
|
||||
if (IS_ERR(driver)) {
|
||||
retval = PTR_ERR(driver);
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
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 */
|
||||
tty = tty_driver_lookup_tty(driver, inode, index);
|
||||
|
||||
if (IS_ERR(tty)) {
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_driver_kref_put(driver);
|
||||
tty_free_file(filp);
|
||||
return PTR_ERR(tty);
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1912,21 +1953,22 @@ got_driver:
|
|||
tty = tty_init_dev(driver, index, 0);
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
if (driver)
|
||||
tty_driver_kref_put(driver);
|
||||
if (IS_ERR(tty)) {
|
||||
tty_unlock();
|
||||
tty_free_file(filp);
|
||||
return PTR_ERR(tty);
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_file;
|
||||
}
|
||||
|
||||
tty_add_file(tty, filp);
|
||||
|
||||
check_tty_count(tty, "tty_open");
|
||||
check_tty_count(tty, __func__);
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
noctty = 1;
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "opening %s...", tty->name);
|
||||
printk(KERN_DEBUG "%s: opening %s...\n", __func__, tty->name);
|
||||
#endif
|
||||
if (tty->ops->open)
|
||||
retval = tty->ops->open(tty, filp);
|
||||
|
@ -1940,8 +1982,8 @@ got_driver:
|
|||
|
||||
if (retval) {
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "error %d in opening %s...", retval,
|
||||
tty->name);
|
||||
printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
|
||||
retval, tty->name);
|
||||
#endif
|
||||
tty_unlock(); /* need to call tty_release without BTM */
|
||||
tty_release(inode, filp);
|
||||
|
@ -1976,6 +2018,15 @@ got_driver:
|
|||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/devpts_fs.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/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -24,18 +16,8 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/seq_file.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>
|
||||
|
||||
/*
|
||||
|
@ -558,8 +540,6 @@ static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
|
|||
long ret;
|
||||
ret = wait_event_timeout(tty_ldisc_idle,
|
||||
atomic_read(&tty->ldisc->users) == 1, timeout);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ret > 0 ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
|
|
|
@ -584,7 +584,7 @@ int con_set_default_unimap(struct vc_data *vc)
|
|||
return 0;
|
||||
dflt->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
|
||||
if (p && --p->refcount) {
|
||||
if (p && !--p->refcount) {
|
||||
con_release_unimap(p);
|
||||
kfree(p);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ enum {
|
|||
* dependent on the 8250 driver.
|
||||
*/
|
||||
struct uart_port;
|
||||
struct uart_8250_port;
|
||||
|
||||
int serial8250_register_port(struct uart_port *);
|
||||
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);
|
||||
extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate);
|
||||
extern int fsl8250_handle_irq(struct uart_port *port);
|
||||
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)
|
||||
(int port, struct uart_port *up,
|
||||
|
|
|
@ -351,6 +351,7 @@ struct uart_port {
|
|||
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
|
||||
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
|
||||
#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. */
|
||||
#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
|
||||
#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.
|
||||
*/
|
||||
|
||||
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
|
||||
uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
if (port->sysrq) {
|
||||
if (ch && time_before(jiffies, port->sysrq)) {
|
||||
handle_sysrq(ch);
|
||||
|
@ -495,11 +505,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
|||
}
|
||||
port->sysrq = 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#ifndef SUPPORT_SYSRQ
|
||||
#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0)
|
||||
#else
|
||||
#define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -522,89 +531,6 @@ static inline int uart_handle_break(struct uart_port *port)
|
|||
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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue