提交 10af77c1 编写于 作者: G 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: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
...@@ -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);
......
此差异已折叠。
...@@ -106,13 +106,6 @@ ...@@ -106,13 +106,6 @@
#define MAX_RX_URBS 2 #define MAX_RX_URBS 2
static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty)
{
if (tty)
return tty->driver_data;
return NULL;
}
/*****************************************************************************/ /*****************************************************************************/
/* Debugging functions */ /* Debugging functions */
/*****************************************************************************/ /*****************************************************************************/
...@@ -255,9 +248,8 @@ struct hso_serial { ...@@ -255,9 +248,8 @@ struct hso_serial {
u8 dtr_state; u8 dtr_state;
unsigned tx_urb_used:1; unsigned tx_urb_used:1;
struct tty_port port;
/* from usb_serial_port */ /* from usb_serial_port */
struct tty_struct *tty;
int open_count;
spinlock_t serial_lock; spinlock_t serial_lock;
int (*write_data) (struct hso_serial *serial); int (*write_data) (struct hso_serial *serial);
...@@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios) ...@@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)
static void _hso_serial_set_termios(struct tty_struct *tty, static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old) struct ktermios *old)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
struct ktermios *termios; struct ktermios *termios;
if (!serial) { if (!serial) {
...@@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) ...@@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
struct urb *urb; struct urb *urb;
urb = serial->rx_urb[0]; urb = serial->rx_urb[0];
if (serial->open_count > 0) { if (serial->port.count > 0) {
count = put_rxbuf_data(urb, serial); count = put_rxbuf_data(urb, serial);
if (count == -1) if (count == -1)
return; return;
...@@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) ...@@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
DUMP1(urb->transfer_buffer, urb->actual_length); DUMP1(urb->transfer_buffer, urb->actual_length);
/* Anyone listening? */ /* Anyone listening? */
if (serial->open_count == 0) if (serial->port.count == 0)
return; return;
if (status == 0) { if (status == 0) {
...@@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial) ...@@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)
static void hso_unthrottle(struct tty_struct *tty) static void hso_unthrottle(struct tty_struct *tty)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
tasklet_hi_schedule(&serial->unthrottle_tasklet); tasklet_hi_schedule(&serial->unthrottle_tasklet);
} }
...@@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) ...@@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
kref_get(&serial->parent->ref); kref_get(&serial->parent->ref);
/* setup */ /* setup */
spin_lock_irq(&serial->serial_lock);
tty->driver_data = serial; tty->driver_data = serial;
tty_kref_put(serial->tty); tty_port_tty_set(&serial->port, tty);
serial->tty = tty_kref_get(tty);
spin_unlock_irq(&serial->serial_lock);
/* check for port already opened, if not set the termios */ /* check for port already opened, if not set the termios */
serial->open_count++; serial->port.count++;
if (serial->open_count == 1) { if (serial->port.count == 1) {
serial->rx_state = RX_IDLE; serial->rx_state = RX_IDLE;
/* Force default termio settings */ /* Force default termio settings */
_hso_serial_set_termios(tty, NULL); _hso_serial_set_termios(tty, NULL);
...@@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) ...@@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
result = hso_start_serial_device(serial->parent, GFP_KERNEL); result = hso_start_serial_device(serial->parent, GFP_KERNEL);
if (result) { if (result) {
hso_stop_serial_device(serial->parent); hso_stop_serial_device(serial->parent);
serial->open_count--; serial->port.count--;
kref_put(&serial->parent->ref, hso_serial_ref_free); kref_put(&serial->parent->ref, hso_serial_ref_free);
} }
} else { } else {
...@@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) ...@@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
/* reset the rts and dtr */ /* reset the rts and dtr */
/* do the actual close */ /* do the actual close */
serial->open_count--; serial->port.count--;
if (serial->open_count <= 0) { if (serial->port.count <= 0) {
serial->open_count = 0; serial->port.count = 0;
spin_lock_irq(&serial->serial_lock); tty_port_tty_set(&serial->port, NULL);
if (serial->tty == tty) {
serial->tty->driver_data = NULL;
serial->tty = NULL;
tty_kref_put(tty);
}
spin_unlock_irq(&serial->serial_lock);
if (!usb_gone) if (!usb_gone)
hso_stop_serial_device(serial->parent); hso_stop_serial_device(serial->parent);
tasklet_kill(&serial->unthrottle_tasklet); tasklet_kill(&serial->unthrottle_tasklet);
...@@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) ...@@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
int count) int count)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
int space, tx_bytes; int space, tx_bytes;
unsigned long flags; unsigned long flags;
...@@ -1422,7 +1405,7 @@ static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, ...@@ -1422,7 +1405,7 @@ static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
/* how much room is there for writing */ /* how much room is there for writing */
static int hso_serial_write_room(struct tty_struct *tty) static int hso_serial_write_room(struct tty_struct *tty)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
int room; int room;
unsigned long flags; unsigned long flags;
...@@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty) ...@@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)
/* setup the term */ /* setup the term */
static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
unsigned long flags; unsigned long flags;
if (old) if (old)
...@@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) ...@@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
/* the actual setup */ /* the actual setup */
spin_lock_irqsave(&serial->serial_lock, flags); spin_lock_irqsave(&serial->serial_lock, flags);
if (serial->open_count) if (serial->port.count)
_hso_serial_set_termios(tty, old); _hso_serial_set_termios(tty, old);
else else
tty->termios = old; tty->termios = old;
...@@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) ...@@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
/* how many characters in the buffer */ /* how many characters in the buffer */
static int hso_serial_chars_in_buffer(struct tty_struct *tty) static int hso_serial_chars_in_buffer(struct tty_struct *tty)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
int chars; int chars;
unsigned long flags; unsigned long flags;
...@@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty, ...@@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,
struct serial_icounter_struct *icount) struct serial_icounter_struct *icount)
{ {
struct uart_icount cnow; struct uart_icount cnow;
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
struct hso_tiocmget *tiocmget = serial->tiocmget; struct hso_tiocmget *tiocmget = serial->tiocmget;
memset(icount, 0, sizeof(struct serial_icounter_struct)); memset(icount, 0, sizeof(struct serial_icounter_struct));
...@@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty, ...@@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,
static int hso_serial_tiocmget(struct tty_struct *tty) static int hso_serial_tiocmget(struct tty_struct *tty)
{ {
int retval; int retval;
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
struct hso_tiocmget *tiocmget; struct hso_tiocmget *tiocmget;
u16 UART_state_bitmap; u16 UART_state_bitmap;
...@@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, ...@@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
int val = 0; int val = 0;
unsigned long flags; unsigned long flags;
int if_num; int if_num;
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
/* sanity check */ /* sanity check */
if (!serial) { if (!serial) {
...@@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, ...@@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
static int hso_serial_ioctl(struct tty_struct *tty, static int hso_serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct hso_serial *serial = get_serial_by_tty(tty); struct hso_serial *serial = tty->driver_data;
int ret = 0; int ret = 0;
D4("IOCTL cmd: %d, arg: %ld", cmd, arg); D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
...@@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb) ...@@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)
D1("Pending read interrupt on port %d\n", i); D1("Pending read interrupt on port %d\n", i);
spin_lock(&serial->serial_lock); spin_lock(&serial->serial_lock);
if (serial->rx_state == RX_IDLE && if (serial->rx_state == RX_IDLE &&
serial->open_count > 0) { serial->port.count > 0) {
/* Setup and send a ctrl req read on /* Setup and send a ctrl req read on
* port i */ * port i */
if (!serial->rx_urb_filled[0]) { if (!serial->rx_urb_filled[0]) {
...@@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) ...@@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
spin_lock(&serial->serial_lock); spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0; serial->tx_urb_used = 0;
tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock); spin_unlock(&serial->serial_lock);
if (status) { if (status) {
handle_usb_error(status, __func__, serial->parent); handle_usb_error(status, __func__, serial->parent);
tty_kref_put(tty);
return; return;
} }
hso_put_activity(serial->parent); hso_put_activity(serial->parent);
tty = tty_port_tty_get(&serial->port);
if (tty) { if (tty) {
tty_wakeup(tty); tty_wakeup(tty);
tty_kref_put(tty); tty_kref_put(tty);
...@@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb) ...@@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)
struct hso_serial *serial = urb->context; struct hso_serial *serial = urb->context;
struct usb_ctrlrequest *req; struct usb_ctrlrequest *req;
int status = urb->status; int status = urb->status;
struct tty_struct *tty;
/* sanity check */ /* sanity check */
if (!serial) if (!serial)
...@@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb) ...@@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)
spin_lock(&serial->serial_lock); spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0; serial->tx_urb_used = 0;
tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock); spin_unlock(&serial->serial_lock);
if (status) { if (status) {
handle_usb_error(status, __func__, serial->parent); handle_usb_error(status, __func__, serial->parent);
tty_kref_put(tty);
return; return;
} }
...@@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb) ...@@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)
put_rxbuf_data_and_resubmit_ctrl_urb(serial); put_rxbuf_data_and_resubmit_ctrl_urb(serial);
spin_unlock(&serial->serial_lock); spin_unlock(&serial->serial_lock);
} else { } else {
struct tty_struct *tty = tty_port_tty_get(&serial->port);
hso_put_activity(serial->parent); hso_put_activity(serial->parent);
if (tty) if (tty) {
tty_wakeup(tty); tty_wakeup(tty);
tty_kref_put(tty);
}
/* response to a write command */ /* response to a write command */
hso_kick_transmit(serial); hso_kick_transmit(serial);
} }
tty_kref_put(tty);
} }
/* handle RX data for serial port */ /* handle RX data for serial port */
...@@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) ...@@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
return -2; return -2;
} }
/* All callers to put_rxbuf_data hold serial_lock */ tty = tty_port_tty_get(&serial->port);
tty = tty_kref_get(serial->tty);
/* Push data to tty */ /* Push data to tty */
if (tty) { if (tty) {
...@@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) ...@@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
write_length_remaining -= curr_write_len; write_length_remaining -= curr_write_len;
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }
tty_kref_put(tty);
} }
if (write_length_remaining == 0) { if (write_length_remaining == 0) {
serial->curr_rx_urb_offset = 0; serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
} }
tty_kref_put(tty);
return write_length_remaining; return write_length_remaining;
} }
...@@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, ...@@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->minor = minor; serial->minor = minor;
serial->magic = HSO_SERIAL_MAGIC; serial->magic = HSO_SERIAL_MAGIC;
spin_lock_init(&serial->serial_lock); spin_lock_init(&serial->serial_lock);
tty_port_init(&serial->port);
serial->num_rx_urbs = num_urbs; serial->num_rx_urbs = num_urbs;
/* RX, allocate urb and initialize */ /* RX, allocate urb and initialize */
...@@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface) ...@@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)
/* Start all serial ports */ /* Start all serial ports */
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i] && (serial_table[i]->interface == iface)) { if (serial_table[i] && (serial_table[i]->interface == iface)) {
if (dev2ser(serial_table[i])->open_count) { if (dev2ser(serial_table[i])->port.count) {
result = result =
hso_start_serial_device(serial_table[i], GFP_NOIO); hso_start_serial_device(serial_table[i], GFP_NOIO);
hso_kick_transmit(dev2ser(serial_table[i])); hso_kick_transmit(dev2ser(serial_table[i]));
...@@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface) ...@@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)
if (serial_table[i] && if (serial_table[i] &&
(serial_table[i]->interface == interface)) { (serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]); hso_dev = dev2ser(serial_table[i]);
spin_lock_irq(&hso_dev->serial_lock); tty = tty_port_tty_get(&hso_dev->port);
tty = tty_kref_get(hso_dev->tty); if (tty) {
spin_unlock_irq(&hso_dev->serial_lock);
if (tty)
tty_hangup(tty); tty_hangup(tty);
tty_kref_put(tty);
}
mutex_lock(&hso_dev->parent->mutex); mutex_lock(&hso_dev->parent->mutex);
tty_kref_put(tty);
hso_dev->parent->usb_gone = 1; hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex); mutex_unlock(&hso_dev->parent->mutex);
kref_put(&serial_table[i]->ref, hso_serial_ref_free); kref_put(&serial_table[i]->ref, hso_serial_ref_free);
...@@ -3312,7 +3292,6 @@ static int __init hso_init(void) ...@@ -3312,7 +3292,6 @@ static int __init hso_init(void)
return -ENOMEM; return -ENOMEM;
/* fill in all needed values */ /* fill in all needed values */
tty_drv->magic = TTY_DRIVER_MAGIC;
tty_drv->driver_name = driver_name; tty_drv->driver_name = driver_name;
tty_drv->name = tty_filename; tty_drv->name = tty_filename;
...@@ -3333,7 +3312,7 @@ static int __init hso_init(void) ...@@ -3333,7 +3312,7 @@ static int __init hso_init(void)
if (result) { if (result) {
printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
__func__, result); __func__, result);
return result; goto err_free_tty;
} }
/* register this module as an usb driver */ /* register this module as an usb driver */
...@@ -3341,13 +3320,16 @@ static int __init hso_init(void) ...@@ -3341,13 +3320,16 @@ static int __init hso_init(void)
if (result) { if (result) {
printk(KERN_ERR "Could not register hso driver? error: %d\n", printk(KERN_ERR "Could not register hso driver? error: %d\n",
result); result);
/* cleanup serial interface */ goto err_unreg_tty;
tty_unregister_driver(tty_drv);
return result;
} }
/* done */ /* done */
return 0; return 0;
err_unreg_tty:
tty_unregister_driver(tty_drv);
err_free_tty:
put_tty_driver(tty_drv);
return result;
} }
static void __exit hso_exit(void) static void __exit hso_exit(void)
...@@ -3355,6 +3337,7 @@ static void __exit hso_exit(void) ...@@ -3355,6 +3337,7 @@ static void __exit hso_exit(void)
printk(KERN_INFO "hso: unloaded\n"); printk(KERN_INFO "hso: unloaded\n");
tty_unregister_driver(tty_drv); tty_unregister_driver(tty_drv);
put_tty_driver(tty_drv);
/* deregister the usb driver */ /* deregister the usb driver */
usb_deregister(&hso_driver); usb_deregister(&hso_driver);
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/serial.h> /* ASYNC_* flags */
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/cio.h> #include <asm/cio.h>
...@@ -44,14 +45,11 @@ ...@@ -44,14 +45,11 @@
#define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */
#define RAW3215_FIXED 1 /* 3215 console device is not be freed */ #define RAW3215_FIXED 1 /* 3215 console device is not be freed */
#define RAW3215_ACTIVE 2 /* set if the device is in use */
#define RAW3215_WORKING 4 /* set if a request is being worked on */ #define RAW3215_WORKING 4 /* set if a request is being worked on */
#define RAW3215_THROTTLED 8 /* set if reading is disabled */ #define RAW3215_THROTTLED 8 /* set if reading is disabled */
#define RAW3215_STOPPED 16 /* set if writing is disabled */ #define RAW3215_STOPPED 16 /* set if writing is disabled */
#define RAW3215_CLOSING 32 /* set while in close process */
#define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */
#define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */
#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */
#define TAB_STOP_SIZE 8 /* tab stop size */ #define TAB_STOP_SIZE 8 /* tab stop size */
...@@ -76,6 +74,7 @@ struct raw3215_req { ...@@ -76,6 +74,7 @@ struct raw3215_req {
} __attribute__ ((aligned(8))); } __attribute__ ((aligned(8)));
struct raw3215_info { struct raw3215_info {
struct tty_port port;
struct ccw_device *cdev; /* device for tty driver */ struct ccw_device *cdev; /* device for tty driver */
spinlock_t *lock; /* pointer to irq lock */ spinlock_t *lock; /* pointer to irq lock */
int flags; /* state flags */ int flags; /* state flags */
...@@ -84,7 +83,6 @@ struct raw3215_info { ...@@ -84,7 +83,6 @@ struct raw3215_info {
int head; /* first free byte in output buffer */ int head; /* first free byte in output buffer */
int count; /* number of bytes in output buffer */ int count; /* number of bytes in output buffer */
int written; /* number of bytes in write requests */ int written; /* number of bytes in write requests */
struct tty_struct *tty; /* pointer to tty structure if present */
struct raw3215_req *queued_read; /* pointer to queued read requests */ struct raw3215_req *queued_read; /* pointer to queued read requests */
struct raw3215_req *queued_write;/* pointer to queued write requests */ struct raw3215_req *queued_write;/* pointer to queued write requests */
struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */ struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
...@@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data) ...@@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)
if (raw->flags & RAW3215_TIMER_RUNS) { if (raw->flags & RAW3215_TIMER_RUNS) {
del_timer(&raw->timer); del_timer(&raw->timer);
raw->flags &= ~RAW3215_TIMER_RUNS; raw->flags &= ~RAW3215_TIMER_RUNS;
if (!(raw->flags & RAW3215_FROZEN)) { if (!(raw->port.flags & ASYNC_SUSPENDED)) {
raw3215_mk_write_req(raw); raw3215_mk_write_req(raw);
raw3215_start_io(raw); raw3215_start_io(raw);
} }
...@@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data) ...@@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)
*/ */
static inline void raw3215_try_io(struct raw3215_info *raw) static inline void raw3215_try_io(struct raw3215_info *raw)
{ {
if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) if (!(raw->port.flags & ASYNC_INITIALIZED) ||
(raw->port.flags & ASYNC_SUSPENDED))
return; return;
if (raw->queued_read != NULL) if (raw->queued_read != NULL)
raw3215_start_io(raw); raw3215_start_io(raw);
...@@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw) ...@@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
} }
} else if (!(raw->flags & RAW3215_TIMER_RUNS)) { } else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
/* delay small writes */ /* delay small writes */
init_timer(&raw->timer);
raw->timer.expires = RAW3215_TIMEOUT + jiffies; raw->timer.expires = RAW3215_TIMEOUT + jiffies;
raw->timer.data = (unsigned long) raw;
raw->timer.function = raw3215_timeout;
add_timer(&raw->timer); add_timer(&raw->timer);
raw->flags |= RAW3215_TIMER_RUNS; raw->flags |= RAW3215_TIMER_RUNS;
} }
...@@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw) ...@@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
static void raw3215_wakeup(unsigned long data) static void raw3215_wakeup(unsigned long data)
{ {
struct raw3215_info *raw = (struct raw3215_info *) data; struct raw3215_info *raw = (struct raw3215_info *) data;
tty_wakeup(raw->tty); struct tty_struct *tty;
tty = tty_port_tty_get(&raw->port);
tty_wakeup(tty);
tty_kref_put(tty);
} }
/* /*
* Try to start the next IO and wake up processes waiting on the tty. * Try to start the next IO and wake up processes waiting on the tty.
*/ */
static void raw3215_next_io(struct raw3215_info *raw) static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)
{ {
raw3215_mk_write_req(raw); raw3215_mk_write_req(raw);
raw3215_try_io(raw); raw3215_try_io(raw);
if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
tasklet_schedule(&raw->tlet); tasklet_schedule(&raw->tlet);
} }
...@@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw = dev_get_drvdata(&cdev->dev); raw = dev_get_drvdata(&cdev->dev);
req = (struct raw3215_req *) intparm; req = (struct raw3215_req *) intparm;
tty = tty_port_tty_get(&raw->port);
cstat = irb->scsw.cmd.cstat; cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat; dstat = irb->scsw.cmd.dstat;
if (cstat != 0) if (cstat != 0)
raw3215_next_io(raw); raw3215_next_io(raw, tty);
if (dstat & 0x01) { /* we got a unit exception */ if (dstat & 0x01) { /* we got a unit exception */
dstat &= ~0x01; /* we can ignore it */ dstat &= ~0x01; /* we can ignore it */
} }
...@@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
break; break;
/* Attention interrupt, someone hit the enter key */ /* Attention interrupt, someone hit the enter key */
raw3215_mk_read_req(raw); raw3215_mk_read_req(raw);
raw3215_next_io(raw); raw3215_next_io(raw, tty);
break; break;
case 0x08: case 0x08:
case 0x0C: case 0x0C:
/* Channel end interrupt. */ /* Channel end interrupt. */
if ((raw = req->info) == NULL) if ((raw = req->info) == NULL)
return; /* That shouldn't happen ... */ goto put_tty; /* That shouldn't happen ... */
if (req->type == RAW3215_READ) { if (req->type == RAW3215_READ) {
/* store residual count, then wait for device end */ /* store residual count, then wait for device end */
req->residual = irb->scsw.cmd.count; req->residual = irb->scsw.cmd.count;
...@@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
case 0x04: case 0x04:
/* Device end interrupt. */ /* Device end interrupt. */
if ((raw = req->info) == NULL) if ((raw = req->info) == NULL)
return; /* That shouldn't happen ... */ goto put_tty; /* That shouldn't happen ... */
if (req->type == RAW3215_READ && raw->tty != NULL) { if (req->type == RAW3215_READ && tty != NULL) {
unsigned int cchar; unsigned int cchar;
tty = raw->tty;
count = 160 - req->residual; count = 160 - req->residual;
EBCASC(raw->inbuf, count); EBCASC(raw->inbuf, count);
cchar = ctrlchar_handle(raw->inbuf, count, tty); cchar = ctrlchar_handle(raw->inbuf, count, tty);
...@@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
case CTRLCHAR_CTRL: case CTRLCHAR_CTRL:
tty_insert_flip_char(tty, cchar, TTY_NORMAL); tty_insert_flip_char(tty, cchar, TTY_NORMAL);
tty_flip_buffer_push(raw->tty); tty_flip_buffer_push(tty);
break; break;
case CTRLCHAR_NONE: case CTRLCHAR_NONE:
...@@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
} else } else
count -= 2; count -= 2;
tty_insert_flip_string(tty, raw->inbuf, count); tty_insert_flip_string(tty, raw->inbuf, count);
tty_flip_buffer_push(raw->tty); tty_flip_buffer_push(tty);
break; break;
} }
} else if (req->type == RAW3215_WRITE) { } else if (req->type == RAW3215_WRITE) {
...@@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw->queued_read == NULL) { raw->queued_read == NULL) {
wake_up_interruptible(&raw->empty_wait); wake_up_interruptible(&raw->empty_wait);
} }
raw3215_next_io(raw); raw3215_next_io(raw, tty);
break; break;
default: default:
/* Strange interrupt, I'll do my best to clean up */ /* Strange interrupt, I'll do my best to clean up */
...@@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw->flags &= ~RAW3215_WORKING; raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req); raw3215_free_req(req);
} }
raw3215_next_io(raw); raw3215_next_io(raw, tty);
} }
return; put_tty:
tty_kref_put(tty);
} }
/* /*
...@@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) ...@@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
/* While console is frozen for suspend we have no other /* While console is frozen for suspend we have no other
* choice but to drop message from the buffer to make * choice but to drop message from the buffer to make
* room for even more messages. */ * room for even more messages. */
if (raw->flags & RAW3215_FROZEN) { if (raw->port.flags & ASYNC_SUSPENDED) {
raw3215_drop_line(raw); raw3215_drop_line(raw);
continue; continue;
} }
...@@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw) ...@@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)
{ {
unsigned long flags; unsigned long flags;
if (raw->flags & RAW3215_ACTIVE) if (raw->port.flags & ASYNC_INITIALIZED)
return 0; return 0;
raw->line_pos = 0; raw->line_pos = 0;
raw->flags |= RAW3215_ACTIVE; raw->port.flags |= ASYNC_INITIALIZED;
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_try_io(raw); raw3215_try_io(raw);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
...@@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw) ...@@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
unsigned long flags; unsigned long flags;
if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) if (!(raw->port.flags & ASYNC_INITIALIZED) ||
(raw->flags & RAW3215_FIXED))
return; return;
/* Wait for outstanding requests, then free irq */ /* Wait for outstanding requests, then free irq */
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
if ((raw->flags & RAW3215_WORKING) || if ((raw->flags & RAW3215_WORKING) ||
raw->queued_write != NULL || raw->queued_write != NULL ||
raw->queued_read != NULL) { raw->queued_read != NULL) {
raw->flags |= RAW3215_CLOSING; raw->port.flags |= ASYNC_CLOSING;
add_wait_queue(&raw->empty_wait, &wait); add_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
...@@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw) ...@@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait); remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
} }
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
} }
static struct raw3215_info *raw3215_alloc_info(void)
{
struct raw3215_info *info;
info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
if (!info)
return NULL;
info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
if (!info->buffer || !info->inbuf) {
kfree(info);
return NULL;
}
setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
init_waitqueue_head(&info->empty_wait);
tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
tty_port_init(&info->port);
return info;
}
static void raw3215_free_info(struct raw3215_info *raw)
{
kfree(raw->inbuf);
kfree(raw->buffer);
kfree(raw);
}
static int raw3215_probe (struct ccw_device *cdev) static int raw3215_probe (struct ccw_device *cdev)
{ {
struct raw3215_info *raw; struct raw3215_info *raw;
...@@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev) ...@@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)
/* Console is special. */ /* Console is special. */
if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev))) if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
return 0; return 0;
raw = kmalloc(sizeof(struct raw3215_info) +
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); raw = raw3215_alloc_info();
if (raw == NULL) if (raw == NULL)
return -ENOMEM; return -ENOMEM;
raw->cdev = cdev;
dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq;
spin_lock(&raw3215_device_lock); spin_lock(&raw3215_device_lock);
for (line = 0; line < NR_3215; line++) { for (line = 0; line < NR_3215; line++) {
if (!raw3215[line]) { if (!raw3215[line]) {
...@@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev) ...@@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)
} }
spin_unlock(&raw3215_device_lock); spin_unlock(&raw3215_device_lock);
if (line == NR_3215) { if (line == NR_3215) {
kfree(raw); raw3215_free_info(raw);
return -ENODEV; return -ENODEV;
} }
raw->cdev = cdev;
raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
memset(raw, 0, sizeof(struct raw3215_info));
raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
GFP_KERNEL|GFP_DMA);
if (raw->buffer == NULL) {
spin_lock(&raw3215_device_lock);
raw3215[line] = NULL;
spin_unlock(&raw3215_device_lock);
kfree(raw);
return -ENOMEM;
}
init_waitqueue_head(&raw->empty_wait);
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq;
return 0; return 0;
} }
...@@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev) ...@@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)
raw = dev_get_drvdata(&cdev->dev); raw = dev_get_drvdata(&cdev->dev);
if (raw) { if (raw) {
dev_set_drvdata(&cdev->dev, NULL); dev_set_drvdata(&cdev->dev, NULL);
kfree(raw->buffer); raw3215_free_info(raw);
kfree(raw);
} }
} }
...@@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev) ...@@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
raw = dev_get_drvdata(&cdev->dev); raw = dev_get_drvdata(&cdev->dev);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_make_room(raw, RAW3215_BUFFER_SIZE); raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
raw->flags |= RAW3215_FROZEN; raw->port.flags |= ASYNC_SUSPENDED;
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
return 0; return 0;
} }
...@@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev) ...@@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
/* Allow I/O again and flush output buffer. */ /* Allow I/O again and flush output buffer. */
raw = dev_get_drvdata(&cdev->dev); raw = dev_get_drvdata(&cdev->dev);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw->flags &= ~RAW3215_FROZEN; raw->port.flags &= ~ASYNC_SUSPENDED;
raw->flags |= RAW3215_FLUSHING; raw->flags |= RAW3215_FLUSHING;
raw3215_try_io(raw); raw3215_try_io(raw);
raw->flags &= ~RAW3215_FLUSHING; raw->flags &= ~RAW3215_FLUSHING;
...@@ -827,7 +844,7 @@ static void con3215_flush(void) ...@@ -827,7 +844,7 @@ static void con3215_flush(void)
unsigned long flags; unsigned long flags;
raw = raw3215[0]; /* console 3215 is the first one */ raw = raw3215[0]; /* console 3215 is the first one */
if (raw->flags & RAW3215_FROZEN) if (raw->port.flags & ASYNC_SUSPENDED)
/* The console is still frozen for suspend. */ /* The console is still frozen for suspend. */
if (ccw_device_force_console()) if (ccw_device_force_console())
/* Forcing didn't work, no panic message .. */ /* Forcing didn't work, no panic message .. */
...@@ -897,23 +914,16 @@ static int __init con3215_init(void) ...@@ -897,23 +914,16 @@ static int __init con3215_init(void)
if (IS_ERR(cdev)) if (IS_ERR(cdev))
return -ENODEV; return -ENODEV;
raw3215[0] = raw = (struct raw3215_info *) raw3215[0] = raw = raw3215_alloc_info();
kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
raw->cdev = cdev; raw->cdev = cdev;
dev_set_drvdata(&cdev->dev, raw); dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq; cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED; raw->flags |= RAW3215_FIXED;
init_waitqueue_head(&raw->empty_wait);
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
/* Request the console irq */ /* Request the console irq */
if (raw3215_startup(raw) != 0) { if (raw3215_startup(raw) != 0) {
kfree(raw->inbuf); raw3215_free_info(raw);
kfree(raw->buffer);
kfree(raw);
raw3215[0] = NULL; raw3215[0] = NULL;
return -ENODEV; return -ENODEV;
} }
...@@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp) ...@@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
return -ENODEV; return -ENODEV;
tty->driver_data = raw; tty->driver_data = raw;
raw->tty = tty; tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */ tty->low_latency = 0; /* don't use bottom half for pushing chars */
/* /*
...@@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp) ...@@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
raw3215_shutdown(raw); raw3215_shutdown(raw);
tasklet_kill(&raw->tlet); tasklet_kill(&raw->tlet);
tty->closing = 0; tty->closing = 0;
raw->tty = NULL; tty_port_tty_set(&raw->port, NULL);
} }
/* /*
......
...@@ -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 */
......
...@@ -61,7 +61,7 @@ struct tty3270_line { ...@@ -61,7 +61,7 @@ struct tty3270_line {
*/ */
struct tty3270 { struct tty3270 {
struct raw3270_view view; struct raw3270_view view;
struct tty_struct *tty; /* Pointer to tty structure */ struct tty_port port;
void **freemem_pages; /* Array of pages used for freemem. */ void **freemem_pages; /* Array of pages used for freemem. */
struct list_head freemem; /* List of free memory for strings. */ struct list_head freemem; /* List of free memory for strings. */
...@@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp) ...@@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)
static void static void
tty3270_write_callback(struct raw3270_request *rq, void *data) tty3270_write_callback(struct raw3270_request *rq, void *data)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
tp = (struct tty3270 *) rq->view;
if (rq->rc != 0) { if (rq->rc != 0) {
/* Write wasn't successful. Refresh all. */ /* Write wasn't successful. Refresh all. */
tp->update_flags = TTY_UPDATE_ALL; tp->update_flags = TTY_UPDATE_ALL;
...@@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len) ...@@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
static void static void
tty3270_rcl_backward(struct kbd_data *kbd) tty3270_rcl_backward(struct kbd_data *kbd)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
struct string *s; struct string *s;
tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock); spin_lock_bh(&tp->view.lock);
if (tp->inattr == TF_INPUT) { if (tp->inattr == TF_INPUT) {
if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines) if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
...@@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd) ...@@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
static void static void
tty3270_exit_tty(struct kbd_data *kbd) tty3270_exit_tty(struct kbd_data *kbd)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
tp = kbd->tty->driver_data;
raw3270_deactivate_view(&tp->view); raw3270_deactivate_view(&tp->view);
} }
...@@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd) ...@@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
static void static void
tty3270_scroll_forward(struct kbd_data *kbd) tty3270_scroll_forward(struct kbd_data *kbd)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
int nr_up; int nr_up;
tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock); spin_lock_bh(&tp->view.lock);
nr_up = tp->nr_up - tp->view.rows + 2; nr_up = tp->nr_up - tp->view.rows + 2;
if (nr_up < 0) if (nr_up < 0)
...@@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd) ...@@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
static void static void
tty3270_scroll_backward(struct kbd_data *kbd) tty3270_scroll_backward(struct kbd_data *kbd)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
int nr_up; int nr_up;
tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock); spin_lock_bh(&tp->view.lock);
nr_up = tp->nr_up + tp->view.rows - 2; nr_up = tp->nr_up + tp->view.rows - 2;
if (nr_up + tp->view.rows - 2 > tp->nr_lines) if (nr_up + tp->view.rows - 2 > tp->nr_lines)
...@@ -537,11 +532,10 @@ static void ...@@ -537,11 +532,10 @@ static void
tty3270_read_tasklet(struct raw3270_request *rrq) tty3270_read_tasklet(struct raw3270_request *rrq)
{ {
static char kreset_data = TW_KR; static char kreset_data = TW_KR;
struct tty3270 *tp; struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
char *input; char *input;
int len; int len;
tp = (struct tty3270 *) rrq->view;
spin_lock_bh(&tp->view.lock); spin_lock_bh(&tp->view.lock);
/* /*
* Two AID keys are special: For 0x7d (enter) the input line * Two AID keys are special: For 0x7d (enter) the input line
...@@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq) ...@@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
raw3270_request_add_data(tp->kreset, &kreset_data, 1); raw3270_request_add_data(tp->kreset, &kreset_data, 1);
raw3270_start(&tp->view, tp->kreset); raw3270_start(&tp->view, tp->kreset);
/* Emit input string. */ while (len-- > 0)
if (tp->tty) { kbd_keycode(tp->kbd, *input++);
while (len-- > 0) /* Emit keycode for AID byte. */
kbd_keycode(tp->kbd, *input++); kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
/* Emit keycode for AID byte. */
kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
}
raw3270_request_reset(rrq); raw3270_request_reset(rrq);
xchg(&tp->read, rrq); xchg(&tp->read, rrq);
...@@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq) ...@@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
static void static void
tty3270_read_callback(struct raw3270_request *rq, void *data) tty3270_read_callback(struct raw3270_request *rq, void *data)
{ {
struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
raw3270_get_view(rq->view); raw3270_get_view(rq->view);
/* Schedule tasklet to pass input to tty. */ /* Schedule tasklet to pass input to tty. */
tasklet_schedule(&((struct tty3270 *) rq->view)->readlet); tasklet_schedule(&tp->readlet);
} }
/* /*
...@@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock) ...@@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock)
static int static int
tty3270_activate(struct raw3270_view *view) tty3270_activate(struct raw3270_view *view)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(view, struct tty3270, view);
tp = (struct tty3270 *) view;
tp->update_flags = TTY_UPDATE_ALL; tp->update_flags = TTY_UPDATE_ALL;
tty3270_set_timer(tp, 1); tty3270_set_timer(tp, 1);
return 0; return 0;
...@@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view) ...@@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)
static void static void
tty3270_deactivate(struct raw3270_view *view) tty3270_deactivate(struct raw3270_view *view)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(view, struct tty3270, view);
tp = (struct tty3270 *) view;
del_timer(&tp->timer); del_timer(&tp->timer);
} }
...@@ -690,6 +680,17 @@ tty3270_alloc_view(void) ...@@ -690,6 +680,17 @@ tty3270_alloc_view(void)
if (!tp->freemem_pages) if (!tp->freemem_pages)
goto out_tp; goto out_tp;
INIT_LIST_HEAD(&tp->freemem); INIT_LIST_HEAD(&tp->freemem);
INIT_LIST_HEAD(&tp->lines);
INIT_LIST_HEAD(&tp->update);
INIT_LIST_HEAD(&tp->rcl_lines);
tp->rcl_max = 20;
tty_port_init(&tp->port);
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
(unsigned long) tp);
tasklet_init(&tp->readlet,
(void (*)(unsigned long)) tty3270_read_tasklet,
(unsigned long) tp->read);
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) { for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
tp->freemem_pages[pages] = (void *) tp->freemem_pages[pages] = (void *)
__get_free_pages(GFP_KERNEL|GFP_DMA, 0); __get_free_pages(GFP_KERNEL|GFP_DMA, 0);
...@@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp) ...@@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)
static void static void
tty3270_release(struct raw3270_view *view) tty3270_release(struct raw3270_view *view)
{ {
struct tty3270 *tp; struct tty3270 *tp = container_of(view, struct tty3270, view);
struct tty_struct *tty; struct tty_struct *tty = tty_port_tty_get(&tp->port);
tp = (struct tty3270 *) view;
tty = tp->tty;
if (tty) { if (tty) {
tty->driver_data = NULL; tty->driver_data = NULL;
tp->tty = tp->kbd->tty = NULL; tty_port_tty_set(&tp->port, NULL);
tty_hangup(tty); tty_hangup(tty);
raw3270_put_view(&tp->view); raw3270_put_view(&tp->view);
tty_kref_put(tty);
} }
} }
...@@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view) ...@@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)
static void static void
tty3270_free(struct raw3270_view *view) tty3270_free(struct raw3270_view *view)
{ {
tty3270_free_screen((struct tty3270 *) view); struct tty3270 *tp = container_of(view, struct tty3270, view);
tty3270_free_view((struct tty3270 *) view); tty3270_free_screen(tp);
tty3270_free_view(tp);
} }
/* /*
...@@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view) ...@@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)
static void static void
tty3270_del_views(void) tty3270_del_views(void)
{ {
struct tty3270 *tp;
int i; int i;
for (i = 0; i < tty3270_max_index; i++) { for (i = 0; i < tty3270_max_index; i++) {
tp = (struct tty3270 *) struct raw3270_view *view =
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR); raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
if (!IS_ERR(tp)) if (!IS_ERR(view))
raw3270_del_view(&tp->view); raw3270_del_view(view);
} }
} }
...@@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = { ...@@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {
static int static int
tty3270_open(struct tty_struct *tty, struct file * filp) tty3270_open(struct tty_struct *tty, struct file * filp)
{ {
struct raw3270_view *view;
struct tty3270 *tp; struct tty3270 *tp;
int i, rc; int i, rc;
if (tty->count > 1) if (tty->count > 1)
return 0; return 0;
/* Check if the tty3270 is already there. */ /* Check if the tty3270 is already there. */
tp = (struct tty3270 *) view = raw3270_find_view(&tty3270_fn,
raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR); tty->index + RAW3270_FIRSTMINOR);
if (!IS_ERR(tp)) { if (!IS_ERR(view)) {
tp = container_of(view, struct tty3270, view);
tty->driver_data = tp; tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols; tty->winsize.ws_col = tp->view.cols;
tty->low_latency = 0; tty->low_latency = 0;
tp->tty = tty; /* why to reassign? */
tp->kbd->tty = tty; tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT; tp->inattr = TF_INPUT;
return 0; return 0;
} }
...@@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) ...@@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tty3270_max_index = tty->index + 1; tty3270_max_index = tty->index + 1;
/* Quick exit if there is no device for tty->index. */ /* Quick exit if there is no device for tty->index. */
if (PTR_ERR(tp) == -ENODEV) if (PTR_ERR(view) == -ENODEV)
return -ENODEV; return -ENODEV;
/* Allocate tty3270 structure on first open. */ /* Allocate tty3270 structure on first open. */
...@@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp) ...@@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
if (IS_ERR(tp)) if (IS_ERR(tp))
return PTR_ERR(tp); return PTR_ERR(tp);
INIT_LIST_HEAD(&tp->lines);
INIT_LIST_HEAD(&tp->update);
INIT_LIST_HEAD(&tp->rcl_lines);
tp->rcl_max = 20;
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
(unsigned long) tp);
tasklet_init(&tp->readlet,
(void (*)(unsigned long)) tty3270_read_tasklet,
(unsigned long) tp->read);
rc = raw3270_add_view(&tp->view, &tty3270_fn, rc = raw3270_add_view(&tp->view, &tty3270_fn,
tty->index + RAW3270_FIRSTMINOR); tty->index + RAW3270_FIRSTMINOR);
if (rc) { if (rc) {
...@@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) ...@@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
return rc; return rc;
} }
tp->tty = tty; tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0; tty->low_latency = 0;
tty->driver_data = tp; tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_row = tp->view.rows - 2;
...@@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) ...@@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
for (i = 0; i < tp->view.rows - 2; i++) for (i = 0; i < tp->view.rows - 2; i++)
tty3270_blank_line(tp); tty3270_blank_line(tp);
tp->kbd->tty = tty; tp->kbd->port = &tp->port;
tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty; tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward; tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward; tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
...@@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp) ...@@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
static void static void
tty3270_close(struct tty_struct *tty, struct file * filp) tty3270_close(struct tty_struct *tty, struct file * filp)
{ {
struct tty3270 *tp; struct tty3270 *tp = tty->driver_data;
if (tty->count > 1) if (tty->count > 1)
return; return;
tp = (struct tty3270 *) tty->driver_data;
if (tp) { if (tp) {
tty->driver_data = NULL; tty->driver_data = NULL;
tp->tty = tp->kbd->tty = NULL; tty_port_tty_set(&tp->port, NULL);
raw3270_put_view(&tp->view); raw3270_put_view(&tp->view);
} }
} }
...@@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch) ...@@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
tty3270_lf(tp); tty3270_lf(tp);
break; break;
case 'Z': /* Respond ID. */ case 'Z': /* Respond ID. */
kbd_puts_queue(tp->tty, "\033[?6c"); kbd_puts_queue(&tp->port, "\033[?6c");
break; break;
case '7': /* Save cursor position. */ case '7': /* Save cursor position. */
tp->saved_cx = tp->cx; tp->saved_cx = tp->cx;
...@@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch) ...@@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
tp->esc_state = ESnormal; tp->esc_state = ESnormal;
if (ch == 'n' && !tp->esc_ques) { if (ch == 'n' && !tp->esc_ques) {
if (tp->esc_par[0] == 5) /* Status report. */ if (tp->esc_par[0] == 5) /* Status report. */
kbd_puts_queue(tp->tty, "\033[0n"); kbd_puts_queue(&tp->port, "\033[0n");
else if (tp->esc_par[0] == 6) { /* Cursor report. */ else if (tp->esc_par[0] == 6) { /* Cursor report. */
char buf[40]; char buf[40];
sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1); sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
kbd_puts_queue(tp->tty, buf); kbd_puts_queue(&tp->port, buf);
} }
return; return;
} }
...@@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch) ...@@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
* String write routine for 3270 ttys * String write routine for 3270 ttys
*/ */
static void static void
tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count) tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
const unsigned char *buf, int count)
{ {
int i_msg, i; int i_msg, i;
spin_lock_bh(&tp->view.lock); spin_lock_bh(&tp->view.lock);
for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) { for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
if (tp->esc_state != 0) { if (tp->esc_state != 0) {
/* Continue escape sequence. */ /* Continue escape sequence. */
tty3270_escape_sequence(tp, buf[i_msg]); tty3270_escape_sequence(tp, buf[i_msg]);
...@@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty, ...@@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,
if (!tp) if (!tp)
return 0; return 0;
if (tp->char_count > 0) { if (tp->char_count > 0) {
tty3270_do_write(tp, tp->char_buf, tp->char_count); tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
tp->char_count = 0; tp->char_count = 0;
} }
tty3270_do_write(tp, buf, count); tty3270_do_write(tp, tty, buf, count);
return count; return count;
} }
...@@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty) ...@@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)
if (!tp) if (!tp)
return; return;
if (tp->char_count > 0) { if (tp->char_count > 0) {
tty3270_do_write(tp, tp->char_buf, tp->char_count); tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
tp->char_count = 0; tp->char_count = 0;
} }
} }
......
...@@ -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;
......
...@@ -69,14 +69,13 @@ ...@@ -69,14 +69,13 @@
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) #define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
struct hvsi_struct { struct hvsi_struct {
struct tty_port port;
struct delayed_work writer; struct delayed_work writer;
struct work_struct handshaker; struct work_struct handshaker;
wait_queue_head_t emptyq; /* woken when outbuf is emptied */ wait_queue_head_t emptyq; /* woken when outbuf is emptied */
wait_queue_head_t stateq; /* woken when HVSI state changes */ wait_queue_head_t stateq; /* woken when HVSI state changes */
spinlock_t lock; spinlock_t lock;
int index; int index;
struct tty_struct *tty;
int count;
uint8_t throttle_buf[128]; uint8_t throttle_buf[128];
uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
/* inbuf is for packet reassembly. leave a little room for leftovers. */ /* inbuf is for packet reassembly. leave a little room for leftovers. */
...@@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) ...@@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
} }
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) struct tty_struct *tty, struct hvsi_struct **to_handshake)
{ {
struct hvsi_control *header = (struct hvsi_control *)packet; struct hvsi_control *header = (struct hvsi_control *)packet;
...@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, ...@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
/* CD went away; no more connection */ /* CD went away; no more connection */
pr_debug("hvsi%i: CD dropped\n", hp->index); pr_debug("hvsi%i: CD dropped\n", hp->index);
hp->mctrl &= TIOCM_CD; hp->mctrl &= TIOCM_CD;
/* If userland hasn't done an open(2) yet, hp->tty is NULL. */ if (tty && !C_CLOCAL(tty))
if (hp->tty && !(hp->tty->flags & CLOCAL)) tty_hangup(tty);
*to_hangup = hp->tty;
} }
break; break;
case VSV_CLOSE_PROTOCOL: case VSV_CLOSE_PROTOCOL:
...@@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) ...@@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
} }
} }
static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
const char *buf, int len)
{ {
int i; int i;
...@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) ...@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
continue; continue;
} }
#endif /* CONFIG_MAGIC_SYSRQ */ #endif /* CONFIG_MAGIC_SYSRQ */
tty_insert_flip_char(hp->tty, c, 0); tty_insert_flip_char(tty, c, 0);
} }
} }
...@@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) ...@@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
* revisited. * revisited.
*/ */
#define TTY_THRESHOLD_THROTTLE 128 #define TTY_THRESHOLD_THROTTLE 128
static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
const uint8_t *packet) const uint8_t *packet)
{ {
const struct hvsi_header *header = (const struct hvsi_header *)packet; const struct hvsi_header *header = (const struct hvsi_header *)packet;
...@@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, ...@@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
if (datalen == 0) if (datalen == 0)
return NULL; return false;
if (overflow > 0) { if (overflow > 0) {
pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE; datalen = TTY_THRESHOLD_THROTTLE;
} }
hvsi_insert_chars(hp, data, datalen); hvsi_insert_chars(hp, tty, data, datalen);
if (overflow > 0) { if (overflow > 0) {
/* /*
...@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, ...@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
hp->n_throttle = overflow; hp->n_throttle = overflow;
} }
return hp->tty; return true;
} }
/* /*
...@@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, ...@@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
* machine during console handshaking (in which case tty = NULL and we ignore * machine during console handshaking (in which case tty = NULL and we ignore
* incoming data). * incoming data).
*/ */
static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
struct tty_struct **hangup, struct hvsi_struct **handshake) struct hvsi_struct **handshake)
{ {
uint8_t *packet = hp->inbuf; uint8_t *packet = hp->inbuf;
int chunklen; int chunklen;
bool flip = false;
*flip = NULL;
*hangup = NULL;
*handshake = NULL; *handshake = NULL;
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
...@@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, ...@@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
case VS_DATA_PACKET_HEADER: case VS_DATA_PACKET_HEADER:
if (!is_open(hp)) if (!is_open(hp))
break; break;
if (hp->tty == NULL) if (tty == NULL)
break; /* no tty buffer to put data in */ break; /* no tty buffer to put data in */
*flip = hvsi_recv_data(hp, packet); flip = hvsi_recv_data(hp, tty, packet);
break; break;
case VS_CONTROL_PACKET_HEADER: case VS_CONTROL_PACKET_HEADER:
hvsi_recv_control(hp, packet, hangup, handshake); hvsi_recv_control(hp, packet, tty, handshake);
break; break;
case VS_QUERY_RESPONSE_PACKET_HEADER: case VS_QUERY_RESPONSE_PACKET_HEADER:
hvsi_recv_response(hp, packet); hvsi_recv_response(hp, packet);
...@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, ...@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
packet += len_packet(packet); packet += len_packet(packet);
if (*hangup || *handshake) { if (*handshake) {
pr_debug("%s: hangup or handshake\n", __func__); pr_debug("%s: handshake\n", __func__);
/*
* we need to send the hangup now before receiving any more data.
* If we get "data, hangup, data", we can't deliver the second
* data before the hangup.
*/
break; break;
} }
} }
compact_inbuf(hp, packet); compact_inbuf(hp, packet);
if (flip)
tty_flip_buffer_push(tty);
return 1; return 1;
} }
static void hvsi_send_overflow(struct hvsi_struct *hp) static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
{ {
pr_debug("%s: delivering %i bytes overflow\n", __func__, pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle); hp->n_throttle);
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
hp->n_throttle = 0; hp->n_throttle = 0;
} }
...@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp) ...@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
static irqreturn_t hvsi_interrupt(int irq, void *arg) static irqreturn_t hvsi_interrupt(int irq, void *arg)
{ {
struct hvsi_struct *hp = (struct hvsi_struct *)arg; struct hvsi_struct *hp = (struct hvsi_struct *)arg;
struct tty_struct *flip;
struct tty_struct *hangup;
struct hvsi_struct *handshake; struct hvsi_struct *handshake;
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
int again = 1; int again = 1;
pr_debug("%s\n", __func__); pr_debug("%s\n", __func__);
tty = tty_port_tty_get(&hp->port);
while (again) { while (again) {
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); again = hvsi_load_chunk(hp, tty, &handshake);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
/*
* we have to call tty_flip_buffer_push() and tty_hangup() outside our
* spinlock. But we also have to keep going until we've read all the
* available data.
*/
if (flip) {
/* there was data put in the tty flip buffer */
tty_flip_buffer_push(flip);
flip = NULL;
}
if (hangup) {
tty_hangup(hangup);
}
if (handshake) { if (handshake) {
pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
schedule_work(&handshake->handshaker); schedule_work(&handshake->handshaker);
...@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) ...@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
} }
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (hp->tty && hp->n_throttle if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { /* we weren't hung up and we weren't throttled, so we can
/* we weren't hung up and we weren't throttled, so we can deliver the * deliver the rest now */
* rest now */ hvsi_send_overflow(hp, tty);
flip = hp->tty; tty_flip_buffer_push(tty);
hvsi_send_overflow(hp);
} }
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
if (flip) { tty_kref_put(tty);
tty_flip_buffer_push(flip);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) ...@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
if (hp->state == HVSI_FSP_DIED) if (hp->state == HVSI_FSP_DIED)
return -EIO; return -EIO;
tty_port_tty_set(&hp->port, tty);
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
hp->tty = tty; hp->port.count++;
hp->count++;
atomic_set(&hp->seqno, 0); atomic_set(&hp->seqno, 0);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
...@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) ...@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (--hp->count == 0) { if (--hp->port.count == 0) {
hp->tty = NULL; tty_port_tty_set(&hp->port, NULL);
hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
/* only close down connection if it is not the console */ /* only close down connection if it is not the console */
...@@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) ...@@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
} }
} else if (hp->count < 0) } else if (hp->port.count < 0)
printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
hp - hvsi_ports, hp->count); hp - hvsi_ports, hp->port.count);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
} }
...@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty) ...@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
pr_debug("%s\n", __func__); pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags); tty_port_tty_set(&hp->port, NULL);
hp->count = 0; spin_lock_irqsave(&hp->lock, flags);
hp->port.count = 0;
hp->n_outbuf = 0; hp->n_outbuf = 0;
hp->tty = NULL;
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
} }
...@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work) ...@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
{ {
struct hvsi_struct *hp = struct hvsi_struct *hp =
container_of(work, struct hvsi_struct, writer.work); container_of(work, struct hvsi_struct, writer.work);
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
#ifdef DEBUG #ifdef DEBUG
static long start_j = 0; static long start_j = 0;
...@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work) ...@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
start_j = 0; start_j = 0;
#endif /* DEBUG */ #endif /* DEBUG */
wake_up_all(&hp->emptyq); wake_up_all(&hp->emptyq);
tty_wakeup(hp->tty); tty = tty_port_tty_get(&hp->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
} }
out: out:
...@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty, ...@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
* and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
* will see there is no room in outbuf and return. * will see there is no room in outbuf and return.
*/ */
while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { while ((count > 0) && (hvsi_write_room(tty) > 0)) {
int chunksize = min(count, hvsi_write_room(hp->tty)); int chunksize = min(count, hvsi_write_room(tty));
BUG_ON(hp->n_outbuf < 0); BUG_ON(hp->n_outbuf < 0);
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
...@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty) ...@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
{ {
struct hvsi_struct *hp = tty->driver_data; struct hvsi_struct *hp = tty->driver_data;
unsigned long flags; unsigned long flags;
int shouldflip = 0;
pr_debug("%s\n", __func__); pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) { if (hp->n_throttle) {
hvsi_send_overflow(hp); hvsi_send_overflow(hp, tty);
shouldflip = 1; tty_flip_buffer_push(tty);
} }
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
if (shouldflip)
tty_flip_buffer_push(hp->tty);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
} }
...@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void) ...@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->emptyq);
init_waitqueue_head(&hp->stateq); init_waitqueue_head(&hp->stateq);
spin_lock_init(&hp->lock); spin_lock_init(&hp->lock);
tty_port_init(&hp->port);
hp->index = hvsi_count; hp->index = hvsi_count;
hp->inbuf_end = hp->inbuf; hp->inbuf_end = hp->inbuf;
hp->state = HVSI_CLOSED; hp->state = HVSI_CLOSED;
......
...@@ -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);
} }
} }
此差异已折叠。
/* 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);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册