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