diff options
Diffstat (limited to 'drivers/s390/char/tty3270.c')
-rw-r--r-- | drivers/s390/char/tty3270.c | 109 |
1 files changed, 84 insertions, 25 deletions
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 48767e6bab9d..8f1e02543ada 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/console.h> | 16 | #include <linux/console.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/workqueue.h> | ||
18 | 19 | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/bootmem.h> | 21 | #include <linux/bootmem.h> |
@@ -80,6 +81,8 @@ struct tty3270 { | |||
80 | unsigned int highlight; /* Blink/reverse/underscore */ | 81 | unsigned int highlight; /* Blink/reverse/underscore */ |
81 | unsigned int f_color; /* Foreground color */ | 82 | unsigned int f_color; /* Foreground color */ |
82 | struct tty3270_line *screen; | 83 | struct tty3270_line *screen; |
84 | unsigned int n_model, n_cols, n_rows; /* New model & size */ | ||
85 | struct work_struct resize_work; | ||
83 | 86 | ||
84 | /* Input stuff. */ | 87 | /* Input stuff. */ |
85 | struct string *prompt; /* Output string for input area. */ | 88 | struct string *prompt; /* Output string for input area. */ |
@@ -115,6 +118,7 @@ struct tty3270 { | |||
115 | #define TTY_UPDATE_ALL 16 /* Recreate screen. */ | 118 | #define TTY_UPDATE_ALL 16 /* Recreate screen. */ |
116 | 119 | ||
117 | static void tty3270_update(struct tty3270 *); | 120 | static void tty3270_update(struct tty3270 *); |
121 | static void tty3270_resize_work(struct work_struct *work); | ||
118 | 122 | ||
119 | /* | 123 | /* |
120 | * Setup timeout for a device. On timeout trigger an update. | 124 | * Setup timeout for a device. On timeout trigger an update. |
@@ -711,6 +715,7 @@ tty3270_alloc_view(void) | |||
711 | tasklet_init(&tp->readlet, | 715 | tasklet_init(&tp->readlet, |
712 | (void (*)(unsigned long)) tty3270_read_tasklet, | 716 | (void (*)(unsigned long)) tty3270_read_tasklet, |
713 | (unsigned long) tp->read); | 717 | (unsigned long) tp->read); |
718 | INIT_WORK(&tp->resize_work, tty3270_resize_work); | ||
714 | 719 | ||
715 | return tp; | 720 | return tp; |
716 | 721 | ||
@@ -754,42 +759,96 @@ tty3270_free_view(struct tty3270 *tp) | |||
754 | /* | 759 | /* |
755 | * Allocate tty3270 screen. | 760 | * Allocate tty3270 screen. |
756 | */ | 761 | */ |
757 | static int | 762 | static struct tty3270_line * |
758 | tty3270_alloc_screen(struct tty3270 *tp) | 763 | tty3270_alloc_screen(unsigned int rows, unsigned int cols) |
759 | { | 764 | { |
765 | struct tty3270_line *screen; | ||
760 | unsigned long size; | 766 | unsigned long size; |
761 | int lines; | 767 | int lines; |
762 | 768 | ||
763 | size = sizeof(struct tty3270_line) * (tp->view.rows - 2); | 769 | size = sizeof(struct tty3270_line) * (rows - 2); |
764 | tp->screen = kzalloc(size, GFP_KERNEL); | 770 | screen = kzalloc(size, GFP_KERNEL); |
765 | if (!tp->screen) | 771 | if (!screen) |
766 | goto out_err; | 772 | goto out_err; |
767 | for (lines = 0; lines < tp->view.rows - 2; lines++) { | 773 | for (lines = 0; lines < rows - 2; lines++) { |
768 | size = sizeof(struct tty3270_cell) * tp->view.cols; | 774 | size = sizeof(struct tty3270_cell) * cols; |
769 | tp->screen[lines].cells = kzalloc(size, GFP_KERNEL); | 775 | screen[lines].cells = kzalloc(size, GFP_KERNEL); |
770 | if (!tp->screen[lines].cells) | 776 | if (!screen[lines].cells) |
771 | goto out_screen; | 777 | goto out_screen; |
772 | } | 778 | } |
773 | return 0; | 779 | return screen; |
774 | out_screen: | 780 | out_screen: |
775 | while (lines--) | 781 | while (lines--) |
776 | kfree(tp->screen[lines].cells); | 782 | kfree(screen[lines].cells); |
777 | kfree(tp->screen); | 783 | kfree(screen); |
778 | out_err: | 784 | out_err: |
779 | return -ENOMEM; | 785 | return ERR_PTR(-ENOMEM); |
780 | } | 786 | } |
781 | 787 | ||
782 | /* | 788 | /* |
783 | * Free tty3270 screen. | 789 | * Free tty3270 screen. |
784 | */ | 790 | */ |
785 | static void | 791 | static void |
786 | tty3270_free_screen(struct tty3270 *tp) | 792 | tty3270_free_screen(struct tty3270_line *screen, unsigned int rows) |
787 | { | 793 | { |
788 | int lines; | 794 | int lines; |
789 | 795 | ||
790 | for (lines = 0; lines < tp->view.rows - 2; lines++) | 796 | for (lines = 0; lines < rows - 2; lines++) |
791 | kfree(tp->screen[lines].cells); | 797 | kfree(screen[lines].cells); |
792 | kfree(tp->screen); | 798 | kfree(screen); |
799 | } | ||
800 | |||
801 | /* | ||
802 | * Resize tty3270 screen | ||
803 | */ | ||
804 | static void tty3270_resize_work(struct work_struct *work) | ||
805 | { | ||
806 | struct tty3270 *tp = container_of(work, struct tty3270, resize_work); | ||
807 | struct tty3270_line *screen, *oscreen; | ||
808 | struct tty_struct *tty; | ||
809 | unsigned int orows; | ||
810 | struct winsize ws; | ||
811 | |||
812 | screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols); | ||
813 | if (!screen) | ||
814 | return; | ||
815 | /* Switch to new output size */ | ||
816 | spin_lock_bh(&tp->view.lock); | ||
817 | oscreen = tp->screen; | ||
818 | orows = tp->view.rows; | ||
819 | tp->view.model = tp->n_model; | ||
820 | tp->view.rows = tp->n_rows; | ||
821 | tp->view.cols = tp->n_cols; | ||
822 | tp->screen = screen; | ||
823 | free_string(&tp->freemem, tp->prompt); | ||
824 | free_string(&tp->freemem, tp->status); | ||
825 | tty3270_create_prompt(tp); | ||
826 | tty3270_create_status(tp); | ||
827 | tp->nr_up = 0; | ||
828 | while (tp->nr_lines < tp->view.rows - 2) | ||
829 | tty3270_blank_line(tp); | ||
830 | tp->update_flags = TTY_UPDATE_ALL; | ||
831 | spin_unlock_bh(&tp->view.lock); | ||
832 | tty3270_free_screen(oscreen, orows); | ||
833 | tty3270_set_timer(tp, 1); | ||
834 | /* Informat tty layer about new size */ | ||
835 | tty = tty_port_tty_get(&tp->port); | ||
836 | if (!tty) | ||
837 | return; | ||
838 | ws.ws_row = tp->view.rows - 2; | ||
839 | ws.ws_col = tp->view.cols; | ||
840 | tty_do_resize(tty, &ws); | ||
841 | } | ||
842 | |||
843 | static void | ||
844 | tty3270_resize(struct raw3270_view *view, int model, int rows, int cols) | ||
845 | { | ||
846 | struct tty3270 *tp = container_of(view, struct tty3270, view); | ||
847 | |||
848 | tp->n_model = model; | ||
849 | tp->n_rows = rows; | ||
850 | tp->n_cols = cols; | ||
851 | schedule_work(&tp->resize_work); | ||
793 | } | 852 | } |
794 | 853 | ||
795 | /* | 854 | /* |
@@ -817,7 +876,8 @@ static void | |||
817 | tty3270_free(struct raw3270_view *view) | 876 | tty3270_free(struct raw3270_view *view) |
818 | { | 877 | { |
819 | struct tty3270 *tp = container_of(view, struct tty3270, view); | 878 | struct tty3270 *tp = container_of(view, struct tty3270, view); |
820 | tty3270_free_screen(tp); | 879 | |
880 | tty3270_free_screen(tp->screen, tp->view.rows); | ||
821 | tty3270_free_view(tp); | 881 | tty3270_free_view(tp); |
822 | } | 882 | } |
823 | 883 | ||
@@ -841,7 +901,8 @@ static struct raw3270_fn tty3270_fn = { | |||
841 | .deactivate = tty3270_deactivate, | 901 | .deactivate = tty3270_deactivate, |
842 | .intv = (void *) tty3270_irq, | 902 | .intv = (void *) tty3270_irq, |
843 | .release = tty3270_release, | 903 | .release = tty3270_release, |
844 | .free = tty3270_free | 904 | .free = tty3270_free, |
905 | .resize = tty3270_resize | ||
845 | }; | 906 | }; |
846 | 907 | ||
847 | /* | 908 | /* |
@@ -869,10 +930,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) | |||
869 | if (tty3270_max_index < tty->index) | 930 | if (tty3270_max_index < tty->index) |
870 | tty3270_max_index = tty->index; | 931 | tty3270_max_index = tty->index; |
871 | 932 | ||
872 | /* Quick exit if there is no device for tty->index. */ | ||
873 | if (PTR_ERR(view) == -ENODEV) | ||
874 | return -ENODEV; | ||
875 | |||
876 | /* Allocate tty3270 structure on first open. */ | 933 | /* Allocate tty3270 structure on first open. */ |
877 | tp = tty3270_alloc_view(); | 934 | tp = tty3270_alloc_view(); |
878 | if (IS_ERR(tp)) | 935 | if (IS_ERR(tp)) |
@@ -884,10 +941,12 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) | |||
884 | return rc; | 941 | return rc; |
885 | } | 942 | } |
886 | 943 | ||
887 | rc = tty3270_alloc_screen(tp); | 944 | tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows); |
888 | if (rc) { | 945 | if (IS_ERR(tp->screen)) { |
946 | rc = PTR_ERR(tp->screen); | ||
889 | raw3270_put_view(&tp->view); | 947 | raw3270_put_view(&tp->view); |
890 | raw3270_del_view(&tp->view); | 948 | raw3270_del_view(&tp->view); |
949 | tty3270_free_view(tp); | ||
891 | return rc; | 950 | return rc; |
892 | } | 951 | } |
893 | 952 | ||