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, ...@@ -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.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout; 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 = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info); pdata_size = sizeof(struct omap_uart_port_info);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/pda_power.h> #include <linux/pda_power.h>
...@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { ...@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTD, .irq = INT_UARTD,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA, .type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = 216000000, .uartclk = 216000000,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
...@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { ...@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTA, .irq = INT_UARTA,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA, .type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = 216000000, .uartclk = 216000000,
...@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { ...@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTC, .irq = INT_UARTC,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA, .type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = 216000000, .uartclk = 216000000,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/input.h> #include <linux/input.h>
...@@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { ...@@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
/* Memory and IRQ filled in before registration */ /* Memory and IRQ filled in before registration */
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA, .type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = 216000000, .uartclk = 216000000,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/of_serial.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { ...@@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTA, .irq = INT_UARTA,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA, .type = PORT_TEGRA,
.handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = 216000000, .uartclk = 216000000,
......
...@@ -65,7 +65,6 @@ struct omap_uart_port_info { ...@@ -65,7 +65,6 @@ struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */ bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */ unsigned int uartclk; /* UART clock rate */
upf_t flags; /* UPF_* flags */ upf_t flags; /* UPF_* flags */
u32 errata;
unsigned int dma_rx_buf_size; unsigned int dma_rx_buf_size;
unsigned int dma_rx_timeout; unsigned int dma_rx_timeout;
unsigned int autosuspend_timeout; unsigned int autosuspend_timeout;
......
...@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex); ...@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
static char *isdn_revision = "$Revision: 1.1.2.3 $"; static char *isdn_revision = "$Revision: 1.1.2.3 $";
extern char *isdn_net_revision; extern char *isdn_net_revision;
extern char *isdn_tty_revision;
#ifdef CONFIG_ISDN_PPP #ifdef CONFIG_ISDN_PPP
extern char *isdn_ppp_revision; extern char *isdn_ppp_revision;
#else #else
...@@ -2327,8 +2326,6 @@ static int __init isdn_init(void) ...@@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
dev->chanmap[i] = -1; dev->chanmap[i] = -1;
dev->m_idx[i] = -1; dev->m_idx[i] = -1;
strcpy(dev->num[i], "???"); 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)) { if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
printk(KERN_WARNING "isdn: Could not register control devices\n"); printk(KERN_WARNING "isdn: Could not register control devices\n");
...@@ -2353,8 +2350,6 @@ static int __init isdn_init(void) ...@@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
strcpy(tmprev, isdn_revision); strcpy(tmprev, isdn_revision);
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev)); 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); strcpy(tmprev, isdn_net_revision);
printk("%s/", isdn_getrev(tmprev)); printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_ppp_revision); 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) ...@@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
if (ch == ' ' || ch == d) if (ch == ' ' || ch == d)
return d; return d;
kbd_put_queue(kbd->tty, d); kbd_put_queue(kbd->port, d);
return ch; return ch;
} }
...@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value) ...@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
{ {
if (kbd->diacr) if (kbd->diacr)
value = handle_diacr(kbd, value); value = handle_diacr(kbd, value);
kbd_put_queue(kbd->tty, value); kbd_put_queue(kbd->port, value);
} }
/* /*
...@@ -239,7 +239,7 @@ static void ...@@ -239,7 +239,7 @@ static void
k_fn(struct kbd_data *kbd, unsigned char value) k_fn(struct kbd_data *kbd, unsigned char value)
{ {
if (kbd->func_table[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 static void
...@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value) ...@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
* but we need only 16 bits here * but we need only 16 bits here
*/ */
static void static void
to_utf8(struct tty_struct *tty, ushort c) to_utf8(struct tty_port *port, ushort c)
{ {
if (c < 0x80) if (c < 0x80)
/* 0******* */ /* 0******* */
kbd_put_queue(tty, c); kbd_put_queue(port, c);
else if (c < 0x800) { else if (c < 0x800) {
/* 110***** 10****** */ /* 110***** 10****** */
kbd_put_queue(tty, 0xc0 | (c >> 6)); kbd_put_queue(port, 0xc0 | (c >> 6));
kbd_put_queue(tty, 0x80 | (c & 0x3f)); kbd_put_queue(port, 0x80 | (c & 0x3f));
} else { } else {
/* 1110**** 10****** 10****** */ /* 1110**** 10****** 10****** */
kbd_put_queue(tty, 0xe0 | (c >> 12)); kbd_put_queue(port, 0xe0 | (c >> 12));
kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f)); kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
kbd_put_queue(tty, 0x80 | (c & 0x3f)); kbd_put_queue(port, 0x80 | (c & 0x3f));
} }
} }
...@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) ...@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
unsigned short keysym; unsigned short keysym;
unsigned char type, value; unsigned char type, value;
if (!kbd || !kbd->tty) if (!kbd)
return; return;
if (keycode >= 384) if (keycode >= 384)
...@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) ...@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
#endif #endif
(*k_handler[type])(kbd, value); (*k_handler[type])(kbd, value);
} else } 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, ...@@ -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) int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
{ {
struct tty_struct *tty;
void __user *argp; void __user *argp;
unsigned int ct; unsigned int ct;
int perm; int perm;
...@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg) ...@@ -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 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. * 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) { switch (cmd) {
case KDGKBTYPE: case KDGKBTYPE:
return put_user(KB_101, (char __user *)argp); return put_user(KB_101, (char __user *)argp);
......
...@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *); ...@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
*/ */
struct kbd_data { struct kbd_data {
struct tty_struct *tty; struct tty_port *port;
unsigned short **key_maps; unsigned short **key_maps;
char **func_table; char **func_table;
fn_handler_fn **fn_handler; fn_handler_fn **fn_handler;
...@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long); ...@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
* Helper Functions. * Helper Functions.
*/ */
static inline void 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_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty); tty_schedule_flip(tty);
tty_kref_put(tty);
} }
static inline void 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) while (*cp)
tty_insert_flip_char(tty, *cp++, 0); tty_insert_flip_char(tty, *cp++, 0);
tty_schedule_flip(tty); tty_schedule_flip(tty);
tty_kref_put(tty);
} }
...@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf; ...@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
/* Timer for delayed output of console messages. */ /* Timer for delayed output of console messages. */
static struct timer_list sclp_tty_timer; 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 char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
static unsigned short int sclp_tty_chars_count; static unsigned short int sclp_tty_chars_count;
...@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80; ...@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
static int static int
sclp_tty_open(struct tty_struct *tty, struct file *filp) 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->driver_data = NULL;
tty->low_latency = 0; tty->low_latency = 0;
return 0; return 0;
...@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
{ {
if (tty->count > 1) if (tty->count > 1)
return; return;
sclp_tty = NULL; tty_port_tty_set(&sclp_port, NULL);
} }
/* /*
...@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty) ...@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
static void static void
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
{ {
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
void *page; void *page;
...@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) ...@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
spin_unlock_irqrestore(&sclp_tty_lock, flags); spin_unlock_irqrestore(&sclp_tty_lock, flags);
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback)); } while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
/* check if the tty needs a wake up call */ /* check if the tty needs a wake up call */
if (sclp_tty != NULL) { tty = tty_port_tty_get(&sclp_port);
tty_wakeup(sclp_tty); if (tty != NULL) {
tty_wakeup(tty);
tty_kref_put(tty);
} }
} }
...@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty) ...@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
static void static void
sclp_tty_input(unsigned char* buf, unsigned int count) sclp_tty_input(unsigned char* buf, unsigned int count)
{ {
struct tty_struct *tty = tty_port_tty_get(&sclp_port);
unsigned int cchar; unsigned int cchar;
/* /*
* If this tty driver is currently closed * If this tty driver is currently closed
* then throw the received input away. * then throw the received input away.
*/ */
if (sclp_tty == NULL) if (tty == NULL)
return; return;
cchar = ctrlchar_handle(buf, count, sclp_tty); cchar = ctrlchar_handle(buf, count, tty);
switch (cchar & CTRLCHAR_MASK) { switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ: case CTRLCHAR_SYSRQ:
break; break;
case CTRLCHAR_CTRL: case CTRLCHAR_CTRL:
tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL); tty_insert_flip_char(tty, cchar, TTY_NORMAL);
tty_flip_buffer_push(sclp_tty); tty_flip_buffer_push(tty);
break; break;
case CTRLCHAR_NONE: case CTRLCHAR_NONE:
/* send (normal) input to line discipline */ /* send (normal) input to line discipline */
...@@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count) ...@@ -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, "^n", 2) &&
strncmp((const char *) buf + count - 2, "\252n", 2))) { strncmp((const char *) buf + count - 2, "\252n", 2))) {
/* add the auto \n */ /* add the auto \n */
tty_insert_flip_string(sclp_tty, buf, count); tty_insert_flip_string(tty, buf, count);
tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL); tty_insert_flip_char(tty, '\n', TTY_NORMAL);
} else } else
tty_insert_flip_string(sclp_tty, buf, count - 2); tty_insert_flip_string(tty, buf, count - 2);
tty_flip_buffer_push(sclp_tty); tty_flip_buffer_push(tty);
break; break;
} }
tty_kref_put(tty);
} }
/* /*
...@@ -543,7 +548,7 @@ sclp_tty_init(void) ...@@ -543,7 +548,7 @@ sclp_tty_init(void)
sclp_tty_tolower = 1; sclp_tty_tolower = 1;
} }
sclp_tty_chars_count = 0; sclp_tty_chars_count = 0;
sclp_tty = NULL; tty_port_init(&sclp_port);
rc = sclp_register(&sclp_input_event); rc = sclp_register(&sclp_input_event);
if (rc) { if (rc) {
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#define SCLP_VT220_DEVICE_NAME "ttysclp" #define SCLP_VT220_DEVICE_NAME "ttysclp"
#define SCLP_VT220_CONSOLE_NAME "ttyS" #define SCLP_VT220_CONSOLE_NAME "ttyS"
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */ #define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
#define SCLP_VT220_BUF_SIZE 80
/* Representation of a single write request */ /* Representation of a single write request */
struct sclp_vt220_request { struct sclp_vt220_request {
...@@ -56,8 +55,7 @@ struct sclp_vt220_sccb { ...@@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
/* Structures and data needed to register tty driver */ /* Structures and data needed to register tty driver */
static struct tty_driver *sclp_vt220_driver; static struct tty_driver *sclp_vt220_driver;
/* The tty_struct that the kernel associated with us */ static struct tty_port sclp_vt220_port;
static struct tty_struct *sclp_vt220_tty;
/* Lock to protect internal data from concurrent access */ /* Lock to protect internal data from concurrent access */
static spinlock_t sclp_vt220_lock; static spinlock_t sclp_vt220_lock;
...@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = { ...@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
static void static void
sclp_vt220_process_queue(struct sclp_vt220_request *request) sclp_vt220_process_queue(struct sclp_vt220_request *request)
{ {
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
void *page; void *page;
...@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) ...@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
if (request == NULL && sclp_vt220_flush_later) if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current(); sclp_vt220_emit_current();
/* Check if the tty needs a wake up call */ /* Check if the tty needs a wake up call */
if (sclp_vt220_tty != NULL) { tty = tty_port_tty_get(&sclp_vt220_port);
tty_wakeup(sclp_vt220_tty); 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) ...@@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
static void static void
sclp_vt220_receiver_fn(struct evbuf_header *evbuf) sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
{ {
struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
char *buffer; char *buffer;
unsigned int count; unsigned int count;
/* Ignore input if device is not open */ /* Ignore input if device is not open */
if (sclp_vt220_tty == NULL) if (tty == NULL)
return; return;
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header)); buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
...@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf) ...@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
/* Send input to line discipline */ /* Send input to line discipline */
buffer++; buffer++;
count--; count--;
tty_insert_flip_string(sclp_vt220_tty, buffer, count); tty_insert_flip_string(tty, buffer, count);
tty_flip_buffer_push(sclp_vt220_tty); tty_flip_buffer_push(tty);
break; break;
} }
tty_kref_put(tty);
} }
/* /*
...@@ -491,10 +494,7 @@ static int ...@@ -491,10 +494,7 @@ static int
sclp_vt220_open(struct tty_struct *tty, struct file *filp) sclp_vt220_open(struct tty_struct *tty, struct file *filp)
{ {
if (tty->count == 1) { if (tty->count == 1) {
sclp_vt220_tty = tty; tty_port_tty_set(&sclp_vt220_port, tty);
tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
if (tty->driver_data == NULL)
return -ENOMEM;
tty->low_latency = 0; tty->low_latency = 0;
if (!tty->winsize.ws_row && !tty->winsize.ws_col) { if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = 24; tty->winsize.ws_row = 24;
...@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp) ...@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
static void static void
sclp_vt220_close(struct tty_struct *tty, struct file *filp) sclp_vt220_close(struct tty_struct *tty, struct file *filp)
{ {
if (tty->count == 1) { if (tty->count == 1)
sclp_vt220_tty = NULL; tty_port_tty_set(&sclp_vt220_port, NULL);
kfree(tty->driver_data);
tty->driver_data = NULL;
}
} }
/* /*
...@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages) ...@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
INIT_LIST_HEAD(&sclp_vt220_empty); INIT_LIST_HEAD(&sclp_vt220_empty);
INIT_LIST_HEAD(&sclp_vt220_outqueue); INIT_LIST_HEAD(&sclp_vt220_outqueue);
init_timer(&sclp_vt220_timer); init_timer(&sclp_vt220_timer);
tty_port_init(&sclp_vt220_port);
sclp_vt220_current_request = NULL; sclp_vt220_current_request = NULL;
sclp_vt220_buffered_chars = 0; sclp_vt220_buffered_chars = 0;
sclp_vt220_tty = NULL;
sclp_vt220_flush_later = 0; sclp_vt220_flush_later = 0;
/* Allocate pages for output buffering */ /* 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) ...@@ -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 tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread; static struct task_struct *bfin_jc_kthread;
static struct tty_struct * volatile bfin_jc_tty; static struct tty_port port;
static unsigned long bfin_jc_count;
static DEFINE_MUTEX(bfin_jc_tty_mutex);
static volatile struct circ_buf bfin_jc_write_buf; static volatile struct circ_buf bfin_jc_write_buf;
static int static int
...@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg) ...@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
uint32_t inbound_len = 0, outbound_len = 0; uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
struct tty_struct *tty = tty_port_tty_get(&port);
/* no one left to give data to, so sleep */ /* 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"); pr_debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE); __set_current_state(TASK_UNINTERRUPTIBLE);
schedule(); schedule();
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
continue;
} }
/* no data available, so just chill */ /* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
tty_kref_put(tty);
if (inbound_len) if (inbound_len)
schedule(); schedule();
else else
...@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg) ...@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
/* if incoming data is ready, eat it */ /* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) { 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) { if (tty != NULL) {
uint32_t emudat = bfin_read_emudat(); uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) { if (inbound_len == 0) {
...@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg) ...@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }
} }
mutex_unlock(&bfin_jc_tty_mutex);
} }
/* if outgoing data is ready, post it */ /* if outgoing data is ready, post it */
...@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg) ...@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
bfin_write_emudat(outbound_len); bfin_write_emudat(outbound_len);
pr_debug("outgoing length: 0x%08x\n", outbound_len); pr_debug("outgoing length: 0x%08x\n", outbound_len);
} else { } else {
struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail; int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len); size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat = uint32_t emudat =
...@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg) ...@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
); );
bfin_jc_write_buf.tail += ate; bfin_jc_write_buf.tail += ate;
outbound_len -= ate; outbound_len -= ate;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty) if (tty)
tty_wakeup(tty); tty_wakeup(tty);
mutex_unlock(&bfin_jc_tty_mutex);
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
} }
} }
tty_kref_put(tty);
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
...@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg) ...@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
static int static int
bfin_jc_open(struct tty_struct *tty, struct file *filp) bfin_jc_open(struct tty_struct *tty, struct file *filp)
{ {
mutex_lock(&bfin_jc_tty_mutex); unsigned long flags;
pr_debug("open %lu\n", bfin_jc_count);
++bfin_jc_count; spin_lock_irqsave(&port.lock, flags);
bfin_jc_tty = tty; port.count++;
spin_unlock_irqrestore(&port.lock, flags);
tty_port_tty_set(&port, tty);
wake_up_process(bfin_jc_kthread); wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
return 0; return 0;
} }
static void static void
bfin_jc_close(struct tty_struct *tty, struct file *filp) bfin_jc_close(struct tty_struct *tty, struct file *filp)
{ {
mutex_lock(&bfin_jc_tty_mutex); unsigned long flags;
pr_debug("close %lu\n", bfin_jc_count); bool last;
if (--bfin_jc_count == 0)
bfin_jc_tty = NULL; 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); 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 */ /* 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) ...@@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
{ {
int ret; int ret;
tty_port_init(&port);
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread)) if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread); return PTR_ERR(bfin_jc_kthread);
......
...@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index) ...@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
list_for_each_entry(hp, &hvc_structs, next) { list_for_each_entry(hp, &hvc_structs, next) {
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (hp->index == index) { if (hp->index == index) {
kref_get(&hp->kref); tty_port_get(&hp->port);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
spin_unlock(&hvc_structs_lock); spin_unlock(&hvc_structs_lock);
return hp; return hp;
...@@ -229,9 +229,9 @@ static int __init hvc_console_init(void) ...@@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
console_initcall(hvc_console_init); console_initcall(hvc_console_init);
/* callback when the kboject ref count reaches zero. */ /* 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; unsigned long flags;
spin_lock(&hvc_structs_lock); spin_lock(&hvc_structs_lock);
...@@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) ...@@ -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 */ /* make sure no no tty has been registered in this index */
hp = hvc_get_by_index(index); hp = hvc_get_by_index(index);
if (hp) { if (hp) {
kref_put(&hp->kref, destroy_hvc_struct); tty_port_put(&hp->port);
return -1; return -1;
} }
...@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) ...@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (!(hp = hvc_get_by_index(tty->index))) if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV; return -ENODEV;
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */ /* Check and then increment for fast path open. */
if (hp->count++ > 0) { if (hp->port.count++ > 0) {
tty_kref_get(tty); spin_unlock_irqrestore(&hp->port.lock, flags);
spin_unlock_irqrestore(&hp->lock, flags);
hvc_kick(); hvc_kick();
return 0; return 0;
} /* else count == 0 */ } /* else count == 0 */
spin_unlock_irqrestore(&hp->port.lock, flags);
tty->driver_data = hp; tty->driver_data = hp;
tty_port_tty_set(&hp->port, tty);
hp->tty = tty_kref_get(tty);
spin_unlock_irqrestore(&hp->lock, flags);
if (hp->ops->notifier_add) if (hp->ops->notifier_add)
rc = hp->ops->notifier_add(hp, hp->data); rc = hp->ops->notifier_add(hp, hp->data);
...@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) ...@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
* tty fields and return the kref reference. * tty fields and return the kref reference.
*/ */
if (rc) { if (rc) {
spin_lock_irqsave(&hp->lock, flags); tty_port_tty_set(&hp->port, NULL);
hp->tty = NULL;
spin_unlock_irqrestore(&hp->lock, flags);
tty_kref_put(tty);
tty->driver_data = 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); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
} }
/* Force wakeup of the polling thread */ /* Force wakeup of the polling thread */
...@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) ...@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp = tty->driver_data; 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. */ /* We are done with the tty pointer now. */
hp->tty = NULL; tty_port_tty_set(&hp->port, NULL);
spin_unlock_irqrestore(&hp->lock, flags);
if (hp->ops->notifier_del) if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data); hp->ops->notifier_del(hp, hp->data);
...@@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) ...@@ -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); tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
} else { } else {
if (hp->count < 0) if (hp->port.count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n", printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
hp->vtermno, hp->count); hp->vtermno, hp->port.count);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->port.lock, flags);
} }
tty_kref_put(tty); tty_port_put(&hp->port);
kref_put(&hp->kref, destroy_hvc_struct);
} }
static void hvc_hangup(struct tty_struct *tty) static void hvc_hangup(struct tty_struct *tty)
...@@ -412,32 +405,31 @@ 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 pending tty resize work */
cancel_work_sync(&hp->tty_resize); 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 * 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 * open->hangup case this can be called after the final close so prevent
* that from happening for now. * that from happening for now.
*/ */
if (hp->count <= 0) { if (hp->port.count <= 0) {
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->port.lock, flags);
return; return;
} }
temp_open_count = hp->count; temp_open_count = hp->port.count;
hp->count = 0; hp->port.count = 0;
hp->n_outbuf = 0; spin_unlock_irqrestore(&hp->port.lock, flags);
hp->tty = NULL; tty_port_tty_set(&hp->port, NULL);
spin_unlock_irqrestore(&hp->lock, flags); hp->n_outbuf = 0;
if (hp->ops->notifier_hangup) if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data); hp->ops->notifier_hangup(hp, hp->data);
while(temp_open_count) { while(temp_open_count) {
--temp_open_count; --temp_open_count;
tty_kref_put(tty); tty_port_put(&hp->port);
kref_put(&hp->kref, destroy_hvc_struct);
} }
} }
...@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count ...@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (!hp) if (!hp)
return -EPIPE; return -EPIPE;
if (hp->count <= 0) /* FIXME what's this (unprotected) check for? */
if (hp->port.count <= 0)
return -EIO; return -EIO;
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
...@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work) ...@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
hp = container_of(work, struct hvc_struct, tty_resize); hp = container_of(work, struct hvc_struct, tty_resize);
spin_lock_irqsave(&hp->lock, hvc_flags); tty = tty_port_tty_get(&hp->port);
if (!hp->tty) { if (!tty)
spin_unlock_irqrestore(&hp->lock, hvc_flags);
return; return;
}
ws = hp->ws; spin_lock_irqsave(&hp->lock, hvc_flags);
tty = tty_kref_get(hp->tty); ws = hp->ws;
spin_unlock_irqrestore(&hp->lock, hvc_flags); spin_unlock_irqrestore(&hp->lock, hvc_flags);
tty_do_resize(tty, &ws); tty_do_resize(tty, &ws);
...@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp) ...@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
} }
/* No tty attached, just skip */ /* No tty attached, just skip */
tty = tty_kref_get(hp->tty); tty = tty_port_tty_get(&hp->port);
if (tty == NULL) if (tty == NULL)
goto bail; goto bail;
...@@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp) ...@@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }
if (tty) tty_kref_put(tty);
tty_kref_put(tty);
return poll_mask; return poll_mask;
} }
...@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = { ...@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
#endif #endif
}; };
static const struct tty_port_operations hvc_port_ops = {
.destruct = hvc_port_destruct,
};
struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
const struct hv_ops *ops, const struct hv_ops *ops,
int outbuf_size) int outbuf_size)
...@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, ...@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
hp->outbuf_size = outbuf_size; hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; 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); INIT_WORK(&hp->tty_resize, hvc_set_winsz);
spin_lock_init(&hp->lock); spin_lock_init(&hp->lock);
...@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp) ...@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
unsigned long flags; unsigned long flags;
struct tty_struct *tty; struct tty_struct *tty;
spin_lock_irqsave(&hp->lock, flags); tty = tty_port_tty_get(&hp->port);
tty = tty_kref_get(hp->tty);
spin_lock_irqsave(&hp->lock, flags);
if (hp->index < MAX_NR_HVC_CONSOLES) if (hp->index < MAX_NR_HVC_CONSOLES)
vtermnos[hp->index] = -1; vtermnos[hp->index] = -1;
...@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp) ...@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
* kref cause it to be removed, which will probably be the tty_vhangup * kref cause it to be removed, which will probably be the tty_vhangup
* below. * below.
*/ */
kref_put(&hp->kref, destroy_hvc_struct); tty_port_put(&hp->port);
/* /*
* This function call will auto chain call hvc_hangup. * This function call will auto chain call hvc_hangup.
......
...@@ -46,10 +46,9 @@ ...@@ -46,10 +46,9 @@
#define HVC_ALLOC_TTY_ADAPTERS 8 #define HVC_ALLOC_TTY_ADAPTERS 8
struct hvc_struct { struct hvc_struct {
struct tty_port port;
spinlock_t lock; spinlock_t lock;
int index; int index;
struct tty_struct *tty;
int count;
int do_wakeup; int do_wakeup;
char *outbuf; char *outbuf;
int outbuf_size; int outbuf_size;
...@@ -61,7 +60,6 @@ struct hvc_struct { ...@@ -61,7 +60,6 @@ struct hvc_struct {
struct winsize ws; struct winsize ws;
struct work_struct tty_resize; struct work_struct tty_resize;
struct list_head next; struct list_head next;
struct kref kref; /* ref count & hvc_struct lifetime */
}; };
/* implemented by a low level driver */ /* implemented by a low level driver */
......
...@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock); ...@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
/* One vty-server per hvcs_struct */ /* One vty-server per hvcs_struct */
struct hvcs_struct { struct hvcs_struct {
struct tty_port port;
spinlock_t lock; spinlock_t lock;
/* /*
...@@ -269,9 +270,6 @@ struct hvcs_struct { ...@@ -269,9 +270,6 @@ struct hvcs_struct {
*/ */
unsigned int index; unsigned int index;
struct tty_struct *tty;
int open_count;
/* /*
* Used to tell the driver kernel_thread what operations need to take * Used to tell the driver kernel_thread what operations need to take
* place upon this hvcs_struct instance. * place upon this hvcs_struct instance.
...@@ -290,12 +288,11 @@ struct hvcs_struct { ...@@ -290,12 +288,11 @@ struct hvcs_struct {
int chars_in_buffer; 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 * stays valid after the tty is disconnected. These shouldn't be
* whacked until the kobject refcount reaches zero though some entries * whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives. * 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? */ int connected; /* is the vty-server currently connected to a vty? */
uint32_t p_unit_address; /* partner unit address */ uint32_t p_unit_address; /* partner unit address */
uint32_t p_partition_ID; /* partner partition ID */ uint32_t p_partition_ID; /* partner partition ID */
...@@ -304,9 +301,6 @@ struct hvcs_struct { ...@@ -304,9 +301,6 @@ struct hvcs_struct {
struct vio_dev *vdev; 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 LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock); static DEFINE_SPINLOCK(hvcs_structs_lock);
static DEFINE_MUTEX(hvcs_init_mutex); static DEFINE_MUTEX(hvcs_init_mutex);
...@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut ...@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->open_count > 0) { if (hvcsd->port.count > 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
printk(KERN_INFO "HVCS: vterm state unchanged. " printk(KERN_INFO "HVCS: vterm state unchanged. "
"The hvcs device node is still in use.\n"); "The hvcs device node is still in use.\n");
...@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) ...@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
static void hvcs_try_write(struct hvcs_struct *hvcsd) static void hvcs_try_write(struct hvcs_struct *hvcsd)
{ {
uint32_t unit_address = hvcsd->vdev->unit_address; uint32_t unit_address = hvcsd->vdev->unit_address;
struct tty_struct *tty = hvcsd->tty; struct tty_struct *tty = hvcsd->port.tty;
int sent; int sent;
if (hvcsd->todo_mask & HVCS_TRY_WRITE) { if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
...@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) ...@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
unit_address = hvcsd->vdev->unit_address; unit_address = hvcsd->vdev->unit_address;
tty = hvcsd->tty; tty = hvcsd->port.tty;
hvcs_try_write(hvcsd); hvcs_try_write(hvcsd);
...@@ -701,10 +695,9 @@ static void hvcs_return_index(int index) ...@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
hvcs_index_list[index] = -1; hvcs_index_list[index] = -1;
} }
/* callback when the kref ref count reaches zero */ static void hvcs_destruct_port(struct tty_port *p)
static void destroy_hvcs_struct(struct kref *kref)
{ {
struct hvcs_struct *hvcsd = from_kref(kref); struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev; struct vio_dev *vdev;
unsigned long flags; unsigned long flags;
...@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref) ...@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
kfree(hvcsd); kfree(hvcsd);
} }
static const struct tty_port_operations hvcs_port_ops = {
.destruct = hvcs_destruct_port,
};
static int hvcs_get_index(void) static int hvcs_get_index(void)
{ {
int i; int i;
...@@ -789,10 +786,9 @@ static int __devinit hvcs_probe( ...@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
if (!hvcsd) if (!hvcsd)
return -ENODEV; return -ENODEV;
tty_port_init(&hvcsd->port);
hvcsd->port.ops = &hvcs_port_ops;
spin_lock_init(&hvcsd->lock); spin_lock_init(&hvcsd->lock);
/* Automatically incs the refcount the first time */
kref_init(&hvcsd->kref);
hvcsd->vdev = dev; hvcsd->vdev = dev;
dev_set_drvdata(&dev->dev, hvcsd); dev_set_drvdata(&dev->dev, hvcsd);
...@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) ...@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
tty = hvcsd->tty; tty = hvcsd->port.tty;
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
...@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) ...@@ -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 * Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below. * 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 * 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) ...@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
list_for_each_entry(hvcsd, &hvcs_structs, next) { list_for_each_entry(hvcsd, &hvcs_structs, next) {
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->index == index) { if (hvcsd->index == index) {
kref_get(&hvcsd->kref); tty_port_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock); spin_unlock(&hvcs_structs_lock);
return hvcsd; return hvcsd;
...@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) ...@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
if ((retval = hvcs_partner_connect(hvcsd))) if ((retval = hvcs_partner_connect(hvcsd)))
goto error_release; goto error_release;
hvcsd->open_count = 1; hvcsd->port.count = 1;
hvcsd->tty = tty; hvcsd->port.tty = tty;
tty->driver_data = hvcsd; tty->driver_data = hvcsd;
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
...@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) ...@@ -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. * and will grab the spinlock and free the connection if it fails.
*/ */
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { 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"); printk(KERN_WARNING "HVCS: enable device failed.\n");
return rc; return rc;
} }
...@@ -1171,8 +1167,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) ...@@ -1171,8 +1167,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data; hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
kref_get(&hvcsd->kref); tty_port_get(&hvcsd->port);
hvcsd->open_count++; hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ; hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
...@@ -1186,7 +1182,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) ...@@ -1186,7 +1182,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
error_release: error_release:
spin_unlock_irqrestore(&hvcsd->lock, flags); 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"); printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval; return retval;
...@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) ...@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data; hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
if (--hvcsd->open_count == 0) { if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev); vio_disable_interrupts(hvcsd->vdev);
...@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) ...@@ -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 * execute any operations on the TTY even though it is obligated
* to deliver any pending I/O to the hypervisor. * to deliver any pending I/O to the hypervisor.
*/ */
hvcsd->tty = NULL; hvcsd->port.tty = NULL;
irq = hvcsd->vdev->irq; irq = hvcsd->vdev->irq;
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
...@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) ...@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL; tty->driver_data = NULL;
free_irq(irq, hvcsd); free_irq(irq, hvcsd);
kref_put(&hvcsd->kref, destroy_hvcs_struct); tty_port_put(&hvcsd->port);
return; return;
} else if (hvcsd->open_count < 0) { } else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
" is missmanaged.\n", " is missmanaged.\n",
hvcsd->vdev->unit_address, hvcsd->open_count); hvcsd->vdev->unit_address, hvcsd->port.count);
} }
spin_unlock_irqrestore(&hvcsd->lock, flags); 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) static void hvcs_hangup(struct tty_struct * tty)
...@@ -1261,7 +1257,7 @@ 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); spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */ /* Preserve this so that we know how many kref refs to put */
temp_open_count = hvcsd->open_count; temp_open_count = hvcsd->port.count;
/* /*
* Don't kref put inside the spinlock because the destruction * Don't kref put inside the spinlock because the destruction
...@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty) ...@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
hvcsd->todo_mask = 0; hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */ /* I don't think the tty needs the hvcs_struct pointer after a hangup */
hvcsd->tty->driver_data = NULL; tty->driver_data = NULL;
hvcsd->tty = 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 /* This will drop any buffered data on the floor which is OK in a hangup
* scenario. */ * scenario. */
...@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty) ...@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
* NOTE: If this hangup was signaled from user space then the * NOTE: If this hangup was signaled from user space then the
* final put will never happen. * 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, ...@@ -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 * the middle of a write operation? This is a crummy place to do this
* but we want to keep it all in the spinlock. * 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); spin_unlock_irqrestore(&hvcsd->lock, flags);
return -ENODEV; return -ENODEV;
} }
...@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty) ...@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
{ {
struct hvcs_struct *hvcsd = tty->driver_data; struct hvcs_struct *hvcsd = tty->driver_data;
if (!hvcsd || hvcsd->open_count <= 0) if (!hvcsd || hvcsd->port.count <= 0)
return 0; return 0;
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; 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) ...@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
pr_devel("HVSI@%x: open !\n", pv->termno); pr_devel("HVSI@%x: open !\n", pv->termno);
/* Keep track of the tty data structure */ /* 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); hvsilib_establish(pv);
......
...@@ -44,14 +44,13 @@ ...@@ -44,14 +44,13 @@
#define TTYTYPE_RAS_RAW (2) #define TTYTYPE_RAS_RAW (2)
struct ipw_tty { struct ipw_tty {
struct tty_port port;
int index; int index;
struct ipw_hardware *hardware; struct ipw_hardware *hardware;
unsigned int channel_idx; unsigned int channel_idx;
unsigned int secondary_channel_idx; unsigned int secondary_channel_idx;
int tty_type; int tty_type;
struct ipw_network *network; struct ipw_network *network;
struct tty_struct *linux_tty;
int open_count;
unsigned int control_lines; unsigned int control_lines;
struct mutex ipw_tty_mutex; struct mutex ipw_tty_mutex;
int tx_bytes_queued; int tx_bytes_queued;
...@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type) ...@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
return channel_names[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) static struct ipw_tty *get_tty(int index)
{ {
/* /*
...@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) ...@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
return -ENODEV; return -ENODEV;
} }
if (tty->open_count == 0) if (tty->port.count == 0)
tty->tx_bytes_queued = 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->driver_data = tty;
linux_tty->low_latency = 1; linux_tty->low_latency = 1;
...@@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) ...@@ -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) static void do_ipw_close(struct ipw_tty *tty)
{ {
tty->open_count--; tty->port.count--;
if (tty->open_count == 0) { if (tty->port.count == 0) {
struct tty_struct *linux_tty = tty->linux_tty; struct tty_struct *linux_tty = tty->port.tty;
if (linux_tty != NULL) { if (linux_tty != NULL) {
tty->linux_tty = NULL; tty->port.tty = NULL;
linux_tty->driver_data = NULL; linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM) if (tty->tty_type == TTYTYPE_MODEM)
...@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty) ...@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
return; return;
mutex_lock(&tty->ipw_tty_mutex); mutex_lock(&tty->ipw_tty_mutex);
if (tty->open_count == 0) { if (tty->port.count == 0) {
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
return; return;
} }
...@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, ...@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
int work = 0; int work = 0;
mutex_lock(&tty->ipw_tty_mutex); mutex_lock(&tty->ipw_tty_mutex);
linux_tty = tty->linux_tty; linux_tty = tty->port.tty;
if (linux_tty == NULL) { if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
return; return;
} }
if (!tty->open_count) { if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
return; return;
} }
...@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty, ...@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
return -ENODEV; return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex); mutex_lock(&tty->ipw_tty_mutex);
if (!tty->open_count) { if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL; return -EINVAL;
} }
...@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) ...@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
if (!tty) if (!tty)
return -ENODEV; return -ENODEV;
if (!tty->open_count) if (!tty->port.count)
return -EINVAL; return -EINVAL;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
...@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty) ...@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
if (!tty) if (!tty)
return 0; return 0;
if (!tty->open_count) if (!tty->port.count)
return 0; return 0;
return tty->tx_bytes_queued; return tty->tx_bytes_queued;
...@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty) ...@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
if (!tty) if (!tty)
return -ENODEV; return -ENODEV;
if (!tty->open_count) if (!tty->port.count)
return -EINVAL; return -EINVAL;
return get_control_lines(tty); return get_control_lines(tty);
...@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, ...@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
if (!tty) if (!tty)
return -ENODEV; return -ENODEV;
if (!tty->open_count) if (!tty->port.count)
return -EINVAL; return -EINVAL;
return set_control_lines(tty, set, clear); return set_control_lines(tty, set, clear);
...@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty, ...@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
if (!tty) if (!tty)
return -ENODEV; return -ENODEV;
if (!tty->open_count) if (!tty->port.count)
return -EINVAL; return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */ /* FIXME: Exactly how is the tty object locked here .. */
...@@ -492,6 +474,7 @@ static int add_tty(int j, ...@@ -492,6 +474,7 @@ static int add_tty(int j,
ttys[j]->network = network; ttys[j]->network = network;
ttys[j]->tty_type = tty_type; ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex); mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
tty_register_device(ipw_tty_driver, j, NULL); tty_register_device(ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]); ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
...@@ -500,8 +483,12 @@ static int add_tty(int j, ...@@ -500,8 +483,12 @@ static int add_tty(int j,
ipwireless_associate_network_tty(network, ipwireless_associate_network_tty(network,
secondary_channel_idx, secondary_channel_idx,
ttys[j]); ttys[j]);
if (get_tty(j) == ttys[j]) /* check if we provide raw device (if loopback is enabled) */
report_registering(ttys[j]); if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n",
tty_type_name(tty_type), j);
return 0; return 0;
} }
...@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty) ...@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
if (ttyj) { if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex); mutex_lock(&ttyj->ipw_tty_mutex);
if (get_tty(j) == ttyj) if (get_tty(j))
report_deregistering(ttyj); printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n",
tty_type_name(ttyj->tty_type), j);
ttyj->closing = 1; ttyj->closing = 1;
if (ttyj->linux_tty != NULL) { if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex); mutex_unlock(&ttyj->ipw_tty_mutex);
tty_hangup(ttyj->linux_tty); tty_vhangup(ttyj->port.tty);
/* Wait till the tty_hangup has completed */
flush_work_sync(&ttyj->linux_tty->hangup_work);
/* FIXME: Exactly how is the tty object locked here /* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */ against a parallel ioctl etc */
/* FIXME2: hangup does not mean all processes
* are gone */
mutex_lock(&ttyj->ipw_tty_mutex); mutex_lock(&ttyj->ipw_tty_mutex);
} }
while (ttyj->open_count) while (ttyj->port.count)
do_ipw_close(ttyj); do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network, ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx); ttyj->channel_idx);
...@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, ...@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
*/ */
if ((old_control_lines & IPW_CONTROL_LINE_DCD) if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD) && !(tty->control_lines & IPW_CONTROL_LINE_DCD)
&& tty->linux_tty) { && tty->port.tty) {
tty_hangup(tty->linux_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) ...@@ -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 * IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to * capability" bit enabled. Note that on XR16C850s, we need to
...@@ -1331,27 +1341,6 @@ static void serial8250_enable_ms(struct uart_port *port) ...@@ -1331,27 +1341,6 @@ static void serial8250_enable_ms(struct uart_port *port)
serial_port_out(port, UART_IER, up->ier); 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 * serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled * value, and returns the remaining LSR bits not handled
...@@ -1386,19 +1375,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) ...@@ -1386,19 +1375,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
up->lsr_saved_flags = 0; up->lsr_saved_flags = 0;
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
/*
* For statistics only
*/
if (lsr & UART_LSR_BI) { if (lsr & UART_LSR_BI) {
lsr &= ~(UART_LSR_FE | UART_LSR_PE); lsr &= ~(UART_LSR_FE | UART_LSR_PE);
port->icount.brk++; 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 * We do the SysRQ and SAK checking
* here because otherwise the break * here because otherwise the break
...@@ -3037,6 +3016,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) ...@@ -3037,6 +3016,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_in = p->serial_in; port.serial_in = p->serial_in;
port.serial_out = p->serial_out; port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq; port.handle_irq = p->handle_irq;
port.handle_break = p->handle_break;
port.set_termios = p->set_termios; port.set_termios = p->set_termios;
port.pm = p->pm; port.pm = p->pm;
port.dev = &dev->dev; port.dev = &dev->dev;
...@@ -3209,6 +3189,8 @@ int serial8250_register_port(struct uart_port *port) ...@@ -3209,6 +3189,8 @@ int serial8250_register_port(struct uart_port *port)
uart->port.set_termios = port->set_termios; uart->port.set_termios = port->set_termios;
if (port->pm) if (port->pm)
uart->port.pm = port->pm; uart->port.pm = port->pm;
if (port->handle_break)
uart->port.handle_break = port->handle_break;
if (serial8250_isa_config != NULL) if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port, serial8250_isa_config(0, &uart->port,
......
...@@ -96,6 +96,8 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) ...@@ -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); 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) #if defined(__alpha__) && !defined(CONFIG_PCI)
/* /*
* Digital did something really horribly wrong with the OUT1 and OUT2 * Digital did something really horribly wrong with the OUT1 and OUT2
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/serial_reg.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/8250_pci.h> #include <linux/8250_pci.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv, ...@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx); return pci_default_setup(priv, board, port, idx);
} }
static 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, static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
struct uart_port *port, int idx) struct uart_port *port, int idx)
{ {
port->flags |= UPF_BUG_THRE; 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); return skip_tx_en_setup(priv, board, port, idx);
} }
...@@ -2775,6 +2814,12 @@ void pciserial_suspend_ports(struct serial_private *priv) ...@@ -2775,6 +2814,12 @@ void pciserial_suspend_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++) for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0) if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]); 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); EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
......
...@@ -67,30 +67,6 @@ ...@@ -67,30 +67,6 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #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_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 */ /* There is by now at least one vendor with differing details, so handle it */
struct vendor_data { struct vendor_data {
unsigned int ifls; unsigned int ifls;
...@@ -100,6 +76,7 @@ struct vendor_data { ...@@ -100,6 +76,7 @@ struct vendor_data {
bool oversampling; bool oversampling;
bool interrupt_may_hang; /* vendor-specific */ bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold; bool dma_threshold;
bool cts_event_workaround;
}; };
static struct vendor_data vendor_arm = { static struct vendor_data vendor_arm = {
...@@ -109,6 +86,7 @@ static struct vendor_data vendor_arm = { ...@@ -109,6 +86,7 @@ static struct vendor_data vendor_arm = {
.lcrh_rx = UART011_LCRH, .lcrh_rx = UART011_LCRH,
.oversampling = false, .oversampling = false,
.dma_threshold = false, .dma_threshold = false,
.cts_event_workaround = false,
}; };
static struct vendor_data vendor_st = { static struct vendor_data vendor_st = {
...@@ -119,6 +97,7 @@ static struct vendor_data vendor_st = { ...@@ -119,6 +97,7 @@ static struct vendor_data vendor_st = {
.oversampling = true, .oversampling = true,
.interrupt_may_hang = true, .interrupt_may_hang = true,
.dma_threshold = true, .dma_threshold = true,
.cts_event_workaround = true,
}; };
static struct uart_amba_port *amba_ports[UART_NR]; 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) ...@@ -1054,69 +1033,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#define pl011_dma_flush_buffer NULL #define pl011_dma_flush_buffer NULL
#endif #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) static void pl011_stop_tx(struct uart_port *port)
{ {
struct uart_amba_port *uap = (struct uart_amba_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) ...@@ -1245,12 +1161,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
unsigned long flags; unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0; int handled = 0;
unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags); spin_lock_irqsave(&uap->port.lock, flags);
status = readw(uap->port.membase + UART011_MIS); status = readw(uap->port.membase + UART011_MIS);
if (status) { if (status) {
do { 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| writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS), UART011_RXIS),
uap->port.membase + UART011_ICR); uap->port.membase + UART011_ICR);
...@@ -1267,11 +1197,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id) ...@@ -1267,11 +1197,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & UART011_TXIS) if (status & UART011_TXIS)
pl011_tx_chars(uap); pl011_tx_chars(uap);
if (pass_counter-- == 0) { if (pass_counter-- == 0)
if (uap->interrupt_may_hang)
tasklet_schedule(&pl011_lockup_tlet);
break; break;
}
status = readw(uap->port.membase + UART011_MIS); status = readw(uap->port.membase + UART011_MIS);
} while (status != 0); } while (status != 0);
......
...@@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = ...@@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Input */ /* Input */
#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) #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. */ /* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info) static void update_char_time(struct e100_serial * info)
{ {
...@@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty, ...@@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,
/* first some sanity checks */ /* first some sanity checks */
if (!tty || !info->xmit.buf || !tmp_buf) if (!tty || !info->xmit.buf)
return 0; return 0;
#ifdef SERIAL_DEBUG_DATA #ifdef SERIAL_DEBUG_DATA
...@@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp) ...@@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
{ {
struct e100_serial *info; struct e100_serial *info;
int retval; int retval;
unsigned long page;
int allocated_resources = 0; int allocated_resources = 0;
info = rs_table + tty->index; info = rs_table + tty->index;
...@@ -4124,17 +4110,6 @@ rs_open(struct tty_struct *tty, struct file * filp) ...@@ -4124,17 +4110,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); 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 * If the port is in the middle of closing, bail out now
*/ */
...@@ -4487,6 +4462,7 @@ static int __init rs_init(void) ...@@ -4487,6 +4462,7 @@ static int __init rs_init(void)
info->enabled = 0; info->enabled = 0;
} }
} }
tty_port_init(&info->port);
info->uses_dma_in = 0; info->uses_dma_in = 0;
info->uses_dma_out = 0; info->uses_dma_out = 0;
info->line = i; info->line = i;
......
...@@ -12,10 +12,13 @@ ...@@ -12,10 +12,13 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_serial.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/nwpserial.h> #include <linux/nwpserial.h>
...@@ -24,6 +27,26 @@ struct of_serial_info { ...@@ -24,6 +27,26 @@ struct of_serial_info {
int line; 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 * 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, ...@@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
| UPF_FIXED_PORT | UPF_FIXED_TYPE; | UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->dev = &ofdev->dev; port->dev = &ofdev->dev;
if (type == PORT_TEGRA)
port->handle_break = tegra_serial_handle_break;
return 0; return 0;
} }
......
...@@ -44,6 +44,13 @@ ...@@ -44,6 +44,13 @@
#include <plat/dmtimer.h> #include <plat/dmtimer.h>
#include <plat/omap-serial.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*/ #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
/* SCR register bitmasks */ /* SCR register bitmasks */
...@@ -53,6 +60,17 @@ ...@@ -53,6 +60,17 @@
#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 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]; static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */ /* Forward declaration of functions */
...@@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) ...@@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
return; 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) static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{ {
struct omap_uart_port_info *omap_up_info; struct omap_uart_port_info *omap_up_info;
...@@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev) ...@@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)
"%d\n", DEFAULT_CLK_SPEED); "%d\n", DEFAULT_CLK_SPEED);
} }
up->uart_dma.uart_base = mem->start; up->uart_dma.uart_base = mem->start;
up->errata = omap_up_info->errata;
if (omap_up_info->dma_enabled) { if (omap_up_info->dma_enabled) {
up->uart_dma.uart_dma_tx = dma_tx->start; up->uart_dma.uart_dma_tx = dma_tx->start;
...@@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev) ...@@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(up);
ui[up->port.line] = up; ui[up->port.line] = up;
serial_omap_add_console_port(up); serial_omap_add_console_port(up);
......
...@@ -39,6 +39,7 @@ enum { ...@@ -39,6 +39,7 @@ enum {
PCH_UART_HANDLED_RX_ERR_INT_SHIFT, PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
PCH_UART_HANDLED_RX_TRG_INT_SHIFT, PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
PCH_UART_HANDLED_MS_INT_SHIFT, PCH_UART_HANDLED_MS_INT_SHIFT,
PCH_UART_HANDLED_LS_INT_SHIFT,
}; };
enum { enum {
...@@ -63,6 +64,8 @@ enum { ...@@ -63,6 +64,8 @@ enum {
PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) 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_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_RBR 0x00
#define PCH_UART_THR 0x00 #define PCH_UART_THR 0x00
...@@ -229,7 +232,6 @@ struct eg20t_port { ...@@ -229,7 +232,6 @@ struct eg20t_port {
int start_tx; int start_tx;
int start_rx; int start_rx;
int tx_empty; int tx_empty;
int int_dis_flag;
int trigger; int trigger;
int trigger_level; int trigger_level;
struct pch_uart_buffer rxbuf; struct pch_uart_buffer rxbuf;
...@@ -237,7 +239,6 @@ struct eg20t_port { ...@@ -237,7 +239,6 @@ struct eg20t_port {
unsigned int fcr; unsigned int fcr;
unsigned int mcr; unsigned int mcr;
unsigned int use_dma; unsigned int use_dma;
unsigned int use_dma_flag;
struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_tx;
struct dma_async_tx_descriptor *desc_rx; struct dma_async_tx_descriptor *desc_rx;
struct pch_dma_slave param_tx; struct pch_dma_slave param_tx;
...@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, ...@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
return i; 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; return ioread8(priv->membase + UART_IIR) &\
int ret; (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
iir = ioread8(priv->membase + UART_IIR);
ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
return ret;
} }
static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) 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) ...@@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)
dma_release_channel(priv->chan_rx); dma_release_channel(priv->chan_rx);
priv->chan_rx = NULL; priv->chan_rx = NULL;
} }
if (sg_dma_address(&priv->sg_rx))
dma_free_coherent(port->dev, port->fifosize, if (priv->rx_buf_dma) {
sg_virt(&priv->sg_rx), dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
sg_dma_address(&priv->sg_rx)); priv->rx_buf_dma);
priv->rx_buf_virt = NULL;
priv->rx_buf_dma = 0;
}
return; return;
} }
...@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ...@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
unsigned int handled; unsigned int handled;
u8 lsr; u8 lsr;
int ret = 0; int ret = 0;
unsigned int iid; unsigned char iid;
unsigned long flags; unsigned long flags;
int next = 1;
u8 msr;
spin_lock_irqsave(&priv->port.lock, flags); spin_lock_irqsave(&priv->port.lock, flags);
handled = 0; 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) { switch (iid) {
case PCH_UART_IID_RLS: /* Receiver Line Status */ case PCH_UART_IID_RLS: /* Receiver Line Status */
lsr = pch_uart_hal_get_line_status(priv); lsr = pch_uart_hal_get_line_status(priv);
...@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ...@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
UART_LSR_PE | UART_LSR_OE)) { UART_LSR_PE | UART_LSR_OE)) {
pch_uart_err_ir(priv, lsr); pch_uart_err_ir(priv, lsr);
ret = PCH_UART_HANDLED_RX_ERR_INT; ret = PCH_UART_HANDLED_RX_ERR_INT;
} else {
ret = PCH_UART_HANDLED_LS_INT;
} }
break; break;
case PCH_UART_IID_RDR: /* Received Data Ready */ case PCH_UART_IID_RDR: /* Received Data Ready */
...@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ...@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
ret = handle_tx(priv); ret = handle_tx(priv);
break; break;
case PCH_UART_IID_MS: /* Modem Status */ 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; break;
default: /* Never junp to this label */ 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); iid, jiffies);
ret = -1; ret = -1;
next = 0;
break; break;
} }
handled |= (unsigned int)ret; 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); spin_unlock_irqrestore(&priv->port.lock, flags);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
...@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port) ...@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)
priv = container_of(port, struct eg20t_port, port); priv = container_of(port, struct eg20t_port, port);
priv->start_rx = 0; priv->start_rx = 0;
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
priv->int_dis_flag = 1;
} }
/* Enable the modem status interrupts. */ /* Enable the modem status interrupts. */
...@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port, ...@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,
__func__); __func__);
return -EOPNOTSUPP; return -EOPNOTSUPP;
#endif #endif
priv->use_dma_flag = 1;
dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
if (!priv->use_dma) if (!priv->use_dma)
pch_request_dma(port); pch_request_dma(port);
......
...@@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) ...@@ -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 /* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */ 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 * @tty: tty structure
* @size: size desired * @size: size desired
* *
* Make at least size bytes of linear space available for the tty * Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find. * buffer. If we fail return the size we managed to find.
* * Locking: Caller must hold tty->buf.lock
* Locking: Takes 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; struct tty_buffer *b, *n;
int left; int left;
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible remove this conditional if its worth it. This would be invisible
to the callers */ to the callers */
...@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) ...@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
size = left; size = left;
} }
spin_unlock_irqrestore(&tty->buf.lock, flags);
return size; 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); EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/** /**
...@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, ...@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
int copied = 0; int copied = 0;
do { do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(tty, goal); int space;
struct tty_buffer *tb = tty->buf.tail; 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 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; break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space); memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space; tb->used += space;
spin_unlock_irqrestore(&tty->buf.lock, flags);
copied += space; copied += space;
chars += space; chars += space;
/* There is a small chance that we need to split the data over /* 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, ...@@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
int copied = 0; int copied = 0;
do { do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(tty, goal); int space;
struct tty_buffer *tb = tty->buf.tail; 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 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; break;
}
memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space; tb->used += space;
spin_unlock_irqrestore(&tty->buf.lock, __flags);
copied += space; copied += space;
chars += space; chars += space;
flags += space; flags += space;
...@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip); ...@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
size_t size) 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)) { if (likely(space)) {
struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used; *chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space; tb->used += space;
} }
spin_unlock_irqrestore(&tty->buf.lock, flags);
return space; return space;
} }
EXPORT_SYMBOL_GPL(tty_prepare_flip_string); EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
...@@ -374,13 +412,20 @@ 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, int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size) 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)) { if (likely(space)) {
struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used; *chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used; *flags = tb->flag_buf_ptr + tb->used;
tb->used += space; tb->used += space;
} }
spin_unlock_irqrestore(&tty->buf.lock, __flags);
return space; return space;
} }
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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