Commit 513ec1e8 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update: 3270 console

Fix 3270 console reboot loop. Recognize 3270 control unit type 3174.
Fix tubfs kmallocs. Dynamically get 3270 input buffer. Get bootup colors
right on 3270 console
parent 0dd3cc51
ChangeLog for the UTS Global 3270-support patch ChangeLog for the UTS Global 3270-support patch
Sep 2002: Get bootup colors right on 3270 console
* In tubttybld.c, substantially revise ESC processing so that
ESC sequences (especially coloring ones) and the strings
they affect work as right as 3270 can get them. Also, set
screen height to omit the two rows used for input area, in
tty3270_open() in tubtty.c.
Sep 2002: Dynamically get 3270 input buffer
* Oversize 3270 screen widths may exceed GEOM_MAXINPLEN columns,
so get input-area buffer dynamically when sizing the device in
tubmakemin() in tuball.c (if it's the console) or tty3270_open()
in tubtty.c (if needed). Change tubp->tty_input to be a
pointer rather than an array, in tubio.h.
Sep 2002: Fix tubfs kmalloc()s
* Do read and write lengths correctly in fs3270_read()
and fs3270_write(), whilst never asking kmalloc()
for more than 0x800 bytes. Affects tubfs.c and tubio.h.
Sep 2002: Recognize 3270 control unit type 3174
* Recognize control-unit type 0x3174 as well as 0x327?.
The IBM 2047 device emulates a 3174 control unit.
Modularize control-unit recognition in tuball.c by
adding and invoking new tub3270_is_ours().
Apr 2002: Fix 3270 console reboot loop
* (Belated log entry) Fixed reboot loop if 3270 console,
in tubtty.c:ttu3270_bh().
Feb 6, 2001: Feb 6, 2001:
* This changelog is new * This changelog is new
* tub3270 now supports 3270 console: * tub3270 now supports 3270 console:
......
...@@ -228,6 +228,16 @@ tub_dec_use_count(void) ...@@ -228,6 +228,16 @@ tub_dec_use_count(void)
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
static int
tub3270_is_ours(s390_dev_info_t *dp)
{
if ((dp->sid_data.cu_type & 0xfff0) == 0x3270)
return 1;
if (dp->sid_data.cu_type == 0x3174)
return 1;
return 0;
}
/* /*
* tub3270_init() called by kernel or module initialization * tub3270_init() called by kernel or module initialization
*/ */
...@@ -283,7 +293,7 @@ tub3270_init(void) ...@@ -283,7 +293,7 @@ tub3270_init(void)
} }
#endif /* LINUX_VERSION_CODE */ #endif /* LINUX_VERSION_CODE */
#endif /* CONFIG_TN3270_CONSOLE */ #endif /* CONFIG_TN3270_CONSOLE */
if ((d.sid_data.cu_type & 0xfff0) != 0x3270) if (!tub3270_is_ours(&d))
continue; continue;
rc = tubmakemin(i, &d); rc = tubmakemin(i, &d);
...@@ -498,6 +508,10 @@ tubfiniminors(void) ...@@ -498,6 +508,10 @@ tubfiniminors(void)
tty3270_rcl_fini(tubp); tty3270_rcl_fini(tubp);
kfree(tubp->tty_bcb.bc_buf); kfree(tubp->tty_bcb.bc_buf);
tubp->tty_bcb.bc_buf = NULL; tubp->tty_bcb.bc_buf = NULL;
if (tubp->tty_input) {
kfree(tubp->tty_input);
tubp->tty_input = NULL;
}
tubp->ttyscreen = NULL; tubp->ttyscreen = NULL;
kfree(tubp); kfree(tubp);
*tubpp = NULL; *tubpp = NULL;
......
...@@ -233,12 +233,18 @@ fs3270_tasklet(unsigned long data) ...@@ -233,12 +233,18 @@ fs3270_tasklet(unsigned long data)
{ {
long flags; long flags;
tub_t *tubp; tub_t *tubp;
addr_t *ip;
tubp = (tub_t *) data; tubp = (tub_t *) data;
TUBLOCK(tubp->irq, flags); TUBLOCK(tubp->irq, flags);
tubp->flags &= ~TUB_BHPENDING; tubp->flags &= ~TUB_BHPENDING;
if (tubp->wbuf) { /* if we were writing */ if (tubp->wbuf) { /* if we were writing */
for (ip = tubp->wbuf; ip < tubp->wbuf+33; ip++) {
if (*ip == 0)
break;
kfree(phys_to_virt(*ip));
}
kfree(tubp->wbuf); kfree(tubp->wbuf);
tubp->wbuf = NULL; tubp->wbuf = NULL;
} }
...@@ -280,8 +286,6 @@ fs3270_int(tub_t *tubp, devstat_t *dsp) ...@@ -280,8 +286,6 @@ fs3270_int(tub_t *tubp, devstat_t *dsp)
#define DEV_UE_BUSY \ #define DEV_UE_BUSY \
(DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP) (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
tubp->dstat = dsp->dstat;
#ifdef RBHNOTYET #ifdef RBHNOTYET
/* XXX needs more work; must save 2d arg to fs370_io() */ /* XXX needs more work; must save 2d arg to fs370_io() */
/* Handle CE-DE-UE and subsequent UDE */ /* Handle CE-DE-UE and subsequent UDE */
...@@ -364,47 +368,78 @@ fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off) ...@@ -364,47 +368,78 @@ fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
ccw1_t *cp; ccw1_t *cp;
int rc; int rc;
long flags; long flags;
addr_t *idalp, *ip;
char *tp;
int count, piece;
int size;
if (len == 0 || len > 65535) {
return -EINVAL;
}
if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL) if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
return -ENODEV; return -ENODEV;
if ((rc = fs3270_wait(tubp, &flags)) != 0) {
TUBUNLOCK(tubp->irq, flags); ip = idalp = kmalloc(33*sizeof(addr_t), GFP_ATOMIC|GFP_DMA);
return rc; if (idalp == NULL)
return -EFAULT;
memset(idalp, 0, 33 * sizeof *idalp);
count = len;
while (count) {
piece = MIN(count, 0x800);
size = count == len? piece: 0x800;
if ((kp = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
len = -ENOMEM;
goto do_cleanup;
}
*ip++ = virt_to_phys(kp);
count -= piece;
} }
kp = kmalloc(len, GFP_KERNEL|GFP_DMA); if ((rc = fs3270_wait(tubp, &flags)) != 0) {
if (kp == NULL) {
TUBUNLOCK(tubp->irq, flags); TUBUNLOCK(tubp->irq, flags);
return -ENOMEM; len = rc;
goto do_cleanup;
} }
cp = &tubp->rccw; cp = &tubp->rccw;
if (tubp->icmd == 0 && tubp->ocmd != 0) tubp->icmd = 6; if (tubp->icmd == 0 && tubp->ocmd != 0) tubp->icmd = 6;
cp->cmd_code = tubp->icmd?:2; cp->cmd_code = tubp->icmd?:2;
cp->flags = CCW_FLAG_SLI; cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
cp->count = len; cp->count = len;
cp->cda = virt_to_phys(kp); cp->cda = virt_to_phys(idalp);
tubp->flags |= TUB_RDPENDING; tubp->flags |= TUB_RDPENDING;
TUBUNLOCK(tubp->irq, flags); TUBUNLOCK(tubp->irq, flags);
if ((rc = fs3270_wait(tubp, &flags)) != 0) { if ((rc = fs3270_wait(tubp, &flags)) != 0) {
tubp->flags &= ~TUB_RDPENDING; tubp->flags &= ~TUB_RDPENDING;
len = rc;
TUBUNLOCK(tubp->irq, flags); TUBUNLOCK(tubp->irq, flags);
kfree(kp); goto do_cleanup;
return rc;
} }
TUBUNLOCK(tubp->irq, flags);
len -= tubp->cswl; len -= tubp->cswl;
TUBUNLOCK(tubp->irq, flags); count = len;
if (tubdebug & 1) tp = dp;
printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n", ip = idalp;
tubp->minor, while (count) {
*(int*)((long)kp + 0), piece = MIN(count, 0x800);
*(int*)((long)kp + 4), if (copy_to_user(tp, phys_to_virt(*ip), piece) != 0) {
*(int*)((long)kp + 8), len = -EFAULT;
*(int*)((long)kp + 12)); goto do_cleanup;
copy_to_user(dp, kp, len); }
kfree(kp); count -= piece;
tp += piece;
ip++;
}
do_cleanup:
for (ip = idalp; ip < idalp+33; ip++) {
if (*ip == 0)
break;
kfree(phys_to_virt(*ip));
}
kfree(idalp);
return len; return len;
} }
...@@ -419,34 +454,65 @@ fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off) ...@@ -419,34 +454,65 @@ fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
int rc; int rc;
long flags; long flags;
void *kb; void *kb;
addr_t *idalp, *ip;
int count, piece;
int index;
int size;
if (len > 65535 || len == 0)
return -EINVAL;
/* Locate the tube */ /* Locate the tube */
if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL) if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
return -ENODEV; return -ENODEV;
/* Copy data to write from user address space */ ip = idalp = kmalloc(33*sizeof(addr_t), GFP_ATOMIC|GFP_DMA);
if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL) if (idalp == NULL)
return -ENOMEM;
if (copy_from_user(kb, dp, len) != 0) {
kfree(kb);
return -EFAULT; return -EFAULT;
memset(idalp, 0, 33 * sizeof *idalp);
count = len;
index = 0;
while (count) {
piece = MIN(count, 0x800);
size = count == len? piece: 0x800;
if ((kb = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
len = -ENOMEM;
goto do_cleanup;
}
*ip++ = virt_to_phys(kb);
if (copy_from_user(kb, &dp[index], piece) != 0) {
len = -EFAULT;
goto do_cleanup;
}
count -= piece;
index += piece;
} }
/* Wait till tube's not working or signal is pending */ /* Wait till tube's not working or signal is pending */
if ((rc = fs3270_wait(tubp, &flags))) { if ((rc = fs3270_wait(tubp, &flags))) {
len = rc;
TUBUNLOCK(tubp->irq, flags); TUBUNLOCK(tubp->irq, flags);
kfree(kb); goto do_cleanup;
return rc;
} }
/* Make CCW and start I/O. Back end will free buffer. */ /* Make CCW and start I/O. Back end will free buffers & idal. */
tubp->wbuf = kb; tubp->wbuf = idalp;
cp = &tubp->wccw; cp = &tubp->wccw;
cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1; cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
cp->flags = CCW_FLAG_SLI; cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
cp->count = len; cp->count = len;
cp->cda = virt_to_phys(tubp->wbuf); cp->cda = virt_to_phys(tubp->wbuf);
fs3270_io(tubp, cp); fs3270_io(tubp, cp);
TUBUNLOCK(tubp->irq, flags); TUBUNLOCK(tubp->irq, flags);
return len; return len;
do_cleanup:
for (ip = idalp; ip < idalp+33; ip++) {
if (*ip == 0)
break;
kfree(phys_to_virt(*ip));
}
kfree(idalp);
return len;
} }
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/idals.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
...@@ -81,10 +82,17 @@ ...@@ -81,10 +82,17 @@
#define TAT_CHARS 0x43 #define TAT_CHARS 0x43
#define TAT_TRANS 0x46 #define TAT_TRANS 0x46
/* Extended-Highlighting Bytes */
#define TAX_RESET 0x00
#define TAX_BLINK 0xf1
#define TAX_REVER 0xf2
#define TAX_UNDER 0xf4
/* Reset value */ /* Reset value */
#define TAR_RESET 0x00 #define TAR_RESET 0x00
/* Color values */ /* Color values */
#define TAC_RESET 0x00
#define TAC_BLUE 0xf1 #define TAC_BLUE 0xf1
#define TAC_RED 0xf2 #define TAC_RED 0xf2
#define TAC_PINK 0xf3 #define TAC_PINK 0xf3
...@@ -220,7 +228,7 @@ typedef struct tub_s { ...@@ -220,7 +228,7 @@ typedef struct tub_s {
devstat_t devstat; devstat_t devstat;
ccw1_t rccw; ccw1_t rccw;
ccw1_t wccw; ccw1_t wccw;
void *wbuf; addr_t *wbuf;
int cswl; int cswl;
void (*intv)(struct tub_s *, devstat_t *); void (*intv)(struct tub_s *, devstat_t *);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
...@@ -242,12 +250,13 @@ typedef struct tub_s { ...@@ -242,12 +250,13 @@ typedef struct tub_s {
/* Stuff for tty-driver support */ /* Stuff for tty-driver support */
struct tty_struct *tty; struct tty_struct *tty;
char tty_input[GEOM_MAXINPLEN]; /* tty input area */ char *tty_input; /* tty input area */
int tty_inattr; /* input-area field attribute */ int tty_inattr; /* input-area field attribute */
#define TTY_OUTPUT_SIZE 1024 #define TTY_OUTPUT_SIZE 1024
bcb_t tty_bcb; /* Output buffer control info */ bcb_t tty_bcb; /* Output buffer control info */
int tty_oucol; /* Kludge */ int tty_oucol; /* Kludge */
int tty_nextlogx; /* next screen-log position */ int tty_nextlogx; /* next screen-log position */
int tty_savecursor; /* saved cursor position */
int tty_scrolltime; /* scrollforward wait time, sec */ int tty_scrolltime; /* scrollforward wait time, sec */
struct timer_list tty_stimer; /* timer for scrolltime */ struct timer_list tty_stimer; /* timer for scrolltime */
aid_t tty_aid[64]; /* Aid descriptors */ aid_t tty_aid[64]; /* Aid descriptors */
......
...@@ -216,8 +216,10 @@ tty3270_open(struct tty_struct *tty, struct file *filp) ...@@ -216,8 +216,10 @@ tty3270_open(struct tty_struct *tty, struct file *filp)
tubp->tty = tty; tubp->tty = tty;
tubp->lnopen = 1; tubp->lnopen = 1;
tty->driver_data = tubp; tty->driver_data = tubp;
tty->winsize.ws_row = tubp->geom_rows; tty->winsize.ws_row = tubp->geom_rows - 2;
tty->winsize.ws_col = tubp->geom_cols; tty->winsize.ws_col = tubp->geom_cols;
if (tubp->tty_input == NULL)
tubp->tty_input = kmalloc(GEOM_INPLEN, GFP_KERNEL|GFP_DMA);
tubp->tty_inattr = TF_INPUT; tubp->tty_inattr = TF_INPUT;
tubp->cmd = cmd; tubp->cmd = cmd;
tty3270_build(tubp); tty3270_build(tubp);
...@@ -801,7 +803,9 @@ tty3270_try_logging(tub_t *tubp) ...@@ -801,7 +803,9 @@ tty3270_try_logging(tub_t *tubp)
static void static void
tty3270_start_input(tub_t *tubp) tty3270_start_input(tub_t *tubp)
{ {
tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input); if (tubp->tty_input == NULL)
return;
tubp->ttyccw.cda = virt_to_phys(tubp->tty_input);
tubp->ttyccw.cmd_code = TC_READMOD; tubp->ttyccw.cmd_code = TC_READMOD;
tubp->ttyccw.count = GEOM_INPLEN; tubp->ttyccw.count = GEOM_INPLEN;
tubp->ttyccw.flags = CCW_FLAG_SLI; tubp->ttyccw.flags = CCW_FLAG_SLI;
...@@ -818,7 +822,8 @@ tty3270_do_input(tub_t *tubp) ...@@ -818,7 +822,8 @@ tty3270_do_input(tub_t *tubp)
char *aidstring; char *aidstring;
count = GEOM_INPLEN - tubp->cswl; count = GEOM_INPLEN - tubp->cswl;
in = tubp->tty_input; if ((in = tubp->tty_input) == NULL)
goto do_build;
tty3270_aid_get(tubp, in[0], &aidflags, &aidstring); tty3270_aid_get(tubp, in[0], &aidflags, &aidstring);
if (aidflags & TA_CLEARKEY) { if (aidflags & TA_CLEARKEY) {
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment