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