18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IBM/3270 Driver - tty functions. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author(s): 68c2ecf20Sopenharmony_ci * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) 78c2ecf20Sopenharmony_ci * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> 88c2ecf20Sopenharmony_ci * -- Copyright IBM Corp. 2003 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/kdev_t.h> 148c2ecf20Sopenharmony_ci#include <linux/tty.h> 158c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/console.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/memblock.h> 238c2ecf20Sopenharmony_ci#include <linux/compat.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <asm/ccwdev.h> 268c2ecf20Sopenharmony_ci#include <asm/cio.h> 278c2ecf20Sopenharmony_ci#include <asm/ebcdic.h> 288c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "raw3270.h" 318c2ecf20Sopenharmony_ci#include "tty3270.h" 328c2ecf20Sopenharmony_ci#include "keyboard.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define TTY3270_CHAR_BUF_SIZE 256 358c2ecf20Sopenharmony_ci#define TTY3270_OUTPUT_BUFFER_SIZE 1024 368c2ecf20Sopenharmony_ci#define TTY3270_STRING_PAGES 5 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct tty_driver *tty3270_driver; 398c2ecf20Sopenharmony_cistatic int tty3270_max_index; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct raw3270_fn tty3270_fn; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct tty3270_cell { 448c2ecf20Sopenharmony_ci unsigned char character; 458c2ecf20Sopenharmony_ci unsigned char highlight; 468c2ecf20Sopenharmony_ci unsigned char f_color; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct tty3270_line { 508c2ecf20Sopenharmony_ci struct tty3270_cell *cells; 518c2ecf20Sopenharmony_ci int len; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define ESCAPE_NPAR 8 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * The main tty view data structure. 588c2ecf20Sopenharmony_ci * FIXME: 598c2ecf20Sopenharmony_ci * 1) describe line orientation & lines list concept against screen 608c2ecf20Sopenharmony_ci * 2) describe conversion of screen to lines 618c2ecf20Sopenharmony_ci * 3) describe line format. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistruct tty3270 { 648c2ecf20Sopenharmony_ci struct raw3270_view view; 658c2ecf20Sopenharmony_ci struct tty_port port; 668c2ecf20Sopenharmony_ci void **freemem_pages; /* Array of pages used for freemem. */ 678c2ecf20Sopenharmony_ci struct list_head freemem; /* List of free memory for strings. */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Output stuff. */ 708c2ecf20Sopenharmony_ci struct list_head lines; /* List of lines. */ 718c2ecf20Sopenharmony_ci struct list_head update; /* List of lines to update. */ 728c2ecf20Sopenharmony_ci unsigned char wcc; /* Write control character. */ 738c2ecf20Sopenharmony_ci int nr_lines; /* # lines in list. */ 748c2ecf20Sopenharmony_ci int nr_up; /* # lines up in history. */ 758c2ecf20Sopenharmony_ci unsigned long update_flags; /* Update indication bits. */ 768c2ecf20Sopenharmony_ci struct string *status; /* Lower right of display. */ 778c2ecf20Sopenharmony_ci struct raw3270_request *write; /* Single write request. */ 788c2ecf20Sopenharmony_ci struct timer_list timer; /* Output delay timer. */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Current tty screen. */ 818c2ecf20Sopenharmony_ci unsigned int cx, cy; /* Current output position. */ 828c2ecf20Sopenharmony_ci unsigned int highlight; /* Blink/reverse/underscore */ 838c2ecf20Sopenharmony_ci unsigned int f_color; /* Foreground color */ 848c2ecf20Sopenharmony_ci struct tty3270_line *screen; 858c2ecf20Sopenharmony_ci unsigned int n_model, n_cols, n_rows; /* New model & size */ 868c2ecf20Sopenharmony_ci struct work_struct resize_work; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Input stuff. */ 898c2ecf20Sopenharmony_ci struct string *prompt; /* Output string for input area. */ 908c2ecf20Sopenharmony_ci struct string *input; /* Input string for read request. */ 918c2ecf20Sopenharmony_ci struct raw3270_request *read; /* Single read request. */ 928c2ecf20Sopenharmony_ci struct raw3270_request *kreset; /* Single keyboard reset request. */ 938c2ecf20Sopenharmony_ci unsigned char inattr; /* Visible/invisible input. */ 948c2ecf20Sopenharmony_ci int throttle, attn; /* tty throttle/unthrottle. */ 958c2ecf20Sopenharmony_ci struct tasklet_struct readlet; /* Tasklet to issue read request. */ 968c2ecf20Sopenharmony_ci struct tasklet_struct hanglet; /* Tasklet to hang up the tty. */ 978c2ecf20Sopenharmony_ci struct kbd_data *kbd; /* key_maps stuff. */ 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Escape sequence parsing. */ 1008c2ecf20Sopenharmony_ci int esc_state, esc_ques, esc_npar; 1018c2ecf20Sopenharmony_ci int esc_par[ESCAPE_NPAR]; 1028c2ecf20Sopenharmony_ci unsigned int saved_cx, saved_cy; 1038c2ecf20Sopenharmony_ci unsigned int saved_highlight, saved_f_color; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Command recalling. */ 1068c2ecf20Sopenharmony_ci struct list_head rcl_lines; /* List of recallable lines. */ 1078c2ecf20Sopenharmony_ci struct list_head *rcl_walk; /* Point in rcl_lines list. */ 1088c2ecf20Sopenharmony_ci int rcl_nr, rcl_max; /* Number/max number of rcl_lines. */ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Character array for put_char/flush_chars. */ 1118c2ecf20Sopenharmony_ci unsigned int char_count; 1128c2ecf20Sopenharmony_ci char char_buf[TTY3270_CHAR_BUF_SIZE]; 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* tty3270->update_flags. See tty3270_update for details. */ 1168c2ecf20Sopenharmony_ci#define TTY_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */ 1178c2ecf20Sopenharmony_ci#define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */ 1188c2ecf20Sopenharmony_ci#define TTY_UPDATE_INPUT 4 /* Update input line. */ 1198c2ecf20Sopenharmony_ci#define TTY_UPDATE_STATUS 8 /* Update status line. */ 1208c2ecf20Sopenharmony_ci#define TTY_UPDATE_ALL 16 /* Recreate screen. */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void tty3270_update(struct timer_list *); 1238c2ecf20Sopenharmony_cistatic void tty3270_resize_work(struct work_struct *work); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* 1268c2ecf20Sopenharmony_ci * Setup timeout for a device. On timeout trigger an update. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_cistatic void tty3270_set_timer(struct tty3270 *tp, int expires) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci mod_timer(&tp->timer, jiffies + expires); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * The input line are the two last lines of the screen. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cistatic void 1378c2ecf20Sopenharmony_citty3270_update_prompt(struct tty3270 *tp, char *input, int count) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct string *line; 1408c2ecf20Sopenharmony_ci unsigned int off; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci line = tp->prompt; 1438c2ecf20Sopenharmony_ci if (count != 0) 1448c2ecf20Sopenharmony_ci line->string[5] = TF_INMDT; 1458c2ecf20Sopenharmony_ci else 1468c2ecf20Sopenharmony_ci line->string[5] = tp->inattr; 1478c2ecf20Sopenharmony_ci if (count > tp->view.cols * 2 - 11) 1488c2ecf20Sopenharmony_ci count = tp->view.cols * 2 - 11; 1498c2ecf20Sopenharmony_ci memcpy(line->string + 6, input, count); 1508c2ecf20Sopenharmony_ci line->string[6 + count] = TO_IC; 1518c2ecf20Sopenharmony_ci /* Clear to end of input line. */ 1528c2ecf20Sopenharmony_ci if (count < tp->view.cols * 2 - 11) { 1538c2ecf20Sopenharmony_ci line->string[7 + count] = TO_RA; 1548c2ecf20Sopenharmony_ci line->string[10 + count] = 0; 1558c2ecf20Sopenharmony_ci off = tp->view.cols * tp->view.rows - 9; 1568c2ecf20Sopenharmony_ci raw3270_buffer_address(tp->view.dev, line->string+count+8, off); 1578c2ecf20Sopenharmony_ci line->len = 11 + count; 1588c2ecf20Sopenharmony_ci } else 1598c2ecf20Sopenharmony_ci line->len = 7 + count; 1608c2ecf20Sopenharmony_ci tp->update_flags |= TTY_UPDATE_INPUT; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void 1648c2ecf20Sopenharmony_citty3270_create_prompt(struct tty3270 *tp) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci static const unsigned char blueprint[] = 1678c2ecf20Sopenharmony_ci { TO_SBA, 0, 0, 0x6e, TO_SF, TF_INPUT, 1688c2ecf20Sopenharmony_ci /* empty input string */ 1698c2ecf20Sopenharmony_ci TO_IC, TO_RA, 0, 0, 0 }; 1708c2ecf20Sopenharmony_ci struct string *line; 1718c2ecf20Sopenharmony_ci unsigned int offset; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci line = alloc_string(&tp->freemem, 1748c2ecf20Sopenharmony_ci sizeof(blueprint) + tp->view.cols * 2 - 9); 1758c2ecf20Sopenharmony_ci tp->prompt = line; 1768c2ecf20Sopenharmony_ci tp->inattr = TF_INPUT; 1778c2ecf20Sopenharmony_ci /* Copy blueprint to status line */ 1788c2ecf20Sopenharmony_ci memcpy(line->string, blueprint, sizeof(blueprint)); 1798c2ecf20Sopenharmony_ci line->len = sizeof(blueprint); 1808c2ecf20Sopenharmony_ci /* Set output offsets. */ 1818c2ecf20Sopenharmony_ci offset = tp->view.cols * (tp->view.rows - 2); 1828c2ecf20Sopenharmony_ci raw3270_buffer_address(tp->view.dev, line->string + 1, offset); 1838c2ecf20Sopenharmony_ci offset = tp->view.cols * tp->view.rows - 9; 1848c2ecf20Sopenharmony_ci raw3270_buffer_address(tp->view.dev, line->string + 8, offset); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Allocate input string for reading. */ 1878c2ecf20Sopenharmony_ci tp->input = alloc_string(&tp->freemem, tp->view.cols * 2 - 9 + 6); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * The status line is the last line of the screen. It shows the string 1928c2ecf20Sopenharmony_ci * "Running"/"Holding" in the lower right corner of the screen. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_cistatic void 1958c2ecf20Sopenharmony_citty3270_update_status(struct tty3270 * tp) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci char *str; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci str = (tp->nr_up != 0) ? "History" : "Running"; 2008c2ecf20Sopenharmony_ci memcpy(tp->status->string + 8, str, 7); 2018c2ecf20Sopenharmony_ci codepage_convert(tp->view.ascebc, tp->status->string + 8, 7); 2028c2ecf20Sopenharmony_ci tp->update_flags |= TTY_UPDATE_STATUS; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void 2068c2ecf20Sopenharmony_citty3270_create_status(struct tty3270 * tp) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci static const unsigned char blueprint[] = 2098c2ecf20Sopenharmony_ci { TO_SBA, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR, TAC_GREEN, 2108c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR, 2118c2ecf20Sopenharmony_ci TAC_RESET }; 2128c2ecf20Sopenharmony_ci struct string *line; 2138c2ecf20Sopenharmony_ci unsigned int offset; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci line = alloc_string(&tp->freemem,sizeof(blueprint)); 2168c2ecf20Sopenharmony_ci tp->status = line; 2178c2ecf20Sopenharmony_ci /* Copy blueprint to status line */ 2188c2ecf20Sopenharmony_ci memcpy(line->string, blueprint, sizeof(blueprint)); 2198c2ecf20Sopenharmony_ci /* Set address to start of status string (= last 9 characters). */ 2208c2ecf20Sopenharmony_ci offset = tp->view.cols * tp->view.rows - 9; 2218c2ecf20Sopenharmony_ci raw3270_buffer_address(tp->view.dev, line->string + 1, offset); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * Set output offsets to 3270 datastream fragment of a tty string. 2268c2ecf20Sopenharmony_ci * (TO_SBA offset at the start and TO_RA offset at the end of the string) 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic void 2298c2ecf20Sopenharmony_citty3270_update_string(struct tty3270 *tp, struct string *line, int nr) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci unsigned char *cp; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci raw3270_buffer_address(tp->view.dev, line->string + 1, 2348c2ecf20Sopenharmony_ci tp->view.cols * nr); 2358c2ecf20Sopenharmony_ci cp = line->string + line->len - 4; 2368c2ecf20Sopenharmony_ci if (*cp == TO_RA) 2378c2ecf20Sopenharmony_ci raw3270_buffer_address(tp->view.dev, cp + 1, 2388c2ecf20Sopenharmony_ci tp->view.cols * (nr + 1)); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* 2428c2ecf20Sopenharmony_ci * Rebuild update list to print all lines. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic void 2458c2ecf20Sopenharmony_citty3270_rebuild_update(struct tty3270 *tp) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct string *s, *n; 2488c2ecf20Sopenharmony_ci int line, nr_up; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* 2518c2ecf20Sopenharmony_ci * Throw away update list and create a new one, 2528c2ecf20Sopenharmony_ci * containing all lines that will fit on the screen. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci list_for_each_entry_safe(s, n, &tp->update, update) 2558c2ecf20Sopenharmony_ci list_del_init(&s->update); 2568c2ecf20Sopenharmony_ci line = tp->view.rows - 3; 2578c2ecf20Sopenharmony_ci nr_up = tp->nr_up; 2588c2ecf20Sopenharmony_ci list_for_each_entry_reverse(s, &tp->lines, list) { 2598c2ecf20Sopenharmony_ci if (nr_up > 0) { 2608c2ecf20Sopenharmony_ci nr_up--; 2618c2ecf20Sopenharmony_ci continue; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci tty3270_update_string(tp, s, line); 2648c2ecf20Sopenharmony_ci list_add(&s->update, &tp->update); 2658c2ecf20Sopenharmony_ci if (--line < 0) 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci tp->update_flags |= TTY_UPDATE_LIST; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* 2728c2ecf20Sopenharmony_ci * Alloc string for size bytes. If there is not enough room in 2738c2ecf20Sopenharmony_ci * freemem, free strings until there is room. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_cistatic struct string * 2768c2ecf20Sopenharmony_citty3270_alloc_string(struct tty3270 *tp, size_t size) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct string *s, *n; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci s = alloc_string(&tp->freemem, size); 2818c2ecf20Sopenharmony_ci if (s) 2828c2ecf20Sopenharmony_ci return s; 2838c2ecf20Sopenharmony_ci list_for_each_entry_safe(s, n, &tp->lines, list) { 2848c2ecf20Sopenharmony_ci BUG_ON(tp->nr_lines <= tp->view.rows - 2); 2858c2ecf20Sopenharmony_ci list_del(&s->list); 2868c2ecf20Sopenharmony_ci if (!list_empty(&s->update)) 2878c2ecf20Sopenharmony_ci list_del(&s->update); 2888c2ecf20Sopenharmony_ci tp->nr_lines--; 2898c2ecf20Sopenharmony_ci if (free_string(&tp->freemem, s) >= size) 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci s = alloc_string(&tp->freemem, size); 2938c2ecf20Sopenharmony_ci BUG_ON(!s); 2948c2ecf20Sopenharmony_ci if (tp->nr_up != 0 && 2958c2ecf20Sopenharmony_ci tp->nr_up + tp->view.rows - 2 >= tp->nr_lines) { 2968c2ecf20Sopenharmony_ci tp->nr_up = tp->nr_lines - tp->view.rows + 2; 2978c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 2988c2ecf20Sopenharmony_ci tty3270_update_status(tp); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci return s; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci * Add an empty line to the list. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistatic void 3078c2ecf20Sopenharmony_citty3270_blank_line(struct tty3270 *tp) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci static const unsigned char blueprint[] = 3108c2ecf20Sopenharmony_ci { TO_SBA, 0, 0, TO_SA, TAT_EXTHI, TAX_RESET, 3118c2ecf20Sopenharmony_ci TO_SA, TAT_COLOR, TAC_RESET, TO_RA, 0, 0, 0 }; 3128c2ecf20Sopenharmony_ci struct string *s; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci s = tty3270_alloc_string(tp, sizeof(blueprint)); 3158c2ecf20Sopenharmony_ci memcpy(s->string, blueprint, sizeof(blueprint)); 3168c2ecf20Sopenharmony_ci s->len = sizeof(blueprint); 3178c2ecf20Sopenharmony_ci list_add_tail(&s->list, &tp->lines); 3188c2ecf20Sopenharmony_ci tp->nr_lines++; 3198c2ecf20Sopenharmony_ci if (tp->nr_up != 0) 3208c2ecf20Sopenharmony_ci tp->nr_up++; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* 3248c2ecf20Sopenharmony_ci * Create a blank screen and remove all lines from the history. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic void 3278c2ecf20Sopenharmony_citty3270_blank_screen(struct tty3270 *tp) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct string *s, *n; 3308c2ecf20Sopenharmony_ci int i; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci for (i = 0; i < tp->view.rows - 2; i++) 3338c2ecf20Sopenharmony_ci tp->screen[i].len = 0; 3348c2ecf20Sopenharmony_ci tp->nr_up = 0; 3358c2ecf20Sopenharmony_ci list_for_each_entry_safe(s, n, &tp->lines, list) { 3368c2ecf20Sopenharmony_ci list_del(&s->list); 3378c2ecf20Sopenharmony_ci if (!list_empty(&s->update)) 3388c2ecf20Sopenharmony_ci list_del(&s->update); 3398c2ecf20Sopenharmony_ci tp->nr_lines--; 3408c2ecf20Sopenharmony_ci free_string(&tp->freemem, s); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* 3458c2ecf20Sopenharmony_ci * Write request completion callback. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_cistatic void 3488c2ecf20Sopenharmony_citty3270_write_callback(struct raw3270_request *rq, void *data) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(rq->view, struct tty3270, view); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (rq->rc != 0) { 3538c2ecf20Sopenharmony_ci /* Write wasn't successful. Refresh all. */ 3548c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ALL; 3558c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci raw3270_request_reset(rq); 3588c2ecf20Sopenharmony_ci xchg(&tp->write, rq); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/* 3628c2ecf20Sopenharmony_ci * Update 3270 display. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic void 3658c2ecf20Sopenharmony_citty3270_update(struct timer_list *t) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct tty3270 *tp = from_timer(tp, t, timer); 3688c2ecf20Sopenharmony_ci static char invalid_sba[2] = { 0xff, 0xff }; 3698c2ecf20Sopenharmony_ci struct raw3270_request *wrq; 3708c2ecf20Sopenharmony_ci unsigned long updated; 3718c2ecf20Sopenharmony_ci struct string *s, *n; 3728c2ecf20Sopenharmony_ci char *sba, *str; 3738c2ecf20Sopenharmony_ci int rc, len; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci wrq = xchg(&tp->write, 0); 3768c2ecf20Sopenharmony_ci if (!wrq) { 3778c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 3788c2ecf20Sopenharmony_ci return; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci spin_lock(&tp->view.lock); 3828c2ecf20Sopenharmony_ci updated = 0; 3838c2ecf20Sopenharmony_ci if (tp->update_flags & TTY_UPDATE_ALL) { 3848c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 3858c2ecf20Sopenharmony_ci tty3270_update_status(tp); 3868c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST | 3878c2ecf20Sopenharmony_ci TTY_UPDATE_INPUT | TTY_UPDATE_STATUS; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci if (tp->update_flags & TTY_UPDATE_ERASE) { 3908c2ecf20Sopenharmony_ci /* Use erase write alternate to erase display. */ 3918c2ecf20Sopenharmony_ci raw3270_request_set_cmd(wrq, TC_EWRITEA); 3928c2ecf20Sopenharmony_ci updated |= TTY_UPDATE_ERASE; 3938c2ecf20Sopenharmony_ci } else 3948c2ecf20Sopenharmony_ci raw3270_request_set_cmd(wrq, TC_WRITE); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci raw3270_request_add_data(wrq, &tp->wcc, 1); 3978c2ecf20Sopenharmony_ci tp->wcc = TW_NONE; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * Update status line. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci if (tp->update_flags & TTY_UPDATE_STATUS) 4038c2ecf20Sopenharmony_ci if (raw3270_request_add_data(wrq, tp->status->string, 4048c2ecf20Sopenharmony_ci tp->status->len) == 0) 4058c2ecf20Sopenharmony_ci updated |= TTY_UPDATE_STATUS; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * Write input line. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci if (tp->update_flags & TTY_UPDATE_INPUT) 4118c2ecf20Sopenharmony_ci if (raw3270_request_add_data(wrq, tp->prompt->string, 4128c2ecf20Sopenharmony_ci tp->prompt->len) == 0) 4138c2ecf20Sopenharmony_ci updated |= TTY_UPDATE_INPUT; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci sba = invalid_sba; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (tp->update_flags & TTY_UPDATE_LIST) { 4188c2ecf20Sopenharmony_ci /* Write strings in the update list to the screen. */ 4198c2ecf20Sopenharmony_ci list_for_each_entry_safe(s, n, &tp->update, update) { 4208c2ecf20Sopenharmony_ci str = s->string; 4218c2ecf20Sopenharmony_ci len = s->len; 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * Skip TO_SBA at the start of the string if the 4248c2ecf20Sopenharmony_ci * last output position matches the start address 4258c2ecf20Sopenharmony_ci * of this line. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci if (s->string[1] == sba[0] && s->string[2] == sba[1]) 4288c2ecf20Sopenharmony_ci str += 3, len -= 3; 4298c2ecf20Sopenharmony_ci if (raw3270_request_add_data(wrq, str, len) != 0) 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci list_del_init(&s->update); 4328c2ecf20Sopenharmony_ci if (s->string[s->len - 4] == TO_RA) 4338c2ecf20Sopenharmony_ci sba = s->string + s->len - 3; 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci sba = invalid_sba; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci if (list_empty(&tp->update)) 4388c2ecf20Sopenharmony_ci updated |= TTY_UPDATE_LIST; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci wrq->callback = tty3270_write_callback; 4418c2ecf20Sopenharmony_ci rc = raw3270_start(&tp->view, wrq); 4428c2ecf20Sopenharmony_ci if (rc == 0) { 4438c2ecf20Sopenharmony_ci tp->update_flags &= ~updated; 4448c2ecf20Sopenharmony_ci if (tp->update_flags) 4458c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci raw3270_request_reset(wrq); 4488c2ecf20Sopenharmony_ci xchg(&tp->write, wrq); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci spin_unlock(&tp->view.lock); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* 4548c2ecf20Sopenharmony_ci * Command recalling. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_cistatic void 4578c2ecf20Sopenharmony_citty3270_rcl_add(struct tty3270 *tp, char *input, int len) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct string *s; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci tp->rcl_walk = NULL; 4628c2ecf20Sopenharmony_ci if (len <= 0) 4638c2ecf20Sopenharmony_ci return; 4648c2ecf20Sopenharmony_ci if (tp->rcl_nr >= tp->rcl_max) { 4658c2ecf20Sopenharmony_ci s = list_entry(tp->rcl_lines.next, struct string, list); 4668c2ecf20Sopenharmony_ci list_del(&s->list); 4678c2ecf20Sopenharmony_ci free_string(&tp->freemem, s); 4688c2ecf20Sopenharmony_ci tp->rcl_nr--; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci s = tty3270_alloc_string(tp, len); 4718c2ecf20Sopenharmony_ci memcpy(s->string, input, len); 4728c2ecf20Sopenharmony_ci list_add_tail(&s->list, &tp->rcl_lines); 4738c2ecf20Sopenharmony_ci tp->rcl_nr++; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void 4778c2ecf20Sopenharmony_citty3270_rcl_backward(struct kbd_data *kbd) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); 4808c2ecf20Sopenharmony_ci struct string *s; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 4838c2ecf20Sopenharmony_ci if (tp->inattr == TF_INPUT) { 4848c2ecf20Sopenharmony_ci if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines) 4858c2ecf20Sopenharmony_ci tp->rcl_walk = tp->rcl_walk->prev; 4868c2ecf20Sopenharmony_ci else if (!list_empty(&tp->rcl_lines)) 4878c2ecf20Sopenharmony_ci tp->rcl_walk = tp->rcl_lines.prev; 4888c2ecf20Sopenharmony_ci s = tp->rcl_walk ? 4898c2ecf20Sopenharmony_ci list_entry(tp->rcl_walk, struct string, list) : NULL; 4908c2ecf20Sopenharmony_ci if (tp->rcl_walk) { 4918c2ecf20Sopenharmony_ci s = list_entry(tp->rcl_walk, struct string, list); 4928c2ecf20Sopenharmony_ci tty3270_update_prompt(tp, s->string, s->len); 4938c2ecf20Sopenharmony_ci } else 4948c2ecf20Sopenharmony_ci tty3270_update_prompt(tp, NULL, 0); 4958c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/* 5018c2ecf20Sopenharmony_ci * Deactivate tty view. 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_cistatic void 5048c2ecf20Sopenharmony_citty3270_exit_tty(struct kbd_data *kbd) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci raw3270_deactivate_view(&tp->view); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci/* 5128c2ecf20Sopenharmony_ci * Scroll forward in history. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistatic void 5158c2ecf20Sopenharmony_citty3270_scroll_forward(struct kbd_data *kbd) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); 5188c2ecf20Sopenharmony_ci int nr_up; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 5218c2ecf20Sopenharmony_ci nr_up = tp->nr_up - tp->view.rows + 2; 5228c2ecf20Sopenharmony_ci if (nr_up < 0) 5238c2ecf20Sopenharmony_ci nr_up = 0; 5248c2ecf20Sopenharmony_ci if (nr_up != tp->nr_up) { 5258c2ecf20Sopenharmony_ci tp->nr_up = nr_up; 5268c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 5278c2ecf20Sopenharmony_ci tty3270_update_status(tp); 5288c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* 5348c2ecf20Sopenharmony_ci * Scroll backward in history. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_cistatic void 5378c2ecf20Sopenharmony_citty3270_scroll_backward(struct kbd_data *kbd) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); 5408c2ecf20Sopenharmony_ci int nr_up; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 5438c2ecf20Sopenharmony_ci nr_up = tp->nr_up + tp->view.rows - 2; 5448c2ecf20Sopenharmony_ci if (nr_up + tp->view.rows - 2 > tp->nr_lines) 5458c2ecf20Sopenharmony_ci nr_up = tp->nr_lines - tp->view.rows + 2; 5468c2ecf20Sopenharmony_ci if (nr_up != tp->nr_up) { 5478c2ecf20Sopenharmony_ci tp->nr_up = nr_up; 5488c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 5498c2ecf20Sopenharmony_ci tty3270_update_status(tp); 5508c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* 5568c2ecf20Sopenharmony_ci * Pass input line to tty. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_cistatic void 5598c2ecf20Sopenharmony_citty3270_read_tasklet(unsigned long data) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct raw3270_request *rrq = (struct raw3270_request *)data; 5628c2ecf20Sopenharmony_ci static char kreset_data = TW_KR; 5638c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(rrq->view, struct tty3270, view); 5648c2ecf20Sopenharmony_ci char *input; 5658c2ecf20Sopenharmony_ci int len; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 5688c2ecf20Sopenharmony_ci /* 5698c2ecf20Sopenharmony_ci * Two AID keys are special: For 0x7d (enter) the input line 5708c2ecf20Sopenharmony_ci * has to be emitted to the tty and for 0x6d the screen 5718c2ecf20Sopenharmony_ci * needs to be redrawn. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci input = NULL; 5748c2ecf20Sopenharmony_ci len = 0; 5758c2ecf20Sopenharmony_ci if (tp->input->string[0] == 0x7d) { 5768c2ecf20Sopenharmony_ci /* Enter: write input to tty. */ 5778c2ecf20Sopenharmony_ci input = tp->input->string + 6; 5788c2ecf20Sopenharmony_ci len = tp->input->len - 6 - rrq->rescnt; 5798c2ecf20Sopenharmony_ci if (tp->inattr != TF_INPUTN) 5808c2ecf20Sopenharmony_ci tty3270_rcl_add(tp, input, len); 5818c2ecf20Sopenharmony_ci if (tp->nr_up > 0) { 5828c2ecf20Sopenharmony_ci tp->nr_up = 0; 5838c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 5848c2ecf20Sopenharmony_ci tty3270_update_status(tp); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci /* Clear input area. */ 5878c2ecf20Sopenharmony_ci tty3270_update_prompt(tp, NULL, 0); 5888c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 5898c2ecf20Sopenharmony_ci } else if (tp->input->string[0] == 0x6d) { 5908c2ecf20Sopenharmony_ci /* Display has been cleared. Redraw. */ 5918c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ALL; 5928c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Start keyboard reset command. */ 5978c2ecf20Sopenharmony_ci raw3270_request_reset(tp->kreset); 5988c2ecf20Sopenharmony_ci raw3270_request_set_cmd(tp->kreset, TC_WRITE); 5998c2ecf20Sopenharmony_ci raw3270_request_add_data(tp->kreset, &kreset_data, 1); 6008c2ecf20Sopenharmony_ci raw3270_start(&tp->view, tp->kreset); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci while (len-- > 0) 6038c2ecf20Sopenharmony_ci kbd_keycode(tp->kbd, *input++); 6048c2ecf20Sopenharmony_ci /* Emit keycode for AID byte. */ 6058c2ecf20Sopenharmony_ci kbd_keycode(tp->kbd, 256 + tp->input->string[0]); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci raw3270_request_reset(rrq); 6088c2ecf20Sopenharmony_ci xchg(&tp->read, rrq); 6098c2ecf20Sopenharmony_ci raw3270_put_view(&tp->view); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci/* 6138c2ecf20Sopenharmony_ci * Read request completion callback. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_cistatic void 6168c2ecf20Sopenharmony_citty3270_read_callback(struct raw3270_request *rq, void *data) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(rq->view, struct tty3270, view); 6198c2ecf20Sopenharmony_ci raw3270_get_view(rq->view); 6208c2ecf20Sopenharmony_ci /* Schedule tasklet to pass input to tty. */ 6218c2ecf20Sopenharmony_ci tasklet_schedule(&tp->readlet); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/* 6258c2ecf20Sopenharmony_ci * Issue a read request. Call with device lock. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_cistatic void 6288c2ecf20Sopenharmony_citty3270_issue_read(struct tty3270 *tp, int lock) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct raw3270_request *rrq; 6318c2ecf20Sopenharmony_ci int rc; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci rrq = xchg(&tp->read, 0); 6348c2ecf20Sopenharmony_ci if (!rrq) 6358c2ecf20Sopenharmony_ci /* Read already scheduled. */ 6368c2ecf20Sopenharmony_ci return; 6378c2ecf20Sopenharmony_ci rrq->callback = tty3270_read_callback; 6388c2ecf20Sopenharmony_ci rrq->callback_data = tp; 6398c2ecf20Sopenharmony_ci raw3270_request_set_cmd(rrq, TC_READMOD); 6408c2ecf20Sopenharmony_ci raw3270_request_set_data(rrq, tp->input->string, tp->input->len); 6418c2ecf20Sopenharmony_ci /* Issue the read modified request. */ 6428c2ecf20Sopenharmony_ci if (lock) { 6438c2ecf20Sopenharmony_ci rc = raw3270_start(&tp->view, rrq); 6448c2ecf20Sopenharmony_ci } else 6458c2ecf20Sopenharmony_ci rc = raw3270_start_irq(&tp->view, rrq); 6468c2ecf20Sopenharmony_ci if (rc) { 6478c2ecf20Sopenharmony_ci raw3270_request_reset(rrq); 6488c2ecf20Sopenharmony_ci xchg(&tp->read, rrq); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/* 6538c2ecf20Sopenharmony_ci * Hang up the tty 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_cistatic void 6568c2ecf20Sopenharmony_citty3270_hangup_tasklet(unsigned long data) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct tty3270 *tp = (struct tty3270 *)data; 6598c2ecf20Sopenharmony_ci tty_port_tty_hangup(&tp->port, true); 6608c2ecf20Sopenharmony_ci raw3270_put_view(&tp->view); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/* 6648c2ecf20Sopenharmony_ci * Switch to the tty view. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_cistatic int 6678c2ecf20Sopenharmony_citty3270_activate(struct raw3270_view *view) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(view, struct tty3270, view); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ALL; 6728c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void 6778c2ecf20Sopenharmony_citty3270_deactivate(struct raw3270_view *view) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(view, struct tty3270, view); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci del_timer(&tp->timer); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void 6858c2ecf20Sopenharmony_citty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci /* Handle ATTN. Schedule tasklet to read aid. */ 6888c2ecf20Sopenharmony_ci if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { 6898c2ecf20Sopenharmony_ci if (!tp->throttle) 6908c2ecf20Sopenharmony_ci tty3270_issue_read(tp, 0); 6918c2ecf20Sopenharmony_ci else 6928c2ecf20Sopenharmony_ci tp->attn = 1; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (rq) { 6968c2ecf20Sopenharmony_ci if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { 6978c2ecf20Sopenharmony_ci rq->rc = -EIO; 6988c2ecf20Sopenharmony_ci raw3270_get_view(&tp->view); 6998c2ecf20Sopenharmony_ci tasklet_schedule(&tp->hanglet); 7008c2ecf20Sopenharmony_ci } else { 7018c2ecf20Sopenharmony_ci /* Normal end. Copy residual count. */ 7028c2ecf20Sopenharmony_ci rq->rescnt = irb->scsw.cmd.count; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci } else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { 7058c2ecf20Sopenharmony_ci /* Interrupt without an outstanding request -> update all */ 7068c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ALL; 7078c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* 7128c2ecf20Sopenharmony_ci * Allocate tty3270 structure. 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_cistatic struct tty3270 * 7158c2ecf20Sopenharmony_citty3270_alloc_view(void) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct tty3270 *tp; 7188c2ecf20Sopenharmony_ci int pages; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci tp = kzalloc(sizeof(struct tty3270), GFP_KERNEL); 7218c2ecf20Sopenharmony_ci if (!tp) 7228c2ecf20Sopenharmony_ci goto out_err; 7238c2ecf20Sopenharmony_ci tp->freemem_pages = 7248c2ecf20Sopenharmony_ci kmalloc_array(TTY3270_STRING_PAGES, sizeof(void *), 7258c2ecf20Sopenharmony_ci GFP_KERNEL); 7268c2ecf20Sopenharmony_ci if (!tp->freemem_pages) 7278c2ecf20Sopenharmony_ci goto out_tp; 7288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->freemem); 7298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->lines); 7308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->update); 7318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->rcl_lines); 7328c2ecf20Sopenharmony_ci tp->rcl_max = 20; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) { 7358c2ecf20Sopenharmony_ci tp->freemem_pages[pages] = (void *) 7368c2ecf20Sopenharmony_ci __get_free_pages(GFP_KERNEL|GFP_DMA, 0); 7378c2ecf20Sopenharmony_ci if (!tp->freemem_pages[pages]) 7388c2ecf20Sopenharmony_ci goto out_pages; 7398c2ecf20Sopenharmony_ci add_string_memory(&tp->freemem, 7408c2ecf20Sopenharmony_ci tp->freemem_pages[pages], PAGE_SIZE); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE); 7438c2ecf20Sopenharmony_ci if (IS_ERR(tp->write)) 7448c2ecf20Sopenharmony_ci goto out_pages; 7458c2ecf20Sopenharmony_ci tp->read = raw3270_request_alloc(0); 7468c2ecf20Sopenharmony_ci if (IS_ERR(tp->read)) 7478c2ecf20Sopenharmony_ci goto out_write; 7488c2ecf20Sopenharmony_ci tp->kreset = raw3270_request_alloc(1); 7498c2ecf20Sopenharmony_ci if (IS_ERR(tp->kreset)) 7508c2ecf20Sopenharmony_ci goto out_read; 7518c2ecf20Sopenharmony_ci tp->kbd = kbd_alloc(); 7528c2ecf20Sopenharmony_ci if (!tp->kbd) 7538c2ecf20Sopenharmony_ci goto out_reset; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci tty_port_init(&tp->port); 7568c2ecf20Sopenharmony_ci timer_setup(&tp->timer, tty3270_update, 0); 7578c2ecf20Sopenharmony_ci tasklet_init(&tp->readlet, tty3270_read_tasklet, 7588c2ecf20Sopenharmony_ci (unsigned long) tp->read); 7598c2ecf20Sopenharmony_ci tasklet_init(&tp->hanglet, tty3270_hangup_tasklet, 7608c2ecf20Sopenharmony_ci (unsigned long) tp); 7618c2ecf20Sopenharmony_ci INIT_WORK(&tp->resize_work, tty3270_resize_work); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return tp; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ciout_reset: 7668c2ecf20Sopenharmony_ci raw3270_request_free(tp->kreset); 7678c2ecf20Sopenharmony_ciout_read: 7688c2ecf20Sopenharmony_ci raw3270_request_free(tp->read); 7698c2ecf20Sopenharmony_ciout_write: 7708c2ecf20Sopenharmony_ci raw3270_request_free(tp->write); 7718c2ecf20Sopenharmony_ciout_pages: 7728c2ecf20Sopenharmony_ci while (pages--) 7738c2ecf20Sopenharmony_ci free_pages((unsigned long) tp->freemem_pages[pages], 0); 7748c2ecf20Sopenharmony_ci kfree(tp->freemem_pages); 7758c2ecf20Sopenharmony_ci tty_port_destroy(&tp->port); 7768c2ecf20Sopenharmony_ciout_tp: 7778c2ecf20Sopenharmony_ci kfree(tp); 7788c2ecf20Sopenharmony_ciout_err: 7798c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/* 7838c2ecf20Sopenharmony_ci * Free tty3270 structure. 7848c2ecf20Sopenharmony_ci */ 7858c2ecf20Sopenharmony_cistatic void 7868c2ecf20Sopenharmony_citty3270_free_view(struct tty3270 *tp) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci int pages; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci kbd_free(tp->kbd); 7918c2ecf20Sopenharmony_ci raw3270_request_free(tp->kreset); 7928c2ecf20Sopenharmony_ci raw3270_request_free(tp->read); 7938c2ecf20Sopenharmony_ci raw3270_request_free(tp->write); 7948c2ecf20Sopenharmony_ci for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) 7958c2ecf20Sopenharmony_ci free_pages((unsigned long) tp->freemem_pages[pages], 0); 7968c2ecf20Sopenharmony_ci kfree(tp->freemem_pages); 7978c2ecf20Sopenharmony_ci tty_port_destroy(&tp->port); 7988c2ecf20Sopenharmony_ci kfree(tp); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci/* 8028c2ecf20Sopenharmony_ci * Allocate tty3270 screen. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_cistatic struct tty3270_line * 8058c2ecf20Sopenharmony_citty3270_alloc_screen(unsigned int rows, unsigned int cols) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct tty3270_line *screen; 8088c2ecf20Sopenharmony_ci unsigned long size; 8098c2ecf20Sopenharmony_ci int lines; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci size = sizeof(struct tty3270_line) * (rows - 2); 8128c2ecf20Sopenharmony_ci screen = kzalloc(size, GFP_KERNEL); 8138c2ecf20Sopenharmony_ci if (!screen) 8148c2ecf20Sopenharmony_ci goto out_err; 8158c2ecf20Sopenharmony_ci for (lines = 0; lines < rows - 2; lines++) { 8168c2ecf20Sopenharmony_ci size = sizeof(struct tty3270_cell) * cols; 8178c2ecf20Sopenharmony_ci screen[lines].cells = kzalloc(size, GFP_KERNEL); 8188c2ecf20Sopenharmony_ci if (!screen[lines].cells) 8198c2ecf20Sopenharmony_ci goto out_screen; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci return screen; 8228c2ecf20Sopenharmony_ciout_screen: 8238c2ecf20Sopenharmony_ci while (lines--) 8248c2ecf20Sopenharmony_ci kfree(screen[lines].cells); 8258c2ecf20Sopenharmony_ci kfree(screen); 8268c2ecf20Sopenharmony_ciout_err: 8278c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci/* 8318c2ecf20Sopenharmony_ci * Free tty3270 screen. 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_cistatic void 8348c2ecf20Sopenharmony_citty3270_free_screen(struct tty3270_line *screen, unsigned int rows) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci int lines; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci for (lines = 0; lines < rows - 2; lines++) 8398c2ecf20Sopenharmony_ci kfree(screen[lines].cells); 8408c2ecf20Sopenharmony_ci kfree(screen); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/* 8448c2ecf20Sopenharmony_ci * Resize tty3270 screen 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_cistatic void tty3270_resize_work(struct work_struct *work) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(work, struct tty3270, resize_work); 8498c2ecf20Sopenharmony_ci struct tty3270_line *screen, *oscreen; 8508c2ecf20Sopenharmony_ci struct tty_struct *tty; 8518c2ecf20Sopenharmony_ci unsigned int orows; 8528c2ecf20Sopenharmony_ci struct winsize ws; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols); 8558c2ecf20Sopenharmony_ci if (IS_ERR(screen)) 8568c2ecf20Sopenharmony_ci return; 8578c2ecf20Sopenharmony_ci /* Switch to new output size */ 8588c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 8598c2ecf20Sopenharmony_ci tty3270_blank_screen(tp); 8608c2ecf20Sopenharmony_ci oscreen = tp->screen; 8618c2ecf20Sopenharmony_ci orows = tp->view.rows; 8628c2ecf20Sopenharmony_ci tp->view.model = tp->n_model; 8638c2ecf20Sopenharmony_ci tp->view.rows = tp->n_rows; 8648c2ecf20Sopenharmony_ci tp->view.cols = tp->n_cols; 8658c2ecf20Sopenharmony_ci tp->screen = screen; 8668c2ecf20Sopenharmony_ci free_string(&tp->freemem, tp->prompt); 8678c2ecf20Sopenharmony_ci free_string(&tp->freemem, tp->status); 8688c2ecf20Sopenharmony_ci tty3270_create_prompt(tp); 8698c2ecf20Sopenharmony_ci tty3270_create_status(tp); 8708c2ecf20Sopenharmony_ci while (tp->nr_lines < tp->view.rows - 2) 8718c2ecf20Sopenharmony_ci tty3270_blank_line(tp); 8728c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ALL; 8738c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 8748c2ecf20Sopenharmony_ci tty3270_free_screen(oscreen, orows); 8758c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 8768c2ecf20Sopenharmony_ci /* Informat tty layer about new size */ 8778c2ecf20Sopenharmony_ci tty = tty_port_tty_get(&tp->port); 8788c2ecf20Sopenharmony_ci if (!tty) 8798c2ecf20Sopenharmony_ci return; 8808c2ecf20Sopenharmony_ci ws.ws_row = tp->view.rows - 2; 8818c2ecf20Sopenharmony_ci ws.ws_col = tp->view.cols; 8828c2ecf20Sopenharmony_ci tty_do_resize(tty, &ws); 8838c2ecf20Sopenharmony_ci tty_kref_put(tty); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void 8878c2ecf20Sopenharmony_citty3270_resize(struct raw3270_view *view, int model, int rows, int cols) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(view, struct tty3270, view); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (tp->n_model == model && tp->n_rows == rows && tp->n_cols == cols) 8928c2ecf20Sopenharmony_ci return; 8938c2ecf20Sopenharmony_ci tp->n_model = model; 8948c2ecf20Sopenharmony_ci tp->n_rows = rows; 8958c2ecf20Sopenharmony_ci tp->n_cols = cols; 8968c2ecf20Sopenharmony_ci schedule_work(&tp->resize_work); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci/* 9008c2ecf20Sopenharmony_ci * Unlink tty3270 data structure from tty. 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_cistatic void 9038c2ecf20Sopenharmony_citty3270_release(struct raw3270_view *view) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(view, struct tty3270, view); 9068c2ecf20Sopenharmony_ci struct tty_struct *tty = tty_port_tty_get(&tp->port); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (tty) { 9098c2ecf20Sopenharmony_ci tty->driver_data = NULL; 9108c2ecf20Sopenharmony_ci tty_port_tty_set(&tp->port, NULL); 9118c2ecf20Sopenharmony_ci tty_hangup(tty); 9128c2ecf20Sopenharmony_ci raw3270_put_view(&tp->view); 9138c2ecf20Sopenharmony_ci tty_kref_put(tty); 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci/* 9188c2ecf20Sopenharmony_ci * Free tty3270 data structure 9198c2ecf20Sopenharmony_ci */ 9208c2ecf20Sopenharmony_cistatic void 9218c2ecf20Sopenharmony_citty3270_free(struct raw3270_view *view) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct tty3270 *tp = container_of(view, struct tty3270, view); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci del_timer_sync(&tp->timer); 9268c2ecf20Sopenharmony_ci tty3270_free_screen(tp->screen, tp->view.rows); 9278c2ecf20Sopenharmony_ci tty3270_free_view(tp); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci/* 9318c2ecf20Sopenharmony_ci * Delayed freeing of tty3270 views. 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_cistatic void 9348c2ecf20Sopenharmony_citty3270_del_views(void) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci int i; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) { 9398c2ecf20Sopenharmony_ci struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i); 9408c2ecf20Sopenharmony_ci if (!IS_ERR(view)) 9418c2ecf20Sopenharmony_ci raw3270_del_view(view); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic struct raw3270_fn tty3270_fn = { 9468c2ecf20Sopenharmony_ci .activate = tty3270_activate, 9478c2ecf20Sopenharmony_ci .deactivate = tty3270_deactivate, 9488c2ecf20Sopenharmony_ci .intv = (void *) tty3270_irq, 9498c2ecf20Sopenharmony_ci .release = tty3270_release, 9508c2ecf20Sopenharmony_ci .free = tty3270_free, 9518c2ecf20Sopenharmony_ci .resize = tty3270_resize 9528c2ecf20Sopenharmony_ci}; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci/* 9558c2ecf20Sopenharmony_ci * This routine is called whenever a 3270 tty is opened first time. 9568c2ecf20Sopenharmony_ci */ 9578c2ecf20Sopenharmony_cistatic int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct raw3270_view *view; 9608c2ecf20Sopenharmony_ci struct tty3270 *tp; 9618c2ecf20Sopenharmony_ci int i, rc; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* Check if the tty3270 is already there. */ 9648c2ecf20Sopenharmony_ci view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); 9658c2ecf20Sopenharmony_ci if (!IS_ERR(view)) { 9668c2ecf20Sopenharmony_ci tp = container_of(view, struct tty3270, view); 9678c2ecf20Sopenharmony_ci tty->driver_data = tp; 9688c2ecf20Sopenharmony_ci tty->winsize.ws_row = tp->view.rows - 2; 9698c2ecf20Sopenharmony_ci tty->winsize.ws_col = tp->view.cols; 9708c2ecf20Sopenharmony_ci tp->port.low_latency = 0; 9718c2ecf20Sopenharmony_ci tp->inattr = TF_INPUT; 9728c2ecf20Sopenharmony_ci goto port_install; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci if (tty3270_max_index < tty->index + 1) 9758c2ecf20Sopenharmony_ci tty3270_max_index = tty->index + 1; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* Allocate tty3270 structure on first open. */ 9788c2ecf20Sopenharmony_ci tp = tty3270_alloc_view(); 9798c2ecf20Sopenharmony_ci if (IS_ERR(tp)) 9808c2ecf20Sopenharmony_ci return PTR_ERR(tp); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci rc = raw3270_add_view(&tp->view, &tty3270_fn, 9838c2ecf20Sopenharmony_ci tty->index + RAW3270_FIRSTMINOR, 9848c2ecf20Sopenharmony_ci RAW3270_VIEW_LOCK_BH); 9858c2ecf20Sopenharmony_ci if (rc) { 9868c2ecf20Sopenharmony_ci tty3270_free_view(tp); 9878c2ecf20Sopenharmony_ci return rc; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci tp->screen = tty3270_alloc_screen(tp->view.rows, tp->view.cols); 9918c2ecf20Sopenharmony_ci if (IS_ERR(tp->screen)) { 9928c2ecf20Sopenharmony_ci rc = PTR_ERR(tp->screen); 9938c2ecf20Sopenharmony_ci raw3270_put_view(&tp->view); 9948c2ecf20Sopenharmony_ci raw3270_del_view(&tp->view); 9958c2ecf20Sopenharmony_ci tty3270_free_view(tp); 9968c2ecf20Sopenharmony_ci return rc; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci tp->port.low_latency = 0; 10008c2ecf20Sopenharmony_ci tty->winsize.ws_row = tp->view.rows - 2; 10018c2ecf20Sopenharmony_ci tty->winsize.ws_col = tp->view.cols; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci tty3270_create_prompt(tp); 10048c2ecf20Sopenharmony_ci tty3270_create_status(tp); 10058c2ecf20Sopenharmony_ci tty3270_update_status(tp); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci /* Create blank line for every line in the tty output area. */ 10088c2ecf20Sopenharmony_ci for (i = 0; i < tp->view.rows - 2; i++) 10098c2ecf20Sopenharmony_ci tty3270_blank_line(tp); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci tp->kbd->port = &tp->port; 10128c2ecf20Sopenharmony_ci tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty; 10138c2ecf20Sopenharmony_ci tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward; 10148c2ecf20Sopenharmony_ci tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward; 10158c2ecf20Sopenharmony_ci tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward; 10168c2ecf20Sopenharmony_ci kbd_ascebc(tp->kbd, tp->view.ascebc); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci raw3270_activate_view(&tp->view); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ciport_install: 10218c2ecf20Sopenharmony_ci rc = tty_port_install(&tp->port, driver, tty); 10228c2ecf20Sopenharmony_ci if (rc) { 10238c2ecf20Sopenharmony_ci raw3270_put_view(&tp->view); 10248c2ecf20Sopenharmony_ci return rc; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci tty->driver_data = tp; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return 0; 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci/* 10338c2ecf20Sopenharmony_ci * This routine is called whenever a 3270 tty is opened. 10348c2ecf20Sopenharmony_ci */ 10358c2ecf20Sopenharmony_cistatic int 10368c2ecf20Sopenharmony_citty3270_open(struct tty_struct *tty, struct file *filp) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct tty3270 *tp = tty->driver_data; 10398c2ecf20Sopenharmony_ci struct tty_port *port = &tp->port; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci port->count++; 10428c2ecf20Sopenharmony_ci tty_port_tty_set(port, tty); 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci/* 10478c2ecf20Sopenharmony_ci * This routine is called when the 3270 tty is closed. We wait 10488c2ecf20Sopenharmony_ci * for the remaining request to be completed. Then we clean up. 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_cistatic void 10518c2ecf20Sopenharmony_citty3270_close(struct tty_struct *tty, struct file * filp) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct tty3270 *tp = tty->driver_data; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (tty->count > 1) 10568c2ecf20Sopenharmony_ci return; 10578c2ecf20Sopenharmony_ci if (tp) 10588c2ecf20Sopenharmony_ci tty_port_tty_set(&tp->port, NULL); 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic void tty3270_cleanup(struct tty_struct *tty) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct tty3270 *tp = tty->driver_data; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (tp) { 10668c2ecf20Sopenharmony_ci tty->driver_data = NULL; 10678c2ecf20Sopenharmony_ci raw3270_put_view(&tp->view); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci/* 10728c2ecf20Sopenharmony_ci * We always have room. 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_cistatic int 10758c2ecf20Sopenharmony_citty3270_write_room(struct tty_struct *tty) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci return INT_MAX; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci/* 10818c2ecf20Sopenharmony_ci * Insert character into the screen at the current position with the 10828c2ecf20Sopenharmony_ci * current color and highlight. This function does NOT do cursor movement. 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_cistatic void tty3270_put_character(struct tty3270 *tp, char ch) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct tty3270_line *line; 10878c2ecf20Sopenharmony_ci struct tty3270_cell *cell; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci line = tp->screen + tp->cy; 10908c2ecf20Sopenharmony_ci if (line->len <= tp->cx) { 10918c2ecf20Sopenharmony_ci while (line->len < tp->cx) { 10928c2ecf20Sopenharmony_ci cell = line->cells + line->len; 10938c2ecf20Sopenharmony_ci cell->character = tp->view.ascebc[' ']; 10948c2ecf20Sopenharmony_ci cell->highlight = tp->highlight; 10958c2ecf20Sopenharmony_ci cell->f_color = tp->f_color; 10968c2ecf20Sopenharmony_ci line->len++; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci line->len++; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci cell = line->cells + tp->cx; 11018c2ecf20Sopenharmony_ci cell->character = tp->view.ascebc[(unsigned int) ch]; 11028c2ecf20Sopenharmony_ci cell->highlight = tp->highlight; 11038c2ecf20Sopenharmony_ci cell->f_color = tp->f_color; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci/* 11078c2ecf20Sopenharmony_ci * Convert a tty3270_line to a 3270 data fragment usable for output. 11088c2ecf20Sopenharmony_ci */ 11098c2ecf20Sopenharmony_cistatic void 11108c2ecf20Sopenharmony_citty3270_convert_line(struct tty3270 *tp, int line_nr) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct tty3270_line *line; 11138c2ecf20Sopenharmony_ci struct tty3270_cell *cell; 11148c2ecf20Sopenharmony_ci struct string *s, *n; 11158c2ecf20Sopenharmony_ci unsigned char highlight; 11168c2ecf20Sopenharmony_ci unsigned char f_color; 11178c2ecf20Sopenharmony_ci char *cp; 11188c2ecf20Sopenharmony_ci int flen, i; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* Determine how long the fragment will be. */ 11218c2ecf20Sopenharmony_ci flen = 3; /* Prefix (TO_SBA). */ 11228c2ecf20Sopenharmony_ci line = tp->screen + line_nr; 11238c2ecf20Sopenharmony_ci flen += line->len; 11248c2ecf20Sopenharmony_ci highlight = TAX_RESET; 11258c2ecf20Sopenharmony_ci f_color = TAC_RESET; 11268c2ecf20Sopenharmony_ci for (i = 0, cell = line->cells; i < line->len; i++, cell++) { 11278c2ecf20Sopenharmony_ci if (cell->highlight != highlight) { 11288c2ecf20Sopenharmony_ci flen += 3; /* TO_SA to switch highlight. */ 11298c2ecf20Sopenharmony_ci highlight = cell->highlight; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci if (cell->f_color != f_color) { 11328c2ecf20Sopenharmony_ci flen += 3; /* TO_SA to switch color. */ 11338c2ecf20Sopenharmony_ci f_color = cell->f_color; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci if (highlight != TAX_RESET) 11378c2ecf20Sopenharmony_ci flen += 3; /* TO_SA to reset hightlight. */ 11388c2ecf20Sopenharmony_ci if (f_color != TAC_RESET) 11398c2ecf20Sopenharmony_ci flen += 3; /* TO_SA to reset color. */ 11408c2ecf20Sopenharmony_ci if (line->len < tp->view.cols) 11418c2ecf20Sopenharmony_ci flen += 4; /* Postfix (TO_RA). */ 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* Find the line in the list. */ 11448c2ecf20Sopenharmony_ci i = tp->view.rows - 2 - line_nr; 11458c2ecf20Sopenharmony_ci list_for_each_entry_reverse(s, &tp->lines, list) 11468c2ecf20Sopenharmony_ci if (--i <= 0) 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci /* 11498c2ecf20Sopenharmony_ci * Check if the line needs to get reallocated. 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_ci if (s->len != flen) { 11528c2ecf20Sopenharmony_ci /* Reallocate string. */ 11538c2ecf20Sopenharmony_ci n = tty3270_alloc_string(tp, flen); 11548c2ecf20Sopenharmony_ci list_add(&n->list, &s->list); 11558c2ecf20Sopenharmony_ci list_del_init(&s->list); 11568c2ecf20Sopenharmony_ci if (!list_empty(&s->update)) 11578c2ecf20Sopenharmony_ci list_del_init(&s->update); 11588c2ecf20Sopenharmony_ci free_string(&tp->freemem, s); 11598c2ecf20Sopenharmony_ci s = n; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* Write 3270 data fragment. */ 11638c2ecf20Sopenharmony_ci cp = s->string; 11648c2ecf20Sopenharmony_ci *cp++ = TO_SBA; 11658c2ecf20Sopenharmony_ci *cp++ = 0; 11668c2ecf20Sopenharmony_ci *cp++ = 0; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci highlight = TAX_RESET; 11698c2ecf20Sopenharmony_ci f_color = TAC_RESET; 11708c2ecf20Sopenharmony_ci for (i = 0, cell = line->cells; i < line->len; i++, cell++) { 11718c2ecf20Sopenharmony_ci if (cell->highlight != highlight) { 11728c2ecf20Sopenharmony_ci *cp++ = TO_SA; 11738c2ecf20Sopenharmony_ci *cp++ = TAT_EXTHI; 11748c2ecf20Sopenharmony_ci *cp++ = cell->highlight; 11758c2ecf20Sopenharmony_ci highlight = cell->highlight; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci if (cell->f_color != f_color) { 11788c2ecf20Sopenharmony_ci *cp++ = TO_SA; 11798c2ecf20Sopenharmony_ci *cp++ = TAT_COLOR; 11808c2ecf20Sopenharmony_ci *cp++ = cell->f_color; 11818c2ecf20Sopenharmony_ci f_color = cell->f_color; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci *cp++ = cell->character; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci if (highlight != TAX_RESET) { 11868c2ecf20Sopenharmony_ci *cp++ = TO_SA; 11878c2ecf20Sopenharmony_ci *cp++ = TAT_EXTHI; 11888c2ecf20Sopenharmony_ci *cp++ = TAX_RESET; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci if (f_color != TAC_RESET) { 11918c2ecf20Sopenharmony_ci *cp++ = TO_SA; 11928c2ecf20Sopenharmony_ci *cp++ = TAT_COLOR; 11938c2ecf20Sopenharmony_ci *cp++ = TAC_RESET; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci if (line->len < tp->view.cols) { 11968c2ecf20Sopenharmony_ci *cp++ = TO_RA; 11978c2ecf20Sopenharmony_ci *cp++ = 0; 11988c2ecf20Sopenharmony_ci *cp++ = 0; 11998c2ecf20Sopenharmony_ci *cp++ = 0; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (tp->nr_up + line_nr < tp->view.rows - 2) { 12038c2ecf20Sopenharmony_ci /* Line is currently visible on screen. */ 12048c2ecf20Sopenharmony_ci tty3270_update_string(tp, s, line_nr); 12058c2ecf20Sopenharmony_ci /* Add line to update list. */ 12068c2ecf20Sopenharmony_ci if (list_empty(&s->update)) { 12078c2ecf20Sopenharmony_ci list_add_tail(&s->update, &tp->update); 12088c2ecf20Sopenharmony_ci tp->update_flags |= TTY_UPDATE_LIST; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci/* 12148c2ecf20Sopenharmony_ci * Do carriage return. 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_cistatic void 12178c2ecf20Sopenharmony_citty3270_cr(struct tty3270 *tp) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci tp->cx = 0; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci/* 12238c2ecf20Sopenharmony_ci * Do line feed. 12248c2ecf20Sopenharmony_ci */ 12258c2ecf20Sopenharmony_cistatic void 12268c2ecf20Sopenharmony_citty3270_lf(struct tty3270 *tp) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci struct tty3270_line temp; 12298c2ecf20Sopenharmony_ci int i; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 12328c2ecf20Sopenharmony_ci if (tp->cy < tp->view.rows - 3) { 12338c2ecf20Sopenharmony_ci tp->cy++; 12348c2ecf20Sopenharmony_ci return; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci /* Last line just filled up. Add new, blank line. */ 12378c2ecf20Sopenharmony_ci tty3270_blank_line(tp); 12388c2ecf20Sopenharmony_ci temp = tp->screen[0]; 12398c2ecf20Sopenharmony_ci temp.len = 0; 12408c2ecf20Sopenharmony_ci for (i = 0; i < tp->view.rows - 3; i++) 12418c2ecf20Sopenharmony_ci tp->screen[i] = tp->screen[i+1]; 12428c2ecf20Sopenharmony_ci tp->screen[tp->view.rows - 3] = temp; 12438c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cistatic void 12478c2ecf20Sopenharmony_citty3270_ri(struct tty3270 *tp) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci if (tp->cy > 0) { 12508c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 12518c2ecf20Sopenharmony_ci tp->cy--; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci/* 12568c2ecf20Sopenharmony_ci * Insert characters at current position. 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_cistatic void 12598c2ecf20Sopenharmony_citty3270_insert_characters(struct tty3270 *tp, int n) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci struct tty3270_line *line; 12628c2ecf20Sopenharmony_ci int k; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci line = tp->screen + tp->cy; 12658c2ecf20Sopenharmony_ci while (line->len < tp->cx) { 12668c2ecf20Sopenharmony_ci line->cells[line->len].character = tp->view.ascebc[' ']; 12678c2ecf20Sopenharmony_ci line->cells[line->len].highlight = TAX_RESET; 12688c2ecf20Sopenharmony_ci line->cells[line->len].f_color = TAC_RESET; 12698c2ecf20Sopenharmony_ci line->len++; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci if (n > tp->view.cols - tp->cx) 12728c2ecf20Sopenharmony_ci n = tp->view.cols - tp->cx; 12738c2ecf20Sopenharmony_ci k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n); 12748c2ecf20Sopenharmony_ci while (k--) 12758c2ecf20Sopenharmony_ci line->cells[tp->cx + n + k] = line->cells[tp->cx + k]; 12768c2ecf20Sopenharmony_ci line->len += n; 12778c2ecf20Sopenharmony_ci if (line->len > tp->view.cols) 12788c2ecf20Sopenharmony_ci line->len = tp->view.cols; 12798c2ecf20Sopenharmony_ci while (n-- > 0) { 12808c2ecf20Sopenharmony_ci line->cells[tp->cx + n].character = tp->view.ascebc[' ']; 12818c2ecf20Sopenharmony_ci line->cells[tp->cx + n].highlight = tp->highlight; 12828c2ecf20Sopenharmony_ci line->cells[tp->cx + n].f_color = tp->f_color; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci/* 12878c2ecf20Sopenharmony_ci * Delete characters at current position. 12888c2ecf20Sopenharmony_ci */ 12898c2ecf20Sopenharmony_cistatic void 12908c2ecf20Sopenharmony_citty3270_delete_characters(struct tty3270 *tp, int n) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci struct tty3270_line *line; 12938c2ecf20Sopenharmony_ci int i; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci line = tp->screen + tp->cy; 12968c2ecf20Sopenharmony_ci if (line->len <= tp->cx) 12978c2ecf20Sopenharmony_ci return; 12988c2ecf20Sopenharmony_ci if (line->len - tp->cx <= n) { 12998c2ecf20Sopenharmony_ci line->len = tp->cx; 13008c2ecf20Sopenharmony_ci return; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci for (i = tp->cx; i + n < line->len; i++) 13038c2ecf20Sopenharmony_ci line->cells[i] = line->cells[i + n]; 13048c2ecf20Sopenharmony_ci line->len -= n; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci/* 13088c2ecf20Sopenharmony_ci * Erase characters at current position. 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_cistatic void 13118c2ecf20Sopenharmony_citty3270_erase_characters(struct tty3270 *tp, int n) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct tty3270_line *line; 13148c2ecf20Sopenharmony_ci struct tty3270_cell *cell; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci line = tp->screen + tp->cy; 13178c2ecf20Sopenharmony_ci while (line->len > tp->cx && n-- > 0) { 13188c2ecf20Sopenharmony_ci cell = line->cells + tp->cx++; 13198c2ecf20Sopenharmony_ci cell->character = ' '; 13208c2ecf20Sopenharmony_ci cell->highlight = TAX_RESET; 13218c2ecf20Sopenharmony_ci cell->f_color = TAC_RESET; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci tp->cx += n; 13248c2ecf20Sopenharmony_ci tp->cx = min_t(int, tp->cx, tp->view.cols - 1); 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci/* 13288c2ecf20Sopenharmony_ci * Erase line, 3 different cases: 13298c2ecf20Sopenharmony_ci * Esc [ 0 K Erase from current position to end of line inclusive 13308c2ecf20Sopenharmony_ci * Esc [ 1 K Erase from beginning of line to current position inclusive 13318c2ecf20Sopenharmony_ci * Esc [ 2 K Erase entire line (without moving cursor) 13328c2ecf20Sopenharmony_ci */ 13338c2ecf20Sopenharmony_cistatic void 13348c2ecf20Sopenharmony_citty3270_erase_line(struct tty3270 *tp, int mode) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct tty3270_line *line; 13378c2ecf20Sopenharmony_ci struct tty3270_cell *cell; 13388c2ecf20Sopenharmony_ci int i; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci line = tp->screen + tp->cy; 13418c2ecf20Sopenharmony_ci if (mode == 0) 13428c2ecf20Sopenharmony_ci line->len = tp->cx; 13438c2ecf20Sopenharmony_ci else if (mode == 1) { 13448c2ecf20Sopenharmony_ci for (i = 0; i < tp->cx; i++) { 13458c2ecf20Sopenharmony_ci cell = line->cells + i; 13468c2ecf20Sopenharmony_ci cell->character = ' '; 13478c2ecf20Sopenharmony_ci cell->highlight = TAX_RESET; 13488c2ecf20Sopenharmony_ci cell->f_color = TAC_RESET; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci if (line->len <= tp->cx) 13518c2ecf20Sopenharmony_ci line->len = tp->cx + 1; 13528c2ecf20Sopenharmony_ci } else if (mode == 2) 13538c2ecf20Sopenharmony_ci line->len = 0; 13548c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci/* 13588c2ecf20Sopenharmony_ci * Erase display, 3 different cases: 13598c2ecf20Sopenharmony_ci * Esc [ 0 J Erase from current position to bottom of screen inclusive 13608c2ecf20Sopenharmony_ci * Esc [ 1 J Erase from top of screen to current position inclusive 13618c2ecf20Sopenharmony_ci * Esc [ 2 J Erase entire screen (without moving the cursor) 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_cistatic void 13648c2ecf20Sopenharmony_citty3270_erase_display(struct tty3270 *tp, int mode) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci int i; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (mode == 0) { 13698c2ecf20Sopenharmony_ci tty3270_erase_line(tp, 0); 13708c2ecf20Sopenharmony_ci for (i = tp->cy + 1; i < tp->view.rows - 2; i++) { 13718c2ecf20Sopenharmony_ci tp->screen[i].len = 0; 13728c2ecf20Sopenharmony_ci tty3270_convert_line(tp, i); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci } else if (mode == 1) { 13758c2ecf20Sopenharmony_ci for (i = 0; i < tp->cy; i++) { 13768c2ecf20Sopenharmony_ci tp->screen[i].len = 0; 13778c2ecf20Sopenharmony_ci tty3270_convert_line(tp, i); 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci tty3270_erase_line(tp, 1); 13808c2ecf20Sopenharmony_ci } else if (mode == 2) { 13818c2ecf20Sopenharmony_ci for (i = 0; i < tp->view.rows - 2; i++) { 13828c2ecf20Sopenharmony_ci tp->screen[i].len = 0; 13838c2ecf20Sopenharmony_ci tty3270_convert_line(tp, i); 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci tty3270_rebuild_update(tp); 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci/* 13908c2ecf20Sopenharmony_ci * Set attributes found in an escape sequence. 13918c2ecf20Sopenharmony_ci * Esc [ <attr> ; <attr> ; ... m 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_cistatic void 13948c2ecf20Sopenharmony_citty3270_set_attributes(struct tty3270 *tp) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci static unsigned char f_colors[] = { 13978c2ecf20Sopenharmony_ci TAC_DEFAULT, TAC_RED, TAC_GREEN, TAC_YELLOW, TAC_BLUE, 13988c2ecf20Sopenharmony_ci TAC_PINK, TAC_TURQ, TAC_WHITE, 0, TAC_DEFAULT 13998c2ecf20Sopenharmony_ci }; 14008c2ecf20Sopenharmony_ci int i, attr; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci for (i = 0; i <= tp->esc_npar; i++) { 14038c2ecf20Sopenharmony_ci attr = tp->esc_par[i]; 14048c2ecf20Sopenharmony_ci switch (attr) { 14058c2ecf20Sopenharmony_ci case 0: /* Reset */ 14068c2ecf20Sopenharmony_ci tp->highlight = TAX_RESET; 14078c2ecf20Sopenharmony_ci tp->f_color = TAC_RESET; 14088c2ecf20Sopenharmony_ci break; 14098c2ecf20Sopenharmony_ci /* Highlight. */ 14108c2ecf20Sopenharmony_ci case 4: /* Start underlining. */ 14118c2ecf20Sopenharmony_ci tp->highlight = TAX_UNDER; 14128c2ecf20Sopenharmony_ci break; 14138c2ecf20Sopenharmony_ci case 5: /* Start blink. */ 14148c2ecf20Sopenharmony_ci tp->highlight = TAX_BLINK; 14158c2ecf20Sopenharmony_ci break; 14168c2ecf20Sopenharmony_ci case 7: /* Start reverse. */ 14178c2ecf20Sopenharmony_ci tp->highlight = TAX_REVER; 14188c2ecf20Sopenharmony_ci break; 14198c2ecf20Sopenharmony_ci case 24: /* End underlining */ 14208c2ecf20Sopenharmony_ci if (tp->highlight == TAX_UNDER) 14218c2ecf20Sopenharmony_ci tp->highlight = TAX_RESET; 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci case 25: /* End blink. */ 14248c2ecf20Sopenharmony_ci if (tp->highlight == TAX_BLINK) 14258c2ecf20Sopenharmony_ci tp->highlight = TAX_RESET; 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci case 27: /* End reverse. */ 14288c2ecf20Sopenharmony_ci if (tp->highlight == TAX_REVER) 14298c2ecf20Sopenharmony_ci tp->highlight = TAX_RESET; 14308c2ecf20Sopenharmony_ci break; 14318c2ecf20Sopenharmony_ci /* Foreground color. */ 14328c2ecf20Sopenharmony_ci case 30: /* Black */ 14338c2ecf20Sopenharmony_ci case 31: /* Red */ 14348c2ecf20Sopenharmony_ci case 32: /* Green */ 14358c2ecf20Sopenharmony_ci case 33: /* Yellow */ 14368c2ecf20Sopenharmony_ci case 34: /* Blue */ 14378c2ecf20Sopenharmony_ci case 35: /* Magenta */ 14388c2ecf20Sopenharmony_ci case 36: /* Cyan */ 14398c2ecf20Sopenharmony_ci case 37: /* White */ 14408c2ecf20Sopenharmony_ci case 39: /* Black */ 14418c2ecf20Sopenharmony_ci tp->f_color = f_colors[attr - 30]; 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic inline int 14488c2ecf20Sopenharmony_citty3270_getpar(struct tty3270 *tp, int ix) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1; 14518c2ecf20Sopenharmony_ci} 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_cistatic void 14548c2ecf20Sopenharmony_citty3270_goto_xy(struct tty3270 *tp, int cx, int cy) 14558c2ecf20Sopenharmony_ci{ 14568c2ecf20Sopenharmony_ci int max_cx = max(0, cx); 14578c2ecf20Sopenharmony_ci int max_cy = max(0, cy); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci tp->cx = min_t(int, tp->view.cols - 1, max_cx); 14608c2ecf20Sopenharmony_ci cy = min_t(int, tp->view.rows - 3, max_cy); 14618c2ecf20Sopenharmony_ci if (cy != tp->cy) { 14628c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 14638c2ecf20Sopenharmony_ci tp->cy = cy; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci/* 14688c2ecf20Sopenharmony_ci * Process escape sequences. Known sequences: 14698c2ecf20Sopenharmony_ci * Esc 7 Save Cursor Position 14708c2ecf20Sopenharmony_ci * Esc 8 Restore Cursor Position 14718c2ecf20Sopenharmony_ci * Esc [ Pn ; Pn ; .. m Set attributes 14728c2ecf20Sopenharmony_ci * Esc [ Pn ; Pn H Cursor Position 14738c2ecf20Sopenharmony_ci * Esc [ Pn ; Pn f Cursor Position 14748c2ecf20Sopenharmony_ci * Esc [ Pn A Cursor Up 14758c2ecf20Sopenharmony_ci * Esc [ Pn B Cursor Down 14768c2ecf20Sopenharmony_ci * Esc [ Pn C Cursor Forward 14778c2ecf20Sopenharmony_ci * Esc [ Pn D Cursor Backward 14788c2ecf20Sopenharmony_ci * Esc [ Pn G Cursor Horizontal Absolute 14798c2ecf20Sopenharmony_ci * Esc [ Pn X Erase Characters 14808c2ecf20Sopenharmony_ci * Esc [ Ps J Erase in Display 14818c2ecf20Sopenharmony_ci * Esc [ Ps K Erase in Line 14828c2ecf20Sopenharmony_ci * // FIXME: add all the new ones. 14838c2ecf20Sopenharmony_ci * 14848c2ecf20Sopenharmony_ci * Pn is a numeric parameter, a string of zero or more decimal digits. 14858c2ecf20Sopenharmony_ci * Ps is a selective parameter. 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_cistatic void 14888c2ecf20Sopenharmony_citty3270_escape_sequence(struct tty3270 *tp, char ch) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci enum { ESnormal, ESesc, ESsquare, ESgetpars }; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci if (tp->esc_state == ESnormal) { 14938c2ecf20Sopenharmony_ci if (ch == 0x1b) 14948c2ecf20Sopenharmony_ci /* Starting new escape sequence. */ 14958c2ecf20Sopenharmony_ci tp->esc_state = ESesc; 14968c2ecf20Sopenharmony_ci return; 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci if (tp->esc_state == ESesc) { 14998c2ecf20Sopenharmony_ci tp->esc_state = ESnormal; 15008c2ecf20Sopenharmony_ci switch (ch) { 15018c2ecf20Sopenharmony_ci case '[': 15028c2ecf20Sopenharmony_ci tp->esc_state = ESsquare; 15038c2ecf20Sopenharmony_ci break; 15048c2ecf20Sopenharmony_ci case 'E': 15058c2ecf20Sopenharmony_ci tty3270_cr(tp); 15068c2ecf20Sopenharmony_ci tty3270_lf(tp); 15078c2ecf20Sopenharmony_ci break; 15088c2ecf20Sopenharmony_ci case 'M': 15098c2ecf20Sopenharmony_ci tty3270_ri(tp); 15108c2ecf20Sopenharmony_ci break; 15118c2ecf20Sopenharmony_ci case 'D': 15128c2ecf20Sopenharmony_ci tty3270_lf(tp); 15138c2ecf20Sopenharmony_ci break; 15148c2ecf20Sopenharmony_ci case 'Z': /* Respond ID. */ 15158c2ecf20Sopenharmony_ci kbd_puts_queue(&tp->port, "\033[?6c"); 15168c2ecf20Sopenharmony_ci break; 15178c2ecf20Sopenharmony_ci case '7': /* Save cursor position. */ 15188c2ecf20Sopenharmony_ci tp->saved_cx = tp->cx; 15198c2ecf20Sopenharmony_ci tp->saved_cy = tp->cy; 15208c2ecf20Sopenharmony_ci tp->saved_highlight = tp->highlight; 15218c2ecf20Sopenharmony_ci tp->saved_f_color = tp->f_color; 15228c2ecf20Sopenharmony_ci break; 15238c2ecf20Sopenharmony_ci case '8': /* Restore cursor position. */ 15248c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 15258c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy); 15268c2ecf20Sopenharmony_ci tp->highlight = tp->saved_highlight; 15278c2ecf20Sopenharmony_ci tp->f_color = tp->saved_f_color; 15288c2ecf20Sopenharmony_ci break; 15298c2ecf20Sopenharmony_ci case 'c': /* Reset terminal. */ 15308c2ecf20Sopenharmony_ci tp->cx = tp->saved_cx = 0; 15318c2ecf20Sopenharmony_ci tp->cy = tp->saved_cy = 0; 15328c2ecf20Sopenharmony_ci tp->highlight = tp->saved_highlight = TAX_RESET; 15338c2ecf20Sopenharmony_ci tp->f_color = tp->saved_f_color = TAC_RESET; 15348c2ecf20Sopenharmony_ci tty3270_erase_display(tp, 2); 15358c2ecf20Sopenharmony_ci break; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci return; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci if (tp->esc_state == ESsquare) { 15408c2ecf20Sopenharmony_ci tp->esc_state = ESgetpars; 15418c2ecf20Sopenharmony_ci memset(tp->esc_par, 0, sizeof(tp->esc_par)); 15428c2ecf20Sopenharmony_ci tp->esc_npar = 0; 15438c2ecf20Sopenharmony_ci tp->esc_ques = (ch == '?'); 15448c2ecf20Sopenharmony_ci if (tp->esc_ques) 15458c2ecf20Sopenharmony_ci return; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci if (tp->esc_state == ESgetpars) { 15488c2ecf20Sopenharmony_ci if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) { 15498c2ecf20Sopenharmony_ci tp->esc_npar++; 15508c2ecf20Sopenharmony_ci return; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci if (ch >= '0' && ch <= '9') { 15538c2ecf20Sopenharmony_ci tp->esc_par[tp->esc_npar] *= 10; 15548c2ecf20Sopenharmony_ci tp->esc_par[tp->esc_npar] += ch - '0'; 15558c2ecf20Sopenharmony_ci return; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci tp->esc_state = ESnormal; 15598c2ecf20Sopenharmony_ci if (ch == 'n' && !tp->esc_ques) { 15608c2ecf20Sopenharmony_ci if (tp->esc_par[0] == 5) /* Status report. */ 15618c2ecf20Sopenharmony_ci kbd_puts_queue(&tp->port, "\033[0n"); 15628c2ecf20Sopenharmony_ci else if (tp->esc_par[0] == 6) { /* Cursor report. */ 15638c2ecf20Sopenharmony_ci char buf[40]; 15648c2ecf20Sopenharmony_ci sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1); 15658c2ecf20Sopenharmony_ci kbd_puts_queue(&tp->port, buf); 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci return; 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci if (tp->esc_ques) 15708c2ecf20Sopenharmony_ci return; 15718c2ecf20Sopenharmony_ci switch (ch) { 15728c2ecf20Sopenharmony_ci case 'm': 15738c2ecf20Sopenharmony_ci tty3270_set_attributes(tp); 15748c2ecf20Sopenharmony_ci break; 15758c2ecf20Sopenharmony_ci case 'H': /* Set cursor position. */ 15768c2ecf20Sopenharmony_ci case 'f': 15778c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1, 15788c2ecf20Sopenharmony_ci tty3270_getpar(tp, 0) - 1); 15798c2ecf20Sopenharmony_ci break; 15808c2ecf20Sopenharmony_ci case 'd': /* Set y position. */ 15818c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1); 15828c2ecf20Sopenharmony_ci break; 15838c2ecf20Sopenharmony_ci case 'A': /* Cursor up. */ 15848c2ecf20Sopenharmony_ci case 'F': 15858c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0)); 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci case 'B': /* Cursor down. */ 15888c2ecf20Sopenharmony_ci case 'e': 15898c2ecf20Sopenharmony_ci case 'E': 15908c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0)); 15918c2ecf20Sopenharmony_ci break; 15928c2ecf20Sopenharmony_ci case 'C': /* Cursor forward. */ 15938c2ecf20Sopenharmony_ci case 'a': 15948c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy); 15958c2ecf20Sopenharmony_ci break; 15968c2ecf20Sopenharmony_ci case 'D': /* Cursor backward. */ 15978c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy); 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci case 'G': /* Set x position. */ 16008c2ecf20Sopenharmony_ci case '`': 16018c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy); 16028c2ecf20Sopenharmony_ci break; 16038c2ecf20Sopenharmony_ci case 'X': /* Erase Characters. */ 16048c2ecf20Sopenharmony_ci tty3270_erase_characters(tp, tty3270_getpar(tp, 0)); 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci case 'J': /* Erase display. */ 16078c2ecf20Sopenharmony_ci tty3270_erase_display(tp, tp->esc_par[0]); 16088c2ecf20Sopenharmony_ci break; 16098c2ecf20Sopenharmony_ci case 'K': /* Erase line. */ 16108c2ecf20Sopenharmony_ci tty3270_erase_line(tp, tp->esc_par[0]); 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci case 'P': /* Delete characters. */ 16138c2ecf20Sopenharmony_ci tty3270_delete_characters(tp, tty3270_getpar(tp, 0)); 16148c2ecf20Sopenharmony_ci break; 16158c2ecf20Sopenharmony_ci case '@': /* Insert characters. */ 16168c2ecf20Sopenharmony_ci tty3270_insert_characters(tp, tty3270_getpar(tp, 0)); 16178c2ecf20Sopenharmony_ci break; 16188c2ecf20Sopenharmony_ci case 's': /* Save cursor position. */ 16198c2ecf20Sopenharmony_ci tp->saved_cx = tp->cx; 16208c2ecf20Sopenharmony_ci tp->saved_cy = tp->cy; 16218c2ecf20Sopenharmony_ci tp->saved_highlight = tp->highlight; 16228c2ecf20Sopenharmony_ci tp->saved_f_color = tp->f_color; 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci case 'u': /* Restore cursor position. */ 16258c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 16268c2ecf20Sopenharmony_ci tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy); 16278c2ecf20Sopenharmony_ci tp->highlight = tp->saved_highlight; 16288c2ecf20Sopenharmony_ci tp->f_color = tp->saved_f_color; 16298c2ecf20Sopenharmony_ci break; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci/* 16348c2ecf20Sopenharmony_ci * String write routine for 3270 ttys 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_cistatic void 16378c2ecf20Sopenharmony_citty3270_do_write(struct tty3270 *tp, struct tty_struct *tty, 16388c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci int i_msg, i; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 16438c2ecf20Sopenharmony_ci for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) { 16448c2ecf20Sopenharmony_ci if (tp->esc_state != 0) { 16458c2ecf20Sopenharmony_ci /* Continue escape sequence. */ 16468c2ecf20Sopenharmony_ci tty3270_escape_sequence(tp, buf[i_msg]); 16478c2ecf20Sopenharmony_ci continue; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci switch (buf[i_msg]) { 16518c2ecf20Sopenharmony_ci case 0x07: /* '\a' -- Alarm */ 16528c2ecf20Sopenharmony_ci tp->wcc |= TW_PLUSALARM; 16538c2ecf20Sopenharmony_ci break; 16548c2ecf20Sopenharmony_ci case 0x08: /* Backspace. */ 16558c2ecf20Sopenharmony_ci if (tp->cx > 0) { 16568c2ecf20Sopenharmony_ci tp->cx--; 16578c2ecf20Sopenharmony_ci tty3270_put_character(tp, ' '); 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci break; 16608c2ecf20Sopenharmony_ci case 0x09: /* '\t' -- Tabulate */ 16618c2ecf20Sopenharmony_ci for (i = tp->cx % 8; i < 8; i++) { 16628c2ecf20Sopenharmony_ci if (tp->cx >= tp->view.cols) { 16638c2ecf20Sopenharmony_ci tty3270_cr(tp); 16648c2ecf20Sopenharmony_ci tty3270_lf(tp); 16658c2ecf20Sopenharmony_ci break; 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci tty3270_put_character(tp, ' '); 16688c2ecf20Sopenharmony_ci tp->cx++; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci break; 16718c2ecf20Sopenharmony_ci case 0x0a: /* '\n' -- New Line */ 16728c2ecf20Sopenharmony_ci tty3270_cr(tp); 16738c2ecf20Sopenharmony_ci tty3270_lf(tp); 16748c2ecf20Sopenharmony_ci break; 16758c2ecf20Sopenharmony_ci case 0x0c: /* '\f' -- Form Feed */ 16768c2ecf20Sopenharmony_ci tty3270_erase_display(tp, 2); 16778c2ecf20Sopenharmony_ci tp->cx = tp->cy = 0; 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci case 0x0d: /* '\r' -- Carriage Return */ 16808c2ecf20Sopenharmony_ci tp->cx = 0; 16818c2ecf20Sopenharmony_ci break; 16828c2ecf20Sopenharmony_ci case 0x0f: /* SuSE "exit alternate mode" */ 16838c2ecf20Sopenharmony_ci break; 16848c2ecf20Sopenharmony_ci case 0x1b: /* Start escape sequence. */ 16858c2ecf20Sopenharmony_ci tty3270_escape_sequence(tp, buf[i_msg]); 16868c2ecf20Sopenharmony_ci break; 16878c2ecf20Sopenharmony_ci default: /* Insert normal character. */ 16888c2ecf20Sopenharmony_ci if (tp->cx >= tp->view.cols) { 16898c2ecf20Sopenharmony_ci tty3270_cr(tp); 16908c2ecf20Sopenharmony_ci tty3270_lf(tp); 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci tty3270_put_character(tp, buf[i_msg]); 16938c2ecf20Sopenharmony_ci tp->cx++; 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci /* Convert current line to 3270 data fragment. */ 16988c2ecf20Sopenharmony_ci tty3270_convert_line(tp, tp->cy); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci /* Setup timer to update display after 1/10 second */ 17018c2ecf20Sopenharmony_ci if (!timer_pending(&tp->timer)) 17028c2ecf20Sopenharmony_ci tty3270_set_timer(tp, HZ/10); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci/* 17088c2ecf20Sopenharmony_ci * String write routine for 3270 ttys 17098c2ecf20Sopenharmony_ci */ 17108c2ecf20Sopenharmony_cistatic int 17118c2ecf20Sopenharmony_citty3270_write(struct tty_struct * tty, 17128c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct tty3270 *tp; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci tp = tty->driver_data; 17178c2ecf20Sopenharmony_ci if (!tp) 17188c2ecf20Sopenharmony_ci return 0; 17198c2ecf20Sopenharmony_ci if (tp->char_count > 0) { 17208c2ecf20Sopenharmony_ci tty3270_do_write(tp, tty, tp->char_buf, tp->char_count); 17218c2ecf20Sopenharmony_ci tp->char_count = 0; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci tty3270_do_write(tp, tty, buf, count); 17248c2ecf20Sopenharmony_ci return count; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci/* 17288c2ecf20Sopenharmony_ci * Put single characters to the ttys character buffer 17298c2ecf20Sopenharmony_ci */ 17308c2ecf20Sopenharmony_cistatic int tty3270_put_char(struct tty_struct *tty, unsigned char ch) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct tty3270 *tp; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci tp = tty->driver_data; 17358c2ecf20Sopenharmony_ci if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE) 17368c2ecf20Sopenharmony_ci return 0; 17378c2ecf20Sopenharmony_ci tp->char_buf[tp->char_count++] = ch; 17388c2ecf20Sopenharmony_ci return 1; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci/* 17428c2ecf20Sopenharmony_ci * Flush all characters from the ttys characeter buffer put there 17438c2ecf20Sopenharmony_ci * by tty3270_put_char. 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_cistatic void 17468c2ecf20Sopenharmony_citty3270_flush_chars(struct tty_struct *tty) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci struct tty3270 *tp; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci tp = tty->driver_data; 17518c2ecf20Sopenharmony_ci if (!tp) 17528c2ecf20Sopenharmony_ci return; 17538c2ecf20Sopenharmony_ci if (tp->char_count > 0) { 17548c2ecf20Sopenharmony_ci tty3270_do_write(tp, tty, tp->char_buf, tp->char_count); 17558c2ecf20Sopenharmony_ci tp->char_count = 0; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci} 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci/* 17608c2ecf20Sopenharmony_ci * Returns the number of characters in the output buffer. This is 17618c2ecf20Sopenharmony_ci * used in tty_wait_until_sent to wait until all characters have 17628c2ecf20Sopenharmony_ci * appeared on the screen. 17638c2ecf20Sopenharmony_ci */ 17648c2ecf20Sopenharmony_cistatic int 17658c2ecf20Sopenharmony_citty3270_chars_in_buffer(struct tty_struct *tty) 17668c2ecf20Sopenharmony_ci{ 17678c2ecf20Sopenharmony_ci return 0; 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_cistatic void 17718c2ecf20Sopenharmony_citty3270_flush_buffer(struct tty_struct *tty) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci} 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci/* 17768c2ecf20Sopenharmony_ci * Check for visible/invisible input switches 17778c2ecf20Sopenharmony_ci */ 17788c2ecf20Sopenharmony_cistatic void 17798c2ecf20Sopenharmony_citty3270_set_termios(struct tty_struct *tty, struct ktermios *old) 17808c2ecf20Sopenharmony_ci{ 17818c2ecf20Sopenharmony_ci struct tty3270 *tp; 17828c2ecf20Sopenharmony_ci int new; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci tp = tty->driver_data; 17858c2ecf20Sopenharmony_ci if (!tp) 17868c2ecf20Sopenharmony_ci return; 17878c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 17888c2ecf20Sopenharmony_ci if (L_ICANON(tty)) { 17898c2ecf20Sopenharmony_ci new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN; 17908c2ecf20Sopenharmony_ci if (new != tp->inattr) { 17918c2ecf20Sopenharmony_ci tp->inattr = new; 17928c2ecf20Sopenharmony_ci tty3270_update_prompt(tp, NULL, 0); 17938c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci/* 18008c2ecf20Sopenharmony_ci * Disable reading from a 3270 tty 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_cistatic void 18038c2ecf20Sopenharmony_citty3270_throttle(struct tty_struct * tty) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci struct tty3270 *tp; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci tp = tty->driver_data; 18088c2ecf20Sopenharmony_ci if (!tp) 18098c2ecf20Sopenharmony_ci return; 18108c2ecf20Sopenharmony_ci tp->throttle = 1; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci/* 18148c2ecf20Sopenharmony_ci * Enable reading from a 3270 tty 18158c2ecf20Sopenharmony_ci */ 18168c2ecf20Sopenharmony_cistatic void 18178c2ecf20Sopenharmony_citty3270_unthrottle(struct tty_struct * tty) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci struct tty3270 *tp; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci tp = tty->driver_data; 18228c2ecf20Sopenharmony_ci if (!tp) 18238c2ecf20Sopenharmony_ci return; 18248c2ecf20Sopenharmony_ci tp->throttle = 0; 18258c2ecf20Sopenharmony_ci if (tp->attn) 18268c2ecf20Sopenharmony_ci tty3270_issue_read(tp, 1); 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci/* 18308c2ecf20Sopenharmony_ci * Hang up the tty device. 18318c2ecf20Sopenharmony_ci */ 18328c2ecf20Sopenharmony_cistatic void 18338c2ecf20Sopenharmony_citty3270_hangup(struct tty_struct *tty) 18348c2ecf20Sopenharmony_ci{ 18358c2ecf20Sopenharmony_ci struct tty3270 *tp; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci tp = tty->driver_data; 18388c2ecf20Sopenharmony_ci if (!tp) 18398c2ecf20Sopenharmony_ci return; 18408c2ecf20Sopenharmony_ci spin_lock_bh(&tp->view.lock); 18418c2ecf20Sopenharmony_ci tp->cx = tp->saved_cx = 0; 18428c2ecf20Sopenharmony_ci tp->cy = tp->saved_cy = 0; 18438c2ecf20Sopenharmony_ci tp->highlight = tp->saved_highlight = TAX_RESET; 18448c2ecf20Sopenharmony_ci tp->f_color = tp->saved_f_color = TAC_RESET; 18458c2ecf20Sopenharmony_ci tty3270_blank_screen(tp); 18468c2ecf20Sopenharmony_ci while (tp->nr_lines < tp->view.rows - 2) 18478c2ecf20Sopenharmony_ci tty3270_blank_line(tp); 18488c2ecf20Sopenharmony_ci tp->update_flags = TTY_UPDATE_ALL; 18498c2ecf20Sopenharmony_ci spin_unlock_bh(&tp->view.lock); 18508c2ecf20Sopenharmony_ci tty3270_set_timer(tp, 1); 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic void 18548c2ecf20Sopenharmony_citty3270_wait_until_sent(struct tty_struct *tty, int timeout) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cistatic int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd, 18598c2ecf20Sopenharmony_ci unsigned long arg) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci struct tty3270 *tp; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci tp = tty->driver_data; 18648c2ecf20Sopenharmony_ci if (!tp) 18658c2ecf20Sopenharmony_ci return -ENODEV; 18668c2ecf20Sopenharmony_ci if (tty_io_error(tty)) 18678c2ecf20Sopenharmony_ci return -EIO; 18688c2ecf20Sopenharmony_ci return kbd_ioctl(tp->kbd, cmd, arg); 18698c2ecf20Sopenharmony_ci} 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 18728c2ecf20Sopenharmony_cistatic long tty3270_compat_ioctl(struct tty_struct *tty, 18738c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci struct tty3270 *tp; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci tp = tty->driver_data; 18788c2ecf20Sopenharmony_ci if (!tp) 18798c2ecf20Sopenharmony_ci return -ENODEV; 18808c2ecf20Sopenharmony_ci if (tty_io_error(tty)) 18818c2ecf20Sopenharmony_ci return -EIO; 18828c2ecf20Sopenharmony_ci return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg)); 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci#endif 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_cistatic const struct tty_operations tty3270_ops = { 18878c2ecf20Sopenharmony_ci .install = tty3270_install, 18888c2ecf20Sopenharmony_ci .cleanup = tty3270_cleanup, 18898c2ecf20Sopenharmony_ci .open = tty3270_open, 18908c2ecf20Sopenharmony_ci .close = tty3270_close, 18918c2ecf20Sopenharmony_ci .write = tty3270_write, 18928c2ecf20Sopenharmony_ci .put_char = tty3270_put_char, 18938c2ecf20Sopenharmony_ci .flush_chars = tty3270_flush_chars, 18948c2ecf20Sopenharmony_ci .write_room = tty3270_write_room, 18958c2ecf20Sopenharmony_ci .chars_in_buffer = tty3270_chars_in_buffer, 18968c2ecf20Sopenharmony_ci .flush_buffer = tty3270_flush_buffer, 18978c2ecf20Sopenharmony_ci .throttle = tty3270_throttle, 18988c2ecf20Sopenharmony_ci .unthrottle = tty3270_unthrottle, 18998c2ecf20Sopenharmony_ci .hangup = tty3270_hangup, 19008c2ecf20Sopenharmony_ci .wait_until_sent = tty3270_wait_until_sent, 19018c2ecf20Sopenharmony_ci .ioctl = tty3270_ioctl, 19028c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 19038c2ecf20Sopenharmony_ci .compat_ioctl = tty3270_compat_ioctl, 19048c2ecf20Sopenharmony_ci#endif 19058c2ecf20Sopenharmony_ci .set_termios = tty3270_set_termios 19068c2ecf20Sopenharmony_ci}; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic void tty3270_create_cb(int minor) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL); 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cistatic void tty3270_destroy_cb(int minor) 19148c2ecf20Sopenharmony_ci{ 19158c2ecf20Sopenharmony_ci tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR); 19168c2ecf20Sopenharmony_ci} 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic struct raw3270_notifier tty3270_notifier = 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci .create = tty3270_create_cb, 19218c2ecf20Sopenharmony_ci .destroy = tty3270_destroy_cb, 19228c2ecf20Sopenharmony_ci}; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci/* 19258c2ecf20Sopenharmony_ci * 3270 tty registration code called from tty_init(). 19268c2ecf20Sopenharmony_ci * Most kernel services (incl. kmalloc) are available at this poimt. 19278c2ecf20Sopenharmony_ci */ 19288c2ecf20Sopenharmony_cistatic int __init tty3270_init(void) 19298c2ecf20Sopenharmony_ci{ 19308c2ecf20Sopenharmony_ci struct tty_driver *driver; 19318c2ecf20Sopenharmony_ci int ret; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci driver = tty_alloc_driver(RAW3270_MAXDEVS, 19348c2ecf20Sopenharmony_ci TTY_DRIVER_REAL_RAW | 19358c2ecf20Sopenharmony_ci TTY_DRIVER_DYNAMIC_DEV | 19368c2ecf20Sopenharmony_ci TTY_DRIVER_RESET_TERMIOS); 19378c2ecf20Sopenharmony_ci if (IS_ERR(driver)) 19388c2ecf20Sopenharmony_ci return PTR_ERR(driver); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci /* 19418c2ecf20Sopenharmony_ci * Initialize the tty_driver structure 19428c2ecf20Sopenharmony_ci * Entries in tty3270_driver that are NOT initialized: 19438c2ecf20Sopenharmony_ci * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc 19448c2ecf20Sopenharmony_ci */ 19458c2ecf20Sopenharmony_ci driver->driver_name = "tty3270"; 19468c2ecf20Sopenharmony_ci driver->name = "3270/tty"; 19478c2ecf20Sopenharmony_ci driver->major = IBM_TTY3270_MAJOR; 19488c2ecf20Sopenharmony_ci driver->minor_start = RAW3270_FIRSTMINOR; 19498c2ecf20Sopenharmony_ci driver->name_base = RAW3270_FIRSTMINOR; 19508c2ecf20Sopenharmony_ci driver->type = TTY_DRIVER_TYPE_SYSTEM; 19518c2ecf20Sopenharmony_ci driver->subtype = SYSTEM_TYPE_TTY; 19528c2ecf20Sopenharmony_ci driver->init_termios = tty_std_termios; 19538c2ecf20Sopenharmony_ci tty_set_operations(driver, &tty3270_ops); 19548c2ecf20Sopenharmony_ci ret = tty_register_driver(driver); 19558c2ecf20Sopenharmony_ci if (ret) { 19568c2ecf20Sopenharmony_ci put_tty_driver(driver); 19578c2ecf20Sopenharmony_ci return ret; 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci tty3270_driver = driver; 19608c2ecf20Sopenharmony_ci raw3270_register_notifier(&tty3270_notifier); 19618c2ecf20Sopenharmony_ci return 0; 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_cistatic void __exit 19658c2ecf20Sopenharmony_citty3270_exit(void) 19668c2ecf20Sopenharmony_ci{ 19678c2ecf20Sopenharmony_ci struct tty_driver *driver; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci raw3270_unregister_notifier(&tty3270_notifier); 19708c2ecf20Sopenharmony_ci driver = tty3270_driver; 19718c2ecf20Sopenharmony_ci tty3270_driver = NULL; 19728c2ecf20Sopenharmony_ci tty_unregister_driver(driver); 19738c2ecf20Sopenharmony_ci put_tty_driver(driver); 19748c2ecf20Sopenharmony_ci tty3270_del_views(); 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 19788c2ecf20Sopenharmony_ciMODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR); 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cimodule_init(tty3270_init); 19818c2ecf20Sopenharmony_cimodule_exit(tty3270_exit); 1982