提交 94b5aff4 编写于 作者: L Linus Torvalds

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

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

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

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

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

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

* tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (115 commits)
  serial: bfin_uart: Make MMR access compatible with 32 bits bf609 style controller.
  serial: bfin_uart: RTS and CTS MMRs can be either 16-bit width or 32-bit width.
  serial: bfin_uart: narrow the reboot condition in DMA tx interrupt
  serial: bfin_uart: Adapt bf5xx serial driver to bf60x serial4 controller.
  Revert "serial_core: Update buffer overrun statistics."
  tty: hvc_xen: NULL dereference on allocation failure
  tty: Fix LED error return
  tty: Allow uart_register/unregister/register
  tty: move global ldisc idle waitqueue to the individual ldisc
  serial8250-em: Add DT support
  serial8250-em: clk_get() IS_ERR() error handling fix
  serial_core: Update buffer overrun statistics.
  tty: drop the pty lock during hangup
  cris: fix missing tty arg in wait_event_interruptible_tty call
  tty/amiserial: Add missing argument for tty_unlock()
  tty_lock: Localise the lock
  pty: Lock the devpts bits privately
  tty_lock: undo the old tty_lock use on the ctty
  serial8250-em: Emma Mobile UART driver V2
  Add missing call to uart_update_timeout()
  ...
