File: /usr/src/linux/drivers/s390/char/tubttybld.c
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_update_log_area(tub_t *, char **);
19 static void tty3270_update_log_area_esc(tub_t *, char **);
20 static void tty3270_clear_log_area(tub_t *, char **);
21 static void tty3270_tub_bufadr(tub_t *, int, char **);
22
23 /*
24 * tty3270_clear_log_area(tub_t *tubp, char **cpp)
25 */
26 static void
27 tty3270_clear_log_area(tub_t *tubp, char **cpp)
28 {
29 *(*cpp)++ = TO_SBA;
30 TUB_BUFADR(GEOM_LOG, cpp);
31 *(*cpp)++ = TO_SF;
32 *(*cpp)++ = TF_LOG;
33 *(*cpp)++ = TO_RA;
34 TUB_BUFADR(GEOM_INPUT, cpp);
35 *(*cpp)++ = '\0';
36 tubp->tty_oucol = tubp->tty_nextlogx = 0;
37 *(*cpp)++ = TO_SBA;
38 TUB_BUFADR(tubp->tty_nextlogx, cpp);
39 }
40
41 static void
42 tty3270_update_log_area(tub_t *tubp, char **cpp)
43 {
44 int lastx = GEOM_INPUT;
45 int c;
46 int next, fill, i;
47 int sba_needed = 1;
48 char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
49
50 /* Place characters */
51 while (tubp->tty_bcb.bc_cnt != 0) {
52 if (tubp->tty_nextlogx >= lastx) {
53 if (sba_needed == 0 || tubp->stat == TBS_RUNNING) {
54 tubp->stat = TBS_MORE;
55 tty3270_set_status_area(tubp, cpp);
56 tty3270_scl_settimer(tubp);
57 }
58 break;
59 }
60
61 /* Check for room for another char + possible ESCs */
62 if (&(*cpp)[tubp->tty_escx + 1] >= overrun)
63 break;
64
65 /* Fetch a character */
66 if ((c = tty3270_next_char(tubp)) == -1)
67 break;
68
69 /* Add a Set-Buffer-Address Order if we haven't */
70 if (sba_needed) {
71 sba_needed = 0;
72 *(*cpp)++ = TO_SBA;
73 TUB_BUFADR(tubp->tty_nextlogx, cpp);
74 }
75
76 switch(c) {
77 default:
78 if (c < ' ') /* Blank it if we don't know it */
79 c = ' ';
80 for (i = 0; i < tubp->tty_escx; i++)
81 *(*cpp)++ = tubp->tty_esca[i];
82 tubp->tty_escx = 0;
83 *(*cpp)++ = tub_ascebc[(int)c];
84 tubp->tty_nextlogx++;
85 tubp->tty_oucol++;
86 break;
87 case 0x1b: /* ESC */
88 tty3270_update_log_area_esc(tubp, cpp);
89 break;
90 case '\r':
91 break; /* completely ignore 0x0d = CR. */
92 case '\n':
93 if (tubp->tty_oucol == GEOM_COLS) {
94 tubp->tty_oucol = 0;
95 break;
96 }
97 next = (tubp->tty_nextlogx + GEOM_COLS) /
98 GEOM_COLS * GEOM_COLS;
99 next = MIN(next, lastx);
100 fill = next - tubp->tty_nextlogx;
101 if (fill < 5) {
102 for (i = 0; i < fill; i++)
103 *(*cpp)++ = tub_ascebc[' '];
104 } else {
105 *(*cpp)++ = TO_RA;
106 TUB_BUFADR(next, cpp);
107 *(*cpp)++ = tub_ascebc[' '];
108 }
109 tubp->tty_nextlogx = next;
110 tubp->tty_oucol = 0;
111 break;
112 case '\t':
113 fill = (tubp->tty_nextlogx % GEOM_COLS) % 8;
114 for (; fill < 8; fill++) {
115 if (tubp->tty_nextlogx >= lastx)
116 break;
117 *(*cpp)++ = tub_ascebc[' '];
118 tubp->tty_nextlogx++;
119 tubp->tty_oucol++;
120 }
121 break;
122 case '\a':
123 tubp->flags |= TUB_ALARM;
124 break;
125 case '\f':
126 tty3270_clear_log_area(tubp, cpp);
127 break;
128 }
129 }
130 }
131
132 #define NUMQUANT 8
133 static void
134 tty3270_update_log_area_esc(tub_t *tubp, char **cpp)
135 {
136 int lastx = GEOM_INPUT;
137 int c;
138 int i;
139 int start, next, fill;
140 int quant[NUMQUANT];
141
142 if ((c = tty3270_next_char(tubp)) != '[') {
143 return;
144 }
145
146 /*
147 * Parse potentially empty string "nn;nn;nn..."
148 */
149 i = -1;
150 c = ';';
151 do {
152 if (c == ';') {
153 if (++i == NUMQUANT)
154 break;
155 quant[i] = 0;
156 } else if (c < '0' || c > '9') {
157 break;
158 } else {
159 quant[i] = quant[i] * 10 + c - '0';
160 }
161 } while ((c = tty3270_next_char(tubp)) != -1);
162 if (c == -1) {
163 return;
164 }
165 if (i >= NUMQUANT) {
166 return;
167 }
168 switch(c) {
169 case -1:
170 return;
171 case 'm': /* Set Attribute */
172 for (next = 0; next <= i; next++) {
173 int type = -1, value = 0;
174
175 if (tubp->tty_escx + 3 > MAX_TTY_ESCA)
176 break;
177 switch(quant[next]) {
178 case 0: /* Reset */
179 tubp->tty_esca[tubp->tty_escx++] = TO_SA;
180 tubp->tty_esca[tubp->tty_escx++] = TAT_RESET;
181 tubp->tty_esca[tubp->tty_escx++] = TAR_RESET;
182 break;
183 case 1: /* Bright */
184 case 2: /* Dim */
185 case 4: /* Underscore */
186 case 5: /* Blink */
187 case 7: /* Reverse */
188 case 8: /* Hidden */
189 break; /* For now ... */
190 /* Foreground Colors */
191 case 30: /* Black */
192 type = TAT_COLOR; value = TAC_DEFAULT;
193 break;
194 case 31: /* Red */
195 type = TAT_COLOR; value = TAC_RED;
196 break;
197 case 32: /* Green */
198 type = TAT_COLOR; value = TAC_GREEN;
199 break;
200 case 33: /* Yellow */
201 type = TAT_COLOR; value = TAC_YELLOW;
202 break;
203 case 34: /* Blue */
204 type = TAT_COLOR; value = TAC_BLUE;
205 break;
206 case 35: /* Magenta */
207 type = TAT_COLOR; value = TAC_PINK;
208 break;
209 case 36: /* Cyan */
210 type = TAT_COLOR; value = TAC_TURQ;
211 break;
212 case 37: /* White */
213 type = TAT_COLOR; value = TAC_WHITE;
214 break;
215 case 39: /* Black */
216 type = TAT_COLOR; value = TAC_DEFAULT;
217 break;
218 /* Background Colors */
219 case 40: /* Black */
220 case 41: /* Red */
221 case 42: /* Green */
222 case 43: /* Yellow */
223 case 44: /* Blue */
224 case 45: /* Magenta */
225 case 46: /* Cyan */
226 case 47: /* White */
227 break; /* For now ... */
228 /* Oops */
229 default:
230 break;
231 }
232 if (type != -1) {
233 tubp->tty_esca[tubp->tty_escx++] = TO_SA;
234 tubp->tty_esca[tubp->tty_escx++] = type;
235 tubp->tty_esca[tubp->tty_escx++] = value;
236 }
237 }
238 break;
239 case 'H': /* Cursor Home */
240 case 'f': /* Force Cursor Position */
241 return;
242 case 'A': /* Cursor Up */
243 return;
244 case 'B': /* Cursor Down */
245 return;
246 case 'C': /* Cursor Forward */
247 next = tubp->tty_nextlogx % GEOM_COLS;
248 start = tubp->tty_nextlogx - next;
249 next = start + MIN(next + quant[i], GEOM_COLS - 1);
250 next = MIN(next, lastx);
251 do_fill:
252 fill = next - tubp->tty_nextlogx;
253 if (fill < 5) {
254 for (i = 0; i < fill; i++)
255 *(*cpp)++ = tub_ascebc[' '];
256 } else {
257 *(*cpp)++ = TO_RA;
258 TUB_BUFADR(next, cpp);
259 *(*cpp)++ = tub_ascebc[' '];
260 }
261 tubp->tty_nextlogx = next;
262 tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
263 break;
264 case 'D': /* Cursor Backward */
265 next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS);
266 tubp->tty_nextlogx -= next;
267 tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
268 *(*cpp)++ = TO_SBA;
269 TUB_BUFADR(tubp->tty_nextlogx, cpp);
270 break;
271 case 'G':
272 start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS;
273 next = MIN(quant[i], GEOM_COLS - 1) + start;
274 next = MIN(next, lastx);
275 goto do_fill;
276 }
277 }
278
279
280 static int
281 tty3270_next_char(tub_t *tubp)
282 {
283 int c;
284 bcb_t *ib;
285
286 ib = &tubp->tty_bcb;
287 if (ib->bc_cnt == 0)
288 return -1;
289 c = ib->bc_buf[ib->bc_rd++];
290 if (ib->bc_rd == ib->bc_len)
291 ib->bc_rd = 0;
292 ib->bc_cnt--;
293 return c;
294 }
295
296
297 static void
298 tty3270_clear_input_area(tub_t *tubp, char **cpp)
299 {
300 *(*cpp)++ = TO_SBA;
301 TUB_BUFADR(GEOM_INPUT, cpp);
302 *(*cpp)++ = TO_SF;
303 *(*cpp)++ = tubp->tty_inattr;
304 *(*cpp)++ = TO_IC;
305 *(*cpp)++ = TO_RA;
306 TUB_BUFADR(GEOM_STAT, cpp);
307 *(*cpp)++ = '\0';
308 }
309
310 static void
311 tty3270_update_input_area(tub_t *tubp, char **cpp)
312 {
313 int len;
314
315 *(*cpp)++ = TO_SBA;
316 TUB_BUFADR(GEOM_INPUT, cpp);
317 *(*cpp)++ = TO_SF;
318 *(*cpp)++ = TF_INMDT;
319 len = strlen(tubp->tty_input);
320 memcpy(*cpp, tubp->tty_input, len);
321 *cpp += len;
322 *(*cpp)++ = TO_IC;
323 len = GEOM_INPLEN - len;
324 if (len > 4) {
325 *(*cpp)++ = TO_RA;
326 TUB_BUFADR(GEOM_STAT, cpp);
327 *(*cpp)++ = '\0';
328 } else {
329 for (; len > 0; len--)
330 *(*cpp)++ = '\0';
331 }
332 }
333
334 /*
335 * tty3270_set_status_area(tub_t *tubp, char **cpp)
336 */
337 static void
338 tty3270_set_status_area(tub_t *tubp, char **cpp)
339 {
340 char *sp;
341
342 if (tubp->stat == TBS_RUNNING)
343 sp = TS_RUNNING;
344 else if (tubp->stat == TBS_MORE)
345 sp = TS_MORE;
346 else if (tubp->stat == TBS_HOLD)
347 sp = TS_HOLD;
348 else
349 sp = "Linux Whatstat";
350
351 *(*cpp)++ = TO_SBA;
352 TUB_BUFADR(GEOM_STAT, cpp);
353 *(*cpp)++ = TO_SF;
354 *(*cpp)++ = TF_STAT;
355 memcpy(*cpp, sp, sizeof TS_RUNNING);
356 TUB_ASCEBC(*cpp, sizeof TS_RUNNING);
357 *cpp += sizeof TS_RUNNING;
358 }
359
360 /*
361 * tty3270_build() -- build an output stream
362 */
363 int
364 tty3270_build(tub_t *tubp)
365 {
366 char *cp, *startcp;
367 int chancmd;
368 int writecc = TW_KR;
369 int force = 0;
370
371 if (tubp->mode == TBM_FS)
372 return 0;
373
374 cp = startcp = *tubp->ttyscreen + 1;
375
376 switch(tubp->cmd) {
377 default:
378 printk(KERN_WARNING "tty3270_build unknown command %d\n", tubp->cmd);
379 return 0;
380 case TBC_OPEN:
381 tbc_open:
382 tubp->flags &= ~TUB_INPUT_HACK;
383 chancmd = TC_EWRITEA;
384 tty3270_clear_input_area(tubp, &cp);
385 tty3270_set_status_area(tubp, &cp);
386 tty3270_clear_log_area(tubp, &cp);
387 break;
388 case TBC_UPDLOG:
389 if (tubp->flags & TUB_INPUT_HACK)
390 goto tbc_open;
391 chancmd = TC_WRITE;
392 writecc = TW_NONE;
393 tty3270_update_log_area(tubp, &cp);
394 break;
395 case TBC_KRUPDLOG:
396 chancmd = TC_WRITE;
397 force = 1;
398 tty3270_update_log_area(tubp, &cp);
399 break;
400 case TBC_CLRUPDLOG:
401 chancmd = TC_WRITE;
402 tty3270_set_status_area(tubp, &cp);
403 tty3270_clear_log_area(tubp, &cp);
404 tty3270_update_log_area(tubp, &cp);
405 break;
406 case TBC_UPDATE:
407 chancmd = TC_EWRITEA;
408 tubp->tty_oucol = tubp->tty_nextlogx = 0;
409 tty3270_clear_input_area(tubp, &cp);
410 tty3270_set_status_area(tubp, &cp);
411 tty3270_update_log_area(tubp, &cp);
412 break;
413 case TBC_UPDSTAT:
414 chancmd = TC_WRITE;
415 tty3270_set_status_area(tubp, &cp);
416 break;
417 case TBC_CLRINPUT:
418 chancmd = TC_WRITE;
419 tty3270_clear_input_area(tubp, &cp);
420 break;
421 case TBC_UPDINPUT:
422 chancmd = TC_WRITE;
423 tty3270_update_input_area(tubp, &cp);
424 break;
425 }
426
427 /* Set Write Control Character and start I/O */
428 if (force == 0 && cp == startcp &&
429 (tubp->flags & TUB_ALARM) == 0)
430 return 0;
431 if (tubp->flags & TUB_ALARM) {
432 tubp->flags &= ~TUB_ALARM;
433 writecc |= TW_PLUSALARM;
434 }
435 **tubp->ttyscreen = writecc;
436 tubp->ttyccw.cmd_code = chancmd;
437 tubp->ttyccw.flags = CCW_FLAG_SLI;
438 tubp->ttyccw.cda = virt_to_phys(*tubp->ttyscreen);
439 tubp->ttyccw.count = cp - *tubp->ttyscreen;
440 tty3270_io(tubp);
441 return 1;
442 }
443
444 static void
445 tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp)
446 {
447 if (tubp->tty_14bitadr) {
448 *(*cpp)++ = (adr >> 8) & 0x3f;
449 *(*cpp)++ = adr & 0xff;
450 } else {
451 *(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f];
452 *(*cpp)++ = tub_ebcgraf[adr & 0x3f];
453 }
454 }
455