URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [s390/] [char/] [tubttybld.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * 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_unnext_char(tub_t *, char); static void tty3270_update_log_area(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_tub_bufadr(tub_t *, int, char **); static void tty3270_set_bufadr(tub_t *, char **, int *); /* * 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]; /* Check for possible ESC sequence work to do */ if (tubp->tty_escx != 0) { /* If compiling new escape sequence */ if (tubp->tty_esca[0] == 0x1b) { if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed)) return; /* If esc seq needs refreshing after a write */ } else if (tubp->tty_esca[0] == TO_SA) { 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]); } } /* Place characters */ while (tubp->tty_bcb.bc_cnt != 0) { /* Check for room. TAB could take up to 4 chars. */ if (&(*cpp)[4] >= overrun) break; /* Fetch a character */ if ((c = tty3270_next_char(tubp)) == -1) break; switch(c) { default: if (tubp->tty_nextlogx >= lastx) { if (sba_needed == 0 || tubp->stat == TBS_RUNNING) { tty3270_unnext_char(tubp, c); tubp->stat = TBS_MORE; 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_oucol++; break; case 0x1b: /* ESC */ 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; case '\n': /* 0x0a -- New Line */ if (tubp->tty_oucol == GEOM_COLS) { tubp->tty_oucol = 0; break; } next = (tubp->tty_nextlogx + GEOM_COLS) / GEOM_COLS * GEOM_COLS; tubp->tty_nextlogx = next; tubp->tty_oucol = 0; sba_needed = 1; break; case '\t': /* 0x09 -- Tabulate */ tty3270_set_bufadr(tubp, cpp, &sba_needed); 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': /* 0x07 -- Alarm */ tubp->flags |= TUB_ALARM; break; case '\f': /* 0x0c -- Form Feed */ tty3270_clear_log_area(tubp, cpp); break; case 0xf: /* SuSE "exit alternate mode" */ break; } } do_return: } #define NUMQUANT 8 static int tty3270_update_log_area_esc(tub_t *tubp, char **cpp, int *sba_needed) { int c; int i, j; int start, end, next; int quant[NUMQUANT]; char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH]; char sabuf[NUMQUANT*3], *sap = sabuf, *cp; /* If starting a sequence, stuff ESC at [0] */ 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 */ if (tubp->tty_escx == sizeof tubp->tty_esca) goto error_return; /* Parse potentially empty string "nn;nn;nn..." */ i = -1; j = 2; /* skip ESC, [ */ c = ';'; do { if (c == ';') { if (++i == NUMQUANT) goto error_return; quant[i] = 0; } else if (c < '0' || c > '9') { break; } else { quant[i] = quant[i] * 10 + c - '0'; } c = tubp->tty_esca[j]; } while (j++ < tubp->tty_escx); /* Add 3270 data stream output to execute the sequence */ switch(c) { case 'm': /* Set Attribute */ for (next = 0; next <= i; next++) { int type = -1, value = 0; switch(quant[next]) { case 0: /* Reset */ next = tubp->tty_nextlogx; tty3270_set_bufadr(tubp, cpp, sba_needed); *(*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; case 1: /* Bright */ break; case 2: /* Dim */ break; case 4: /* Underscore */ type = TAT_EXTHI; value = TAX_UNDER; break; case 5: /* Blink */ type = TAT_EXTHI; value = TAX_BLINK; break; case 7: /* Reverse */ type = TAT_EXTHI; value = TAX_REVER; break; 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) { tty3270_set_bufadr(tubp, cpp, sba_needed); *(*cpp)++ = TO_SA; *(*cpp)++ = type; *(*cpp)++ = value; *sap++ = TO_SA; *sap++ = type; *sap++ = value; } } break; case 'H': /* Cursor Home */ case 'f': /* Force Cursor Position */ if (quant[0]) quant[0]--; if (quant[1]) quant[1]--; next = quant[0] * GEOM_COLS + quant[1]; goto do_setcur; case 'A': /* Cursor Up */ if (quant[i] == 0) quant[i] = 1; next = tubp->tty_nextlogx - GEOM_COLS * quant[i]; goto do_setcur; case 'B': /* Cursor Down */ if (quant[i] == 0) quant[i] = 1; next = tubp->tty_nextlogx + GEOM_COLS * quant[i]; goto do_setcur; case 'C': /* Cursor Forward */ if (quant[i] == 0) quant[i] = 1; next = tubp->tty_nextlogx % GEOM_COLS; start = tubp->tty_nextlogx - next; next = start + MIN(next + quant[i], GEOM_COLS - 1); goto do_setcur; case 'D': /* Cursor Backward */ if (quant[i] == 0) quant[i] = 1; next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS); 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; *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; TUB_BUFADR(tubp->tty_nextlogx, cpp); break; case 'K': start = tubp->tty_nextlogx; end = (start + GEOM_COLS) / GEOM_COLS * GEOM_COLS; 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 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_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 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]; } } 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; }