......@@ -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>
......@@ -48,6 +49,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>
......@@ -49,6 +50,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);
......
此差异已折叠。
......@@ -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 @@ static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
/* 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);
......@@ -3313,7 +3293,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;
......@@ -3334,7 +3313,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 */
......@@ -3342,13 +3321,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)
......@@ -3356,6 +3338,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;
}
}
......
......@@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttys%d, count = %d\n",
info->line, state->count);
#endif
tty_unlock();
tty_unlock(tty);
schedule();
tty_lock();
tty_lock(tty);
}
current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
......
......@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tty_lock();
tty_lock(tty);
tmp.line = tty->index;
tmp.port = state->port;
tmp.flags = state->tport.flags;
......@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
tmp.close_delay = state->tport.close_delay;
tmp.closing_wait = state->tport.closing_wait;
tmp.custom_divisor = state->custom_divisor;
tty_unlock();
tty_unlock(tty);
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
......@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
tty_lock();
tty_lock(tty);
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
new_serial.custom_divisor != state->custom_divisor;
if (new_serial.irq || new_serial.port != state->port ||
new_serial.xmit_fifo_size != state->xmit_fifo_size) {
tty_unlock();
tty_unlock(tty);
return -EINVAL;
}
......@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
(new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
tty_unlock();
tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
......@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
}
if (new_serial.baud_base < 9600) {
tty_unlock();
tty_unlock(tty);
return -EINVAL;
}
......@@ -1116,7 +1116,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
}
} else
retval = startup(tty, state);
tty_unlock();
tty_unlock(tty);
return retval;
}
......
......@@ -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);
......
......@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(info->port.close_wait,
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
......
......@@ -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 */
......
......@@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,
if (devid == 0)
return -ENODEV;
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
goto error_nomem;
return -ENOMEM;
dev_set_drvdata(&dev->dev, info);
info->xbdev = dev;
info->vtermno = xenbus_devid_to_vtermno(devid);
......
......@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
/* One vty-server per hvcs_struct */
struct hvcs_struct {
struct tty_port port;
spinlock_t lock;
/*
......@@ -269,9 +270,6 @@ struct hvcs_struct {
*/
unsigned int index;
struct tty_struct *tty;
int open_count;
/*
* Used to tell the driver kernel_thread what operations need to take
* place upon this hvcs_struct instance.
......@@ -290,12 +288,11 @@ struct hvcs_struct {
int chars_in_buffer;
/*
* Any variable below the kref is valid before a tty is connected and
* Any variable below is valid before a tty is connected and
* stays valid after the tty is disconnected. These shouldn't be
* whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives.
*/
struct kref kref; /* ref count & hvcs_struct lifetime */
int connected; /* is the vty-server currently connected to a vty? */
uint32_t p_unit_address; /* partner unit address */
uint32_t p_partition_ID; /* partner partition ID */
......@@ -304,9 +301,6 @@ struct hvcs_struct {
struct vio_dev *vdev;
};
/* Required to back map a kref to its containing object */
#define from_kref(k) container_of(k, struct hvcs_struct, kref)
static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
static DEFINE_MUTEX(hvcs_init_mutex);
......@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->open_count > 0) {
if (hvcsd->port.count > 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
printk(KERN_INFO "HVCS: vterm state unchanged. "
"The hvcs device node is still in use.\n");
......@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
static void hvcs_try_write(struct hvcs_struct *hvcsd)
{
uint32_t unit_address = hvcsd->vdev->unit_address;
struct tty_struct *tty = hvcsd->tty;
struct tty_struct *tty = hvcsd->port.tty;
int sent;
if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
......@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_lock_irqsave(&hvcsd->lock, flags);
unit_address = hvcsd->vdev->unit_address;
tty = hvcsd->tty;
tty = hvcsd->port.tty;
hvcs_try_write(hvcsd);
......@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
hvcs_index_list[index] = -1;
}
/* callback when the kref ref count reaches zero */
static void destroy_hvcs_struct(struct kref *kref)
static void hvcs_destruct_port(struct tty_port *p)
{
struct hvcs_struct *hvcsd = from_kref(kref);
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
unsigned long flags;
......@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
kfree(hvcsd);
}
static const struct tty_port_operations hvcs_port_ops = {
.destruct = hvcs_destruct_port,
};
static int hvcs_get_index(void)
{
int i;
......@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
if (!hvcsd)
return -ENODEV;
tty_port_init(&hvcsd->port);
hvcsd->port.ops = &hvcs_port_ops;
spin_lock_init(&hvcsd->lock);
/* Automatically incs the refcount the first time */
kref_init(&hvcsd->kref);
hvcsd->vdev = dev;
dev_set_drvdata(&dev->dev, hvcsd);
......@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
tty = hvcsd->tty;
tty = hvcsd->port.tty;
spin_unlock_irqrestore(&hvcsd->lock, flags);
......@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
* Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below.
*/
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
/*
* The hangup is a scheduled function which will auto chain call
......@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
list_for_each_entry(hvcsd, &hvcs_structs, next) {
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->index == index) {
kref_get(&hvcsd->kref);
tty_port_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
return hvcsd;
......@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
if ((retval = hvcs_partner_connect(hvcsd)))
goto error_release;
hvcsd->open_count = 1;
hvcsd->tty = tty;
hvcsd->port.count = 1;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
......@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* and will grab the spinlock and free the connection if it fails.
*/
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: enable device failed.\n");
return rc;
}
......@@ -1171,8 +1167,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
kref_get(&hvcsd->kref);
hvcsd->open_count++;
tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
......@@ -1186,7 +1182,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
error_release:
spin_unlock_irqrestore(&hvcsd->lock, flags);
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval;
......@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
if (--hvcsd->open_count == 0) {
if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
......@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
* execute any operations on the TTY even though it is obligated
* to deliver any pending I/O to the hypervisor.
*/
hvcsd->tty = NULL;
hvcsd->port.tty = NULL;
irq = hvcsd->vdev->irq;
spin_unlock_irqrestore(&hvcsd->lock, flags);
......@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->open_count < 0) {
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
" is missmanaged.\n",
hvcsd->vdev->unit_address, hvcsd->open_count);
hvcsd->vdev->unit_address, hvcsd->port.count);
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
}
static void hvcs_hangup(struct tty_struct * tty)
......@@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */
temp_open_count = hvcsd->open_count;
temp_open_count = hvcsd->port.count;
/*
* Don't kref put inside the spinlock because the destruction
......@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
hvcsd->tty->driver_data = NULL;
hvcsd->tty = NULL;
tty->driver_data = NULL;
hvcsd->port.tty = NULL;
hvcsd->open_count = 0;
hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
* scenario. */
......@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
* NOTE: If this hangup was signaled from user space then the
* final put will never happen.
*/
kref_put(&hvcsd->kref, destroy_hvcs_struct);
tty_port_put(&hvcsd->port);
}
}
......@@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
* the middle of a write operation? This is a crummy place to do this
* but we want to keep it all in the spinlock.
*/
if (hvcsd->open_count <= 0) {
if (hvcsd->port.count <= 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
return -ENODEV;
}
......@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
if (!hvcsd || hvcsd->open_count <= 0)
if (!hvcsd || hvcsd->port.count <= 0)
return 0;
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
......
......@@ -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__);
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->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;
......
......@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
pr_devel("HVSI@%x: open !\n", pv->termno);
/* Keep track of the tty data structure */
pv->tty = tty_kref_get(hp->tty);
pv->tty = tty_port_tty_get(&hp->port);
hvsilib_establish(pv);
......
......@@ -44,14 +44,13 @@
#define TTYTYPE_RAS_RAW (2)
struct ipw_tty {
struct tty_port port;
int index;
struct ipw_hardware *hardware;
unsigned int channel_idx;
unsigned int secondary_channel_idx;
int tty_type;
struct ipw_network *network;
struct tty_struct *linux_tty;
int open_count;
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
......@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
return channel_names[tty_type];
}
static void report_registering(struct ipw_tty *tty)
{
char *iftype = tty_type_name(tty->tty_type);
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n", iftype, tty->index);
}
static void report_deregistering(struct ipw_tty *tty)
{
char *iftype = tty_type_name(tty->tty_type);
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n", iftype,
tty->index);
}
static struct ipw_tty *get_tty(int index)
{
/*
......@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
mutex_unlock(&tty->ipw_tty_mutex);
return -ENODEV;
}
if (tty->open_count == 0)
if (tty->port.count == 0)
tty->tx_bytes_queued = 0;
tty->open_count++;
tty->port.count++;
tty->linux_tty = linux_tty;
tty->port.tty = linux_tty;
linux_tty->driver_data = tty;
linux_tty->low_latency = 1;
......@@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
static void do_ipw_close(struct ipw_tty *tty)
{
tty->open_count--;
tty->port.count--;
if (tty->open_count == 0) {
struct tty_struct *linux_tty = tty->linux_tty;
if (tty->port.count == 0) {
struct tty_struct *linux_tty = tty->port.tty;
if (linux_tty != NULL) {
tty->linux_tty = NULL;
tty->port.tty = NULL;
linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM)
......@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
return;
mutex_lock(&tty->ipw_tty_mutex);
if (tty->open_count == 0) {
if (tty->port.count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
......@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
int work = 0;
mutex_lock(&tty->ipw_tty_mutex);
linux_tty = tty->linux_tty;
linux_tty = tty->port.tty;
if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
if (!tty->open_count) {
if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
......@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
if (!tty->open_count) {
if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL;
}
......@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
......@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
if (!tty)
return 0;
if (!tty->open_count)
if (!tty->port.count)
return 0;
return tty->tx_bytes_queued;
......@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
return get_control_lines(tty);
......@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
return set_control_lines(tty, set, clear);
......@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
if (!tty->open_count)
if (!tty->port.count)
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
......@@ -492,6 +474,7 @@ static int add_tty(int j,
ttys[j]->network = network;
ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
tty_register_device(ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
......@@ -500,8 +483,12 @@ static int add_tty(int j,
ipwireless_associate_network_tty(network,
secondary_channel_idx,
ttys[j]);
if (get_tty(j) == ttys[j])
report_registering(ttys[j]);
/* check if we provide raw device (if loopback is enabled) */
if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n",
tty_type_name(tty_type), j);
return 0;
}
......@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex);
if (get_tty(j) == ttyj)
report_deregistering(ttyj);
if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n",
tty_type_name(ttyj->tty_type), j);
ttyj->closing = 1;
if (ttyj->linux_tty != NULL) {
if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
tty_hangup(ttyj->linux_tty);
/* Wait till the tty_hangup has completed */
flush_work_sync(&ttyj->linux_tty->hangup_work);
tty_vhangup(ttyj->port.tty);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
/* FIXME2: hangup does not mean all processes
* are gone */
mutex_lock(&ttyj->ipw_tty_mutex);
}
while (ttyj->open_count)
while (ttyj->port.count)
do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
......@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
*/
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
&& tty->linux_tty) {
tty_hangup(tty->linux_tty);
&& tty->port.tty) {
tty_hangup(tty->port.tty);
}
}
......@@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {
.get_icount = mxser_get_icount,
};
struct tty_port_operations mxser_port_ops = {
static struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.dtr_rts = mxser_dtr_rts,
.activate = mxser_activate,
......
......@@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
tty_lock();
/* FIXME: should use a private lock */
tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
......@@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock;
}
/* block until there is a message: */
wait_event_interruptible_tty(pInfo->read_wait,
wait_event_interruptible_tty(tty, pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient)));
}
......@@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
}
ret = -EPERM;
unlock:
tty_unlock();
tty_unlock(tty);
return ret;
}
......@@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
tty_lock();
tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
......@@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
tty_unlock();
tty_unlock(tty);
return 0;
}
......
......@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval;
size_t n;
unsigned long flags;
bool is_eof;
retval = 0;
spin_lock_irqsave(&tty->read_lock, flags);
......@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
is_eof = n == 1 &&
tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && tty->icanon && n == 1) {
if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
n--;
}
if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
n = 0;
spin_unlock_irqrestore(&tty->read_lock, flags);
*b += n;
*nr -= n;
......
......@@ -26,11 +26,13 @@
#include <linux/bitops.h>
#include <linux/devpts_fs.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
static DEFINE_MUTEX(devpts_mutex);
#endif
static void pty_close(struct tty_struct *tty, struct file *filp)
......@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
tty->packet = 0;
/* Review - krefs on tty_link ?? */
if (!tty->link)
return;
tty->link->packet = 0;
......@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver)
if (tty->driver == ptm_driver) {
mutex_lock(&devpts_mutex);
devpts_pty_kill(tty->link);
mutex_unlock(&devpts_mutex);
}
#endif
tty_unlock();
tty_unlock(tty);
tty_vhangup(tty->link);
tty_lock();
tty_lock(tty);
}
}
......@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
* @idx: tty index
*
* Look up a pty master device. Called under the tty_mutex for now.
* This provides our locking.
* This provides our locking for the tty pointer.
*/
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct inode *pts_inode, int idx)
{
struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
struct tty_struct *tty;
mutex_lock(&devpts_mutex);
tty = devpts_get_tty(pts_inode, idx);
mutex_unlock(&devpts_mutex);
/* Master must be open before slave */
if (!tty)
return ERR_PTR(-EIO);
......@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval;
/* find a device that is not in use. */
tty_lock();
mutex_lock(&devpts_mutex);
index = devpts_new_index(inode);
tty_unlock();
if (index < 0) {
retval = index;
goto err_file;
}
mutex_unlock(&devpts_mutex);
mutex_lock(&tty_mutex);
tty_lock();
mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index);
mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
goto out;
}
/* The tty returned here is locked so we can safely
drop the mutex */
mutex_unlock(&devpts_mutex);
mutex_unlock(&tty_mutex);
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp);
......@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
tty_unlock();
tty_unlock(tty);
return 0;
err_release:
tty_unlock();
tty_unlock(tty);
tty_release(inode, filp);
return retval;
out:
mutex_unlock(&tty_mutex);
devpts_kill_index(inode, index);
tty_unlock();
err_file:
mutex_unlock(&devpts_mutex);
tty_free_file(filp);
return retval;
}
......
此差异已折叠。
/* 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) */
......@@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = {
},
};
#if defined(CONFIG_MIPS_ALCHEMY)
/* Uart divisor latch read */
static int default_serial_dl_read(struct uart_8250_port *up)
{
return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
}
/* Uart divisor latch write */
static void default_serial_dl_write(struct uart_8250_port *up, int value)
{
serial_out(up, UART_DLL, value & 0xff);
serial_out(up, UART_DLM, value >> 8 & 0xff);
}
#ifdef CONFIG_MIPS_ALCHEMY
/* Au1x00 UART hardware has a weird register layout */
static const u8 au_io_in_map[] = {
......@@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = {
[UART_MCR] = 6,
};
/* sane hardware needs no mapping */
static inline int map_8250_in_reg(struct uart_port *p, int offset)
static unsigned int au_serial_in(struct uart_port *p, int offset)
{
offset = au_io_in_map[offset] << p->regshift;
return __raw_readl(p->membase + offset);
}
static void au_serial_out(struct uart_port *p, int offset, int value)
{
offset = au_io_out_map[offset] << p->regshift;
__raw_writel(value, p->membase + offset);
}
/* Au1x00 haven't got a standard divisor latch */
static int au_serial_dl_read(struct uart_8250_port *up)
{
if (p->iotype != UPIO_AU)
return offset;
return au_io_in_map[offset];
return __raw_readl(up->port.membase + 0x28);
}
static inline int map_8250_out_reg(struct uart_port *p, int offset)
static void au_serial_dl_write(struct uart_8250_port *up, int value)
{
if (p->iotype != UPIO_AU)
return offset;
return au_io_out_map[offset];
__raw_writel(value, up->port.membase + 0x28);
}
#elif defined(CONFIG_SERIAL_8250_RM9K)
#endif
#ifdef CONFIG_SERIAL_8250_RM9K
static const u8
regmap_in[8] = {
......@@ -344,87 +367,79 @@ static const u8
[UART_SCR] = 0x2c
};
static inline int map_8250_in_reg(struct uart_port *p, int offset)
static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
{
if (p->iotype != UPIO_RM9000)
return offset;
return regmap_in[offset];
offset = regmap_in[offset] << p->regshift;
return readl(p->membase + offset);
}
static inline int map_8250_out_reg(struct uart_port *p, int offset)
static void rm9k_serial_out(struct uart_port *p, int offset, int value)
{
if (p->iotype != UPIO_RM9000)
return offset;
return regmap_out[offset];
offset = regmap_out[offset] << p->regshift;
writel(value, p->membase + offset);
}
#else
static int rm9k_serial_dl_read(struct uart_8250_port *up)
{
return ((__raw_readl(up->port.membase + 0x10) << 8) |
(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
}
/* sane hardware needs no mapping */
#define map_8250_in_reg(up, offset) (offset)
#define map_8250_out_reg(up, offset) (offset)
static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
{
__raw_writel(value, up->port.membase + 0x08);
__raw_writel(value >> 8, up->port.membase + 0x10);
}
#endif
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
return inb(p->iobase + 1);
}
static void hub6_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
outb(value, p->iobase + 1);
}
static unsigned int mem_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
return readb(p->membase + offset);
}
static void mem_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
writeb(value, p->membase + offset);
}
static void mem32_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
writel(value, p->membase + offset);
}
static unsigned int mem32_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
return readl(p->membase + offset);
}
static unsigned int au_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
return __raw_readl(p->membase + offset);
}
static void au_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
__raw_writel(value, p->membase + offset);
}
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
return inb(p->iobase + offset);
}
static void io_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
offset = offset << p->regshift;
outb(value, p->iobase + offset);
}
......@@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p)
{
struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port);
up->dl_read = default_serial_dl_read;
up->dl_write = default_serial_dl_write;
switch (p->iotype) {
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
......@@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem_serial_out;
break;
case UPIO_RM9000:
case UPIO_MEM32:
p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out;
break;
#ifdef CONFIG_SERIAL_8250_RM9K
case UPIO_RM9000:
p->serial_in = rm9k_serial_in;
p->serial_out = rm9k_serial_out;
up->dl_read = rm9k_serial_dl_read;
up->dl_write = rm9k_serial_dl_write;
break;
#endif
#ifdef CONFIG_MIPS_ALCHEMY
case UPIO_AU:
p->serial_in = au_serial_in;
p->serial_out = au_serial_out;
up->dl_read = au_serial_dl_read;
up->dl_write = au_serial_dl_write;
break;
#endif
default:
p->serial_in = io_serial_in;
......@@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
}
}
/* Uart divisor latch read */
static inline int _serial_dl_read(struct uart_8250_port *up)
{
return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
}
/* Uart divisor latch write */
static inline void _serial_dl_write(struct uart_8250_port *up, int value)
{
serial_out(up, UART_DLL, value & 0xff);
serial_out(up, UART_DLM, value >> 8 & 0xff);
}
#if defined(CONFIG_MIPS_ALCHEMY)
/* Au1x00 haven't got a standard divisor latch */
static int serial_dl_read(struct uart_8250_port *up)
{
if (up->port.iotype == UPIO_AU)
return __raw_readl(up->port.membase + 0x28);
else
return _serial_dl_read(up);
}
static void serial_dl_write(struct uart_8250_port *up, int value)
{
if (up->port.iotype == UPIO_AU)
__raw_writel(value, up->port.membase + 0x28);
else
_serial_dl_write(up, value);
}
#elif defined(CONFIG_SERIAL_8250_RM9K)
static int serial_dl_read(struct uart_8250_port *up)
{
return (up->port.iotype == UPIO_RM9000) ?
(((__raw_readl(up->port.membase + 0x10) << 8) |
(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
_serial_dl_read(up);
}
static void serial_dl_write(struct uart_8250_port *up, int value)
{
if (up->port.iotype == UPIO_RM9000) {
__raw_writel(value, up->port.membase + 0x08);
__raw_writel(value >> 8, up->port.membase + 0x10);
} else {
_serial_dl_write(up, value);
}
}
#else
#define serial_dl_read(up) _serial_dl_read(up)
#define serial_dl_write(up, value) _serial_dl_write(up, value)
#endif
/*
* For the 16C950
*/
......@@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
unsigned char fcr;
serial8250_clear_fifos(p);
fcr = uart_config[p->port.type].fcr;
serial_out(p, UART_FCR, fcr);
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
/*
* IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to
......@@ -1331,27 +1319,6 @@ static void serial8250_enable_ms(struct uart_port *port)
serial_port_out(port, UART_IER, up->ier);
}
/*
* Clear the Tegra rx fifo after a break
*
* FIXME: This needs to become a port specific callback once we have a
* framework for this
*/
static void clear_rx_fifo(struct uart_8250_port *up)
{
unsigned int status, tmout = 10000;
do {
status = serial_in(up, UART_LSR);
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
status = serial_in(up, UART_RX);
else
break;
if (--tmout == 0)
break;
udelay(1);
} while (1);
}
/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
......@@ -1386,19 +1353,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
up->lsr_saved_flags = 0;
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
/*
* For statistics only
*/
if (lsr & UART_LSR_BI) {
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
port->icount.brk++;
/*
* If tegra port then clear the rx fifo to
* accept another break/character.
*/
if (port->type == PORT_TEGRA)
clear_rx_fifo(up);
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
......@@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
quot++;
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
if (baud < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
else
fcr = uart_config[port->type].fcr;
fcr = uart_config[port->type].fcr;
if (baud < 2400) {
fcr &= ~UART_FCR_TRIGGER_MASK;
fcr |= UART_FCR_TRIGGER_1;
}
}
/*
......@@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq;
port.handle_break = p->handle_break;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
......@@ -3153,7 +3112,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
}
/**
* serial8250_register_port - register a serial port
* serial8250_register_8250_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
......@@ -3165,50 +3124,56 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
*
* On success the port is ready to use and the line number is returned.
*/
int serial8250_register_port(struct uart_port *port)
int serial8250_register_8250_port(struct uart_8250_port *up)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
if (port->uartclk == 0)
if (up->port.uartclk == 0)
return -EINVAL;
mutex_lock(&serial_mutex);
uart = serial8250_find_match_or_unused(port);
uart = serial8250_find_match_or_unused(&up->port);
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.iobase = port->iobase;
uart->port.membase = port->membase;
uart->port.irq = port->irq;
uart->port.irqflags = port->irqflags;
uart->port.uartclk = port->uartclk;
uart->port.fifosize = port->fifosize;
uart->port.regshift = port->regshift;
uart->port.iotype = port->iotype;
uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
uart->port.mapbase = port->mapbase;
uart->port.private_data = port->private_data;
if (port->dev)
uart->port.dev = port->dev;
if (port->flags & UPF_FIXED_TYPE)
serial8250_init_fixed_type_port(uart, port->type);
uart->port.iobase = up->port.iobase;
uart->port.membase = up->port.membase;
uart->port.irq = up->port.irq;
uart->port.irqflags = up->port.irqflags;
uart->port.uartclk = up->port.uartclk;
uart->port.fifosize = up->port.fifosize;
uart->port.regshift = up->port.regshift;
uart->port.iotype = up->port.iotype;
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
uart->port.mapbase = up->port.mapbase;
uart->port.private_data = up->port.private_data;
if (up->port.dev)
uart->port.dev = up->port.dev;
if (up->port.flags & UPF_FIXED_TYPE)
serial8250_init_fixed_type_port(uart, up->port.type);
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
if (port->serial_in)
uart->port.serial_in = port->serial_in;
if (port->serial_out)
uart->port.serial_out = port->serial_out;
if (port->handle_irq)
uart->port.handle_irq = port->handle_irq;
if (up->port.serial_in)
uart->port.serial_in = up->port.serial_in;
if (up->port.serial_out)
uart->port.serial_out = up->port.serial_out;
if (up->port.handle_irq)
uart->port.handle_irq = up->port.handle_irq;
/* Possibly override set_termios call */
if (port->set_termios)
uart->port.set_termios = port->set_termios;
if (port->pm)
uart->port.pm = port->pm;
if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios;
if (up->port.pm)
uart->port.pm = up->port.pm;
if (up->port.handle_break)
uart->port.handle_break = up->port.handle_break;
if (up->dl_read)
uart->dl_read = up->dl_read;
if (up->dl_write)
uart->dl_write = up->dl_write;
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
......@@ -3222,6 +3187,29 @@ int serial8250_register_port(struct uart_port *port)
return ret;
}
EXPORT_SYMBOL(serial8250_register_8250_port);
/**
* serial8250_register_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
* port exists and is in use, it is hung up and unregistered
* first.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int serial8250_register_port(struct uart_port *port)
{
struct uart_8250_port up;
memset(&up, 0, sizeof(up));
memcpy(&up.port, port, sizeof(*port));
return serial8250_register_8250_port(&up);
}
EXPORT_SYMBOL(serial8250_register_port);
/**
......
......@@ -37,6 +37,10 @@ struct uart_8250_port {
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
/* 8250 specific callbacks */
int (*dl_read)(struct uart_8250_port *);
void (*dl_write)(struct uart_8250_port *, int);
};
struct old_serial_port {
......@@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
up->port.serial_out(&up->port, offset, value);
}
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
static inline int serial_dl_read(struct uart_8250_port *up)
{
return up->dl_read(up);
}
static inline void serial_dl_write(struct uart_8250_port *up, int value)
{
up->dl_write(up, value);
}
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
* Digital did something really horribly wrong with the OUT1 and OUT2
......
此差异已折叠。
此差异已折叠。
......@@ -278,3 +278,11 @@ config SERIAL_8250_DW
help
Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART.
config SERIAL_8250_EM
tristate "Support for Emma Mobile intergrated serial port"
depends on SERIAL_8250 && ARM && HAVE_CLK
help
Selecting this option will add support for the integrated serial
port hardware found on the Emma Mobile line of processors.
If unsure, say N.
......@@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -370,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,
writel(ctrl, u->membase + AUART_LINECTRL);
writel(ctrl2, u->membase + AUART_CTRL2);
uart_update_timeout(u, termios->c_cflag, baud);
}
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)
tty_unregister_driver(p);
put_tty_driver(p);
kfree(drv->state);
drv->state = NULL;
drv->tty_driver = NULL;
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册