diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-21 17:54:03 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-21 17:54:03 -0800 |
commit | 81ec44a6c69342fec1b1140c60a604027e429f69 (patch) | |
tree | ee6bec8a94ef28e111bf766cf4b7a9366cb4f7c1 /drivers/s390/char/tty3270.c | |
parent | 48a732dfaa77a4dfec803aa8f248373998704f76 (diff) | |
parent | e80cfc31d872b6b85b8966bce6ba80bee401a7dd (diff) | |
download | linux-81ec44a6c69342fec1b1140c60a604027e429f69.tar.bz2 |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 update from Martin Schwidefsky:
"The most prominent change in this patch set is the software dirty bit
patch for s390. It removes __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY and
the page_test_and_clear_dirty primitive which makes the common memory
management code a bit less obscure.
Heiko fixed most of the PCI related fallout, more often than not
missing GENERIC_HARDIRQS dependencies. Notable is one of the 3270
patches which adds an export to tty_io to be able to resize a tty.
The rest is the usual bunch of cleanups and bug fixes."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (42 commits)
s390/module: Add missing R_390_NONE relocation type
drivers/gpio: add missing GENERIC_HARDIRQ dependency
drivers/input: add couple of missing GENERIC_HARDIRQS dependencies
s390/cleanup: rename SPP to LPP
s390/mm: implement software dirty bits
s390/mm: Fix crst upgrade of mmap with MAP_FIXED
s390/linker skript: discard exit.data at runtime
drivers/media: add missing GENERIC_HARDIRQS dependency
s390/bpf,jit: add vlan tag support
drivers/net,AT91RM9200: add missing GENERIC_HARDIRQS dependency
iucv: fix kernel panic at reboot
s390/Kconfig: sort list of arch selected config options
phylib: remove !S390 dependeny from Kconfig
uio: remove !S390 dependency from Kconfig
dasd: fix sysfs cleanup in dasd_generic_remove
s390/pci: fix hotplug module init
s390/pci: cleanup clp page allocation
s390/pci: cleanup clp inline assembly
s390/perf: cpum_cf: fallback to software sampling events
s390/mm: provide PAGE_SHARED define
...
Diffstat (limited to 'drivers/s390/char/tty3270.c')
-rw-r--r-- | drivers/s390/char/tty3270.c | 187 |
1 files changed, 140 insertions, 47 deletions
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 3860e796b65f..b907dba24025 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/console.h> #include <linux/interrupt.h> +#include <linux/workqueue.h> #include <linux/slab.h> #include <linux/bootmem.h> @@ -80,6 +81,8 @@ struct tty3270 { unsigned int highlight; /* Blink/reverse/underscore */ unsigned int f_color; /* Foreground color */ struct tty3270_line *screen; + unsigned int n_model, n_cols, n_rows; /* New model & size */ + struct work_struct resize_work; /* Input stuff. */ struct string *prompt; /* Output string for input area. */ @@ -115,6 +118,7 @@ struct tty3270 { #define TTY_UPDATE_ALL 16 /* Recreate screen. */ static void tty3270_update(struct tty3270 *); +static void tty3270_resize_work(struct work_struct *work); /* * Setup timeout for a device. On timeout trigger an update. @@ -683,12 +687,6 @@ tty3270_alloc_view(void) 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 *) @@ -710,6 +708,15 @@ tty3270_alloc_view(void) tp->kbd = kbd_alloc(); if (!tp->kbd) goto out_reset; + + 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); + INIT_WORK(&tp->resize_work, tty3270_resize_work); + return tp; out_reset: @@ -752,42 +759,96 @@ tty3270_free_view(struct tty3270 *tp) /* * Allocate tty3270 screen. */ -static int -tty3270_alloc_screen(struct tty3270 *tp) +static struct tty3270_line * +tty3270_alloc_screen(unsigned int rows, unsigned int cols) { + struct tty3270_line *screen; unsigned long size; int lines; - size = sizeof(struct tty3270_line) * (tp->view.rows - 2); - tp->screen = kzalloc(size, GFP_KERNEL); - if (!tp->screen) + size = sizeof(struct tty3270_line) * (rows - 2); + screen = kzalloc(size, GFP_KERNEL); + if (!screen) goto out_err; - for (lines = 0; lines < tp->view.rows - 2; lines++) { - size = sizeof(struct tty3270_cell) * tp->view.cols; - tp->screen[lines].cells = kzalloc(size, GFP_KERNEL); - if (!tp->screen[lines].cells) + for (lines = 0; lines < rows - 2; lines++) { + size = sizeof(struct tty3270_cell) * cols; + screen[lines].cells = kzalloc(size, GFP_KERNEL); + if (!screen[lines].cells) goto out_screen; } - return 0; + return screen; out_screen: while (lines--) - kfree(tp->screen[lines].cells); - kfree(tp->screen); + kfree(screen[lines].cells); + kfree(screen); out_err: - return -ENOMEM; + return ERR_PTR(-ENOMEM); } /* * Free tty3270 screen. */ static void -tty3270_free_screen(struct tty3270 *tp) +tty3270_free_screen(struct tty3270_line *screen, unsigned int rows) { int lines; - for (lines = 0; lines < tp->view.rows - 2; lines++) - kfree(tp->screen[lines].cells); - kfree(tp->screen); + for (lines = 0; lines < rows - 2; lines++) + kfree(screen[lines].cells); + kfree(screen); +} + +/* + * Resize tty3270 screen + */ +static void tty3270_resize_work(struct work_struct *work) +{ + struct tty3270 *tp = container_of(work, struct tty3270, resize_work); + struct tty3270_line *screen, *oscreen; + struct tty_struct *tty; + unsigned int orows; + struct winsize ws; + + screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols); + if (!screen) + return; + /* Switch to new output size */ + spin_lock_bh(&tp->view.lock); + oscreen = tp->screen; + orows = tp->view.rows; + tp->view.model = tp->n_model; + tp->view.rows = tp->n_rows; + tp->view.cols = tp->n_cols; + tp->screen = screen; + free_string(&tp->freemem, tp->prompt); + free_string(&tp->freemem, tp->status); + tty3270_create_prompt(tp); + tty3270_create_status(tp); + tp->nr_up = 0; + while (tp->nr_lines < tp->view.rows - 2) + tty3270_blank_line(tp); + tp->update_flags = TTY_UPDATE_ALL; + spin_unlock_bh(&tp->view.lock); + tty3270_free_screen(oscreen, orows); + tty3270_set_timer(tp, 1); + /* Informat tty layer about new size */ + tty = tty_port_tty_get(&tp->port); + if (!tty) + return; + ws.ws_row = tp->view.rows - 2; + ws.ws_col = tp->view.cols; + tty_do_resize(tty, &ws); +} + +static void +tty3270_resize(struct raw3270_view *view, int model, int rows, int cols) +{ + struct tty3270 *tp = container_of(view, struct tty3270, view); + + tp->n_model = model; + tp->n_rows = rows; + tp->n_cols = cols; + schedule_work(&tp->resize_work); } /* @@ -815,7 +876,8 @@ static void tty3270_free(struct raw3270_view *view) { struct tty3270 *tp = container_of(view, struct tty3270, view); - tty3270_free_screen(tp); + + tty3270_free_screen(tp->screen, tp->view.rows); tty3270_free_view(tp); } @@ -827,9 +889,8 @@ tty3270_del_views(void) { int i; - for (i = 0; i < tty3270_max_index; i++) { - struct raw3270_view *view = - raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR); + for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) { + struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i); if (!IS_ERR(view)) raw3270_del_view(view); } @@ -840,7 +901,8 @@ static struct raw3270_fn tty3270_fn = { .deactivate = tty3270_deactivate, .intv = (void *) tty3270_irq, .release = tty3270_release, - .free = tty3270_free + .free = tty3270_free, + .resize = tty3270_resize }; /* @@ -853,8 +915,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) int i, rc; /* Check if the tty3270 is already there. */ - view = raw3270_find_view(&tty3270_fn, - tty->index + RAW3270_FIRSTMINOR); + view = raw3270_find_view(&tty3270_fn, tty->index); if (!IS_ERR(view)) { tp = container_of(view, struct tty3270, view); tty->driver_data = tp; @@ -866,29 +927,26 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) tp->inattr = TF_INPUT; return tty_port_install(&tp->port, driver, tty); } - if (tty3270_max_index < tty->index + 1) - tty3270_max_index = tty->index + 1; - - /* Quick exit if there is no device for tty->index. */ - if (PTR_ERR(view) == -ENODEV) - return -ENODEV; + if (tty3270_max_index < tty->index) + tty3270_max_index = tty->index; /* Allocate tty3270 structure on first open. */ tp = tty3270_alloc_view(); if (IS_ERR(tp)) return PTR_ERR(tp); - rc = raw3270_add_view(&tp->view, &tty3270_fn, - tty->index + RAW3270_FIRSTMINOR); + rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index); if (rc) { tty3270_free_view(tp); return rc; } - rc = tty3270_alloc_screen(tp); - if (rc) { + tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows); + if (IS_ERR(tp->screen)) { + rc = PTR_ERR(tp->screen); raw3270_put_view(&tp->view); raw3270_del_view(&tp->view); + tty3270_free_view(tp); return rc; } @@ -926,6 +984,20 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) } /* + * This routine is called whenever a 3270 tty is opened. + */ +static int +tty3270_open(struct tty_struct *tty, struct file *filp) +{ + struct tty3270 *tp = tty->driver_data; + struct tty_port *port = &tp->port; + + port->count++; + tty_port_tty_set(port, tty); + return 0; +} + +/* * This routine is called when the 3270 tty is closed. We wait * for the remaining request to be completed. Then we clean up. */ @@ -1753,6 +1825,7 @@ static long tty3270_compat_ioctl(struct tty_struct *tty, static const struct tty_operations tty3270_ops = { .install = tty3270_install, .cleanup = tty3270_cleanup, + .open = tty3270_open, .close = tty3270_close, .write = tty3270_write, .put_char = tty3270_put_char, @@ -1771,6 +1844,22 @@ static const struct tty_operations tty3270_ops = { .set_termios = tty3270_set_termios }; +void tty3270_create_cb(int minor) +{ + tty_register_device(tty3270_driver, minor, NULL); +} + +void tty3270_destroy_cb(int minor) +{ + tty_unregister_device(tty3270_driver, minor); +} + +struct raw3270_notifier tty3270_notifier = +{ + .create = tty3270_create_cb, + .destroy = tty3270_destroy_cb, +}; + /* * 3270 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. @@ -1780,23 +1869,25 @@ static int __init tty3270_init(void) struct tty_driver *driver; int ret; - driver = alloc_tty_driver(RAW3270_MAXDEVS); - if (!driver) - return -ENOMEM; + driver = tty_alloc_driver(RAW3270_MAXDEVS, + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_RESET_TERMIOS); + if (IS_ERR(driver)) + return PTR_ERR(driver); /* * Initialize the tty_driver structure * Entries in tty3270_driver that are NOT initialized: * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ - driver->driver_name = "ttyTUB"; - driver->name = "ttyTUB"; + driver->driver_name = "tty3270"; + driver->name = "3270/tty"; driver->major = IBM_TTY3270_MAJOR; - driver->minor_start = RAW3270_FIRSTMINOR; + driver->minor_start = 0; driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; - driver->flags = TTY_DRIVER_RESET_TERMIOS; tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { @@ -1804,6 +1895,7 @@ static int __init tty3270_init(void) return ret; } tty3270_driver = driver; + raw3270_register_notifier(&tty3270_notifier); return 0; } @@ -1812,6 +1904,7 @@ tty3270_exit(void) { struct tty_driver *driver; + raw3270_unregister_notifier(&tty3270_notifier); driver = tty3270_driver; tty3270_driver = NULL; tty_unregister_driver(driver); |