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
41static struct tty_driver *tty3270_driver;
42static int tty3270_max_index;
43static 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
49struct 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
56struct tty3270_cell {
57	unsigned char character;
58	struct tty3270_attribute attributes;
59};
60
61struct tty3270_line {
62	struct tty3270_cell *cells;
63	int len;
64	int dirty;
65};
66
67static 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 */
80struct 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 */
140static void tty3270_set_timer(struct tty3270 *tp, int expires)
141{
142	mod_timer(&tp->timer, jiffies + expires);
143}
144
145static int tty3270_tty_rows(struct tty3270 *tp)
146{
147	return tp->view.rows - TTY3270_INPUT_AREA_ROWS;
148}
149
150static 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
157static 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
164static 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
172static char *tty3270_add_ge(struct tty3270 *tp, char *cp, char c)
173{
174	*cp++ = TO_GE;
175	*cp++ = c;
176	return cp;
177}
178
179static char *tty3270_add_sf(struct tty3270 *tp, char *cp, char type)
180{
181	*cp++ = TO_SF;
182	*cp++ = type;
183	return cp;
184}
185
186static int tty3270_line_increment(struct tty3270 *tp, unsigned int line, unsigned int incr)
187{
188	return (line + incr) & (tp->allocated_lines - 1);
189}
190
191static 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
196static 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
201static int tty3270_input_size(int cols)
202{
203	return cols * 2 - 11;
204}
205
206static 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 */
216static 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
241static 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 */
252static 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
285static 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 */
301static 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
314static 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
353static 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
367static 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
397static 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
445static 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 */
455static 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
472static 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
493static 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 */
524static 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 */
585static 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
598static 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 */
618static 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
625static 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 */
638static 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 */
655static 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 */
670static 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 */
732static 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 */
744static 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 */
771static 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 */
782static 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
791static 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
798static 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 */
827static 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
859out_readpartreq:
860	raw3270_request_free(tp->readpartreq);
861out_reset:
862	raw3270_request_free(tp->kreset);
863out_read:
864	raw3270_request_free(tp->read);
865out_write:
866	raw3270_request_free(tp->write);
867out_tp:
868	kfree(tp);
869out_err:
870	return ERR_PTR(-ENOMEM);
871}
872
873/*
874 * Free tty3270 structure.
875 */
876static 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 */
890static 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;
907out_screen:
908	while (lines--)
909		kfree(screen[lines].cells);
910	kfree(screen);
911out_err:
912	return ERR_PTR(-ENOMEM);
913}
914
915static 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
938static 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 */
950static 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 */
962static 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;
1030out_screen:
1031	tty3270_free_screen(screen, new_rows);
1032out_prompt:
1033	kfree(new_prompt);
1034out_input:
1035	kfree(new_input);
1036}
1037
1038/*
1039 * Unlink tty3270 data structure from tty.
1040 */
1041static 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 */
1058static 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 */
1073static 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
1085static 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
1094static int
1095tty3270_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
1160out_free_prompt:
1161	kfree(tp->prompt);
1162out_free_input:
1163	kfree(tp->input);
1164out_free_converted_line:
1165	free_page((unsigned long)tp->converted_line);
1166out_free_screen:
1167	tty3270_free_screen(tp->screen, tp->view.rows);
1168out_put_view:
1169	raw3270_put_view(&tp->view);
1170	raw3270_del_view(&tp->view);
1171out_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 */
1179static int
1180tty3270_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 */
1212static 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 */
1226static 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
1236static 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 */
1249static 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 */
1258static 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 */
1282static void tty3270_cr(struct tty3270 *tp)
1283{
1284	tp->cx = 0;
1285}
1286
1287/*
1288 * Do line feed.
1289 */
1290static 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
1309static void tty3270_ri(struct tty3270 *tp)
1310{
1311	if (tp->cy > 0)
1312		tp->cy--;
1313}
1314
1315static 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 */
1324static 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 */
1349static 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 */
1369static 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 */
1389static 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 */
1430static 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 */
1464static 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
1521static inline int tty3270_getpar(struct tty3270 *tp, int ix)
1522{
1523	return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
1524}
1525
1526static 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 */
1564static 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 */
1728static 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 */
1806static 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 */
1825static 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 */
1840static 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 */
1856static 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 */
1879static 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 */
1892static 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 */
1907static 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
1927static void tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
1928{
1929}
1930
1931static 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
1945static 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
1959static 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
1979static void tty3270_create_cb(int minor)
1980{
1981	tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
1982}
1983
1984static void tty3270_destroy_cb(int minor)
1985{
1986	tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
1987}
1988
1989static 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 */
1998static 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
2034static 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
2048static struct tty3270 *condev;
2049
2050static void
2051con3270_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
2075static struct tty_driver *
2076con3270_device(struct console *c, int *index)
2077{
2078	*index = c->index;
2079	return tty3270_driver;
2080}
2081
2082static void
2083con3270_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 */
2099static 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
2129static struct notifier_block on_panic_nb = {
2130	.notifier_call = con3270_notify,
2131	.priority = INT_MIN + 1, /* run the callback late */
2132};
2133
2134static struct notifier_block on_reboot_nb = {
2135	.notifier_call = con3270_notify,
2136	.priority = INT_MIN + 1, /* run the callback late */
2137};
2138
2139static struct console con3270 = {
2140	.name	 = "tty3270",
2141	.write	 = con3270_write,
2142	.device	 = con3270_device,
2143	.flags	 = CON_PRINTBUFFER,
2144};
2145
2146static int __init
2147con3270_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}
2185console_initcall(con3270_init);
2186#endif
2187
2188MODULE_LICENSE("GPL");
2189MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
2190
2191module_init(tty3270_init);
2192module_exit(tty3270_exit);
2193