Merge tag 'drm-intel-next-fixes-2024-01-19' of git://anongit.freedesktop.org/drm...
[linux-block.git] / drivers / s390 / char / con3270.c
CommitLineData
6f05e69e 1// SPDX-License-Identifier: GPL-2.0
1da177e4 2/*
1da177e4
LT
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>
a53c8fab 8 * -- Copyright IBM Corp. 2003
1da177e4
LT
9 */
10
1da177e4
LT
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>
4d334fd1 19#include <linux/workqueue.h>
c17fe081
SS
20#include <linux/panic_notifier.h>
21#include <linux/reboot.h>
1da177e4 22#include <linux/slab.h>
57c8a661 23#include <linux/memblock.h>
9d4bfd41 24#include <linux/compat.h>
1da177e4
LT
25
26#include <asm/ccwdev.h>
27#include <asm/cio.h>
28#include <asm/ebcdic.h>
c17fe081 29#include <asm/cpcmd.h>
7c0f6ba6 30#include <linux/uaccess.h>
1da177e4 31
1da177e4
LT
32#include "raw3270.h"
33#include "keyboard.h"
34
35#define TTY3270_CHAR_BUF_SIZE 256
9c138af9 36#define TTY3270_OUTPUT_BUFFER_SIZE 4096
b2057c87 37#define TTY3270_SCREEN_PAGES 8 /* has to be power-of-two */
76485078 38#define TTY3270_RECALL_SIZE 16 /* has to be power-of-two */
525c919d 39#define TTY3270_STATUS_AREA_SIZE 40
b2057c87 40
c17fe081 41static struct tty_driver *tty3270_driver;
1da177e4 42static int tty3270_max_index;
2b67fc46 43static struct raw3270_fn tty3270_fn;
1da177e4 44
0573fff2
SS
45#define TTY3270_HIGHLIGHT_BLINK 1
46#define TTY3270_HIGHLIGHT_REVERSE 2
47#define TTY3270_HIGHLIGHT_UNDERSCORE 4
48
c2e9375e 49struct tty3270_attribute {
94dbb0a7 50 unsigned char alternate_charset:1; /* Graphics charset */
0573fff2 51 unsigned char highlight:3; /* Blink/reverse/underscore */
18fc2e93
SS
52 unsigned char f_color:4; /* Foreground color */
53 unsigned char b_color:4; /* Background color */
c2e9375e
SS
54};
55
1da177e4 56struct tty3270_cell {
e17934c1 57 u8 character;
c2e9375e 58 struct tty3270_attribute attributes;
1da177e4
LT
59};
60
61struct tty3270_line {
62 struct tty3270_cell *cells;
63 int len;
b2057c87 64 int dirty;
1da177e4
LT
65};
66
cbb36313
SS
67static const unsigned char sfq_read_partition[] = {
68 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81
69};
70
1da177e4
LT
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;
ba186e7d 82 struct tty_port port;
1da177e4
LT
83
84 /* Output stuff. */
1da177e4 85 unsigned char wcc; /* Write control character. */
1da177e4
LT
86 int nr_up; /* # lines up in history. */
87 unsigned long update_flags; /* Update indication bits. */
1da177e4
LT
88 struct raw3270_request *write; /* Single write request. */
89 struct timer_list timer; /* Output delay timer. */
ec1b0a33 90 char *converted_line; /* RAW 3270 data stream */
9c138af9
SS
91 unsigned int line_view_start; /* Start of visible area */
92 unsigned int line_write_start; /* current write position */
ba5c2e2a 93 unsigned int oops_line; /* line counter used when print oops */
1da177e4
LT
94
95 /* Current tty screen. */
96 unsigned int cx, cy; /* Current output position. */
c2e9375e
SS
97 struct tty3270_attribute attributes;
98 struct tty3270_attribute saved_attributes;
b2057c87 99 int allocated_lines;
1da177e4
LT
100 struct tty3270_line *screen;
101
102 /* Input stuff. */
164eb669
SS
103 char *prompt; /* Output string for input area. */
104 char *input; /* Input string for read request. */
1da177e4
LT
105 struct raw3270_request *read; /* Single read request. */
106 struct raw3270_request *kreset; /* Single keyboard reset request. */
cbb36313 107 struct raw3270_request *readpartreq;
1da177e4
LT
108 unsigned char inattr; /* Visible/invisible input. */
109 int throttle, attn; /* tty throttle/unthrottle. */
110 struct tasklet_struct readlet; /* Tasklet to issue read request. */
0c756914 111 struct tasklet_struct hanglet; /* Tasklet to hang up the tty. */
1da177e4
LT
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;
1da177e4
LT
118
119 /* Command recalling. */
76485078
SS
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 */
1da177e4
LT
123
124 /* Character array for put_char/flush_chars. */
125 unsigned int char_count;
e17934c1 126 u8 char_buf[TTY3270_CHAR_BUF_SIZE];
1da177e4
LT
127};
128
129/* tty3270->update_flags. See tty3270_update for details. */
da4e272e
SS
130#define TTY_UPDATE_INPUT 0x1 /* Update input line. */
131#define TTY_UPDATE_STATUS 0x2 /* Update status line. */
ba5c2e2a
SS
132#define TTY_UPDATE_LINES 0x4 /* Update visible screen lines */
133#define TTY_UPDATE_ALL 0x7 /* Recreate screen. */
1da177e4 134
9eb99b94 135#define TTY3270_INPUT_AREA_ROWS 2
f77f936a 136
1da177e4
LT
137/*
138 * Setup timeout for a device. On timeout trigger an update.
139 */
2b67fc46 140static void tty3270_set_timer(struct tty3270 *tp, int expires)
1da177e4 141{
03439e7d 142 mod_timer(&tp->timer, jiffies + expires);
1da177e4
LT
143}
144
9eb99b94
SS
145static int tty3270_tty_rows(struct tty3270 *tp)
146{
147 return tp->view.rows - TTY3270_INPUT_AREA_ROWS;
148}
149
ae657244
SS
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
ec1b0a33
SS
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
9c138af9
SS
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
164eb669 201static int tty3270_input_size(int cols)
1da177e4 202{
164eb669
SS
203 return cols * 2 - 11;
204}
1da177e4 205
76485078 206static void tty3270_update_prompt(struct tty3270 *tp, char *input)
164eb669 207{
76485078 208 strcpy(tp->prompt, input);
1da177e4 209 tp->update_flags |= TTY_UPDATE_INPUT;
164eb669 210 tty3270_set_timer(tp, 1);
1da177e4
LT
211}
212
164eb669
SS
213/*
214 * The input line are the two last lines of the screen.
215 */
216static int tty3270_add_prompt(struct tty3270 *tp)
1da177e4 217{
164eb669
SS
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);
525c919d
SS
227 count = min_t(int, strlen(tp->prompt),
228 tp->view.cols * 2 - TTY3270_STATUS_AREA_SIZE - 2);
164eb669
SS
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)
525c919d 237 cp = tty3270_add_ra(tp, cp, -TTY3270_STATUS_AREA_SIZE, -1, 0);
164eb669 238 return cp - tp->converted_line;
1da177e4
LT
239}
240
525c919d
SS
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
ae657244
SS
248/*
249 * The status line is the last line of the screen. It shows the string
525c919d 250 * "Running"/"History X" in the lower right corner of the screen.
ae657244 251 */
ec1b0a33 252static int tty3270_add_status(struct tty3270 *tp)
1da177e4 253{
ec1b0a33
SS
254 char *cp = tp->converted_line;
255 int len;
1da177e4 256
525c919d 257 cp = tty3270_add_ba(tp, cp, TO_SBA, -TTY3270_STATUS_AREA_SIZE, -1);
ec1b0a33
SS
258 cp = tty3270_add_sf(tp, cp, TF_LOG);
259 cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAC_GREEN);
525c919d
SS
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 {
ba5c2e2a 278 cp = tty3270_ebcdic_convert(tp, cp, oops_in_progress ? "Crashed" : "Running");
525c919d 279 }
ec1b0a33
SS
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;
1da177e4
LT
283}
284
e6d98bb8 285static void tty3270_blank_screen(struct tty3270 *tp)
7e36eff1 286{
9c138af9 287 struct tty3270_line *line;
7e36eff1
MS
288 int i;
289
9c138af9
SS
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;
7e36eff1 294 }
9c138af9 295 tp->nr_up = 0;
7e36eff1
MS
296}
297
1da177e4
LT
298/*
299 * Write request completion callback.
300 */
e6d98bb8 301static void tty3270_write_callback(struct raw3270_request *rq, void *data)
1da177e4 302{
881e18f9 303 struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
1da177e4 304
1da177e4 305 if (rq->rc != 0) {
25985edc 306 /* Write wasn't successful. Refresh all. */
1da177e4
LT
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
9c138af9 314static int tty3270_required_length(struct tty3270 *tp, struct tty3270_line *line)
2b62ba58
SS
315{
316 unsigned char f_color, b_color, highlight;
2b62ba58
SS
317 struct tty3270_cell *cell;
318 int i, flen = 3; /* Prefix (TO_SBA). */
319
2b62ba58 320 flen += line->len;
0573fff2 321 highlight = 0;
2b62ba58
SS
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 }
0573fff2 341 if (highlight)
2b62ba58
SS
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,
422a78ea 354 char *cp, struct tty3270_attribute *attr, int lineno)
2b62ba58 355{
0573fff2 356 if (attr->highlight)
ae657244
SS
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)
422a78ea 363 cp = tty3270_add_ra(tp, cp, 0, lineno + 1, 0);
2b62ba58
SS
364 return cp;
365}
366
6e49017c
SS
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,
422a78ea 398 struct tty3270_attribute *attr, char *cp, int lineno)
2b62ba58 399{
18fc2e93
SS
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
0573fff2
SS
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
2b62ba58 418 struct tty3270_cell *cell;
ae657244 419 int c, i;
2b62ba58 420
422a78ea 421 cp = tty3270_add_ba(tp, cp, TO_SBA, 0, lineno);
2b62ba58
SS
422
423 for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
424 if (cell->attributes.highlight != attr->highlight) {
2b62ba58 425 attr->highlight = cell->attributes.highlight;
0573fff2 426 cp = tty3270_add_sa(tp, cp, TAT_EXTHI, highlights[attr->highlight]);
2b62ba58
SS
427 }
428 if (cell->attributes.f_color != attr->f_color) {
2b62ba58 429 attr->f_color = cell->attributes.f_color;
18fc2e93 430 cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, colors[attr->f_color]);
2b62ba58
SS
431 }
432 if (cell->attributes.b_color != attr->b_color) {
2b62ba58 433 attr->b_color = cell->attributes.b_color;
18fc2e93 434 cp = tty3270_add_sa(tp, cp, TAT_BGCOLOR, colors[attr->b_color]);
2b62ba58 435 }
ae657244
SS
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];
2b62ba58
SS
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
2b62ba58
SS
452/*
453 * Convert a tty3270_line to a 3270 data fragment usable for output.
454 */
422a78ea 455static unsigned int tty3270_convert_line(struct tty3270 *tp, struct tty3270_line *line, int lineno)
2b62ba58 456{
2b62ba58 457 struct tty3270_attribute attr;
9c138af9 458 int flen;
2b62ba58
SS
459 char *cp;
460
461 /* Determine how long the fragment will be. */
9c138af9
SS
462 flen = tty3270_required_length(tp, line);
463 if (flen > PAGE_SIZE)
464 return 0;
2b62ba58
SS
465 /* Write 3270 data fragment. */
466 tty3270_reset_attributes(&attr);
422a78ea
SS
467 cp = tty3270_add_attributes(tp, line, &attr, tp->converted_line, lineno);
468 cp = tty3270_add_reset_attributes(tp, line, cp, &attr, lineno);
9c138af9 469 return cp - (char *)tp->converted_line;
2b62ba58
SS
470}
471
ba5c2e2a
SS
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
1da177e4
LT
521/*
522 * Update 3270 display.
523 */
e6d98bb8 524static void tty3270_update(struct timer_list *t)
1da177e4 525{
c9602ee7 526 struct tty3270 *tp = from_timer(tp, t, timer);
1da177e4 527 struct raw3270_request *wrq;
da4e272e 528 u8 cmd = TC_WRITE;
ba5c2e2a 529 int rc, len;
1da177e4
LT
530
531 wrq = xchg(&tp->write, 0);
532 if (!wrq) {
533 tty3270_set_timer(tp, 1);
534 return;
535 }
536
c17fe081 537 spin_lock_irq(&tp->view.lock);
da4e272e
SS
538 if (tp->update_flags == TTY_UPDATE_ALL)
539 cmd = TC_EWRITEA;
540
541 raw3270_request_set_cmd(wrq, cmd);
1da177e4
LT
542 raw3270_request_add_data(wrq, &tp->wcc, 1);
543 tp->wcc = TW_NONE;
544
545 /*
546 * Update status line.
547 */
ec1b0a33
SS
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)
da4e272e 551 tp->update_flags &= ~TTY_UPDATE_STATUS;
ec1b0a33 552 }
1da177e4
LT
553
554 /*
555 * Write input line.
556 */
164eb669
SS
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)
da4e272e 560 tp->update_flags &= ~TTY_UPDATE_INPUT;
164eb669 561 }
1da177e4 562
ba5c2e2a
SS
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);
1da177e4 568 }
9c138af9 569
1da177e4
LT
570 wrq->callback = tty3270_write_callback;
571 rc = raw3270_start(&tp->view, wrq);
572 if (rc == 0) {
1da177e4
LT
573 if (tp->update_flags)
574 tty3270_set_timer(tp, 1);
575 } else {
576 raw3270_request_reset(wrq);
577 xchg(&tp->write, wrq);
578 }
c17fe081 579 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
580}
581
582/*
583 * Command recalling.
584 */
e6d98bb8 585static void tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
1da177e4 586{
76485078 587 char *p;
7ef21387 588
1da177e4
LT
589 if (len <= 0)
590 return;
76485078
SS
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;
1da177e4
LT
596}
597
e6d98bb8 598static void tty3270_rcl_backward(struct kbd_data *kbd)
1da177e4 599{
ba186e7d 600 struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
76485078 601 int i = 0;
1da177e4 602
c17fe081 603 spin_lock_irq(&tp->view.lock);
1da177e4 604 if (tp->inattr == TF_INPUT) {
76485078
SS
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]);
1da177e4 611 }
c17fe081 612 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
613}
614
615/*
616 * Deactivate tty view.
617 */
e6d98bb8 618static void tty3270_exit_tty(struct kbd_data *kbd)
1da177e4 619{
ba186e7d 620 struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
1da177e4 621
1da177e4
LT
622 raw3270_deactivate_view(&tp->view);
623}
624
9c138af9
SS
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}
7ef21387 634
1da177e4
LT
635/*
636 * Scroll forward in history.
637 */
e6d98bb8 638static void tty3270_scroll_forward(struct kbd_data *kbd)
1da177e4 639{
ba186e7d 640 struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
1da177e4 641
c17fe081 642 spin_lock_irq(&tp->view.lock);
9c138af9
SS
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);
c17fe081 649 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
650}
651
652/*
653 * Scroll backward in history.
654 */
e6d98bb8 655static void tty3270_scroll_backward(struct kbd_data *kbd)
1da177e4 656{
ba186e7d 657 struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
1da177e4 658
c17fe081 659 spin_lock_irq(&tp->view.lock);
9c138af9
SS
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);
c17fe081 664 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
665}
666
667/*
668 * Pass input line to tty.
669 */
e6d98bb8 670static void tty3270_read_tasklet(unsigned long data)
1da177e4 671{
5cdfbdce 672 struct raw3270_request *rrq = (struct raw3270_request *)data;
1da177e4 673 static char kreset_data = TW_KR;
881e18f9 674 struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
1da177e4
LT
675 char *input;
676 int len;
677
c17fe081 678 spin_lock_irq(&tp->view.lock);
1da177e4
LT
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 */
d2c993d8 684 input = NULL;
1da177e4 685 len = 0;
164eb669 686 switch (tp->input[0]) {
e22de7d7 687 case AID_ENTER:
1da177e4 688 /* Enter: write input to tty. */
164eb669
SS
689 input = tp->input + 6;
690 len = tty3270_input_size(tp->view.cols) - 6 - rrq->rescnt;
1da177e4
LT
691 if (tp->inattr != TF_INPUTN)
692 tty3270_rcl_add(tp, input, len);
9c138af9 693 if (tp->nr_up > 0)
1da177e4 694 tp->nr_up = 0;
1da177e4 695 /* Clear input area. */
76485078 696 tty3270_update_prompt(tp, "");
1da177e4 697 tty3270_set_timer(tp, 1);
e22de7d7
SS
698 break;
699 case AID_CLEAR:
1da177e4 700 /* Display has been cleared. Redraw. */
1da177e4
LT
701 tp->update_flags = TTY_UPDATE_ALL;
702 tty3270_set_timer(tp, 1);
cbb36313
SS
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:
164eb669 709 raw3270_read_modified_cb(tp->readpartreq, tp->input);
cbb36313 710 break;
e22de7d7
SS
711 default:
712 break;
1da177e4 713 }
c17fe081 714 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
715
716 /* Start keyboard reset command. */
f08e3155 717 raw3270_start_request(&tp->view, tp->kreset, TC_WRITE, &kreset_data, 1);
1da177e4 718
ba186e7d
JS
719 while (len-- > 0)
720 kbd_keycode(tp->kbd, *input++);
721 /* Emit keycode for AID byte. */
164eb669 722 kbd_keycode(tp->kbd, 256 + tp->input[0]);
1da177e4
LT
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 */
e6d98bb8 732static void tty3270_read_callback(struct raw3270_request *rq, void *data)
1da177e4 733{
881e18f9 734 struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
7ef21387 735
1da177e4
LT
736 raw3270_get_view(rq->view);
737 /* Schedule tasklet to pass input to tty. */
881e18f9 738 tasklet_schedule(&tp->readlet);
1da177e4
LT
739}
740
741/*
742 * Issue a read request. Call with device lock.
743 */
e6d98bb8 744static void tty3270_issue_read(struct tty3270 *tp, int lock)
1da177e4
LT
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);
164eb669 756 raw3270_request_set_data(rrq, tp->input, tty3270_input_size(tp->view.cols));
1da177e4 757 /* Issue the read modified request. */
7ef21387 758 if (lock)
1da177e4 759 rc = raw3270_start(&tp->view, rrq);
7ef21387 760 else
1da177e4
LT
761 rc = raw3270_start_irq(&tp->view, rrq);
762 if (rc) {
763 raw3270_request_reset(rrq);
764 xchg(&tp->read, rrq);
765 }
766}
767
0c756914
MS
768/*
769 * Hang up the tty
770 */
e6d98bb8 771static void tty3270_hangup_tasklet(unsigned long data)
0c756914 772{
5cdfbdce 773 struct tty3270 *tp = (struct tty3270 *)data;
7ef21387 774
0c756914
MS
775 tty_port_tty_hangup(&tp->port, true);
776 raw3270_put_view(&tp->view);
777}
778
1da177e4
LT
779/*
780 * Switch to the tty view.
781 */
e6d98bb8 782static int tty3270_activate(struct raw3270_view *view)
1da177e4 783{
881e18f9 784 struct tty3270 *tp = container_of(view, struct tty3270, view);
1da177e4 785
1da177e4
LT
786 tp->update_flags = TTY_UPDATE_ALL;
787 tty3270_set_timer(tp, 1);
1da177e4
LT
788 return 0;
789}
790
e6d98bb8 791static void tty3270_deactivate(struct raw3270_view *view)
1da177e4 792{
881e18f9 793 struct tty3270 *tp = container_of(view, struct tty3270, view);
205d7ab9 794
205d7ab9 795 del_timer(&tp->timer);
1da177e4
LT
796}
797
e6d98bb8 798static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
1da177e4
LT
799{
800 /* Handle ATTN. Schedule tasklet to read aid. */
23d805b6 801 if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
1da177e4
LT
802 if (!tp->throttle)
803 tty3270_issue_read(tp, 0);
804 else
805 tp->attn = 1;
806 }
807
808 if (rq) {
0c756914 809 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
1da177e4 810 rq->rc = -EIO;
0c756914
MS
811 raw3270_get_view(&tp->view);
812 tasklet_schedule(&tp->hanglet);
813 } else {
1da177e4 814 /* Normal end. Copy residual count. */
23d805b6 815 rq->rescnt = irb->scsw.cmd.count;
0c756914 816 }
05bfd70b
MS
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);
1da177e4 821 }
1da177e4
LT
822}
823
824/*
825 * Allocate tty3270 structure.
826 */
e6d98bb8 827static struct tty3270 *tty3270_alloc_view(void)
1da177e4
LT
828{
829 struct tty3270 *tp;
1da177e4 830
7ef21387 831 tp = kzalloc(sizeof(*tp), GFP_KERNEL);
1da177e4
LT
832 if (!tp)
833 goto out_err;
76485078 834
1da177e4 835 tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
ed3cb6f0 836 if (IS_ERR(tp->write))
76485078 837 goto out_tp;
1da177e4 838 tp->read = raw3270_request_alloc(0);
ed3cb6f0 839 if (IS_ERR(tp->read))
1da177e4
LT
840 goto out_write;
841 tp->kreset = raw3270_request_alloc(1);
ed3cb6f0 842 if (IS_ERR(tp->kreset))
1da177e4 843 goto out_read;
cbb36313
SS
844 tp->readpartreq = raw3270_request_alloc(sizeof(sfq_read_partition));
845 if (IS_ERR(tp->readpartreq))
846 goto out_reset;
1da177e4
LT
847 tp->kbd = kbd_alloc();
848 if (!tp->kbd)
cbb36313 849 goto out_readpartreq;
57985d7e
MS
850
851 tty_port_init(&tp->port);
c9602ee7 852 timer_setup(&tp->timer, tty3270_update, 0);
5cdfbdce 853 tasklet_init(&tp->readlet, tty3270_read_tasklet,
7ef21387 854 (unsigned long)tp->read);
5cdfbdce 855 tasklet_init(&tp->hanglet, tty3270_hangup_tasklet,
7ef21387 856 (unsigned long)tp);
1da177e4
LT
857 return tp;
858
cbb36313
SS
859out_readpartreq:
860 raw3270_request_free(tp->readpartreq);
1da177e4
LT
861out_reset:
862 raw3270_request_free(tp->kreset);
863out_read:
864 raw3270_request_free(tp->read);
865out_write:
866 raw3270_request_free(tp->write);
1da177e4
LT
867out_tp:
868 kfree(tp);
869out_err:
870 return ERR_PTR(-ENOMEM);
871}
872
873/*
874 * Free tty3270 structure.
875 */
e6d98bb8 876static void tty3270_free_view(struct tty3270 *tp)
1da177e4 877{
1da177e4
LT
878 kbd_free(tp->kbd);
879 raw3270_request_free(tp->kreset);
880 raw3270_request_free(tp->read);
881 raw3270_request_free(tp->write);
9c138af9 882 free_page((unsigned long)tp->converted_line);
191c5f10 883 tty_port_destroy(&tp->port);
1da177e4
LT
884 kfree(tp);
885}
886
887/*
888 * Allocate tty3270 screen.
889 */
b2057c87
SS
890static struct tty3270_line *tty3270_alloc_screen(struct tty3270 *tp, unsigned int rows,
891 unsigned int cols, int *allocated_out)
1da177e4 892{
4d334fd1 893 struct tty3270_line *screen;
b2057c87 894 int allocated, lines;
1da177e4 895
b2057c87
SS
896 allocated = __roundup_pow_of_two(rows) * TTY3270_SCREEN_PAGES;
897 screen = kcalloc(allocated, sizeof(struct tty3270_line), GFP_KERNEL);
4d334fd1 898 if (!screen)
1da177e4 899 goto out_err;
b2057c87
SS
900 for (lines = 0; lines < allocated; lines++) {
901 screen[lines].cells = kcalloc(cols, sizeof(struct tty3270_cell), GFP_KERNEL);
4d334fd1 902 if (!screen[lines].cells)
1da177e4 903 goto out_screen;
1da177e4 904 }
b2057c87 905 *allocated_out = allocated;
4d334fd1 906 return screen;
1da177e4
LT
907out_screen:
908 while (lines--)
4d334fd1
MS
909 kfree(screen[lines].cells);
910 kfree(screen);
1da177e4 911out_err:
4d334fd1 912 return ERR_PTR(-ENOMEM);
1da177e4
LT
913}
914
76485078
SS
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
1da177e4
LT
947/*
948 * Free tty3270 screen.
949 */
b2057c87 950static void tty3270_free_screen(struct tty3270_line *screen, int old_lines)
1da177e4
LT
951{
952 int lines;
953
b2057c87 954 for (lines = 0; lines < old_lines; lines++)
4d334fd1
MS
955 kfree(screen[lines].cells);
956 kfree(screen);
957}
958
959/*
960 * Resize tty3270 screen
961 */
91621ba7
SS
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)
4d334fd1 965{
91621ba7 966 struct tty3270 *tp = container_of(view, struct tty3270, view);
4d334fd1 967 struct tty3270_line *screen, *oscreen;
76485078 968 char **old_rcl_lines, **new_rcl_lines;
164eb669
SS
969 char *old_prompt, *new_prompt;
970 char *old_input, *new_input;
4d334fd1 971 struct tty_struct *tty;
4d334fd1 972 struct winsize ws;
b2057c87 973 int new_allocated, old_allocated = tp->allocated_lines;
4d334fd1 974
91621ba7
SS
975 if (old_model == new_model &&
976 old_cols == new_cols &&
977 old_rows == new_rows) {
978 spin_lock_irq(&tp->view.lock);
9c138af9 979 tty3270_redraw(tp);
91621ba7
SS
980 spin_unlock_irq(&tp->view.lock);
981 return;
982 }
164eb669
SS
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;
b2057c87 990 screen = tty3270_alloc_screen(tp, new_rows, new_cols, &new_allocated);
8f0ba630 991 if (IS_ERR(screen))
164eb669 992 goto out_prompt;
76485078
SS
993 new_rcl_lines = tty3270_alloc_recall(new_cols);
994 if (!new_rcl_lines)
995 goto out_screen;
164eb669 996
4d334fd1 997 /* Switch to new output size */
c17fe081 998 spin_lock_irq(&tp->view.lock);
7e36eff1 999 tty3270_blank_screen(tp);
4d334fd1 1000 oscreen = tp->screen;
4d334fd1 1001 tp->screen = screen;
b2057c87 1002 tp->allocated_lines = new_allocated;
91621ba7
SS
1003 tp->view.rows = new_rows;
1004 tp->view.cols = new_cols;
1005 tp->view.model = new_model;
4d334fd1 1006 tp->update_flags = TTY_UPDATE_ALL;
164eb669
SS
1007 old_input = tp->input;
1008 old_prompt = tp->prompt;
76485078 1009 old_rcl_lines = tp->rcl_lines;
164eb669
SS
1010 tp->input = new_input;
1011 tp->prompt = new_prompt;
76485078
SS
1012 tp->rcl_lines = new_rcl_lines;
1013 tp->rcl_read_index = 0;
1014 tp->rcl_write_index = 0;
c17fe081 1015 spin_unlock_irq(&tp->view.lock);
b2057c87 1016 tty3270_free_screen(oscreen, old_allocated);
164eb669
SS
1017 kfree(old_input);
1018 kfree(old_prompt);
76485078 1019 tty3270_free_recall(old_rcl_lines);
4d334fd1
MS
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;
9eb99b94 1025 ws.ws_row = tty3270_tty_rows(tp);
4d334fd1
MS
1026 ws.ws_col = tp->view.cols;
1027 tty_do_resize(tty, &ws);
5ff04fe5 1028 tty_kref_put(tty);
164eb669 1029 return;
76485078
SS
1030out_screen:
1031 tty3270_free_screen(screen, new_rows);
164eb669
SS
1032out_prompt:
1033 kfree(new_prompt);
1034out_input:
1035 kfree(new_input);
4d334fd1
MS
1036}
1037
1da177e4
LT
1038/*
1039 * Unlink tty3270 data structure from tty.
1040 */
e6d98bb8 1041static void tty3270_release(struct raw3270_view *view)
1da177e4 1042{
881e18f9 1043 struct tty3270 *tp = container_of(view, struct tty3270, view);
ba186e7d 1044 struct tty_struct *tty = tty_port_tty_get(&tp->port);
1da177e4 1045
1da177e4 1046 if (tty) {
d2c993d8 1047 tty->driver_data = NULL;
ba186e7d 1048 tty_port_tty_set(&tp->port, NULL);
1da177e4
LT
1049 tty_hangup(tty);
1050 raw3270_put_view(&tp->view);
ba186e7d 1051 tty_kref_put(tty);
1da177e4
LT
1052 }
1053}
1054
1055/*
1056 * Free tty3270 data structure
1057 */
e6d98bb8 1058static void tty3270_free(struct raw3270_view *view)
1da177e4 1059{
881e18f9 1060 struct tty3270 *tp = container_of(view, struct tty3270, view);
4d334fd1 1061
03439e7d 1062 del_timer_sync(&tp->timer);
b2057c87 1063 tty3270_free_screen(tp->screen, tp->allocated_lines);
ec1b0a33 1064 free_page((unsigned long)tp->converted_line);
164eb669
SS
1065 kfree(tp->input);
1066 kfree(tp->prompt);
881e18f9 1067 tty3270_free_view(tp);
1da177e4
LT
1068}
1069
1070/*
1071 * Delayed freeing of tty3270 views.
1072 */
e6d98bb8 1073static void tty3270_del_views(void)
1da177e4 1074{
1da177e4
LT
1075 int i;
1076
c95571e6
MS
1077 for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) {
1078 struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i);
7ef21387 1079
881e18f9
JS
1080 if (!IS_ERR(view))
1081 raw3270_del_view(view);
1da177e4
LT
1082 }
1083}
1084
2b67fc46 1085static struct raw3270_fn tty3270_fn = {
1da177e4
LT
1086 .activate = tty3270_activate,
1087 .deactivate = tty3270_deactivate,
7ef21387 1088 .intv = (void *)tty3270_irq,
1da177e4 1089 .release = tty3270_release,
4d334fd1
MS
1090 .free = tty3270_free,
1091 .resize = tty3270_resize
1da177e4
LT
1092};
1093
a21e962e
SS
1094static int
1095tty3270_create_view(int index, struct tty3270 **newtp)
1da177e4
LT
1096{
1097 struct tty3270 *tp;
9c138af9 1098 int rc;
1da177e4 1099
a21e962e
SS
1100 if (tty3270_max_index < index + 1)
1101 tty3270_max_index = index + 1;
1da177e4
LT
1102
1103 /* Allocate tty3270 structure on first open. */
1104 tp = tty3270_alloc_view();
1105 if (IS_ERR(tp))
1106 return PTR_ERR(tp);
1107
1fcbba3d 1108 rc = raw3270_add_view(&tp->view, &tty3270_fn,
a21e962e 1109 index + RAW3270_FIRSTMINOR,
c17fe081 1110 RAW3270_VIEW_LOCK_IRQ);
ec1b0a33
SS
1111 if (rc)
1112 goto out_free_view;
1da177e4 1113
b2057c87
SS
1114 tp->screen = tty3270_alloc_screen(tp, tp->view.rows, tp->view.cols,
1115 &tp->allocated_lines);
4d334fd1
MS
1116 if (IS_ERR(tp->screen)) {
1117 rc = PTR_ERR(tp->screen);
ec1b0a33
SS
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;
1da177e4
LT
1125 }
1126
164eb669
SS
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 }
1da177e4 1138
76485078
SS
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
1da177e4 1145 /* Create blank line for every line in the tty output area. */
9c138af9 1146 tty3270_blank_screen(tp);
1da177e4 1147
ba186e7d 1148 tp->kbd->port = &tp->port;
1da177e4
LT
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);
a21e962e
SS
1156 raw3270_put_view(&tp->view);
1157 *newtp = tp;
1158 return 0;
ec1b0a33 1159
76485078
SS
1160out_free_prompt:
1161 kfree(tp->prompt);
164eb669
SS
1162out_free_input:
1163 kfree(tp->input);
1164out_free_converted_line:
1165 free_page((unsigned long)tp->converted_line);
ec1b0a33
SS
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;
a21e962e
SS
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;
20cda6f2 1185
a21e962e
SS
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
9eb99b94 1198 tty->winsize.ws_row = tty3270_tty_rows(tp);
a21e962e 1199 tty->winsize.ws_col = tp->view.cols;
20cda6f2
JS
1200 rc = tty_port_install(&tp->port, driver, tty);
1201 if (rc) {
1202 raw3270_put_view(&tp->view);
1203 return rc;
1204 }
20cda6f2 1205 tty->driver_data = tp;
1da177e4
LT
1206 return 0;
1207}
1208
736c9fd2
MS
1209/*
1210 * This routine is called whenever a 3270 tty is opened.
1211 */
e6d98bb8 1212static int tty3270_open(struct tty_struct *tty, struct file *filp)
736c9fd2
MS
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
1da177e4
LT
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 */
e6d98bb8 1226static void tty3270_close(struct tty_struct *tty, struct file *filp)
1da177e4 1227{
881e18f9 1228 struct tty3270 *tp = tty->driver_data;
1da177e4
LT
1229
1230 if (tty->count > 1)
1231 return;
b512353c 1232 if (tp)
ba186e7d 1233 tty_port_tty_set(&tp->port, NULL);
1da177e4
LT
1234}
1235
20cda6f2
JS
1236static void tty3270_cleanup(struct tty_struct *tty)
1237{
1238 struct tty3270 *tp = tty->driver_data;
1239
b512353c
MS
1240 if (tp) {
1241 tty->driver_data = NULL;
20cda6f2 1242 raw3270_put_view(&tp->view);
b512353c 1243 }
20cda6f2
JS
1244}
1245
1da177e4
LT
1246/*
1247 * We always have room.
1248 */
e6d98bb8 1249static unsigned int tty3270_write_room(struct tty_struct *tty)
1da177e4
LT
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 */
e17934c1 1258static void tty3270_put_character(struct tty3270 *tp, u8 ch)
1da177e4
LT
1259{
1260 struct tty3270_line *line;
1261 struct tty3270_cell *cell;
1262
9c138af9 1263 line = tty3270_get_write_line(tp, tp->cy);
1da177e4
LT
1264 if (line->len <= tp->cx) {
1265 while (line->len < tp->cx) {
1266 cell = line->cells + line->len;
6e49017c 1267 cell->character = ' ';
c2e9375e 1268 cell->attributes = tp->attributes;
1da177e4
LT
1269 line->len++;
1270 }
1271 line->len++;
1272 }
1273 cell = line->cells + tp->cx;
6e49017c 1274 cell->character = ch;
c2e9375e 1275 cell->attributes = tp->attributes;
9c138af9 1276 line->dirty = 1;
1da177e4
LT
1277}
1278
1da177e4
LT
1279/*
1280 * Do carriage return.
1281 */
e6d98bb8 1282static void tty3270_cr(struct tty3270 *tp)
1da177e4
LT
1283{
1284 tp->cx = 0;
1285}
1286
1287/*
1288 * Do line feed.
1289 */
e6d98bb8 1290static void tty3270_lf(struct tty3270 *tp)
1da177e4 1291{
9c138af9 1292 struct tty3270_line *line;
1da177e4
LT
1293 int i;
1294
9eb99b94 1295 if (tp->cy < tty3270_tty_rows(tp) - 1) {
1da177e4 1296 tp->cy++;
9c138af9
SS
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;
1da177e4 1302 }
9c138af9
SS
1303
1304 line = tty3270_get_write_line(tp, tp->cy);
1305 line->len = 0;
1306 line->dirty = 1;
1da177e4
LT
1307}
1308
e6d98bb8 1309static void tty3270_ri(struct tty3270 *tp)
1da177e4 1310{
9c138af9
SS
1311 if (tp->cy > 0)
1312 tp->cy--;
1da177e4
LT
1313}
1314
c2e9375e
SS
1315static void tty3270_reset_cell(struct tty3270 *tp, struct tty3270_cell *cell)
1316{
6e49017c 1317 cell->character = ' ';
c2e9375e
SS
1318 tty3270_reset_attributes(&cell->attributes);
1319}
1320
1da177e4
LT
1321/*
1322 * Insert characters at current position.
1323 */
e6d98bb8 1324static void tty3270_insert_characters(struct tty3270 *tp, int n)
1da177e4
LT
1325{
1326 struct tty3270_line *line;
1327 int k;
1328
9c138af9 1329 line = tty3270_get_write_line(tp, tp->cy);
c2e9375e
SS
1330 while (line->len < tp->cx)
1331 tty3270_reset_cell(tp, &line->cells[line->len++]);
1da177e4
LT
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) {
6e49017c 1341 line->cells[tp->cx + n].character = ' ';
c2e9375e 1342 line->cells[tp->cx + n].attributes = tp->attributes;
1da177e4
LT
1343 }
1344}
1345
1346/*
1347 * Delete characters at current position.
1348 */
e6d98bb8 1349static void tty3270_delete_characters(struct tty3270 *tp, int n)
1da177e4
LT
1350{
1351 struct tty3270_line *line;
1352 int i;
1353
9c138af9 1354 line = tty3270_get_write_line(tp, tp->cy);
1da177e4
LT
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 */
e6d98bb8 1369static void tty3270_erase_characters(struct tty3270 *tp, int n)
1da177e4
LT
1370{
1371 struct tty3270_line *line;
1372 struct tty3270_cell *cell;
1373
9c138af9 1374 line = tty3270_get_write_line(tp, tp->cy);
1da177e4
LT
1375 while (line->len > tp->cx && n-- > 0) {
1376 cell = line->cells + tp->cx++;
c2e9375e 1377 tty3270_reset_cell(tp, cell);
1da177e4
LT
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 */
e6d98bb8 1389static void tty3270_erase_line(struct tty3270 *tp, int mode)
1da177e4
LT
1390{
1391 struct tty3270_line *line;
1392 struct tty3270_cell *cell;
4043ea22 1393 int i, start, end;
1da177e4 1394
9c138af9 1395 line = tty3270_get_write_line(tp, tp->cy);
4043ea22 1396
815f3eee
SS
1397 switch (mode) {
1398 case 0:
4043ea22
SS
1399 start = tp->cx;
1400 end = tp->view.cols;
815f3eee
SS
1401 break;
1402 case 1:
4043ea22
SS
1403 start = 0;
1404 end = tp->cx;
815f3eee
SS
1405 break;
1406 case 2:
4043ea22
SS
1407 start = 0;
1408 end = tp->view.cols;
815f3eee
SS
1409 break;
1410 default:
1411 return;
1412 }
4043ea22
SS
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;
1da177e4
LT
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 */
e6d98bb8 1430static void tty3270_erase_display(struct tty3270 *tp, int mode)
1da177e4 1431{
9c138af9 1432 struct tty3270_line *line;
65b77ccb 1433 int i, start, end;
1da177e4 1434
65b77ccb
SS
1435 switch (mode) {
1436 case 0:
1da177e4 1437 tty3270_erase_line(tp, 0);
65b77ccb 1438 start = tp->cy + 1;
9eb99b94 1439 end = tty3270_tty_rows(tp);
65b77ccb
SS
1440 break;
1441 case 1:
1442 start = 0;
1443 end = tp->cy;
1da177e4 1444 tty3270_erase_line(tp, 1);
65b77ccb
SS
1445 break;
1446 case 2:
1447 start = 0;
9eb99b94 1448 end = tty3270_tty_rows(tp);
65b77ccb
SS
1449 break;
1450 default:
1451 return;
1452 }
1453 for (i = start; i < end; i++) {
9c138af9
SS
1454 line = tty3270_get_write_line(tp, i);
1455 line->len = 0;
1456 line->dirty = 1;
1da177e4 1457 }
1da177e4
LT
1458}
1459
1460/*
1461 * Set attributes found in an escape sequence.
1462 * Esc [ <attr> ; <attr> ; ... m
1463 */
e6d98bb8 1464static void tty3270_set_attributes(struct tty3270 *tp)
1da177e4 1465{
1da177e4
LT
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 */
c2e9375e 1472 tty3270_reset_attributes(&tp->attributes);
1da177e4
LT
1473 break;
1474 /* Highlight. */
1475 case 4: /* Start underlining. */
0573fff2 1476 tp->attributes.highlight = TTY3270_HIGHLIGHT_UNDERSCORE;
1da177e4
LT
1477 break;
1478 case 5: /* Start blink. */
0573fff2 1479 tp->attributes.highlight = TTY3270_HIGHLIGHT_BLINK;
1da177e4
LT
1480 break;
1481 case 7: /* Start reverse. */
0573fff2 1482 tp->attributes.highlight = TTY3270_HIGHLIGHT_REVERSE;
1da177e4
LT
1483 break;
1484 case 24: /* End underlining */
0573fff2 1485 tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_UNDERSCORE;
1da177e4
LT
1486 break;
1487 case 25: /* End blink. */
0573fff2 1488 tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_BLINK;
1da177e4
LT
1489 break;
1490 case 27: /* End reverse. */
0573fff2 1491 tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_REVERSE;
1da177e4
LT
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 */
18fc2e93 1503 tp->attributes.f_color = attr - 30;
4043ea22
SS
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 */
18fc2e93 1515 tp->attributes.b_color = attr - 40;
1da177e4
LT
1516 break;
1517 }
1518 }
1519}
1520
e6d98bb8 1521static inline int tty3270_getpar(struct tty3270 *tp, int ix)
1da177e4
LT
1522{
1523 return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
1524}
1525
e6d98bb8 1526static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
1da177e4 1527{
4043ea22
SS
1528 struct tty3270_line *line;
1529 struct tty3270_cell *cell;
364c8558
HC
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);
9c138af9 1534 line = tty3270_get_write_line(tp, tp->cy);
4043ea22
SS
1535 while (line->len < tp->cx) {
1536 cell = line->cells + line->len;
1537 cell->character = ' ';
1538 cell->attributes = tp->attributes;
1539 line->len++;
1540 }
9c138af9 1541 tp->cy = min_t(int, tty3270_tty_rows(tp) - 1, max_cy);
1da177e4
LT
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 */
e17934c1 1564static void tty3270_escape_sequence(struct tty3270 *tp, u8 ch)
1da177e4 1565{
303bac9d 1566 enum { ES_NORMAL, ES_ESC, ES_SQUARE, ES_PAREN, ES_GETPARS };
1da177e4 1567
303bac9d 1568 if (tp->esc_state == ES_NORMAL) {
1da177e4
LT
1569 if (ch == 0x1b)
1570 /* Starting new escape sequence. */
303bac9d 1571 tp->esc_state = ES_ESC;
1da177e4
LT
1572 return;
1573 }
303bac9d
SS
1574 if (tp->esc_state == ES_ESC) {
1575 tp->esc_state = ES_NORMAL;
1da177e4
LT
1576 switch (ch) {
1577 case '[':
303bac9d 1578 tp->esc_state = ES_SQUARE;
1da177e4 1579 break;
e4b57b93 1580 case '(':
303bac9d 1581 tp->esc_state = ES_PAREN;
e4b57b93 1582 break;
1da177e4
LT
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. */
ba186e7d 1594 kbd_puts_queue(&tp->port, "\033[?6c");
1da177e4
LT
1595 break;
1596 case '7': /* Save cursor position. */
1597 tp->saved_cx = tp->cx;
1598 tp->saved_cy = tp->cy;
c2e9375e 1599 tp->saved_attributes = tp->attributes;
1da177e4
LT
1600 break;
1601 case '8': /* Restore cursor position. */
1da177e4 1602 tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
c2e9375e 1603 tp->attributes = tp->saved_attributes;
1da177e4
LT
1604 break;
1605 case 'c': /* Reset terminal. */
f8674930
SS
1606 tp->cx = 0;
1607 tp->cy = 0;
1608 tp->saved_cx = 0;
1609 tp->saved_cy = 0;
c2e9375e
SS
1610 tty3270_reset_attributes(&tp->attributes);
1611 tty3270_reset_attributes(&tp->saved_attributes);
1da177e4
LT
1612 tty3270_erase_display(tp, 2);
1613 break;
1614 }
1615 return;
1616 }
e4b57b93
SS
1617
1618 switch (tp->esc_state) {
303bac9d
SS
1619 case ES_PAREN:
1620 tp->esc_state = ES_NORMAL;
e4b57b93
SS
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;
303bac9d
SS
1630 case ES_SQUARE:
1631 tp->esc_state = ES_GETPARS;
1da177e4
LT
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;
e4b57b93 1637 fallthrough;
303bac9d 1638 case ES_GETPARS:
1da177e4
LT
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 }
e4b57b93
SS
1648 break;
1649 default:
1650 break;
1da177e4 1651 }
303bac9d 1652 tp->esc_state = ES_NORMAL;
1da177e4
LT
1653 if (ch == 'n' && !tp->esc_ques) {
1654 if (tp->esc_par[0] == 5) /* Status report. */
ba186e7d 1655 kbd_puts_queue(&tp->port, "\033[0n");
1da177e4
LT
1656 else if (tp->esc_par[0] == 6) { /* Cursor report. */
1657 char buf[40];
7ef21387 1658
1da177e4 1659 sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
ba186e7d 1660 kbd_puts_queue(&tp->port, buf);
1da177e4
LT
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;
c2e9375e 1716 tp->saved_attributes = tp->attributes;
1da177e4
LT
1717 break;
1718 case 'u': /* Restore cursor position. */
1da177e4 1719 tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
c2e9375e 1720 tp->attributes = tp->saved_attributes;
1da177e4
LT
1721 break;
1722 }
1723}
1724
1725/*
1726 * String write routine for 3270 ttys
1727 */
e6d98bb8 1728static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
e17934c1 1729 const u8 *buf, size_t count)
1da177e4
LT
1730{
1731 int i_msg, i;
1732
c17fe081 1733 spin_lock_irq(&tp->view.lock);
6e94dbc7 1734 for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
1da177e4
LT
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]) {
970cf9a9
SS
1742 case 0x00:
1743 break;
1da177e4
LT
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);
f8674930
SS
1770 tp->cx = 0;
1771 tp->cy = 0;
1da177e4
LT
1772 break;
1773 case 0x0d: /* '\r' -- Carriage Return */
1774 tp->cx = 0;
1775 break;
94dbb0a7
SS
1776 case 0x0e:
1777 tp->attributes.alternate_charset = 1;
1778 break;
1da177e4 1779 case 0x0f: /* SuSE "exit alternate mode" */
94dbb0a7 1780 tp->attributes.alternate_charset = 0;
1da177e4
LT
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 }
1da177e4 1795 /* Setup timer to update display after 1/10 second */
ba5c2e2a 1796 tp->update_flags |= TTY_UPDATE_LINES;
1da177e4 1797 if (!timer_pending(&tp->timer))
9e1d1d8e 1798 tty3270_set_timer(tp, msecs_to_jiffies(100));
1da177e4 1799
c17fe081 1800 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
1801}
1802
1803/*
1804 * String write routine for 3270 ttys
1805 */
95713967
JSS
1806static ssize_t tty3270_write(struct tty_struct *tty, const u8 *buf,
1807 size_t count)
1da177e4
LT
1808{
1809 struct tty3270 *tp;
1810
1811 tp = tty->driver_data;
1812 if (!tp)
1813 return 0;
1814 if (tp->char_count > 0) {
20acdfa8 1815 tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
1da177e4
LT
1816 tp->char_count = 0;
1817 }
20acdfa8 1818 tty3270_do_write(tp, tty, buf, count);
1da177e4
LT
1819 return count;
1820}
1821
1822/*
1823 * Put single characters to the ttys character buffer
1824 */
dcaafbe6 1825static int tty3270_put_char(struct tty_struct *tty, u8 ch)
1da177e4
LT
1826{
1827 struct tty3270 *tp;
1828
1829 tp = tty->driver_data;
74c76c84
HC
1830 if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
1831 return 0;
1832 tp->char_buf[tp->char_count++] = ch;
1833 return 1;
1da177e4
LT
1834}
1835
1836/*
1837 * Flush all characters from the ttys characeter buffer put there
1838 * by tty3270_put_char.
1839 */
e6d98bb8 1840static void tty3270_flush_chars(struct tty_struct *tty)
1da177e4
LT
1841{
1842 struct tty3270 *tp;
1843
1844 tp = tty->driver_data;
1845 if (!tp)
1846 return;
1847 if (tp->char_count > 0) {
20acdfa8 1848 tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
1da177e4
LT
1849 tp->char_count = 0;
1850 }
1851}
1852
1da177e4
LT
1853/*
1854 * Check for visible/invisible input switches
1855 */
e6d98bb8 1856static void tty3270_set_termios(struct tty_struct *tty, const struct ktermios *old)
1da177e4
LT
1857{
1858 struct tty3270 *tp;
1859 int new;
1860
1861 tp = tty->driver_data;
1862 if (!tp)
1863 return;
c17fe081 1864 spin_lock_irq(&tp->view.lock);
1da177e4 1865 if (L_ICANON(tty)) {
7ef21387 1866 new = L_ECHO(tty) ? TF_INPUT : TF_INPUTN;
1da177e4
LT
1867 if (new != tp->inattr) {
1868 tp->inattr = new;
76485078 1869 tty3270_update_prompt(tp, "");
1da177e4
LT
1870 tty3270_set_timer(tp, 1);
1871 }
1872 }
c17fe081 1873 spin_unlock_irq(&tp->view.lock);
1da177e4
LT
1874}
1875
1876/*
1877 * Disable reading from a 3270 tty
1878 */
e6d98bb8 1879static void tty3270_throttle(struct tty_struct *tty)
1da177e4
LT
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 */
e6d98bb8 1892static void tty3270_unthrottle(struct tty_struct *tty)
1da177e4
LT
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 */
e6d98bb8 1907static void tty3270_hangup(struct tty_struct *tty)
1da177e4 1908{
0c756914
MS
1909 struct tty3270 *tp;
1910
1911 tp = tty->driver_data;
1912 if (!tp)
1913 return;
c17fe081 1914 spin_lock_irq(&tp->view.lock);
f8674930
SS
1915 tp->cx = 0;
1916 tp->cy = 0;
1917 tp->saved_cx = 0;
1918 tp->saved_cy = 0;
c2e9375e
SS
1919 tty3270_reset_attributes(&tp->attributes);
1920 tty3270_reset_attributes(&tp->saved_attributes);
0c756914 1921 tty3270_blank_screen(tp);
0c756914 1922 tp->update_flags = TTY_UPDATE_ALL;
c17fe081 1923 spin_unlock_irq(&tp->view.lock);
0c756914 1924 tty3270_set_timer(tp, 1);
1da177e4
LT
1925}
1926
e6d98bb8 1927static void tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
1da177e4
LT
1928{
1929}
1930
65c56e07
HC
1931static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
1932 unsigned long arg)
1da177e4
LT
1933{
1934 struct tty3270 *tp;
1935
1936 tp = tty->driver_data;
1937 if (!tp)
1938 return -ENODEV;
18900ca6 1939 if (tty_io_error(tty))
1da177e4 1940 return -EIO;
65c56e07 1941 return kbd_ioctl(tp->kbd, cmd, arg);
1da177e4
LT
1942}
1943
9d4bfd41 1944#ifdef CONFIG_COMPAT
65c56e07
HC
1945static long tty3270_compat_ioctl(struct tty_struct *tty,
1946 unsigned int cmd, unsigned long arg)
9d4bfd41
AB
1947{
1948 struct tty3270 *tp;
1949
1950 tp = tty->driver_data;
1951 if (!tp)
1952 return -ENODEV;
18900ca6 1953 if (tty_io_error(tty))
9d4bfd41 1954 return -EIO;
65c56e07 1955 return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
9d4bfd41
AB
1956}
1957#endif
1958
b68e31d0 1959static const struct tty_operations tty3270_ops = {
20cda6f2
JS
1960 .install = tty3270_install,
1961 .cleanup = tty3270_cleanup,
736c9fd2 1962 .open = tty3270_open,
1da177e4
LT
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,
1da177e4
LT
1968 .throttle = tty3270_throttle,
1969 .unthrottle = tty3270_unthrottle,
1970 .hangup = tty3270_hangup,
1971 .wait_until_sent = tty3270_wait_until_sent,
1972 .ioctl = tty3270_ioctl,
9d4bfd41
AB
1973#ifdef CONFIG_COMPAT
1974 .compat_ioctl = tty3270_compat_ioctl,
1975#endif
1da177e4
LT
1976 .set_termios = tty3270_set_termios
1977};
1978
63df41d6 1979static void tty3270_create_cb(int minor)
c95571e6 1980{
1fcbba3d 1981 tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
c95571e6
MS
1982}
1983
63df41d6 1984static void tty3270_destroy_cb(int minor)
c95571e6 1985{
1fcbba3d 1986 tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
c95571e6
MS
1987}
1988
7ef21387 1989static struct raw3270_notifier tty3270_notifier = {
c95571e6
MS
1990 .create = tty3270_create_cb,
1991 .destroy = tty3270_destroy_cb,
1992};
1993
1da177e4
LT
1994/*
1995 * 3270 tty registration code called from tty_init().
1996 * Most kernel services (incl. kmalloc) are available at this poimt.
1997 */
2b67fc46 1998static int __init tty3270_init(void)
1da177e4
LT
1999{
2000 struct tty_driver *driver;
2001 int ret;
2002
c95571e6
MS
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);
1da177e4
LT
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 */
c95571e6
MS
2015 driver->driver_name = "tty3270";
2016 driver->name = "3270/tty";
1da177e4 2017 driver->major = IBM_TTY3270_MAJOR;
1fcbba3d
MS
2018 driver->minor_start = RAW3270_FIRSTMINOR;
2019 driver->name_base = RAW3270_FIRSTMINOR;
1da177e4
LT
2020 driver->type = TTY_DRIVER_TYPE_SYSTEM;
2021 driver->subtype = SYSTEM_TYPE_TTY;
2022 driver->init_termios = tty_std_termios;
1da177e4
LT
2023 tty_set_operations(driver, &tty3270_ops);
2024 ret = tty_register_driver(driver);
2025 if (ret) {
9f90a4dd 2026 tty_driver_kref_put(driver);
1da177e4
LT
2027 return ret;
2028 }
2029 tty3270_driver = driver;
c95571e6 2030 raw3270_register_notifier(&tty3270_notifier);
1da177e4
LT
2031 return 0;
2032}
2033
e6d98bb8 2034static void __exit tty3270_exit(void)
1da177e4
LT
2035{
2036 struct tty_driver *driver;
2037
c95571e6 2038 raw3270_unregister_notifier(&tty3270_notifier);
1da177e4 2039 driver = tty3270_driver;
d2c993d8 2040 tty3270_driver = NULL;
1da177e4 2041 tty_unregister_driver(driver);
9f90a4dd 2042 tty_driver_kref_put(driver);
1da177e4
LT
2043 tty3270_del_views();
2044}
2045
c17fe081 2046#if IS_ENABLED(CONFIG_TN3270_CONSOLE)
9cab4f7d
HC
2047
2048static struct tty3270 *condev;
2049
c17fe081
SS
2050static void
2051con3270_write(struct console *co, const char *str, unsigned int count)
2052{
2053 struct tty3270 *tp = co->data;
2054 unsigned long flags;
e17934c1 2055 u8 c;
c17fe081
SS
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;
9975fde0 2104 int rc;
c17fe081
SS
2105
2106 tp = condev;
2107 if (!tp->view.dev)
2108 return NOTIFY_DONE;
9975fde0
SS
2109 if (!raw3270_view_lock_unavailable(&tp->view)) {
2110 rc = raw3270_activate_view(&tp->view);
2111 if (rc)
2112 return NOTIFY_DONE;
2113 }
c17fe081
SS
2114 if (!spin_trylock_irqsave(&tp->view.lock, flags))
2115 return NOTIFY_DONE;
2116 con3270_wait_write(tp);
2117 tp->nr_up = 0;
ba5c2e2a 2118 tp->update_flags = TTY_UPDATE_ALL;
c17fe081
SS
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
1da177e4
LT
2188MODULE_LICENSE("GPL");
2189MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
2190
2191module_init(tty3270_init);
2192module_exit(tty3270_exit);