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