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 int
 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        return RAW3270_IO_DONE;
 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        if (rc) {
 468                fs3270_free_view(&fp->view);
 469                goto out;
 470        }
 471
 472        /* Allocate idal-buffer. */
 473        ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
 474        if (IS_ERR(ib)) {
 475                raw3270_put_view(&fp->view);
 476                raw3270_del_view(&fp->view);
 477                rc = PTR_ERR(ib);
 478                goto out;
 479        }
 480        fp->rdbuf = ib;
 481
 482        rc = raw3270_activate_view(&fp->view);
 483        if (rc) {
 484                raw3270_put_view(&fp->view);
 485                raw3270_del_view(&fp->view);
 486                goto out;
 487        }
 488        nonseekable_open(inode, filp);
 489        filp->private_data = fp;
 490out:
 491        mutex_unlock(&fs3270_mutex);
 492        return rc;
 493}
 494
 495/*
 496 * This routine is called when the 3270 tty is closed. We wait
 497 * for the remaining request to be completed. Then we clean up.
 498 */
 499static int
 500fs3270_close(struct inode *inode, struct file *filp)
 501{
 502        struct fs3270 *fp;
 503
 504        fp = filp->private_data;
 505        filp->private_data = NULL;
 506        if (fp) {
 507                put_pid(fp->fs_pid);
 508                fp->fs_pid = NULL;
 509                raw3270_reset(&fp->view);
 510                raw3270_put_view(&fp->view);
 511                raw3270_del_view(&fp->view);
 512        }
 513        return 0;
 514}
 515
 516static const struct file_operations fs3270_fops = {
 517        .owner           = THIS_MODULE,         /* owner */
 518        .read            = fs3270_read,         /* read */
 519        .write           = fs3270_write,        /* write */
 520        .unlocked_ioctl  = fs3270_ioctl,        /* ioctl */
 521        .compat_ioctl    = fs3270_ioctl,        /* ioctl */
 522        .open            = fs3270_open,         /* open */
 523        .release         = fs3270_close,        /* release */
 524        .llseek         = no_llseek,
 525};
 526
 527static void fs3270_create_cb(int minor)
 528{
 529        __register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops);
 530        device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
 531                      NULL, "3270/tub%d", minor);
 532}
 533
 534static void fs3270_destroy_cb(int minor)
 535{
 536        device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor));
 537        __unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
 538}
 539
 540static struct raw3270_notifier fs3270_notifier =
 541{
 542        .create = fs3270_create_cb,
 543        .destroy = fs3270_destroy_cb,
 544};
 545
 546/*
 547 * 3270 fullscreen driver initialization.
 548 */
 549static int __init
 550fs3270_init(void)
 551{
 552        int rc;
 553
 554        rc = __register_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270", &fs3270_fops);
 555        if (rc)
 556                return rc;
 557        device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0),
 558                      NULL, "3270/tub");
 559        raw3270_register_notifier(&fs3270_notifier);
 560        return 0;
 561}
 562
 563static void __exit
 564fs3270_exit(void)
 565{
 566        raw3270_unregister_notifier(&fs3270_notifier);
 567        device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, 0));
 568        __unregister_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270");
 569}
 570
 571MODULE_LICENSE("GPL");
 572MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);
 573
 574module_init(fs3270_init);
 575module_exit(fs3270_exit);
 576