fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / s390 / char / tty3270.c
index 9c816f0..0984462 100644 (file)
@@ -8,7 +8,6 @@
  *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kdev_t.h>
@@ -35,6 +34,7 @@
 #define TTY3270_STRING_PAGES 5
 
 struct tty_driver *tty3270_driver;
+static int tty3270_max_index;
 
 struct raw3270_fn tty3270_fn;
 
@@ -123,16 +123,13 @@ void
 tty3270_set_timer(struct tty3270 *tp, int expires)
 {
        if (expires == 0) {
-               if (timer_pending(&tp->timer)) {
+               if (timer_pending(&tp->timer) && del_timer(&tp->timer))
                        raw3270_put_view(&tp->view);
-                       del_timer(&tp->timer);
-               }
                return;
        }
-       if (timer_pending(&tp->timer)) {
-               if (mod_timer(&tp->timer, jiffies + expires))
-                       return;
-       }
+       if (timer_pending(&tp->timer) &&
+           mod_timer(&tp->timer, jiffies + expires))
+               return;
        raw3270_get_view(&tp->view);
        tp->timer.function = (void (*)(unsigned long)) tty3270_update;
        tp->timer.data = (unsigned long) tp;
@@ -440,7 +437,7 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
 {
        struct string *s;
 
-       tp->rcl_walk = 0;
+       tp->rcl_walk = NULL;
        if (len <= 0)
                return;
        if (tp->rcl_nr >= tp->rcl_max) {
@@ -469,12 +466,12 @@ tty3270_rcl_backward(struct kbd_data *kbd)
                else if (!list_empty(&tp->rcl_lines))
                        tp->rcl_walk = tp->rcl_lines.prev;
                s = tp->rcl_walk ? 
-                       list_entry(tp->rcl_walk, struct string, list) : 0;
+                       list_entry(tp->rcl_walk, struct string, list) : NULL;
                if (tp->rcl_walk) {
                        s = list_entry(tp->rcl_walk, struct string, list);
                        tty3270_update_prompt(tp, s->string, s->len);
                } else
-                       tty3270_update_prompt(tp, 0, 0);
+                       tty3270_update_prompt(tp, NULL, 0);
                tty3270_set_timer(tp, 1);
        }
        spin_unlock_bh(&tp->view.lock);
@@ -556,7 +553,7 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
         * has to be emitted to the tty and for 0x6d the screen
         * needs to be redrawn.
         */
-       input = 0;
+       input = NULL;
        len = 0;
        if (tp->input->string[0] == 0x7d) {
                /* Enter: write input to tty. */
@@ -570,7 +567,7 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
                        tty3270_update_status(tp);
                }
                /* Clear input area. */
-               tty3270_update_prompt(tp, 0, 0);
+               tty3270_update_prompt(tp, NULL, 0);
                tty3270_set_timer(tp, 1);
        } else if (tp->input->string[0] == 0x6d) {
                /* Display has been cleared. Redraw. */
@@ -655,18 +652,12 @@ tty3270_activate(struct raw3270_view *view)
        tp->update_flags = TTY_UPDATE_ALL;
        tty3270_set_timer(tp, 1);
        spin_unlock_irqrestore(&tp->view.lock, flags);
-       start_tty(tp->tty);
        return 0;
 }
 
 static void
 tty3270_deactivate(struct raw3270_view *view)
 {
-       struct tty3270 *tp;
-
-       tp = (struct tty3270 *) view;
-       if (tp && tp->tty)
-               stop_tty(tp->tty);
 }
 
 static int
@@ -699,10 +690,9 @@ tty3270_alloc_view(void)
        struct tty3270 *tp;
        int pages;
 
-       tp = kmalloc(sizeof(struct tty3270),GFP_KERNEL);
+       tp = kzalloc(sizeof(struct tty3270), GFP_KERNEL);
        if (!tp)
                goto out_err;
-       memset(tp, 0, sizeof(struct tty3270));
        tp->freemem_pages =
                kmalloc(sizeof(void *) * TTY3270_STRING_PAGES, GFP_KERNEL);
        if (!tp->freemem_pages)
@@ -717,13 +707,13 @@ tty3270_alloc_view(void)
                                  tp->freemem_pages[pages], PAGE_SIZE);
        }
        tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
-       if (!tp->write)
+       if (IS_ERR(tp->write))
                goto out_pages;
        tp->read = raw3270_request_alloc(0);
