Commit 10af77c1 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge 3.4-rc4 into tty-next

This resolves the merge problem with:
	drivers/tty/serial/pch_uart.c
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parents 66f75a5d 5f1a3895
......@@ -245,14 +245,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout;
/* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
if (!cpu_is_omap2420() && !cpu_is_ti816x())
omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
/* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
if (cpu_is_omap34xx() || cpu_is_omap3630())
omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info);
......
......@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/pda_power.h>
......@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTD,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
......
......@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/gpio_keys.h>
......@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTA,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
......@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTC,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
......
......@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/input.h>
......@@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
/* Memory and IRQ filled in before registration */
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
......
......@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
......@@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTA,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
......
......@@ -65,7 +65,6 @@ struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */
upf_t flags; /* UPF_* flags */
u32 errata;
unsigned int dma_rx_buf_size;
unsigned int dma_rx_timeout;
unsigned int autosuspend_timeout;
......
......@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
static char *isdn_revision = "$Revision: 1.1.2.3 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
#ifdef CONFIG_ISDN_PPP
extern char *isdn_ppp_revision;
#else
......@@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
dev->chanmap[i] = -1;
dev->m_idx[i] = -1;
strcpy(dev->num[i], "???");
init_waitqueue_head(&dev->mdm.info[i].open_wait);
init_waitqueue_head(&dev->mdm.info[i].close_wait);
}
if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
printk(KERN_WARNING "isdn: Could not register control devices\n");
......@@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
strcpy(tmprev, isdn_revision);
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_tty_revision);
printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_net_revision);
printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_ppp_revision);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
if (ch == ' ' || ch == d)
return d;
kbd_put_queue(kbd->tty, d);
kbd_put_queue(kbd->port, d);
return ch;
}
......@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
{
if (kbd->diacr)
value = handle_diacr(kbd, value);
kbd_put_queue(kbd->tty, value);
kbd_put_queue(kbd->port, value);
}
/*
......@@ -239,7 +239,7 @@ static void
k_fn(struct kbd_data *kbd, unsigned char value)
{
if (kbd->func_table[value])
kbd_puts_queue(kbd->tty, kbd->func_table[value]);
kbd_puts_queue(kbd->port, kbd->func_table[value]);
}
static void
......@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
* but we need only 16 bits here
*/
static void
to_utf8(struct tty_struct *tty, ushort c)
to_utf8(struct tty_port *port, ushort c)
{
if (c < 0x80)
/* 0******* */
kbd_put_queue(tty, c);
kbd_put_queue(port, c);
else if (c < 0x800) {
/* 110***** 10****** */
kbd_put_queue(tty, 0xc0 | (c >> 6));
kbd_put_queue(tty, 0x80 | (c & 0x3f));
kbd_put_queue(port, 0xc0 | (c >> 6));
kbd_put_queue(port, 0x80 | (c & 0x3f));
} else {
/* 1110**** 10****** 10****** */
kbd_put_queue(tty, 0xe0 | (c >> 12));
kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
kbd_put_queue(tty, 0x80 | (c & 0x3f));
kbd_put_queue(port, 0xe0 | (c >> 12));
kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
kbd_put_queue(port, 0x80 | (c & 0x3f));
}
}
......@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
unsigned short keysym;
unsigned char type, value;
if (!kbd || !kbd->tty)
if (!kbd)
return;
if (keycode >= 384)
......@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
#endif
(*k_handler[type])(kbd, value);
} else
to_utf8(kbd->tty, keysym);
to_utf8(kbd->port, keysym);
}
/*
......@@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
{
struct tty_struct *tty;
void __user *argp;
unsigned int ct;
int perm;
......@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
* To have permissions to do most of the vt ioctls, we either have
* to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
*/
perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
tty = tty_port_tty_get(kbd->port);
/* FIXME this test is pretty racy */
perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
tty_kref_put(tty);
switch (cmd) {
case KDGKBTYPE:
return put_user(KB_101, (char __user *)argp);
......
......@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
*/
struct kbd_data {
struct tty_struct *tty;
struct tty_port *port;
unsigned short **key_maps;
char **func_table;
fn_handler_fn **fn_handler;
......@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
* Helper Functions.
*/
static inline void
kbd_put_queue(struct tty_struct *tty, int ch)
kbd_put_queue(struct tty_port *port, int ch)
{
struct tty_struct *tty = tty_port_tty_get(port);
if (!tty)
return;
tty_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty);
tty_kref_put(tty);
}
static inline void
kbd_puts_queue(struct tty_struct *tty, char *cp)
kbd_puts_queue(struct tty_port *port, char *cp)
{
struct tty_struct *tty = tty_port_tty_get(port);
if (!tty)
return;
while (*cp)
tty_insert_flip_char(tty, *cp++, 0);
tty_schedule_flip(tty);
tty_kref_put(tty);
}
......@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
/* Timer for delayed output of console messages. */
static struct timer_list sclp_tty_timer;
static struct tty_struct *sclp_tty;
static struct tty_port sclp_port;
static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
static unsigned short int sclp_tty_chars_count;
......@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
static int
sclp_tty_open(struct tty_struct *tty, struct file *filp)
{
sclp_tty = tty;
tty_port_tty_set(&sclp_port, tty);
tty->driver_data = NULL;
tty->low_latency = 0;
return 0;
......@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
{
if (tty->count > 1)
return;
sclp_tty = NULL;
tty_port_tty_set(&sclp_port, NULL);
}
/*
......@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
static void
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
{
struct tty_struct *tty;
unsigned long flags;
void *page;
......@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
spin_unlock_irqrestore(&sclp_tty_lock, flags);
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
/* check if the tty needs a wake up call */
if (sclp_tty != NULL) {
tty_wakeup(sclp_tty);
tty = tty_port_tty_get(&sclp_port);
if (tty != NULL) {
tty_wakeup(tty);
tty_kref_put(tty);
}
}
......@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
static void
sclp_tty_input(unsigned char* buf, unsigned int count)
{
struct tty_struct *tty = tty_port_tty_get(&sclp_port);
unsigned int cchar;
/*
* If this tty driver is currently closed
* then throw the received input away.
*/
if (sclp_tty == NULL)
if (tty == NULL)
return;
cchar = ctrlchar_handle(buf, count, sclp_tty);
cchar = ctrlchar_handle(buf, count, tty);
switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ:
break;
case CTRLCHAR_CTRL:
tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
tty_flip_buffer_push(sclp_tty);
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
tty_flip_buffer_push(tty);
break;
case CTRLCHAR_NONE:
/* send (normal) input to line discipline */
......@@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
(strncmp((const char *) buf + count - 2, "^n", 2) &&
strncmp((const char *) buf + count - 2, "\252n", 2))) {
/* add the auto \n */
tty_insert_flip_string(sclp_tty, buf, count);
tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
tty_insert_flip_string(tty, buf, count);
tty_insert_flip_char(tty, '\n', TTY_NORMAL);
} else
tty_insert_flip_string(sclp_tty, buf, count - 2);
tty_flip_buffer_push(sclp_tty);
tty_insert_flip_string(tty, buf, count - 2);
tty_flip_buffer_push(tty);
break;
}
tty_kref_put(tty);
}
/*
......@@ -543,7 +548,7 @@ sclp_tty_init(void)
sclp_tty_tolower = 1;
}
sclp_tty_chars_count = 0;
sclp_tty = NULL;
tty_port_init(&sclp_port);
rc = sclp_register(&sclp_input_event);
if (rc) {
......
......@@ -34,7 +34,6 @@
#define SCLP_VT220_DEVICE_NAME "ttysclp"
#define SCLP_VT220_CONSOLE_NAME "ttyS"
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
#define SCLP_VT220_BUF_SIZE 80
/* Representation of a single write request */
struct sclp_vt220_request {
......@@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
/* Structures and data needed to register tty driver */
static struct tty_driver *sclp_vt220_driver;
/* The tty_struct that the kernel associated with us */
static struct tty_struct *sclp_vt220_tty;
static struct tty_port sclp_vt220_port;
/* Lock to protect internal data from concurrent access */
static spinlock_t sclp_vt220_lock;
......@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
static void
sclp_vt220_process_queue(struct sclp_vt220_request *request)
{
struct tty_struct *tty;
unsigned long flags;
void *page;
......@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current();
/* Check if the tty needs a wake up call */
if (sclp_vt220_tty != NULL) {
tty_wakeup(sclp_vt220_tty);
tty = tty_port_tty_get(&sclp_vt220_port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
}
......@@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
static void
sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
{
struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
char *buffer;
unsigned int count;
/* Ignore input if device is not open */
if (sclp_vt220_tty == NULL)
if (tty == NULL)
return;
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
......@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
/* Send input to line discipline */
buffer++;
count--;
tty_insert_flip_string(sclp_vt220_tty, buffer, count);
tty_flip_buffer_push(sclp_vt220_tty);
tty_insert_flip_string(tty, buffer, count);
tty_flip_buffer_push(tty);
break;
}
tty_kref_put(tty);
}
/*
......@@ -491,10 +494,7 @@ static int
sclp_vt220_open(struct tty_struct *tty, struct file *filp)
{
if (tty->count == 1) {
sclp_vt220_tty = tty;
tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
if (tty->driver_data == NULL)
return -ENOMEM;
tty_port_tty_set(&sclp_vt220_port, tty);
tty->low_latency = 0;
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = 24;
......@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
static void
sclp_vt220_close(struct tty_struct *tty, struct file *filp)
{
if (tty->count == 1) {
sclp_vt220_tty = NULL;
kfree(tty->driver_data);
tty->driver_data = NULL;
}
if (tty->count == 1)
tty_port_tty_set(&sclp_vt220_port, NULL);
}
/*
......@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
INIT_LIST_HEAD(&sclp_vt220_empty);
INIT_LIST_HEAD(&sclp_vt220_outqueue);
init_timer(&sclp_vt220_timer);
tty_port_init(&sclp_vt220_port);
sclp_vt220_current_request = NULL;
sclp_vt220_buffered_chars = 0;
sclp_vt220_tty = NULL;
sclp_vt220_flush_later = 0;
/* Allocate pages for output buffering */
......
This diff is collapsed.
......@@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
static struct tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread;
static struct tty_struct * volatile bfin_jc_tty;
static unsigned long bfin_jc_count;
static DEFINE_MUTEX(bfin_jc_tty_mutex);
static struct tty_port port;
static volatile struct circ_buf bfin_jc_write_buf;
static int
......@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) {
struct tty_struct *tty = tty_port_tty_get(&port);
/* no one left to give data to, so sleep */
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
continue;
}
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
tty_kref_put(tty);
if (inbound_len)
schedule();
else
......@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
/* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) {
struct tty_struct *tty;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
......@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
tty_flip_buffer_push(tty);
}
}
mutex_unlock(&bfin_jc_tty_mutex);
}
/* if outgoing data is ready, post it */
......@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
bfin_write_emudat(outbound_len);
pr_debug("outgoing length: 0x%08x\n", outbound_len);
} else {
struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat =
......@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
);
bfin_jc_write_buf.tail += ate;
outbound_len -= ate;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty)
tty_wakeup(tty);
mutex_unlock(&bfin_jc_tty_mutex);
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
tty_kref_put(tty);
}
__set_current_state(TASK_RUNNING);
......@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
pr_debug("open %lu\n", bfin_jc_count);
++bfin_jc_count;
bfin_jc_tty = tty;
unsigned long flags;
spin_lock_irqsave(&port.lock, flags);
port.count++;
spin_unlock_irqrestore(&port.lock, flags);
tty_port_tty_set(&port, tty);
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
return 0;
}
static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
pr_debug("close %lu\n", bfin_jc_count);
if (--bfin_jc_count == 0)
bfin_jc_tty = NULL;
unsigned long flags;
bool last;
spin_lock_irqsave(&port.lock, flags);
last = --port.count == 0;
spin_unlock_irqrestore(&port.lock, flags);
if (last)
tty_port_tty_set(&port, NULL);
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
}
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
......@@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
{
int ret;
tty_port_init(&port);
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
......
......@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
list_for_each_entry(hp, &hvc_structs, next) {
spin_lock_irqsave(&hp->lock, flags);
if (hp->index == index) {
kref_get(&hp->kref);
tty_port_get(&hp->port);
spin_unlock_irqrestore(&hp->lock, flags);
spin_unlock(&hvc_structs_lock);
return hp;
......@@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
console_initcall(hvc_console_init);
/* callback when the kboject ref count reaches zero. */
static void destroy_hvc_struct(struct kref *kref)
static void hvc_port_destruct(struct tty_port *port)
{
struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
unsigned long flags;
spin_lock(&hvc_structs_lock);
......@@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
/* make sure no no tty has been registered in this index */
hp = hvc_get_by_index(index);
if (hp) {
kref_put(&hp->kref, destroy_hvc_struct);
tty_port_put(&hp->port);
return -1;
}
......@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
spin_lock_irqsave(&hp->lock, flags);
spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
if (hp->count++ > 0) {
tty_kref_get(tty);
spin_unlock_irqrestore(&hp->lock, flags);
if (hp->port.count++ > 0) {
spin_unlock_irqrestore(&hp->port.lock, flags);
hvc_kick();
return 0;
} /* else count == 0 */
spin_unlock_irqrestore(&hp->port.lock, flags);
tty->driver_data = hp;
hp->tty = tty_kref_get(tty);
spin_unlock_irqrestore(&hp->lock, flags);
tty_port_tty_set(&hp->port, tty);
if (hp->ops->notifier_add)
rc = hp->ops->notifier_add(hp, hp->data);
......@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
* tty fields and return the kref reference.
*/
if (rc) {
spin_lock_irqsave(&hp->lock, flags);
hp->tty = NULL;
spin_unlock_irqrestore(&hp->lock, flags);
tty_kref_put(tty);
tty_port_tty_set(&hp->port, NULL);
tty->driver_data = NULL;
kref_put(&hp->kref, destroy_hvc_struct);
tty_port_put(&hp->port);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
}
/* Force wakeup of the polling thread */
......@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp = tty->driver_data;
spin_lock_irqsave(&hp->lock, flags);
spin_lock_irqsave(&hp->port.lock, flags);
if (--hp->count == 0) {
if (--hp->port.count == 0) {
spin_unlock_irqrestore(&hp->port.lock, flags);
/* We are done with the tty pointer now. */
hp->tty = NULL;
spin_unlock_irqrestore(&hp->lock, flags);
tty_port_tty_set(&hp->port, NULL);
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
......@@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
*/
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
} else {
if (hp->count < 0)
if (hp->port.count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
hp->vtermno, hp->count);
spin_unlock_irqrestore(&hp->lock, flags);
hp->vtermno, hp->port.count);
spin_unlock_irqrestore(&hp->port.lock, flags);
}
tty_kref_put(tty);
kref_put(&hp->kref, destroy_hvc_struct);
tty_port_put(&hp->port);
}
static void hvc_hangup(struct tty_struct *tty)
......@@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)
/* cancel pending tty resize work */
cancel_work_sync(&hp->tty_resize);
spin_lock_irqsave(&hp->lock, flags);
spin_lock_irqsave(&hp->port.lock, flags);
/*
* The N_TTY line discipline has problems such that in a close vs
* open->hangup case this can be called after the final close so prevent
* that from happening for now.
*/
if (hp->count <= 0) {
spin_unlock_irqrestore(&hp->lock, flags);
if (hp->port.count <= 0) {
spin_unlock_irqrestore(&hp->port.lock, flags);
return;
}
temp_open_count = hp->count;
hp->count = 0;
hp->n_outbuf = 0;
hp->tty = NULL;
temp_open_count = hp->port.count;
hp->port.count = 0;
spin_unlock_irqrestore(&hp->port.lock, flags);
tty_port_tty_set(&hp->port, NULL);
spin_unlock_irqrestore(&hp->lock, flags);
hp->n_outbuf = 0;
if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data);
while(temp_open_count) {
--temp_open_count;
tty_kref_put(tty);
kref_put(&hp->kref, destroy_hvc_struct);
tty_port_put(&hp->port);
}
}
......@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (!hp)
return -EPIPE;
if (hp->count <= 0)
/* FIXME what's this (unprotected) check for? */
if (hp->port.count <= 0)
return -EIO;
spin_lock_irqsave(&hp->lock, flags);
......@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
hp = container_of(work, struct hvc_struct, tty_resize);
spin_lock_irqsave(&hp->lock, hvc_flags);
if (!hp->tty) {
spin_unlock_irqrestore(&hp->lock, hvc_flags);
tty = tty_port_tty_get(&hp->port);
if (!tty)
return;
}
spin_lock_irqsave(&hp->lock, hvc_flags);
ws = hp->ws;
tty = tty_kref_get(hp->tty);
spin_unlock_irqrestore(&hp->lock, hvc_flags);
tty_do_resize(tty, &ws);
......@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
}
/* No tty attached, just skip */
tty = tty_kref_get(hp->tty);
tty = tty_port_tty_get(&hp->port);
if (tty == NULL)
goto bail;
......@@ -681,7 +673,6 @@ int hvc_poll(struct hvc_struct *hp)
tty_flip_buffer_push(tty);
}
if (tty)
tty_kref_put(tty);
return poll_mask;
......@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
#endif
};
static const struct tty_port_operations hvc_port_ops = {
.destruct = hvc_port_destruct,
};
struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
const struct hv_ops *ops,
int outbuf_size)
......@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
kref_init(&hp->kref);
tty_port_init(&hp->port);
hp->port.ops = &hvc_port_ops;
INIT_WORK(&hp->tty_resize, hvc_set_winsz);
spin_lock_init(&hp->lock);
......@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
unsigned long flags;
struct tty_struct *tty;
spin_lock_irqsave(&hp->lock, flags);
tty = tty_kref_get(hp->tty);
tty = tty_port_tty_get(&hp->port);
spin_lock_irqsave(&hp->lock, flags);
if (hp->index < MAX_NR_HVC_CONSOLES)
vtermnos[hp->index] = -1;
......@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
* kref cause it to be removed, which will probably be the tty_vhangup
* below.
*/
kref_put(&hp->kref, destroy_hvc_struct);
tty_port_put(&hp->port);
/*
* This function call will auto chain call hvc_hangup.
......
......@@ -46,10 +46,9 @@
#define HVC_ALLOC_TTY_ADAPTERS 8
struct hvc_struct {
struct tty_port port;
spinlock_t lock;
int index;
struct tty_struct *tty;
int count;
int do_wakeup;
char *outbuf;
int outbuf_size;
......@@ -61,7 +60,6 @@ struct hvc_struct {
struct winsize ws;
struct work_struct tty_resize;
struct list_head next;
struct kref kref; /* ref count & hvc_struct lifetime */
};
/* implemented by a low level driver */
......
......@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
/* One vty-server per hvcs_struct */
struct hvcs_struct {
struct tty_port port;
spinlock_t lock;
/*
......@@ -269,9 +270,6 @@ struct hvcs_struct {
*/
unsigned int index;
struct tty_struct *tty;
int open_count;
/*
* Used to tell the driver kernel_thread what operations need to take
* place upon this hvcs_struct instance.
......@@ -290,12 +288,11 @@ struct hvcs_struct {
int chars_in_buffer;
/*
* Any variable below the kref is valid before a tty is connected and
* Any variable below is valid before a tty is connected and
* stays valid after the tty is disconnected. These shouldn't be
* whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives.
*/
struct kref kref; /* ref count & hvcs_struct lifetime */
int connected; /* is the vty-server currently connected to a vty? */
uint32_t p_unit_address; /* partner unit address */
uint32_t p_partition_ID; /* partner partition ID */
......@@ -304,9 +301,6 @@ struct hvcs_struct {
struct vio_dev *vdev;
};
/* Required to back map a kref to its containing object */
#define from_kref(k) container_of(k, struct hvcs_struct, kref)
static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
static DEFINE_MUTEX(hvcs_init_mutex);
......@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->open_count > 0) {
if (hvcsd->port.count > 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
printk(KERN_INFO "HVCS: vterm state unchanged. "
"The hvcs device node is still in use.\n");
......@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
static void hvcs_try_write(struct hvcs_struct *hvcsd)
{
uint32_t unit_address = hvcsd->vdev->unit_address;
struct tty_struct *tty = hvcsd->tty;
struct tty_struct *tty = hvcsd->port.tty;
int sent;
if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
......@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_lock_irqsave(&hvcsd->lock, flags);
unit_address = hvcsd->vdev->unit_address;
tty = hvcsd->tty;
tty = hvcsd->port.tty;
hvcs_try_write(hvcsd);
......@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
hvcs_index_list[index] = -1;
}
/* callback when the kref ref count reaches zero */
static void destroy_hvcs_struct(struct kref *kref)
static void hvcs_destruct_port(struct tty_port *p)
{
struct hvcs_struct *hvcsd = from_kref(kref);
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
unsigned long flags;
......@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
kfree(hvcsd);
}
static const struct tty_port_operations hvcs_port_ops = {
.destruct = hvcs_destruct_port,
};
static int hvcs_get_index(void)
{
int i;
......@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
if (!hvcsd)
return -ENODEV;
tty_port_init(&hvcsd->port);
hvcsd->port.ops = &hvcs_port_ops;
spin_lock_init(&hvcsd->lock);
/* Automatically incs the refcount the first time */
kref_init(&hvcsd->kref);
hvcsd->vdev = dev;
dev_set_drvdata(&dev->dev, hvcsd);
......@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
tty = hvcsd->tty;
tty = hvcsd->port.tty;
spin_unlock_irqrestore(&hvcsd->lock, flags);
......@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
* Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below.
*/
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
/*
* The hangup is a scheduled function which will auto chain call
......@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
list_for_each_entry(hvcsd, &hvcs_structs, next) {
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->index == index) {
kref_get(&hvcsd->kref);
tty_port_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
return hvcsd;
......@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
if ((retval = hvcs_partner_connect(hvcsd)))
goto error_release;
hvcsd->open_count = 1;
hvcsd->tty = tty;
hvcsd->port.count = 1;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
......@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* and will grab the spinlock and free the connection if it fails.
*/
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: enable device failed.\n");
return rc;
}
......@@ -1171,8 +1167,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
kref_get(&hvcsd->kref);
hvcsd->open_count++;
tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
......@@ -1186,7 +1182,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
error_release:
spin_unlock_irqrestore(&hvcsd->lock, flags);
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval;
......@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
if (--hvcsd->open_count == 0) {
if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
......@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
* execute any operations on the TTY even though it is obligated
* to deliver any pending I/O to the hypervisor.
*/
hvcsd->tty = NULL;
hvcsd->port.tty = NULL;
irq = hvcsd->vdev->irq;
spin_unlock_irqrestore(&hvcsd->lock, flags);
......@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->open_count < 0) {
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
" is missmanaged.\n",
hvcsd->vdev->unit_address, hvcsd->open_count);
hvcsd->vdev->unit_address, hvcsd->port.count);
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
}
static void hvcs_hangup(struct tty_struct * tty)
......@@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */
temp_open_count = hvcsd->open_count;
temp_open_count = hvcsd->port.count;
/*
* Don't kref put inside the spinlock because the destruction
......@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
hvcsd->tty->driver_data = NULL;
hvcsd->tty = NULL;
tty->driver_data = NULL;
hvcsd->port.tty = NULL;
hvcsd->open_count = 0;
hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
* scenario. */
......@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
* NOTE: If this hangup was signaled from user space then the
* final put will never happen.
*/
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
}
}
......@@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
* the middle of a write operation? This is a crummy place to do this
* but we want to keep it all in the spinlock.
*/
if (hvcsd->open_count <= 0) {
if (hvcsd->port.count <= 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
return -ENODEV;
}
......@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
if (!hvcsd || hvcsd->open_count <= 0)
if (!hvcsd || hvcsd->port.count <= 0)
return 0;
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
......
This diff is collapsed.
......@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
pr_devel("HVSI@%x: open !\n", pv->termno);
/* Keep track of the tty data structure */
pv->tty = tty_kref_get(hp->tty);
pv->tty = tty_port_tty_get(&hp->port);
hvsilib_establish(pv);
......
......@@ -44,14 +44,13 @@
#define TTYTYPE_RAS_RAW (2)
struct ipw_tty {
struct tty_port port;
int index;
struct ipw_hardware *hardware;
unsigned int channel_idx;
unsigned int secondary_channel_idx;
int tty_type;
struct ipw_network *network;
struct tty_struct *linux_tty;
int open_count;
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
......@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
return channel_names[tty_type];
}
static void report_registering(struct ipw_tty *tty)
{
char *iftype = tty_type_name(tty->tty_type);
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n", iftype, tty->index);
}
static void report_deregistering(struct ipw_tty *tty)
{
char *iftype = tty_type_name(tty->tty_type);
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n", iftype,
tty->index);
}
static struct ipw_tty *get_tty(int index)
{
/*
......@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
mutex_unlock(&tty->ipw_tty_mutex);
return -ENODEV;
}
if (tty->open_count == 0)
if (tty->port.count == 0)
tty->tx_bytes_queued = 0;
tty->open_count++;
tty->port.count++;
tty->linux_tty = linux_tty;
tty->port.tty = linux_tty;
linux_tty->driver_data = tty;
linux_tty->low_latency = 1;
......@@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
static void do_ipw_close(struct ipw_tty *tty)
{
tty->open_count--;
tty->port.count--;
if (tty->open_count == 0) {
struct tty_struct *linux_tty = tty->linux_tty;
if (tty->port.count == 0) {
struct tty_struct *linux_tty = tty->port.tty;
if (linux_tty != NULL) {
tty->linux_tty = NULL;
tty->port.tty = NULL;
linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM)
......@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
return;
mutex_lock(&tty->ipw_tty_mutex);
if (tty->open_count == 0) {
if (tty->port.count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
......@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
int work = 0;
mutex_lock(&tty->ipw_tty_mutex);
linux_tty = tty->linux_tty;
linux_tty = tty->port.tty;
if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
if (!tty->open_count) {
if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
......@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
if (!tty->open_count) {
if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL;
}
......@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
......@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
if (!tty)
return 0;
if (!tty->open_count)
if (!tty->port.count)
return 0;
return tty->tx_bytes_queued;
......@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
return get_control_lines(tty);
......@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
return set_control_lines(tty, set, clear);
......@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
......@@ -492,6 +474,7 @@ static int add_tty(int j,
ttys[j]->network = network;
ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
tty_register_device(ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
......@@ -500,8 +483,12 @@ static int add_tty(int j,
ipwireless_associate_network_tty(network,
secondary_channel_idx,
ttys[j]);
if (get_tty(j) == ttys[j])
report_registering(ttys[j]);
/* check if we provide raw device (if loopback is enabled) */
if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n",
tty_type_name(tty_type), j);
return 0;
}
......@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex);
if (get_tty(j) == ttyj)
report_deregistering(ttyj);
if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n",
tty_type_name(ttyj->tty_type), j);
ttyj->closing = 1;
if (ttyj->linux_tty != NULL) {
if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
tty_hangup(ttyj->linux_tty);
/* Wait till the tty_hangup has completed */
flush_work_sync(&ttyj->linux_tty->hangup_work);
tty_vhangup(ttyj->port.tty);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
/* FIXME2: hangup does not mean all processes
* are gone */
mutex_lock(&ttyj->ipw_tty_mutex);
}
while (ttyj->open_count)
while (ttyj->port.count)
do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
......@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
*/
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
&& tty->linux_tty) {
tty_hangup(tty->linux_tty);
&& tty->port.tty) {
tty_hangup(tty->port.tty);
}
}
This diff is collapsed.
/* 68328serial.h: Definitions for the mc68328 serial driver.
*
* Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
* Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
* Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
*
* VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
*/
#ifndef _MC683XX_SERIAL_H
#define _MC683XX_SERIAL_H
struct serial_struct {
int type;
int line;
int port;
int irq;
int flags;
int xmit_fifo_size;
int custom_divisor;
int baud_base;
unsigned short close_delay;
char reserved_char[2];
int hub6; /* FIXME: We don't have AT&T Hub6 boards! */
unsigned short closing_wait; /* time to wait before closing */
unsigned short closing_wait2; /* no longer used... */
int reserved[4];
};
/*
* For the close wait times, 0 means wait forever for serial port to
* flush its output. 65535 means don't wait at all.
*/
#define S_CLOSING_WAIT_INF 0
#define S_CLOSING_WAIT_NONE 65535
/*
* Definitions for S_struct (and serial_struct) flags field
*/
#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
on the callout port */
#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */
#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
#define S_SPD_MASK 0x0030
#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
#define S_SPD_CUST 0x0030 /* Use user-specified divisor */
#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
#define S_FLAGS 0x0FFF /* Possible legal S flags */
#define S_USR_MASK 0x0430 /* Legal flags that non-privileged
* users can set or reset */
/* Internal flags used only by kernel/chr_drv/serial.c */
#define S_INITIALIZED 0x80000000 /* Serial port was initialized */
#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
#define S_CLOSING 0x08000000 /* Serial port is closing */
#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */
/* Software state per channel */
#ifdef __KERNEL__
/*
* I believe this is the optimal setting that reduces the number of interrupts.
* At high speeds the output might become a little "bursted" (use USTCNT_TXHE
* if that bothers you), but in most cases it will not, since we try to
* transmit characters every time rs_interrupt is called. Thus, quite often
* you'll see that a receive interrupt occures before the transmit one.
* -- Vladimir Gurevich
*/
#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
/*
* 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
* "Old data interrupt" which occures whenever the data stay in the FIFO
* longer than 30 bits time. This allows us to use FIFO without compromising
* latency. '328 does not have this feature and without the real 328-based
* board I would assume that RXRE is the safest setting.
*
* For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
* interrupts. RXFE (receive queue full) causes the system to lose data
* at least at 115200 baud
*
* If your board is busy doing other stuff, you might consider to use
* RXRE (data ready intrrupt) instead.
*
* The other option is to make these INTR masks run-time configurable, so
* that people can dynamically adapt them according to the current usage.
* -- Vladimir Gurevich
*/
/* (es) */
#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
#elif defined(CONFIG_M68328)
#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
#else
#error Please, define the Rx interrupt events for your CPU
#endif
/* (/es) */
/*
* This is our internal structure for each serial port's state.
*
* Many fields are paralleled by the structure used by the serial_struct
* structure.
*
* For definitions of the flags field, see tty.h
*/
struct m68k_serial {
char soft_carrier; /* Use soft carrier on this channel */
char break_abort; /* Is serial console in, so process brk/abrt */
char is_cons; /* Is this our console. */
/* We need to know the current clock divisor
* to read the bps rate the chip has currently
* loaded.
*/
unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
int baud;
int magic;
int baud_base;
int port;
int irq;
int flags; /* defined in tty.h */
int type; /* UART type */
struct tty_struct *tty;
int read_status_mask;
int ignore_status_mask;
int timeout;
int xmit_fifo_size;
int custom_divisor;
int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned long event;
unsigned long last_active;
int line;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
};
#define SERIAL_MAGIC 0x5301
/*
* The size of the serial xmit buffer is 1 page, or 4096 bytes
*/
#define SERIAL_XMIT_SIZE 4096
/*
* Events are used to schedule things to happen at timer-interrupt
* time, instead of at rs interrupt time.
*/
#define RS_EVENT_WRITE_WAKEUP 0
/*
* Define the number of ports supported and their irqs.
*/
#define NR_PORTS 1
#define UART_IRQ_DEFNS {UART_IRQ_NUM}
#endif /* __KERNEL__ */
#endif /* !(_MC683XX_SERIAL_H) */
......@@ -568,6 +568,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
unsigned char fcr;
serial8250_clear_fifos(p);
fcr = uart_config[p->port.type].fcr;
serial_out(p, UART_FCR, fcr);
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
/*
* IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to
......@@ -1331,27 +1341,6 @@ static void serial8250_enable_ms(struct uart_port *port)
serial_port_out(port, UART_IER, up->ier);
}
/*
* Clear the Tegra rx fifo after a break
*
* FIXME: This needs to become a port specific callback once we have a
* framework for this
*/
static void clear_rx_fifo(struct uart_8250_port *up)
{
unsigned int status, tmout = 10000;
do {
status = serial_in(up, UART_LSR);
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
status = serial_in(up, UART_RX);
else
break;
if (--tmout == 0)
break;
udelay(1);
} while (1);
}
/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
......@@ -1386,19 +1375,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
up->lsr_saved_flags = 0;
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
/*
* For statistics only
*/
if (lsr & UART_LSR_BI) {
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
port->icount.brk++;
/*
* If tegra port then clear the rx fifo to
* accept another break/character.
*/
if (port->type == PORT_TEGRA)
clear_rx_fifo(up);
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
......@@ -3037,6 +3016,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq;
port.handle_break = p->handle_break;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
......@@ -3209,6 +3189,8 @@ int serial8250_register_port(struct uart_port *port)
uart->port.set_termios = port->set_termios;
if (port->pm)
uart->port.pm = port->pm;
if (port->handle_break)
uart->port.handle_break = port->handle_break;
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
......
......@@ -96,6 +96,8 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
up->port.serial_out(&up->port, offset, value);
}
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
* Digital did something really horribly wrong with the OUT1 and OUT2
......
......@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/tty.h>
#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/8250_pci.h>
#include <linux/bitops.h>
......@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx);
}
static void kt_handle_break(struct uart_port *p)
{
struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port);
/*
* On receipt of a BI, serial device in Intel ME (Intel
* management engine) needs to have its fifos cleared for sane
* SOL (Serial Over Lan) output.
*/
serial8250_clear_and_reinit_fifos(up);
}
static unsigned int kt_serial_in(struct uart_port *p, int offset)
{
struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port);
unsigned int val;
/*
* When the Intel ME (management engine) gets reset its serial
* port registers could return 0 momentarily. Functions like
* serial8250_console_write, read and save the IER, perform
* some operation and then restore it. In order to avoid
* setting IER register inadvertently to 0, if the value read
* is 0, double check with ier value in uart_8250_port and use
* that instead. up->ier should be the same value as what is
* currently configured.
*/
val = inb(p->iobase + offset);
if (offset == UART_IER) {
if (val == 0)
val = up->ier;
}
return val;
}
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
port->flags |= UPF_BUG_THRE;
port->serial_in = kt_serial_in;
port->handle_break = kt_handle_break;
return skip_tx_en_setup(priv, board, port, idx);
}
......@@ -2775,6 +2814,12 @@ void pciserial_suspend_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
/*
* Ensure that every init quirk is properly torn down
*/
if (priv->quirk->exit)
priv->quirk->exit(priv->dev);
}
EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
......
......@@ -67,30 +67,6 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
#define UART_WA_SAVE_NR 14
static void pl011_lockup_wa(unsigned long data);
static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
ST_UART011_DMAWM,
ST_UART011_TIMEOUT,
ST_UART011_LCRH_RX,
UART011_IBRD,
UART011_FBRD,
ST_UART011_LCRH_TX,
UART011_IFLS,
ST_UART011_XFCR,
ST_UART011_XON1,
ST_UART011_XON2,
ST_UART011_XOFF1,
ST_UART011_XOFF2,
UART011_CR,
UART011_IMSC
};
static u32 uart_wa_regdata[UART_WA_SAVE_NR];
static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
......@@ -100,6 +76,7 @@ struct vendor_data {
bool oversampling;
bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
bool cts_event_workaround;
};
static struct vendor_data vendor_arm = {
......@@ -109,6 +86,7 @@ static struct vendor_data vendor_arm = {
.lcrh_rx = UART011_LCRH,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
};
static struct vendor_data vendor_st = {
......@@ -119,6 +97,7 @@ static struct vendor_data vendor_st = {
.oversampling = true,
.interrupt_may_hang = true,
.dma_threshold = true,
.cts_event_workaround = true,
};
static struct uart_amba_port *amba_ports[UART_NR];
......@@ -1054,69 +1033,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#define pl011_dma_flush_buffer NULL
#endif
/*
* pl011_lockup_wa
* This workaround aims to break the deadlock situation
* when after long transfer over uart in hardware flow
* control, uart interrupt registers cannot be cleared.
* Hence uart transfer gets blocked.
*
* It is seen that during such deadlock condition ICR
* don't get cleared even on multiple write. This leads
* pass_counter to decrease and finally reach zero. This
* can be taken as trigger point to run this UART_BT_WA.
*
*/
static void pl011_lockup_wa(unsigned long data)
{
struct uart_amba_port *uap = amba_ports[0];
void __iomem *base = uap->port.membase;
struct circ_buf *xmit = &uap->port.state->xmit;
struct tty_struct *tty = uap->port.state->port.tty;
int buf_empty_retries = 200;
int loop;
/* Stop HCI layer from submitting data for tx */
tty->hw_stopped = 1;
while (!uart_circ_empty(xmit)) {
if (buf_empty_retries-- == 0)
break;
udelay(100);
}
/* Backup registers */
for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
/* Disable UART so that FIFO data is flushed out */
writew(0x00, uap->port.membase + UART011_CR);
/* Soft reset UART module */
if (uap->port.dev->platform_data) {
struct amba_pl011_data *plat;
plat = uap->port.dev->platform_data;
if (plat->reset)
plat->reset();
}
/* Restore registers */
for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
writew(uart_wa_regdata[loop] ,
uap->port.membase + uart_wa_reg[loop]);
/* Initialise the old status of the modem signals */
uap->old_status = readw(uap->port.membase + UART01x_FR) &
UART01x_FR_MODEM_ANY;
if (readl(base + UART011_MIS) & 0x2)
printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
/* Start Tx/Rx */
tty->hw_stopped = 0;
}
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
......@@ -1245,12 +1161,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags);
status = readw(uap->port.membase + UART011_MIS);
if (status) {
do {
if (uap->vendor->cts_event_workaround) {
/* workaround to make sure that all bits are unlocked.. */
writew(0x00, uap->port.membase + UART011_ICR);
/*
* WA: introduce 26ns(1 uart clk) delay before W1C;
* single apb access will incur 2 pclk(133.12Mhz) delay,
* so add 2 dummy reads
*/
dummy_read = readw(uap->port.membase + UART011_ICR);
dummy_read = readw(uap->port.membase + UART011_ICR);
}
writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS),
uap->port.membase + UART011_ICR);
......@@ -1267,11 +1197,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & UART011_TXIS)
pl011_tx_chars(uap);
if (pass_counter-- == 0) {
if (uap->interrupt_may_hang)
tasklet_schedule(&pl011_lockup_tlet);
if (pass_counter-- == 0)
break;
}
status = readw(uap->port.membase + UART011_MIS);
} while (status != 0);
......
......@@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Input */
#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
* lock it in case the memcpy_fromfs blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf;
static DEFINE_MUTEX(tmp_buf_mutex);
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info)
{
......@@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,
/* first some sanity checks */
if (!tty || !info->xmit.buf || !tmp_buf)
if (!tty || !info->xmit.buf)
return 0;
#ifdef SERIAL_DEBUG_DATA
......@@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
{
struct e100_serial *info;
int retval;
unsigned long page;
int allocated_resources = 0;
info = rs_table + tty->index;
......@@ -4124,17 +4110,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
if (!tmp_buf) {
page = get_zeroed_page(GFP_KERNEL);
if (!page) {
return -ENOMEM;
}
if (tmp_buf)
free_page(page);
else
tmp_buf = (unsigned char *) page;
}
/*
* If the port is in the middle of closing, bail out now
*/
......@@ -4487,6 +4462,7 @@ static int __init rs_init(void)
info->enabled = 0;
}
}
tty_port_init(&info->port);
info->uses_dma_in = 0;
info->uses_dma_out = 0;
info->line = i;
......
......@@ -12,10 +12,13 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_serial.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
......@@ -24,6 +27,26 @@ struct of_serial_info {
int line;
};
#ifdef CONFIG_ARCH_TEGRA
void tegra_serial_handle_break(struct uart_port *p)
{
unsigned int status, tmout = 10000;
do {
status = p->serial_in(p, UART_LSR);
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
status = p->serial_in(p, UART_RX);
else
break;
if (--tmout == 0)
break;
udelay(1);
} while (1);
}
/* FIXME remove this export when tegra finishes conversion to open firmware */
EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
#endif
/*
* Fill a struct uart_port for a given device node
*/
......@@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->dev = &ofdev->dev;
if (type == PORT_TEGRA)
port->handle_break = tegra_serial_handle_break;
return 0;
}
......
......@@ -44,6 +44,13 @@
#include <plat/dmtimer.h>
#include <plat/omap-serial.h>
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
#define OMAP_UART_REV_42 0x0402
#define OMAP_UART_REV_46 0x0406
#define OMAP_UART_REV_52 0x0502
#define OMAP_UART_REV_63 0x0603
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
/* SCR register bitmasks */
......@@ -53,6 +60,17 @@
#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
/* MVR register bitmasks */
#define OMAP_UART_MVR_SCHEME_SHIFT 30
#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0
#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4
#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f
#define OMAP_UART_MVR_MAJ_MASK 0x700
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
......@@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
return;
}
static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
u32 mvr, scheme;
u16 revision, major, minor;
mvr = serial_in(up, UART_OMAP_MVER);
/* Check revision register scheme */
scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
switch (scheme) {
case 0: /* Legacy Scheme: OMAP2/3 */
/* MINOR_REV[0:4], MAJOR_REV[4:7] */
major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
break;
case 1:
/* New Scheme: OMAP4+ */
/* MINOR_REV[0:5], MAJOR_REV[8:10] */
major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
OMAP_UART_MVR_MAJ_SHIFT;
minor = (mvr & OMAP_UART_MVR_MIN_MASK);
break;
default:
dev_warn(&up->pdev->dev,
"Unknown %s revision, defaulting to highest\n",
up->name);
/* highest possible revision */
major = 0xff;
minor = 0xff;
}
/* normalize revision for the driver */
revision = UART_BUILD_REVISION(major, minor);
switch (revision) {
case OMAP_UART_REV_46:
up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
UART_ERRATA_i291_DMA_FORCEIDLE);
break;
case OMAP_UART_REV_52:
up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
UART_ERRATA_i291_DMA_FORCEIDLE);
break;
case OMAP_UART_REV_63:
up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
break;
default:
break;
}
}
static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{
struct omap_uart_port_info *omap_up_info;
......@@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)
"%d\n", DEFAULT_CLK_SPEED);
}
up->uart_dma.uart_base = mem->start;
up->errata = omap_up_info->errata;
if (omap_up_info->dma_enabled) {
up->uart_dma.uart_dma_tx = dma_tx->start;
......@@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(up);
ui[up->port.line] = up;
serial_omap_add_console_port(up);
......
......@@ -39,6 +39,7 @@ enum {
PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
PCH_UART_HANDLED_MS_INT_SHIFT,
PCH_UART_HANDLED_LS_INT_SHIFT,
};
enum {
......@@ -63,6 +64,8 @@ enum {
PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1))
#define PCH_UART_RBR 0x00
#define PCH_UART_THR 0x00
......@@ -229,7 +232,6 @@ struct eg20t_port {
int start_tx;
int start_rx;
int tx_empty;
int int_dis_flag;
int trigger;
int trigger_level;
struct pch_uart_buffer rxbuf;
......@@ -237,7 +239,6 @@ struct eg20t_port {
unsigned int fcr;
unsigned int mcr;
unsigned int use_dma;
unsigned int use_dma_flag;
struct dma_async_tx_descriptor *desc_tx;
struct dma_async_tx_descriptor *desc_rx;
struct pch_dma_slave param_tx;
......@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
return i;
}
static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv)
{
unsigned int iir;
int ret;
iir = ioread8(priv->membase + UART_IIR);
ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
return ret;
return ioread8(priv->membase + UART_IIR) &\
(PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
}
static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
......@@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)
dma_release_channel(priv->chan_rx);
priv->chan_rx = NULL;
}
if (sg_dma_address(&priv->sg_rx))
dma_free_coherent(port->dev, port->fifosize,
sg_virt(&priv->sg_rx),
sg_dma_address(&priv->sg_rx));
if (priv->rx_buf_dma) {
dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
priv->rx_buf_dma);
priv->rx_buf_virt = NULL;
priv->rx_buf_dma = 0;
}
return;
}
......@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
unsigned int handled;
u8 lsr;
int ret = 0;
unsigned int iid;
unsigned char iid;
unsigned long flags;
int next = 1;
u8 msr;
spin_lock_irqsave(&priv->port.lock, flags);
handled = 0;
while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
while (next) {
iid = pch_uart_hal_get_iid(priv);
if (iid & PCH_UART_IIR_IP) /* No Interrupt */
break;
switch (iid) {
case PCH_UART_IID_RLS: /* Receiver Line Status */
lsr = pch_uart_hal_get_line_status(priv);
......@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
UART_LSR_PE | UART_LSR_OE)) {
pch_uart_err_ir(priv, lsr);
ret = PCH_UART_HANDLED_RX_ERR_INT;
} else {
ret = PCH_UART_HANDLED_LS_INT;
}
break;
case PCH_UART_IID_RDR: /* Received Data Ready */
......@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
ret = handle_tx(priv);
break;
case PCH_UART_IID_MS: /* Modem Status */
ret = PCH_UART_HANDLED_MS_INT;
msr = pch_uart_hal_get_modem(priv);
next = 0; /* MS ir prioirty is the lowest. So, MS ir
means final interrupt */
if ((msr & UART_MSR_ANY_DELTA) == 0)
break;
ret |= PCH_UART_HANDLED_MS_INT;
break;
default: /* Never junp to this label */
dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
iid, jiffies);
ret = -1;
next = 0;
break;
}
handled |= (unsigned int)ret;
}
if (handled == 0 && iid <= 1) {
if (priv->int_dis_flag)
priv->int_dis_flag = 0;
}
spin_unlock_irqrestore(&priv->port.lock, flags);
return IRQ_RETVAL(handled);
......@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)
priv = container_of(port, struct eg20t_port, port);
priv->start_rx = 0;
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
priv->int_dis_flag = 1;
}
/* Enable the modem status interrupts. */
......@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,
__func__);
return -EOPNOTSUPP;
#endif
priv->use_dma_flag = 1;
dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
if (!priv->use_dma)
pch_request_dma(port);
......
......@@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
/**
* tty_buffer_request_room - grow tty buffer if needed
* __tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
* Locking: Takes tty->buf.lock
* Locking: Caller must hold tty->buf.lock
*/
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
int left;
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
......@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
size = left;
}
spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
/**
* tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
* Locking: Takes tty->buf.lock
*/
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
unsigned long flags;
int length;
spin_lock_irqsave(&tty->buf.lock, flags);
length = __tty_buffer_request_room(tty, size);
spin_unlock_irqrestore(&tty->buf.lock, flags);
return length;
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
......@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(tty, goal);
struct tty_buffer *tb = tty->buf.tail;
int space;
unsigned long flags;
struct tty_buffer *tb;
spin_lock_irqsave(&tty->buf.lock, flags);
space = __tty_buffer_request_room(tty, goal);
tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0))
if (unlikely(space == 0)) {
spin_unlock_irqrestore(&tty->buf.lock, flags);
break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
spin_unlock_irqrestore(&tty->buf.lock, flags);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
......@@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(tty, goal);
struct tty_buffer *tb = tty->buf.tail;
int space;
unsigned long __flags;
struct tty_buffer *tb;
spin_lock_irqsave(&tty->buf.lock, __flags);
space = __tty_buffer_request_room(tty, goal);
tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0))
if (unlikely(space == 0)) {
spin_unlock_irqrestore(&tty->buf.lock, __flags);
break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space;
spin_unlock_irqrestore(&tty->buf.lock, __flags);
copied += space;
chars += space;
flags += space;
......@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
size_t size)
{
int space = tty_buffer_request_room(tty, size);
int space;
unsigned long flags;
struct tty_buffer *tb;
spin_lock_irqsave(&tty->buf.lock, flags);
space = __tty_buffer_request_room(tty, size);
tb = tty->buf.tail;
if (likely(space)) {
struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space;
}
spin_unlock_irqrestore(&tty->buf.lock, flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
......@@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
int space = tty_buffer_request_room(tty, size);
int space;
unsigned long __flags;
struct tty_buffer *tb;
spin_lock_irqsave(&tty->buf.lock, __flags);
space = __tty_buffer_request_room(tty, size);
tb = tty->buf.tail;
if (likely(space)) {
struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used;
tb->used += space;
}
spin_unlock_irqrestore(&tty->buf.lock, __flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
......
......@@ -3892,25 +3892,28 @@ static void set_palette(struct vc_data *vc)
vc->vc_sw->con_set_palette(vc, color_table);
}
static int set_get_cmap(unsigned char __user *arg, int set)
/*
* Load palette into the DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
*/
int con_set_cmap(unsigned char __user *arg)
{
int i, j, k;
unsigned char colormap[3*16];
WARN_CONSOLE_UNLOCKED();
if (copy_from_user(colormap, arg, sizeof(colormap)))
return -EFAULT;
for (i = 0; i < 16; i++)
if (set) {
get_user(default_red[i], arg++);
get_user(default_grn[i], arg++);
get_user(default_blu[i], arg++);
} else {
put_user(default_red[i], arg++);
put_user(default_grn[i], arg++);
put_user(default_blu[i], arg++);
console_lock();
for (i = k = 0; i < 16; i++) {
default_red[i] = colormap[k++];
default_grn[i] = colormap[k++];
default_blu[i] = colormap[k++];
}
if (set) {
for (i = 0; i < MAX_NR_CONSOLES; i++)
if (vc_cons_allocated(i)) {
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
for (j = k = 0; j < 16; j++) {
vc_cons[i].d->vc_palette[k++] = default_red[j];
vc_cons[i].d->vc_palette[k++] = default_grn[j];
......@@ -3918,35 +3921,28 @@ static int set_get_cmap(unsigned char __user *arg, int set)
}
set_palette(vc_cons[i].d);
}
}
return 0;
}
/*
* Load palette into the DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
*/
int con_set_cmap(unsigned char __user *arg)
{
int rc;
console_lock();
rc = set_get_cmap (arg,1);
console_unlock();
return rc;
return 0;
}
int con_get_cmap(unsigned char __user *arg)
{
int rc;
int i, k;
unsigned char colormap[3*16];
console_lock();
rc = set_get_cmap (arg,0);
for (i = k = 0; i < 16; i++) {
colormap[k++] = default_red[i];
colormap[k++] = default_grn[i];
colormap[k++] = default_blu[i];
}
console_unlock();
return rc;
if (copy_to_user(arg, colormap, sizeof(colormap)))
return -EFAULT;
return 0;
}
void reset_palette(struct vc_data *vc)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef __LINUX_OF_SERIAL_H
#define __LINUX_OF_SERIAL_H
/*
* FIXME remove this file when tegra finishes conversion to open firmware,
* expectation is that all quirks will then be self-contained in
* drivers/tty/serial/of_serial.c.
*/
#ifdef CONFIG_ARCH_TEGRA
extern void tegra_serial_handle_break(struct uart_port *port);
#else
static inline void tegra_serial_handle_break(struct uart_port *port)
{
}
#endif
#endif /* __LINUX_OF_SERIAL */
......@@ -38,6 +38,7 @@ struct plat_serial8250_port {
int (*handle_irq)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned old);
void (*handle_break)(struct uart_port *);
};
/*
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment