1 /*
2 * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
3 *
4 * tubttybld.c -- Linemode tty driver screen-building functions
5 *
6 *
7 *
8 *
9 *
10 * Author: Richard Hitt
11 */
12
13 #include "tubio.h"
14
15 extern int tty3270_io(tub_t *);
16 static void tty3270_set_status_area(tub_t *, char **);
17 static int tty3270_next_char(tub_t *);
18 static void tty3270_unnext_char(tub_t *, char);
19 static void tty3270_update_log_area(tub_t *, char **);
20 static int tty3270_update_log_area_esc(tub_t *, char **, int *);
21 static void tty3270_clear_log_area(tub_t *, char **);
22 static void tty3270_tub_bufadr(tub_t *, int, char **);
23 static void tty3270_set_bufadr(tub_t *, char **, int *);
24
25 /*
26 * tty3270_clear_log_area(tub_t *tubp, char **cpp)
27 */
28 static void
tty3270_clear_log_area(tub_t * tubp,char ** cpp)29 tty3270_clear_log_area(tub_t *tubp, char **cpp)
30 {
31 *(*cpp)++ = TO_SBA;
32 TUB_BUFADR(GEOM_LOG, cpp);
33 *(*cpp)++ = TO_SF;
34 *(*cpp)++ = TF_LOG;
35 *(*cpp)++ = TO_RA;
36 TUB_BUFADR(GEOM_INPUT, cpp);
37 *(*cpp)++ = '\0';
38 tubp->tty_oucol = tubp->tty_nextlogx = 0;
39 *(*cpp)++ = TO_SBA;
40 TUB_BUFADR(tubp->tty_nextlogx, cpp);
41 }
42
43 static void
tty3270_update_log_area(tub_t * tubp,char ** cpp)44 tty3270_update_log_area(tub_t *tubp, char **cpp)
45 {
46 int lastx = GEOM_INPUT;
47 int c;
48 int next, fill, i;
49 int sba_needed = 1;
50 char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
51
52 /* Check for possible ESC sequence work to do */
53 if (tubp->tty_escx != 0) {
54 /* If compiling new escape sequence */
55 if (tubp->tty_esca[0] == 0x1b) {
56 if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
57 return;
58 /* If esc seq needs refreshing after a write */
59 } else if (tubp->tty_esca[0] == TO_SA) {
60 tty3270_set_bufadr(tubp, cpp, &sba_needed);
61 for (i = 0; i < tubp->tty_escx; i++)
62 *(*cpp)++ = tubp->tty_esca[i];
63 } else {
64 printk(KERN_WARNING "tty3270_update_log_area esca "
65 "character surprising: %.2x\n", tubp->tty_esca[0]);
66 }
67 }
68
69 /* Place characters */
70 while (tubp->tty_bcb.bc_cnt != 0) {
71 /* Check for room. TAB could take up to 4 chars. */
72 if (&(*cpp)[4] >= overrun)
73 break;
74
75 /* Fetch a character */
76 if ((c = tty3270_next_char(tubp)) == -1)
77 break;
78
79 switch(c) {
80 default:
81 if (tubp->tty_nextlogx >= lastx) {
82 if (sba_needed == 0 ||
83 tubp->stat == TBS_RUNNING) {
84 tty3270_unnext_char(tubp, c);
85 tubp->stat = TBS_MORE;
86 tty3270_set_status_area(tubp, cpp);
87 tty3270_scl_settimer(tubp);
88 }
89 goto do_return;
90 }
91 tty3270_set_bufadr(tubp, cpp, &sba_needed);
92 /* Use blank if we don't know the character */
93 *(*cpp)++ = tub_ascebc[(int)(c < ' '? ' ': c)];
94 tubp->tty_nextlogx++;
95 tubp->tty_oucol++;
96 break;
97 case 0x1b: /* ESC */
98 tubp->tty_escx = 0;
99 if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
100 return;
101 break;
102 case '\r': /* 0x0d -- Carriage Return */
103 tubp->tty_nextlogx -=
104 tubp->tty_nextlogx % GEOM_COLS;
105 sba_needed = 1;
106 break;
107 case '\n': /* 0x0a -- New Line */
108 if (tubp->tty_oucol == GEOM_COLS) {
109 tubp->tty_oucol = 0;
110 break;
111 }
112 next = (tubp->tty_nextlogx + GEOM_COLS) /
113 GEOM_COLS * GEOM_COLS;
114 tubp->tty_nextlogx = next;
115 tubp->tty_oucol = 0;
116 sba_needed = 1;
117 break;
118 case '\t': /* 0x09 -- Tabulate */
119 tty3270_set_bufadr(tubp, cpp, &sba_needed);
120 fill = (tubp->tty_nextlogx % GEOM_COLS) % 8;
121 for (; fill < 8; fill++) {
122 if (tubp->tty_nextlogx >= lastx)
123 break;
124 *(*cpp)++ = tub_ascebc[' '];
125 tubp->tty_nextlogx++;
126 tubp->tty_oucol++;
127 }
128 break;
129 case '\a': /* 0x07 -- Alarm */
130 tubp->flags |= TUB_ALARM;
131 break;
132 case '\f': /* 0x0c -- Form Feed */
133 tty3270_clear_log_area(tubp, cpp);
134 break;
135 case 0xf: /* SuSE "exit alternate mode" */
136 break;
137 }
138 }
139 do_return:
140 }
141
142 #define NUMQUANT 8
143 static int
tty3270_update_log_area_esc(tub_t * tubp,char ** cpp,int * sba_needed)144 tty3270_update_log_area_esc(tub_t *tubp, char **cpp, int *sba_needed)
145 {
146 int c;
147 int i, j;
148 int start, end, next;
149 int quant[NUMQUANT];
150 char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
151 char sabuf[NUMQUANT*3], *sap = sabuf, *cp;
152
153 /* If starting a sequence, stuff ESC at [0] */
154 if (tubp->tty_escx == 0)
155 tubp->tty_esca[tubp->tty_escx++] = 0x1b;
156
157 /* Now that sequence is started, see if room in buffer */
158 if (&(*cpp)[NUMQUANT * 3] >= overrun)
159 return tubp->tty_escx;
160
161 /* Gather the rest of the sequence's characters */
162 while (tubp->tty_escx < sizeof tubp->tty_esca) {
163 if ((c = tty3270_next_char(tubp)) == -1)
164 return tubp->tty_escx;
165 if (tubp->tty_escx == 1) {
166 switch(c) {
167 case '[':
168 tubp->tty_esca[tubp->tty_escx++] = c;
169 continue;
170 case '7':
171 tubp->tty_savecursor = tubp->tty_nextlogx;
172 goto done_return;
173 case '8':
174 next = tubp->tty_savecursor;
175 goto do_setcur;
176 default:
177 goto error_return;
178 }
179 }
180 tubp->tty_esca[tubp->tty_escx++] = c;
181 if (c != ';' && (c < '0' || c > '9'))
182 break;
183 }
184
185 /* Check for overrun */
186 if (tubp->tty_escx == sizeof tubp->tty_esca)
187 goto error_return;
188
189 /* Parse potentially empty string "nn;nn;nn..." */
190 i = -1;
191 j = 2; /* skip ESC, [ */
192 c = ';';
193 do {
194 if (c == ';') {
195 if (++i == NUMQUANT)
196 goto error_return;
197 quant[i] = 0;
198 } else if (c < '0' || c > '9') {
199 break;
200 } else {
201 quant[i] = quant[i] * 10 + c - '0';
202 }
203 c = tubp->tty_esca[j];
204 } while (j++ < tubp->tty_escx);
205
206 /* Add 3270 data stream output to execute the sequence */
207 switch(c) {
208 case 'm': /* Set Attribute */
209 for (next = 0; next <= i; next++) {
210 int type = -1, value = 0;
211
212 switch(quant[next]) {
213 case 0: /* Reset */
214 next = tubp->tty_nextlogx;
215 tty3270_set_bufadr(tubp, cpp, sba_needed);
216 *(*cpp)++ = TO_SA;
217 *(*cpp)++ = TAT_EXTHI;
218 *(*cpp)++ = TAX_RESET;
219 *(*cpp)++ = TO_SA;
220 *(*cpp)++ = TAT_COLOR;
221 *(*cpp)++ = TAC_RESET;
222 tubp->tty_nextlogx = next;
223 *sba_needed = 1;
224 sap = sabuf;
225 break;
226 case 1: /* Bright */
227 break;
228 case 2: /* Dim */
229 break;
230 case 4: /* Underscore */
231 type = TAT_EXTHI; value = TAX_UNDER;
232 break;
233 case 5: /* Blink */
234 type = TAT_EXTHI; value = TAX_BLINK;
235 break;
236 case 7: /* Reverse */
237 type = TAT_EXTHI; value = TAX_REVER;
238 break;
239 case 8: /* Hidden */
240 break; /* For now ... */
241 /* Foreground Colors */
242 case 30: /* Black */
243 type = TAT_COLOR; value = TAC_DEFAULT;
244 break;
245 case 31: /* Red */
246 type = TAT_COLOR; value = TAC_RED;
247 break;
248 case 32: /* Green */
249 type = TAT_COLOR; value = TAC_GREEN;
250 break;
251 case 33: /* Yellow */
252 type = TAT_COLOR; value = TAC_YELLOW;
253 break;
254 case 34: /* Blue */
255 type = TAT_COLOR; value = TAC_BLUE;
256 break;
257 case 35: /* Magenta */
258 type = TAT_COLOR; value = TAC_PINK;
259 break;
260 case 36: /* Cyan */
261 type = TAT_COLOR; value = TAC_TURQ;
262 break;
263 case 37: /* White */
264 type = TAT_COLOR; value = TAC_WHITE;
265 break;
266 case 39: /* Black */
267 type = TAT_COLOR; value = TAC_DEFAULT;
268 break;
269 /* Background Colors */
270 case 40: /* Black */
271 case 41: /* Red */
272 case 42: /* Green */
273 case 43: /* Yellow */
274 case 44: /* Blue */
275 case 45: /* Magenta */
276 case 46: /* Cyan */
277 case 47: /* White */
278 break; /* For now ... */
279 /* Oops */
280 default:
281 break;
282 }
283 if (type != -1) {
284 tty3270_set_bufadr(tubp, cpp, sba_needed);
285 *(*cpp)++ = TO_SA;
286 *(*cpp)++ = type;
287 *(*cpp)++ = value;
288 *sap++ = TO_SA;
289 *sap++ = type;
290 *sap++ = value;
291 }
292 }
293 break;
294
295 case 'H': /* Cursor Home */
296 case 'f': /* Force Cursor Position */
297 if (quant[0]) quant[0]--;
298 if (quant[1]) quant[1]--;
299 next = quant[0] * GEOM_COLS + quant[1];
300 goto do_setcur;
301 case 'A': /* Cursor Up */
302 if (quant[i] == 0) quant[i] = 1;
303 next = tubp->tty_nextlogx - GEOM_COLS * quant[i];
304 goto do_setcur;
305 case 'B': /* Cursor Down */
306 if (quant[i] == 0) quant[i] = 1;
307 next = tubp->tty_nextlogx + GEOM_COLS * quant[i];
308 goto do_setcur;
309 case 'C': /* Cursor Forward */
310 if (quant[i] == 0) quant[i] = 1;
311 next = tubp->tty_nextlogx % GEOM_COLS;
312 start = tubp->tty_nextlogx - next;
313 next = start + MIN(next + quant[i], GEOM_COLS - 1);
314 goto do_setcur;
315 case 'D': /* Cursor Backward */
316 if (quant[i] == 0) quant[i] = 1;
317 next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS);
318 next = tubp->tty_nextlogx - next;
319 goto do_setcur;
320 case 'G':
321 if (quant[0]) quant[0]--;
322 next = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS + quant[0];
323 do_setcur:
324 if (next < 0)
325 break;
326 tubp->tty_nextlogx = next;
327 tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
328 *sba_needed = 1;
329 break;
330
331 case 'r': /* Define scroll area */
332 start = quant[0];
333 if (start <= 0) start = 1;
334 if (start > GEOM_ROWS - 2) start = GEOM_ROWS - 2;
335 tubp->tty_nextlogx = (start - 1) * GEOM_COLS;
336 tubp->tty_oucol = 0;
337 *sba_needed = 1;
338 break;
339
340 case 'X': /* Erase for n chars from cursor */
341 start = tubp->tty_nextlogx;
342 end = start + (quant[0]?: 1);
343 goto do_fill;
344 case 'J': /* Erase to screen end from cursor */
345 *(*cpp)++ = TO_SBA;
346 TUB_BUFADR(tubp->tty_nextlogx, cpp);
347 *(*cpp)++ = TO_RA;
348 TUB_BUFADR(GEOM_INPUT, cpp);
349 *(*cpp)++ = tub_ascebc[' '];
350 *(*cpp)++ = TO_SBA;
351 TUB_BUFADR(tubp->tty_nextlogx, cpp);
352 break;
353 case 'K':
354 start = tubp->tty_nextlogx;
355 end = (start + GEOM_COLS) / GEOM_COLS * GEOM_COLS;
356 do_fill:
357 if (start >= GEOM_INPUT)
358 break;
359 if (end > GEOM_INPUT)
360 end = GEOM_INPUT;
361 if (end <= start)
362 break;
363 *(*cpp)++ = TO_SBA;
364 TUB_BUFADR(start, cpp);
365 if (end - start > 4) {
366 *(*cpp)++ = TO_RA;
367 TUB_BUFADR(end, cpp);
368 *(*cpp)++ = tub_ascebc[' '];
369 } else while (start++ < end) {
370 *(*cpp)++ = tub_ascebc[' '];
371 }
372 tubp->tty_nextlogx = end;
373 tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
374 *sba_needed = 1;
375 break;
376 }
377 done_return:
378 tubp->tty_escx = 0;
379 cp = sabuf;
380 while (cp != sap)
381 tubp->tty_esca[tubp->tty_escx++] = *cp++;
382 return 0;
383 error_return:
384 tubp->tty_escx = 0;
385 return 0;
386 }
387
388 static int
tty3270_next_char(tub_t * tubp)389 tty3270_next_char(tub_t *tubp)
390 {
391 int c;
392 bcb_t *ib;
393
394 ib = &tubp->tty_bcb;
395 if (ib->bc_cnt == 0)
396 return -1;
397 c = ib->bc_buf[ib->bc_rd++];
398 if (ib->bc_rd == ib->bc_len)
399 ib->bc_rd = 0;
400 ib->bc_cnt--;
401 return c;
402 }
403
404 static void
tty3270_unnext_char(tub_t * tubp,char c)405 tty3270_unnext_char(tub_t *tubp, char c)
406 {
407 bcb_t *ib;
408
409 ib = &tubp->tty_bcb;
410 if (ib->bc_rd == 0)
411 ib->bc_rd = ib->bc_len;
412 ib->bc_buf[--ib->bc_rd] = c;
413 ib->bc_cnt++;
414 }
415
416
417 static void
tty3270_clear_input_area(tub_t * tubp,char ** cpp)418 tty3270_clear_input_area(tub_t *tubp, char **cpp)
419 {
420 *(*cpp)++ = TO_SBA;
421 TUB_BUFADR(GEOM_INPUT, cpp);
422 *(*cpp)++ = TO_SF;
423 *(*cpp)++ = tubp->tty_inattr;
424 *(*cpp)++ = TO_IC;
425 *(*cpp)++ = TO_RA;
426 TUB_BUFADR(GEOM_STAT, cpp);
427 *(*cpp)++ = '\0';
428 }
429
430 static void
tty3270_update_input_area(tub_t * tubp,char ** cpp)431 tty3270_update_input_area(tub_t *tubp, char **cpp)
432 {
433 int len;
434
435 *(*cpp)++ = TO_SBA;
436 TUB_BUFADR(GEOM_INPUT, cpp);
437 *(*cpp)++ = TO_SF;
438 *(*cpp)++ = TF_INMDT;
439 len = strlen(tubp->tty_input);
440 memcpy(*cpp, tubp->tty_input, len);
441 *cpp += len;
442 *(*cpp)++ = TO_IC;
443 len = GEOM_INPLEN - len;
444 if (len > 4) {
445 *(*cpp)++ = TO_RA;
446 TUB_BUFADR(GEOM_STAT, cpp);
447 *(*cpp)++ = '\0';
448 } else {
449 for (; len > 0; len--)
450 *(*cpp)++ = '\0';
451 }
452 }
453
454 /*
455 * tty3270_set_status_area(tub_t *tubp, char **cpp)
456 */
457 static void
tty3270_set_status_area(tub_t * tubp,char ** cpp)458 tty3270_set_status_area(tub_t *tubp, char **cpp)
459 {
460 char *sp;
461
462 if (tubp->stat == TBS_RUNNING)
463 sp = TS_RUNNING;
464 else if (tubp->stat == TBS_MORE)
465 sp = TS_MORE;
466 else if (tubp->stat == TBS_HOLD)
467 sp = TS_HOLD;
468 else
469 sp = "Linux Whatstat";
470
471 *(*cpp)++ = TO_SBA;
472 TUB_BUFADR(GEOM_STAT, cpp);
473 *(*cpp)++ = TO_SF;
474 *(*cpp)++ = TF_STAT;
475 memcpy(*cpp, sp, sizeof TS_RUNNING);
476 TUB_ASCEBC(*cpp, sizeof TS_RUNNING);
477 *cpp += sizeof TS_RUNNING;
478 }
479
480 /*
481 * tty3270_build() -- build an output stream
482 */
483 int
tty3270_build(tub_t * tubp)484 tty3270_build(tub_t *tubp)
485 {
486 char *cp, *startcp;
487 int chancmd;
488 int writecc = TW_KR;
489 int force = 0;
490
491 if (tubp->mode == TBM_FS)
492 return 0;
493
494 cp = startcp = *tubp->ttyscreen + 1;
495
496 switch(tubp->cmd) {
497 default:
498 printk(KERN_WARNING "tty3270_build unknown command %d\n", tubp->cmd);
499 return 0;
500 case TBC_OPEN:
501 tbc_open:
502 tubp->flags &= ~TUB_INPUT_HACK;
503 chancmd = TC_EWRITEA;
504 tty3270_clear_input_area(tubp, &cp);
505 tty3270_set_status_area(tubp, &cp);
506 tty3270_clear_log_area(tubp, &cp);
507 break;
508 case TBC_UPDLOG:
509 if (tubp->flags & TUB_INPUT_HACK)
510 goto tbc_open;
511 chancmd = TC_WRITE;
512 writecc = TW_NONE;
513 tty3270_update_log_area(tubp, &cp);
514 break;
515 case TBC_KRUPDLOG:
516 chancmd = TC_WRITE;
517 force = 1;
518 tty3270_update_log_area(tubp, &cp);
519 break;
520 case TBC_CLRUPDLOG:
521 chancmd = TC_WRITE;
522 tty3270_set_status_area(tubp, &cp);
523 tty3270_clear_log_area(tubp, &cp);
524 tty3270_update_log_area(tubp, &cp);
525 break;
526 case TBC_UPDATE:
527 chancmd = TC_EWRITEA;
528 tubp->tty_oucol = tubp->tty_nextlogx = 0;
529 tty3270_clear_input_area(tubp, &cp);
530 tty3270_set_status_area(tubp, &cp);
531 tty3270_update_log_area(tubp, &cp);
532 break;
533 case TBC_UPDSTAT:
534 chancmd = TC_WRITE;
535 tty3270_set_status_area(tubp, &cp);
536 break;
537 case TBC_CLRINPUT:
538 chancmd = TC_WRITE;
539 tty3270_clear_input_area(tubp, &cp);
540 break;
541 case TBC_UPDINPUT:
542 chancmd = TC_WRITE;
543 tty3270_update_input_area(tubp, &cp);
544 break;
545 }
546
547 /* Set Write Control Character and start I/O */
548 if (force == 0 && cp == startcp &&
549 (tubp->flags & TUB_ALARM) == 0)
550 return 0;
551 if (tubp->flags & TUB_ALARM) {
552 tubp->flags &= ~TUB_ALARM;
553 writecc |= TW_PLUSALARM;
554 }
555 **tubp->ttyscreen = writecc;
556 tubp->ttyccw.cmd_code = chancmd;
557 tubp->ttyccw.flags = CCW_FLAG_SLI;
558 tubp->ttyccw.cda = virt_to_phys(*tubp->ttyscreen);
559 tubp->ttyccw.count = cp - *tubp->ttyscreen;
560 tty3270_io(tubp);
561 return 1;
562 }
563
564 static void
tty3270_tub_bufadr(tub_t * tubp,int adr,char ** cpp)565 tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp)
566 {
567 if (tubp->tty_14bitadr) {
568 *(*cpp)++ = (adr >> 8) & 0x3f;
569 *(*cpp)++ = adr & 0xff;
570 } else {
571 *(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f];
572 *(*cpp)++ = tub_ebcgraf[adr & 0x3f];
573 }
574 }
575
576 static void
tty3270_set_bufadr(tub_t * tubp,char ** cpp,int * sba_needed)577 tty3270_set_bufadr(tub_t *tubp, char **cpp, int *sba_needed)
578 {
579 if (!*sba_needed)
580 return;
581 if (tubp->tty_nextlogx >= GEOM_INPUT) {
582 tubp->tty_nextlogx = GEOM_INPUT - 1;
583 tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
584 }
585 *(*cpp)++ = TO_SBA;
586 TUB_BUFADR(tubp->tty_nextlogx, cpp);
587 *sba_needed = 0;
588 }
589