-       if (!tp->read)
+       if (IS_ERR(tp->read))
                goto out_write;
        tp->kreset = raw3270_request_alloc(1);
-       if (!tp->kreset)
+       if (IS_ERR(tp->kreset))
                goto out_read;
        tp->kbd = kbd_alloc();
        if (!tp->kbd)
@@ -774,16 +764,14 @@ tty3270_alloc_screen(struct tty3270 *tp)
        int lines;
 
        size = sizeof(struct tty3270_line) * (tp->view.rows - 2);
-       tp->screen = kmalloc(size, GFP_KERNEL);
+       tp->screen = kzalloc(size, GFP_KERNEL);
        if (!tp->screen)
                goto out_err;
-       memset(tp->screen, 0, size);
        for (lines = 0; lines < tp->view.rows - 2; lines++) {
                size = sizeof(struct tty3270_cell) * tp->view.cols;
-               tp->screen[lines].cells = kmalloc(size, GFP_KERNEL);
+               tp->screen[lines].cells = kzalloc(size, GFP_KERNEL);
                if (!tp->screen[lines].cells)
                        goto out_screen;
-               memset(tp->screen[lines].cells, 0, size);
        }
        return 0;
 out_screen:
@@ -819,8 +807,8 @@ tty3270_release(struct raw3270_view *view)
        tp = (struct tty3270 *) view;
        tty = tp->tty;
        if (tty) {
-               tty->driver_data = 0;
-               tp->tty = tp->kbd->tty = 0;
+               tty->driver_data = NULL;
+               tp->tty = tp->kbd->tty = NULL;
                tty_hangup(tty);
                raw3270_put_view(&tp->view);
        }
@@ -836,6 +824,23 @@ tty3270_free(struct raw3270_view *view)
        tty3270_free_view((struct tty3270 *) view);
 }
 
+/*
+ * Delayed freeing of tty3270 views.
+ */
+static void
+tty3270_del_views(void)
+{
+       struct tty3270 *tp;
+       int i;
+
+       for (i = 0; i < tty3270_max_index; i++) {
+               tp = (struct tty3270 *)
+                       raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
+               if (!IS_ERR(tp))
+                       raw3270_del_view(&tp->view);
+       }
+}
+
 struct raw3270_fn tty3270_fn = {
        .activate = tty3270_activate,
        .deactivate = tty3270_deactivate,
@@ -856,7 +861,9 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
        if (tty->count > 1)
                return 0;
        /* Check if the tty3270 is already there. */
-       tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, tty->index);
+       tp = (struct tty3270 *)
+               raw3270_find_view(&tty3270_fn,
+                                 tty->index + RAW3270_FIRSTMINOR);
        if (!IS_ERR(tp)) {
                tty->driver_data = tp;
                tty->winsize.ws_row = tp->view.rows - 2;
@@ -867,6 +874,12 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
                tp->inattr = TF_INPUT;
                return 0;
        }
+       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(tp) == -ENODEV)
+               return -ENODEV;
 
        /* Allocate tty3270 structure on first open. */
        tp = tty3270_alloc_view();
@@ -882,7 +895,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
                     (void (*)(unsigned long)) tty3270_read_tasklet,
                     (unsigned long) tp->read);
 
-       rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index);
+       rc = raw3270_add_view(&tp->view, &tty3270_fn,
+                             tty->index + RAW3270_FIRSTMINOR);
        if (rc) {
                tty3270_free_view(tp);
                return rc;
@@ -890,8 +904,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 
        rc = tty3270_alloc_screen(tp);
        if (rc) {
-               raw3270_del_view(&tp->view);
                raw3270_put_view(&tp->view);
+               raw3270_del_view(&tp->view);
                return rc;
        }
 
@@ -933,8 +947,8 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
                return;
        tp = (struct tty3270 *) tty->driver_data;
        if (tp) {
-               tty->driver_data = 0;
-               tp->tty = tp->kbd->tty = 0;
+               tty->driver_data = NULL;
+               tp->tty = tp->kbd->tty = NULL;
                raw3270_put_view(&tp->view);
        }
 }
@@ -1576,11 +1590,10 @@ tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
  * String write routine for 3270 ttys
  */
 static int
