[PATCH] s390: 3270 fullscreen view
Martin Schwidefsky <schwidefsky@de.ibm.com> Fix fullscreen view of the 3270 device driver. Signed-off-by: Richard Hitt <rbh00@utsglobal.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
d89ea9b8bb
commit
ed3cb6f039
|
@ -18,6 +18,8 @@
|
|||
#include <asm/dasd.h>
|
||||
#include <asm/cmb.h>
|
||||
#include <asm/tape390.h>
|
||||
#include <asm/ccwdev.h>
|
||||
#include "../../../drivers/s390/char/raw3270.h"
|
||||
|
||||
static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
|
||||
unsigned long arg, struct file *f)
|
||||
|
@ -62,6 +64,13 @@ COMPATIBLE_IOCTL(BIODASDCMFENABLE)
|
|||
COMPATIBLE_IOCTL(BIODASDCMFDISABLE)
|
||||
COMPATIBLE_IOCTL(BIODASDREADALLCMB)
|
||||
|
||||
COMPATIBLE_IOCTL(TUBICMD)
|
||||
COMPATIBLE_IOCTL(TUBOCMD)
|
||||
COMPATIBLE_IOCTL(TUBGETI)
|
||||
COMPATIBLE_IOCTL(TUBGETO)
|
||||
COMPATIBLE_IOCTL(TUBSETMOD)
|
||||
COMPATIBLE_IOCTL(TUBGETMOD)
|
||||
|
||||
COMPATIBLE_IOCTL(TAPE390_DISPLAY)
|
||||
|
||||
/* s390 doesn't need handlers here */
|
||||
|
|
|
@ -213,6 +213,9 @@ con3270_update(struct con3270 *cp)
|
|||
struct string *s, *n;
|
||||
int rc;
|
||||
|
||||
if (cp->view.dev)
|
||||
raw3270_activate_view(&cp->view);
|
||||
|
||||
wrq = xchg(&cp->write, 0);
|
||||
if (!wrq) {
|
||||
con3270_set_timer(cp, 1);
|
||||
|
@ -489,8 +492,6 @@ con3270_write(struct console *co, const char *str, unsigned int count)
|
|||
unsigned char c;
|
||||
|
||||
cp = condev;
|
||||
if (cp->view.dev)
|
||||
raw3270_activate_view(&cp->view);
|
||||
spin_lock_irqsave(&cp->view.lock, flags);
|
||||
while (count-- > 0) {
|
||||
c = *str++;
|
||||
|
@ -620,7 +621,7 @@ con3270_init(void)
|
|||
(void (*)(unsigned long)) con3270_read_tasklet,
|
||||
(unsigned long) condev->read);
|
||||
|
||||
raw3270_add_view(&condev->view, &con3270_fn, 0);
|
||||
raw3270_add_view(&condev->view, &con3270_fn, 1);
|
||||
|
||||
INIT_LIST_HEAD(&condev->freemem);
|
||||
for (i = 0; i < CON3270_STRING_PAGES; i++) {
|
||||
|
|
|
@ -33,8 +33,11 @@ struct fs3270 {
|
|||
int read_command; /* ccw command to use for reads. */
|
||||
int write_command; /* ccw command to use for writes. */
|
||||
int attention; /* Got attention. */
|
||||
struct raw3270_request *clear; /* single clear request. */
|
||||
wait_queue_head_t attn_wait; /* Attention wait queue. */
|
||||
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 void
|
||||
|
@ -43,58 +46,172 @@ fs3270_wake_up(struct raw3270_request *rq, void *data)
|
|||
wake_up((wait_queue_head_t *) data);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
|
||||
{
|
||||
wait_queue_head_t wq;
|
||||
struct fs3270 *fp;
|
||||
int rc;
|
||||
|
||||
init_waitqueue_head(&wq);
|
||||
fp = (struct fs3270 *) view;
|
||||
rq->callback = fs3270_wake_up;
|
||||
rq->callback_data = &wq;
|
||||
rc = raw3270_start(view, rq);
|
||||
if (rc)
|
||||
return rc;
|
||||
/* Started sucessfully. Now wait for completion. */
|
||||
wait_event(wq, raw3270_request_final(rq));
|
||||
return rq->rc;
|
||||
}
|
||||
rq->callback_data = &fp->wait;
|
||||
|
||||
static void
|
||||
fs3270_reset_callback(struct raw3270_request *rq, void *data)
|
||||
{
|
||||
raw3270_request_reset(rq);
|
||||
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 sucessfully. Now wait for completion. */
|
||||
wait_event(fp->wait, raw3270_request_final(rq));
|
||||
}
|
||||
} while (rc == -EACCES);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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_proc(fp->fs_pid, SIGHUP, 1);
|
||||
}
|
||||
fp->rdbuf_size = 0;
|
||||
raw3270_request_reset(rq);
|
||||
wake_up(&fp->wait);
|
||||
}
|
||||
|
||||
static int
|
||||
fs3270_activate(struct raw3270_view *view)
|
||||
{
|
||||
struct fs3270 *fp;
|
||||
char *cp;
|
||||
int rc;
|
||||
|
||||
fp = (struct fs3270 *) view;
|
||||
raw3270_request_set_cmd(fp->clear, TC_EWRITEA);
|
||||
fp->clear->callback = fs3270_reset_callback;
|
||||
return raw3270_start(view, fp->clear);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_proc(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);
|
||||
}
|
||||
|
||||
static void
|
||||
fs3270_deactivate(struct raw3270_view *view)
|
||||
{
|
||||
// FIXME: is this a good idea? The user program using fullscreen 3270
|
||||
// will die just because a console message appeared. On the other
|
||||
// hand the fullscreen device is unoperational now.
|
||||
struct fs3270 *fp;
|
||||
|
||||
fp = (struct fs3270 *) view;
|
||||
if (fp->fs_pid != 0)
|
||||
kill_proc(fp->fs_pid, SIGHUP, 1);
|
||||
fp->fs_pid = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -103,7 +220,7 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
|
|||
/* Handle ATTN. Set indication and wake waiters for attention. */
|
||||
if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
|
||||
fp->attention = 1;
|
||||
wake_up(&fp->attn_wait);
|
||||
wake_up(&fp->wait);
|
||||
}
|
||||
|
||||
if (rq) {
|
||||
|
@ -125,7 +242,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
|
|||
struct fs3270 *fp;
|
||||
struct raw3270_request *rq;
|
||||
struct idal_buffer *ib;
|
||||
int rc;
|
||||
ssize_t rc;
|
||||
|
||||
if (count == 0 || count > 65535)
|
||||
return -EINVAL;
|
||||
|
@ -133,7 +250,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
|
|||
if (!fp)
|
||||
return -ENODEV;
|
||||
ib = idal_buffer_alloc(count, 0);
|
||||
if (!ib)
|
||||
if (IS_ERR(ib))
|
||||
return -ENOMEM;
|
||||
rq = raw3270_request_alloc(0);
|
||||
if (!IS_ERR(rq)) {
|
||||
|
@ -141,10 +258,19 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
|
|||
fp->read_command = 6;
|
||||
raw3270_request_set_cmd(rq, fp->read_command ? : 2);
|
||||
raw3270_request_set_idal(rq, ib);
|
||||
wait_event(fp->attn_wait, fp->attention);
|
||||
rc = fs3270_do_io(&fp->view, rq);
|
||||
if (rc == 0 && idal_buffer_to_user(ib, data, count))
|
||||
rc = -EFAULT;
|
||||
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);
|
||||
|
@ -162,13 +288,13 @@ fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
|
|||
struct raw3270_request *rq;
|
||||
struct idal_buffer *ib;
|
||||
int write_command;
|
||||
int rc;
|
||||
ssize_t rc;
|
||||
|
||||
fp = filp->private_data;
|
||||
if (!fp)
|
||||
return -ENODEV;
|
||||
ib = idal_buffer_alloc(count, 0);
|
||||
if (!ib)
|
||||
if (IS_ERR(ib))
|
||||
return -ENOMEM;
|
||||
rq = raw3270_request_alloc(0);
|
||||
if (!IS_ERR(rq)) {
|
||||
|
@ -179,6 +305,8 @@ fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
|
|||
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);
|
||||
|
@ -232,7 +360,7 @@ fs3270_ioctl(struct inode *inode, struct file *filp,
|
|||
}
|
||||
|
||||
/*
|
||||
* Allocate tty3270 structure.
|
||||
* Allocate fs3270 structure.
|
||||
*/
|
||||
static struct fs3270 *
|
||||
fs3270_alloc_view(void)
|
||||
|
@ -243,8 +371,8 @@ fs3270_alloc_view(void)
|
|||
if (!fp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(fp, 0, sizeof(struct fs3270));
|
||||
fp->clear = raw3270_request_alloc(0);
|
||||
if (!IS_ERR(fp->clear)) {
|
||||
fp->init = raw3270_request_alloc(0);
|
||||
if (IS_ERR(fp->init)) {
|
||||
kfree(fp);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
@ -252,12 +380,17 @@ fs3270_alloc_view(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Free tty3270 structure.
|
||||
* Free fs3270 structure.
|
||||
*/
|
||||
static void
|
||||
fs3270_free_view(struct raw3270_view *view)
|
||||
{
|
||||
raw3270_request_free(((struct fs3270 *) view)->clear);
|
||||
struct fs3270 *fp;
|
||||
|
||||
fp = (struct fs3270 *) view;
|
||||
if (fp->rdbuf)
|
||||
idal_buffer_free(fp->rdbuf);
|
||||
raw3270_request_free(((struct fs3270 *) view)->init);
|
||||
kfree(view);
|
||||
}
|
||||
|
||||
|
@ -285,11 +418,20 @@ static int
|
|||
fs3270_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fs3270 *fp;
|
||||
struct idal_buffer *ib;
|
||||
int minor, rc;
|
||||
|
||||
if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR)
|
||||
return -ENODEV;
|
||||
minor = iminor(filp->f_dentry->d_inode);
|
||||
/* Check for minor 0 multiplexer. */
|
||||
if (minor == 0) {
|
||||
if (!current->signal->tty)
|
||||
return -ENODEV;
|
||||
if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR)
|
||||
return -ENODEV;
|
||||
minor = current->signal->tty->index + RAW3270_FIRSTMINOR;
|
||||
}
|
||||
/* Check if some other program is already using fullscreen mode. */
|
||||
fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
|
||||
if (!IS_ERR(fp)) {
|
||||
|
@ -301,7 +443,7 @@ fs3270_open(struct inode *inode, struct file *filp)
|
|||
if (IS_ERR(fp))
|
||||
return PTR_ERR(fp);
|
||||
|
||||
init_waitqueue_head(&fp->attn_wait);
|
||||
init_waitqueue_head(&fp->wait);
|
||||
fp->fs_pid = current->pid;
|
||||
rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
|
||||
if (rc) {
|
||||
|
@ -309,8 +451,18 @@ fs3270_open(struct inode *inode, struct file *filp)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return PTR_ERR(fp);
|
||||
}
|
||||
fp->rdbuf = ib;
|
||||
|
||||
rc = raw3270_activate_view(&fp->view);
|
||||
if (rc) {
|
||||
raw3270_put_view(&fp->view);
|
||||
raw3270_del_view(&fp->view);
|
||||
return rc;
|
||||
}
|
||||
|
@ -329,8 +481,12 @@ fs3270_close(struct inode *inode, struct file *filp)
|
|||
|
||||
fp = filp->private_data;
|
||||
filp->private_data = 0;
|
||||
if (fp)
|
||||
if (fp) {
|
||||
fp->fs_pid = 0;
|
||||
raw3270_reset(&fp->view);
|
||||
raw3270_put_view(&fp->view);
|
||||
raw3270_del_view(&fp->view);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
|
||||
#include "raw3270.h"
|
||||
|
||||
#include <linux/major.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct class *class3270;
|
||||
|
||||
/* The main 3270 data structure. */
|
||||
struct raw3270 {
|
||||
struct list_head list;
|
||||
|
@ -41,6 +47,8 @@ struct raw3270 {
|
|||
struct timer_list timer; /* Device timer. */
|
||||
|
||||
unsigned char *ascebc; /* ascii -> ebcdic table */
|
||||
struct class_device *clttydev; /* 3270-class tty device ptr */
|
||||
struct class_device *cltubdev; /* 3270-class tub device ptr */
|
||||
};
|
||||
|
||||
/* raw3270->flags */
|
||||
|
@ -316,6 +324,22 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
|
||||
{
|
||||
struct raw3270 *rp;
|
||||
int rc;
|
||||
|
||||
rp = view->dev;
|
||||
if (!rp || rp->view != view)
|
||||
rc = -EACCES;
|
||||
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
|
||||
rc = -ENODEV;
|
||||
else
|
||||
rc = __raw3270_start(rp, view, rq);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
|
||||
{
|
||||
|
@ -744,6 +768,22 @@ raw3270_reset_device(struct raw3270 *rp)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
raw3270_reset(struct raw3270_view *view)
|
||||
{
|
||||
struct raw3270 *rp;
|
||||
int rc;
|
||||
|
||||
rp = view->dev;
|
||||
if (!rp || rp->view != view)
|
||||
rc = -EACCES;
|
||||
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
|
||||
rc = -ENODEV;
|
||||
else
|
||||
rc = raw3270_reset_device(view->dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup new 3270 device.
|
||||
*/
|
||||
|
@ -774,11 +814,12 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
|
|||
|
||||
/*
|
||||
* Add device to list and find the smallest unused minor
|
||||
* number for it.
|
||||
* number for it. Note: there is no device with minor 0,
|
||||
* see special case for fs3270.c:fs3270_open().
|
||||
*/
|
||||
down(&raw3270_sem);
|
||||
/* Keep the list sorted. */
|
||||
minor = 0;
|
||||
minor = RAW3270_FIRSTMINOR;
|
||||
rp->minor = -1;
|
||||
list_for_each(l, &raw3270_devices) {
|
||||
tmp = list_entry(l, struct raw3270, list);
|
||||
|
@ -789,7 +830,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
|
|||
}
|
||||
minor++;
|
||||
}
|
||||
if (rp->minor == -1 && minor < RAW3270_MAXDEVS) {
|
||||
if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
|
||||
rp->minor = minor;
|
||||
list_add_tail(&rp->list, &raw3270_devices);
|
||||
}
|
||||
|
@ -941,11 +982,12 @@ raw3270_deactivate_view(struct raw3270_view *view)
|
|||
list_add_tail(&view->list, &rp->view_list);
|
||||
/* Try to activate another view. */
|
||||
if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
|
||||
list_for_each_entry(view, &rp->view_list, list)
|
||||
if (view->fn->activate(view) == 0) {
|
||||
rp->view = view;
|
||||
list_for_each_entry(view, &rp->view_list, list) {
|
||||
rp->view = view;
|
||||
if (view->fn->activate(view) == 0)
|
||||
break;
|
||||
}
|
||||
rp->view = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||
|
@ -961,6 +1003,8 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
|
|||
struct raw3270 *rp;
|
||||
int rc;
|
||||
|
||||
if (minor <= 0)
|
||||
return -ENODEV;
|
||||
down(&raw3270_sem);
|
||||
rc = -ENODEV;
|
||||
list_for_each_entry(rp, &raw3270_devices, list) {
|
||||
|
@ -976,7 +1020,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
|
|||
view->cols = rp->cols;
|
||||
view->ascebc = rp->ascebc;
|
||||
spin_lock_init(&view->lock);
|
||||
list_add_tail(&view->list, &rp->view_list);
|
||||
list_add(&view->list, &rp->view_list);
|
||||
rc = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||
|
@ -1039,7 +1083,7 @@ raw3270_del_view(struct raw3270_view *view)
|
|||
if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
|
||||
/* Try to activate another view. */
|
||||
list_for_each_entry(nv, &rp->view_list, list) {
|
||||
if (nv->fn->activate(view) == 0) {
|
||||
if (nv->fn->activate(nv) == 0) {
|
||||
rp->view = nv;
|
||||
break;
|
||||
}
|
||||
|
@ -1063,6 +1107,12 @@ raw3270_delete_device(struct raw3270 *rp)
|
|||
|
||||
/* Remove from device chain. */
|
||||
down(&raw3270_sem);
|
||||
if (rp->clttydev)
|
||||
class_device_destroy(class3270,
|
||||
MKDEV(IBM_TTY3270_MAJOR, rp->minor));
|
||||
if (rp->cltubdev)
|
||||
class_device_destroy(class3270,
|
||||
MKDEV(IBM_FS3270_MAJOR, rp->minor));
|
||||
list_del_init(&rp->list);
|
||||
up(&raw3270_sem);
|
||||
|
||||
|
@ -1129,6 +1179,16 @@ raw3270_create_attributes(struct raw3270 *rp)
|
|||
{
|
||||
//FIXME: check return code
|
||||
sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
|
||||
rp->clttydev =
|
||||
class_device_create(class3270,
|
||||
MKDEV(IBM_TTY3270_MAJOR, rp->minor),
|
||||
&rp->cdev->dev, "tty%s",
|
||||
rp->cdev->dev.bus_id);
|
||||
rp->cltubdev =
|
||||
class_device_create(class3270,
|
||||
MKDEV(IBM_FS3270_MAJOR, rp->minor),
|
||||
&rp->cdev->dev, "tub%s",
|
||||
rp->cdev->dev.bus_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1189,13 +1249,13 @@ raw3270_set_online (struct ccw_device *cdev)
|
|||
return PTR_ERR(rp);
|
||||
rc = raw3270_reset_device(rp);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto failure;
|
||||
rc = raw3270_size_device(rp);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto failure;
|
||||
rc = raw3270_reset_device(rp);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto failure;
|
||||
raw3270_create_attributes(rp);
|
||||
set_bit(RAW3270_FLAGS_READY, &rp->flags);
|
||||
down(&raw3270_sem);
|
||||
|
@ -1203,6 +1263,10 @@ raw3270_set_online (struct ccw_device *cdev)
|
|||
np->notifier(rp->minor, 1);
|
||||
up(&raw3270_sem);
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
raw3270_delete_device(rp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1217,6 +1281,14 @@ raw3270_remove (struct ccw_device *cdev)
|
|||
struct raw3270_notifier *np;
|
||||
|
||||
rp = cdev->dev.driver_data;
|
||||
/*
|
||||
* _remove is the opposite of _probe; it's probe that
|
||||
* should set up rp. raw3270_remove gets entered for
|
||||
* devices even if they haven't been varied online.
|
||||
* Thus, rp may validly be NULL here.
|
||||
*/
|
||||
if (rp == NULL)
|
||||
return;
|
||||
clear_bit(RAW3270_FLAGS_READY, &rp->flags);
|
||||
|
||||
sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
|
||||
|
@ -1301,6 +1373,7 @@ raw3270_init(void)
|
|||
if (rc == 0) {
|
||||
/* Create attributes for early (= console) device. */
|
||||
down(&raw3270_sem);
|
||||
class3270 = class_create(THIS_MODULE, "3270");
|
||||
list_for_each_entry(rp, &raw3270_devices, list) {
|
||||
get_device(&rp->cdev->dev);
|
||||
raw3270_create_attributes(rp);
|
||||
|
@ -1314,6 +1387,7 @@ static void
|
|||
raw3270_exit(void)
|
||||
{
|
||||
ccw_driver_unregister(&raw3270_ccw_driver);
|
||||
class_destroy(class3270);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1335,7 +1409,9 @@ EXPORT_SYMBOL(raw3270_find_view);
|
|||
EXPORT_SYMBOL(raw3270_activate_view);
|
||||
EXPORT_SYMBOL(raw3270_deactivate_view);
|
||||
EXPORT_SYMBOL(raw3270_start);
|
||||
EXPORT_SYMBOL(raw3270_start_locked);
|
||||
EXPORT_SYMBOL(raw3270_start_irq);
|
||||
EXPORT_SYMBOL(raw3270_reset);
|
||||
EXPORT_SYMBOL(raw3270_register_notifier);
|
||||
EXPORT_SYMBOL(raw3270_unregister_notifier);
|
||||
EXPORT_SYMBOL(raw3270_wait_queue);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
/* Local Channel Commands */
|
||||
#define TC_WRITE 0x01 /* Write */
|
||||
#define TC_RDBUF 0x02 /* Read Buffer */
|
||||
#define TC_EWRITE 0x05 /* Erase write */
|
||||
#define TC_READMOD 0x06 /* Read modified */
|
||||
#define TC_EWRITEA 0x0d /* Erase write alternate */
|
||||
|
@ -76,7 +77,8 @@
|
|||
#define TW_KR 0xc2 /* Keyboard restore */
|
||||
#define TW_PLUSALARM 0x04 /* Add this bit for alarm */
|
||||
|
||||
#define RAW3270_MAXDEVS 256
|
||||
#define RAW3270_FIRSTMINOR 1 /* First minor number */
|
||||
#define RAW3270_MAXDEVS 255 /* Max number of 3270 devices */
|
||||
|
||||
/* For TUBGETMOD and TUBSETMOD. Should include. */
|
||||
struct raw3270_iocb {
|
||||
|
@ -166,7 +168,10 @@ void raw3270_del_view(struct raw3270_view *);
|
|||
void raw3270_deactivate_view(struct raw3270_view *);
|
||||
struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int);
|
||||
int raw3270_start(struct raw3270_view *, struct raw3270_request *);
|
||||
int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *);
|
||||
int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
|
||||
int raw3270_reset(struct raw3270_view *);
|
||||
struct raw3270_view *raw3270_view(struct raw3270_view *);
|
||||
|
||||
/* Reference count inliner for view structures. */
|
||||
static inline void
|
||||
|
|
|
@ -653,18 +653,12 @@ tty3270_activate(struct raw3270_view *view)
|
|||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
tty3270_set_timer(tp, 1);
|
||||
spin_unlock_irqrestore(&tp->view.lock, flags);
|
||||
start_tty(tp->tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tty3270_deactivate(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
if (tp && tp->tty)
|
||||
stop_tty(tp->tty);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -716,13 +710,13 @@ tty3270_alloc_view(void)
|
|||
tp->freemem_pages[pages], PAGE_SIZE);
|
||||
}
|
||||
tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
|
||||
if (!tp->write)
|
||||
if (IS_ERR(tp->write))
|
||||
goto out_pages;
|
||||
tp->read = raw3270_request_alloc(0);
|
||||
if (!tp->read)
|
||||
if (IS_ERR(tp->read))
|
||||
goto out_write;
|
||||
tp->kreset = raw3270_request_alloc(1);
|
||||
if (!tp->kreset)
|
||||
if (IS_ERR(tp->kreset))
|
||||
goto out_read;
|
||||
tp->kbd = kbd_alloc();
|
||||
if (!tp->kbd)
|
||||
|
@ -845,7 +839,8 @@ tty3270_del_views(void)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < tty3270_max_index; i++) {
|
||||
tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, i);
|
||||
tp = (struct tty3270 *)
|
||||
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
|
||||
if (!IS_ERR(tp))
|
||||
raw3270_del_view(&tp->view);
|
||||
}
|
||||
|
@ -871,7 +866,9 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
if (tty->count > 1)
|
||||
return 0;
|
||||
/* Check if the tty3270 is already there. */
|
||||
tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, tty->index);
|
||||
tp = (struct tty3270 *)
|
||||
raw3270_find_view(&tty3270_fn,
|
||||
tty->index + RAW3270_FIRSTMINOR);
|
||||
if (!IS_ERR(tp)) {
|
||||
tty->driver_data = tp;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
|
@ -903,7 +900,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
(void (*)(unsigned long)) tty3270_read_tasklet,
|
||||
(unsigned long) tp->read);
|
||||
|
||||
rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index);
|
||||
rc = raw3270_add_view(&tp->view, &tty3270_fn,
|
||||
tty->index + RAW3270_FIRSTMINOR);
|
||||
if (rc) {
|
||||
tty3270_free_view(tp);
|
||||
return rc;
|
||||
|
@ -911,8 +909,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
rc = tty3270_alloc_screen(tp);
|
||||
if (rc) {
|
||||
raw3270_del_view(&tp->view);
|
||||
raw3270_put_view(&tp->view);
|
||||
raw3270_del_view(&tp->view);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1780,7 +1778,7 @@ tty3270_init(void)
|
|||
struct tty_driver *driver;
|
||||
int ret;
|
||||
|
||||
driver = alloc_tty_driver(256);
|
||||
driver = alloc_tty_driver(RAW3270_MAXDEVS);
|
||||
if (!driver)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1794,6 +1792,7 @@ tty3270_init(void)
|
|||
driver->driver_name = "ttyTUB";
|
||||
driver->name = "ttyTUB";
|
||||
driver->major = IBM_TTY3270_MAJOR;
|
||||
driver->minor_start = RAW3270_FIRSTMINOR;
|
||||
driver->type = TTY_DRIVER_TYPE_SYSTEM;
|
||||
driver->subtype = SYSTEM_TYPE_TTY;
|
||||
driver->init_termios = tty_std_termios;
|
||||
|
|
Loading…
Reference in New Issue