linux/drivers/s390/char/fs3270.c
<<
>>
Prefs
   1/*
   2 * IBM/3270 Driver - fullscreen driver.
   3 *
   4 * Author(s):
   5 *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
   6 *   Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
   7 *     Copyright IBM Corp. 2003, 2009
   8 */
   9
  10#include <linux/bootmem.h>
  11#include <linux/console.h>
  12#include <linux/init.h>
  13#include <linux/interrupt.h>
  14#include <linux/compat.h>
  15#include <linux/module.h>
  16#include <linux/list.h>
  17#include <linux/slab.h>
  18#include <linux/types.h>
  19
  20#include <asm/compat.h>
  21#include <asm/ccwdev.h>
  22#include <asm/cio.h>
  23#include <asm/ebcdic.h>
  24#include <asm/idals.h>
  25
  26#include "raw3270.h"
  27#include "ctrlchar.h"
  28
  29static struct raw3270_fn fs3270_fn;
  30
  31struct fs3270 {
  32        struct raw3270_view view;
  33        struct pid *fs_pid;             /* Pid of controlling program. */
  34        int read_command;               /* ccw command to use for reads. */
  35        int write_command;              /* ccw command to use for writes. */
  36        int attention;                  /* Got attention. */
  37        int active;                     /* Fullscreen view is active. */
  38        struct raw3270_request *init;   /* single init request. */
  39        wait_queue_head_t wait;         /* Init & attention wait queue. */
  40        struct idal_buffer *rdbuf;      /* full-screen-deactivate buffer */
  41        size_t rdbuf_size;              /* size of data returned by RDBUF */
  42};
  43
  44static DEFINE_MUTEX(fs3270_mutex);
  45
  46static void
  47fs3270_wake_up(struct raw3270_request *rq, void *data)
  48{
  49        wake_up((wait_queue_head_t *) data);
  50}
  51
  52static inline int
  53fs3270_working(struct fs3270 *fp)
  54{
  55        /*
  56         * The fullscreen view is in working order if the view
  57         * has been activated AND the initial request is finished.
  58         */
  59        return fp->active && raw3270_request_final(fp->init);
  60}
  61
  62static int
  63fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
  64{
  65        struct fs3270 *fp;
  66        int rc;
  67
  68        fp = (struct fs3270 *) view;
  69        rq->callback = fs3270_wake_up;
  70        rq->callback_data = &fp->wait;
  71
  72        do {
  73                if (!fs3270_working(fp)) {
  74                        /* Fullscreen view isn't ready yet. */
  75                        rc = wait_event_interruptible(fp->wait,
  76                                                      fs3270_working(fp));
  77                        if (rc != 0)
  78                                break;
  79                }
  80                rc = raw3270_start(view, rq);
  81                if (rc == 0) {
  82                        /* Started successfully. Now wait for completion. */
  83                        wait_event(fp->wait, raw3270_request_final(rq));
  84                }
  85        } while (rc == -EACCES);
  86        return rc;
  87}
  88
  89/*
  90 * Switch to the fullscreen view.
  91 */
  92static void
  93fs3270_reset_callback(struct raw3270_request *rq, void *data)
  94{
  95        struct fs3270 *fp;
  96
  97        fp = (struct fs3270 *) rq->view;
  98        raw3270_request_reset(rq);
  99        wake_up(&fp->wait);
 100}
 101
 102static void
 103fs3270_restore_callback(struct raw3270_request *rq, void *data)
 104{
 105        struct fs3270 *fp;
 106
 107        fp = (struct fs3270 *) rq->view;
 108        if (rq->rc != 0 || rq->rescnt != 0) {
 109                if (fp->fs_pid)
 110                        kill_pid(fp->fs_pid, SIGHUP, 1);
 111        }
 112        fp->rdbuf_size = 0;
 113        raw3270_request_reset(rq);
 114        wake_up(&fp->wait);
 115}
 116
 117static int
 118fs3270_activate(struct raw3270_view *view)
 119{
 120        struct fs3270 *fp;
 121        char *cp;
 122        int rc;
 123
 124        fp = (struct fs3270 *) view;
 125
 126        /* If an old init command is still running just return. */
 127        if (!raw3270_request_final(fp->init))
 128                return 0;
 129
 130        if (fp->rdbuf_size == 0) {
 131                /* No saved buffer. Just clear the screen. */
 132                raw3270_request_set_cmd(fp->init, TC_EWRITEA);
 133                fp->init->callback = fs3270_reset_callback;
 134        } else {
 135                /* Restore fullscreen buffer saved by fs3270_deactivate. */
 136                raw3270_request_set_cmd(fp->init, TC_EWRITEA);
 137                raw3270_request_set_idal(fp->init, fp->rdbuf);
 138                fp->init->ccw.count = fp->rdbuf_size;
 139                cp = fp->rdbuf->data[0];
 140                cp[0] = TW_KR;
 141                cp[1] = TO_SBA;
 142                cp[2] = cp[6];
 143                cp[3] = cp[7];
 144                cp[4] = TO_IC;
 145                cp[5] = TO_SBA;
 146                cp[6] = 0x40;
 147                cp[7] = 0x40;
 148                fp->init->rescnt = 0;
 149                fp->init->callback = fs3270_restore_callback;
 150        }
 151        rc = fp->init->rc = raw3270_start_locked(view, fp->init);
 152        if (rc)
 153                fp->init->callback(fp->init, NULL);
 154        else
 155                fp->active = 1;
 156        return rc;
 157}
 158
 159/*
 160 * Shutdown fullscreen view.
 161 */
 162static void
 163fs3270_save_callback(struct raw3270_request *rq, void *data)
 164{
 165        struct fs3270 *fp;
 166
 167        fp = (struct fs3270 *) rq->view;
 168
 169        /* Correct idal buffer element 0 address. */
 170        fp->rdbuf->data[0] -= 5;
 171        fp->rdbuf->size += 5;
 172
 173        /*
 174         * If the rdbuf command failed or the idal buffer is
 175         * to small for the amount of data returned by the
 176         * rdbuf command, then we have no choice but to send
 177         * a SIGHUP to the application.
 178         */
 179        if (rq->rc != 0 || rq->rescnt == 0) {
 180                if (fp->fs_pid)
 181                        kill_pid(fp->fs_pid, SIGHUP, 1);
 182                fp->rdbuf_size = 0;
 183        } else
 184                fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
 185        raw3270_request_reset(rq);
 186        wake_up(&fp->wait);
 187}
 188
 189static void
 190fs3270_deactivate(struct raw3270_view *view)
 191{
 192        struct fs3270 *fp;
 193
 194        fp = (struct fs3270 *) view;
 195        fp->active = 0;
 196
 197        /* If an old init command is still running just return. */
 198        if (!raw3270_request_final(fp->init))
 199                return;
 200
 201        /* Prepare read-buffer request. */
 202        raw3270_request_set_cmd(fp->init, TC_RDBUF);
 203        /*
 204         * Hackish: skip first 5 bytes of the idal buffer to make
 205         * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence
 206         * in the activation command.
 207         */
 208        fp->rdbuf->data[0] += 5;
 209        fp->rdbuf->size -= 5;
 210        raw3270_request_set_idal(fp->init, fp->rdbuf);
 211        fp->init->rescnt = 0;
 212        fp->init->callback = fs3270_save_callback;
 213
 214        /* Start I/O to read in the 3270 buffer. */
 215        fp->init->rc = raw3270_start_locked(view, fp->init);
 216        if (fp->init->rc)
 217                fp->init->callback(fp->init, NULL);
 218}
 219
 220static void
 221fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
 222{
 223        /* Handle ATTN. Set indication and wake waiters for attention. */
 224        if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
 225                fp->attention = 1;
 226                wake_up(&fp->wait);
 227        }
 228
 229        if (rq) {
 230                if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
 231                        rq->rc = -EIO;
 232                else
 233                        /* Normal end. Copy residual count. */
 234                        rq->rescnt = irb->scsw.cmd.count;
 235        }
 236}
 237
 238/*
 239 * Process reads from fullscreen 3270.
 240 */
 241static ssize_t
 242fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
 243{
 244        struct fs3270 *fp;
 245        struct raw3270_request *rq;
 246        struct idal_buffer *ib;
 247        ssize_t rc;
 248        
 249        if (count == 0 || count > 65535)
 250                return -EINVAL;
 251        fp = filp->private_data;
 252        if (!fp)
 253                return -ENODEV;
 254        ib = idal_buffer_alloc(count, 0);
 255        if (IS_ERR(ib))
 256                return -ENOMEM;
 257        rq = raw3270_request_alloc(0);
 258        if (!IS_ERR(rq)) {
 259                if (fp->read_command == 0 && fp->write_command != 0)
 260                        fp->read_command = 6;
 261                raw3270_request_set_cmd(rq, fp->read_command ? : 2);
 262                raw3270_request_set_idal(rq, ib);
 263                rc = wait_event_interruptible(fp->wait, fp->attention);
 264                fp->attention = 0;
 265                if (rc == 0) {
 266                        rc = fs3270_do_io(&fp->view, rq);
 267                        if (rc == 0) {
 268                                count -= rq->rescnt;
 269                                if (idal_buffer_to_user(ib, data, count) != 0)
 270                                        rc = -EFAULT;
 271                                else
 272                                        rc = count;
 273
 274                        }
 275                }
 276                raw3270_request_free(rq);
 277        } else
 278                rc = PTR_ERR(rq);
 279        idal_buffer_free(ib);
 280        return rc;
 281}
 282
 283/*
 284 * Process writes to fullscreen 3270.
 285 */
 286static ssize_t
 287fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
 288{
 289        struct fs3270 *fp;
 290        struct raw3270_request *rq;
 291        struct idal_buffer *ib;
 292        int write_command;
 293        ssize_t rc;
 294
 295        fp = filp->private_data;
 296        if (!fp)
 297                return -ENODEV;
 298        ib = idal_buffer_alloc(count, 0);
 299        if (IS_ERR(ib))
 300                return -ENOMEM;
 301        rq = raw3270_request_alloc(0);
 302        if (!IS_ERR(rq)) {
 303                if (idal_buffer_from_user(ib, data, count) == 0) {
 304                        write_command = fp->write_command ? : 1;
 305                        if (write_command == 5)
 306                                write_command = 13;
 307                        raw3270_request_set_cmd(rq, write_command);
 308                        raw3270_request_set_idal(rq, ib);
 309                        rc = fs3270_do_io(&fp->view, rq);
 310                        if (rc == 0)
 311                                rc = count - rq->rescnt;
 312                } else
 313                        rc = -EFAULT;
 314                raw3270_request_free(rq);
 315        } else
 316                rc = PTR_ERR(rq);
 317        idal_buffer_free(ib);
 318        return rc;
 319}
 320
 321/*
 322 * process ioctl commands for the tube driver
 323 */
 324static long
 325fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 326{
 327        char __user *argp;
 328        struct fs3270 *fp;
 329        struct raw3270_iocb iocb;
 330        int rc;
 331
 332        fp = filp->private_data;
 333        if (!fp)
 334                return -ENODEV;
 335        if (is_compat_task())
 336                argp = compat_ptr(arg);
 337        else
 338                argp = (char __user *)arg;
 339        rc = 0;
 340        mutex_lock(&fs3270_mutex);
 341        switch (cmd) {
 342        case TUBICMD:
 343                fp->read_command = arg;
 344                break;
 345        case TUBOCMD:
 346                fp->write_command = arg;
 347                break;
 348        case TUBGETI:
 349                rc = put_user(fp->read_command, argp);
 350                break;
 351        case TUBGETO:
 352                rc = put_user(fp->write_command, argp);
 353                break;
 354        case TUBGETMOD:
 355                iocb.model = fp->view.model;
 356                iocb.line_cnt = fp->view.rows;
 357                iocb.col_cnt = fp->view.cols;
 358                iocb.pf_cnt = 24;
 359                iocb.re_cnt = 20;
 360                iocb.map = 0;
 361                if (copy_to_user(argp, &iocb, sizeof(struct raw3270_iocb)))
 362                        rc = -EFAULT;
 363                break;
 364        }
 365        mutex_unlock(&fs3270_mutex);
 366        return rc;
 367}
 368
 369/*
 370 * Allocate fs3270 structure.
 371 */
 372static struct fs3270 *
 373fs3270_alloc_view(void)
 374{
 375        struct fs3270 *fp;
 376
 377        fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL);
 378        if (!fp)
 379                return ERR_PTR(-ENOMEM);
 380        fp->init = raw3270_request_alloc(0);
 381        if (IS_ERR(fp->init)) {
 382                kfree(fp);
 383                return ERR_PTR(-ENOMEM);
 384        }
 385        return fp;
 386}
 387
 388/*
 389 * Free fs3270 structure.
 390 */
 391static void
 392fs3270_free_view(struct raw3270_view *view)
 393{
 394        struct fs3270 *fp;
 395
 396        fp = (struct fs3270 *) view;
 397        if (fp->rdbuf)
 398                idal_buffer_free(fp->rdbuf);
 399        raw3270_request_free(((struct fs3270 *) view)->init);
 400        kfree(view);
 401}
 402
 403/*
 404 * Unlink fs3270 data structure from filp.
 405 */
 406static void
 407fs3270_release(struct raw3270_view *view)
 408{
 409        struct fs3270 *fp;
 410
 411        fp = (struct fs3270 *) view;
 412        if (fp->fs_pid)
 413                kill_pid(fp->fs_pid, SIGHUP, 1);
 414}
 415
 416/* View to a 3270 device. Can be console, tty or fullscreen. */
 417static struct raw3270_fn fs3270_fn = {
 418        .activate = fs3270_activate,
 419        .deactivate = fs3270_deactivate,
 420        .intv = (void *) fs3270_irq,
 421        .release = fs3270_release,
 422        .free = fs3270_free_view
 423};
 424
 425/*
 426 * This routine is called whenever a 3270 fullscreen device is opened.
 427 */
 428static int
 429fs3270_open(struct inode *inode, struct file *filp)
 430{
 431        struct fs3270 *fp;
 432        struct idal_buffer *ib;
 433        int minor, rc = 0;
 434
 435        if (imajor(file_inode(filp)) != IBM_FS3270_MAJOR)
 436                return -ENODEV;
 437        minor = iminor(file_inode(filp));
 438        /* Check for minor 0 multiplexer. */
 439        if (minor == 0) {
 440                struct tty_struct *tty = get_current_tty();
 441                if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
 442                        tty_kref_put(tty);
 443                        return -ENODEV;
 444                }
 445                minor = tty->index;
 446                tty_kref_put(tty);
 447        }
 448        mutex_lock(&fs3270_mutex);
 449        /* Check if some other program is already using fullscreen mode. */
 450        fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
 451        if (!IS_ERR(fp)) {
 452                raw3270_put_view(&fp->view);
 453                rc = -EBUSY;
 454                goto out;
 455        }
 456        /* Allocate fullscreen view structure. */
 457        fp = fs3270_alloc_view();
 458        if (IS_ERR(fp)) {
 459                rc = PTR_ERR(fp);
 460                goto out;
 461        }
 462
 463        init_waitqueue_head(&fp->wait);
 464        fp->fs_pid = get_pid(task_pid(current));
 465        rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
 466        if (rc) {
 467                fs3270_free_view(&fp->view);
 468                goto out;
 469        }
 470
 471        /* Allocate idal-buffer. */
 472        ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
 473        if (IS_ERR(ib)) {
 474                raw3270_put_view(&fp->view);
 475                raw3270_del_view(&fp->view);
 476                rc = PTR_ERR(ib);
 477                goto out;
 478        }
 479        fp->rdbuf = ib;
 480
 481        rc = raw3270_activate_view(&fp->view);
 482        if (rc) {
 483                raw3270_put_view(&fp->view);
 484                raw3270_del_view(&fp->view);
 485                goto out;
 486        }
 487        nonseekable_open(inode, filp);
 488        filp->private_data = fp;
 489out:
 490        mutex_unlock(&fs3270_mutex);
 491        return rc;
 492}
 493
 494/*
 495 * This routine is called when the 3270 tty is closed. We wait
 496 * for the remaining request to be completed. Then we clean up.
 497 */
 498static int
 499fs3270_close(struct inode *inode, struct file *filp)
 500{
 501        struct fs3270 *fp;
 502
 503        fp = filp->private_data;
 504        filp->private_data = NULL;
 505        if (fp) {
 506                put_pid(fp->fs_pid);
 507                fp->fs_pid = NULL;
 508                raw3270_reset(&fp->view);
 509                raw3270_put_view(&fp->view);
 510                raw3270_del_view(&fp->view);
 511        }
 512        return 0;
 513}
 514
 515static const struct file_operations fs3270_fops = {
 516        .owner           = THIS_MODULE,         /* owner */
 517        .read            = fs3270_read,         /* read */
 518        .write           = fs3270_write,        /* write */
 519        .unlocked_ioctl  = fs3270_ioctl,        /* ioctl */
 520        .compat_ioctl    = fs3270_ioctl,        /* ioctl */
 521        .open            = fs3270_open,         /* open */
 522        .release         = fs3270_close,        /* release */
 523        .llseek         = no_llseek,
 524};
 525
 526static void fs3270_create_cb(int minor)
 527{
 528        __register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops);
 529        device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
 530                      NULL, "3270/tub%d", minor);
 531}
 532
 533static void fs3270_destroy_cb(int minor)
 534{
 535        device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor));
 536        __unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
 537}
 538
 539static struct raw3270_notifier fs3270_notifier =
 540{
 541        .create = fs3270_create_cb,
 542        .destroy = fs3270_destroy_cb,
 543};
 544
 545/*
 546 * 3270 fullscreen driver initialization.
 547 */
 548static int __init
 549fs3270_init(void)
 550{
 551        int rc;
 552
 553        rc = __register_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270", &fs3270_fops);
 554        if (rc)
 555                return rc;
 556        device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0),
 557                      NULL, "3270/tub");
 558        raw3270_register_notifier(&fs3270_notifier);
 559        return 0;
 560}
 561
 562static void __exit
 563fs3270_exit(void)
 564{
 565        raw3270_unregister_notifier(&fs3270_notifier);
 566        device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, 0));
 567        __unregister_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270");
 568}
 569
 570MODULE_LICENSE("GPL");
 571MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);
 572
 573module_init(fs3270_init);
 574module_exit(fs3270_exit);
 575