aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hvc_console.c86
-rw-r--r--drivers/char/hvc_console.h12
-rw-r--r--drivers/char/hvc_irq.c5
-rw-r--r--drivers/char/hvc_iseries.c1
-rw-r--r--drivers/char/hvc_vio.c1
-rw-r--r--drivers/char/hvc_xen.c1
-rw-r--r--drivers/char/tty_port.c2
-rw-r--r--drivers/char/virtio_console.c1
8 files changed, 93 insertions, 16 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index bf70450a49cc..5b819b12675a 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -161,7 +161,7 @@ static void hvc_console_print(struct console *co, const char *b,
161 } 161 }
162 } else { 162 } else {
163 r = cons_ops[index]->put_chars(vtermnos[index], c, i); 163 r = cons_ops[index]->put_chars(vtermnos[index], c, i);
164 if (r < 0) { 164 if (r <= 0) {
165 /* throw away chars on error */ 165 /* throw away chars on error */
166 i = 0; 166 i = 0;
167 } else if (r > 0) { 167 } else if (r > 0) {
@@ -374,6 +374,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
374 if (hp->ops->notifier_del) 374 if (hp->ops->notifier_del)
375 hp->ops->notifier_del(hp, hp->data); 375 hp->ops->notifier_del(hp, hp->data);
376 376
377 /* cancel pending tty resize work */
378 cancel_work_sync(&hp->tty_resize);
379
377 /* 380 /*
378 * Chain calls chars_in_buffer() and returns immediately if 381 * Chain calls chars_in_buffer() and returns immediately if
379 * there is no buffered data otherwise sleeps on a wait queue 382 * there is no buffered data otherwise sleeps on a wait queue
@@ -399,6 +402,9 @@ static void hvc_hangup(struct tty_struct *tty)
399 if (!hp) 402 if (!hp)
400 return; 403 return;
401 404
405 /* cancel pending tty resize work */
406 cancel_work_sync(&hp->tty_resize);
407
402 spin_lock_irqsave(&hp->lock, flags); 408 spin_lock_irqsave(&hp->lock, flags);
403 409
404 /* 410 /*
@@ -418,8 +424,8 @@ static void hvc_hangup(struct tty_struct *tty)
418 424
419 spin_unlock_irqrestore(&hp->lock, flags); 425 spin_unlock_irqrestore(&hp->lock, flags);
420 426
421 if (hp->ops->notifier_del) 427 if (hp->ops->notifier_hangup)
422 hp->ops->notifier_del(hp, hp->data); 428 hp->ops->notifier_hangup(hp, hp->data);
423 429
424 while(temp_open_count) { 430 while(temp_open_count) {
425 --temp_open_count; 431 --temp_open_count;
@@ -431,7 +437,7 @@ static void hvc_hangup(struct tty_struct *tty)
431 * Push buffered characters whether they were just recently buffered or waiting 437 * Push buffered characters whether they were just recently buffered or waiting
432 * on a blocked hypervisor. Call this function with hp->lock held. 438 * on a blocked hypervisor. Call this function with hp->lock held.
433 */ 439 */
434static void hvc_push(struct hvc_struct *hp) 440static int hvc_push(struct hvc_struct *hp)
435{ 441{
436 int n; 442 int n;
437 443
@@ -439,7 +445,7 @@ static void hvc_push(struct hvc_struct *hp)
439 if (n <= 0) { 445 if (n <= 0) {
440 if (n == 0) { 446 if (n == 0) {
441 hp->do_wakeup = 1; 447 hp->do_wakeup = 1;
442 return; 448 return 0;
443 } 449 }
444 /* throw away output on error; this happens when 450 /* throw away output on error; this happens when
445 there is no session connected to the vterm. */ 451 there is no session connected to the vterm. */
@@ -450,6 +456,8 @@ static void hvc_push(struct hvc_struct *hp)
450 memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf); 456 memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
451 else 457 else
452 hp->do_wakeup = 1; 458 hp->do_wakeup = 1;
459
460 return n;
453} 461}
454 462
455static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) 463static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -492,6 +500,39 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
492 return written; 500 return written;
493} 501}
494 502
503/**
504 * hvc_set_winsz() - Resize the hvc tty terminal window.
505 * @work: work structure.
506 *
507 * The routine shall not be called within an atomic context because it
508 * might sleep.
509 *
510 * Locking: hp->lock
511 */
512static void hvc_set_winsz(struct work_struct *work)
513{
514 struct hvc_struct *hp;
515 unsigned long hvc_flags;
516 struct tty_struct *tty;
517 struct winsize ws;
518
519 hp = container_of(work, struct hvc_struct, tty_resize);
520 if (!hp)
521 return;
522
523 spin_lock_irqsave(&hp->lock, hvc_flags);
524 if (!hp->tty) {
525 spin_unlock_irqrestore(&hp->lock, hvc_flags);
526 return;
527 }
528 ws = hp->ws;
529 tty = tty_kref_get(hp->tty);
530 spin_unlock_irqrestore(&hp->lock, hvc_flags);
531
532 tty_do_resize(tty, tty, &ws);
533 tty_kref_put(tty);
534}
535
495/* 536/*
496 * This is actually a contract between the driver and the tty layer outlining 537 * This is actually a contract between the driver and the tty layer outlining
497 * how much write room the driver can guarantee will be sent OR BUFFERED. This 538 * how much write room the driver can guarantee will be sent OR BUFFERED. This
@@ -538,16 +579,20 @@ int hvc_poll(struct hvc_struct *hp)
538 char buf[N_INBUF] __ALIGNED__; 579 char buf[N_INBUF] __ALIGNED__;
539 unsigned long flags; 580 unsigned long flags;
540 int read_total = 0; 581 int read_total = 0;
582 int written_total = 0;
541 583
542 spin_lock_irqsave(&hp->lock, flags); 584 spin_lock_irqsave(&hp->lock, flags);
543 585
544 /* Push pending writes */ 586 /* Push pending writes */
545 if (hp->n_outbuf > 0) 587 if (hp->n_outbuf > 0)
546 hvc_push(hp); 588 written_total = hvc_push(hp);
547 589
548 /* Reschedule us if still some write pending */ 590 /* Reschedule us if still some write pending */
549 if (hp->n_outbuf > 0) 591 if (hp->n_outbuf > 0) {
550 poll_mask |= HVC_POLL_WRITE; 592 poll_mask |= HVC_POLL_WRITE;
593 /* If hvc_push() was not able to write, sleep a few msecs */
594 timeout = (written_total) ? 0 : MIN_TIMEOUT;
595 }
551 596
552 /* No tty attached, just skip */ 597 /* No tty attached, just skip */
553 tty = hp->tty; 598 tty = hp->tty;
@@ -632,6 +677,24 @@ int hvc_poll(struct hvc_struct *hp)
632} 677}
633EXPORT_SYMBOL_GPL(hvc_poll); 678EXPORT_SYMBOL_GPL(hvc_poll);
634 679
680/**
681 * hvc_resize() - Update terminal window size information.
682 * @hp: HVC console pointer
683 * @ws: Terminal window size structure
684 *
685 * Stores the specified window size information in the hvc structure of @hp.
686 * The function schedule the tty resize update.
687 *
688 * Locking: Locking free; the function MUST be called holding hp->lock
689 */
690void hvc_resize(struct hvc_struct *hp, struct winsize ws)
691{
692 if ((hp->ws.ws_row != ws.ws_row) || (hp->ws.ws_col != ws.ws_col)) {
693 hp->ws = ws;
694 schedule_work(&hp->tty_resize);
695 }
696}
697
635/* 698/*
636 * This kthread is either polling or interrupt driven. This is determined by 699 * This kthread is either polling or interrupt driven. This is determined by
637 * calling hvc_poll() who determines whether a console adapter support 700 * calling hvc_poll() who determines whether a console adapter support
@@ -659,10 +722,6 @@ static int khvcd(void *unused)
659 poll_mask |= HVC_POLL_READ; 722 poll_mask |= HVC_POLL_READ;
660 if (hvc_kicked) 723 if (hvc_kicked)
661 continue; 724 continue;
662 if (poll_mask & HVC_POLL_WRITE) {
663 yield();
664 continue;
665 }
666 set_current_state(TASK_INTERRUPTIBLE); 725 set_current_state(TASK_INTERRUPTIBLE);
667 if (!hvc_kicked) { 726 if (!hvc_kicked) {
668 if (poll_mask == 0) 727 if (poll_mask == 0)
@@ -718,6 +777,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
718 777
719 kref_init(&hp->kref); 778 kref_init(&hp->kref);
720 779
780 INIT_WORK(&hp->tty_resize, hvc_set_winsz);
721 spin_lock_init(&hp->lock); 781 spin_lock_init(&hp->lock);
722 spin_lock(&hvc_structs_lock); 782 spin_lock(&hvc_structs_lock);
723 783
@@ -743,7 +803,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
743} 803}
744EXPORT_SYMBOL_GPL(hvc_alloc); 804EXPORT_SYMBOL_GPL(hvc_alloc);
745 805
746int __devexit hvc_remove(struct hvc_struct *hp) 806int hvc_remove(struct hvc_struct *hp)
747{ 807{
748 unsigned long flags; 808 unsigned long flags;
749 struct tty_struct *tty; 809 struct tty_struct *tty;
@@ -796,7 +856,7 @@ static int hvc_init(void)
796 drv->minor_start = HVC_MINOR; 856 drv->minor_start = HVC_MINOR;
797 drv->type = TTY_DRIVER_TYPE_SYSTEM; 857 drv->type = TTY_DRIVER_TYPE_SYSTEM;
798 drv->init_termios = tty_std_termios; 858 drv->init_termios = tty_std_termios;
799 drv->flags = TTY_DRIVER_REAL_RAW; 859 drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
800 tty_set_operations(drv, &hvc_ops); 860 tty_set_operations(drv, &hvc_ops);
801 861
802 /* Always start the kthread because there can be hotplug vty adapters 862 /* Always start the kthread because there can be hotplug vty adapters
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 9790201718ae..8297dbc2e6ec 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -27,6 +27,7 @@
27#ifndef HVC_CONSOLE_H 27#ifndef HVC_CONSOLE_H
28#define HVC_CONSOLE_H 28#define HVC_CONSOLE_H
29#include <linux/kref.h> 29#include <linux/kref.h>
30#include <linux/tty.h>
30 31
31/* 32/*
32 * This is the max number of console adapters that can/will be found as 33 * This is the max number of console adapters that can/will be found as
@@ -56,6 +57,8 @@ struct hvc_struct {
56 struct hv_ops *ops; 57 struct hv_ops *ops;
57 int irq_requested; 58 int irq_requested;
58 int data; 59 int data;
60 struct winsize ws;
61 struct work_struct tty_resize;
59 struct list_head next; 62 struct list_head next;
60 struct kref kref; /* ref count & hvc_struct lifetime */ 63 struct kref kref; /* ref count & hvc_struct lifetime */
61}; 64};
@@ -65,9 +68,10 @@ struct hv_ops {
65 int (*get_chars)(uint32_t vtermno, char *buf, int count); 68 int (*get_chars)(uint32_t vtermno, char *buf, int count);
66 int (*put_chars)(uint32_t vtermno, const char *buf, int count); 69 int (*put_chars)(uint32_t vtermno, const char *buf, int count);
67 70
68 /* Callbacks for notification. Called in open and close */ 71 /* Callbacks for notification. Called in open, close and hangup */
69 int (*notifier_add)(struct hvc_struct *hp, int irq); 72 int (*notifier_add)(struct hvc_struct *hp, int irq);
70 void (*notifier_del)(struct hvc_struct *hp, int irq); 73 void (*notifier_del)(struct hvc_struct *hp, int irq);
74 void (*notifier_hangup)(struct hvc_struct *hp, int irq);
71}; 75};
72 76
73/* Register a vterm and a slot index for use as a console (console_init) */ 77/* Register a vterm and a slot index for use as a console (console_init) */
@@ -77,15 +81,19 @@ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
77extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, 81extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
78 struct hv_ops *ops, int outbuf_size); 82 struct hv_ops *ops, int outbuf_size);
79/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ 83/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
80extern int __devexit hvc_remove(struct hvc_struct *hp); 84extern int hvc_remove(struct hvc_struct *hp);
81 85
82/* data available */ 86/* data available */
83int hvc_poll(struct hvc_struct *hp); 87int hvc_poll(struct hvc_struct *hp);
84void hvc_kick(void); 88void hvc_kick(void);
85 89
90/* Resize hvc tty terminal window */
91extern void hvc_resize(struct hvc_struct *hp, struct winsize ws);
92
86/* default notifier for irq based notification */ 93/* default notifier for irq based notification */
87extern int notifier_add_irq(struct hvc_struct *hp, int data); 94extern int notifier_add_irq(struct hvc_struct *hp, int data);
88extern void notifier_del_irq(struct hvc_struct *hp, int data); 95extern void notifier_del_irq(struct hvc_struct *hp, int data);
96extern void notifier_hangup_irq(struct hvc_struct *hp, int data);
89 97
90 98
91#if defined(CONFIG_XMON) && defined(CONFIG_SMP) 99#if defined(CONFIG_XMON) && defined(CONFIG_SMP)
diff --git a/drivers/char/hvc_irq.c b/drivers/char/hvc_irq.c
index 73a59cdb8947..d09e5688d449 100644
--- a/drivers/char/hvc_irq.c
+++ b/drivers/char/hvc_irq.c
@@ -42,3 +42,8 @@ void notifier_del_irq(struct hvc_struct *hp, int irq)
42 free_irq(irq, hp); 42 free_irq(irq, hp);
43 hp->irq_requested = 0; 43 hp->irq_requested = 0;
44} 44}
45
46void notifier_hangup_irq(struct hvc_struct *hp, int irq)
47{
48 notifier_del_irq(hp, irq);
49}
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b71c610fe5ae..b74a2f8ab908 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -202,6 +202,7 @@ static struct hv_ops hvc_get_put_ops = {
202 .put_chars = put_chars, 202 .put_chars = put_chars,
203 .notifier_add = notifier_add_irq, 203 .notifier_add = notifier_add_irq,
204 .notifier_del = notifier_del_irq, 204 .notifier_del = notifier_del_irq,
205 .notifier_hangup = notifier_hangup_irq,
205}; 206};
206 207
207static int __devinit hvc_vio_probe(struct vio_dev *vdev, 208static int __devinit hvc_vio_probe(struct vio_dev *vdev,
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 93f3840c1682..019e0b58593d 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -82,6 +82,7 @@ static struct hv_ops hvc_get_put_ops = {
82 .put_chars = hvc_put_chars, 82 .put_chars = hvc_put_chars,
83 .notifier_add = notifier_add_irq, 83 .notifier_add = notifier_add_irq,
84 .notifier_del = notifier_del_irq, 84 .notifier_del = notifier_del_irq,
85 .notifier_hangup = notifier_hangup_irq,
85}; 86};
86 87
87static int __devinit hvc_vio_probe(struct vio_dev *vdev, 88static int __devinit hvc_vio_probe(struct vio_dev *vdev,
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index 538ceea5e7df..eba999f8598d 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -102,6 +102,7 @@ static struct hv_ops hvc_ops = {
102 .put_chars = write_console, 102 .put_chars = write_console,
103 .notifier_add = notifier_add_irq, 103 .notifier_add = notifier_add_irq,
104 .notifier_del = notifier_del_irq, 104 .notifier_del = notifier_del_irq,
105 .notifier_hangup = notifier_hangup_irq,
105}; 106};
106 107
107static int __init xen_init(void) 108static int __init xen_init(void)
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 553b0e9d8d17..c8f8024cb40e 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -90,7 +90,7 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
90 spin_lock_irqsave(&port->lock, flags); 90 spin_lock_irqsave(&port->lock, flags);
91 if (port->tty) 91 if (port->tty)
92 tty_kref_put(port->tty); 92 tty_kref_put(port->tty);
93 port->tty = tty; 93 port->tty = tty_kref_get(tty);
94 spin_unlock_irqrestore(&port->lock, flags); 94 spin_unlock_irqrestore(&port->lock, flags);
95} 95}
96EXPORT_SYMBOL(tty_port_tty_set); 96EXPORT_SYMBOL(tty_port_tty_set);
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index d0f4eb6fdb7f..3fb0d2c88ba5 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -198,6 +198,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
198 virtio_cons.put_chars = put_chars; 198 virtio_cons.put_chars = put_chars;
199 virtio_cons.notifier_add = notifier_add_vio; 199 virtio_cons.notifier_add = notifier_add_vio;
200 virtio_cons.notifier_del = notifier_del_vio; 200 virtio_cons.notifier_del = notifier_del_vio;
201 virtio_cons.notifier_hangup = notifier_del_vio;
201 202
202 /* The first argument of hvc_alloc() is the virtual console number, so 203 /* The first argument of hvc_alloc() is the virtual console number, so
203 * we use zero. The second argument is the parameter for the 204 * we use zero. The second argument is the parameter for the