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