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/memblock.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/ccwdev.h>
  23#include <asm/cio.h>
  24#include <asm/ebcdic.h>
  25#include <asm/idals.h>
  26
  27#include "raw3270.h"
  28#include "ctrlchar.h"
  29
  30static struct raw3270_fn fs3270_fn;
  31
  32struct fs3270 {
  33        struct raw3270_view view;
  34        struct pid *fs_pid;             /* Pid of controlling program. */
  35        int read_command;               /* ccw command to use for reads. */
  36        int write_command;              /* ccw command to use for writes. */
  37        int attention;                  /* Got attention. */
  38        int active;                     /* Fullscreen view is active. */
  39        struct raw3270_request *init;   /* single init request. */
  40        wait_queue_head_t wait;         /* Init & attention wait queue. */
  41        struct idal_buffer *rdbuf;      /* full-screen-deactivate buffer */
  42        size_t rdbuf_size;              /* size of data returned by RDBUF */
  43};
  44
  45static DEFINE_MUTEX(fs3270_mutex);
  46
  47static void
  48fs3270_wake_up(struct raw3270_request *rq, void *data)
  49{
  50        wake_up((wait_queue_head_t *) data);
  51}
  52
  53static inline int
  54fs3270_working(struct fs3270 *fp)
  55{
  56        /*
  57         * The fullscreen view is in working order if the view
  58         * has been activated AND the initial request is finished.
  59         */
  60        return fp->active && raw3270_request_final(fp->init);
  61}
  62
  63static int
  64fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
  65{
  66        struct fs3270 *fp;
  67        int rc;
  68
  69        fp = (struct fs3270 *) view;
  70        rq->callback = fs3270_wake_up;
  71        rq->callback_data = &fp->wait;
  72
  73        do {
  74                if (!fs3270_working(fp)) {
  75                        /* Fullscreen view isn't ready yet. */
  76                        rc = wait_event_interruptible(fp->wait,
  77                                                      fs3270_working(fp));
  78                        if (rc != 0)
  79                                break;
  80                }
  81                rc = raw3270_start(view, rq);
  82                if (rc == 0) {
  83                        /* Started successfully. Now wait for completion. */
  84                        wait_event(fp->wait, raw3270_request_final(rq));
  85                }
  86        } while (rc == -EACCES);
  87        return rc;
  88}
  89
  90/*
  91 * Switch to the fullscreen view.
  92 */
  93static void
  94fs3270_reset_callback(struct raw3270_request *rq, void *data)
  95{
  96        struct fs3270 *fp;
  97
  98        fp = (struct fs3270 *) rq->view;
  99        raw3270_request_reset(rq);
 100        wake_up(&fp->wait);
 101}
 102
 103static void
 104fs3270_restore_callback(struct raw3270_request *rq, void *data)
 105{
 106        struct fs3270 *fp;
 107
 108        fp = (struct fs3270 *) rq->view;
 109        if (rq->rc != 0 || rq->rescnt != 0) {
 110                if (fp->fs_pid)
 111                        kill_pid(fp->fs_pid, SIGHUP, 1);
 112        }
 113        fp->rdbuf_size = 0;
 114        raw3270_request_reset(rq);
 115        wake_up(&fp->wait);
 116}
 117
 118static int
 119fs3270_activate(struct raw3270_view *view)
 120{
 121        struct fs3270 *fp;
 122        char *cp;
 123        int rc;
 124
 125        fp = (struct fs3270 *) view;
 126
 127        /* If an old init command is still running just return. */
 128        if (!raw3270_request_final(fp->init))
 129                return 0;
 130
 131        if (fp->rdbuf_size == 0) {
 132                /* No saved buffer. Just clear the screen. */
 133                raw3270_request_set_cmd(fp->init, TC_EWRITEA);
 134                fp->init->callback = fs3270_reset_callback;
 135        } else {
 136                /* Restore fullscreen buffer saved by fs3270_deactivate. */
 137                raw3270_request_set_cmd(fp->init, TC_EWRITEA);
 138                raw3270_request_set_idal(fp->init, fp->rdbuf);
 139                fp->init->ccw.count = fp->rdbuf_size;
 140                cp = fp->rdbuf->data[0];
 141                cp[0] = TW_KR;
 142                cp[1] = TO_SBA;
 143                cp[2] = cp[6];
 144                cp[3] = cp[7];
 145                cp[4] = TO_IC;
 146                cp[5] = TO_SBA;
 147                cp[6] = 0x40;
 148                cp[7] = 0x40;
 149                fp->init->rescnt = 0;
 150                fp->init->callback = fs3270_restore_callback;
 151        }
 152        rc = fp->init->rc = raw3270_start_locked(view, fp->init);
 153        if (rc)
 154                fp->init->callback(fp->init, NULL);
 155        else
 156                fp->active = 1;
 157        return rc;
 158}
 159
 160/*
 161 * Shutdown fullscreen view.
 162 */
 163static void
 164fs3270_save_callback(struct raw3270_request *rq, void *data)
 165{
 166        struct fs3270 *fp;
 167
 168        fp = (struct fs3270 *) rq->view;
 169
 170        /* Correct idal buffer element 0 address. */
 171        fp->rdbuf->data[0] -= 5;
 172        fp->rdbuf->size += 5;
 173
 174        /*
 175         * If the rdbuf command failed or the idal buffer is
 176         * to small for the amount of data returned by the
 177         * rdbuf command, then we have no choice but to send
 178         * a SIGHUP to the application.
 179         */
 180        if (rq->rc != 0 || rq->rescnt == 0) {
 181                if (fp->fs_pid)
 182                        kill_pid(fp->fs_pid, SIGHUP, 1);
 183                fp->rdbuf_size = 0;
 184        } else
 185                fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
 186        raw3270_request_reset(rq);
 187        wake_up(&fp->wait);
 188}
 189
 190static void
 191fs3270_deactivate(struct raw3270_view *view)
 192{
 193        struct fs3270 *fp;
 194
 195        fp = (struct fs3270 *) view;
 196        fp->active = 0;
 197
 198        /* If an old init command is still running just return. */
 199        if (!raw3270_request_final(fp->init))
 200                return;
 201
 202        /* Prepare read-buffer request. */
 203        raw3270_request_set_cmd(fp->init, TC_RDBUF);
 204        /*
 205         * Hackish: skip first 5 bytes of the idal buffer to make
 206         * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence
 207         * in the activation command.
 208         */
 209        fp->rdbuf->data[0] += 5;
 210        fp->rdbuf->size -= 5;
 211        raw3270_request_set_idal(fp->init, fp->rdbuf);
 212        fp->init->rescnt = 0;
 213        fp->init->callback = fs3270_save_callback;
 214
 215        /* Start I/O to read in the 3270 buffer. */
 216        fp->init->rc = raw3270_start_locked(view, fp->init);
 217        if (fp->init->rc)
 218                fp->init->callback(fp->init, NULL);
 219}
 220
 221static void
 222fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
 223{
 224        /* Handle ATTN. Set indication and wake waiters for attention. */
 225        if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
 226                fp->attention = 1;
 227                wake_up(&fp->wait);
 228        }
 229
 230        if (rq) {
 231                if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
 232                        rq->rc = -EIO;
 233                else
 234                        /* Normal end. Copy residual count. */
 235                        rq->rescnt = irb->scsw.cmd.count;
 236        }
 237}
 238
 239/*
 240 * Process reads from fullscreen 3270.
 241 */
 242static ssize_t
 243fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
 244{
 245        struct fs3270 *fp;
 246        struct raw3270_request *rq;
 247        struct idal_buffer *ib;
 248        ssize_t rc;
 249        
 250        if (count == 0 || count > 65535)
 251                return -EINVAL;
 252        fp = filp->private_data;
 253        if (!fp)
 254                return -ENODEV;
 255        ib = idal_buffer_alloc(count, 0);
 256        if (IS_ERR(ib))
 257                return -ENOMEM;
 258        rq = raw3270_request_alloc(0);
 259        if (!IS_ERR(rq)) {
 260                if (fp->read_command == 0 && fp->write_command != 0)
 261                        fp->read_command = 6;
 262                raw3270_request_set_cmd(rq, fp->read_command ? : 2);
 263                raw3270_request_set_idal(rq, ib);
 264                rc = wait_event_interruptible(fp->wait, fp->attention);
 265                fp->attention = 0;
 266                if (rc == 0) {
 267                        rc = fs3270_do_io(&fp->view, rq);
 268                        if (rc == 0) {
 269                                count -= rq->rescnt;
 270                                if (idal_buffer_to_user(ib, data, count) != 0)
 271                                        rc = -EFAULT;
 272                                else
 273                                        rc = count;
 274
 275                        }
 276                }
 277                raw3270_request_free(rq);
 278        } else
 279                rc = PTR_ERR(rq);
 280        idal_buffer_free(ib);
 281        return rc;
 282}
 283
 284/*
 285 * Process writes to fullscreen 3270.
 286 */
 287static ssize_t
 288fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
 289{
 290        struct fs3270 *fp;
 291        struct raw3270_request *rq;
 292        struct idal_buffer *ib;
 293        int write_command;
 294        ssize_t rc;
 295
 296        fp = filp->private_data;
 297        if (!fp)
 298                return -ENODEV;
 299        ib = idal_buffer_alloc(count, 0);
 300        if (IS_ERR(ib))
 301                return -ENOMEM;
 302        rq = raw3270_request_alloc(0);
 303        if (!IS_ERR(rq)) {
 304                if (idal_buffer_from_user(ib, data, count) == 0) {
 305                        write_command = fp->write_command ? : 1;
 306                        if (write_command == 5)
 307                                write_command = 13;
 308                        raw3270_request_set_cmd(rq, write_command);
 309                        raw3270_request_set_idal(rq, ib);
 310                        rc = fs3270_do_io(&fp->view, rq);
 311                        if (rc == 0)
 312                                rc = count - rq->rescnt;
 313                } else
 314                        rc = -EFAULT;
 315                raw3270_request_free(rq);
 316        } else
 317                rc = PTR_ERR(rq);
 318        idal_buffer_free(ib);
 319        return rc;
 320}
 321
 322/*
 323 * process ioctl commands for the tube driver
 324 */
 325static long
 326fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 327{
 328        char __user *argp;
 329        struct fs3270 *fp;
 330        struct raw3270_iocb iocb;
 331        int rc;
 332
 333        fp = filp->private_data;
 334        if (!fp)
 335                return -ENODEV;
 336        if (is_compat_task())
 337                argp = compat_ptr(arg);
 338        else
 339                argp = (char __user *)arg;
 340        rc = 0;
 341        mutex_lock(&fs3270_mutex);
 342        switch (cmd) {
 343        case TUBICMD:
 344                fp->read_command = arg;
 345                break;
 346        case TUBOCMD:
 347                fp->write_command = arg;
 348                break;
 349        case TUBGETI:
 350                rc = put_user(fp->read_command, argp);
 351                break;
 352        case TUBGETO:
 353                rc = put_user(fp->write_command, argp);
 354                break;
 355        case TUBGETMOD:
 356                iocb.model = fp->view.model;
 357                iocb.line_cnt = fp->view.rows;
 358                iocb.col_cnt = fp->view.cols;
 359                iocb.pf_cnt = 24;
 360                iocb.re_cnt = 20;
 361                iocb.map = 0;
 362                if (copy_to_user(argp, &iocb, sizeof(struct raw3270_iocb)))
 363                        rc = -EFAULT;
 364                break;
 365        }
 366        mutex_unlock(&fs3270_mutex);
 367        return rc;
 368}
 369
 370/*
 371 * Allocate fs3270 structure.
 372 */
 373static struct fs3270 *
 374fs3270_alloc_view(void)
 375{
 376        struct fs3270 *fp;
 377
 378        fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL);
 379        if (!fp)
 380                return ERR_PTR(-ENOMEM);
 381        fp->init = raw3270_request_alloc(0);
 382        if (IS_ERR(fp->init)) {
 383                kfree(fp);
 384                return ERR_PTR(-ENOMEM);
 385        }
 386        return fp;
 387}
 388
 389/*
 390 * Free fs3270 structure.
 391 */
 392static void
 393fs3270_free_view(struct raw3270_view *view)
 394{
 395        struct fs3270 *fp;
 396
 397        fp = (struct fs3270 *) view;
 398        if (fp->rdbuf)
 399                idal_buffer_free(fp->rdbuf);
 400        raw3270_request_free(((struct fs3270 *) view)->init);
 401        kfree(view);
 402}
 403
 404/*
 405 * Unlink fs3270 data structure from filp.
 406 */
 407static void
 408fs3270_release(struct raw3270_view *view)
 409{
 410        struct fs3270 *fp;
 411
 412        fp = (struct fs3270 *) view;
 413        if (fp->fs_pid)
 414                kill_pid(fp->fs_pid, SIGHUP, 1);
 415}
 416
 417/* View to a 3270 device. Can be console, tty or fullscreen. */
 418static struct raw3270_fn fs3270_fn = {
 419        .activate = fs3270_activate,
 420        .deactivate = fs3270_deactivate,
 421        .intv = (void *) fs3270_irq,
 422        .release = fs3270_release,
 423        .free = fs3270_free_view
 424};
 425
 426/*
 427 * This routine is called whenever a 3270 fullscreen device is opened.
 428 */
 429static int
 430fs3270_open(struct inode *inode, struct file *filp)
 431{
 432        struct fs3270 *fp;
 433        struct idal_buffer *ib;
 434        int minor, rc = 0;
 435
 436        if (imajor(file_inode(filp)) != IBM_FS3270_MAJOR)
 437                return -ENODEV;
 438        minor = iminor(file_inode(filp));
 439        /* Check for minor 0 multiplexer. */
 440        if (minor == 0) {
 441                struct tty_struct *tty = get_current_tty();
 442                if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
 443                        tty_kref_put(tty);
 444                        return -ENODEV;
 445                }
 446                minor = tty->index;
 447                tty_kref_put(tty);
 448        }
 449        mutex_lock(&fs3270_mutex);
 450        /* Check if some other program is already using fullscreen mode. */
 451        fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
 452        if (!IS_ERR(fp)) {
 453                raw3270_put_view(&fp->view);
 454                rc = -EBUSY;
 455                goto out;
 456        }
 457        /* Allocate fullscreen view structure. */
 458        fp = fs3270_alloc_view();
 459        if (IS_ERR(fp)) {
 460                rc = PTR_ERR(fp);
 461                goto out;
 462        }
 463
 464        init_waitqueue_head(&fp->wait);
 465        fp->fs_pid = get_pid(task_pid(current));
 466        rc = raw3270_add_view(&fp->view, &fs3270_fn, minor,
 467                              RAW3270_VIEW_LOCK_BH);
 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        stream_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