Commit 94b5aff4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull TTY updates from Greg Kroah-Hartman:
 "Here's the big TTY/serial driver pull request for the 3.5-rc1 merge
  window.

  Nothing major in here, just lots of incremental changes from Alan and
  Jiri reworking some tty core things to behave better and to get a more
  solid grasp on some of the nasty tty locking issues.

  There are a few tty and serial driver updates in here as well.

  All of this has been in the linux-next releases for a while with no
  problems.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

* tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (115 commits)
  serial: bfin_uart: Make MMR access compatible with 32 bits bf609 style controller.
  serial: bfin_uart: RTS and CTS MMRs can be either 16-bit width or 32-bit width.
  serial: bfin_uart: narrow the reboot condition in DMA tx interrupt
  serial: bfin_uart: Adapt bf5xx serial driver to bf60x serial4 controller.
  Revert "serial_core: Update buffer overrun statistics."
  tty: hvc_xen: NULL dereference on allocation failure
  tty: Fix LED error return
  tty: Allow uart_register/unregister/register
  tty: move global ldisc idle waitqueue to the individual ldisc
  serial8250-em: Add DT support
  serial8250-em: clk_get() IS_ERR() error handling fix
  serial_core: Update buffer overrun statistics.
  tty: drop the pty lock during hangup
  cris: fix missing tty arg in wait_event_interruptible_tty call
  tty/amiserial: Add missing argument for tty_unlock()
  tty_lock: Localise the lock
  pty: Lock the devpts bits privately
  tty_lock: undo the old tty_lock use on the ctty
  serial8250-em: Emma Mobile UART driver V2
  Add missing call to uart_update_timeout()
  ...
