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) {
......
...@@ -15,10 +15,12 @@ ...@@ -15,10 +15,12 @@
extern int tty3270_io(tub_t *); extern int tty3270_io(tub_t *);
static void tty3270_set_status_area(tub_t *, char **); static void tty3270_set_status_area(tub_t *, char **);
static int tty3270_next_char(tub_t *); static int tty3270_next_char(tub_t *);
static void tty3270_unnext_char(tub_t *, char);
static void tty3270_update_log_area(tub_t *, char **); static void tty3270_update_log_area(tub_t *, char **);
static void tty3270_update_log_area_esc(tub_t *, char **); static int tty3270_update_log_area_esc(tub_t *, char **, int *);
static void tty3270_clear_log_area(tub_t *, char **); static void tty3270_clear_log_area(tub_t *, char **);
static void tty3270_tub_bufadr(tub_t *, int, char **); static void tty3270_tub_bufadr(tub_t *, int, char **);
static void tty3270_set_bufadr(tub_t *, char **, int *);
/* /*
* tty3270_clear_log_area(tub_t *tubp, char **cpp) * tty3270_clear_log_area(tub_t *tubp, char **cpp)
...@@ -47,69 +49,73 @@ tty3270_update_log_area(tub_t *tubp, char **cpp) ...@@ -47,69 +49,73 @@ tty3270_update_log_area(tub_t *tubp, char **cpp)
int sba_needed = 1; int sba_needed = 1;
char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH]; char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
/* Place characters */ /* Check for possible ESC sequence work to do */
while (tubp->tty_bcb.bc_cnt != 0) { if (tubp->tty_escx != 0) {
if (tubp->tty_nextlogx >= lastx) { /* If compiling new escape sequence */
if (sba_needed == 0 || tubp->stat == TBS_RUNNING) { if (tubp->tty_esca[0] == 0x1b) {
tubp->stat = TBS_MORE; if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
tty3270_set_status_area(tubp, cpp); return;
tty3270_scl_settimer(tubp); /* If esc seq needs refreshing after a write */
} } else if (tubp->tty_esca[0] == TO_SA) {
break; tty3270_set_bufadr(tubp, cpp, &sba_needed);
for (i = 0; i < tubp->tty_escx; i++)
*(*cpp)++ = tubp->tty_esca[i];
} else {
printk(KERN_WARNING "tty3270_update_log_area esca "
"character surprising: %.2x\n", tubp->tty_esca[0]);
} }
}
/* Check for room for another char + possible ESCs */ /* Place characters */
if (&(*cpp)[tubp->tty_escx + 1] >= overrun) while (tubp->tty_bcb.bc_cnt != 0) {
/* Check for room. TAB could take up to 4 chars. */
if (&(*cpp)[4] >= overrun)
break; break;
/* Fetch a character */ /* Fetch a character */
if ((c = tty3270_next_char(tubp)) == -1) if ((c = tty3270_next_char(tubp)) == -1)
break; break;
/* Add a Set-Buffer-Address Order if we haven't */
if (sba_needed) {
sba_needed = 0;
*(*cpp)++ = TO_SBA;
TUB_BUFADR(tubp->tty_nextlogx, cpp);
}
switch(c) { switch(c) {
default: default:
if (c < ' ') /* Blank it if we don't know it */ if (tubp->tty_nextlogx >= lastx) {
c = ' '; if (sba_needed == 0 ||
for (i = 0; i < tubp->tty_escx; i++) tubp->stat == TBS_RUNNING) {
*(*cpp)++ = tubp->tty_esca[i]; tty3270_unnext_char(tubp, c);
tubp->tty_escx = 0; tubp->stat = TBS_MORE;
*(*cpp)++ = tub_ascebc[(int)c]; tty3270_set_status_area(tubp, cpp);
tty3270_scl_settimer(tubp);
}
goto do_return;
}
tty3270_set_bufadr(tubp, cpp, &sba_needed);
/* Use blank if we don't know the character */
*(*cpp)++ = tub_ascebc[(int)(c < ' '? ' ': c)];
tubp->tty_nextlogx++; tubp->tty_nextlogx++;
tubp->tty_oucol++; tubp->tty_oucol++;
break; break;
case 0x1b: /* ESC */ case 0x1b: /* ESC */
tty3270_update_log_area_esc(tubp, cpp); tubp->tty_escx = 0;
if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
return;
break;
case '\r': /* 0x0d -- Carriage Return */
tubp->tty_nextlogx -=
tubp->tty_nextlogx % GEOM_COLS;
sba_needed = 1;
break; break;
case '\r': case '\n': /* 0x0a -- New Line */
break; /* completely ignore 0x0d = CR. */
case '\n':
if (tubp->tty_oucol == GEOM_COLS) { if (tubp->tty_oucol == GEOM_COLS) {
tubp->tty_oucol = 0; tubp->tty_oucol = 0;
break; break;
} }
next = (tubp->tty_nextlogx + GEOM_COLS) / next = (tubp->tty_nextlogx + GEOM_COLS) /
GEOM_COLS * GEOM_COLS; GEOM_COLS * GEOM_COLS;
next = MIN(next, lastx);
fill = next - tubp->tty_nextlogx;
if (fill < 5) {
for (i = 0; i < fill; i++)
*(*cpp)++ = tub_ascebc[' '];
} else {
*(*cpp)++ = TO_RA;
TUB_BUFADR(next, cpp);
*(*cpp)++ = tub_ascebc[' '];
}
tubp->tty_nextlogx = next; tubp->tty_nextlogx = next;
tubp->tty_oucol = 0; tubp->tty_oucol = 0;
sba_needed = 1;
break; break;
case '\t': case '\t': /* 0x09 -- Tabulate */
fill = (tubp->tty_nextlogx % GEOM_COLS) % 8; fill = (tubp->tty_nextlogx % GEOM_COLS) % 8;
for (; fill < 8; fill++) { for (; fill < 8; fill++) {
if (tubp->tty_nextlogx >= lastx) if (tubp->tty_nextlogx >= lastx)
...@@ -119,72 +125,116 @@ tty3270_update_log_area(tub_t *tubp, char **cpp) ...@@ -119,72 +125,116 @@ tty3270_update_log_area(tub_t *tubp, char **cpp)
tubp->tty_oucol++; tubp->tty_oucol++;
} }
break; break;
case '\a': case '\a': /* 0x07 -- Alarm */
tubp->flags |= TUB_ALARM; tubp->flags |= TUB_ALARM;
break; break;
case '\f': case '\f': /* 0x0c -- Form Feed */
tty3270_clear_log_area(tubp, cpp); tty3270_clear_log_area(tubp, cpp);
break; break;
case 0xf: /* SuSE "exit alternate mode" */
break;
} }
} }
do_return:
} }
#define NUMQUANT 8 #define NUMQUANT 8
static void static int
tty3270_update_log_area_esc(tub_t *tubp, char **cpp) tty3270_update_log_area_esc(tub_t *tubp, char **cpp, int *sba_needed)
{ {
int lastx = GEOM_INPUT;
int c; int c;
int i; int i, j;
int start, next, fill; int start, end, next;
int quant[NUMQUANT]; int quant[NUMQUANT];
char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
char sabuf[NUMQUANT*3], *sap = sabuf, *cp;
if ((c = tty3270_next_char(tubp)) != '[') { /* If starting a sequence, stuff ESC at [0] */
return; if (tubp->tty_escx == 0)
tubp->tty_esca[tubp->tty_escx++] = 0x1b;
/* Now that sequence is started, see if room in buffer */
if (&(*cpp)[NUMQUANT * 3] >= overrun)
return tubp->tty_escx;
/* Gather the rest of the sequence's characters */
while (tubp->tty_escx < sizeof tubp->tty_esca) {
if ((c = tty3270_next_char(tubp)) == -1)
return tubp->tty_escx;
if (tubp->tty_escx == 1) {
switch(c) {
case '[':
tubp->tty_esca[tubp->tty_escx++] = c;
continue;
case '7':
tubp->tty_savecursor = tubp->tty_nextlogx;
goto done_return;
case '8':
next = tubp->tty_savecursor;
goto do_setcur;
default:
goto error_return;
}
}
tubp->tty_esca[tubp->tty_escx++] = c;
if (c != ';' && (c < '0' || c > '9'))
break;
} }
/* /* Check for overrun */
* Parse potentially empty string "nn;nn;nn..." if (tubp->tty_escx == sizeof tubp->tty_esca)
*/ goto error_return;
/* Parse potentially empty string "nn;nn;nn..." */
i = -1; i = -1;
j = 2; /* skip ESC, [ */
c = ';'; c = ';';
do { do {
if (c == ';') { if (c == ';') {
if (++i == NUMQUANT) if (++i == NUMQUANT)
break; goto error_return;
quant[i] = 0; quant[i] = 0;
} else if (c < '0' || c > '9') { } else if (c < '0' || c > '9') {
break; break;
} else { } else {
quant[i] = quant[i] * 10 + c - '0'; quant[i] = quant[i] * 10 + c - '0';
} }
} while ((c = tty3270_next_char(tubp)) != -1); c = tubp->tty_esca[j];
if (c == -1) { } while (j++ < tubp->tty_escx);
return;
} /* Add 3270 data stream output to execute the sequence */
if (i >= NUMQUANT) {
return;
}
switch(c) { switch(c) {
case -1:
return;
case 'm': /* Set Attribute */ case 'm': /* Set Attribute */
for (next = 0; next <= i; next++) { for (next = 0; next <= i; next++) {
int type = -1, value = 0; int type = -1, value = 0;
if (tubp->tty_escx + 3 > MAX_TTY_ESCA)
break;
switch(quant[next]) { switch(quant[next]) {
case 0: /* Reset */ case 0: /* Reset */
tubp->tty_esca[tubp->tty_escx++] = TO_SA; next = tubp->tty_nextlogx;
tubp->tty_esca[tubp->tty_escx++] = TAT_RESET; tty3270_set_bufadr(tubp, cpp, sba_needed);
tubp->tty_esca[tubp->tty_escx++] = TAR_RESET; *(*cpp)++ = TO_SA;
*(*cpp)++ = TAT_EXTHI;
*(*cpp)++ = TAX_RESET;
*(*cpp)++ = TO_SA;
*(*cpp)++ = TAT_COLOR;
*(*cpp)++ = TAC_RESET;
tubp->tty_nextlogx = next;
*sba_needed = 1;
sap = sabuf;
break; break;
case 1: /* Bright */ case 1: /* Bright */
break;
case 2: /* Dim */ case 2: /* Dim */
break;
case 4: /* Underscore */ case 4: /* Underscore */
type = TAT_EXTHI; value = TAX_UNDER;
break;
case 5: /* Blink */ case 5: /* Blink */
type = TAT_EXTHI; value = TAX_BLINK;
break;
case 7: /* Reverse */ case 7: /* Reverse */
type = TAT_EXTHI; value = TAX_REVER;
break;
case 8: /* Hidden */ case 8: /* Hidden */
break; /* For now ... */ break; /* For now ... */
/* Foreground Colors */ /* Foreground Colors */
...@@ -230,53 +280,110 @@ tty3270_update_log_area_esc(tub_t *tubp, char **cpp) ...@@ -230,53 +280,110 @@ tty3270_update_log_area_esc(tub_t *tubp, char **cpp)
break; break;
} }
if (type != -1) { if (type != -1) {
tubp->tty_esca[tubp->tty_escx++] = TO_SA; tty3270_set_bufadr(tubp, cpp, sba_needed);
tubp->tty_esca[tubp->tty_escx++] = type; *(*cpp)++ = TO_SA;
tubp->tty_esca[tubp->tty_escx++] = value; *(*cpp)++ = type;
*(*cpp)++ = value;
*sap++ = TO_SA;
*sap++ = type;
*sap++ = value;
} }
} }
break; break;
case 'H': /* Cursor Home */ case 'H': /* Cursor Home */
case 'f': /* Force Cursor Position */ case 'f': /* Force Cursor Position */
return; if (quant[0]) quant[0]--;
if (quant[1]) quant[1]--;
next = quant[0] * GEOM_COLS + quant[1];
goto do_setcur;
case 'A': /* Cursor Up */ case 'A': /* Cursor Up */
return; if (quant[i] == 0) quant[i] = 1;
next = tubp->tty_nextlogx - GEOM_COLS * quant[i];
goto do_setcur;
case 'B': /* Cursor Down */ case 'B': /* Cursor Down */
return; if (quant[i] == 0) quant[i] = 1;
next = tubp->tty_nextlogx + GEOM_COLS * quant[i];
goto do_setcur;
case 'C': /* Cursor Forward */ case 'C': /* Cursor Forward */
if (quant[i] == 0) quant[i] = 1;
next = tubp->tty_nextlogx % GEOM_COLS; next = tubp->tty_nextlogx % GEOM_COLS;
start = tubp->tty_nextlogx - next; start = tubp->tty_nextlogx - next;
next = start + MIN(next + quant[i], GEOM_COLS - 1); next = start + MIN(next + quant[i], GEOM_COLS - 1);
next = MIN(next, lastx); goto do_setcur;
do_fill:
fill = next - tubp->tty_nextlogx;
if (fill < 5) {
for (i = 0; i < fill; i++)
*(*cpp)++ = tub_ascebc[' '];
} else {
*(*cpp)++ = TO_RA;
TUB_BUFADR(next, cpp);
*(*cpp)++ = tub_ascebc[' '];
}
tubp->tty_nextlogx = next;
tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
break;
case 'D': /* Cursor Backward */ case 'D': /* Cursor Backward */
if (quant[i] == 0) quant[i] = 1;
next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS); next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS);
tubp->tty_nextlogx -= next; next = tubp->tty_nextlogx - next;
goto do_setcur;
case 'G':
if (quant[0]) quant[0]--;
next = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS + quant[0];
do_setcur:
if (next < 0)
break;
tubp->tty_nextlogx = next;
tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS; tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
*sba_needed = 1;
break;
case 'r': /* Define scroll area */
start = quant[0];
if (start <= 0) start = 1;
if (start > GEOM_ROWS - 2) start = GEOM_ROWS - 2;
tubp->tty_nextlogx = (start - 1) * GEOM_COLS;
tubp->tty_oucol = 0;
*sba_needed = 1;
break;
case 'X': /* Erase for n chars from cursor */
start = tubp->tty_nextlogx;
end = start + (quant[0]?: 1);
goto do_fill;
case 'J': /* Erase to screen end from cursor */
*(*cpp)++ = TO_SBA;
TUB_BUFADR(tubp->tty_nextlogx, cpp);
*(*cpp)++ = TO_RA;
TUB_BUFADR(GEOM_INPUT, cpp);
*(*cpp)++ = tub_ascebc[' '];
*(*cpp)++ = TO_SBA; *(*cpp)++ = TO_SBA;
TUB_BUFADR(tubp->tty_nextlogx, cpp); TUB_BUFADR(tubp->tty_nextlogx, cpp);
break; break;
case 'G': case 'K':
start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS; start = tubp->tty_nextlogx;
next = MIN(quant[i], GEOM_COLS - 1) + start; end = (start + GEOM_COLS) / GEOM_COLS * GEOM_COLS;
next = MIN(next, lastx); do_fill:
goto do_fill; if (start >= GEOM_INPUT)
break;
if (end > GEOM_INPUT)
end = GEOM_INPUT;
if (end <= start)
break;
*(*cpp)++ = TO_SBA;
TUB_BUFADR(start, cpp);
if (end - start > 4) {
*(*cpp)++ = TO_RA;
TUB_BUFADR(end, cpp);
*(*cpp)++ = tub_ascebc[' '];
} else while (start++ < end) {
*(*cpp)++ = tub_ascebc[' '];
}
tubp->tty_nextlogx = end;
tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
*sba_needed = 1;
break;
} }
done_return:
tubp->tty_escx = 0;
cp = sabuf;
while (cp != sap)
tubp->tty_esca[tubp->tty_escx++] = *cp++;
return 0;
error_return:
tubp->tty_escx = 0;
return 0;
} }
static int static int
tty3270_next_char(tub_t *tubp) tty3270_next_char(tub_t *tubp)
{ {
...@@ -293,6 +400,18 @@ tty3270_next_char(tub_t *tubp) ...@@ -293,6 +400,18 @@ tty3270_next_char(tub_t *tubp)
return c; return c;
} }
static void
tty3270_unnext_char(tub_t *tubp, char c)
{
bcb_t *ib;
ib = &tubp->tty_bcb;
if (ib->bc_rd == 0)
ib->bc_rd = ib->bc_len;
ib->bc_buf[--ib->bc_rd] = c;
ib->bc_cnt++;
}
static void static void
tty3270_clear_input_area(tub_t *tubp, char **cpp) tty3270_clear_input_area(tub_t *tubp, char **cpp)
...@@ -452,3 +571,17 @@ tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp) ...@@ -452,3 +571,17 @@ tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp)
*(*cpp)++ = tub_ebcgraf[adr & 0x3f]; *(*cpp)++ = tub_ebcgraf[adr & 0x3f];
} }
} }
static void
tty3270_set_bufadr(tub_t *tubp, char **cpp, int *sba_needed)
{
if (!*sba_needed)
return;
if (tubp->tty_nextlogx >= GEOM_INPUT) {
tubp->tty_nextlogx = GEOM_INPUT - 1;
tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
}
*(*cpp)++ = TO_SBA;
TUB_BUFADR(tubp->tty_nextlogx, cpp);
*sba_needed = 0;
}
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