summaryrefslogtreecommitdiff
path: root/drivers/tty/hvc/hvcs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 19:26:52 (GMT)
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 19:26:52 (GMT)
commit3498d13b8090c0b0ef911409fbc503a7c4cca6ef (patch)
tree254ca00276e863d9fba25707690c66b2a04c49e9 /drivers/tty/hvc/hvcs.c
parentdef7cb8cd4e3258db88050eaaca5438bcc3dafca (diff)
parent0c57dfcc6c1d037243c2f8fbf62eab3633326ec0 (diff)
downloadlinux-3498d13b8090c0b0ef911409fbc503a7c4cca6ef.tar.xz
Merge tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull TTY changes from Greg Kroah-Hartman: "As we skipped the merge window for 3.6-rc1 for the tty tree, everything is now settled down and working properly, so we are ready for 3.7-rc1. Here's the patchset, it's big, but the large changes are removing a firmware file and adding a staging tty driver (it depended on the tty core changes, so it's going through this tree instead of the staging tree.) All of these patches have been in the linux-next tree for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" Fix up more-or-less trivial conflicts in - drivers/char/pcmcia/synclink_cs.c: tty NULL dereference fix vs tty_port_cts_enabled() helper function - drivers/staging/{Kconfig,Makefile}: add-add conflict (dgrp driver added close to other staging drivers) - drivers/staging/ipack/devices/ipoctal.c: "split ipoctal_channel from iopctal" vs "TTY: use tty_port_register_device" * tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (235 commits) tty/serial: Add kgdb_nmi driver tty/serial/amba-pl011: Quiesce interrupts in poll_get_char tty/serial/amba-pl011: Implement poll_init callback tty/serial/core: Introduce poll_init callback kdb: Turn KGDB_KDB=n stubs into static inlines kdb: Implement disable_nmi command kernel/debug: Mask KGDB NMI upon entry serial: pl011: handle corruption at high clock speeds serial: sccnxp: Make 'default' choice in switch last serial: sccnxp: Remove mask termios caps for SW flow control serial: sccnxp: Report actual baudrate back to core serial: samsung: Add poll_get_char & poll_put_char Powerpc 8xx CPM_UART setting MAXIDL register proportionaly to baud rate Powerpc 8xx CPM_UART maxidl should not depend on fifo size Powerpc 8xx CPM_UART too many interrupts Powerpc 8xx CPM_UART desynchronisation serial: set correct baud_base for EXSYS EX-41092 Dual 16950 serial: omap: fix the reciever line error case 8250: blacklist Winbond CIR port 8250_pnp: do pnp probe before legacy probe ...
Diffstat (limited to 'drivers/tty/hvc/hvcs.c')
-rw-r--r--drivers/tty/hvc/hvcs.c82
1 files changed, 49 insertions, 33 deletions
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d56788c..cab5c7a 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
return NULL;
}
-/*
- * This is invoked via the tty_open interface when a user app connects to the
- * /dev node.
- */
-static int hvcs_open(struct tty_struct *tty, struct file *filp)
+static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct hvcs_struct *hvcsd;
- int rc, retval = 0;
- unsigned long flags;
- unsigned int irq;
struct vio_dev *vdev;
- unsigned long unit_address;
-
- if (tty->driver_data)
- goto fast_open;
+ unsigned long unit_address, flags;
+ unsigned int irq;
+ int retval;
/*
* Is there a vty-server that shares the same index?
* This function increments the kref index.
*/
- if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+ hvcsd = hvcs_get_by_index(tty->index);
+ if (!hvcsd) {
printk(KERN_WARNING "HVCS: open failed, no device associated"
" with tty->index %d.\n", tty->index);
return -ENODEV;
@@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hvcsd->lock, flags);
- if (hvcsd->connected == 0)
- if ((retval = hvcs_partner_connect(hvcsd)))
- goto error_release;
+ if (hvcsd->connected == 0) {
+ retval = hvcs_partner_connect(hvcsd);
+ if (retval) {
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ printk(KERN_WARNING "HVCS: partner connect failed.\n");
+ goto err_put;
+ }
+ }
- hvcsd->port.count = 1;
+ hvcsd->port.count = 0;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
@@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* This must be done outside of the spinlock because it requests irqs
* and will grab the spinlock and free the connection if it fails.
*/
- if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
- tty_port_put(&hvcsd->port);
+ retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
+ if (retval) {
printk(KERN_WARNING "HVCS: enable device failed.\n");
- return rc;
+ goto err_put;
}
- goto open_success;
+ retval = tty_port_install(&hvcsd->port, driver, tty);
+ if (retval)
+ goto err_irq;
-fast_open:
- hvcsd = tty->driver_data;
+ return 0;
+err_irq:
+ spin_lock_irqsave(&hvcsd->lock, flags);
+ vio_disable_interrupts(hvcsd->vdev);
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ free_irq(irq, hvcsd);
+err_put:
+ tty_port_put(&hvcsd->port);
+
+ return retval;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+ unsigned long flags;
spin_lock_irqsave(&hvcsd->lock, flags);
- tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
-open_success:
hvcs_kick();
printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
hvcsd->vdev->unit_address );
return 0;
-
-error_release:
- spin_unlock_irqrestore(&hvcsd->lock, flags);
- tty_port_put(&hvcsd->port);
-
- printk(KERN_WARNING "HVCS: partner connect failed.\n");
- return retval;
}
static void hvcs_close(struct tty_struct *tty, struct file *filp)
@@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
- tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+static void hvcs_cleanup(struct tty_struct * tty)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+
tty_port_put(&hvcsd->port);
}
@@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
}
static const struct tty_operations hvcs_ops = {
+ .install = hvcs_install,
.open = hvcs_open,
.close = hvcs_close,
+ .cleanup = hvcs_cleanup,
.hangup = hvcs_hangup,
.write = hvcs_write,
.write_room = hvcs_write_room,