-tty3270_write(struct tty_struct * tty, int from_user,
+tty3270_write(struct tty_struct * tty,
              const unsigned char *buf, int count)
 {
        struct tty3270 *tp;
-       int length, ret;
 
        tp = tty->driver_data;
        if (!tp)
@@ -1589,26 +1602,8 @@ tty3270_write(struct tty_struct * tty, int from_user,
                tty3270_do_write(tp, tp->char_buf, tp->char_count);
                tp->char_count = 0;
        }
-       if (!from_user) {
-               tty3270_do_write(tp, buf, count);
-               return count;
-       }
-       ret = 0;
-       while (count > 0) {
-               length = count < TTY3270_CHAR_BUF_SIZE ?
-                       count : TTY3270_CHAR_BUF_SIZE;
-               length -= copy_from_user(tp->char_buf, buf, length);
-               if (length == 0) {
-                       if (!ret)
-                               ret = -EFAULT;
-                       break;
-               }
-               tty3270_do_write(tp, tp->char_buf, count);
-               buf += length;
-               count -= length;
-               ret += length;
-       }
-       return ret;
+       tty3270_do_write(tp, buf, count);
+       return count;
 }
 
 /*
@@ -1664,7 +1659,7 @@ tty3270_flush_buffer(struct tty_struct *tty)
  * Check for visible/invisible input switches
  */
 static void
-tty3270_set_termios(struct tty_struct *tty, struct termios *old)
+tty3270_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
        struct tty3270 *tp;
        int new;
@@ -1677,7 +1672,7 @@ tty3270_set_termios(struct tty_struct *tty, struct termios *old)
                new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
                if (new != tp->inattr) {
                        tp->inattr = new;
-                       tty3270_update_prompt(tp, 0, 0);
+                       tty3270_update_prompt(tp, NULL, 0);
                        tty3270_set_timer(tp, 1);
                }
        }
@@ -1742,7 +1737,7 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file,
        return kbd_ioctl(tp->kbd, file, cmd, arg);
 }
 
-static struct tty_operations tty3270_ops = {
+static const struct tty_operations tty3270_ops = {
        .open = tty3270_open,
        .close = tty3270_close,
        .write = tty3270_write,
@@ -1763,7 +1758,7 @@ void
 tty3270_notifier(int index, int active)
 {
        if (active)
-               tty_register_device(tty3270_driver, index, 0);
+               tty_register_device(tty3270_driver, index, NULL);
        else
                tty_unregister_device(tty3270_driver, index);
 }
@@ -1778,10 +1773,7 @@ tty3270_init(void)
        struct tty_driver *driver;
        int ret;
 
-       ret = raw3270_init();
-       if (ret)
-               return ret;
-       driver = alloc_tty_driver(256);
+       driver = alloc_tty_driver(RAW3270_MAXDEVS);
        if (!driver)
                return -ENOMEM;
 
@@ -1791,14 +1783,14 @@ tty3270_init(void)
         * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
         */
        driver->owner = THIS_MODULE;
-       driver->devfs_name = "ttyTUB/";
        driver->driver_name = "ttyTUB";
        driver->name = "ttyTUB";
        driver->major = IBM_TTY3270_MAJOR;
+       driver->minor_start = RAW3270_FIRSTMINOR;
        driver->type = TTY_DRIVER_TYPE_SYSTEM;
        driver->subtype = SYSTEM_TYPE_TTY;
        driver->init_termios = tty_std_termios;
-       driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
+       driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(driver, &tty3270_ops);
        ret = tty_register_driver(driver);
        if (ret) {
@@ -1807,6 +1799,14 @@ tty3270_init(void)
                return ret;
        }
        tty3270_driver = driver;
+       ret = raw3270_register_notifier(tty3270_notifier);
+       if (ret) {
+               printk(KERN_ERR "tty3270 notifier registration failed "
+                      "with %d\n", ret);
+               put_tty_driver(driver);
+               return ret;
+
+       }
        return 0;
 }
 
@@ -1815,10 +1815,11 @@ tty3270_exit(void)
 {
        struct tty_driver *driver;
 
+       raw3270_unregister_notifier(tty3270_notifier);
        driver = tty3270_driver;
-       tty3270_driver = 0;
+       tty3270_driver = NULL;
        tty_unregister_driver(driver);
-       raw3270_exit();
+       tty3270_del_views();
 }
 
 MODULE_LICENSE("GPL");