diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/hvc_console.c | 86 | ||||
-rw-r--r-- | drivers/char/hvc_console.h | 12 | ||||
-rw-r--r-- | drivers/char/hvc_irq.c | 5 | ||||
-rw-r--r-- | drivers/char/hvc_iseries.c | 1 | ||||
-rw-r--r-- | drivers/char/hvc_vio.c | 1 | ||||
-rw-r--r-- | drivers/char/hvc_xen.c | 1 | ||||
-rw-r--r-- | drivers/char/tty_port.c | 2 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 1 |
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 | */ |
434 | static void hvc_push(struct hvc_struct *hp) | 440 | static 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 | ||
455 | static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) | 463 | static 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 | */ | ||
512 | static 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 | } |
633 | EXPORT_SYMBOL_GPL(hvc_poll); | 678 | EXPORT_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 | */ | ||
690 | void 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 | } |
744 | EXPORT_SYMBOL_GPL(hvc_alloc); | 804 | EXPORT_SYMBOL_GPL(hvc_alloc); |
745 | 805 | ||
746 | int __devexit hvc_remove(struct hvc_struct *hp) | 806 | int 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); | |||
77 | extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, | 81 | extern 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) */ |
80 | extern int __devexit hvc_remove(struct hvc_struct *hp); | 84 | extern int hvc_remove(struct hvc_struct *hp); |
81 | 85 | ||
82 | /* data available */ | 86 | /* data available */ |
83 | int hvc_poll(struct hvc_struct *hp); | 87 | int hvc_poll(struct hvc_struct *hp); |
84 | void hvc_kick(void); | 88 | void hvc_kick(void); |
85 | 89 | ||
90 | /* Resize hvc tty terminal window */ | ||
91 | extern 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 */ |
87 | extern int notifier_add_irq(struct hvc_struct *hp, int data); | 94 | extern int notifier_add_irq(struct hvc_struct *hp, int data); |
88 | extern void notifier_del_irq(struct hvc_struct *hp, int data); | 95 | extern void notifier_del_irq(struct hvc_struct *hp, int data); |
96 | extern 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 | |||
46 | void 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 | ||
207 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, | 208 | static 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 | ||
87 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, | 88 | static 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 | ||
107 | static int __init xen_init(void) | 108 | static 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 | } |
96 | EXPORT_SYMBOL(tty_port_tty_set); | 96 | EXPORT_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 |