parents 5d4e2d08 59bd234b
...@@ -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>
...@@ -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[] = {
/* 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>
...@@ -49,6 +50,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { ...@@ -49,6 +50,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.
...@@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttys%d, count = %d\n", printk("block_til_ready blocking: ttys%d, count = %d\n",
info->line, state->count); info->line, state->count);
#endif #endif
tty_unlock(); tty_unlock(tty);
schedule(); schedule();
tty_lock(); tty_lock(tty);
} }
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait); remove_wait_queue(&info->open_wait, &wait);
......
...@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, ...@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
if (!retinfo) if (!retinfo)
return -EFAULT; return -EFAULT;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tty_lock(); tty_lock(tty);
tmp.line = tty->index; tmp.line = tty->index;
tmp.port = state->port; tmp.port = state->port;
tmp.flags = state->tport.flags; tmp.flags = state->tport.flags;
...@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, ...@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
tmp.close_delay = state->tport.close_delay; tmp.close_delay = state->tport.close_delay;
tmp.closing_wait = state->tport.closing_wait; tmp.closing_wait = state->tport.closing_wait;
tmp.custom_divisor = state->custom_divisor; tmp.custom_divisor = state->custom_divisor;
tty_unlock(); tty_unlock(tty);
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, ...@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT; return -EFAULT;
tty_lock(); tty_lock(tty);
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
new_serial.custom_divisor != state->custom_divisor; new_serial.custom_divisor != state->custom_divisor;
if (new_serial.irq || new_serial.port != state->port || if (new_serial.irq || new_serial.port != state->port ||
new_serial.xmit_fifo_size != state->xmit_fifo_size) { new_serial.xmit_fifo_size != state->xmit_fifo_size) {
tty_unlock(); tty_unlock(tty);
return -EINVAL; return -EINVAL;
} }
...@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, ...@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
(new_serial.xmit_fifo_size != state->xmit_fifo_size) || (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
((new_serial.flags & ~ASYNC_USR_MASK) != ((new_serial.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) { (port->flags & ~ASYNC_USR_MASK))) {
tty_unlock(); tty_unlock(tty);
return -EPERM; return -EPERM;
} }
port->flags = ((port->flags & ~ASYNC_USR_MASK) | port->flags = ((port->flags & ~ASYNC_USR_MASK) |
...@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, ...@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
} }
if (new_serial.baud_base < 9600) { if (new_serial.baud_base < 9600) {
tty_unlock(); tty_unlock(tty);
return -EINVAL; return -EINVAL;
} }
...@@ -1116,7 +1116,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, ...@@ -1116,7 +1116,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
} }
} else } else
retval = startup(tty, state); retval = startup(tty, state);
tty_unlock(); tty_unlock(tty);
return retval; return retval;
} }
......
...@@ -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);
......
...@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) ...@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now * If the port is the middle of closing, bail out now
*/ */
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(info->port.close_wait, wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING)); !(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
} }
......
...@@ -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 */
......
...@@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev, ...@@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,
if (devid == 0) if (devid == 0)
return -ENODEV; return -ENODEV;
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info) if (!info)
goto error_nomem; return -ENOMEM;
dev_set_drvdata(&dev->dev, info); dev_set_drvdata(&dev->dev, info);
info->xbdev = dev; info->xbdev = dev;
info->vtermno = xenbus_devid_to_vtermno(devid); info->vtermno = xenbus_devid_to_vtermno(devid);
......
...@@ -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);
} }
} }
...@@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = { ...@@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {
.get_icount = mxser_get_icount, .get_icount = mxser_get_icount,
}; };
struct tty_port_operations mxser_port_ops = { static struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised, .carrier_raised = mxser_carrier_raised,
.dtr_rts = mxser_dtr_rts, .dtr_rts = mxser_dtr_rts,
.activate = mxser_activate, .activate = mxser_activate,
......
...@@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, ...@@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()"); TRACE_L("read()");
tty_lock(); /* FIXME: should use a private lock */
tty_lock(tty);
pClient = findClient(pInfo, task_pid(current)); pClient = findClient(pInfo, task_pid(current));
if (pClient) { if (pClient) {
...@@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, ...@@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock; goto unlock;
} }
/* block until there is a message: */ /* block until there is a message: */
wait_event_interruptible_tty(pInfo->read_wait, wait_event_interruptible_tty(tty, pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient))); (pMsg = remove_msg(pInfo, pClient)));
} }
...@@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, ...@@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
} }
ret = -EPERM; ret = -EPERM;
unlock: unlock:
tty_unlock(); tty_unlock(tty);
return ret; return ret;
} }
...@@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, ...@@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0; pHeader->locks = 0;
pHeader->owner = NULL; pHeader->owner = NULL;
tty_lock(); tty_lock(tty);
pClient = findClient(pInfo, task_pid(current)); pClient = findClient(pInfo, task_pid(current));
if (pClient) { if (pClient) {
...@@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, ...@@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader); add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo); trigger_transmit(pInfo);
tty_unlock(); tty_unlock(tty);
return 0; return 0;
} }
......
...@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty, ...@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval; int retval;
size_t n; size_t n;
unsigned long flags; unsigned long flags;
bool is_eof;
retval = 0; retval = 0;
spin_lock_irqsave(&tty->read_lock, flags); spin_lock_irqsave(&tty->read_lock, flags);
...@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty, ...@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) { if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval; n -= retval;
is_eof = n == 1 &&
tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n); tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags); spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n; tty->read_cnt -= n;
/* Turn single EOF into zero-length read */ /* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && tty->icanon && n == 1) { if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty)) n = 0;
n--;
}
spin_unlock_irqrestore(&tty->read_lock, flags); spin_unlock_irqrestore(&tty->read_lock, flags);
*b += n; *b += n;
*nr -= n; *nr -= n;
......
...@@ -26,11 +26,13 @@ ...@@ -26,11 +26,13 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/devpts_fs.h> #include <linux/devpts_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h>
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver; static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver; static struct tty_driver *pts_driver;
static DEFINE_MUTEX(devpts_mutex);
#endif #endif
static void pty_close(struct tty_struct *tty, struct file *filp) static void pty_close(struct tty_struct *tty, struct file *filp)
...@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) ...@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
tty->packet = 0; tty->packet = 0;
/* Review - krefs on tty_link ?? */
if (!tty->link) if (!tty->link)
return; return;
tty->link->packet = 0; tty->link->packet = 0;
...@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp) ...@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
if (tty->driver->subtype == PTY_TYPE_MASTER) { if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags); set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver) if (tty->driver == ptm_driver) {
mutex_lock(&devpts_mutex);
devpts_pty_kill(tty->link); devpts_pty_kill(tty->link);
mutex_unlock(&devpts_mutex);
}
#endif #endif
tty_unlock(); tty_unlock(tty);
tty_vhangup(tty->link); tty_vhangup(tty->link);
tty_lock(); tty_lock(tty);
} }
} }
...@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, ...@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
* @idx: tty index * @idx: tty index
* *
* Look up a pty master device. Called under the tty_mutex for now. * Look up a pty master device. Called under the tty_mutex for now.
* This provides our locking. * This provides our locking for the tty pointer.
*/ */
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct inode *pts_inode, int idx) struct inode *pts_inode, int idx)
{ {
struct tty_struct *tty = devpts_get_tty(pts_inode, idx); struct tty_struct *tty;
mutex_lock(&devpts_mutex);
tty = devpts_get_tty(pts_inode, idx);
mutex_unlock(&devpts_mutex);
/* Master must be open before slave */ /* Master must be open before slave */
if (!tty) if (!tty)
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
...@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp) ...@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval; return retval;
/* find a device that is not in use. */ /* find a device that is not in use. */
tty_lock(); mutex_lock(&devpts_mutex);
index = devpts_new_index(inode); index = devpts_new_index(inode);
tty_unlock();
if (index < 0) { if (index < 0) {
retval = index; retval = index;
goto err_file; goto err_file;
} }
mutex_unlock(&devpts_mutex);
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
tty_lock(); mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index); tty = tty_init_dev(ptm_driver, index);
mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
retval = PTR_ERR(tty); retval = PTR_ERR(tty);
goto out; goto out;
} }
/* The tty returned here is locked so we can safely
drop the mutex */
mutex_unlock(&devpts_mutex);
mutex_unlock(&tty_mutex);
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp); tty_add_file(tty, filp);
...@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp) ...@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval) if (retval)
goto err_release; goto err_release;
tty_unlock(); tty_unlock(tty);
return 0; return 0;
err_release: err_release:
tty_unlock(); tty_unlock(tty);
tty_release(inode, filp); tty_release(inode, filp);
return retval; return retval;
out: out:
mutex_unlock(&tty_mutex);
devpts_kill_index(inode, index); devpts_kill_index(inode, index);
tty_unlock();
err_file: err_file:
mutex_unlock(&devpts_mutex);
tty_free_file(filp); tty_free_file(filp);
return retval; return retval;
} }
......
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) */
This diff is collapsed.
...@@ -37,6 +37,10 @@ struct uart_8250_port { ...@@ -37,6 +37,10 @@ struct uart_8250_port {
unsigned char lsr_saved_flags; unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags; unsigned char msr_saved_flags;
/* 8250 specific callbacks */
int (*dl_read)(struct uart_8250_port *);
void (*dl_write)(struct uart_8250_port *, int);
}; };
struct old_serial_port { struct old_serial_port {
...@@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) ...@@ -96,6 +100,18 @@ 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);
static inline int serial_dl_read(struct uart_8250_port *up)
{
return up->dl_read(up);
}
static inline void serial_dl_write(struct uart_8250_port *up, int value)
{
up->dl_write(up, value);
}
#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
......
This diff is collapsed.
This diff is collapsed.
...@@ -278,3 +278,11 @@ config SERIAL_8250_DW ...@@ -278,3 +278,11 @@ config SERIAL_8250_DW
help help
Selecting this option will enable handling of the extra features Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART. present in the Synopsys DesignWare APB UART.
config SERIAL_8250_EM
tristate "Support for Emma Mobile intergrated serial port"
depends on SERIAL_8250 && ARM && HAVE_CLK
help
Selecting this option will add support for the integrated serial
port hardware found on the Emma Mobile line of processors.
If unsure, say N.
...@@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o ...@@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -370,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u, ...@@ -370,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,
writel(ctrl, u->membase + AUART_LINECTRL); writel(ctrl, u->membase + AUART_LINECTRL);
writel(ctrl2, u->membase + AUART_CTRL2); writel(ctrl2, u->membase + AUART_CTRL2);
uart_update_timeout(u, termios->c_cflag, baud);
} }
static irqreturn_t mxs_auart_irq_handle(int irq, void *context) static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv) ...@@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)
tty_unregister_driver(p); tty_unregister_driver(p);
put_tty_driver(p); put_tty_driver(p);
kfree(drv->state); kfree(drv->state);
drv->state = NULL;
drv->tty_driver = NULL; drv->tty_driver = NULL;
} }
......
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.
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.
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