mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
Merge 3.4-rc4 into tty-next
This resolves the merge problem with: drivers/tty/serial/pch_uart.c Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
@@ -245,14 +245,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
|
||||
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
|
||||
omap_up.autosuspend_timeout = info->autosuspend_timeout;
|
||||
|
||||
/* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
|
||||
if (!cpu_is_omap2420() && !cpu_is_ti816x())
|
||||
omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
|
||||
|
||||
/* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
|
||||
if (cpu_is_omap34xx() || cpu_is_omap3630())
|
||||
omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
|
||||
|
||||
pdata = &omap_up;
|
||||
pdata_size = sizeof(struct omap_uart_port_info);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pda_power.h>
|
||||
@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
.irq = INT_UARTD,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
.irq = INT_UARTA,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
.irq = INT_UARTC,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
@@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
/* Memory and IRQ filled in before registration */
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
@@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
.irq = INT_UARTA,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
||||
@@ -65,7 +65,6 @@ struct omap_uart_port_info {
|
||||
bool dma_enabled; /* To specify DMA Mode */
|
||||
unsigned int uartclk; /* UART clock rate */
|
||||
upf_t flags; /* UPF_* flags */
|
||||
u32 errata;
|
||||
unsigned int dma_rx_buf_size;
|
||||
unsigned int dma_rx_timeout;
|
||||
unsigned int autosuspend_timeout;
|
||||
|
||||
@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
|
||||
static char *isdn_revision = "$Revision: 1.1.2.3 $";
|
||||
|
||||
extern char *isdn_net_revision;
|
||||
extern char *isdn_tty_revision;
|
||||
#ifdef CONFIG_ISDN_PPP
|
||||
extern char *isdn_ppp_revision;
|
||||
#else
|
||||
@@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
|
||||
dev->chanmap[i] = -1;
|
||||
dev->m_idx[i] = -1;
|
||||
strcpy(dev->num[i], "???");
|
||||
init_waitqueue_head(&dev->mdm.info[i].open_wait);
|
||||
init_waitqueue_head(&dev->mdm.info[i].close_wait);
|
||||
}
|
||||
if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
|
||||
printk(KERN_WARNING "isdn: Could not register control devices\n");
|
||||
@@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
|
||||
|
||||
strcpy(tmprev, isdn_revision);
|
||||
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
|
||||
strcpy(tmprev, isdn_tty_revision);
|
||||
printk("%s/", isdn_getrev(tmprev));
|
||||
strcpy(tmprev, isdn_net_revision);
|
||||
printk("%s/", isdn_getrev(tmprev));
|
||||
strcpy(tmprev, isdn_ppp_revision);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -106,13 +106,6 @@
|
||||
|
||||
#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 */
|
||||
/*****************************************************************************/
|
||||
@@ -255,9 +248,8 @@ struct hso_serial {
|
||||
u8 dtr_state;
|
||||
unsigned tx_urb_used:1;
|
||||
|
||||
struct tty_port port;
|
||||
/* from usb_serial_port */
|
||||
struct tty_struct *tty;
|
||||
int open_count;
|
||||
spinlock_t serial_lock;
|
||||
|
||||
int (*write_data) (struct hso_serial *serial);
|
||||
@@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)
|
||||
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;
|
||||
struct ktermios *termios;
|
||||
|
||||
if (!serial) {
|
||||
@@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
|
||||
struct urb *urb;
|
||||
|
||||
urb = serial->rx_urb[0];
|
||||
if (serial->open_count > 0) {
|
||||
if (serial->port.count > 0) {
|
||||
count = put_rxbuf_data(urb, serial);
|
||||
if (count == -1)
|
||||
return;
|
||||
@@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
|
||||
DUMP1(urb->transfer_buffer, urb->actual_length);
|
||||
|
||||
/* Anyone listening? */
|
||||
if (serial->open_count == 0)
|
||||
if (serial->port.count == 0)
|
||||
return;
|
||||
|
||||
if (status == 0) {
|
||||
@@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
|
||||
kref_get(&serial->parent->ref);
|
||||
|
||||
/* setup */
|
||||
spin_lock_irq(&serial->serial_lock);
|
||||
tty->driver_data = serial;
|
||||
tty_kref_put(serial->tty);
|
||||
serial->tty = tty_kref_get(tty);
|
||||
spin_unlock_irq(&serial->serial_lock);
|
||||
tty_port_tty_set(&serial->port, tty);
|
||||
|
||||
/* check for port already opened, if not set the termios */
|
||||
serial->open_count++;
|
||||
if (serial->open_count == 1) {
|
||||
serial->port.count++;
|
||||
if (serial->port.count == 1) {
|
||||
serial->rx_state = RX_IDLE;
|
||||
/* Force default termio settings */
|
||||
_hso_serial_set_termios(tty, NULL);
|
||||
@@ -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);
|
||||
if (result) {
|
||||
hso_stop_serial_device(serial->parent);
|
||||
serial->open_count--;
|
||||
serial->port.count--;
|
||||
kref_put(&serial->parent->ref, hso_serial_ref_free);
|
||||
}
|
||||
} else {
|
||||
@@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
/* reset the rts and dtr */
|
||||
/* do the actual close */
|
||||
serial->open_count--;
|
||||
serial->port.count--;
|
||||
|
||||
if (serial->open_count <= 0) {
|
||||
serial->open_count = 0;
|
||||
spin_lock_irq(&serial->serial_lock);
|
||||
if (serial->tty == tty) {
|
||||
serial->tty->driver_data = NULL;
|
||||
serial->tty = NULL;
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
spin_unlock_irq(&serial->serial_lock);
|
||||
if (serial->port.count <= 0) {
|
||||
serial->port.count = 0;
|
||||
tty_port_tty_set(&serial->port, NULL);
|
||||
if (!usb_gone)
|
||||
hso_stop_serial_device(serial->parent);
|
||||
tasklet_kill(&serial->unthrottle_tasklet);
|
||||
@@ -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,
|
||||
int count)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
int space, tx_bytes;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -1422,7 +1405,7 @@ out:
|
||||
/* how much room is there for writing */
|
||||
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;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)
|
||||
/* setup the term */
|
||||
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;
|
||||
|
||||
if (old)
|
||||
@@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
|
||||
/* the actual setup */
|
||||
spin_lock_irqsave(&serial->serial_lock, flags);
|
||||
if (serial->open_count)
|
||||
if (serial->port.count)
|
||||
_hso_serial_set_termios(tty, old);
|
||||
else
|
||||
tty->termios = old;
|
||||
@@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
/* how many characters in the buffer */
|
||||
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;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,
|
||||
struct serial_icounter_struct *icount)
|
||||
{
|
||||
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;
|
||||
|
||||
memset(icount, 0, sizeof(struct serial_icounter_struct));
|
||||
@@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,
|
||||
static int hso_serial_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
int retval;
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
struct hso_tiocmget *tiocmget;
|
||||
u16 UART_state_bitmap;
|
||||
|
||||
@@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
|
||||
int val = 0;
|
||||
unsigned long flags;
|
||||
int if_num;
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
|
||||
/* sanity check */
|
||||
if (!serial) {
|
||||
@@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
|
||||
static int hso_serial_ioctl(struct tty_struct *tty,
|
||||
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;
|
||||
D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
|
||||
|
||||
@@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)
|
||||
D1("Pending read interrupt on port %d\n", i);
|
||||
spin_lock(&serial->serial_lock);
|
||||
if (serial->rx_state == RX_IDLE &&
|
||||
serial->open_count > 0) {
|
||||
serial->port.count > 0) {
|
||||
/* Setup and send a ctrl req read on
|
||||
* port i */
|
||||
if (!serial->rx_urb_filled[0]) {
|
||||
@@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
|
||||
|
||||
spin_lock(&serial->serial_lock);
|
||||
serial->tx_urb_used = 0;
|
||||
tty = tty_kref_get(serial->tty);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
if (status) {
|
||||
handle_usb_error(status, __func__, serial->parent);
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
hso_put_activity(serial->parent);
|
||||
tty = tty_port_tty_get(&serial->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
@@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)
|
||||
struct hso_serial *serial = urb->context;
|
||||
struct usb_ctrlrequest *req;
|
||||
int status = urb->status;
|
||||
struct tty_struct *tty;
|
||||
|
||||
/* sanity check */
|
||||
if (!serial)
|
||||
@@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)
|
||||
|
||||
spin_lock(&serial->serial_lock);
|
||||
serial->tx_urb_used = 0;
|
||||
tty = tty_kref_get(serial->tty);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
if (status) {
|
||||
handle_usb_error(status, __func__, serial->parent);
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)
|
||||
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
} else {
|
||||
struct tty_struct *tty = tty_port_tty_get(&serial->port);
|
||||
hso_put_activity(serial->parent);
|
||||
if (tty)
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
/* response to a write command */
|
||||
hso_kick_transmit(serial);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/* handle RX data for serial port */
|
||||
@@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* All callers to put_rxbuf_data hold serial_lock */
|
||||
tty = tty_kref_get(serial->tty);
|
||||
tty = tty_port_tty_get(&serial->port);
|
||||
|
||||
/* Push data to tty */
|
||||
if (tty) {
|
||||
@@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
|
||||
write_length_remaining -= curr_write_len;
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (write_length_remaining == 0) {
|
||||
serial->curr_rx_urb_offset = 0;
|
||||
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
return write_length_remaining;
|
||||
}
|
||||
|
||||
@@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
|
||||
serial->minor = minor;
|
||||
serial->magic = HSO_SERIAL_MAGIC;
|
||||
spin_lock_init(&serial->serial_lock);
|
||||
tty_port_init(&serial->port);
|
||||
serial->num_rx_urbs = num_urbs;
|
||||
|
||||
/* RX, allocate urb and initialize */
|
||||
@@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)
|
||||
/* Start all serial ports */
|
||||
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
|
||||
if (serial_table[i] && (serial_table[i]->interface == iface)) {
|
||||
if (dev2ser(serial_table[i])->open_count) {
|
||||
if (dev2ser(serial_table[i])->port.count) {
|
||||
result =
|
||||
hso_start_serial_device(serial_table[i], GFP_NOIO);
|
||||
hso_kick_transmit(dev2ser(serial_table[i]));
|
||||
@@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)
|
||||
if (serial_table[i] &&
|
||||
(serial_table[i]->interface == interface)) {
|
||||
hso_dev = dev2ser(serial_table[i]);
|
||||
spin_lock_irq(&hso_dev->serial_lock);
|
||||
tty = tty_kref_get(hso_dev->tty);
|
||||
spin_unlock_irq(&hso_dev->serial_lock);
|
||||
if (tty)
|
||||
tty = tty_port_tty_get(&hso_dev->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
mutex_lock(&hso_dev->parent->mutex);
|
||||
tty_kref_put(tty);
|
||||
hso_dev->parent->usb_gone = 1;
|
||||
mutex_unlock(&hso_dev->parent->mutex);
|
||||
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
|
||||
@@ -3312,7 +3292,6 @@ static int __init hso_init(void)
|
||||
return -ENOMEM;
|
||||
|
||||
/* fill in all needed values */
|
||||
tty_drv->magic = TTY_DRIVER_MAGIC;
|
||||
tty_drv->driver_name = driver_name;
|
||||
tty_drv->name = tty_filename;
|
||||
|
||||
@@ -3333,7 +3312,7 @@ static int __init hso_init(void)
|
||||
if (result) {
|
||||
printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
|
||||
__func__, result);
|
||||
return result;
|
||||
goto err_free_tty;
|
||||
}
|
||||
|
||||
/* register this module as an usb driver */
|
||||
@@ -3341,13 +3320,16 @@ static int __init hso_init(void)
|
||||
if (result) {
|
||||
printk(KERN_ERR "Could not register hso driver? error: %d\n",
|
||||
result);
|
||||
/* cleanup serial interface */
|
||||
tty_unregister_driver(tty_drv);
|
||||
return result;
|
||||
goto err_unreg_tty;
|
||||
}
|
||||
|
||||
/* done */
|
||||
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)
|
||||
@@ -3355,6 +3337,7 @@ static void __exit hso_exit(void)
|
||||
printk(KERN_INFO "hso: unloaded\n");
|
||||
|
||||
tty_unregister_driver(tty_drv);
|
||||
put_tty_driver(tty_drv);
|
||||
/* deregister the usb driver */
|
||||
usb_deregister(&hso_driver);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/serial.h> /* ASYNC_* flags */
|
||||
#include <linux/slab.h>
|
||||
#include <asm/ccwdev.h>
|
||||
#include <asm/cio.h>
|
||||
@@ -44,14 +45,11 @@
|
||||
#define RAW3215_TIMEOUT HZ/10 /* time for delayed output */
|
||||
|
||||
#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_THROTTLED 8 /* set if reading 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_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 */
|
||||
|
||||
@@ -76,6 +74,7 @@ struct raw3215_req {
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
struct raw3215_info {
|
||||
struct tty_port port;
|
||||
struct ccw_device *cdev; /* device for tty driver */
|
||||
spinlock_t *lock; /* pointer to irq lock */
|
||||
int flags; /* state flags */
|
||||
@@ -84,7 +83,6 @@ struct raw3215_info {
|
||||
int head; /* first free byte in output buffer */
|
||||
int count; /* number of bytes in output buffer */
|
||||
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_write;/* pointer to queued write requests */
|
||||
struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
|
||||
@@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)
|
||||
if (raw->flags & RAW3215_TIMER_RUNS) {
|
||||
del_timer(&raw->timer);
|
||||
raw->flags &= ~RAW3215_TIMER_RUNS;
|
||||
if (!(raw->flags & RAW3215_FROZEN)) {
|
||||
if (!(raw->port.flags & ASYNC_SUSPENDED)) {
|
||||
raw3215_mk_write_req(raw);
|
||||
raw3215_start_io(raw);
|
||||
}
|
||||
@@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)
|
||||
*/
|
||||
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;
|
||||
if (raw->queued_read != NULL)
|
||||
raw3215_start_io(raw);
|
||||
@@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
|
||||
}
|
||||
} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
|
||||
/* delay small writes */
|
||||
init_timer(&raw->timer);
|
||||
raw->timer.expires = RAW3215_TIMEOUT + jiffies;
|
||||
raw->timer.data = (unsigned long) raw;
|
||||
raw->timer.function = raw3215_timeout;
|
||||
add_timer(&raw->timer);
|
||||
raw->flags |= RAW3215_TIMER_RUNS;
|
||||
}
|
||||
@@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
|
||||
static void raw3215_wakeup(unsigned long 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.
|
||||
*/
|
||||
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_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);
|
||||
}
|
||||
|
||||
@@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
|
||||
raw = dev_get_drvdata(&cdev->dev);
|
||||
req = (struct raw3215_req *) intparm;
|
||||
tty = tty_port_tty_get(&raw->port);
|
||||
cstat = irb->scsw.cmd.cstat;
|
||||
dstat = irb->scsw.cmd.dstat;
|
||||
if (cstat != 0)
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
if (dstat & 0x01) { /* we got a unit exception */
|
||||
dstat &= ~0x01; /* we can ignore it */
|
||||
}
|
||||
@@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
break;
|
||||
/* Attention interrupt, someone hit the enter key */
|
||||
raw3215_mk_read_req(raw);
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x0C:
|
||||
/* Channel end interrupt. */
|
||||
if ((raw = req->info) == NULL)
|
||||
return; /* That shouldn't happen ... */
|
||||
goto put_tty; /* That shouldn't happen ... */
|
||||
if (req->type == RAW3215_READ) {
|
||||
/* store residual count, then wait for device end */
|
||||
req->residual = irb->scsw.cmd.count;
|
||||
@@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
case 0x04:
|
||||
/* Device end interrupt. */
|
||||
if ((raw = req->info) == NULL)
|
||||
return; /* That shouldn't happen ... */
|
||||
if (req->type == RAW3215_READ && raw->tty != NULL) {
|
||||
goto put_tty; /* That shouldn't happen ... */
|
||||
if (req->type == RAW3215_READ && tty != NULL) {
|
||||
unsigned int cchar;
|
||||
|
||||
tty = raw->tty;
|
||||
count = 160 - req->residual;
|
||||
EBCASC(raw->inbuf, count);
|
||||
cchar = ctrlchar_handle(raw->inbuf, count, tty);
|
||||
@@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
|
||||
case CTRLCHAR_CTRL:
|
||||
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(raw->tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
|
||||
case CTRLCHAR_NONE:
|
||||
@@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
} else
|
||||
count -= 2;
|
||||
tty_insert_flip_string(tty, raw->inbuf, count);
|
||||
tty_flip_buffer_push(raw->tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
}
|
||||
} else if (req->type == RAW3215_WRITE) {
|
||||
@@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
raw->queued_read == NULL) {
|
||||
wake_up_interruptible(&raw->empty_wait);
|
||||
}
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
break;
|
||||
default:
|
||||
/* 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,
|
||||
raw->flags &= ~RAW3215_WORKING;
|
||||
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)
|
||||
/* While console is frozen for suspend we have no other
|
||||
* choice but to drop message from the buffer to make
|
||||
* room for even more messages. */
|
||||
if (raw->flags & RAW3215_FROZEN) {
|
||||
if (raw->port.flags & ASYNC_SUSPENDED) {
|
||||
raw3215_drop_line(raw);
|
||||
continue;
|
||||
}
|
||||
@@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (raw->flags & RAW3215_ACTIVE)
|
||||
if (raw->port.flags & ASYNC_INITIALIZED)
|
||||
return 0;
|
||||
raw->line_pos = 0;
|
||||
raw->flags |= RAW3215_ACTIVE;
|
||||
raw->port.flags |= ASYNC_INITIALIZED;
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
raw3215_try_io(raw);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
@@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
unsigned long flags;
|
||||
|
||||
if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
|
||||
if (!(raw->port.flags & ASYNC_INITIALIZED) ||
|
||||
(raw->flags & RAW3215_FIXED))
|
||||
return;
|
||||
/* Wait for outstanding requests, then free irq */
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
if ((raw->flags & RAW3215_WORKING) ||
|
||||
raw->queued_write != NULL ||
|
||||
raw->queued_read != NULL) {
|
||||
raw->flags |= RAW3215_CLOSING;
|
||||
raw->port.flags |= ASYNC_CLOSING;
|
||||
add_wait_queue(&raw->empty_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
@@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
remove_wait_queue(&raw->empty_wait, &wait);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct raw3215_info *raw;
|
||||
@@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)
|
||||
/* Console is special. */
|
||||
if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
|
||||
return 0;
|
||||
raw = kmalloc(sizeof(struct raw3215_info) +
|
||||
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
|
||||
|
||||
raw = raw3215_alloc_info();
|
||||
if (raw == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
raw->cdev = cdev;
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
spin_lock(&raw3215_device_lock);
|
||||
for (line = 0; line < NR_3215; line++) {
|
||||
if (!raw3215[line]) {
|
||||
@@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)
|
||||
}
|
||||
spin_unlock(&raw3215_device_lock);
|
||||
if (line == NR_3215) {
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)
|
||||
raw = dev_get_drvdata(&cdev->dev);
|
||||
if (raw) {
|
||||
dev_set_drvdata(&cdev->dev, NULL);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
|
||||
raw = dev_get_drvdata(&cdev->dev);
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
@@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
|
||||
/* Allow I/O again and flush output buffer. */
|
||||
raw = dev_get_drvdata(&cdev->dev);
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
raw->flags &= ~RAW3215_FROZEN;
|
||||
raw->port.flags &= ~ASYNC_SUSPENDED;
|
||||
raw->flags |= RAW3215_FLUSHING;
|
||||
raw3215_try_io(raw);
|
||||
raw->flags &= ~RAW3215_FLUSHING;
|
||||
@@ -827,7 +844,7 @@ static void con3215_flush(void)
|
||||
unsigned long flags;
|
||||
|
||||
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. */
|
||||
if (ccw_device_force_console())
|
||||
/* Forcing didn't work, no panic message .. */
|
||||
@@ -897,23 +914,16 @@ static int __init con3215_init(void)
|
||||
if (IS_ERR(cdev))
|
||||
return -ENODEV;
|
||||
|
||||
raw3215[0] = raw = (struct raw3215_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);
|
||||
raw3215[0] = raw = raw3215_alloc_info();
|
||||
raw->cdev = cdev;
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
raw->flags |= RAW3215_FIXED;
|
||||
init_waitqueue_head(&raw->empty_wait);
|
||||
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
|
||||
|
||||
/* Request the console irq */
|
||||
if (raw3215_startup(raw) != 0) {
|
||||
kfree(raw->inbuf);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
raw3215[0] = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
|
||||
return -ENODEV;
|
||||
|
||||
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 */
|
||||
/*
|
||||
@@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
|
||||
raw3215_shutdown(raw);
|
||||
tasklet_kill(&raw->tlet);
|
||||
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)
|
||||
if (ch == ' ' || ch == d)
|
||||
return d;
|
||||
|
||||
kbd_put_queue(kbd->tty, d);
|
||||
kbd_put_queue(kbd->port, d);
|
||||
return ch;
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
|
||||
{
|
||||
if (kbd->diacr)
|
||||
value = handle_diacr(kbd, value);
|
||||
kbd_put_queue(kbd->tty, value);
|
||||
kbd_put_queue(kbd->port, value);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -239,7 +239,7 @@ static void
|
||||
k_fn(struct kbd_data *kbd, unsigned char value)
|
||||
{
|
||||
if (kbd->func_table[value])
|
||||
kbd_puts_queue(kbd->tty, kbd->func_table[value]);
|
||||
kbd_puts_queue(kbd->port, kbd->func_table[value]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
|
||||
* but we need only 16 bits here
|
||||
*/
|
||||
static void
|
||||
to_utf8(struct tty_struct *tty, ushort c)
|
||||
to_utf8(struct tty_port *port, ushort c)
|
||||
{
|
||||
if (c < 0x80)
|
||||
/* 0******* */
|
||||
kbd_put_queue(tty, c);
|
||||
kbd_put_queue(port, c);
|
||||
else if (c < 0x800) {
|
||||
/* 110***** 10****** */
|
||||
kbd_put_queue(tty, 0xc0 | (c >> 6));
|
||||
kbd_put_queue(tty, 0x80 | (c & 0x3f));
|
||||
kbd_put_queue(port, 0xc0 | (c >> 6));
|
||||
kbd_put_queue(port, 0x80 | (c & 0x3f));
|
||||
} else {
|
||||
/* 1110**** 10****** 10****** */
|
||||
kbd_put_queue(tty, 0xe0 | (c >> 12));
|
||||
kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
|
||||
kbd_put_queue(tty, 0x80 | (c & 0x3f));
|
||||
kbd_put_queue(port, 0xe0 | (c >> 12));
|
||||
kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
|
||||
kbd_put_queue(port, 0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
|
||||
unsigned short keysym;
|
||||
unsigned char type, value;
|
||||
|
||||
if (!kbd || !kbd->tty)
|
||||
if (!kbd)
|
||||
return;
|
||||
|
||||
if (keycode >= 384)
|
||||
@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
|
||||
#endif
|
||||
(*k_handler[type])(kbd, value);
|
||||
} else
|
||||
to_utf8(kbd->tty, keysym);
|
||||
to_utf8(kbd->port, keysym);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
|
||||
|
||||
int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
void __user *argp;
|
||||
unsigned int ct;
|
||||
int perm;
|
||||
@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
|
||||
* To have permissions to do most of the vt ioctls, we either have
|
||||
* to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
|
||||
*/
|
||||
perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
|
||||
tty = tty_port_tty_get(kbd->port);
|
||||
/* FIXME this test is pretty racy */
|
||||
perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
|
||||
tty_kref_put(tty);
|
||||
switch (cmd) {
|
||||
case KDGKBTYPE:
|
||||
return put_user(KB_101, (char __user *)argp);
|
||||
|
||||
@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
|
||||
*/
|
||||
|
||||
struct kbd_data {
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
unsigned short **key_maps;
|
||||
char **func_table;
|
||||
fn_handler_fn **fn_handler;
|
||||
@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
|
||||
* Helper Functions.
|
||||
*/
|
||||
static inline void
|
||||
kbd_put_queue(struct tty_struct *tty, int ch)
|
||||
kbd_put_queue(struct tty_port *port, int ch)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_insert_flip_char(tty, ch, 0);
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static inline void
|
||||
kbd_puts_queue(struct tty_struct *tty, char *cp)
|
||||
kbd_puts_queue(struct tty_port *port, char *cp)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
if (!tty)
|
||||
return;
|
||||
while (*cp)
|
||||
tty_insert_flip_char(tty, *cp++, 0);
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
|
||||
/* Timer for delayed output of console messages. */
|
||||
static struct timer_list sclp_tty_timer;
|
||||
|
||||
static struct tty_struct *sclp_tty;
|
||||
static struct tty_port sclp_port;
|
||||
static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
|
||||
static unsigned short int sclp_tty_chars_count;
|
||||
|
||||
@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
|
||||
static int
|
||||
sclp_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
sclp_tty = tty;
|
||||
tty_port_tty_set(&sclp_port, tty);
|
||||
tty->driver_data = NULL;
|
||||
tty->low_latency = 0;
|
||||
return 0;
|
||||
@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count > 1)
|
||||
return;
|
||||
sclp_tty = NULL;
|
||||
tty_port_tty_set(&sclp_port, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
|
||||
static void
|
||||
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
|
||||
@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
|
||||
spin_unlock_irqrestore(&sclp_tty_lock, flags);
|
||||
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
|
||||
/* check if the tty needs a wake up call */
|
||||
if (sclp_tty != NULL) {
|
||||
tty_wakeup(sclp_tty);
|
||||
tty = tty_port_tty_get(&sclp_port);
|
||||
if (tty != NULL) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
|
||||
static void
|
||||
sclp_tty_input(unsigned char* buf, unsigned int count)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&sclp_port);
|
||||
unsigned int cchar;
|
||||
|
||||
/*
|
||||
* If this tty driver is currently closed
|
||||
* then throw the received input away.
|
||||
*/
|
||||
if (sclp_tty == NULL)
|
||||
if (tty == NULL)
|
||||
return;
|
||||
cchar = ctrlchar_handle(buf, count, sclp_tty);
|
||||
cchar = ctrlchar_handle(buf, count, tty);
|
||||
switch (cchar & CTRLCHAR_MASK) {
|
||||
case CTRLCHAR_SYSRQ:
|
||||
break;
|
||||
case CTRLCHAR_CTRL:
|
||||
tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(sclp_tty);
|
||||
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
case CTRLCHAR_NONE:
|
||||
/* send (normal) input to line discipline */
|
||||
@@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
|
||||
(strncmp((const char *) buf + count - 2, "^n", 2) &&
|
||||
strncmp((const char *) buf + count - 2, "\252n", 2))) {
|
||||
/* add the auto \n */
|
||||
tty_insert_flip_string(sclp_tty, buf, count);
|
||||
tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
|
||||
tty_insert_flip_string(tty, buf, count);
|
||||
tty_insert_flip_char(tty, '\n', TTY_NORMAL);
|
||||
} else
|
||||
tty_insert_flip_string(sclp_tty, buf, count - 2);
|
||||
tty_flip_buffer_push(sclp_tty);
|
||||
tty_insert_flip_string(tty, buf, count - 2);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -543,7 +548,7 @@ sclp_tty_init(void)
|
||||
sclp_tty_tolower = 1;
|
||||
}
|
||||
sclp_tty_chars_count = 0;
|
||||
sclp_tty = NULL;
|
||||
tty_port_init(&sclp_port);
|
||||
|
||||
rc = sclp_register(&sclp_input_event);
|
||||
if (rc) {
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#define SCLP_VT220_DEVICE_NAME "ttysclp"
|
||||
#define SCLP_VT220_CONSOLE_NAME "ttyS"
|
||||
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
|
||||
#define SCLP_VT220_BUF_SIZE 80
|
||||
|
||||
/* Representation of a single write request */
|
||||
struct sclp_vt220_request {
|
||||
@@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
|
||||
/* Structures and data needed to register tty driver */
|
||||
static struct tty_driver *sclp_vt220_driver;
|
||||
|
||||
/* The tty_struct that the kernel associated with us */
|
||||
static struct tty_struct *sclp_vt220_tty;
|
||||
static struct tty_port sclp_vt220_port;
|
||||
|
||||
/* Lock to protect internal data from concurrent access */
|
||||
static spinlock_t sclp_vt220_lock;
|
||||
@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
|
||||
static void
|
||||
sclp_vt220_process_queue(struct sclp_vt220_request *request)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
|
||||
@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
|
||||
if (request == NULL && sclp_vt220_flush_later)
|
||||
sclp_vt220_emit_current();
|
||||
/* Check if the tty needs a wake up call */
|
||||
if (sclp_vt220_tty != NULL) {
|
||||
tty_wakeup(sclp_vt220_tty);
|
||||
tty = tty_port_tty_get(&sclp_vt220_port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
static void
|
||||
sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
|
||||
char *buffer;
|
||||
unsigned int count;
|
||||
|
||||
/* Ignore input if device is not open */
|
||||
if (sclp_vt220_tty == NULL)
|
||||
if (tty == NULL)
|
||||
return;
|
||||
|
||||
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
|
||||
@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
|
||||
/* Send input to line discipline */
|
||||
buffer++;
|
||||
count--;
|
||||
tty_insert_flip_string(sclp_vt220_tty, buffer, count);
|
||||
tty_flip_buffer_push(sclp_vt220_tty);
|
||||
tty_insert_flip_string(tty, buffer, count);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -491,10 +494,7 @@ static int
|
||||
sclp_vt220_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count == 1) {
|
||||
sclp_vt220_tty = tty;
|
||||
tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
|
||||
if (tty->driver_data == NULL)
|
||||
return -ENOMEM;
|
||||
tty_port_tty_set(&sclp_vt220_port, tty);
|
||||
tty->low_latency = 0;
|
||||
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
|
||||
tty->winsize.ws_row = 24;
|
||||
@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
|
||||
static void
|
||||
sclp_vt220_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count == 1) {
|
||||
sclp_vt220_tty = NULL;
|
||||
kfree(tty->driver_data);
|
||||
tty->driver_data = NULL;
|
||||
}
|
||||
if (tty->count == 1)
|
||||
tty_port_tty_set(&sclp_vt220_port, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
|
||||
INIT_LIST_HEAD(&sclp_vt220_empty);
|
||||
INIT_LIST_HEAD(&sclp_vt220_outqueue);
|
||||
init_timer(&sclp_vt220_timer);
|
||||
tty_port_init(&sclp_vt220_port);
|
||||
sclp_vt220_current_request = NULL;
|
||||
sclp_vt220_buffered_chars = 0;
|
||||
sclp_vt220_tty = NULL;
|
||||
sclp_vt220_flush_later = 0;
|
||||
|
||||
/* Allocate pages for output buffering */
|
||||
|
||||
@@ -61,7 +61,7 @@ struct tty3270_line {
|
||||
*/
|
||||
struct tty3270 {
|
||||
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. */
|
||||
struct list_head freemem; /* List of free memory for strings. */
|
||||
|
||||
@@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)
|
||||
static void
|
||||
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) {
|
||||
/* Write wasn't successful. Refresh all. */
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
@@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
|
||||
static void
|
||||
tty3270_rcl_backward(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
struct string *s;
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
if (tp->inattr == TF_INPUT) {
|
||||
if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
|
||||
@@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
|
||||
static void
|
||||
tty3270_scroll_forward(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
int nr_up;
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
nr_up = tp->nr_up - tp->view.rows + 2;
|
||||
if (nr_up < 0)
|
||||
@@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
|
||||
static void
|
||||
tty3270_scroll_backward(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
int nr_up;
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
nr_up = tp->nr_up + tp->view.rows - 2;
|
||||
if (nr_up + tp->view.rows - 2 > tp->nr_lines)
|
||||
@@ -537,11 +532,10 @@ static void
|
||||
tty3270_read_tasklet(struct raw3270_request *rrq)
|
||||
{
|
||||
static char kreset_data = TW_KR;
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
|
||||
char *input;
|
||||
int len;
|
||||
|
||||
tp = (struct tty3270 *) rrq->view;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
/*
|
||||
* Two AID keys are special: For 0x7d (enter) the input line
|
||||
@@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
|
||||
raw3270_request_add_data(tp->kreset, &kreset_data, 1);
|
||||
raw3270_start(&tp->view, tp->kreset);
|
||||
|
||||
/* Emit input string. */
|
||||
if (tp->tty) {
|
||||
while (len-- > 0)
|
||||
kbd_keycode(tp->kbd, *input++);
|
||||
/* Emit keycode for AID byte. */
|
||||
kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
|
||||
}
|
||||
while (len-- > 0)
|
||||
kbd_keycode(tp->kbd, *input++);
|
||||
/* Emit keycode for AID byte. */
|
||||
kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
|
||||
|
||||
raw3270_request_reset(rrq);
|
||||
xchg(&tp->read, rrq);
|
||||
@@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
|
||||
static void
|
||||
tty3270_read_callback(struct raw3270_request *rq, void *data)
|
||||
{
|
||||
struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
|
||||
raw3270_get_view(rq->view);
|
||||
/* 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)
|
||||
static int
|
||||
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;
|
||||
tty3270_set_timer(tp, 1);
|
||||
return 0;
|
||||
@@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -690,6 +680,17 @@ tty3270_alloc_view(void)
|
||||
if (!tp->freemem_pages)
|
||||
goto out_tp;
|
||||
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++) {
|
||||
tp->freemem_pages[pages] = (void *)
|
||||
__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
|
||||
@@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)
|
||||
static void
|
||||
tty3270_release(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty_struct *tty;
|
||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||
struct tty_struct *tty = tty_port_tty_get(&tp->port);
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
tty = tp->tty;
|
||||
if (tty) {
|
||||
tty->driver_data = NULL;
|
||||
tp->tty = tp->kbd->tty = NULL;
|
||||
tty_port_tty_set(&tp->port, NULL);
|
||||
tty_hangup(tty);
|
||||
raw3270_put_view(&tp->view);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)
|
||||
static void
|
||||
tty3270_free(struct raw3270_view *view)
|
||||
{
|
||||
tty3270_free_screen((struct tty3270 *) view);
|
||||
tty3270_free_view((struct tty3270 *) view);
|
||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||
tty3270_free_screen(tp);
|
||||
tty3270_free_view(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)
|
||||
static void
|
||||
tty3270_del_views(void)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tty3270_max_index; i++) {
|
||||
tp = (struct tty3270 *)
|
||||
struct raw3270_view *view =
|
||||
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
|
||||
if (!IS_ERR(tp))
|
||||
raw3270_del_view(&tp->view);
|
||||
if (!IS_ERR(view))
|
||||
raw3270_del_view(view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {
|
||||
static int
|
||||
tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct raw3270_view *view;
|
||||
struct tty3270 *tp;
|
||||
int i, rc;
|
||||
|
||||
if (tty->count > 1)
|
||||
return 0;
|
||||
/* Check if the tty3270 is already there. */
|
||||
tp = (struct tty3270 *)
|
||||
raw3270_find_view(&tty3270_fn,
|
||||
view = raw3270_find_view(&tty3270_fn,
|
||||
tty->index + RAW3270_FIRSTMINOR);
|
||||
if (!IS_ERR(tp)) {
|
||||
if (!IS_ERR(view)) {
|
||||
tp = container_of(view, struct tty3270, view);
|
||||
tty->driver_data = tp;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
tty->winsize.ws_col = tp->view.cols;
|
||||
tty->low_latency = 0;
|
||||
tp->tty = tty;
|
||||
tp->kbd->tty = tty;
|
||||
/* why to reassign? */
|
||||
tty_port_tty_set(&tp->port, tty);
|
||||
tp->inattr = TF_INPUT;
|
||||
return 0;
|
||||
}
|
||||
@@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
tty3270_max_index = tty->index + 1;
|
||||
|
||||
/* Quick exit if there is no device for tty->index. */
|
||||
if (PTR_ERR(tp) == -ENODEV)
|
||||
if (PTR_ERR(view) == -ENODEV)
|
||||
return -ENODEV;
|
||||
|
||||
/* Allocate tty3270 structure on first open. */
|
||||
@@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
if (IS_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,
|
||||
tty->index + RAW3270_FIRSTMINOR);
|
||||
if (rc) {
|
||||
@@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
return rc;
|
||||
}
|
||||
|
||||
tp->tty = tty;
|
||||
tty_port_tty_set(&tp->port, tty);
|
||||
tty->low_latency = 0;
|
||||
tty->driver_data = tp;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
@@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
for (i = 0; i < tp->view.rows - 2; i++)
|
||||
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_SCROLLBACK)] = tty3270_scroll_backward;
|
||||
tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
|
||||
@@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
static void
|
||||
tty3270_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = tty->driver_data;
|
||||
|
||||
if (tty->count > 1)
|
||||
return;
|
||||
tp = (struct tty3270 *) tty->driver_data;
|
||||
if (tp) {
|
||||
tty->driver_data = NULL;
|
||||
tp->tty = tp->kbd->tty = NULL;
|
||||
tty_port_tty_set(&tp->port, NULL);
|
||||
raw3270_put_view(&tp->view);
|
||||
}
|
||||
}
|
||||
@@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
|
||||
tty3270_lf(tp);
|
||||
break;
|
||||
case 'Z': /* Respond ID. */
|
||||
kbd_puts_queue(tp->tty, "\033[?6c");
|
||||
kbd_puts_queue(&tp->port, "\033[?6c");
|
||||
break;
|
||||
case '7': /* Save cursor position. */
|
||||
tp->saved_cx = tp->cx;
|
||||
@@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
|
||||
tp->esc_state = ESnormal;
|
||||
if (ch == 'n' && !tp->esc_ques) {
|
||||
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. */
|
||||
char buf[40];
|
||||
sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
|
||||
kbd_puts_queue(tp->tty, buf);
|
||||
kbd_puts_queue(&tp->port, buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
|
||||
* String write routine for 3270 ttys
|
||||
*/
|
||||
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;
|
||||
|
||||
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) {
|
||||
/* Continue escape sequence. */
|
||||
tty3270_escape_sequence(tp, buf[i_msg]);
|
||||
@@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,
|
||||
if (!tp)
|
||||
return 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;
|
||||
}
|
||||
tty3270_do_write(tp, buf, count);
|
||||
tty3270_do_write(tp, tty, buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)
|
||||
if (!tp)
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
|
||||
|
||||
static struct tty_driver *bfin_jc_driver;
|
||||
static struct task_struct *bfin_jc_kthread;
|
||||
static struct tty_struct * volatile bfin_jc_tty;
|
||||
static unsigned long bfin_jc_count;
|
||||
static DEFINE_MUTEX(bfin_jc_tty_mutex);
|
||||
static struct tty_port port;
|
||||
static volatile struct circ_buf bfin_jc_write_buf;
|
||||
|
||||
static int
|
||||
@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
|
||||
uint32_t inbound_len = 0, outbound_len = 0;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&port);
|
||||
/* no one left to give data to, so sleep */
|
||||
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
|
||||
if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
|
||||
pr_debug("waiting for readers\n");
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule();
|
||||
__set_current_state(TASK_RUNNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* no data available, so just chill */
|
||||
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
|
||||
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
|
||||
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
|
||||
tty_kref_put(tty);
|
||||
if (inbound_len)
|
||||
schedule();
|
||||
else
|
||||
@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
|
||||
|
||||
/* if incoming data is ready, eat it */
|
||||
if (bfin_read_DBGSTAT() & EMUDIF) {
|
||||
struct tty_struct *tty;
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
tty = (struct tty_struct *)bfin_jc_tty;
|
||||
if (tty != NULL) {
|
||||
uint32_t emudat = bfin_read_emudat();
|
||||
if (inbound_len == 0) {
|
||||
@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
}
|
||||
|
||||
/* if outgoing data is ready, post it */
|
||||
@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
|
||||
bfin_write_emudat(outbound_len);
|
||||
pr_debug("outgoing length: 0x%08x\n", outbound_len);
|
||||
} else {
|
||||
struct tty_struct *tty;
|
||||
int tail = bfin_jc_write_buf.tail;
|
||||
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
|
||||
uint32_t emudat =
|
||||
@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
|
||||
);
|
||||
bfin_jc_write_buf.tail += ate;
|
||||
outbound_len -= ate;
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
tty = (struct tty_struct *)bfin_jc_tty;
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
|
||||
}
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
|
||||
static int
|
||||
bfin_jc_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
pr_debug("open %lu\n", bfin_jc_count);
|
||||
++bfin_jc_count;
|
||||
bfin_jc_tty = tty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port.lock, flags);
|
||||
port.count++;
|
||||
spin_unlock_irqrestore(&port.lock, flags);
|
||||
tty_port_tty_set(&port, tty);
|
||||
wake_up_process(bfin_jc_kthread);
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bfin_jc_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
pr_debug("close %lu\n", bfin_jc_count);
|
||||
if (--bfin_jc_count == 0)
|
||||
bfin_jc_tty = NULL;
|
||||
unsigned long flags;
|
||||
bool last;
|
||||
|
||||
spin_lock_irqsave(&port.lock, flags);
|
||||
last = --port.count == 0;
|
||||
spin_unlock_irqrestore(&port.lock, flags);
|
||||
if (last)
|
||||
tty_port_tty_set(&port, NULL);
|
||||
wake_up_process(bfin_jc_kthread);
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
}
|
||||
|
||||
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
|
||||
@@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
tty_port_init(&port);
|
||||
|
||||
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
|
||||
if (IS_ERR(bfin_jc_kthread))
|
||||
return PTR_ERR(bfin_jc_kthread);
|
||||
|
||||
@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
|
||||
list_for_each_entry(hp, &hvc_structs, next) {
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->index == index) {
|
||||
kref_get(&hp->kref);
|
||||
tty_port_get(&hp->port);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
spin_unlock(&hvc_structs_lock);
|
||||
return hp;
|
||||
@@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
|
||||
console_initcall(hvc_console_init);
|
||||
|
||||
/* callback when the kboject ref count reaches zero. */
|
||||
static void destroy_hvc_struct(struct kref *kref)
|
||||
static void hvc_port_destruct(struct tty_port *port)
|
||||
{
|
||||
struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
|
||||
struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&hvc_structs_lock);
|
||||
@@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
|
||||
/* make sure no no tty has been registered in this index */
|
||||
hp = hvc_get_by_index(index);
|
||||
if (hp) {
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
||||
if (!(hp = hvc_get_by_index(tty->index)))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
/* Check and then increment for fast path open. */
|
||||
if (hp->count++ > 0) {
|
||||
tty_kref_get(tty);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
if (hp->port.count++ > 0) {
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
hvc_kick();
|
||||
return 0;
|
||||
} /* else count == 0 */
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
|
||||
tty->driver_data = hp;
|
||||
|
||||
hp->tty = tty_kref_get(tty);
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
tty_port_tty_set(&hp->port, tty);
|
||||
|
||||
if (hp->ops->notifier_add)
|
||||
rc = hp->ops->notifier_add(hp, hp->data);
|
||||
@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
||||
* tty fields and return the kref reference.
|
||||
*/
|
||||
if (rc) {
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
hp->tty = NULL;
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
tty->driver_data = NULL;
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
|
||||
}
|
||||
/* Force wakeup of the polling thread */
|
||||
@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
||||
|
||||
hp = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
|
||||
if (--hp->count == 0) {
|
||||
if (--hp->port.count == 0) {
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
/* We are done with the tty pointer now. */
|
||||
hp->tty = NULL;
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
if (hp->ops->notifier_del)
|
||||
hp->ops->notifier_del(hp, hp->data);
|
||||
@@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
||||
*/
|
||||
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
|
||||
} else {
|
||||
if (hp->count < 0)
|
||||
if (hp->port.count < 0)
|
||||
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
|
||||
hp->vtermno, hp->count);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
hp->vtermno, hp->port.count);
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
}
|
||||
|
||||
tty_kref_put(tty);
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
}
|
||||
|
||||
static void hvc_hangup(struct tty_struct *tty)
|
||||
@@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)
|
||||
/* cancel pending tty resize work */
|
||||
cancel_work_sync(&hp->tty_resize);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
|
||||
/*
|
||||
* The N_TTY line discipline has problems such that in a close vs
|
||||
* open->hangup case this can be called after the final close so prevent
|
||||
* that from happening for now.
|
||||
*/
|
||||
if (hp->count <= 0) {
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
if (hp->port.count <= 0) {
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
temp_open_count = hp->count;
|
||||
hp->count = 0;
|
||||
hp->n_outbuf = 0;
|
||||
hp->tty = NULL;
|
||||
temp_open_count = hp->port.count;
|
||||
hp->port.count = 0;
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
hp->n_outbuf = 0;
|
||||
|
||||
if (hp->ops->notifier_hangup)
|
||||
hp->ops->notifier_hangup(hp, hp->data);
|
||||
|
||||
while(temp_open_count) {
|
||||
--temp_open_count;
|
||||
tty_kref_put(tty);
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
|
||||
if (!hp)
|
||||
return -EPIPE;
|
||||
|
||||
if (hp->count <= 0)
|
||||
/* FIXME what's this (unprotected) check for? */
|
||||
if (hp->port.count <= 0)
|
||||
return -EIO;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
|
||||
|
||||
hp = container_of(work, struct hvc_struct, tty_resize);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, hvc_flags);
|
||||
if (!hp->tty) {
|
||||
spin_unlock_irqrestore(&hp->lock, hvc_flags);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (!tty)
|
||||
return;
|
||||
}
|
||||
ws = hp->ws;
|
||||
tty = tty_kref_get(hp->tty);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, hvc_flags);
|
||||
ws = hp->ws;
|
||||
spin_unlock_irqrestore(&hp->lock, hvc_flags);
|
||||
|
||||
tty_do_resize(tty, &ws);
|
||||
@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
}
|
||||
|
||||
/* No tty attached, just skip */
|
||||
tty = tty_kref_get(hp->tty);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (tty == NULL)
|
||||
goto bail;
|
||||
|
||||
@@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
if (tty)
|
||||
tty_kref_put(tty);
|
||||
tty_kref_put(tty);
|
||||
|
||||
return poll_mask;
|
||||
}
|
||||
@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct tty_port_operations hvc_port_ops = {
|
||||
.destruct = hvc_port_destruct,
|
||||
};
|
||||
|
||||
struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
||||
const struct hv_ops *ops,
|
||||
int outbuf_size)
|
||||
@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
||||
hp->outbuf_size = outbuf_size;
|
||||
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
|
||||
|
||||
kref_init(&hp->kref);
|
||||
tty_port_init(&hp->port);
|
||||
hp->port.ops = &hvc_port_ops;
|
||||
|
||||
INIT_WORK(&hp->tty_resize, hvc_set_winsz);
|
||||
spin_lock_init(&hp->lock);
|
||||
@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
|
||||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
tty = tty_kref_get(hp->tty);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->index < MAX_NR_HVC_CONSOLES)
|
||||
vtermnos[hp->index] = -1;
|
||||
|
||||
@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
|
||||
* kref cause it to be removed, which will probably be the tty_vhangup
|
||||
* below.
|
||||
*/
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
|
||||
/*
|
||||
* This function call will auto chain call hvc_hangup.
|
||||
|
||||
@@ -46,10 +46,9 @@
|
||||
#define HVC_ALLOC_TTY_ADAPTERS 8
|
||||
|
||||
struct hvc_struct {
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
int index;
|
||||
struct tty_struct *tty;
|
||||
int count;
|
||||
int do_wakeup;
|
||||
char *outbuf;
|
||||
int outbuf_size;
|
||||
@@ -61,7 +60,6 @@ struct hvc_struct {
|
||||
struct winsize ws;
|
||||
struct work_struct tty_resize;
|
||||
struct list_head next;
|
||||
struct kref kref; /* ref count & hvc_struct lifetime */
|
||||
};
|
||||
|
||||
/* implemented by a low level driver */
|
||||
|
||||
@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
|
||||
|
||||
/* One vty-server per hvcs_struct */
|
||||
struct hvcs_struct {
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
|
||||
/*
|
||||
@@ -269,9 +270,6 @@ struct hvcs_struct {
|
||||
*/
|
||||
unsigned int index;
|
||||
|
||||
struct tty_struct *tty;
|
||||
int open_count;
|
||||
|
||||
/*
|
||||
* Used to tell the driver kernel_thread what operations need to take
|
||||
* place upon this hvcs_struct instance.
|
||||
@@ -290,12 +288,11 @@ struct hvcs_struct {
|
||||
int chars_in_buffer;
|
||||
|
||||
/*
|
||||
* Any variable below the kref is valid before a tty is connected and
|
||||
* Any variable below is valid before a tty is connected and
|
||||
* stays valid after the tty is disconnected. These shouldn't be
|
||||
* whacked until the kobject refcount reaches zero though some entries
|
||||
* may be changed via sysfs initiatives.
|
||||
*/
|
||||
struct kref kref; /* ref count & hvcs_struct lifetime */
|
||||
int connected; /* is the vty-server currently connected to a vty? */
|
||||
uint32_t p_unit_address; /* partner unit address */
|
||||
uint32_t p_partition_ID; /* partner partition ID */
|
||||
@@ -304,9 +301,6 @@ struct hvcs_struct {
|
||||
struct vio_dev *vdev;
|
||||
};
|
||||
|
||||
/* Required to back map a kref to its containing object */
|
||||
#define from_kref(k) container_of(k, struct hvcs_struct, kref)
|
||||
|
||||
static LIST_HEAD(hvcs_structs);
|
||||
static DEFINE_SPINLOCK(hvcs_structs_lock);
|
||||
static DEFINE_MUTEX(hvcs_init_mutex);
|
||||
@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
if (hvcsd->open_count > 0) {
|
||||
if (hvcsd->port.count > 0) {
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
printk(KERN_INFO "HVCS: vterm state unchanged. "
|
||||
"The hvcs device node is still in use.\n");
|
||||
@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
|
||||
static void hvcs_try_write(struct hvcs_struct *hvcsd)
|
||||
{
|
||||
uint32_t unit_address = hvcsd->vdev->unit_address;
|
||||
struct tty_struct *tty = hvcsd->tty;
|
||||
struct tty_struct *tty = hvcsd->port.tty;
|
||||
int sent;
|
||||
|
||||
if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
|
||||
@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
unit_address = hvcsd->vdev->unit_address;
|
||||
tty = hvcsd->tty;
|
||||
tty = hvcsd->port.tty;
|
||||
|
||||
hvcs_try_write(hvcsd);
|
||||
|
||||
@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
|
||||
hvcs_index_list[index] = -1;
|
||||
}
|
||||
|
||||
/* callback when the kref ref count reaches zero */
|
||||
static void destroy_hvcs_struct(struct kref *kref)
|
||||
static void hvcs_destruct_port(struct tty_port *p)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = from_kref(kref);
|
||||
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
|
||||
struct vio_dev *vdev;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
|
||||
kfree(hvcsd);
|
||||
}
|
||||
|
||||
static const struct tty_port_operations hvcs_port_ops = {
|
||||
.destruct = hvcs_destruct_port,
|
||||
};
|
||||
|
||||
static int hvcs_get_index(void)
|
||||
{
|
||||
int i;
|
||||
@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
|
||||
if (!hvcsd)
|
||||
return -ENODEV;
|
||||
|
||||
|
||||
tty_port_init(&hvcsd->port);
|
||||
hvcsd->port.ops = &hvcs_port_ops;
|
||||
spin_lock_init(&hvcsd->lock);
|
||||
/* Automatically incs the refcount the first time */
|
||||
kref_init(&hvcsd->kref);
|
||||
|
||||
hvcsd->vdev = dev;
|
||||
dev_set_drvdata(&dev->dev, hvcsd);
|
||||
@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
tty = hvcsd->tty;
|
||||
tty = hvcsd->port.tty;
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
|
||||
* Let the last holder of this object cause it to be removed, which
|
||||
* would probably be tty_hangup below.
|
||||
*/
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
|
||||
/*
|
||||
* The hangup is a scheduled function which will auto chain call
|
||||
@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
|
||||
list_for_each_entry(hvcsd, &hvcs_structs, next) {
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (hvcsd->index == index) {
|
||||
kref_get(&hvcsd->kref);
|
||||
tty_port_get(&hvcsd->port);
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
return hvcsd;
|
||||
@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
|
||||
if ((retval = hvcs_partner_connect(hvcsd)))
|
||||
goto error_release;
|
||||
|
||||
hvcsd->open_count = 1;
|
||||
hvcsd->tty = tty;
|
||||
hvcsd->port.count = 1;
|
||||
hvcsd->port.tty = tty;
|
||||
tty->driver_data = hvcsd;
|
||||
|
||||
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
|
||||
@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
|
||||
* and will grab the spinlock and free the connection if it fails.
|
||||
*/
|
||||
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
printk(KERN_WARNING "HVCS: enable device failed.\n");
|
||||
return rc;
|
||||
}
|
||||
@@ -1171,8 +1167,8 @@ fast_open:
|
||||
hvcsd = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
kref_get(&hvcsd->kref);
|
||||
hvcsd->open_count++;
|
||||
tty_port_get(&hvcsd->port);
|
||||
hvcsd->port.count++;
|
||||
hvcsd->todo_mask |= HVCS_SCHED_READ;
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
@@ -1186,7 +1182,7 @@ open_success:
|
||||
|
||||
error_release:
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
|
||||
printk(KERN_WARNING "HVCS: partner connect failed.\n");
|
||||
return retval;
|
||||
@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||
hvcsd = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (--hvcsd->open_count == 0) {
|
||||
if (--hvcsd->port.count == 0) {
|
||||
|
||||
vio_disable_interrupts(hvcsd->vdev);
|
||||
|
||||
@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||
* execute any operations on the TTY even though it is obligated
|
||||
* to deliver any pending I/O to the hypervisor.
|
||||
*/
|
||||
hvcsd->tty = NULL;
|
||||
hvcsd->port.tty = NULL;
|
||||
|
||||
irq = hvcsd->vdev->irq;
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||
tty->driver_data = NULL;
|
||||
|
||||
free_irq(irq, hvcsd);
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
return;
|
||||
} else if (hvcsd->open_count < 0) {
|
||||
} else if (hvcsd->port.count < 0) {
|
||||
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
|
||||
" is missmanaged.\n",
|
||||
hvcsd->vdev->unit_address, hvcsd->open_count);
|
||||
hvcsd->vdev->unit_address, hvcsd->port.count);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
}
|
||||
|
||||
static void hvcs_hangup(struct tty_struct * tty)
|
||||
@@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
/* Preserve this so that we know how many kref refs to put */
|
||||
temp_open_count = hvcsd->open_count;
|
||||
temp_open_count = hvcsd->port.count;
|
||||
|
||||
/*
|
||||
* Don't kref put inside the spinlock because the destruction
|
||||
@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
|
||||
hvcsd->todo_mask = 0;
|
||||
|
||||
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
|
||||
hvcsd->tty->driver_data = NULL;
|
||||
hvcsd->tty = NULL;
|
||||
tty->driver_data = NULL;
|
||||
hvcsd->port.tty = NULL;
|
||||
|
||||
hvcsd->open_count = 0;
|
||||
hvcsd->port.count = 0;
|
||||
|
||||
/* This will drop any buffered data on the floor which is OK in a hangup
|
||||
* scenario. */
|
||||
@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
||||
* NOTE: If this hangup was signaled from user space then the
|
||||
* final put will never happen.
|
||||
*/
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
|
||||
* the middle of a write operation? This is a crummy place to do this
|
||||
* but we want to keep it all in the spinlock.
|
||||
*/
|
||||
if (hvcsd->open_count <= 0) {
|
||||
if (hvcsd->port.count <= 0) {
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = tty->driver_data;
|
||||
|
||||
if (!hvcsd || hvcsd->open_count <= 0)
|
||||
if (!hvcsd || hvcsd->port.count <= 0)
|
||||
return 0;
|
||||
|
||||
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
|
||||
|
||||
@@ -69,14 +69,13 @@
|
||||
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
|
||||
|
||||
struct hvsi_struct {
|
||||
struct tty_port port;
|
||||
struct delayed_work writer;
|
||||
struct work_struct handshaker;
|
||||
wait_queue_head_t emptyq; /* woken when outbuf is emptied */
|
||||
wait_queue_head_t stateq; /* woken when HVSI state changes */
|
||||
spinlock_t lock;
|
||||
int index;
|
||||
struct tty_struct *tty;
|
||||
int count;
|
||||
uint8_t throttle_buf[128];
|
||||
uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
|
||||
/* 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)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
|
||||
/* CD went away; no more connection */
|
||||
pr_debug("hvsi%i: CD dropped\n", hp->index);
|
||||
hp->mctrl &= TIOCM_CD;
|
||||
/* If userland hasn't done an open(2) yet, hp->tty is NULL. */
|
||||
if (hp->tty && !(hp->tty->flags & CLOCAL))
|
||||
*to_hangup = hp->tty;
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
}
|
||||
break;
|
||||
case VSV_CLOSE_PROTOCOL:
|
||||
@@ -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;
|
||||
|
||||
@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
|
||||
continue;
|
||||
}
|
||||
#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)
|
||||
* revisited.
|
||||
*/
|
||||
#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 struct hvsi_header *header = (const struct hvsi_header *)packet;
|
||||
@@ -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);
|
||||
|
||||
if (datalen == 0)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
if (overflow > 0) {
|
||||
pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
|
||||
datalen = TTY_THRESHOLD_THROTTLE;
|
||||
}
|
||||
|
||||
hvsi_insert_chars(hp, data, datalen);
|
||||
hvsi_insert_chars(hp, tty, data, datalen);
|
||||
|
||||
if (overflow > 0) {
|
||||
/*
|
||||
@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
|
||||
hp->n_throttle = overflow;
|
||||
}
|
||||
|
||||
return hp->tty;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -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
|
||||
* incoming data).
|
||||
*/
|
||||
static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
|
||||
struct tty_struct **hangup, struct hvsi_struct **handshake)
|
||||
static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
struct hvsi_struct **handshake)
|
||||
{
|
||||
uint8_t *packet = hp->inbuf;
|
||||
int chunklen;
|
||||
bool flip = false;
|
||||
|
||||
*flip = NULL;
|
||||
*hangup = NULL;
|
||||
*handshake = NULL;
|
||||
|
||||
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,
|
||||
case VS_DATA_PACKET_HEADER:
|
||||
if (!is_open(hp))
|
||||
break;
|
||||
if (hp->tty == NULL)
|
||||
if (tty == NULL)
|
||||
break; /* no tty buffer to put data in */
|
||||
*flip = hvsi_recv_data(hp, packet);
|
||||
flip = hvsi_recv_data(hp, tty, packet);
|
||||
break;
|
||||
case VS_CONTROL_PACKET_HEADER:
|
||||
hvsi_recv_control(hp, packet, hangup, handshake);
|
||||
hvsi_recv_control(hp, packet, tty, handshake);
|
||||
break;
|
||||
case VS_QUERY_RESPONSE_PACKET_HEADER:
|
||||
hvsi_recv_response(hp, packet);
|
||||
@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
|
||||
|
||||
packet += len_packet(packet);
|
||||
|
||||
if (*hangup || *handshake) {
|
||||
pr_debug("%s: hangup or 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.
|
||||
*/
|
||||
if (*handshake) {
|
||||
pr_debug("%s: handshake\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
compact_inbuf(hp, packet);
|
||||
|
||||
if (flip)
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
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__,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
|
||||
static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
||||
{
|
||||
struct hvsi_struct *hp = (struct hvsi_struct *)arg;
|
||||
struct tty_struct *flip;
|
||||
struct tty_struct *hangup;
|
||||
struct hvsi_struct *handshake;
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
int again = 1;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
|
||||
while (again) {
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
|
||||
schedule_work(&handshake->handshaker);
|
||||
@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->tty && hp->n_throttle
|
||||
&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
|
||||
/* we weren't hung up and we weren't throttled, so we can deliver the
|
||||
* rest now */
|
||||
flip = hp->tty;
|
||||
hvsi_send_overflow(hp);
|
||||
if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
/* we weren't hung up and we weren't throttled, so we can
|
||||
* deliver the rest now */
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
if (flip) {
|
||||
tty_flip_buffer_push(flip);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
|
||||
if (hp->state == HVSI_FSP_DIED)
|
||||
return -EIO;
|
||||
|
||||
tty_port_tty_set(&hp->port, tty);
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
hp->tty = tty;
|
||||
hp->count++;
|
||||
hp->port.count++;
|
||||
atomic_set(&hp->seqno, 0);
|
||||
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
|
||||
if (--hp->count == 0) {
|
||||
hp->tty = NULL;
|
||||
if (--hp->port.count == 0) {
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
|
||||
|
||||
/* 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)
|
||||
|
||||
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",
|
||||
hp - hvsi_ports, hp->count);
|
||||
hp - hvsi_ports, hp->port.count);
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
}
|
||||
@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
|
||||
hp->count = 0;
|
||||
hp->port.count = 0;
|
||||
hp->n_outbuf = 0;
|
||||
hp->tty = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
}
|
||||
|
||||
@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
|
||||
{
|
||||
struct hvsi_struct *hp =
|
||||
container_of(work, struct hvsi_struct, writer.work);
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
#ifdef DEBUG
|
||||
static long start_j = 0;
|
||||
@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
|
||||
start_j = 0;
|
||||
#endif /* DEBUG */
|
||||
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:
|
||||
@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
|
||||
* and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
|
||||
* will see there is no room in outbuf and return.
|
||||
*/
|
||||
while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
|
||||
int chunksize = min(count, hvsi_write_room(hp->tty));
|
||||
while ((count > 0) && (hvsi_write_room(tty) > 0)) {
|
||||
int chunksize = min(count, hvsi_write_room(tty));
|
||||
|
||||
BUG_ON(hp->n_outbuf < 0);
|
||||
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
|
||||
@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct hvsi_struct *hp = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int shouldflip = 0;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->n_throttle) {
|
||||
hvsi_send_overflow(hp);
|
||||
shouldflip = 1;
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
if (shouldflip)
|
||||
tty_flip_buffer_push(hp->tty);
|
||||
|
||||
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
|
||||
}
|
||||
@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
|
||||
init_waitqueue_head(&hp->emptyq);
|
||||
init_waitqueue_head(&hp->stateq);
|
||||
spin_lock_init(&hp->lock);
|
||||
tty_port_init(&hp->port);
|
||||
hp->index = hvsi_count;
|
||||
hp->inbuf_end = hp->inbuf;
|
||||
hp->state = HVSI_CLOSED;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user