/* * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC * * tubttybld.c -- Linemode tty driver screen-building functions * * * * * * Author: Richard Hitt */ #include "tubio.h" extern int tty3270_io(tub_t *); static void tty3270_set_status_area(tub_t *, char **); static int tty3270_next_char(tub_t *); static void tty3270_update_log_area(tub_t *, char **); static void tty3270_update_log_area_esc(tub_t *, char **); static void tty3270_clear_log_area(tub_t *, char **); static void tty3270_tub_bufadr(tub_t *, int, char **); /* * tty3270_clear_log_area(tub_t *tubp, char **cpp) */ static void tty3270_clear_log_area(tub_t *tubp, char **cpp) { *(*cpp)++ = TO_SBA; TUB_BUFADR(GEOM_LOG, cpp); *(*cpp)++ = TO_SF; *(*cpp)++ = TF_LOG; *(*cpp)++ = TO_RA; TUB_BUFADR(GEOM_INPUT, cpp); *(*cpp)++ = '\0'; tubp->tty_oucol = tubp->tty_nextlogx = 0; *(*cpp)++ = TO_SBA; TUB_BUFADR(tubp->tty_nextlogx, cpp); } static void tty3270_update_log_area(tub_t *tubp, char **cpp) { int lastx = GEOM_INPUT; int c; int next, fill, i; int sba_needed = 1; char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH]; /* Place characters */ while (tubp->tty_bcb.bc_cnt != 0) { if (tubp->tty_nextlogx >= lastx) { if (sba_needed == 0 || tubp->stat == TBS_RUNNING) { tubp->stat = TBS_MORE; tty3270_set_status_area(tubp, cpp); tty3270_scl_settimer(tubp); } break; } /* Check for room for another char + possible ESCs */ if (&(*cpp)[tubp->tty_escx + 1] >= overrun) break; /* Fetch a character */ if ((c = tty3270_next_char(tubp)) == -1) 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) { default: if (c < ' ') /* Blank it if we don't know it */ c = ' '; for (i = 0; i < tubp->tty_escx; i++) *(*cpp)++ = tubp->tty_esca[i]; tubp->tty_escx = 0; *(*cpp)++ = tub_ascebc[(int)c]; tubp->tty_nextlogx++; tubp->tty_oucol++; break; case 0x1b: /* ESC */ tty3270_update_log_area_esc(tubp, cpp); break; case '\r': break; /* completely ignore 0x0d = CR. */ case '\n': if (tubp->tty_oucol == GEOM_COLS) { tubp->tty_oucol = 0; break; } next = (tubp->tty_nextlogx + 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_oucol = 0; break; case '\t': fill = (tubp->tty_nextlogx % GEOM_COLS) % 8; for (; fill < 8; fill++) { if (tubp->tty_nextlogx >= lastx) break; *(*cpp)++ = tub_ascebc[' ']; tubp->tty_nextlogx++; tubp->tty_oucol++; } break; case '\a': tubp->flags |= TUB_ALARM; break; case '\f': tty3270_clear_log_area(tubp, cpp); break; } } } #define NUMQUANT 8 static void tty3270_update_log_area_esc(tub_t *tubp, char **cpp) { int lastx = GEOM_INPUT; int c; int i; int start, next, fill; int quant[NUMQUANT]; if ((c = tty3270_next_char(tubp)) != '[') { return; } /* * Parse potentially empty string "nn;nn;nn..." */ i = -1; c = ';'; do { if (c == ';') { if (++i == NUMQUANT) break; quant[i] = 0; } else if (c < '0' || c > '9') { break; } else { quant[i] = quant[i] * 10 + c - '0'; } } while ((c = tty3270_next_char(tubp)) != -1); if (c == -1) { return; } if (i >= NUMQUANT) { return; } switch(c) { case -1: return; case 'm': /* Set Attribute */ for (next = 0; next <= i; next++) { int type = -1, value = 0; if (tubp->tty_escx + 3 > MAX_TTY_ESCA) break; switch(quant[next]) { case 0: /* Reset */ tubp->tty_esca[tubp->tty_escx++] = TO_SA; tubp->tty_esca[tubp->tty_escx++] = TAT_RESET; tubp->tty_esca[tubp->tty_escx++] = TAR_RESET; break; case 1: /* Bright */ case 2: /* Dim */ case 4: /* Underscore */ case 5: /* Blink */ case 7: /* Reverse */ case 8: /* Hidden */ break; /* For now ... */ /* Foreground Colors */ case 30: /* Black */ type = TAT_COLOR; value = TAC_DEFAULT; break; case 31: /* Red */ type = TAT_COLOR; value = TAC_RED; break; case 32: /* Green */ type = TAT_COLOR; value = TAC_GREEN; break; case 33: /* Yellow */ type = TAT_COLOR; value = TAC_YELLOW; break; case 34: /* Blue */ type = TAT_COLOR; value = TAC_BLUE; break; case 35: /* Magenta */ type = TAT_COLOR; value = TAC_PINK; break; case 36: /* Cyan */ type = TAT_COLOR; value = TAC_TURQ; break; case 37: /* White */ type = TAT_COLOR; value = TAC_WHITE; break; case 39: /* Black */ type = TAT_COLOR; value = TAC_DEFAULT; break; /* Background Colors */ case 40: /* Black */ case 41: /* Red */ case 42: /* Green */ case 43: /* Yellow */ case 44: /* Blue */ case 45: /* Magenta */ case 46: /* Cyan */ case 47: /* White */ break; /* For now ... */ /* Oops */ default: break; } if (type != -1) { tubp->tty_esca[tubp->tty_escx++] = TO_SA; tubp->tty_esca[tubp->tty_escx++] = type; tubp->tty_esca[tubp->tty_escx++] = value; } } break; case 'H': /* Cursor Home */ case 'f': /* Force Cursor Position */ return; case 'A': /* Cursor Up */ return; case 'B': /* Cursor Down */ return; case 'C': /* Cursor Forward */ next = tubp->tty_nextlogx % GEOM_COLS; start = tubp->tty_nextlogx - next; next = start + MIN(next + quant[i], GEOM_COLS - 1); next = MIN(next, lastx); 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 */ next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS); tubp->tty_nextlogx -= next; tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS; *(*cpp)++ = TO_SBA; TUB_BUFADR(tubp->tty_nextlogx, cpp); break; case 'G': start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS; next = MIN(quant[i], GEOM_COLS - 1) + start; next = MIN(next, lastx); goto do_fill; } } static int tty3270_next_char(tub_t *tubp) { int c; bcb_t *ib; ib = &tubp->tty_bcb; if (ib->bc_cnt == 0) return -1; c = ib->bc_buf[ib->bc_rd++]; if (ib->bc_rd == ib->bc_len) ib->bc_rd = 0; ib->bc_cnt--; return c; } static void tty3270_clear_input_area(tub_t *tubp, char **cpp) { *(*cpp)++ = TO_SBA; TUB_BUFADR(GEOM_INPUT, cpp); *(*cpp)++ = TO_SF; *(*cpp)++ = tubp->tty_inattr; *(*cpp)++ = TO_IC; *(*cpp)++ = TO_RA; TUB_BUFADR(GEOM_STAT, cpp); *(*cpp)++ = '\0'; } static void tty3270_update_input_area(tub_t *tubp, char **cpp) { int len; *(*cpp)++ = TO_SBA; TUB_BUFADR(GEOM_INPUT, cpp); *(*cpp)++ = TO_SF; *(*cpp)++ = TF_INMDT; len = strlen(tubp->tty_input); memcpy(*cpp, tubp->tty_input, len); *cpp += len; *(*cpp)++ = TO_IC; len = GEOM_INPLEN - len; if (len > 4) { *(*cpp)++ = TO_RA; TUB_BUFADR(GEOM_STAT, cpp); *(*cpp)++ = '\0'; } else { for (; len > 0; len--) *(*cpp)++ = '\0'; } } /* * tty3270_set_status_area(tub_t *tubp, char **cpp) */ static void tty3270_set_status_area(tub_t *tubp, char **cpp) { char *sp; if (tubp->stat == TBS_RUNNING) sp = TS_RUNNING; else if (tubp->stat == TBS_MORE) sp = TS_MORE; else if (tubp->stat == TBS_HOLD) sp = TS_HOLD; else sp = "Linux Whatstat"; *(*cpp)++ = TO_SBA; TUB_BUFADR(GEOM_STAT, cpp); *(*cpp)++ = TO_SF; *(*cpp)++ = TF_STAT; memcpy(*cpp, sp, sizeof TS_RUNNING); TUB_ASCEBC(*cpp, sizeof TS_RUNNING); *cpp += sizeof TS_RUNNING; } /* * tty3270_build() -- build an output stream */ int tty3270_build(tub_t *tubp) { char *cp, *startcp; int chancmd; int writecc = TW_KR; int force = 0; if (tubp->mode == TBM_FS) return 0; cp = startcp = *tubp->ttyscreen + 1; switch(tubp->cmd) { default: printk(KERN_WARNING "tty3270_build unknown command %d\n", tubp->cmd); return 0; case TBC_OPEN: tbc_open: tubp->flags &= ~TUB_INPUT_HACK; chancmd = TC_EWRITEA; tty3270_clear_input_area(tubp, &cp); tty3270_set_status_area(tubp, &cp); tty3270_clear_log_area(tubp, &cp); break; case TBC_UPDLOG: if (tubp->flags & TUB_INPUT_HACK) goto tbc_open; chancmd = TC_WRITE; writecc = TW_NONE; tty3270_update_log_area(tubp, &cp); break; case TBC_KRUPDLOG: chancmd = TC_WRITE; force = 1; tty3270_update_log_area(tubp, &cp); break; case TBC_CLRUPDLOG: chancmd = TC_WRITE; tty3270_set_status_area(tubp, &cp); tty3270_clear_log_area(tubp, &cp); tty3270_update_log_area(tubp, &cp); break; case TBC_UPDATE: chancmd = TC_EWRITEA; tubp->tty_oucol = tubp->tty_nextlogx = 0; tty3270_clear_input_area(tubp, &cp); tty3270_set_status_area(tubp, &cp); tty3270_update_log_area(tubp, &cp); break; case TBC_UPDSTAT: chancmd = TC_WRITE; tty3270_set_status_area(tubp, &cp); break; case TBC_CLRINPUT: chancmd = TC_WRITE; tty3270_clear_input_area(tubp, &cp); break; case TBC_UPDINPUT: chancmd = TC_WRITE; tty3270_update_input_area(tubp, &cp); break; } /* Set Write Control Character and start I/O */ if (force == 0 && cp == startcp && (tubp->flags & TUB_ALARM) == 0) return 0; if (tubp->flags & TUB_ALARM) { tubp->flags &= ~TUB_ALARM; writecc |= TW_PLUSALARM; } **tubp->ttyscreen = writecc; tubp->ttyccw.cmd_code = chancmd; tubp->ttyccw.flags = CCW_FLAG_SLI; tubp->ttyccw.cda = virt_to_phys(*tubp->ttyscreen); tubp->ttyccw.count = cp - *tubp->ttyscreen; tty3270_io(tubp); return 1; } static void tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp) { if (tubp->tty_14bitadr) { *(*cpp)++ = (adr >> 8) & 0x3f; *(*cpp)++ = adr & 0xff; } else { *(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f]; *(*cpp)++ = tub_ebcgraf[adr & 0x3f]; } }