1 // SPDX-License-Identifier: GPL-2.0
3 * IBM/3270 Driver - tty functions.
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
11 #include <linux/module.h>
12 #include <linux/types.h>
13 #include <linux/kdev_t.h>
14 #include <linux/tty.h>
15 #include <linux/vt_kern.h>
16 #include <linux/init.h>
17 #include <linux/console.h>
18 #include <linux/interrupt.h>
19 #include <linux/workqueue.h>
20 #include <linux/panic_notifier.h>
21 #include <linux/reboot.h>
22 #include <linux/slab.h>
23 #include <linux/memblock.h>
24 #include <linux/compat.h>
26 #include <asm/ccwdev.h>
28 #include <asm/ebcdic.h>
29 #include <asm/cpcmd.h>
30 #include <linux/uaccess.h>
35 #define TTY3270_CHAR_BUF_SIZE 256
36 #define TTY3270_OUTPUT_BUFFER_SIZE 4096
37 #define TTY3270_SCREEN_PAGES 8 /* has to be power-of-two */
38 #define TTY3270_RECALL_SIZE 16 /* has to be power-of-two */
39 #define TTY3270_STATUS_AREA_SIZE 40
41 static struct tty_driver
*tty3270_driver
;
42 static int tty3270_max_index
;
43 static struct raw3270_fn tty3270_fn
;
45 #define TTY3270_HIGHLIGHT_BLINK 1
46 #define TTY3270_HIGHLIGHT_REVERSE 2
47 #define TTY3270_HIGHLIGHT_UNDERSCORE 4
49 struct tty3270_attribute
{
50 unsigned char alternate_charset
:1; /* Graphics charset */
51 unsigned char highlight
:3; /* Blink/reverse/underscore */
52 unsigned char f_color
:4; /* Foreground color */
53 unsigned char b_color
:4; /* Background color */
58 struct tty3270_attribute attributes
;
62 struct tty3270_cell
*cells
;
67 static const unsigned char sfq_read_partition
[] = {
68 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81
74 * The main tty view data structure.
76 * 1) describe line orientation & lines list concept against screen
77 * 2) describe conversion of screen to lines
78 * 3) describe line format.
81 struct raw3270_view view
;
85 unsigned char wcc
; /* Write control character. */
86 int nr_up
; /* # lines up in history. */
87 unsigned long update_flags
; /* Update indication bits. */
88 struct raw3270_request
*write
; /* Single write request. */
89 struct timer_list timer
; /* Output delay timer. */
90 char *converted_line
; /* RAW 3270 data stream */
91 unsigned int line_view_start
; /* Start of visible area */
92 unsigned int line_write_start
; /* current write position */
93 unsigned int oops_line
; /* line counter used when print oops */
95 /* Current tty screen. */
96 unsigned int cx
, cy
; /* Current output position. */
97 struct tty3270_attribute attributes
;
98 struct tty3270_attribute saved_attributes
;
100 struct tty3270_line
*screen
;
103 char *prompt
; /* Output string for input area. */
104 char *input
; /* Input string for read request. */
105 struct raw3270_request
*read
; /* Single read request. */
106 struct raw3270_request
*kreset
; /* Single keyboard reset request. */
107 struct raw3270_request
*readpartreq
;
108 unsigned char inattr
; /* Visible/invisible input. */
109 int throttle
, attn
; /* tty throttle/unthrottle. */
110 struct tasklet_struct readlet
; /* Tasklet to issue read request. */
111 struct tasklet_struct hanglet
; /* Tasklet to hang up the tty. */
112 struct kbd_data
*kbd
; /* key_maps stuff. */
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
;
119 /* Command recalling. */
120 char **rcl_lines
; /* Array of recallable lines */
121 int rcl_write_index
; /* Write index of recallable items */
122 int rcl_read_index
; /* Read index of recallable items */
124 /* Character array for put_char/flush_chars. */
125 unsigned int char_count
;
126 u8 char_buf
[TTY3270_CHAR_BUF_SIZE
];
129 /* tty3270->update_flags. See tty3270_update for details. */
130 #define TTY_UPDATE_INPUT 0x1 /* Update input line. */
131 #define TTY_UPDATE_STATUS 0x2 /* Update status line. */
132 #define TTY_UPDATE_LINES 0x4 /* Update visible screen lines */
133 #define TTY_UPDATE_ALL 0x7 /* Recreate screen. */
135 #define TTY3270_INPUT_AREA_ROWS 2
138 * Setup timeout for a device. On timeout trigger an update.
140 static void tty3270_set_timer(struct tty3270
*tp
, int expires
)
142 mod_timer(&tp
->timer
, jiffies
+ expires
);
145 static int tty3270_tty_rows(struct tty3270
*tp
)
147 return tp
->view
.rows
- TTY3270_INPUT_AREA_ROWS
;
150 static char *tty3270_add_ba(struct tty3270
*tp
, char *cp
, char order
, int x
, int y
)
153 raw3270_buffer_address(tp
->view
.dev
, cp
, x
, y
);
157 static char *tty3270_add_ra(struct tty3270
*tp
, char *cp
, int x
, int y
, char c
)
159 cp
= tty3270_add_ba(tp
, cp
, TO_RA
, x
, y
);
164 static char *tty3270_add_sa(struct tty3270
*tp
, char *cp
, char attr
, char value
)
172 static char *tty3270_add_ge(struct tty3270
*tp
, char *cp
, char c
)
179 static char *tty3270_add_sf(struct tty3270
*tp
, char *cp
, char type
)
186 static int tty3270_line_increment(struct tty3270
*tp
, unsigned int line
, unsigned int incr
)
188 return (line
+ incr
) & (tp
->allocated_lines
- 1);
191 static struct tty3270_line
*tty3270_get_write_line(struct tty3270
*tp
, unsigned int num
)
193 return tp
->screen
+ tty3270_line_increment(tp
, tp
->line_write_start
, num
);
196 static struct tty3270_line
*tty3270_get_view_line(struct tty3270
*tp
, unsigned int num
)
198 return tp
->screen
+ tty3270_line_increment(tp
, tp
->line_view_start
, num
- tp
->nr_up
);
201 static int tty3270_input_size(int cols
)
203 return cols
* 2 - 11;
206 static void tty3270_update_prompt(struct tty3270
*tp
, char *input
)
208 strcpy(tp
->prompt
, input
);
209 tp
->update_flags
|= TTY_UPDATE_INPUT
;
210 tty3270_set_timer(tp
, 1);
214 * The input line are the two last lines of the screen.
216 static int tty3270_add_prompt(struct tty3270
*tp
)
221 cp
= tp
->converted_line
;
222 cp
= tty3270_add_ba(tp
, cp
, TO_SBA
, 0, -2);
223 *cp
++ = tp
->view
.ascebc
['>'];
226 cp
= tty3270_add_sf(tp
, cp
, TF_INMDT
);
227 count
= min_t(int, strlen(tp
->prompt
),
228 tp
->view
.cols
* 2 - TTY3270_STATUS_AREA_SIZE
- 2);
229 memcpy(cp
, tp
->prompt
, count
);
232 cp
= tty3270_add_sf(tp
, cp
, tp
->inattr
);
235 /* Clear to end of input line. */
236 if (count
< tp
->view
.cols
* 2 - 11)
237 cp
= tty3270_add_ra(tp
, cp
, -TTY3270_STATUS_AREA_SIZE
, -1, 0);
238 return cp
- tp
->converted_line
;
241 static char *tty3270_ebcdic_convert(struct tty3270
*tp
, char *d
, char *s
)
244 *d
++ = tp
->view
.ascebc
[(int)*s
++];
249 * The status line is the last line of the screen. It shows the string
250 * "Running"/"History X" in the lower right corner of the screen.
252 static int tty3270_add_status(struct tty3270
*tp
)
254 char *cp
= tp
->converted_line
;
257 cp
= tty3270_add_ba(tp
, cp
, TO_SBA
, -TTY3270_STATUS_AREA_SIZE
, -1);
258 cp
= tty3270_add_sf(tp
, cp
, TF_LOG
);
259 cp
= tty3270_add_sa(tp
, cp
, TAT_FGCOLOR
, TAC_GREEN
);
260 cp
= tty3270_ebcdic_convert(tp
, cp
, " 7");
261 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_REVER
);
262 cp
= tty3270_ebcdic_convert(tp
, cp
, "PrevPg");
263 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_RESET
);
264 cp
= tty3270_ebcdic_convert(tp
, cp
, " 8");
265 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_REVER
);
266 cp
= tty3270_ebcdic_convert(tp
, cp
, "NextPg");
267 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_RESET
);
268 cp
= tty3270_ebcdic_convert(tp
, cp
, " 12");
269 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_REVER
);
270 cp
= tty3270_ebcdic_convert(tp
, cp
, "Recall");
271 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_RESET
);
272 cp
= tty3270_ebcdic_convert(tp
, cp
, " ");
274 len
= sprintf(cp
, "History %d", -tp
->nr_up
);
275 codepage_convert(tp
->view
.ascebc
, cp
, len
);
278 cp
= tty3270_ebcdic_convert(tp
, cp
, oops_in_progress
? "Crashed" : "Running");
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
;
285 static void tty3270_blank_screen(struct tty3270
*tp
)
287 struct tty3270_line
*line
;
290 for (i
= 0; i
< tty3270_tty_rows(tp
); i
++) {
291 line
= tty3270_get_write_line(tp
, i
);
299 * Write request completion callback.
301 static void tty3270_write_callback(struct raw3270_request
*rq
, void *data
)
303 struct tty3270
*tp
= container_of(rq
->view
, struct tty3270
, view
);
306 /* Write wasn't successful. Refresh all. */
307 tp
->update_flags
= TTY_UPDATE_ALL
;
308 tty3270_set_timer(tp
, 1);
310 raw3270_request_reset(rq
);
311 xchg(&tp
->write
, rq
);
314 static int tty3270_required_length(struct tty3270
*tp
, struct tty3270_line
*line
)
316 unsigned char f_color
, b_color
, highlight
;
317 struct tty3270_cell
*cell
;
318 int i
, flen
= 3; /* Prefix (TO_SBA). */
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
;
330 if (cell
->attributes
.f_color
!= f_color
) {
331 flen
+= 3; /* TO_SA to switch color. */
332 f_color
= cell
->attributes
.f_color
;
334 if (cell
->attributes
.b_color
!= b_color
) {
335 flen
+= 3; /* TO_SA to switch color. */
336 b_color
= cell
->attributes
.b_color
;
338 if (cell
->attributes
.alternate_charset
)
339 flen
+= 1; /* TO_GE to switch to graphics extensions */
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). */
353 static char *tty3270_add_reset_attributes(struct tty3270
*tp
, struct tty3270_line
*line
,
354 char *cp
, struct tty3270_attribute
*attr
, int lineno
)
357 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, TAX_RESET
);
358 if (attr
->f_color
!= TAC_RESET
)
359 cp
= tty3270_add_sa(tp
, cp
, TAT_FGCOLOR
, TAX_RESET
);
360 if (attr
->b_color
!= TAC_RESET
)
361 cp
= tty3270_add_sa(tp
, cp
, TAT_BGCOLOR
, TAX_RESET
);
362 if (line
->len
< tp
->view
.cols
)
363 cp
= tty3270_add_ra(tp
, cp
, 0, lineno
+ 1, 0);
367 static char tty3270_graphics_translate(struct tty3270
*tp
, char ch
)
397 static char *tty3270_add_attributes(struct tty3270
*tp
, struct tty3270_line
*line
,
398 struct tty3270_attribute
*attr
, char *cp
, int lineno
)
400 const unsigned char colors
[16] = {
412 const unsigned char highlights
[8] = {
413 [TTY3270_HIGHLIGHT_BLINK
] = TAX_BLINK
,
414 [TTY3270_HIGHLIGHT_REVERSE
] = TAX_REVER
,
415 [TTY3270_HIGHLIGHT_UNDERSCORE
] = TAX_UNDER
,
418 struct tty3270_cell
*cell
;
421 cp
= tty3270_add_ba(tp
, cp
, TO_SBA
, 0, lineno
);
423 for (i
= 0, cell
= line
->cells
; i
< line
->len
; i
++, cell
++) {
424 if (cell
->attributes
.highlight
!= attr
->highlight
) {
425 attr
->highlight
= cell
->attributes
.highlight
;
426 cp
= tty3270_add_sa(tp
, cp
, TAT_EXTHI
, highlights
[attr
->highlight
]);
428 if (cell
->attributes
.f_color
!= attr
->f_color
) {
429 attr
->f_color
= cell
->attributes
.f_color
;
430 cp
= tty3270_add_sa(tp
, cp
, TAT_FGCOLOR
, colors
[attr
->f_color
]);
432 if (cell
->attributes
.b_color
!= attr
->b_color
) {
433 attr
->b_color
= cell
->attributes
.b_color
;
434 cp
= tty3270_add_sa(tp
, cp
, TAT_BGCOLOR
, colors
[attr
->b_color
]);
437 if (cell
->attributes
.alternate_charset
)
438 cp
= tty3270_add_ge(tp
, cp
, tty3270_graphics_translate(tp
, c
));
440 *cp
++ = tp
->view
.ascebc
[c
];
445 static void tty3270_reset_attributes(struct tty3270_attribute
*attr
)
447 attr
->highlight
= TAX_RESET
;
448 attr
->f_color
= TAC_RESET
;
449 attr
->b_color
= TAC_RESET
;
453 * Convert a tty3270_line to a 3270 data fragment usable for output.
455 static unsigned int tty3270_convert_line(struct tty3270
*tp
, struct tty3270_line
*line
, int lineno
)
457 struct tty3270_attribute attr
;
461 /* Determine how long the fragment will be. */
462 flen
= tty3270_required_length(tp
, line
);
463 if (flen
> PAGE_SIZE
)
465 /* Write 3270 data fragment. */
466 tty3270_reset_attributes(&attr
);
467 cp
= tty3270_add_attributes(tp
, line
, &attr
, tp
->converted_line
, lineno
);
468 cp
= tty3270_add_reset_attributes(tp
, line
, cp
, &attr
, lineno
);
469 return cp
- (char *)tp
->converted_line
;
472 static void tty3270_update_lines_visible(struct tty3270
*tp
, struct raw3270_request
*rq
)
474 struct tty3270_line
*line
;
477 for (i
= 0; i
< tty3270_tty_rows(tp
); i
++) {
478 line
= tty3270_get_view_line(tp
, i
);
481 len
= tty3270_convert_line(tp
, line
, i
);
482 if (raw3270_request_add_data(rq
, tp
->converted_line
, len
))
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
;
493 static void tty3270_update_lines_all(struct tty3270
*tp
, struct raw3270_request
*rq
)
495 struct tty3270_line
*line
;
499 for (i
= 0; i
< tp
->allocated_lines
; i
++) {
500 line
= tty3270_get_write_line(tp
, i
+ tp
->cy
+ 1);
503 len
= tty3270_convert_line(tp
, line
, tp
->oops_line
);
504 if (raw3270_request_add_data(rq
, tp
->converted_line
, len
))
507 if (++tp
->oops_line
>= tty3270_tty_rows(tp
))
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
)))
517 tp
->update_flags
&= ~TTY_UPDATE_LINES
;
522 * Update 3270 display.
524 static void tty3270_update(struct timer_list
*t
)
526 struct tty3270
*tp
= from_timer(tp
, t
, timer
);
527 struct raw3270_request
*wrq
;
531 wrq
= xchg(&tp
->write
, NULL
);
533 tty3270_set_timer(tp
, 1);
537 spin_lock_irq(&tp
->view
.lock
);
538 if (tp
->update_flags
== TTY_UPDATE_ALL
)
541 raw3270_request_set_cmd(wrq
, cmd
);
542 raw3270_request_add_data(wrq
, &tp
->wcc
, 1);
546 * Update status line.
548 if (tp
->update_flags
& TTY_UPDATE_STATUS
) {
549 len
= tty3270_add_status(tp
);
550 if (raw3270_request_add_data(wrq
, tp
->converted_line
, len
) == 0)
551 tp
->update_flags
&= ~TTY_UPDATE_STATUS
;
557 if (tp
->update_flags
& TTY_UPDATE_INPUT
) {
558 len
= tty3270_add_prompt(tp
);
559 if (raw3270_request_add_data(wrq
, tp
->converted_line
, len
) == 0)
560 tp
->update_flags
&= ~TTY_UPDATE_INPUT
;
563 if (tp
->update_flags
& TTY_UPDATE_LINES
) {
564 if (oops_in_progress
)
565 tty3270_update_lines_all(tp
, wrq
);
567 tty3270_update_lines_visible(tp
, wrq
);
570 wrq
->callback
= tty3270_write_callback
;
571 rc
= raw3270_start(&tp
->view
, wrq
);
573 if (tp
->update_flags
)
574 tty3270_set_timer(tp
, 1);
576 raw3270_request_reset(wrq
);
577 xchg(&tp
->write
, wrq
);
579 spin_unlock_irq(&tp
->view
.lock
);
585 static void tty3270_rcl_add(struct tty3270
*tp
, char *input
, int len
)
591 p
= tp
->rcl_lines
[tp
->rcl_write_index
++];
592 tp
->rcl_write_index
&= TTY3270_RECALL_SIZE
- 1;
593 memcpy(p
, input
, len
);
595 tp
->rcl_read_index
= tp
->rcl_write_index
;
598 static void tty3270_rcl_backward(struct kbd_data
*kbd
)
600 struct tty3270
*tp
= container_of(kbd
->port
, struct tty3270
, port
);
603 spin_lock_irq(&tp
->view
.lock
);
604 if (tp
->inattr
== TF_INPUT
) {
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
]);
612 spin_unlock_irq(&tp
->view
.lock
);
616 * Deactivate tty view.
618 static void tty3270_exit_tty(struct kbd_data
*kbd
)
620 struct tty3270
*tp
= container_of(kbd
->port
, struct tty3270
, port
);
622 raw3270_deactivate_view(&tp
->view
);
625 static void tty3270_redraw(struct tty3270
*tp
)
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);
636 * Scroll forward in history.
638 static void tty3270_scroll_forward(struct kbd_data
*kbd
)
640 struct tty3270
*tp
= container_of(kbd
->port
, struct tty3270
, port
);
642 spin_lock_irq(&tp
->view
.lock
);
644 if (tp
->nr_up
>= tty3270_tty_rows(tp
))
645 tp
->nr_up
-= tty3270_tty_rows(tp
) / 2;
649 spin_unlock_irq(&tp
->view
.lock
);
653 * Scroll backward in history.
655 static void tty3270_scroll_backward(struct kbd_data
*kbd
)
657 struct tty3270
*tp
= container_of(kbd
->port
, struct tty3270
, port
);
659 spin_lock_irq(&tp
->view
.lock
);
660 tp
->nr_up
+= tty3270_tty_rows(tp
) / 2;
661 if (tp
->nr_up
> tp
->allocated_lines
- tty3270_tty_rows(tp
))
662 tp
->nr_up
= tp
->allocated_lines
- tty3270_tty_rows(tp
);
664 spin_unlock_irq(&tp
->view
.lock
);
668 * Pass input line to tty.
670 static void tty3270_read_tasklet(unsigned long data
)
672 struct raw3270_request
*rrq
= (struct raw3270_request
*)data
;
673 static char kreset_data
= TW_KR
;
674 struct tty3270
*tp
= container_of(rrq
->view
, struct tty3270
, view
);
678 spin_lock_irq(&tp
->view
.lock
);
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.
686 switch (tp
->input
[0]) {
688 /* Enter: write input to tty. */
689 input
= tp
->input
+ 6;
690 len
= tty3270_input_size(tp
->view
.cols
) - 6 - rrq
->rescnt
;
691 if (tp
->inattr
!= TF_INPUTN
)
692 tty3270_rcl_add(tp
, input
, len
);
695 /* Clear input area. */
696 tty3270_update_prompt(tp
, "");
697 tty3270_set_timer(tp
, 1);
700 /* Display has been cleared. Redraw. */
701 tp
->update_flags
= TTY_UPDATE_ALL
;
702 tty3270_set_timer(tp
, 1);
703 if (!list_empty(&tp
->readpartreq
->list
))
705 raw3270_start_request(&tp
->view
, tp
->readpartreq
, TC_WRITESF
,
706 (char *)sfq_read_partition
, sizeof(sfq_read_partition
));
708 case AID_READ_PARTITION
:
709 raw3270_read_modified_cb(tp
->readpartreq
, tp
->input
);
714 spin_unlock_irq(&tp
->view
.lock
);
716 /* Start keyboard reset command. */
717 raw3270_start_request(&tp
->view
, tp
->kreset
, TC_WRITE
, &kreset_data
, 1);
720 kbd_keycode(tp
->kbd
, *input
++);
721 /* Emit keycode for AID byte. */
722 kbd_keycode(tp
->kbd
, 256 + tp
->input
[0]);
724 raw3270_request_reset(rrq
);
725 xchg(&tp
->read
, rrq
);
726 raw3270_put_view(&tp
->view
);
730 * Read request completion callback.
732 static void tty3270_read_callback(struct raw3270_request
*rq
, void *data
)
734 struct tty3270
*tp
= container_of(rq
->view
, struct tty3270
, view
);
736 raw3270_get_view(rq
->view
);
737 /* Schedule tasklet to pass input to tty. */
738 tasklet_schedule(&tp
->readlet
);
742 * Issue a read request. Call with device lock.
744 static void tty3270_issue_read(struct tty3270
*tp
, int lock
)
746 struct raw3270_request
*rrq
;
749 rrq
= xchg(&tp
->read
, NULL
);
751 /* Read already scheduled. */
753 rrq
->callback
= tty3270_read_callback
;
754 rrq
->callback_data
= tp
;
755 raw3270_request_set_cmd(rrq
, TC_READMOD
);
756 raw3270_request_set_data(rrq
, tp
->input
, tty3270_input_size(tp
->view
.cols
));
757 /* Issue the read modified request. */
759 rc
= raw3270_start(&tp
->view
, rrq
);
761 rc
= raw3270_start_irq(&tp
->view
, rrq
);
763 raw3270_request_reset(rrq
);
764 xchg(&tp
->read
, rrq
);
771 static void tty3270_hangup_tasklet(unsigned long data
)
773 struct tty3270
*tp
= (struct tty3270
*)data
;
775 tty_port_tty_hangup(&tp
->port
, true);
776 raw3270_put_view(&tp
->view
);
780 * Switch to the tty view.
782 static int tty3270_activate(struct raw3270_view
*view
)
784 struct tty3270
*tp
= container_of(view
, struct tty3270
, view
);
786 tp
->update_flags
= TTY_UPDATE_ALL
;
787 tty3270_set_timer(tp
, 1);
791 static void tty3270_deactivate(struct raw3270_view
*view
)
793 struct tty3270
*tp
= container_of(view
, struct tty3270
, view
);
795 del_timer(&tp
->timer
);
798 static void tty3270_irq(struct tty3270
*tp
, struct raw3270_request
*rq
, struct irb
*irb
)
800 /* Handle ATTN. Schedule tasklet to read aid. */
801 if (irb
->scsw
.cmd
.dstat
& DEV_STAT_ATTENTION
) {
803 tty3270_issue_read(tp
, 0);
809 if (irb
->scsw
.cmd
.dstat
& DEV_STAT_UNIT_CHECK
) {
811 raw3270_get_view(&tp
->view
);
812 tasklet_schedule(&tp
->hanglet
);
814 /* Normal end. Copy residual count. */
815 rq
->rescnt
= irb
->scsw
.cmd
.count
;
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);
825 * Allocate tty3270 structure.
827 static struct tty3270
*tty3270_alloc_view(void)
831 tp
= kzalloc(sizeof(*tp
), GFP_KERNEL
);
835 tp
->write
= raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE
);
836 if (IS_ERR(tp
->write
))
838 tp
->read
= raw3270_request_alloc(0);
839 if (IS_ERR(tp
->read
))
841 tp
->kreset
= raw3270_request_alloc(1);
842 if (IS_ERR(tp
->kreset
))
844 tp
->readpartreq
= raw3270_request_alloc(sizeof(sfq_read_partition
));
845 if (IS_ERR(tp
->readpartreq
))
847 tp
->kbd
= kbd_alloc();
849 goto out_readpartreq
;
851 tty_port_init(&tp
->port
);
852 timer_setup(&tp
->timer
, tty3270_update
, 0);
853 tasklet_init(&tp
->readlet
, tty3270_read_tasklet
,
854 (unsigned long)tp
->read
);
855 tasklet_init(&tp
->hanglet
, tty3270_hangup_tasklet
,
860 raw3270_request_free(tp
->readpartreq
);
862 raw3270_request_free(tp
->kreset
);
864 raw3270_request_free(tp
->read
);
866 raw3270_request_free(tp
->write
);
870 return ERR_PTR(-ENOMEM
);
874 * Free tty3270 structure.
876 static void tty3270_free_view(struct tty3270
*tp
)
879 raw3270_request_free(tp
->kreset
);
880 raw3270_request_free(tp
->read
);
881 raw3270_request_free(tp
->write
);
882 free_page((unsigned long)tp
->converted_line
);
883 tty_port_destroy(&tp
->port
);
888 * Allocate tty3270 screen.
890 static struct tty3270_line
*tty3270_alloc_screen(struct tty3270
*tp
, unsigned int rows
,
891 unsigned int cols
, int *allocated_out
)
893 struct tty3270_line
*screen
;
894 int allocated
, lines
;
896 allocated
= __roundup_pow_of_two(rows
) * TTY3270_SCREEN_PAGES
;
897 screen
= kcalloc(allocated
, sizeof(struct tty3270_line
), GFP_KERNEL
);
900 for (lines
= 0; lines
< allocated
; lines
++) {
901 screen
[lines
].cells
= kcalloc(cols
, sizeof(struct tty3270_cell
), GFP_KERNEL
);
902 if (!screen
[lines
].cells
)
905 *allocated_out
= allocated
;
909 kfree(screen
[lines
].cells
);
912 return ERR_PTR(-ENOMEM
);
915 static char **tty3270_alloc_recall(int cols
)
920 lines
= kmalloc_array(TTY3270_RECALL_SIZE
, sizeof(char *), GFP_KERNEL
);
923 for (i
= 0; i
< TTY3270_RECALL_SIZE
; i
++) {
924 lines
[i
] = kcalloc(1, tty3270_input_size(cols
) + 1, GFP_KERNEL
);
929 if (i
== TTY3270_RECALL_SIZE
)
938 static void tty3270_free_recall(char **lines
)
942 for (i
= 0; i
< TTY3270_RECALL_SIZE
; i
++)
948 * Free tty3270 screen.
950 static void tty3270_free_screen(struct tty3270_line
*screen
, int old_lines
)
954 for (lines
= 0; lines
< old_lines
; lines
++)
955 kfree(screen
[lines
].cells
);
960 * Resize tty3270 screen
962 static void tty3270_resize(struct raw3270_view
*view
,
963 int new_model
, int new_rows
, int new_cols
,
964 int old_model
, int old_rows
, int old_cols
)
966 struct tty3270
*tp
= container_of(view
, struct tty3270
, view
);
967 struct tty3270_line
*screen
, *oscreen
;
968 char **old_rcl_lines
, **new_rcl_lines
;
969 char *old_prompt
, *new_prompt
;
970 char *old_input
, *new_input
;
971 struct tty_struct
*tty
;
973 int new_allocated
, old_allocated
= tp
->allocated_lines
;
975 if (old_model
== new_model
&&
976 old_cols
== new_cols
&&
977 old_rows
== new_rows
) {
978 spin_lock_irq(&tp
->view
.lock
);
980 spin_unlock_irq(&tp
->view
.lock
);
984 new_input
= kzalloc(tty3270_input_size(new_cols
), GFP_KERNEL
| GFP_DMA
);
987 new_prompt
= kzalloc(tty3270_input_size(new_cols
), GFP_KERNEL
);
990 screen
= tty3270_alloc_screen(tp
, new_rows
, new_cols
, &new_allocated
);
993 new_rcl_lines
= tty3270_alloc_recall(new_cols
);
997 /* Switch to new output size */
998 spin_lock_irq(&tp
->view
.lock
);
999 tty3270_blank_screen(tp
);
1000 oscreen
= tp
->screen
;
1001 tp
->screen
= screen
;
1002 tp
->allocated_lines
= new_allocated
;
1003 tp
->view
.rows
= new_rows
;
1004 tp
->view
.cols
= new_cols
;
1005 tp
->view
.model
= new_model
;
1006 tp
->update_flags
= TTY_UPDATE_ALL
;
1007 old_input
= tp
->input
;
1008 old_prompt
= tp
->prompt
;
1009 old_rcl_lines
= tp
->rcl_lines
;
1010 tp
->input
= new_input
;
1011 tp
->prompt
= new_prompt
;
1012 tp
->rcl_lines
= new_rcl_lines
;
1013 tp
->rcl_read_index
= 0;
1014 tp
->rcl_write_index
= 0;
1015 spin_unlock_irq(&tp
->view
.lock
);
1016 tty3270_free_screen(oscreen
, old_allocated
);
1019 tty3270_free_recall(old_rcl_lines
);
1020 tty3270_set_timer(tp
, 1);
1021 /* Informat tty layer about new size */
1022 tty
= tty_port_tty_get(&tp
->port
);
1025 ws
.ws_row
= tty3270_tty_rows(tp
);
1026 ws
.ws_col
= tp
->view
.cols
;
1027 tty_do_resize(tty
, &ws
);
1031 tty3270_free_screen(screen
, new_rows
);
1039 * Unlink tty3270 data structure from tty.
1041 static void tty3270_release(struct raw3270_view
*view
)
1043 struct tty3270
*tp
= container_of(view
, struct tty3270
, view
);
1044 struct tty_struct
*tty
= tty_port_tty_get(&tp
->port
);
1047 tty
->driver_data
= NULL
;
1048 tty_port_tty_set(&tp
->port
, NULL
);
1050 raw3270_put_view(&tp
->view
);
1056 * Free tty3270 data structure
1058 static void tty3270_free(struct raw3270_view
*view
)
1060 struct tty3270
*tp
= container_of(view
, struct tty3270
, view
);
1062 del_timer_sync(&tp
->timer
);
1063 tty3270_free_screen(tp
->screen
, tp
->allocated_lines
);
1064 free_page((unsigned long)tp
->converted_line
);
1067 tty3270_free_view(tp
);
1071 * Delayed freeing of tty3270 views.
1073 static void tty3270_del_views(void)
1077 for (i
= RAW3270_FIRSTMINOR
; i
<= tty3270_max_index
; i
++) {
1078 struct raw3270_view
*view
= raw3270_find_view(&tty3270_fn
, i
);
1081 raw3270_del_view(view
);
1085 static struct raw3270_fn tty3270_fn
= {
1086 .activate
= tty3270_activate
,
1087 .deactivate
= tty3270_deactivate
,
1088 .intv
= (void *)tty3270_irq
,
1089 .release
= tty3270_release
,
1090 .free
= tty3270_free
,
1091 .resize
= tty3270_resize
1095 tty3270_create_view(int index
, struct tty3270
**newtp
)
1100 if (tty3270_max_index
< index
+ 1)
1101 tty3270_max_index
= index
+ 1;
1103 /* Allocate tty3270 structure on first open. */
1104 tp
= tty3270_alloc_view();
1108 rc
= raw3270_add_view(&tp
->view
, &tty3270_fn
,
1109 index
+ RAW3270_FIRSTMINOR
,
1110 RAW3270_VIEW_LOCK_IRQ
);
1114 tp
->screen
= tty3270_alloc_screen(tp
, tp
->view
.rows
, tp
->view
.cols
,
1115 &tp
->allocated_lines
);
1116 if (IS_ERR(tp
->screen
)) {
1117 rc
= PTR_ERR(tp
->screen
);
1121 tp
->converted_line
= (void *)__get_free_page(GFP_KERNEL
);
1122 if (!tp
->converted_line
) {
1124 goto out_free_screen
;
1127 tp
->input
= kzalloc(tty3270_input_size(tp
->view
.cols
), GFP_KERNEL
| GFP_DMA
);
1130 goto out_free_converted_line
;
1133 tp
->prompt
= kzalloc(tty3270_input_size(tp
->view
.cols
), GFP_KERNEL
);
1136 goto out_free_input
;
1139 tp
->rcl_lines
= tty3270_alloc_recall(tp
->view
.cols
);
1140 if (!tp
->rcl_lines
) {
1142 goto out_free_prompt
;
1145 /* Create blank line for every line in the tty output area. */
1146 tty3270_blank_screen(tp
);
1148 tp
->kbd
->port
= &tp
->port
;
1149 tp
->kbd
->fn_handler
[KVAL(K_INCRCONSOLE
)] = tty3270_exit_tty
;
1150 tp
->kbd
->fn_handler
[KVAL(K_SCROLLBACK
)] = tty3270_scroll_backward
;
1151 tp
->kbd
->fn_handler
[KVAL(K_SCROLLFORW
)] = tty3270_scroll_forward
;
1152 tp
->kbd
->fn_handler
[KVAL(K_CONS
)] = tty3270_rcl_backward
;
1153 kbd_ascebc(tp
->kbd
, tp
->view
.ascebc
);
1155 raw3270_activate_view(&tp
->view
);
1156 raw3270_put_view(&tp
->view
);
1164 out_free_converted_line
:
1165 free_page((unsigned long)tp
->converted_line
);
1167 tty3270_free_screen(tp
->screen
, tp
->view
.rows
);
1169 raw3270_put_view(&tp
->view
);
1170 raw3270_del_view(&tp
->view
);
1172 tty3270_free_view(tp
);
1177 * This routine is called whenever a 3270 tty is opened first time.
1180 tty3270_install(struct tty_driver
*driver
, struct tty_struct
*tty
)
1182 struct raw3270_view
*view
;
1186 /* Check if the tty3270 is already there. */
1187 view
= raw3270_find_view(&tty3270_fn
, tty
->index
+ RAW3270_FIRSTMINOR
);
1189 rc
= tty3270_create_view(tty
->index
, &tp
);
1193 tp
= container_of(view
, struct tty3270
, view
);
1194 tty
->driver_data
= tp
;
1195 tp
->inattr
= TF_INPUT
;
1198 tty
->winsize
.ws_row
= tty3270_tty_rows(tp
);
1199 tty
->winsize
.ws_col
= tp
->view
.cols
;
1200 rc
= tty_port_install(&tp
->port
, driver
, tty
);
1202 raw3270_put_view(&tp
->view
);
1205 tty
->driver_data
= tp
;
1210 * This routine is called whenever a 3270 tty is opened.
1212 static int tty3270_open(struct tty_struct
*tty
, struct file
*filp
)
1214 struct tty3270
*tp
= tty
->driver_data
;
1215 struct tty_port
*port
= &tp
->port
;
1218 tty_port_tty_set(port
, tty
);
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.
1226 static void tty3270_close(struct tty_struct
*tty
, struct file
*filp
)
1228 struct tty3270
*tp
= tty
->driver_data
;
1233 tty_port_tty_set(&tp
->port
, NULL
);
1236 static void tty3270_cleanup(struct tty_struct
*tty
)
1238 struct tty3270
*tp
= tty
->driver_data
;
1241 tty
->driver_data
= NULL
;
1242 raw3270_put_view(&tp
->view
);
1247 * We always have room.
1249 static unsigned int tty3270_write_room(struct tty_struct
*tty
)
1255 * Insert character into the screen at the current position with the
1256 * current color and highlight. This function does NOT do cursor movement.
1258 static void tty3270_put_character(struct tty3270
*tp
, u8 ch
)
1260 struct tty3270_line
*line
;
1261 struct tty3270_cell
*cell
;
1263 line
= tty3270_get_write_line(tp
, tp
->cy
);
1264 if (line
->len
<= tp
->cx
) {
1265 while (line
->len
< tp
->cx
) {
1266 cell
= line
->cells
+ line
->len
;
1267 cell
->character
= ' ';
1268 cell
->attributes
= tp
->attributes
;
1273 cell
= line
->cells
+ tp
->cx
;
1274 cell
->character
= ch
;
1275 cell
->attributes
= tp
->attributes
;
1280 * Do carriage return.
1282 static void tty3270_cr(struct tty3270
*tp
)
1290 static void tty3270_lf(struct tty3270
*tp
)
1292 struct tty3270_line
*line
;
1295 if (tp
->cy
< tty3270_tty_rows(tp
) - 1) {
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;
1304 line
= tty3270_get_write_line(tp
, tp
->cy
);
1309 static void tty3270_ri(struct tty3270
*tp
)
1315 static void tty3270_reset_cell(struct tty3270
*tp
, struct tty3270_cell
*cell
)
1317 cell
->character
= ' ';
1318 tty3270_reset_attributes(&cell
->attributes
);
1322 * Insert characters at current position.
1324 static void tty3270_insert_characters(struct tty3270
*tp
, int n
)
1326 struct tty3270_line
*line
;
1329 line
= tty3270_get_write_line(tp
, tp
->cy
);
1330 while (line
->len
< tp
->cx
)
1331 tty3270_reset_cell(tp
, &line
->cells
[line
->len
++]);
1332 if (n
> tp
->view
.cols
- tp
->cx
)
1333 n
= tp
->view
.cols
- tp
->cx
;
1334 k
= min_t(int, line
->len
- tp
->cx
, tp
->view
.cols
- tp
->cx
- n
);
1336 line
->cells
[tp
->cx
+ n
+ k
] = line
->cells
[tp
->cx
+ k
];
1338 if (line
->len
> tp
->view
.cols
)
1339 line
->len
= tp
->view
.cols
;
1341 line
->cells
[tp
->cx
+ n
].character
= ' ';
1342 line
->cells
[tp
->cx
+ n
].attributes
= tp
->attributes
;
1347 * Delete characters at current position.
1349 static void tty3270_delete_characters(struct tty3270
*tp
, int n
)
1351 struct tty3270_line
*line
;
1354 line
= tty3270_get_write_line(tp
, tp
->cy
);
1355 if (line
->len
<= tp
->cx
)
1357 if (line
->len
- tp
->cx
<= n
) {
1361 for (i
= tp
->cx
; i
+ n
< line
->len
; i
++)
1362 line
->cells
[i
] = line
->cells
[i
+ n
];
1367 * Erase characters at current position.
1369 static void tty3270_erase_characters(struct tty3270
*tp
, int n
)
1371 struct tty3270_line
*line
;
1372 struct tty3270_cell
*cell
;
1374 line
= tty3270_get_write_line(tp
, tp
->cy
);
1375 while (line
->len
> tp
->cx
&& n
-- > 0) {
1376 cell
= line
->cells
+ tp
->cx
++;
1377 tty3270_reset_cell(tp
, cell
);
1380 tp
->cx
= min_t(int, tp
->cx
, tp
->view
.cols
- 1);
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)
1389 static void tty3270_erase_line(struct tty3270
*tp
, int mode
)
1391 struct tty3270_line
*line
;
1392 struct tty3270_cell
*cell
;
1395 line
= tty3270_get_write_line(tp
, tp
->cy
);
1400 end
= tp
->view
.cols
;
1408 end
= tp
->view
.cols
;
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
;
1420 if (line
->len
<= end
)
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)
1430 static void tty3270_erase_display(struct tty3270
*tp
, int mode
)
1432 struct tty3270_line
*line
;
1437 tty3270_erase_line(tp
, 0);
1439 end
= tty3270_tty_rows(tp
);
1444 tty3270_erase_line(tp
, 1);
1448 end
= tty3270_tty_rows(tp
);
1453 for (i
= start
; i
< end
; i
++) {
1454 line
= tty3270_get_write_line(tp
, i
);
1461 * Set attributes found in an escape sequence.
1462 * Esc [ <attr> ; <attr> ; ... m
1464 static void tty3270_set_attributes(struct tty3270
*tp
)
1468 for (i
= 0; i
<= tp
->esc_npar
; i
++) {
1469 attr
= tp
->esc_par
[i
];
1472 tty3270_reset_attributes(&tp
->attributes
);
1475 case 4: /* Start underlining. */
1476 tp
->attributes
.highlight
= TTY3270_HIGHLIGHT_UNDERSCORE
;
1478 case 5: /* Start blink. */
1479 tp
->attributes
.highlight
= TTY3270_HIGHLIGHT_BLINK
;
1481 case 7: /* Start reverse. */
1482 tp
->attributes
.highlight
= TTY3270_HIGHLIGHT_REVERSE
;
1484 case 24: /* End underlining */
1485 tp
->attributes
.highlight
&= ~TTY3270_HIGHLIGHT_UNDERSCORE
;
1487 case 25: /* End blink. */
1488 tp
->attributes
.highlight
&= ~TTY3270_HIGHLIGHT_BLINK
;
1490 case 27: /* End reverse. */
1491 tp
->attributes
.highlight
&= ~TTY3270_HIGHLIGHT_REVERSE
;
1493 /* Foreground color. */
1494 case 30: /* Black */
1496 case 32: /* Green */
1497 case 33: /* Yellow */
1499 case 35: /* Magenta */
1501 case 37: /* White */
1502 case 39: /* Black */
1503 tp
->attributes
.f_color
= attr
- 30;
1505 /* Background color. */
1506 case 40: /* Black */
1508 case 42: /* Green */
1509 case 43: /* Yellow */
1511 case 45: /* Magenta */
1513 case 47: /* White */
1514 case 49: /* Black */
1515 tp
->attributes
.b_color
= attr
- 40;
1521 static inline int tty3270_getpar(struct tty3270
*tp
, int ix
)
1523 return (tp
->esc_par
[ix
] > 0) ? tp
->esc_par
[ix
] : 1;
1526 static void tty3270_goto_xy(struct tty3270
*tp
, int cx
, int cy
)
1528 struct tty3270_line
*line
;
1529 struct tty3270_cell
*cell
;
1530 int max_cx
= max(0, cx
);
1531 int max_cy
= max(0, cy
);
1533 tp
->cx
= min_t(int, tp
->view
.cols
- 1, max_cx
);
1534 line
= tty3270_get_write_line(tp
, tp
->cy
);
1535 while (line
->len
< tp
->cx
) {
1536 cell
= line
->cells
+ line
->len
;
1537 cell
->character
= ' ';
1538 cell
->attributes
= tp
->attributes
;
1541 tp
->cy
= min_t(int, tty3270_tty_rows(tp
) - 1, max_cy
);
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.
1561 * Pn is a numeric parameter, a string of zero or more decimal digits.
1562 * Ps is a selective parameter.
1564 static void tty3270_escape_sequence(struct tty3270
*tp
, u8 ch
)
1566 enum { ES_NORMAL
, ES_ESC
, ES_SQUARE
, ES_PAREN
, ES_GETPARS
};
1568 if (tp
->esc_state
== ES_NORMAL
) {
1570 /* Starting new escape sequence. */
1571 tp
->esc_state
= ES_ESC
;
1574 if (tp
->esc_state
== ES_ESC
) {
1575 tp
->esc_state
= ES_NORMAL
;
1578 tp
->esc_state
= ES_SQUARE
;
1581 tp
->esc_state
= ES_PAREN
;
1593 case 'Z': /* Respond ID. */
1594 kbd_puts_queue(&tp
->port
, "\033[?6c");
1596 case '7': /* Save cursor position. */
1597 tp
->saved_cx
= tp
->cx
;
1598 tp
->saved_cy
= tp
->cy
;
1599 tp
->saved_attributes
= tp
->attributes
;
1601 case '8': /* Restore cursor position. */
1602 tty3270_goto_xy(tp
, tp
->saved_cx
, tp
->saved_cy
);
1603 tp
->attributes
= tp
->saved_attributes
;
1605 case 'c': /* Reset terminal. */
1610 tty3270_reset_attributes(&tp
->attributes
);
1611 tty3270_reset_attributes(&tp
->saved_attributes
);
1612 tty3270_erase_display(tp
, 2);
1618 switch (tp
->esc_state
) {
1620 tp
->esc_state
= ES_NORMAL
;
1623 tp
->attributes
.alternate_charset
= 0;
1626 tp
->attributes
.alternate_charset
= 1;
1631 tp
->esc_state
= ES_GETPARS
;
1632 memset(tp
->esc_par
, 0, sizeof(tp
->esc_par
));
1634 tp
->esc_ques
= (ch
== '?');
1639 if (ch
== ';' && tp
->esc_npar
< ESCAPE_NPAR
- 1) {
1643 if (ch
>= '0' && ch
<= '9') {
1644 tp
->esc_par
[tp
->esc_npar
] *= 10;
1645 tp
->esc_par
[tp
->esc_npar
] += ch
- '0';
1652 tp
->esc_state
= ES_NORMAL
;
1653 if (ch
== 'n' && !tp
->esc_ques
) {
1654 if (tp
->esc_par
[0] == 5) /* Status report. */
1655 kbd_puts_queue(&tp
->port
, "\033[0n");
1656 else if (tp
->esc_par
[0] == 6) { /* Cursor report. */
1659 sprintf(buf
, "\033[%d;%dR", tp
->cy
+ 1, tp
->cx
+ 1);
1660 kbd_puts_queue(&tp
->port
, buf
);
1668 tty3270_set_attributes(tp
);
1670 case 'H': /* Set cursor position. */
1672 tty3270_goto_xy(tp
, tty3270_getpar(tp
, 1) - 1,
1673 tty3270_getpar(tp
, 0) - 1);
1675 case 'd': /* Set y position. */
1676 tty3270_goto_xy(tp
, tp
->cx
, tty3270_getpar(tp
, 0) - 1);
1678 case 'A': /* Cursor up. */
1680 tty3270_goto_xy(tp
, tp
->cx
, tp
->cy
- tty3270_getpar(tp
, 0));
1682 case 'B': /* Cursor down. */
1685 tty3270_goto_xy(tp
, tp
->cx
, tp
->cy
+ tty3270_getpar(tp
, 0));
1687 case 'C': /* Cursor forward. */
1689 tty3270_goto_xy(tp
, tp
->cx
+ tty3270_getpar(tp
, 0), tp
->cy
);
1691 case 'D': /* Cursor backward. */
1692 tty3270_goto_xy(tp
, tp
->cx
- tty3270_getpar(tp
, 0), tp
->cy
);
1694 case 'G': /* Set x position. */
1696 tty3270_goto_xy(tp
, tty3270_getpar(tp
, 0), tp
->cy
);
1698 case 'X': /* Erase Characters. */
1699 tty3270_erase_characters(tp
, tty3270_getpar(tp
, 0));
1701 case 'J': /* Erase display. */
1702 tty3270_erase_display(tp
, tp
->esc_par
[0]);
1704 case 'K': /* Erase line. */
1705 tty3270_erase_line(tp
, tp
->esc_par
[0]);
1707 case 'P': /* Delete characters. */
1708 tty3270_delete_characters(tp
, tty3270_getpar(tp
, 0));
1710 case '@': /* Insert characters. */
1711 tty3270_insert_characters(tp
, tty3270_getpar(tp
, 0));
1713 case 's': /* Save cursor position. */
1714 tp
->saved_cx
= tp
->cx
;
1715 tp
->saved_cy
= tp
->cy
;
1716 tp
->saved_attributes
= tp
->attributes
;
1718 case 'u': /* Restore cursor position. */
1719 tty3270_goto_xy(tp
, tp
->saved_cx
, tp
->saved_cy
);
1720 tp
->attributes
= tp
->saved_attributes
;
1726 * String write routine for 3270 ttys
1728 static void tty3270_do_write(struct tty3270
*tp
, struct tty_struct
*tty
,
1729 const u8
*buf
, size_t count
)
1733 spin_lock_irq(&tp
->view
.lock
);
1734 for (i_msg
= 0; !tty
->flow
.stopped
&& i_msg
< count
; i_msg
++) {
1735 if (tp
->esc_state
!= 0) {
1736 /* Continue escape sequence. */
1737 tty3270_escape_sequence(tp
, buf
[i_msg
]);
1741 switch (buf
[i_msg
]) {
1744 case 0x07: /* '\a' -- Alarm */
1745 tp
->wcc
|= TW_PLUSALARM
;
1747 case 0x08: /* Backspace. */
1750 tty3270_put_character(tp
, ' ');
1753 case 0x09: /* '\t' -- Tabulate */
1754 for (i
= tp
->cx
% 8; i
< 8; i
++) {
1755 if (tp
->cx
>= tp
->view
.cols
) {
1760 tty3270_put_character(tp
, ' ');
1764 case 0x0a: /* '\n' -- New Line */
1768 case 0x0c: /* '\f' -- Form Feed */
1769 tty3270_erase_display(tp
, 2);
1773 case 0x0d: /* '\r' -- Carriage Return */
1777 tp
->attributes
.alternate_charset
= 1;
1779 case 0x0f: /* SuSE "exit alternate mode" */
1780 tp
->attributes
.alternate_charset
= 0;
1782 case 0x1b: /* Start escape sequence. */
1783 tty3270_escape_sequence(tp
, buf
[i_msg
]);
1785 default: /* Insert normal character. */
1786 if (tp
->cx
>= tp
->view
.cols
) {
1790 tty3270_put_character(tp
, buf
[i_msg
]);
1795 /* Setup timer to update display after 1/10 second */
1796 tp
->update_flags
|= TTY_UPDATE_LINES
;
1797 if (!timer_pending(&tp
->timer
))
1798 tty3270_set_timer(tp
, msecs_to_jiffies(100));
1800 spin_unlock_irq(&tp
->view
.lock
);
1804 * String write routine for 3270 ttys
1806 static ssize_t
tty3270_write(struct tty_struct
*tty
, const u8
*buf
,
1811 tp
= tty
->driver_data
;
1814 if (tp
->char_count
> 0) {
1815 tty3270_do_write(tp
, tty
, tp
->char_buf
, tp
->char_count
);
1818 tty3270_do_write(tp
, tty
, buf
, count
);
1823 * Put single characters to the ttys character buffer
1825 static int tty3270_put_char(struct tty_struct
*tty
, u8 ch
)
1829 tp
= tty
->driver_data
;
1830 if (!tp
|| tp
->char_count
>= TTY3270_CHAR_BUF_SIZE
)
1832 tp
->char_buf
[tp
->char_count
++] = ch
;
1837 * Flush all characters from the ttys characeter buffer put there
1838 * by tty3270_put_char.
1840 static void tty3270_flush_chars(struct tty_struct
*tty
)
1844 tp
= tty
->driver_data
;
1847 if (tp
->char_count
> 0) {
1848 tty3270_do_write(tp
, tty
, tp
->char_buf
, tp
->char_count
);
1854 * Check for visible/invisible input switches
1856 static void tty3270_set_termios(struct tty_struct
*tty
, const struct ktermios
*old
)
1861 tp
= tty
->driver_data
;
1864 spin_lock_irq(&tp
->view
.lock
);
1865 if (L_ICANON(tty
)) {
1866 new = L_ECHO(tty
) ? TF_INPUT
: TF_INPUTN
;
1867 if (new != tp
->inattr
) {
1869 tty3270_update_prompt(tp
, "");
1870 tty3270_set_timer(tp
, 1);
1873 spin_unlock_irq(&tp
->view
.lock
);
1877 * Disable reading from a 3270 tty
1879 static void tty3270_throttle(struct tty_struct
*tty
)
1883 tp
= tty
->driver_data
;
1890 * Enable reading from a 3270 tty
1892 static void tty3270_unthrottle(struct tty_struct
*tty
)
1896 tp
= tty
->driver_data
;
1901 tty3270_issue_read(tp
, 1);
1905 * Hang up the tty device.
1907 static void tty3270_hangup(struct tty_struct
*tty
)
1911 tp
= tty
->driver_data
;
1914 spin_lock_irq(&tp
->view
.lock
);
1919 tty3270_reset_attributes(&tp
->attributes
);
1920 tty3270_reset_attributes(&tp
->saved_attributes
);
1921 tty3270_blank_screen(tp
);
1922 tp
->update_flags
= TTY_UPDATE_ALL
;
1923 spin_unlock_irq(&tp
->view
.lock
);
1924 tty3270_set_timer(tp
, 1);
1927 static void tty3270_wait_until_sent(struct tty_struct
*tty
, int timeout
)
1931 static int tty3270_ioctl(struct tty_struct
*tty
, unsigned int cmd
,
1936 tp
= tty
->driver_data
;
1939 if (tty_io_error(tty
))
1941 return kbd_ioctl(tp
->kbd
, cmd
, arg
);
1944 #ifdef CONFIG_COMPAT
1945 static long tty3270_compat_ioctl(struct tty_struct
*tty
,
1946 unsigned int cmd
, unsigned long arg
)
1950 tp
= tty
->driver_data
;
1953 if (tty_io_error(tty
))
1955 return kbd_ioctl(tp
->kbd
, cmd
, (unsigned long)compat_ptr(arg
));
1959 static const struct tty_operations tty3270_ops
= {
1960 .install
= tty3270_install
,
1961 .cleanup
= tty3270_cleanup
,
1962 .open
= tty3270_open
,
1963 .close
= tty3270_close
,
1964 .write
= tty3270_write
,
1965 .put_char
= tty3270_put_char
,
1966 .flush_chars
= tty3270_flush_chars
,
1967 .write_room
= tty3270_write_room
,
1968 .throttle
= tty3270_throttle
,
1969 .unthrottle
= tty3270_unthrottle
,
1970 .hangup
= tty3270_hangup
,
1971 .wait_until_sent
= tty3270_wait_until_sent
,
1972 .ioctl
= tty3270_ioctl
,
1973 #ifdef CONFIG_COMPAT
1974 .compat_ioctl
= tty3270_compat_ioctl
,
1976 .set_termios
= tty3270_set_termios
1979 static void tty3270_create_cb(int minor
)
1981 tty_register_device(tty3270_driver
, minor
- RAW3270_FIRSTMINOR
, NULL
);
1984 static void tty3270_destroy_cb(int minor
)
1986 tty_unregister_device(tty3270_driver
, minor
- RAW3270_FIRSTMINOR
);
1989 static struct raw3270_notifier tty3270_notifier
= {
1990 .create
= tty3270_create_cb
,
1991 .destroy
= tty3270_destroy_cb
,
1995 * 3270 tty registration code called from tty_init().
1996 * Most kernel services (incl. kmalloc) are available at this poimt.
1998 static int __init
tty3270_init(void)
2000 struct tty_driver
*driver
;
2003 driver
= tty_alloc_driver(RAW3270_MAXDEVS
,
2004 TTY_DRIVER_REAL_RAW
|
2005 TTY_DRIVER_DYNAMIC_DEV
|
2006 TTY_DRIVER_RESET_TERMIOS
);
2008 return PTR_ERR(driver
);
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
2015 driver
->driver_name
= "tty3270";
2016 driver
->name
= "3270/tty";
2017 driver
->major
= IBM_TTY3270_MAJOR
;
2018 driver
->minor_start
= RAW3270_FIRSTMINOR
;
2019 driver
->name_base
= RAW3270_FIRSTMINOR
;
2020 driver
->type
= TTY_DRIVER_TYPE_SYSTEM
;
2021 driver
->subtype
= SYSTEM_TYPE_TTY
;
2022 driver
->init_termios
= tty_std_termios
;
2023 tty_set_operations(driver
, &tty3270_ops
);
2024 ret
= tty_register_driver(driver
);
2026 tty_driver_kref_put(driver
);
2029 tty3270_driver
= driver
;
2030 raw3270_register_notifier(&tty3270_notifier
);
2034 static void __exit
tty3270_exit(void)
2036 struct tty_driver
*driver
;
2038 raw3270_unregister_notifier(&tty3270_notifier
);
2039 driver
= tty3270_driver
;
2040 tty3270_driver
= NULL
;
2041 tty_unregister_driver(driver
);
2042 tty_driver_kref_put(driver
);
2043 tty3270_del_views();
2046 #if IS_ENABLED(CONFIG_TN3270_CONSOLE)
2048 static struct tty3270
*condev
;
2051 con3270_write(struct console
*co
, const char *str
, unsigned int count
)
2053 struct tty3270
*tp
= co
->data
;
2054 unsigned long flags
;
2057 spin_lock_irqsave(&tp
->view
.lock
, flags
);
2064 if (tp
->cx
>= tp
->view
.cols
) {
2068 tty3270_put_character(tp
, c
);
2072 spin_unlock_irqrestore(&tp
->view
.lock
, flags
);
2075 static struct tty_driver
*
2076 con3270_device(struct console
*c
, int *index
)
2079 return tty3270_driver
;
2083 con3270_wait_write(struct tty3270
*tp
)
2085 while (!tp
->write
) {
2086 raw3270_wait_cons_dev(tp
->view
.dev
);
2092 * The below function is called as a panic/reboot notifier before the
2093 * system enters a disabled, endless loop.
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).
2099 static int con3270_notify(struct notifier_block
*self
,
2100 unsigned long event
, void *data
)
2103 unsigned long flags
;
2109 if (!raw3270_view_lock_unavailable(&tp
->view
)) {
2110 rc
= raw3270_activate_view(&tp
->view
);
2114 if (!spin_trylock_irqsave(&tp
->view
.lock
, flags
))
2116 con3270_wait_write(tp
);
2118 tp
->update_flags
= TTY_UPDATE_ALL
;
2119 while (tp
->update_flags
!= 0) {
2120 spin_unlock_irqrestore(&tp
->view
.lock
, flags
);
2121 tty3270_update(&tp
->timer
);
2122 spin_lock_irqsave(&tp
->view
.lock
, flags
);
2123 con3270_wait_write(tp
);
2125 spin_unlock_irqrestore(&tp
->view
.lock
, flags
);
2129 static struct notifier_block on_panic_nb
= {
2130 .notifier_call
= con3270_notify
,
2131 .priority
= INT_MIN
+ 1, /* run the callback late */
2134 static struct notifier_block on_reboot_nb
= {
2135 .notifier_call
= con3270_notify
,
2136 .priority
= INT_MIN
+ 1, /* run the callback late */
2139 static struct console con3270
= {
2141 .write
= con3270_write
,
2142 .device
= con3270_device
,
2143 .flags
= CON_PRINTBUFFER
,
2149 struct raw3270_view
*view
;
2154 /* Check if 3270 is to be the console */
2155 if (!CONSOLE_IS_3270
)
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
);
2164 rp
= raw3270_setup_console();
2168 /* Check if the tty3270 is already there. */
2169 view
= raw3270_find_view(&tty3270_fn
, RAW3270_FIRSTMINOR
);
2171 rc
= tty3270_create_view(0, &tp
);
2175 tp
= container_of(view
, struct tty3270
, view
);
2176 tp
->inattr
= TF_INPUT
;
2180 atomic_notifier_chain_register(&panic_notifier_list
, &on_panic_nb
);
2181 register_reboot_notifier(&on_reboot_nb
);
2182 register_console(&con3270
);
2185 console_initcall(con3270_init
);
2188 MODULE_DESCRIPTION("IBM/3270 Driver - tty functions");
2189 MODULE_LICENSE("GPL");
2190 MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR
);
2192 module_init(tty3270_init
);
2193 module_exit(tty3270_exit
);