cregit-Linux how code gets into the kernel

Release 4.7 drivers/s390/char/fs3270.c

/*
 * IBM/3270 Driver - fullscreen driver.
 *
 * Author(s):
 *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
 *   Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
 *     Copyright IBM Corp. 2003, 2009
 */

#include <linux/bootmem.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/compat.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/types.h>

#include <asm/compat.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>

#include "raw3270.h"
#include "ctrlchar.h"


static struct raw3270_fn fs3270_fn;


struct fs3270 {
	
struct raw3270_view view;
	
struct pid *fs_pid;		/* Pid of controlling program. */
	
int read_command;		/* ccw command to use for reads. */
	
int write_command;		/* ccw command to use for writes. */
	
int attention;			/* Got attention. */
	
int active;			/* Fullscreen view is active. */
	
struct raw3270_request *init;	/* single init request. */
	
wait_queue_head_t wait;		/* Init & attention wait queue. */
	
struct idal_buffer *rdbuf;	/* full-screen-deactivate buffer */
	
size_t rdbuf_size;		/* size of data returned by RDBUF */
};

static DEFINE_MUTEX(fs3270_mutex);


static void fs3270_wake_up(struct raw3270_request *rq, void *data) { wake_up((wait_queue_head_t *) data); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton24100.00%1100.00%
Total24100.00%1100.00%


static inline int fs3270_working(struct fs3270 *fp) { /* * The fullscreen view is in working order if the view * has been activated AND the initial request is finished. */ return fp->active && raw3270_request_final(fp->init); }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt2496.00%150.00%
andrew mortonandrew morton14.00%150.00%
Total25100.00%2100.00%


static int fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq) { struct fs3270 *fp; int rc; fp = (struct fs3270 *) view; rq->callback = fs3270_wake_up; rq->callback_data = &fp->wait; do { if (!fs3270_working(fp)) { /* Fullscreen view isn't ready yet. */ rc = wait_event_interruptible(fp->wait, fs3270_working(fp)); if (rc != 0) break; } rc = raw3270_start(view, rq); if (rc == 0) { /* Started successfully. Now wait for completion. */ wait_event(fp->wait, raw3270_request_final(rq)); } } while (rc == -EACCES); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt6653.23%133.33%
andrew mortonandrew morton5745.97%133.33%
andre goddard rosaandre goddard rosa10.81%133.33%
Total124100.00%3100.00%

/* * Switch to the fullscreen view. */
static void fs3270_reset_callback(struct raw3270_request *rq, void *data) { struct fs3270 *fp; fp = (struct fs3270 *) rq->view; raw3270_request_reset(rq); wake_up(&fp->wait); }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt2556.82%150.00%
andrew mortonandrew morton1943.18%150.00%
Total44100.00%2100.00%


static void fs3270_restore_callback(struct raw3270_request *rq, void *data) { struct fs3270 *fp; fp = (struct fs3270 *) rq->view; if (rq->rc != 0 || rq->rescnt != 0) { if (fp->fs_pid) kill_pid(fp->fs_pid, SIGHUP, 1); } fp->rdbuf_size = 0; raw3270_request_reset(rq); wake_up(&fp->wait); }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt8197.59%133.33%
cedric le goatercedric le goater11.20%133.33%
andrew mortonandrew morton11.20%133.33%
Total83100.00%3100.00%


static int fs3270_activate(struct raw3270_view *view) { struct fs3270 *fp; char *cp; int rc; fp = (struct fs3270 *) view; /* If an old init command is still running just return. */ if (!raw3270_request_final(fp->init)) return 0; if (fp->rdbuf_size == 0) { /* No saved buffer. Just clear the screen. */ raw3270_request_set_cmd(fp->init, TC_EWRITEA); fp->init->callback = fs3270_reset_callback; } else { /* Restore fullscreen buffer saved by fs3270_deactivate. */ raw3270_request_set_cmd(fp->init, TC_EWRITEA); raw3270_request_set_idal(fp->init, fp->rdbuf); fp->init->ccw.count = fp->rdbuf_size; cp = fp->rdbuf->data[0]; cp[0] = TW_KR; cp[1] = TO_SBA; cp[2] = cp[6]; cp[3] = cp[7]; cp[4] = TO_IC; cp[5] = TO_SBA; cp[6] = 0x40; cp[7] = 0x40; fp->init->rescnt = 0; fp->init->callback = fs3270_restore_callback; } rc = fp->init->rc = raw3270_start_locked(view, fp->init); if (rc) fp->init->callback(fp->init, NULL); else fp->active = 1; return rc; }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt19680.66%150.00%
andrew mortonandrew morton4719.34%150.00%
Total243100.00%2100.00%

/* * Shutdown fullscreen view. */
static void fs3270_save_callback(struct raw3270_request *rq, void *data) { struct fs3270 *fp; fp = (struct fs3270 *) rq->view; /* Correct idal buffer element 0 address. */ fp->rdbuf->data[0] -= 5; fp->rdbuf->size += 5; /* * If the rdbuf command failed or the idal buffer is * to small for the amount of data returned by the * rdbuf command, then we have no choice but to send * a SIGHUP to the application. */ if (rq->rc != 0 || rq->rescnt == 0) { if (fp->fs_pid) kill_pid(fp->fs_pid, SIGHUP, 1); fp->rdbuf_size = 0; } else fp->rdbuf_size = fp->rdbuf->size - rq->rescnt; raw3270_request_reset(rq); wake_up(&fp->wait); }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt11697.48%133.33%
andrew mortonandrew morton21.68%133.33%
cedric le goatercedric le goater10.84%133.33%
Total119100.00%3100.00%


static void fs3270_deactivate(struct raw3270_view *view) { struct fs3270 *fp; fp = (struct fs3270 *) view; fp->active = 0; /* If an old init command is still running just return. */ if (!raw3270_request_final(fp->init)) return; /* Prepare read-buffer request. */ raw3270_request_set_cmd(fp->init, TC_RDBUF); /* * Hackish: skip first 5 bytes of the idal buffer to make * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence * in the activation command. */ fp->rdbuf->data[0] += 5; fp->rdbuf->size -= 5; raw3270_request_set_idal(fp->init, fp->rdbuf); fp->init->rescnt = 0; fp->init->callback = fs3270_save_callback; /* Start I/O to read in the 3270 buffer. */ fp->init->rc = raw3270_start_locked(view, fp->init); if (fp->init->rc) fp->init->callback(fp->init, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
richard hittrichard hitt10878.83%150.00%
andrew mortonandrew morton2921.17%150.00%
Total137100.00%2100.00%


static void fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Set indication and wake waiters for attention. */ if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { fp->attention = 1; wake_up(&fp->wait); } if (rq) { if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ rq->rescnt = irb->scsw.cmd.count; } }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton8191.01%125.00%
peter oberparleiterpeter oberparleiter66.74%125.00%
richard hittrichard hitt11.12%125.00%
martin schwidefskymartin schwidefsky11.12%125.00%
Total89100.00%4100.00%

/* * Process reads from fullscreen 3270. */
static ssize_t fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off) { struct fs3270 *fp; struct raw3270_request *rq; struct idal_buffer *ib; ssize_t rc; if (count == 0 || count > 65535) return -EINVAL; fp = filp->private_data; if (!fp) return -ENODEV; ib = idal_buffer_alloc(count, 0); if (IS_ERR(ib)) return -ENOMEM; rq = raw3270_request_alloc(0); if (!IS_ERR(rq)) { if (fp->read_command == 0 && fp->write_command != 0) fp->read_command = 6; raw3270_request_set_cmd(rq, fp->read_command ? : 2); raw3270_request_set_idal(rq, ib); rc = wait_event_interruptible(fp->wait, fp->attention); fp->attention = 0; if (rc == 0) { rc = fs3270_do_io(&fp->view, rq); if (rc == 0) { count -= rq->rescnt; if (idal_buffer_to_user(ib, data, count) != 0) rc = -EFAULT; else rc = count; } } raw3270_request_free(rq); } else rc = PTR_ERR(rq); idal_buffer_free(ib); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton20283.13%133.33%
richard hittrichard hitt4016.46%133.33%
heiko carstensheiko carstens10.41%133.33%
Total243100.00%3100.00%

/* * Process writes to fullscreen 3270. */
static ssize_t fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off) { struct fs3270 *fp; struct raw3270_request *rq; struct idal_buffer *ib; int write_command; ssize_t rc; fp = filp->private_data; if (!fp) return -ENODEV; ib = idal_buffer_alloc(count, 0); if (IS_ERR(ib)) return -ENOMEM; rq = raw3270_request_alloc(0); if (!IS_ERR(rq)) { if (idal_buffer_from_user(ib, data, count) == 0) { write_command = fp->write_command ? : 1; if (write_command == 5) write_command = 13; raw3270_request_set_cmd(rq, write_command); raw3270_request_set_idal(rq, ib); rc = fs3270_do_io(&fp->view, rq); if (rc == 0) rc = count - rq->rescnt; } else rc = -EFAULT; raw3270_request_free(rq); } else rc = PTR_ERR(rq); idal_buffer_free(ib); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton17990.40%133.33%
richard hittrichard hitt189.09%133.33%
heiko carstensheiko carstens10.51%133.33%
Total198100.00%3100.00%

/* * process ioctl commands for the tube driver */
static long fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { char __user *argp; struct fs3270 *fp; struct raw3270_iocb iocb; int rc; fp = filp->private_data; if (!fp) return -ENODEV; if (is_compat_task()) argp = compat_ptr(arg); else argp = (char __user *)arg; rc = 0; mutex_lock(&fs3270_mutex); switch (cmd) { case TUBICMD: fp->read_command = arg; break; case TUBOCMD: fp->write_command = arg; break; case TUBGETI: rc = put_user(fp->read_command, argp); break; case TUBGETO: rc = put_user(fp->write_command, argp); break; case TUBGETMOD: iocb.model = fp->view.model; iocb.line_cnt = fp->view.rows; iocb.col_cnt = fp->view.cols; iocb.pf_cnt = 24; iocb.re_cnt = 20; iocb.map = 0; if (copy_to_user(argp, &iocb, sizeof(struct raw3270_iocb))) rc = -EFAULT; break; } mutex_unlock(&fs3270_mutex); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton17880.54%125.00%
heiko carstensheiko carstens3013.57%125.00%
martin schwidefskymartin schwidefsky104.52%125.00%
christoph hellwigchristoph hellwig31.36%125.00%
Total221100.00%4100.00%

/* * Allocate fs3270 structure. */
static struct fs3270 * fs3270_alloc_view(void) { struct fs3270 *fp; fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL); if (!fp) return ERR_PTR(-ENOMEM); fp->init = raw3270_request_alloc(0); if (IS_ERR(fp->init)) { kfree(fp); return ERR_PTR(-ENOMEM); } return fp; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton7296.00%133.33%
richard hittrichard hitt22.67%133.33%
eric sesterhenneric sesterhenn11.33%133.33%
Total75100.00%3100.00%

/* * Free fs3270 structure. */
static void fs3270_free_view(struct raw3270_view *view) { struct fs3270 *fp; fp = (struct fs3270 *) view; if (fp->rdbuf) idal_buffer_free(fp->rdbuf); raw3270_request_free(((struct fs3270 *) view)->init); kfree(view); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2950.88%150.00%
richard hittrichard hitt2849.12%150.00%
Total57100.00%2100.00%

/* * Unlink fs3270 data structure from filp. */
static void fs3270_release(struct raw3270_view *view) { struct fs3270 *fp; fp = (struct fs3270 *) view; if (fp->fs_pid) kill_pid(fp->fs_pid, SIGHUP, 1); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky3378.57%150.00%
andrew mortonandrew morton921.43%150.00%
Total42100.00%2100.00%

/* View to a 3270 device. Can be console, tty or fullscreen. */ static struct raw3270_fn fs3270_fn = { .activate = fs3270_activate, .deactivate = fs3270_deactivate, .intv = (void *) fs3270_irq, .release = fs3270_release, .free = fs3270_free_view }; /* * This routine is called whenever a 3270 fullscreen device is opened. */
static int fs3270_open(struct inode *inode, struct file *filp) { struct fs3270 *fp; struct idal_buffer *ib; int minor, rc = 0; if (imajor(file_inode(filp)) != IBM_FS3270_MAJOR) return -ENODEV; minor = iminor(file_inode(filp)); /* Check for minor 0 multiplexer. */ if (minor == 0) { struct tty_struct *tty = get_current_tty(); if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { tty_kref_put(tty); return -ENODEV; } minor = tty->index; tty_kref_put(tty); } mutex_lock(&fs3270_mutex); /* Check if some other program is already using fullscreen mode. */ fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); if (!IS_ERR(fp)) { raw3270_put_view(&fp->view); rc = -EBUSY; goto out; } /* Allocate fullscreen view structure. */ fp = fs3270_alloc_view(); if (IS_ERR(fp)) { rc = PTR_ERR(fp); goto out; } init_waitqueue_head(&fp->wait); fp->fs_pid = get_pid(task_pid(current)); rc = raw3270_add_view(&fp->view, &fs3270_fn, minor); if (rc) { fs3270_free_view(&fp->view); goto out; } /* Allocate idal-buffer. */ ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0); if (IS_ERR(ib)) { raw3270_put_view(&fp->view); raw3270_del_view(&fp->view); rc = PTR_ERR(ib); goto out; } fp->rdbuf = ib; rc = raw3270_activate_view(&fp->view); if (rc) { raw3270_put_view(&fp->view); raw3270_del_view(&fp->view); goto out; } nonseekable_open(inode, filp); filp->private_data = fp; out: mutex_unlock(&fs3270_mutex); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton17348.06%18.33%
richard hittrichard hitt10128.06%18.33%
jonathan corbetjonathan corbet298.06%18.33%
martin schwidefskymartin schwidefsky174.72%216.67%
alan coxalan cox154.17%325.00%
peter zijlstrapeter zijlstra123.33%18.33%
al viroal viro61.67%18.33%
cedric le goatercedric le goater61.67%18.33%
roel kluinroel kluin10.28%18.33%
Total360100.00%12100.00%

/* * This routine is called when the 3270 tty is closed. We wait * for the remaining request to be completed. Then we clean up. */
static int fs3270_close(struct inode *inode, struct file *filp) { struct fs3270 *fp; fp = filp->private_data; filp->private_data = NULL; if (fp) { put_pid(fp->fs_pid); fp->fs_pid = NULL; raw3270_reset(&fp->view); raw3270_put_view(&fp->view); raw3270_del_view(&fp->view); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton4759.49%125.00%
richard hittrichard hitt2329.11%125.00%
cedric le goatercedric le goater810.13%125.00%
heiko carstensheiko carstens11.27%125.00%
Total79100.00%4100.00%

static const struct file_operations fs3270_fops = { .owner = THIS_MODULE, /* owner */ .read = fs3270_read, /* read */ .write = fs3270_write, /* write */ .unlocked_ioctl = fs3270_ioctl, /* ioctl */ .compat_ioctl = fs3270_ioctl, /* ioctl */ .open = fs3270_open, /* open */ .release = fs3270_close, /* release */ .llseek = no_llseek, };
static void fs3270_create_cb(int minor) { __register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops); device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor), NULL, "3270/tub%d", minor); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky4297.67%150.00%
heiko carstensheiko carstens12.33%150.00%
Total43100.00%2100.00%


static void fs3270_destroy_cb(int minor) { device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor)); __unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub"); }

Contributors

PersonTokensPropCommitsCommitProp
martin schwidefskymartin schwidefsky3196.88%150.00%
heiko carstensheiko carstens13.12%150.00%
Total32100.00%2100.00%

static struct raw3270_notifier fs3270_notifier = { .create = fs3270_create_cb, .destroy = fs3270_destroy_cb, }; /* * 3270 fullscreen driver initialization. */
static int __init fs3270_init(void) { int rc; rc = __register_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270", &fs3270_fops); if (rc) return rc; device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0), NULL, "3270/tub"); raw3270_register_notifier(&fs3270_notifier); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton3353.23%150.00%
martin schwidefskymartin schwidefsky2946.77%150.00%
Total62100.00%2100.00%


static void __exit fs3270_exit(void) { raw3270_unregister_notifier(&fs3270_notifier); device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, 0)); __unregister_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270"); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton1539.47%133.33%
hendrik bruecknerhendrik brueckner1231.58%133.33%
martin schwidefskymartin schwidefsky1128.95%133.33%
Total38100.00%3100.00%

MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR); module_init(fs3270_init); module_exit(fs3270_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton137453.07%13.45%
richard hittrichard hitt85032.83%13.45%
martin schwidefskymartin schwidefsky1977.61%517.24%
heiko carstensheiko carstens471.82%620.69%
jonathan corbetjonathan corbet291.12%13.45%
cedric le goatercedric le goater190.73%13.45%
alan coxalan cox150.58%310.34%
peter zijlstrapeter zijlstra120.46%13.45%
hendrik bruecknerhendrik brueckner120.46%13.45%
christoph hellwigchristoph hellwig100.39%13.45%
al viroal viro60.23%13.45%
peter oberparleiterpeter oberparleiter60.23%13.45%
arnd bergmannarnd bergmann50.19%13.45%
tejun heotejun heo30.12%13.45%
arjan van de venarjan van de ven10.04%13.45%
andre goddard rosaandre goddard rosa10.04%13.45%
roel kluinroel kluin10.04%13.45%
eric sesterhenneric sesterhenn10.04%13.45%
Total2589100.00%29100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}