xref: /openbmc/linux/drivers/s390/char/con3270.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   *    IBM/3270 Driver - tty functions.
4   *
5   *  Author(s):
6   *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
7   *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
8   *	-- Copyright IBM Corp. 2003
9   */
10  
11  #include <linux/module.h>
12  #include <linux/types.h>
13  #include <linux/kdev_t.h>
14  #include <linux/tty.h>
15  #include <linux/vt_kern.h>
16  #include <linux/init.h>
17  #include <linux/console.h>
18  #include <linux/interrupt.h>
19  #include <linux/workqueue.h>
20  #include <linux/panic_notifier.h>
21  #include <linux/reboot.h>
22  #include <linux/slab.h>
23  #include <linux/memblock.h>
24  #include <linux/compat.h>
25  
26  #include <asm/ccwdev.h>
27  #include <asm/cio.h>
28  #include <asm/ebcdic.h>
29  #include <asm/cpcmd.h>
30  #include <linux/uaccess.h>
31  
32  #include "raw3270.h"
33  #include "keyboard.h"
34  
35  #define TTY3270_CHAR_BUF_SIZE 256
36  #define TTY3270_OUTPUT_BUFFER_SIZE 4096
37  #define TTY3270_SCREEN_PAGES 8 /* has to be power-of-two */
38  #define TTY3270_RECALL_SIZE 16 /* has to be power-of-two */
39  #define TTY3270_STATUS_AREA_SIZE 40
40  
41  static struct tty_driver *tty3270_driver;
42  static int tty3270_max_index;
43  static struct raw3270_fn tty3270_fn;
44  
45  #define TTY3270_HIGHLIGHT_BLINK		1
46  #define TTY3270_HIGHLIGHT_REVERSE	2
47  #define TTY3270_HIGHLIGHT_UNDERSCORE	4
48  
49  struct tty3270_attribute {
50  	unsigned char alternate_charset:1;	/* Graphics charset */
51  	unsigned char highlight:3;		/* Blink/reverse/underscore */
52  	unsigned char f_color:4;		/* Foreground color */
53  	unsigned char b_color:4;		/* Background color */
54  };
55  
56  struct tty3270_cell {
57  	unsigned char character;
58  	struct tty3270_attribute attributes;
59  };
60  
61  struct tty3270_line {
62  	struct tty3270_cell *cells;
63  	int len;
64  	int dirty;
65  };
66  
67  static const unsigned char sfq_read_partition[] = {
68  	0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81
69  };
70  
71  #define ESCAPE_NPAR 8
72  
73  /*
74   * The main tty view data structure.
75   * FIXME:
76   * 1) describe line orientation & lines list concept against screen
77   * 2) describe conversion of screen to lines
78   * 3) describe line format.
79   */
80  struct tty3270 {
81  	struct raw3270_view view;
82  	struct tty_port port;
83  
84  	/* Output stuff. */
85  	unsigned char wcc;		/* Write control character. */
86  	int nr_up;			/* # lines up in history. */
87  	unsigned long update_flags;	/* Update indication bits. */
88  	struct raw3270_request *write;	/* Single write request. */
89  	struct timer_list timer;	/* Output delay timer. */
90  	char *converted_line;		/* RAW 3270 data stream */
91  	unsigned int line_view_start;	/* Start of visible area */
92  	unsigned int line_write_start;	/* current write position */
93  	unsigned int oops_line;		/* line counter used when print oops */
94  
95  	/* Current tty screen. */
96  	unsigned int cx, cy;		/* Current output position. */
97  	struct tty3270_attribute attributes;
98  	struct tty3270_attribute saved_attributes;
99  	int allocated_lines;
100  	struct tty3270_line *screen;
101  
102  	/* Input stuff. */
103  	char *prompt;			/* Output string for input area. */
104  	char *input;			/* Input string for read request. */
105  	struct raw3270_request *read;	/* Single read request. */
106  	struct raw3270_request *kreset;	/* Single keyboard reset request. */
107  	struct raw3270_request *readpartreq;
108  	unsigned char inattr;		/* Visible/invisible input. */
109  	int throttle, attn;		/* tty throttle/unthrottle. */
110  	struct tasklet_struct readlet;	/* Tasklet to issue read request. */
111  	struct tasklet_struct hanglet;	/* Tasklet to hang up the tty. */
112  	struct kbd_data *kbd;		/* key_maps stuff. */
113  
114  	/* Escape sequence parsing. */
115  	int esc_state, esc_ques, esc_npar;
116  	int esc_par[ESCAPE_NPAR];
117  	unsigned int saved_cx, saved_cy;
118  
119  	/* Command recalling. */
120  	char **rcl_lines;		/* Array of recallable lines */
121  	int rcl_write_index;		/* Write index of recallable items */
122  	int rcl_read_index;		/* Read index of recallable items */
123  
124  	/* Character array for put_char/flush_chars. */
125  	unsigned int char_count;
126  	char char_buf[TTY3270_CHAR_BUF_SIZE];
127  };
128  
129  /* tty3270->update_flags. See tty3270_update for details. */
130  #define TTY_UPDATE_INPUT	0x1	/* Update input line. */
131  #define TTY_UPDATE_STATUS	0x2	/* Update status line. */
132  #define TTY_UPDATE_LINES	0x4	/* Update visible screen lines */
133  #define TTY_UPDATE_ALL		0x7	/* Recreate screen. */
134  
135  #define TTY3270_INPUT_AREA_ROWS 2
136  
137  /*
138   * Setup timeout for a device. On timeout trigger an update.
139   */
tty3270_set_timer(struct tty3270 * tp,int expires)140  static void tty3270_set_timer(struct tty3270 *tp, int expires)
141  {
142  	mod_timer(&tp->timer, jiffies + expires);
143  }
144  
tty3270_tty_rows(struct tty3270 * tp)145  static int tty3270_tty_rows(struct tty3270 *tp)
146  {
147  	return tp->view.rows - TTY3270_INPUT_AREA_ROWS;
148  }
149  
tty3270_add_ba(struct tty3270 * tp,char * cp,char order,int x,int y)150  static char *tty3270_add_ba(struct tty3270 *tp, char *cp, char order, int x, int y)
151  {
152  	*cp++ = order;
153  	raw3270_buffer_address(tp->view.dev, cp, x, y);
154  	return cp + 2;
155  }
156  
tty3270_add_ra(struct tty3270 * tp,char * cp,int x,int y,char c)157  static char *tty3270_add_ra(struct tty3270 *tp, char *cp, int x, int y, char c)
158  {
159  	cp = tty3270_add_ba(tp, cp, TO_RA, x, y);
160  	*cp++ = c;
161  	return cp;
162  }
163  
tty3270_add_sa(struct tty3270 * tp,char * cp,char attr,char value)164  static char *tty3270_add_sa(struct tty3270 *tp, char *cp, char attr, char value)
165  {
166  	*cp++ = TO_SA;
167  	*cp++ = attr;
168  	*cp++ = value;
169  	return cp;
170  }
171  
tty3270_add_ge(struct tty3270 * tp,char * cp,char c)172  static char *tty3270_add_ge(struct tty3270 *tp, char *cp, char c)
173  {
174  	*cp++ = TO_GE;
175  	*cp++ = c;
176  	return cp;
177  }
178  
tty3270_add_sf(struct tty3270 * tp,char * cp,char type)179  static char *tty3270_add_sf(struct tty3270 *tp, char *cp, char type)
180  {
181  	*cp++ = TO_SF;
182  	*cp++ = type;
183  	return cp;
184  }
185  
tty3270_line_increment(struct tty3270 * tp,unsigned int line,unsigned int incr)186  static int tty3270_line_increment(struct tty3270 *tp, unsigned int line, unsigned int incr)
187  {
188  	return (line + incr) & (tp->allocated_lines - 1);
189  }
190  
tty3270_get_write_line(struct tty3270 * tp,unsigned int num)191  static struct tty3270_line *tty3270_get_write_line(struct tty3270 *tp, unsigned int num)
192  {
193  	return tp->screen + tty3270_line_increment(tp, tp->line_write_start, num);
194  }
195  
tty3270_get_view_line(struct tty3270 * tp,unsigned int num)196  static struct tty3270_line *tty3270_get_view_line(struct tty3270 *tp, unsigned int num)
197  {
198  	return tp->screen + tty3270_line_increment(tp, tp->line_view_start, num - tp->nr_up);
199  }
200  
tty3270_input_size(int cols)201  static int tty3270_input_size(int cols)
202  {
203  	return cols * 2 - 11;
204  }
205  
tty3270_update_prompt(struct tty3270 * tp,char * input)206  static void tty3270_update_prompt(struct tty3270 *tp, char *input)
207  {
208  	strcpy(tp->prompt, input);
209  	tp->update_flags |= TTY_UPDATE_INPUT;
210  	tty3270_set_timer(tp, 1);
211  }
212  
213  /*
214   * The input line are the two last lines of the screen.
215   */
tty3270_add_prompt(struct tty3270 * tp)216  static int tty3270_add_prompt(struct tty3270 *tp)
217  {
218  	int count = 0;
219  	char *cp;
220  
221  	cp = tp->converted_line;
222  	cp = tty3270_add_ba(tp, cp, TO_SBA, 0, -2);
223  	*cp++ = tp->view.ascebc['>'];
224  
225  	if (*tp->prompt) {
226  		cp = tty3270_add_sf(tp, cp, TF_INMDT);
227  		count = min_t(int, strlen(tp->prompt),
228  			      tp->view.cols * 2 - TTY3270_STATUS_AREA_SIZE - 2);
229  		memcpy(cp, tp->prompt, count);
230  		cp += count;
231  	} else {
232  		cp = tty3270_add_sf(tp, cp, tp->inattr);
233  	}
234  	*cp++ = TO_IC;
235  	/* Clear to end of input line. */
236  	if (count < tp->view.cols * 2 - 11)
237  		cp = tty3270_add_ra(tp, cp, -TTY3270_STATUS_AREA_SIZE, -1, 0);
238  	return cp - tp->converted_line;
239  }
240  
tty3270_ebcdic_convert(struct tty3270 * tp,char * d,char * s)241  static char *tty3270_ebcdic_convert(struct tty3270 *tp, char *d, char *s)
242  {
243  	while (*s)
244  		*d++ = tp->view.ascebc[(int)*s++];
245  	return d;
246  }
247  
248  /*
249   * The status line is the last line of the screen. It shows the string
250   * "Running"/"History X" in the lower right corner of the screen.
251   */
tty3270_add_status(struct tty3270 * tp)252  static int tty3270_add_status(struct tty3270 *tp)
253  {
254  	char *cp = tp->converted_line;
255  	int len;
256  
257  	cp = tty3270_add_ba(tp, cp, TO_SBA, -TTY3270_STATUS_AREA_SIZE, -1);
258  	cp = tty3270_add_sf(tp, cp, TF_LOG);
259  	cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAC_GREEN);
260  	cp = tty3270_ebcdic_convert(tp, cp, " 7");
261  	cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_REVER);
262  	cp = tty3270_ebcdic_convert(tp, cp, "PrevPg");
263  	cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
264  	cp = tty3270_ebcdic_convert(tp, cp, " 8");
265  	cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_REVER);
266  	cp = tty3270_ebcdic_convert(tp, cp, "NextPg");
267  	cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
268  	cp = tty3270_ebcdic_convert(tp, cp, " 12");
269  	cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_REVER);
270  	cp = tty3270_ebcdic_convert(tp, cp, "Recall");
271  	cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
272  	cp = tty3270_ebcdic_convert(tp, cp, "  ");
273  	if (tp->nr_up) {
274  		len = sprintf(cp, "History %d", -tp->nr_up);
275  		codepage_convert(tp->view.ascebc, cp, len);
276  		cp += len;
277  	} else {
278  		cp = tty3270_ebcdic_convert(tp, cp, oops_in_progress ? "Crashed" : "Running");
279  	}
280  	cp = tty3270_add_sf(tp, cp, TF_LOG);
281  	cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAC_RESET);
282  	return cp - (char *)tp->converted_line;
283  }
284  
tty3270_blank_screen(struct tty3270 * tp)285  static void tty3270_blank_screen(struct tty3270 *tp)
286  {
287  	struct tty3270_line *line;
288  	int i;
289  
290  	for (i = 0; i < tty3270_tty_rows(tp); i++) {
291  		line = tty3270_get_write_line(tp, i);
292  		line->len = 0;
293  		line->dirty = 1;
294  	}
295  	tp->nr_up = 0;
296  }
297  
298  /*
299   * Write request completion callback.
300   */
tty3270_write_callback(struct raw3270_request * rq,void * data)301  static void tty3270_write_callback(struct raw3270_request *rq, void *data)
302  {
303  	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
304  
305  	if (rq->rc != 0) {
306  		/* Write wasn't successful. Refresh all. */
307  		tp->update_flags = TTY_UPDATE_ALL;
308  		tty3270_set_timer(tp, 1);
309  	}
310  	raw3270_request_reset(rq);
311  	xchg(&tp->write, rq);
312  }
313  
tty3270_required_length(struct tty3270 * tp,struct tty3270_line * line)314  static int tty3270_required_length(struct tty3270 *tp, struct tty3270_line *line)
315  {
316  	unsigned char f_color, b_color, highlight;
317  	struct tty3270_cell *cell;
318  	int i, flen = 3;		/* Prefix (TO_SBA). */
319  
320  	flen += line->len;
321  	highlight = 0;
322  	f_color = TAC_RESET;
323  	b_color = TAC_RESET;
324  
325  	for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
326  		if (cell->attributes.highlight != highlight) {
327  			flen += 3;	/* TO_SA to switch highlight. */
328  			highlight = cell->attributes.highlight;
329  		}
330  		if (cell->attributes.f_color != f_color) {
331  			flen += 3;	/* TO_SA to switch color. */
332  			f_color = cell->attributes.f_color;
333  		}
334  		if (cell->attributes.b_color != b_color) {
335  			flen += 3;	/* TO_SA to switch color. */
336  			b_color = cell->attributes.b_color;
337  		}
338  		if (cell->attributes.alternate_charset)
339  			flen += 1;	/* TO_GE to switch to graphics extensions */
340  	}
341  	if (highlight)
342  		flen += 3;	/* TO_SA to reset hightlight. */
343  	if (f_color != TAC_RESET)
344  		flen += 3;	/* TO_SA to reset color. */
345  	if (b_color != TAC_RESET)
346  		flen += 3;	/* TO_SA to reset color. */
347  	if (line->len < tp->view.cols)
348  		flen += 4;	/* Postfix (TO_RA). */
349  
350  	return flen;
351  }
352  
tty3270_add_reset_attributes(struct tty3270 * tp,struct tty3270_line * line,char * cp,struct tty3270_attribute * attr,int lineno)353  static char *tty3270_add_reset_attributes(struct tty3270 *tp, struct tty3270_line *line,
354  					  char *cp, struct tty3270_attribute *attr, int lineno)
355  {
356  	if (attr->highlight)
357  		cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
358  	if (attr->f_color != TAC_RESET)
359  		cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAX_RESET);
360  	if (attr->b_color != TAC_RESET)
361  		cp = tty3270_add_sa(tp, cp, TAT_BGCOLOR, TAX_RESET);
362  	if (line->len < tp->view.cols)
363  		cp = tty3270_add_ra(tp, cp, 0, lineno + 1, 0);
364  	return cp;
365  }
366  
tty3270_graphics_translate(struct tty3270 * tp,char ch)367  static char tty3270_graphics_translate(struct tty3270 *tp, char ch)
368  {
369  	switch (ch) {
370  	case 'q': /* - */
371  		return 0xa2;
372  	case 'x': /* '|' */
373  		return 0x85;
374  	case 'l': /* |- */
375  		return 0xc5;
376  	case 't': /* |_ */
377  		return 0xc6;
378  	case 'u': /* _| */
379  		return 0xd6;
380  	case 'k': /* -| */
381  		return 0xd5;
382  	case 'j':
383  		return 0xd4;
384  	case 'm':
385  		return 0xc4;
386  	case 'n': /* + */
387  		return 0xd3;
388  	case 'v':
389  		return 0xc7;
390  	case 'w':
391  		return 0xd7;
392  	default:
393  		return ch;
394  	}
395  }
396  
tty3270_add_attributes(struct tty3270 * tp,struct tty3270_line * line,struct tty3270_attribute * attr,char * cp,int lineno)397  static char *tty3270_add_attributes(struct tty3270 *tp, struct tty3270_line *line,
398  				    struct tty3270_attribute *attr, char *cp, int lineno)
399  {
400  	const unsigned char colors[16] = {
401  		[0] = TAC_DEFAULT,
402  		[1] = TAC_RED,
403  		[2] = TAC_GREEN,
404  		[3] = TAC_YELLOW,
405  		[4] = TAC_BLUE,
406  		[5] = TAC_PINK,
407  		[6] = TAC_TURQ,
408  		[7] = TAC_WHITE,
409  		[9] = TAC_DEFAULT
410  	};
411  
412  	const unsigned char highlights[8] = {
413  		[TTY3270_HIGHLIGHT_BLINK] = TAX_BLINK,
414  		[TTY3270_HIGHLIGHT_REVERSE] = TAX_REVER,
415  		[TTY3270_HIGHLIGHT_UNDERSCORE] = TAX_UNDER,
416  	};
417  
418  	struct tty3270_cell *cell;
419  	int c, i;
420  
421  	cp = tty3270_add_ba(tp, cp, TO_SBA, 0, lineno);
422  
423  	for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
424  		if (cell->attributes.highlight != attr->highlight) {
425  			attr->highlight = cell->attributes.highlight;
426  			cp = tty3270_add_sa(tp, cp, TAT_EXTHI, highlights[attr->highlight]);
427  		}
428  		if (cell->attributes.f_color != attr->f_color) {
429  			attr->f_color = cell->attributes.f_color;
430  			cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, colors[attr->f_color]);
431  		}
432  		if (cell->attributes.b_color != attr->b_color) {
433  			attr->b_color = cell->attributes.b_color;
434  			cp = tty3270_add_sa(tp, cp, TAT_BGCOLOR, colors[attr->b_color]);
435  		}
436  		c = cell->character;
437  		if (cell->attributes.alternate_charset)
438  			cp = tty3270_add_ge(tp, cp, tty3270_graphics_translate(tp, c));
439  		else
440  			*cp++ = tp->view.ascebc[c];
441  	}
442  	return cp;
443  }
444  
tty3270_reset_attributes(struct tty3270_attribute * attr)445  static void tty3270_reset_attributes(struct tty3270_attribute *attr)
446  {
447  	attr->highlight = TAX_RESET;
448  	attr->f_color = TAC_RESET;
449  	attr->b_color = TAC_RESET;
450  }
451  
452  /*
453   * Convert a tty3270_line to a 3270 data fragment usable for output.
454   */
tty3270_convert_line(struct tty3270 * tp,struct tty3270_line * line,int lineno)455  static unsigned int tty3270_convert_line(struct tty3270 *tp, struct tty3270_line *line, int lineno)
456  {
457  	struct tty3270_attribute attr;
458  	int flen;
459  	char *cp;
460  
461  	/* Determine how long the fragment will be. */
462  	flen = tty3270_required_length(tp, line);
463  	if (flen > PAGE_SIZE)
464  		return 0;
465  	/* Write 3270 data fragment. */
466  	tty3270_reset_attributes(&attr);
467  	cp = tty3270_add_attributes(tp, line, &attr, tp->converted_line, lineno);
468  	cp = tty3270_add_reset_attributes(tp, line, cp, &attr, lineno);
469  	return cp - (char *)tp->converted_line;
470  }
471  
tty3270_update_lines_visible(struct tty3270 * tp,struct raw3270_request * rq)472  static void tty3270_update_lines_visible(struct tty3270 *tp, struct raw3270_request *rq)
473  {
474  	struct tty3270_line *line;
475  	int len, i;
476  
477  	for (i = 0; i < tty3270_tty_rows(tp); i++) {
478  		line = tty3270_get_view_line(tp, i);
479  		if (!line->dirty)
480  			continue;
481  		len = tty3270_convert_line(tp, line, i);
482  		if (raw3270_request_add_data(rq, tp->converted_line, len))
483  			break;
484  		line->dirty = 0;
485  	}
486  	if (i == tty3270_tty_rows(tp)) {
487  		for (i = 0; i < tp->allocated_lines; i++)
488  			tp->screen[i].dirty = 0;
489  		tp->update_flags &= ~TTY_UPDATE_LINES;
490  	}
491  }
492  
tty3270_update_lines_all(struct tty3270 * tp,struct raw3270_request * rq)493  static void tty3270_update_lines_all(struct tty3270 *tp, struct raw3270_request *rq)
494  {
495  	struct tty3270_line *line;
496  	char buf[4];
497  	int len, i;
498  
499  	for (i = 0; i < tp->allocated_lines; i++) {
500  		line = tty3270_get_write_line(tp, i + tp->cy + 1);
501  		if (!line->dirty)
502  			continue;
503  		len = tty3270_convert_line(tp, line, tp->oops_line);
504  		if (raw3270_request_add_data(rq, tp->converted_line, len))
505  			break;
506  		line->dirty = 0;
507  		if (++tp->oops_line >= tty3270_tty_rows(tp))
508  			tp->oops_line = 0;
509  	}
510  
511  	if (i == tp->allocated_lines) {
512  		if (tp->oops_line < tty3270_tty_rows(tp)) {
513  			tty3270_add_ra(tp, buf, 0, tty3270_tty_rows(tp), 0);
514  			if (raw3270_request_add_data(rq, buf, sizeof(buf)))
515  				return;
516  		}
517  		tp->update_flags &= ~TTY_UPDATE_LINES;
518  	}
519  }
520  
521  /*
522   * Update 3270 display.
523   */
tty3270_update(struct timer_list * t)524  static void tty3270_update(struct timer_list *t)
525  {
526  	struct tty3270 *tp = from_timer(tp, t, timer);
527  	struct raw3270_request *wrq;
528  	u8 cmd = TC_WRITE;
529  	int rc, len;
530  
531  	wrq = xchg(&tp->write, 0);
532  	if (!wrq) {
533  		tty3270_set_timer(tp, 1);
534  		return;
535  	}
536  
537  	spin_lock_irq(&tp->view.lock);
538  	if (tp->update_flags == TTY_UPDATE_ALL)
539  		cmd = TC_EWRITEA;
540  
541  	raw3270_request_set_cmd(wrq, cmd);
542  	raw3270_request_add_data(wrq, &tp->wcc, 1);
543  	tp->wcc = TW_NONE;
544  
545  	/*
546  	 * Update status line.
547  	 */
548  	if (tp->update_flags & TTY_UPDATE_STATUS) {
549  		len = tty3270_add_status(tp);
550  		if (raw3270_request_add_data(wrq, tp->converted_line, len) == 0)
551  			tp->update_flags &= ~TTY_UPDATE_STATUS;
552  	}
553  
554  	/*
555  	 * Write input line.
556  	 */
557  	if (tp->update_flags & TTY_UPDATE_INPUT) {
558  		len = tty3270_add_prompt(tp);
559  		if (raw3270_request_add_data(wrq, tp->converted_line, len) == 0)
560  			tp->update_flags &= ~TTY_UPDATE_INPUT;
561  	}
562  
563  	if (tp->update_flags & TTY_UPDATE_LINES) {
564  		if (oops_in_progress)
565  			tty3270_update_lines_all(tp, wrq);
566  		else
567  			tty3270_update_lines_visible(tp, wrq);
568  	}
569  
570  	wrq->callback = tty3270_write_callback;
571  	rc = raw3270_start(&tp->view, wrq);
572  	if (rc == 0) {
573  		if (tp->update_flags)
574  			tty3270_set_timer(tp, 1);
575  	} else {
576  		raw3270_request_reset(wrq);
577  		xchg(&tp->write, wrq);
578  	}
579  	spin_unlock_irq(&tp->view.lock);
580  }
581  
582  /*
583   * Command recalling.
584   */
tty3270_rcl_add(struct tty3270 * tp,char * input,int len)585  static void tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
586  {
587  	char *p;
588  
589  	if (len <= 0)
590  		return;
591  	p = tp->rcl_lines[tp->rcl_write_index++];
592  	tp->rcl_write_index &= TTY3270_RECALL_SIZE - 1;
593  	memcpy(p, input, len);
594  	p[len] = '\0';
595  	tp->rcl_read_index = tp->rcl_write_index;
596  }
597  
tty3270_rcl_backward(struct kbd_data * kbd)598  static void tty3270_rcl_backward(struct kbd_data *kbd)
599  {
600  	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
601  	int i = 0;
602  
603  	spin_lock_irq(&tp->view.lock);
604  	if (tp->inattr == TF_INPUT) {
605  		do {
606  			tp->rcl_read_index--;
607  			tp->rcl_read_index &= TTY3270_RECALL_SIZE - 1;
608  		} while (!*tp->rcl_lines[tp->rcl_read_index] &&
609  			 i++ < TTY3270_RECALL_SIZE - 1);
610  		tty3270_update_prompt(tp, tp->rcl_lines[tp->rcl_read_index]);
611  	}
612  	spin_unlock_irq(&tp->view.lock);
613  }
614  
615  /*
616   * Deactivate tty view.
617   */
tty3270_exit_tty(struct kbd_data * kbd)618  static void tty3270_exit_tty(struct kbd_data *kbd)
619  {
620  	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
621  
622  	raw3270_deactivate_view(&tp->view);
623  }
624  
tty3270_redraw(struct tty3270 * tp)625  static void tty3270_redraw(struct tty3270 *tp)
626  {
627  	int i;
628  
629  	for (i = 0; i < tty3270_tty_rows(tp); i++)
630  		tty3270_get_view_line(tp, i)->dirty = 1;
631  	tp->update_flags = TTY_UPDATE_ALL;
632  	tty3270_set_timer(tp, 1);
633  }
634  
635  /*
636   * Scroll forward in history.
637   */
tty3270_scroll_forward(struct kbd_data * kbd)638  static void tty3270_scroll_forward(struct kbd_data *kbd)
639  {
640  	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
641  
642  	spin_lock_irq(&tp->view.lock);
643  
644  	if (tp->nr_up >= tty3270_tty_rows(tp))
645  		tp->nr_up -= tty3270_tty_rows(tp) / 2;
646  	else
647  		tp->nr_up = 0;
648  	tty3270_redraw(tp);
649  	spin_unlock_irq(&tp->view.lock);
650  }
651  
652  /*
653   * Scroll backward in history.
654   */
tty3270_scroll_backward(struct kbd_data * kbd)655  static void tty3270_scroll_backward(struct kbd_data *kbd)
656  {
657  	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
658  
659  	spin_lock_irq(&tp->view.lock);
660  	tp->nr_up += tty3270_tty_rows(tp) / 2;
661  	if (tp->nr_up > tp->allocated_lines - tty3270_tty_rows(tp))
662  		tp->nr_up = tp->allocated_lines - tty3270_tty_rows(tp);
663  	tty3270_redraw(tp);
664  	spin_unlock_irq(&tp->view.lock);
665  }
666  
667  /*
668   * Pass input line to tty.
669   */
tty3270_read_tasklet(unsigned long data)670  static void tty3270_read_tasklet(unsigned long data)
671  {
672  	struct raw3270_request *rrq = (struct raw3270_request *)data;
673  	static char kreset_data = TW_KR;
674  	struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
675  	char *input;
676  	int len;
677  
678  	spin_lock_irq(&tp->view.lock);
679  	/*
680  	 * Two AID keys are special: For 0x7d (enter) the input line
681  	 * has to be emitted to the tty and for 0x6d the screen
682  	 * needs to be redrawn.
683  	 */
684  	input = NULL;
685  	len = 0;
686  	switch (tp->input[0]) {
687  	case AID_ENTER:
688  		/* Enter: write input to tty. */
689  		input = tp->input + 6;
690  		len = tty3270_input_size(tp->view.cols) - 6 - rrq->rescnt;
691  		if (tp->inattr != TF_INPUTN)
692  			tty3270_rcl_add(tp, input, len);
693  		if (tp->nr_up > 0)
694  			tp->nr_up = 0;
695  		/* Clear input area. */
696  		tty3270_update_prompt(tp, "");
697  		tty3270_set_timer(tp, 1);
698  		break;
699  	case AID_CLEAR:
700  		/* Display has been cleared. Redraw. */
701  		tp->update_flags = TTY_UPDATE_ALL;
702  		tty3270_set_timer(tp, 1);
703  		if (!list_empty(&tp->readpartreq->list))
704  			break;
705  		raw3270_start_request(&tp->view, tp->readpartreq, TC_WRITESF,
706  				      (char *)sfq_read_partition, sizeof(sfq_read_partition));
707  		break;
708  	case AID_READ_PARTITION:
709  		raw3270_read_modified_cb(tp->readpartreq, tp->input);
710  		break;
711  	default:
712  		break;
713  	}
714  	spin_unlock_irq(&tp->view.lock);
715  
716  	/* Start keyboard reset command. */
717  	raw3270_start_request(&tp->view, tp->kreset, TC_WRITE, &kreset_data, 1);
718  
719  	while (len-- > 0)
720  		kbd_keycode(tp->kbd, *input++);
721  	/* Emit keycode for AID byte. */
722  	kbd_keycode(tp->kbd, 256 + tp->input[0]);
723  
724  	raw3270_request_reset(rrq);
725  	xchg(&tp->read, rrq);
726  	raw3270_put_view(&tp->view);
727  }
728  
729  /*
730   * Read request completion callback.
731   */
tty3270_read_callback(struct raw3270_request * rq,void * data)732  static void tty3270_read_callback(struct raw3270_request *rq, void *data)
733  {
734  	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
735  
736  	raw3270_get_view(rq->view);
737  	/* Schedule tasklet to pass input to tty. */
738  	tasklet_schedule(&tp->readlet);
739  }
740  
741  /*
742   * Issue a read request. Call with device lock.
743   */
tty3270_issue_read(struct tty3270 * tp,int lock)744  static void tty3270_issue_read(struct tty3270 *tp, int lock)
745  {
746  	struct raw3270_request *rrq;
747  	int rc;
748  
749  	rrq = xchg(&tp->read, 0);
750  	if (!rrq)
751  		/* Read already scheduled. */
752  		return;
753  	rrq->callback = tty3270_read_callback;
754  	rrq->callback_data = tp;
755  	raw3270_request_set_cmd(rrq, TC_READMOD);
756  	raw3270_request_set_data(rrq, tp->input, tty3270_input_size(tp->view.cols));
757  	/* Issue the read modified request. */
758  	if (lock)
759  		rc = raw3270_start(&tp->view, rrq);
760  	else
761  		rc = raw3270_start_irq(&tp->view, rrq);
762  	if (rc) {
763  		raw3270_request_reset(rrq);
764  		xchg(&tp->read, rrq);
765  	}
766  }
767  
768  /*
769   * Hang up the tty
770   */
tty3270_hangup_tasklet(unsigned long data)771  static void tty3270_hangup_tasklet(unsigned long data)
772  {
773  	struct tty3270 *tp = (struct tty3270 *)data;
774  
775  	tty_port_tty_hangup(&tp->port, true);
776  	raw3270_put_view(&tp->view);
777  }
778  
779  /*
780   * Switch to the tty view.
781   */
tty3270_activate(struct raw3270_view * view)782  static int tty3270_activate(struct raw3270_view *view)
783  {
784  	struct tty3270 *tp = container_of(view, struct tty3270, view);
785  
786  	tp->update_flags = TTY_UPDATE_ALL;
787  	tty3270_set_timer(tp, 1);
788  	return 0;
789  }
790  
tty3270_deactivate(struct raw3270_view * view)791  static void tty3270_deactivate(struct raw3270_view *view)
792  {
793  	struct tty3270 *tp = container_of(view, struct tty3270, view);
794  
795  	del_timer(&tp->timer);
796  }
797  
tty3270_irq(struct tty3270 * tp,struct raw3270_request * rq,struct irb * irb)798  static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
799  {
800  	/* Handle ATTN. Schedule tasklet to read aid. */
801  	if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
802  		if (!tp->throttle)
803  			tty3270_issue_read(tp, 0);
804  		else
805  			tp->attn = 1;
806  	}
807  
808  	if (rq) {
809  		if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
810  			rq->rc = -EIO;
811  			raw3270_get_view(&tp->view);
812  			tasklet_schedule(&tp->hanglet);
813  		} else {
814  			/* Normal end. Copy residual count. */
815  			rq->rescnt = irb->scsw.cmd.count;
816  		}
817  	} else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
818  		/* Interrupt without an outstanding request -> update all */
819  		tp->update_flags = TTY_UPDATE_ALL;
820  		tty3270_set_timer(tp, 1);
821  	}
822  }
823  
824  /*
825   * Allocate tty3270 structure.
826   */
tty3270_alloc_view(void)827  static struct tty3270 *tty3270_alloc_view(void)
828  {
829  	struct tty3270 *tp;
830  
831  	tp = kzalloc(sizeof(*tp), GFP_KERNEL);
832  	if (!tp)
833  		goto out_err;
834  
835  	tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
836  	if (IS_ERR(tp->write))
837  		goto out_tp;
838  	tp->read = raw3270_request_alloc(0);
839  	if (IS_ERR(tp->read))
840  		goto out_write;
841  	tp->kreset = raw3270_request_alloc(1);
842  	if (IS_ERR(tp->kreset))
843  		goto out_read;
844  	tp->readpartreq = raw3270_request_alloc(sizeof(sfq_read_partition));
845  	if (IS_ERR(tp->readpartreq))
846  		goto out_reset;
847  	tp->kbd = kbd_alloc();
848  	if (!tp->kbd)
849  		goto out_readpartreq;
850  
851  	tty_port_init(&tp->port);
852  	timer_setup(&tp->timer, tty3270_update, 0);
853  	tasklet_init(&tp->readlet, tty3270_read_tasklet,
854  		     (unsigned long)tp->read);
855  	tasklet_init(&tp->hanglet, tty3270_hangup_tasklet,
856  		     (unsigned long)tp);
857  	return tp;
858  
859  out_readpartreq:
860  	raw3270_request_free(tp->readpartreq);
861  out_reset:
862  	raw3270_request_free(tp->kreset);
863  out_read:
864  	raw3270_request_free(tp->read);
865  out_write:
866  	raw3270_request_free(tp->write);
867  out_tp:
868  	kfree(tp);
869  out_err:
870  	return ERR_PTR(-ENOMEM);
871  }
872  
873  /*
874   * Free tty3270 structure.
875   */
tty3270_free_view(struct tty3270 * tp)876  static void tty3270_free_view(struct tty3270 *tp)
877  {
878  	kbd_free(tp->kbd);
879  	raw3270_request_free(tp->kreset);
880  	raw3270_request_free(tp->read);
881  	raw3270_request_free(tp->write);
882  	free_page((unsigned long)tp->converted_line);
883  	tty_port_destroy(&tp->port);
884  	kfree(tp);
885  }
886  
887  /*
888   * Allocate tty3270 screen.
889   */
tty3270_alloc_screen(struct tty3270 * tp,unsigned int rows,unsigned int cols,int * allocated_out)890  static struct tty3270_line *tty3270_alloc_screen(struct tty3270 *tp, unsigned int rows,
891  						 unsigned int cols, int *allocated_out)
892  {
893  	struct tty3270_line *screen;
894  	int allocated, lines;
895  
896  	allocated = __roundup_pow_of_two(rows) * TTY3270_SCREEN_PAGES;
897  	screen = kcalloc(allocated, sizeof(struct tty3270_line), GFP_KERNEL);
898  	if (!screen)
899  		goto out_err;
900  	for (lines = 0; lines < allocated; lines++) {
901  		screen[lines].cells = kcalloc(cols, sizeof(struct tty3270_cell), GFP_KERNEL);
902  		if (!screen[lines].cells)
903  			goto out_screen;
904  	}
905  	*allocated_out = allocated;
906  	return screen;
907  out_screen:
908  	while (lines--)
909  		kfree(screen[lines].cells);
910  	kfree(screen);
911  out_err:
912  	return ERR_PTR(-ENOMEM);
913  }
914  
tty3270_alloc_recall(int cols)915  static char **tty3270_alloc_recall(int cols)
916  {
917  	char **lines;
918  	int i;
919  
920  	lines = kmalloc_array(TTY3270_RECALL_SIZE, sizeof(char *), GFP_KERNEL);
921  	if (!lines)
922  		return NULL;
923  	for (i = 0; i < TTY3270_RECALL_SIZE; i++) {
924  		lines[i] = kcalloc(1, tty3270_input_size(cols) + 1, GFP_KERNEL);
925  		if (!lines[i])
926  			break;
927  	}
928  
929  	if (i == TTY3270_RECALL_SIZE)
930  		return lines;
931  
932  	while (i--)
933  		kfree(lines[i]);
934  	kfree(lines);
935  	return NULL;
936  }
937  
tty3270_free_recall(char ** lines)938  static void tty3270_free_recall(char **lines)
939  {
940  	int i;
941  
942  	for (i = 0; i < TTY3270_RECALL_SIZE; i++)
943  		kfree(lines[i]);
944  	kfree(lines);
945  }
946  
947  /*
948   * Free tty3270 screen.
949   */
tty3270_free_screen(struct tty3270_line * screen,int old_lines)950  static void tty3270_free_screen(struct tty3270_line *screen, int old_lines)
951  {
952  	int lines;
953  
954  	for (lines = 0; lines < old_lines; lines++)
955  		kfree(screen[lines].cells);
956  	kfree(screen);
957  }
958  
959  /*
960   * Resize tty3270 screen
961   */
tty3270_resize(struct raw3270_view * view,int new_model,int new_rows,int new_cols,int old_model,int old_rows,int old_cols)962  static void tty3270_resize(struct raw3270_view *view,
963  			   int new_model, int new_rows, int new_cols,
964  			   int old_model, int old_rows, int old_cols)
965  {
966  	struct tty3270 *tp = container_of(view, struct tty3270, view);
967  	struct tty3270_line *screen, *oscreen;
968  	char **old_rcl_lines, **new_rcl_lines;
969  	char *old_prompt, *new_prompt;
970  	char *old_input, *new_input;
971  	struct tty_struct *tty;
972  	struct winsize ws;
973  	int new_allocated, old_allocated = tp->allocated_lines;
974  
975  	if (old_model == new_model &&
976  	    old_cols == new_cols &&
977  	    old_rows == new_rows) {
978  		spin_lock_irq(&tp->view.lock);
979  		tty3270_redraw(tp);
980  		spin_unlock_irq(&tp->view.lock);
981  		return;
982  	}
983  
984  	new_input = kzalloc(tty3270_input_size(new_cols), GFP_KERNEL | GFP_DMA);
985  	if (!new_input)
986  		return;
987  	new_prompt = kzalloc(tty3270_input_size(new_cols), GFP_KERNEL);
988  	if (!new_prompt)
989  		goto out_input;
990  	screen = tty3270_alloc_screen(tp, new_rows, new_cols, &new_allocated);
991  	if (IS_ERR(screen))
992  		goto out_prompt;
993  	new_rcl_lines = tty3270_alloc_recall(new_cols);
994  	if (!new_rcl_lines)
995  		goto out_screen;
996  
997  	/* Switch to new output size */
998  	spin_lock_irq(&tp->view.lock);
999  	tty3270_blank_screen(tp);
1000  	oscreen = tp->screen;
1001  	tp->screen = screen;
1002  	tp->allocated_lines = new_allocated;
1003  	tp->view.rows = new_rows;
1004  	tp->view.cols = new_cols;
1005  	tp->view.model = new_model;
1006  	tp->update_flags = TTY_UPDATE_ALL;
1007  	old_input = tp->input;
1008  	old_prompt = tp->prompt;
1009  	old_rcl_lines = tp->rcl_lines;
1010  	tp->input = new_input;
1011  	tp->prompt = new_prompt;
1012  	tp->rcl_lines = new_rcl_lines;
1013  	tp->rcl_read_index = 0;
1014  	tp->rcl_write_index = 0;
1015  	spin_unlock_irq(&tp->view.lock);
1016  	tty3270_free_screen(oscreen, old_allocated);
1017  	kfree(old_input);
1018  	kfree(old_prompt);
1019  	tty3270_free_recall(old_rcl_lines);
1020  	tty3270_set_timer(tp, 1);
1021  	/* Informat tty layer about new size */
1022  	tty = tty_port_tty_get(&tp->port);
1023  	if (!tty)
1024  		return;
1025  	ws.ws_row = tty3270_tty_rows(tp);
1026  	ws.ws_col = tp->view.cols;
1027  	tty_do_resize(tty, &ws);
1028  	tty_kref_put(tty);
1029  	return;
1030  out_screen:
1031  	tty3270_free_screen(screen, new_rows);
1032  out_prompt:
1033  	kfree(new_prompt);
1034  out_input:
1035  	kfree(new_input);
1036  }
1037  
1038  /*
1039   * Unlink tty3270 data structure from tty.
1040   */
tty3270_release(struct raw3270_view * view)1041  static void tty3270_release(struct raw3270_view *view)
1042  {
1043  	struct tty3270 *tp = container_of(view, struct tty3270, view);
1044  	struct tty_struct *tty = tty_port_tty_get(&tp->port);
1045  
1046  	if (tty) {
1047  		tty->driver_data = NULL;
1048  		tty_port_tty_set(&tp->port, NULL);
1049  		tty_hangup(tty);
1050  		raw3270_put_view(&tp->view);
1051  		tty_kref_put(tty);
1052  	}
1053  }
1054  
1055  /*
1056   * Free tty3270 data structure
1057   */
tty3270_free(struct raw3270_view * view)1058  static void tty3270_free(struct raw3270_view *view)
1059  {
1060  	struct tty3270 *tp = container_of(view, struct tty3270, view);
1061  
1062  	del_timer_sync(&tp->timer);
1063  	tty3270_free_screen(tp->screen, tp->allocated_lines);
1064  	free_page((unsigned long)tp->converted_line);
1065  	kfree(tp->input);
1066  	kfree(tp->prompt);
1067  	tty3270_free_view(tp);
1068  }
1069  
1070  /*
1071   * Delayed freeing of tty3270 views.
1072   */
tty3270_del_views(void)1073  static void tty3270_del_views(void)
1074  {
1075  	int i;
1076  
1077  	for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) {
1078  		struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i);
1079  
1080  		if (!IS_ERR(view))
1081  			raw3270_del_view(view);
1082  	}
1083  }
1084  
1085  static struct raw3270_fn tty3270_fn = {
1086  	.activate = tty3270_activate,
1087  	.deactivate = tty3270_deactivate,
1088  	.intv = (void *)tty3270_irq,
1089  	.release = tty3270_release,
1090  	.free = tty3270_free,
1091  	.resize = tty3270_resize
1092  };
1093  
1094  static int
tty3270_create_view(int index,struct tty3270 ** newtp)1095  tty3270_create_view(int index, struct tty3270 **newtp)
1096  {
1097  	struct tty3270 *tp;
1098  	int rc;
1099  
1100  	if (tty3270_max_index < index + 1)
1101  		tty3270_max_index = index + 1;
1102  
1103  	/* Allocate tty3270 structure on first open. */
1104  	tp = tty3270_alloc_view();
1105  	if (IS_ERR(tp))
1106  		return PTR_ERR(tp);
1107  
1108  	rc = raw3270_add_view(&tp->view, &tty3270_fn,
1109  			      index + RAW3270_FIRSTMINOR,
1110  			      RAW3270_VIEW_LOCK_IRQ);
1111  	if (rc)
1112  		goto out_free_view;
1113  
1114  	tp->screen = tty3270_alloc_screen(tp, tp->view.rows, tp->view.cols,
1115  					  &tp->allocated_lines);
1116  	if (IS_ERR(tp->screen)) {
1117  		rc = PTR_ERR(tp->screen);
1118  		goto out_put_view;
1119  	}
1120  
1121  	tp->converted_line = (void *)__get_free_page(GFP_KERNEL);
1122  	if (!tp->converted_line) {
1123  		rc = -ENOMEM;
1124  		goto out_free_screen;
1125  	}
1126  
1127  	tp->input = kzalloc(tty3270_input_size(tp->view.cols), GFP_KERNEL | GFP_DMA);
1128  	if (!tp->input) {
1129  		rc = -ENOMEM;
1130  		goto out_free_converted_line;
1131  	}
1132  
1133  	tp->prompt = kzalloc(tty3270_input_size(tp->view.cols), GFP_KERNEL);
1134  	if (!tp->prompt) {
1135  		rc = -ENOMEM;
1136  		goto out_free_input;
1137  	}
1138  
1139  	tp->rcl_lines = tty3270_alloc_recall(tp->view.cols);
1140  	if (!tp->rcl_lines) {
1141  		rc = -ENOMEM;
1142  		goto out_free_prompt;
1143  	}
1144  
1145  	/* Create blank line for every line in the tty output area. */
1146  	tty3270_blank_screen(tp);
1147  
1148  	tp->kbd->port = &tp->port;
1149  	tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
1150  	tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
1151  	tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
1152  	tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward;
1153  	kbd_ascebc(tp->kbd, tp->view.ascebc);
1154  
1155  	raw3270_activate_view(&tp->view);
1156  	raw3270_put_view(&tp->view);
1157  	*newtp = tp;
1158  	return 0;
1159  
1160  out_free_prompt:
1161  	kfree(tp->prompt);
1162  out_free_input:
1163  	kfree(tp->input);
1164  out_free_converted_line:
1165  	free_page((unsigned long)tp->converted_line);
1166  out_free_screen:
1167  	tty3270_free_screen(tp->screen, tp->view.rows);
1168  out_put_view:
1169  	raw3270_put_view(&tp->view);
1170  	raw3270_del_view(&tp->view);
1171  out_free_view:
1172  	tty3270_free_view(tp);
1173  	return rc;
1174  }
1175  
1176  /*
1177   * This routine is called whenever a 3270 tty is opened first time.
1178   */
1179  static int
tty3270_install(struct tty_driver * driver,struct tty_struct * tty)1180  tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
1181  {
1182  	struct raw3270_view *view;
1183  	struct tty3270 *tp;
1184  	int rc;
1185  
1186  	/* Check if the tty3270 is already there. */
1187  	view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR);
1188  	if (IS_ERR(view)) {
1189  		rc = tty3270_create_view(tty->index, &tp);
1190  		if (rc)
1191  			return rc;
1192  	} else {
1193  		tp = container_of(view, struct tty3270, view);
1194  		tty->driver_data = tp;
1195  		tp->inattr = TF_INPUT;
1196  	}
1197  
1198  	tty->winsize.ws_row = tty3270_tty_rows(tp);
1199  	tty->winsize.ws_col = tp->view.cols;
1200  	rc = tty_port_install(&tp->port, driver, tty);
1201  	if (rc) {
1202  		raw3270_put_view(&tp->view);
1203  		return rc;
1204  	}
1205  	tty->driver_data = tp;
1206  	return 0;
1207  }
1208  
1209  /*
1210   * This routine is called whenever a 3270 tty is opened.
1211   */
tty3270_open(struct tty_struct * tty,struct file * filp)1212  static int tty3270_open(struct tty_struct *tty, struct file *filp)
1213  {
1214  	struct tty3270 *tp = tty->driver_data;
1215  	struct tty_port *port = &tp->port;
1216  
1217  	port->count++;
1218  	tty_port_tty_set(port, tty);
1219  	return 0;
1220  }
1221  
1222  /*
1223   * This routine is called when the 3270 tty is closed. We wait
1224   * for the remaining request to be completed. Then we clean up.
1225   */
tty3270_close(struct tty_struct * tty,struct file * filp)1226  static void tty3270_close(struct tty_struct *tty, struct file *filp)
1227  {
1228  	struct tty3270 *tp = tty->driver_data;
1229  
1230  	if (tty->count > 1)
1231  		return;
1232  	if (tp)
1233  		tty_port_tty_set(&tp->port, NULL);
1234  }
1235  
tty3270_cleanup(struct tty_struct * tty)1236  static void tty3270_cleanup(struct tty_struct *tty)
1237  {
1238  	struct tty3270 *tp = tty->driver_data;
1239  
1240  	if (tp) {
1241  		tty->driver_data = NULL;
1242  		raw3270_put_view(&tp->view);
1243  	}
1244  }
1245  
1246  /*
1247   * We always have room.
1248   */
tty3270_write_room(struct tty_struct * tty)1249  static unsigned int tty3270_write_room(struct tty_struct *tty)
1250  {
1251  	return INT_MAX;
1252  }
1253  
1254  /*
1255   * Insert character into the screen at the current position with the
1256   * current color and highlight. This function does NOT do cursor movement.
1257   */
tty3270_put_character(struct tty3270 * tp,char ch)1258  static void tty3270_put_character(struct tty3270 *tp, char ch)
1259  {
1260  	struct tty3270_line *line;
1261  	struct tty3270_cell *cell;
1262  
1263  	line = tty3270_get_write_line(tp, tp->cy);
1264  	if (line->len <= tp->cx) {
1265  		while (line->len < tp->cx) {
1266  			cell = line->cells + line->len;
1267  			cell->character = ' ';
1268  			cell->attributes = tp->attributes;
1269  			line->len++;
1270  		}
1271  		line->len++;
1272  	}
1273  	cell = line->cells + tp->cx;
1274  	cell->character = ch;
1275  	cell->attributes = tp->attributes;
1276  	line->dirty = 1;
1277  }
1278  
1279  /*
1280   * Do carriage return.
1281   */
tty3270_cr(struct tty3270 * tp)1282  static void tty3270_cr(struct tty3270 *tp)
1283  {
1284  	tp->cx = 0;
1285  }
1286  
1287  /*
1288   * Do line feed.
1289   */
tty3270_lf(struct tty3270 * tp)1290  static void tty3270_lf(struct tty3270 *tp)
1291  {
1292  	struct tty3270_line *line;
1293  	int i;
1294  
1295  	if (tp->cy < tty3270_tty_rows(tp) - 1) {
1296  		tp->cy++;
1297  	} else {
1298  		tp->line_view_start = tty3270_line_increment(tp, tp->line_view_start, 1);
1299  		tp->line_write_start = tty3270_line_increment(tp, tp->line_write_start, 1);
1300  		for (i = 0; i < tty3270_tty_rows(tp); i++)
1301  			tty3270_get_view_line(tp, i)->dirty = 1;
1302  	}
1303  
1304  	line = tty3270_get_write_line(tp, tp->cy);
1305  	line->len = 0;
1306  	line->dirty = 1;
1307  }
1308  
tty3270_ri(struct tty3270 * tp)1309  static void tty3270_ri(struct tty3270 *tp)
1310  {
1311  	if (tp->cy > 0)
1312  		tp->cy--;
1313  }
1314  
tty3270_reset_cell(struct tty3270 * tp,struct tty3270_cell * cell)1315  static void tty3270_reset_cell(struct tty3270 *tp, struct tty3270_cell *cell)
1316  {
1317  	cell->character = ' ';
1318  	tty3270_reset_attributes(&cell->attributes);
1319  }
1320  
1321  /*
1322   * Insert characters at current position.
1323   */
tty3270_insert_characters(struct tty3270 * tp,int n)1324  static void tty3270_insert_characters(struct tty3270 *tp, int n)
1325  {
1326  	struct tty3270_line *line;
1327  	int k;
1328  
1329  	line = tty3270_get_write_line(tp, tp->cy);
1330  	while (line->len < tp->cx)
1331  		tty3270_reset_cell(tp, &line->cells[line->len++]);
1332  	if (n > tp->view.cols - tp->cx)
1333  		n = tp->view.cols - tp->cx;
1334  	k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n);
1335  	while (k--)
1336  		line->cells[tp->cx + n + k] = line->cells[tp->cx + k];
1337  	line->len += n;
1338  	if (line->len > tp->view.cols)
1339  		line->len = tp->view.cols;
1340  	while (n-- > 0) {
1341  		line->cells[tp->cx + n].character = ' ';
1342  		line->cells[tp->cx + n].attributes = tp->attributes;
1343  	}
1344  }
1345  
1346  /*
1347   * Delete characters at current position.
1348   */
tty3270_delete_characters(struct tty3270 * tp,int n)1349  static void tty3270_delete_characters(struct tty3270 *tp, int n)
1350  {
1351  	struct tty3270_line *line;
1352  	int i;
1353  
1354  	line = tty3270_get_write_line(tp, tp->cy);
1355  	if (line->len <= tp->cx)
1356  		return;
1357  	if (line->len - tp->cx <= n) {
1358  		line->len = tp->cx;
1359  		return;
1360  	}
1361  	for (i = tp->cx; i + n < line->len; i++)
1362  		line->cells[i] = line->cells[i + n];
1363  	line->len -= n;
1364  }
1365  
1366  /*
1367   * Erase characters at current position.
1368   */
tty3270_erase_characters(struct tty3270 * tp,int n)1369  static void tty3270_erase_characters(struct tty3270 *tp, int n)
1370  {
1371  	struct tty3270_line *line;
1372  	struct tty3270_cell *cell;
1373  
1374  	line = tty3270_get_write_line(tp, tp->cy);
1375  	while (line->len > tp->cx && n-- > 0) {
1376  		cell = line->cells + tp->cx++;
1377  		tty3270_reset_cell(tp, cell);
1378  	}
1379  	tp->cx += n;
1380  	tp->cx = min_t(int, tp->cx, tp->view.cols - 1);
1381  }
1382  
1383  /*
1384   * Erase line, 3 different cases:
1385   *  Esc [ 0 K	Erase from current position to end of line inclusive
1386   *  Esc [ 1 K	Erase from beginning of line to current position inclusive
1387   *  Esc [ 2 K	Erase entire line (without moving cursor)
1388   */
tty3270_erase_line(struct tty3270 * tp,int mode)1389  static void tty3270_erase_line(struct tty3270 *tp, int mode)
1390  {
1391  	struct tty3270_line *line;
1392  	struct tty3270_cell *cell;
1393  	int i, start, end;
1394  
1395  	line = tty3270_get_write_line(tp, tp->cy);
1396  
1397  	switch (mode) {
1398  	case 0:
1399  		start = tp->cx;
1400  		end = tp->view.cols;
1401  		break;
1402  	case 1:
1403  		start = 0;
1404  		end = tp->cx;
1405  		break;
1406  	case 2:
1407  		start = 0;
1408  		end = tp->view.cols;
1409  		break;
1410  	default:
1411  		return;
1412  	}
1413  
1414  	for (i = start; i < end; i++) {
1415  		cell = line->cells + i;
1416  		tty3270_reset_cell(tp, cell);
1417  		cell->attributes.b_color = tp->attributes.b_color;
1418  	}
1419  
1420  	if (line->len <= end)
1421  		line->len = end;
1422  }
1423  
1424  /*
1425   * Erase display, 3 different cases:
1426   *  Esc [ 0 J	Erase from current position to bottom of screen inclusive
1427   *  Esc [ 1 J	Erase from top of screen to current position inclusive
1428   *  Esc [ 2 J	Erase entire screen (without moving the cursor)
1429   */
tty3270_erase_display(struct tty3270 * tp,int mode)1430  static void tty3270_erase_display(struct tty3270 *tp, int mode)
1431  {
1432  	struct tty3270_line *line;
1433  	int i, start, end;
1434  
1435  	switch (mode) {
1436  	case 0:
1437  		tty3270_erase_line(tp, 0);
1438  		start = tp->cy + 1;
1439  		end = tty3270_tty_rows(tp);
1440  		break;
1441  	case 1:
1442  		start = 0;
1443  		end = tp->cy;
1444  		tty3270_erase_line(tp, 1);
1445  		break;
1446  	case 2:
1447  		start = 0;
1448  		end = tty3270_tty_rows(tp);
1449  		break;
1450  	default:
1451  		return;
1452  	}
1453  	for (i = start; i < end; i++) {
1454  		line = tty3270_get_write_line(tp, i);
1455  		line->len = 0;
1456  		line->dirty = 1;
1457  	}
1458  }
1459  
1460  /*
1461   * Set attributes found in an escape sequence.
1462   *  Esc [ <attr> ; <attr> ; ... m
1463   */
tty3270_set_attributes(struct tty3270 * tp)1464  static void tty3270_set_attributes(struct tty3270 *tp)
1465  {
1466  	int i, attr;
1467  
1468  	for (i = 0; i <= tp->esc_npar; i++) {
1469  		attr = tp->esc_par[i];
1470  		switch (attr) {
1471  		case 0:		/* Reset */
1472  			tty3270_reset_attributes(&tp->attributes);
1473  			break;
1474  		/* Highlight. */
1475  		case 4:		/* Start underlining. */
1476  			tp->attributes.highlight = TTY3270_HIGHLIGHT_UNDERSCORE;
1477  			break;
1478  		case 5:		/* Start blink. */
1479  			tp->attributes.highlight = TTY3270_HIGHLIGHT_BLINK;
1480  			break;
1481  		case 7:		/* Start reverse. */
1482  			tp->attributes.highlight = TTY3270_HIGHLIGHT_REVERSE;
1483  			break;
1484  		case 24:	/* End underlining */
1485  			tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_UNDERSCORE;
1486  			break;
1487  		case 25:	/* End blink. */
1488  			tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_BLINK;
1489  			break;
1490  		case 27:	/* End reverse. */
1491  			tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_REVERSE;
1492  			break;
1493  		/* Foreground color. */
1494  		case 30:	/* Black */
1495  		case 31:	/* Red */
1496  		case 32:	/* Green */
1497  		case 33:	/* Yellow */
1498  		case 34:	/* Blue */
1499  		case 35:	/* Magenta */
1500  		case 36:	/* Cyan */
1501  		case 37:	/* White */
1502  		case 39:	/* Black */
1503  			tp->attributes.f_color = attr - 30;
1504  			break;
1505  		/* Background color. */
1506  		case 40:	/* Black */
1507  		case 41:	/* Red */
1508  		case 42:	/* Green */
1509  		case 43:	/* Yellow */
1510  		case 44:	/* Blue */
1511  		case 45:	/* Magenta */
1512  		case 46:	/* Cyan */
1513  		case 47:	/* White */
1514  		case 49:	/* Black */
1515  			tp->attributes.b_color = attr - 40;
1516  			break;
1517  		}
1518  	}
1519  }
1520  
tty3270_getpar(struct tty3270 * tp,int ix)1521  static inline int tty3270_getpar(struct tty3270 *tp, int ix)
1522  {
1523  	return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
1524  }
1525  
tty3270_goto_xy(struct tty3270 * tp,int cx,int cy)1526  static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
1527  {
1528  	struct tty3270_line *line;
1529  	struct tty3270_cell *cell;
1530  	int max_cx = max(0, cx);
1531  	int max_cy = max(0, cy);
1532  
1533  	tp->cx = min_t(int, tp->view.cols - 1, max_cx);
1534  	line = tty3270_get_write_line(tp, tp->cy);
1535  	while (line->len < tp->cx) {
1536  		cell = line->cells + line->len;
1537  		cell->character = ' ';
1538  		cell->attributes = tp->attributes;
1539  		line->len++;
1540  	}
1541  	tp->cy = min_t(int, tty3270_tty_rows(tp) - 1, max_cy);
1542  }
1543  
1544  /*
1545   * Process escape sequences. Known sequences:
1546   *  Esc 7			Save Cursor Position
1547   *  Esc 8			Restore Cursor Position
1548   *  Esc [ Pn ; Pn ; .. m	Set attributes
1549   *  Esc [ Pn ; Pn H		Cursor Position
1550   *  Esc [ Pn ; Pn f		Cursor Position
1551   *  Esc [ Pn A			Cursor Up
1552   *  Esc [ Pn B			Cursor Down
1553   *  Esc [ Pn C			Cursor Forward
1554   *  Esc [ Pn D			Cursor Backward
1555   *  Esc [ Pn G			Cursor Horizontal Absolute
1556   *  Esc [ Pn X			Erase Characters
1557   *  Esc [ Ps J			Erase in Display
1558   *  Esc [ Ps K			Erase in Line
1559   * // FIXME: add all the new ones.
1560   *
1561   *  Pn is a numeric parameter, a string of zero or more decimal digits.
1562   *  Ps is a selective parameter.
1563   */
tty3270_escape_sequence(struct tty3270 * tp,char ch)1564  static void tty3270_escape_sequence(struct tty3270 *tp, char ch)
1565  {
1566  	enum { ES_NORMAL, ES_ESC, ES_SQUARE, ES_PAREN, ES_GETPARS };
1567  
1568  	if (tp->esc_state == ES_NORMAL) {
1569  		if (ch == 0x1b)
1570  			/* Starting new escape sequence. */
1571  			tp->esc_state = ES_ESC;
1572  		return;
1573  	}
1574  	if (tp->esc_state == ES_ESC) {
1575  		tp->esc_state = ES_NORMAL;
1576  		switch (ch) {
1577  		case '[':
1578  			tp->esc_state = ES_SQUARE;
1579  			break;
1580  		case '(':
1581  			tp->esc_state = ES_PAREN;
1582  			break;
1583  		case 'E':
1584  			tty3270_cr(tp);
1585  			tty3270_lf(tp);
1586  			break;
1587  		case 'M':
1588  			tty3270_ri(tp);
1589  			break;
1590  		case 'D':
1591  			tty3270_lf(tp);
1592  			break;
1593  		case 'Z':		/* Respond ID. */
1594  			kbd_puts_queue(&tp->port, "\033[?6c");
1595  			break;
1596  		case '7':		/* Save cursor position. */
1597  			tp->saved_cx = tp->cx;
1598  			tp->saved_cy = tp->cy;
1599  			tp->saved_attributes = tp->attributes;
1600  			break;
1601  		case '8':		/* Restore cursor position. */
1602  			tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
1603  			tp->attributes = tp->saved_attributes;
1604  			break;
1605  		case 'c':		/* Reset terminal. */
1606  			tp->cx = 0;
1607  			tp->cy = 0;
1608  			tp->saved_cx = 0;
1609  			tp->saved_cy = 0;
1610  			tty3270_reset_attributes(&tp->attributes);
1611  			tty3270_reset_attributes(&tp->saved_attributes);
1612  			tty3270_erase_display(tp, 2);
1613  			break;
1614  		}
1615  		return;
1616  	}
1617  
1618  	switch (tp->esc_state) {
1619  	case ES_PAREN:
1620  		tp->esc_state = ES_NORMAL;
1621  		switch (ch) {
1622  		case 'B':
1623  			tp->attributes.alternate_charset = 0;
1624  			break;
1625  		case '0':
1626  			tp->attributes.alternate_charset = 1;
1627  			break;
1628  		}
1629  		return;
1630  	case ES_SQUARE:
1631  		tp->esc_state = ES_GETPARS;
1632  		memset(tp->esc_par, 0, sizeof(tp->esc_par));
1633  		tp->esc_npar = 0;
1634  		tp->esc_ques = (ch == '?');
1635  		if (tp->esc_ques)
1636  			return;
1637  		fallthrough;
1638  	case ES_GETPARS:
1639  		if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) {
1640  			tp->esc_npar++;
1641  			return;
1642  		}
1643  		if (ch >= '0' && ch <= '9') {
1644  			tp->esc_par[tp->esc_npar] *= 10;
1645  			tp->esc_par[tp->esc_npar] += ch - '0';
1646  			return;
1647  		}
1648  		break;
1649  	default:
1650  		break;
1651  	}
1652  	tp->esc_state = ES_NORMAL;
1653  	if (ch == 'n' && !tp->esc_ques) {
1654  		if (tp->esc_par[0] == 5)		/* Status report. */
1655  			kbd_puts_queue(&tp->port, "\033[0n");
1656  		else if (tp->esc_par[0] == 6) {	/* Cursor report. */
1657  			char buf[40];
1658  
1659  			sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
1660  			kbd_puts_queue(&tp->port, buf);
1661  		}
1662  		return;
1663  	}
1664  	if (tp->esc_ques)
1665  		return;
1666  	switch (ch) {
1667  	case 'm':
1668  		tty3270_set_attributes(tp);
1669  		break;
1670  	case 'H':	/* Set cursor position. */
1671  	case 'f':
1672  		tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1,
1673  				tty3270_getpar(tp, 0) - 1);
1674  		break;
1675  	case 'd':	/* Set y position. */
1676  		tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1);
1677  		break;
1678  	case 'A':	/* Cursor up. */
1679  	case 'F':
1680  		tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0));
1681  		break;
1682  	case 'B':	/* Cursor down. */
1683  	case 'e':
1684  	case 'E':
1685  		tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0));
1686  		break;
1687  	case 'C':	/* Cursor forward. */
1688  	case 'a':
1689  		tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy);
1690  		break;
1691  	case 'D':	/* Cursor backward. */
1692  		tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy);
1693  		break;
1694  	case 'G':	/* Set x position. */
1695  	case '`':
1696  		tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy);
1697  		break;
1698  	case 'X':	/* Erase Characters. */
1699  		tty3270_erase_characters(tp, tty3270_getpar(tp, 0));
1700  		break;
1701  	case 'J':	/* Erase display. */
1702  		tty3270_erase_display(tp, tp->esc_par[0]);
1703  		break;
1704  	case 'K':	/* Erase line. */
1705  		tty3270_erase_line(tp, tp->esc_par[0]);
1706  		break;
1707  	case 'P':	/* Delete characters. */
1708  		tty3270_delete_characters(tp, tty3270_getpar(tp, 0));
1709  		break;
1710  	case '@':	/* Insert characters. */
1711  		tty3270_insert_characters(tp, tty3270_getpar(tp, 0));
1712  		break;
1713  	case 's':	/* Save cursor position. */
1714  		tp->saved_cx = tp->cx;
1715  		tp->saved_cy = tp->cy;
1716  		tp->saved_attributes = tp->attributes;
1717  		break;
1718  	case 'u':	/* Restore cursor position. */
1719  		tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
1720  		tp->attributes = tp->saved_attributes;
1721  		break;
1722  	}
1723  }
1724  
1725  /*
1726   * String write routine for 3270 ttys
1727   */
tty3270_do_write(struct tty3270 * tp,struct tty_struct * tty,const unsigned char * buf,int count)1728  static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
1729  			     const unsigned char *buf, int count)
1730  {
1731  	int i_msg, i;
1732  
1733  	spin_lock_irq(&tp->view.lock);
1734  	for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
1735  		if (tp->esc_state != 0) {
1736  			/* Continue escape sequence. */
1737  			tty3270_escape_sequence(tp, buf[i_msg]);
1738  			continue;
1739  		}
1740  
1741  		switch (buf[i_msg]) {
1742  		case 0x00:
1743  			break;
1744  		case 0x07:		/* '\a' -- Alarm */
1745  			tp->wcc |= TW_PLUSALARM;
1746  			break;
1747  		case 0x08:		/* Backspace. */
1748  			if (tp->cx > 0) {
1749  				tp->cx--;
1750  				tty3270_put_character(tp, ' ');
1751  			}
1752  			break;
1753  		case 0x09:		/* '\t' -- Tabulate */
1754  			for (i = tp->cx % 8; i < 8; i++) {
1755  				if (tp->cx >= tp->view.cols) {
1756  					tty3270_cr(tp);
1757  					tty3270_lf(tp);
1758  					break;
1759  				}
1760  				tty3270_put_character(tp, ' ');
1761  				tp->cx++;
1762  			}
1763  			break;
1764  		case 0x0a:		/* '\n' -- New Line */
1765  			tty3270_cr(tp);
1766  			tty3270_lf(tp);
1767  			break;
1768  		case 0x0c:		/* '\f' -- Form Feed */
1769  			tty3270_erase_display(tp, 2);
1770  			tp->cx = 0;
1771  			tp->cy = 0;
1772  			break;
1773  		case 0x0d:		/* '\r' -- Carriage Return */
1774  			tp->cx = 0;
1775  			break;
1776  		case 0x0e:
1777  			tp->attributes.alternate_charset = 1;
1778  			break;
1779  		case 0x0f:		/* SuSE "exit alternate mode" */
1780  			tp->attributes.alternate_charset = 0;
1781  			break;
1782  		case 0x1b:		/* Start escape sequence. */
1783  			tty3270_escape_sequence(tp, buf[i_msg]);
1784  			break;
1785  		default:		/* Insert normal character. */
1786  			if (tp->cx >= tp->view.cols) {
1787  				tty3270_cr(tp);
1788  				tty3270_lf(tp);
1789  			}
1790  			tty3270_put_character(tp, buf[i_msg]);
1791  			tp->cx++;
1792  			break;
1793  		}
1794  	}
1795  	/* Setup timer to update display after 1/10 second */
1796  	tp->update_flags |= TTY_UPDATE_LINES;
1797  	if (!timer_pending(&tp->timer))
1798  		tty3270_set_timer(tp, msecs_to_jiffies(100));
1799  
1800  	spin_unlock_irq(&tp->view.lock);
1801  }
1802  
1803  /*
1804   * String write routine for 3270 ttys
1805   */
tty3270_write(struct tty_struct * tty,const u8 * buf,size_t count)1806  static ssize_t tty3270_write(struct tty_struct *tty, const u8 *buf,
1807  			     size_t count)
1808  {
1809  	struct tty3270 *tp;
1810  
1811  	tp = tty->driver_data;
1812  	if (!tp)
1813  		return 0;
1814  	if (tp->char_count > 0) {
1815  		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
1816  		tp->char_count = 0;
1817  	}
1818  	tty3270_do_write(tp, tty, buf, count);
1819  	return count;
1820  }
1821  
1822  /*
1823   * Put single characters to the ttys character buffer
1824   */
tty3270_put_char(struct tty_struct * tty,u8 ch)1825  static int tty3270_put_char(struct tty_struct *tty, u8 ch)
1826  {
1827  	struct tty3270 *tp;
1828  
1829  	tp = tty->driver_data;
1830  	if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
1831  		return 0;
1832  	tp->char_buf[tp->char_count++] = ch;
1833  	return 1;
1834  }
1835  
1836  /*
1837   * Flush all characters from the ttys characeter buffer put there
1838   * by tty3270_put_char.
1839   */
tty3270_flush_chars(struct tty_struct * tty)1840  static void tty3270_flush_chars(struct tty_struct *tty)
1841  {
1842  	struct tty3270 *tp;
1843  
1844  	tp = tty->driver_data;
1845  	if (!tp)
1846  		return;
1847  	if (tp->char_count > 0) {
1848  		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
1849  		tp->char_count = 0;
1850  	}
1851  }
1852  
1853  /*
1854   * Check for visible/invisible input switches
1855   */
tty3270_set_termios(struct tty_struct * tty,const struct ktermios * old)1856  static void tty3270_set_termios(struct tty_struct *tty, const struct ktermios *old)
1857  {
1858  	struct tty3270 *tp;
1859  	int new;
1860  
1861  	tp = tty->driver_data;
1862  	if (!tp)
1863  		return;
1864  	spin_lock_irq(&tp->view.lock);
1865  	if (L_ICANON(tty)) {
1866  		new = L_ECHO(tty) ? TF_INPUT : TF_INPUTN;
1867  		if (new != tp->inattr) {
1868  			tp->inattr = new;
1869  			tty3270_update_prompt(tp, "");
1870  			tty3270_set_timer(tp, 1);
1871  		}
1872  	}
1873  	spin_unlock_irq(&tp->view.lock);
1874  }
1875  
1876  /*
1877   * Disable reading from a 3270 tty
1878   */
tty3270_throttle(struct tty_struct * tty)1879  static void tty3270_throttle(struct tty_struct *tty)
1880  {
1881  	struct tty3270 *tp;
1882  
1883  	tp = tty->driver_data;
1884  	if (!tp)
1885  		return;
1886  	tp->throttle = 1;
1887  }
1888  
1889  /*
1890   * Enable reading from a 3270 tty
1891   */
tty3270_unthrottle(struct tty_struct * tty)1892  static void tty3270_unthrottle(struct tty_struct *tty)
1893  {
1894  	struct tty3270 *tp;
1895  
1896  	tp = tty->driver_data;
1897  	if (!tp)
1898  		return;
1899  	tp->throttle = 0;
1900  	if (tp->attn)
1901  		tty3270_issue_read(tp, 1);
1902  }
1903  
1904  /*
1905   * Hang up the tty device.
1906   */
tty3270_hangup(struct tty_struct * tty)1907  static void tty3270_hangup(struct tty_struct *tty)
1908  {
1909  	struct tty3270 *tp;
1910  
1911  	tp = tty->driver_data;
1912  	if (!tp)
1913  		return;
1914  	spin_lock_irq(&tp->view.lock);
1915  	tp->cx = 0;
1916  	tp->cy = 0;
1917  	tp->saved_cx = 0;
1918  	tp->saved_cy = 0;
1919  	tty3270_reset_attributes(&tp->attributes);
1920  	tty3270_reset_attributes(&tp->saved_attributes);
1921  	tty3270_blank_screen(tp);
1922  	tp->update_flags = TTY_UPDATE_ALL;
1923  	spin_unlock_irq(&tp->view.lock);
1924  	tty3270_set_timer(tp, 1);
1925  }
1926  
tty3270_wait_until_sent(struct tty_struct * tty,int timeout)1927  static void tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
1928  {
1929  }
1930  
tty3270_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)1931  static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
1932  			 unsigned long arg)
1933  {
1934  	struct tty3270 *tp;
1935  
1936  	tp = tty->driver_data;
1937  	if (!tp)
1938  		return -ENODEV;
1939  	if (tty_io_error(tty))
1940  		return -EIO;
1941  	return kbd_ioctl(tp->kbd, cmd, arg);
1942  }
1943  
1944  #ifdef CONFIG_COMPAT
tty3270_compat_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)1945  static long tty3270_compat_ioctl(struct tty_struct *tty,
1946  				 unsigned int cmd, unsigned long arg)
1947  {
1948  	struct tty3270 *tp;
1949  
1950  	tp = tty->driver_data;
1951  	if (!tp)
1952  		return -ENODEV;
1953  	if (tty_io_error(tty))
1954  		return -EIO;
1955  	return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
1956  }
1957  #endif
1958  
1959  static const struct tty_operations tty3270_ops = {
1960  	.install = tty3270_install,
1961  	.cleanup = tty3270_cleanup,
1962  	.open = tty3270_open,
1963  	.close = tty3270_close,
1964  	.write = tty3270_write,
1965  	.put_char = tty3270_put_char,
1966  	.flush_chars = tty3270_flush_chars,
1967  	.write_room = tty3270_write_room,
1968  	.throttle = tty3270_throttle,
1969  	.unthrottle = tty3270_unthrottle,
1970  	.hangup = tty3270_hangup,
1971  	.wait_until_sent = tty3270_wait_until_sent,
1972  	.ioctl = tty3270_ioctl,
1973  #ifdef CONFIG_COMPAT
1974  	.compat_ioctl = tty3270_compat_ioctl,
1975  #endif
1976  	.set_termios = tty3270_set_termios
1977  };
1978  
tty3270_create_cb(int minor)1979  static void tty3270_create_cb(int minor)
1980  {
1981  	tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
1982  }
1983  
tty3270_destroy_cb(int minor)1984  static void tty3270_destroy_cb(int minor)
1985  {
1986  	tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
1987  }
1988  
1989  static struct raw3270_notifier tty3270_notifier = {
1990  	.create = tty3270_create_cb,
1991  	.destroy = tty3270_destroy_cb,
1992  };
1993  
1994  /*
1995   * 3270 tty registration code called from tty_init().
1996   * Most kernel services (incl. kmalloc) are available at this poimt.
1997   */
tty3270_init(void)1998  static int __init tty3270_init(void)
1999  {
2000  	struct tty_driver *driver;
2001  	int ret;
2002  
2003  	driver = tty_alloc_driver(RAW3270_MAXDEVS,
2004  				  TTY_DRIVER_REAL_RAW |
2005  				  TTY_DRIVER_DYNAMIC_DEV |
2006  				  TTY_DRIVER_RESET_TERMIOS);
2007  	if (IS_ERR(driver))
2008  		return PTR_ERR(driver);
2009  
2010  	/*
2011  	 * Initialize the tty_driver structure
2012  	 * Entries in tty3270_driver that are NOT initialized:
2013  	 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
2014  	 */
2015  	driver->driver_name = "tty3270";
2016  	driver->name = "3270/tty";
2017  	driver->major = IBM_TTY3270_MAJOR;
2018  	driver->minor_start = RAW3270_FIRSTMINOR;
2019  	driver->name_base = RAW3270_FIRSTMINOR;
2020  	driver->type = TTY_DRIVER_TYPE_SYSTEM;
2021  	driver->subtype = SYSTEM_TYPE_TTY;
2022  	driver->init_termios = tty_std_termios;
2023  	tty_set_operations(driver, &tty3270_ops);
2024  	ret = tty_register_driver(driver);
2025  	if (ret) {
2026  		tty_driver_kref_put(driver);
2027  		return ret;
2028  	}
2029  	tty3270_driver = driver;
2030  	raw3270_register_notifier(&tty3270_notifier);
2031  	return 0;
2032  }
2033  
tty3270_exit(void)2034  static void __exit tty3270_exit(void)
2035  {
2036  	struct tty_driver *driver;
2037  
2038  	raw3270_unregister_notifier(&tty3270_notifier);
2039  	driver = tty3270_driver;
2040  	tty3270_driver = NULL;
2041  	tty_unregister_driver(driver);
2042  	tty_driver_kref_put(driver);
2043  	tty3270_del_views();
2044  }
2045  
2046  #if IS_ENABLED(CONFIG_TN3270_CONSOLE)
2047  
2048  static struct tty3270 *condev;
2049  
2050  static void
con3270_write(struct console * co,const char * str,unsigned int count)2051  con3270_write(struct console *co, const char *str, unsigned int count)
2052  {
2053  	struct tty3270 *tp = co->data;
2054  	unsigned long flags;
2055  	char c;
2056  
2057  	spin_lock_irqsave(&tp->view.lock, flags);
2058  	while (count--) {
2059  		c = *str++;
2060  		if (c == 0x0a) {
2061  			tty3270_cr(tp);
2062  			tty3270_lf(tp);
2063  		} else {
2064  			if (tp->cx >= tp->view.cols) {
2065  				tty3270_cr(tp);
2066  				tty3270_lf(tp);
2067  			}
2068  			tty3270_put_character(tp, c);
2069  			tp->cx++;
2070  		}
2071  	}
2072  	spin_unlock_irqrestore(&tp->view.lock, flags);
2073  }
2074  
2075  static struct tty_driver *
con3270_device(struct console * c,int * index)2076  con3270_device(struct console *c, int *index)
2077  {
2078  	*index = c->index;
2079  	return tty3270_driver;
2080  }
2081  
2082  static void
con3270_wait_write(struct tty3270 * tp)2083  con3270_wait_write(struct tty3270 *tp)
2084  {
2085  	while (!tp->write) {
2086  		raw3270_wait_cons_dev(tp->view.dev);
2087  		barrier();
2088  	}
2089  }
2090  
2091  /*
2092   * The below function is called as a panic/reboot notifier before the
2093   * system enters a disabled, endless loop.
2094   *
2095   * Notice we must use the spin_trylock() alternative, to prevent lockups
2096   * in atomic context (panic routine runs with secondary CPUs, local IRQs
2097   * and preemption disabled).
2098   */
con3270_notify(struct notifier_block * self,unsigned long event,void * data)2099  static int con3270_notify(struct notifier_block *self,
2100  			  unsigned long event, void *data)
2101  {
2102  	struct tty3270 *tp;
2103  	unsigned long flags;
2104  	int rc;
2105  
2106  	tp = condev;
2107  	if (!tp->view.dev)
2108  		return NOTIFY_DONE;
2109  	if (!raw3270_view_lock_unavailable(&tp->view)) {
2110  		rc = raw3270_activate_view(&tp->view);
2111  		if (rc)
2112  			return NOTIFY_DONE;
2113  	}
2114  	if (!spin_trylock_irqsave(&tp->view.lock, flags))
2115  		return NOTIFY_DONE;
2116  	con3270_wait_write(tp);
2117  	tp->nr_up = 0;
2118  	tp->update_flags = TTY_UPDATE_ALL;
2119  	while (tp->update_flags != 0) {
2120  		spin_unlock_irqrestore(&tp->view.lock, flags);
2121  		tty3270_update(&tp->timer);
2122  		spin_lock_irqsave(&tp->view.lock, flags);
2123  		con3270_wait_write(tp);
2124  	}
2125  	spin_unlock_irqrestore(&tp->view.lock, flags);
2126  	return NOTIFY_DONE;
2127  }
2128  
2129  static struct notifier_block on_panic_nb = {
2130  	.notifier_call = con3270_notify,
2131  	.priority = INT_MIN + 1, /* run the callback late */
2132  };
2133  
2134  static struct notifier_block on_reboot_nb = {
2135  	.notifier_call = con3270_notify,
2136  	.priority = INT_MIN + 1, /* run the callback late */
2137  };
2138  
2139  static struct console con3270 = {
2140  	.name	 = "tty3270",
2141  	.write	 = con3270_write,
2142  	.device	 = con3270_device,
2143  	.flags	 = CON_PRINTBUFFER,
2144  };
2145  
2146  static int __init
con3270_init(void)2147  con3270_init(void)
2148  {
2149  	struct raw3270_view *view;
2150  	struct raw3270 *rp;
2151  	struct tty3270 *tp;
2152  	int rc;
2153  
2154  	/* Check if 3270 is to be the console */
2155  	if (!CONSOLE_IS_3270)
2156  		return -ENODEV;
2157  
2158  	/* Set the console mode for VM */
2159  	if (MACHINE_IS_VM) {
2160  		cpcmd("TERM CONMODE 3270", NULL, 0, NULL);
2161  		cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
2162  	}
2163  
2164  	rp = raw3270_setup_console();
2165  	if (IS_ERR(rp))
2166  		return PTR_ERR(rp);
2167  
2168  	/* Check if the tty3270 is already there. */
2169  	view = raw3270_find_view(&tty3270_fn, RAW3270_FIRSTMINOR);
2170  	if (IS_ERR(view)) {
2171  		rc = tty3270_create_view(0, &tp);
2172  		if (rc)
2173  			return rc;
2174  	} else {
2175  		tp = container_of(view, struct tty3270, view);
2176  		tp->inattr = TF_INPUT;
2177  	}
2178  	con3270.data = tp;
2179  	condev = tp;
2180  	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
2181  	register_reboot_notifier(&on_reboot_nb);
2182  	register_console(&con3270);
2183  	return 0;
2184  }
2185  console_initcall(con3270_init);
2186  #endif
2187  
2188  MODULE_LICENSE("GPL");
2189  MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
2190  
2191  module_init(tty3270_init);
2192  module_exit(tty3270_exit);
2193