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