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 struct tty_struct *tty; 974 struct winsize ws; 975 size_t prompt_sz; 976 int new_allocated, old_allocated = tp->allocated_lines; 977 978 if (old_model == new_model && 979 old_cols == new_cols && 980 old_rows == new_rows) { 981 spin_lock_irq(&tp->view.lock); 982 tty3270_redraw(tp); 983 spin_unlock_irq(&tp->view.lock); 984 return; 985 } 986 987 prompt_sz = tty3270_input_size(new_cols); 988 new_input = kzalloc(prompt_sz, GFP_KERNEL | GFP_DMA); 989 if (!new_input) 990 return; 991 new_prompt = kzalloc(prompt_sz, GFP_KERNEL); 992 if (!new_prompt) 993 goto out_input; 994 screen = tty3270_alloc_screen(tp, new_rows, new_cols, &new_allocated); 995 if (IS_ERR(screen)) 996 goto out_prompt; 997 new_rcl_lines = tty3270_alloc_recall(new_cols); 998 if (!new_rcl_lines) 999 goto out_screen; 1000 1001 /* Switch to new output size */ 1002 spin_lock_irq(&tp->view.lock); 1003 tty3270_blank_screen(tp); 1004 oscreen = tp->screen; 1005 tp->screen = screen; 1006 tp->allocated_lines = new_allocated; 1007 tp->view.rows = new_rows; 1008 tp->view.cols = new_cols; 1009 tp->view.model = new_model; 1010 tp->update_flags = TTY_UPDATE_ALL; 1011 old_input = tp->input; 1012 old_prompt = tp->prompt; 1013 old_rcl_lines = tp->rcl_lines; 1014 tp->input = new_input; 1015 tp->prompt = new_prompt; 1016 tp->prompt_sz = prompt_sz; 1017 tp->rcl_lines = new_rcl_lines; 1018 tp->rcl_read_index = 0; 1019 tp->rcl_write_index = 0; 1020 spin_unlock_irq(&tp->view.lock); 1021 tty3270_free_screen(oscreen, old_allocated); 1022 kfree(old_input); 1023 kfree(old_prompt); 1024 tty3270_free_recall(old_rcl_lines); 1025 tty3270_set_timer(tp, 1); 1026 /* Informat tty layer about new size */ 1027 tty = tty_port_tty_get(&tp->port); 1028 if (!tty) 1029 return; 1030 ws.ws_row = tty3270_tty_rows(tp); 1031 ws.ws_col = tp->view.cols; 1032 tty_do_resize(tty, &ws); 1033 tty_kref_put(tty); 1034 return; 1035 out_screen: 1036 tty3270_free_screen(screen, new_rows); 1037 out_prompt: 1038 kfree(new_prompt); 1039 out_input: 1040 kfree(new_input); 1041 } 1042 1043 /* 1044 * Unlink tty3270 data structure from tty. 1045 */ 1046 static void tty3270_release(struct raw3270_view *view) 1047 { 1048 struct tty3270 *tp = container_of(view, struct tty3270, view); 1049 struct tty_struct *tty = tty_port_tty_get(&tp->port); 1050 1051 if (tty) { 1052 tty->driver_data = NULL; 1053 tty_port_tty_set(&tp->port, NULL); 1054 tty_hangup(tty); 1055 raw3270_put_view(&tp->view); 1056 tty_kref_put(tty); 1057 } 1058 } 1059 1060 /* 1061 * Free tty3270 data structure 1062 */ 1063 static void tty3270_free(struct raw3270_view *view) 1064 { 1065 struct tty3270 *tp = container_of(view, struct tty3270, view); 1066 1067 timer_delete_sync(&tp->timer); 1068 tty3270_free_screen(tp->screen, tp->allocated_lines); 1069 free_page((unsigned long)tp->converted_line); 1070 kfree(tp->input); 1071 kfree(tp->prompt); 1072 tty3270_free_view(tp); 1073 } 1074 1075 /* 1076 * Delayed freeing of tty3270 views. 1077 */ 1078 static void tty3270_del_views(void) 1079 { 1080 int i; 1081 1082 for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) { 1083 struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i); 1084 1085 if (!IS_ERR(view)) 1086 raw3270_del_view(view); 1087 } 1088 } 1089 1090 static struct raw3270_fn tty3270_fn = { 1091 .activate = tty3270_activate, 1092 .deactivate = tty3270_deactivate, 1093 .intv = (void *)tty3270_irq, 1094 .release = tty3270_release, 1095 .free = tty3270_free, 1096 .resize = tty3270_resize 1097 }; 1098 1099 static int 1100 tty3270_create_view(int index, struct tty3270 **newtp) 1101 { 1102 struct tty3270 *tp; 1103 size_t prompt_sz; 1104 int rc; 1105 1106 if (tty3270_max_index < index + 1) 1107 tty3270_max_index = index + 1; 1108 1109 /* Allocate tty3270 structure on first open. */ 1110 tp = tty3270_alloc_view(); 1111 if (IS_ERR(tp)) 1112 return PTR_ERR(tp); 1113 1114 rc = raw3270_add_view(&tp->view, &tty3270_fn, 1115 index + RAW3270_FIRSTMINOR, 1116 RAW3270_VIEW_LOCK_IRQ); 1117 if (rc) 1118 goto out_free_view; 1119 1120 tp->screen = tty3270_alloc_screen(tp, tp->view.rows, tp->view.cols, 1121 &tp->allocated_lines); 1122 if (IS_ERR(tp->screen)) { 1123 rc = PTR_ERR(tp->screen); 1124 goto out_put_view; 1125 } 1126 1127 tp->converted_line = (void *)__get_free_page(GFP_KERNEL); 1128 if (!tp->converted_line) { 1129 rc = -ENOMEM; 1130 goto out_free_screen; 1131 } 1132 1133 prompt_sz = tty3270_input_size(tp->view.cols); 1134 tp->input = kzalloc(prompt_sz, GFP_KERNEL | GFP_DMA); 1135 if (!tp->input) { 1136 rc = -ENOMEM; 1137 goto out_free_converted_line; 1138 } 1139 1140 tp->prompt = kzalloc(prompt_sz, GFP_KERNEL); 1141 if (!tp->prompt) { 1142 rc = -ENOMEM; 1143 goto out_free_input; 1144 } 1145 tp->prompt_sz = prompt_sz; 1146 1147 tp->rcl_lines = tty3270_alloc_recall(tp->view.cols); 1148 if (!tp->rcl_lines) { 1149 rc = -ENOMEM; 1150 goto out_free_prompt; 1151 } 1152 1153 /* Create blank line for every line in the tty output area. */ 1154 tty3270_blank_screen(tp); 1155 1156 tp->kbd->port = &tp->port; 1157 tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty; 1158 tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward; 1159 tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward; 1160 tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward; 1161 kbd_ascebc(tp->kbd, tp->view.ascebc); 1162 1163 raw3270_activate_view(&tp->view); 1164 raw3270_put_view(&tp->view); 1165 *newtp = tp; 1166 return 0; 1167 1168 out_free_prompt: 1169 kfree(tp->prompt); 1170 out_free_input: 1171 kfree(tp->input); 1172 out_free_converted_line: 1173 free_page((unsigned long)tp->converted_line); 1174 out_free_screen: 1175 tty3270_free_screen(tp->screen, tp->view.rows); 1176 out_put_view: 1177 raw3270_put_view(&tp->view); 1178 raw3270_del_view(&tp->view); 1179 out_free_view: 1180 tty3270_free_view(tp); 1181 return rc; 1182 } 1183 1184 /* 1185 * This routine is called whenever a 3270 tty is opened first time. 1186 */ 1187 static int 1188 tty3270_install(struct tty_driver *driver, struct tty_struct *tty) 1189 { 1190 struct raw3270_view *view; 1191 struct tty3270 *tp; 1192 int rc; 1193 1194 /* Check if the tty3270 is already there. */ 1195 view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); 1196 if (IS_ERR(view)) { 1197 rc = tty3270_create_view(tty->index, &tp); 1198 if (rc) 1199 return rc; 1200 } else { 1201 tp = container_of(view, struct tty3270, view); 1202 tty->driver_data = tp; 1203 tp->inattr = TF_INPUT; 1204 } 1205 1206 tty->winsize.ws_row = tty3270_tty_rows(tp); 1207 tty->winsize.ws_col = tp->view.cols; 1208 rc = tty_port_install(&tp->port, driver, tty); 1209 if (rc) { 1210 raw3270_put_view(&tp->view); 1211 return rc; 1212 } 1213 tty->driver_data = tp; 1214 return 0; 1215 } 1216 1217 /* 1218 * This routine is called whenever a 3270 tty is opened. 1219 */ 1220 static int tty3270_open(struct tty_struct *tty, struct file *filp) 1221 { 1222 struct tty3270 *tp = tty->driver_data; 1223 struct tty_port *port = &tp->port; 1224 1225 port->count++; 1226 tty_port_tty_set(port, tty); 1227 return 0; 1228 } 1229 1230 /* 1231 * This routine is called when the 3270 tty is closed. We wait 1232 * for the remaining request to be completed. Then we clean up. 1233 */ 1234 static void tty3270_close(struct tty_struct *tty, struct file *filp) 1235 { 1236 struct tty3270 *tp = tty->driver_data; 1237 1238 if (tty->count > 1) 1239 return; 1240 if (tp) 1241 tty_port_tty_set(&tp->port, NULL); 1242 } 1243 1244 static void tty3270_cleanup(struct tty_struct *tty) 1245 { 1246 struct tty3270 *tp = tty->driver_data; 1247 1248 if (tp) { 1249 tty->driver_data = NULL; 1250 raw3270_put_view(&tp->view); 1251 } 1252 } 1253 1254 /* 1255 * We always have room. 1256 */ 1257 static unsigned int tty3270_write_room(struct tty_struct *tty) 1258 { 1259 return INT_MAX; 1260 } 1261 1262 /* 1263 * Insert character into the screen at the current position with the 1264 * current color and highlight. This function does NOT do cursor movement. 1265 */ 1266 static void tty3270_put_character(struct tty3270 *tp, u8 ch) 1267 { 1268 struct tty3270_line *line; 1269 struct tty3270_cell *cell; 1270 1271 line = tty3270_get_write_line(tp, tp->cy); 1272 if (line->len <= tp->cx) { 1273 while (line->len < tp->cx) { 1274 cell = line->cells + line->len; 1275 cell->character = ' '; 1276 cell->attributes = tp->attributes; 1277 line->len++; 1278 } 1279 line->len++; 1280 } 1281 cell = line->cells + tp->cx; 1282 cell->character = ch; 1283 cell->attributes = tp->attributes; 1284 line->dirty = 1; 1285 } 1286 1287 /* 1288 * Do carriage return. 1289 */ 1290 static void tty3270_cr(struct tty3270 *tp) 1291 { 1292 tp->cx = 0; 1293 } 1294 1295 /* 1296 * Do line feed. 1297 */ 1298 static void tty3270_lf(struct tty3270 *tp) 1299 { 1300 struct tty3270_line *line; 1301 int i; 1302 1303 if (tp->cy < tty3270_tty_rows(tp) - 1) { 1304 tp->cy++; 1305 } else { 1306 tp->line_view_start = tty3270_line_increment(tp, tp->line_view_start, 1); 1307 tp->line_write_start = tty3270_line_increment(tp, tp->line_write_start, 1); 1308 for (i = 0; i < tty3270_tty_rows(tp); i++) 1309 tty3270_get_view_line(tp, i)->dirty = 1; 1310 } 1311 1312 line = tty3270_get_write_line(tp, tp->cy); 1313 line->len = 0; 1314 line->dirty = 1; 1315 } 1316 1317 static void tty3270_ri(struct tty3270 *tp) 1318 { 1319 if (tp->cy > 0) 1320 tp->cy--; 1321 } 1322 1323 static void tty3270_reset_cell(struct tty3270 *tp, struct tty3270_cell *cell) 1324 { 1325 cell->character = ' '; 1326 tty3270_reset_attributes(&cell->attributes); 1327 } 1328 1329 /* 1330 * Insert characters at current position. 1331 */ 1332 static void tty3270_insert_characters(struct tty3270 *tp, int n) 1333 { 1334 struct tty3270_line *line; 1335 int k; 1336 1337 line = tty3270_get_write_line(tp, tp->cy); 1338 while (line->len < tp->cx) 1339 tty3270_reset_cell(tp, &line->cells[line->len++]); 1340 if (n > tp->view.cols - tp->cx) 1341 n = tp->view.cols - tp->cx; 1342 k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n); 1343 while (k--) 1344 line->cells[tp->cx + n + k] = line->cells[tp->cx + k]; 1345 line->len += n; 1346 if (line->len > tp->view.cols) 1347 line->len = tp->view.cols; 1348 while (n-- > 0) { 1349 line->cells[tp->cx + n].character = ' '; 1350 line->cells[tp->cx + n].attributes = tp->attributes; 1351 } 1352 } 1353 1354 /* 1355 * Delete characters at current position. 1356 */ 1357 static void tty3270_delete_characters(struct tty3270 *tp, int n) 1358 { 1359 struct tty3270_line *line; 1360 int i; 1361 1362 line = tty3270_get_write_line(tp, tp->cy); 1363 if (line->len <= tp->cx) 1364 return; 1365 if (line->len - tp->cx <= n) { 1366 line->len = tp->cx; 1367 return; 1368 } 1369 for (i = tp->cx; i + n < line->len; i++) 1370 line->cells[i] = line->cells[i + n]; 1371 line->len -= n; 1372 } 1373 1374 /* 1375 * Erase characters at current position. 1376 */ 1377 static void tty3270_erase_characters(struct tty3270 *tp, int n) 1378 { 1379 struct tty3270_line *line; 1380 struct tty3270_cell *cell; 1381 1382 line = tty3270_get_write_line(tp, tp->cy); 1383 while (line->len > tp->cx && n-- > 0) { 1384 cell = line->cells + tp->cx++; 1385 tty3270_reset_cell(tp, cell); 1386 } 1387 tp->cx += n; 1388 tp->cx = min_t(int, tp->cx, tp->view.cols - 1); 1389 } 1390 1391 /* 1392 * Erase line, 3 different cases: 1393 * Esc [ 0 K Erase from current position to end of line inclusive 1394 * Esc [ 1 K Erase from beginning of line to current position inclusive 1395 * Esc [ 2 K Erase entire line (without moving cursor) 1396 */ 1397 static void tty3270_erase_line(struct tty3270 *tp, int mode) 1398 { 1399 struct tty3270_line *line; 1400 struct tty3270_cell *cell; 1401 int i, start, end; 1402 1403 line = tty3270_get_write_line(tp, tp->cy); 1404 1405 switch (mode) { 1406 case 0: 1407 start = tp->cx; 1408 end = tp->view.cols; 1409 break; 1410 case 1: 1411 start = 0; 1412 end = tp->cx; 1413 break; 1414 case 2: 1415 start = 0; 1416 end = tp->view.cols; 1417 break; 1418 default: 1419 return; 1420 } 1421 1422 for (i = start; i < end; i++) { 1423 cell = line->cells + i; 1424 tty3270_reset_cell(tp, cell); 1425 cell->attributes.b_color = tp->attributes.b_color; 1426 } 1427 1428 if (line->len <= end) 1429 line->len = end; 1430 } 1431 1432 /* 1433 * Erase display, 3 different cases: 1434 * Esc [ 0 J Erase from current position to bottom of screen inclusive 1435 * Esc [ 1 J Erase from top of screen to current position inclusive 1436 * Esc [ 2 J Erase entire screen (without moving the cursor) 1437 */ 1438 static void tty3270_erase_display(struct tty3270 *tp, int mode) 1439 { 1440 struct tty3270_line *line; 1441 int i, start, end; 1442 1443 switch (mode) { 1444 case 0: 1445 tty3270_erase_line(tp, 0); 1446 start = tp->cy + 1; 1447 end = tty3270_tty_rows(tp); 1448 break; 1449 case 1: 1450 start = 0; 1451 end = tp->cy; 1452 tty3270_erase_line(tp, 1); 1453 break; 1454 case 2: 1455 start = 0; 1456 end = tty3270_tty_rows(tp); 1457 break; 1458 default: 1459 return; 1460 } 1461 for (i = start; i < end; i++) { 1462 line = tty3270_get_write_line(tp, i); 1463 line->len = 0; 1464 line->dirty = 1; 1465 } 1466 } 1467 1468 /* 1469 * Set attributes found in an escape sequence. 1470 * Esc [ <attr> ; <attr> ; ... m 1471 */ 1472 static void tty3270_set_attributes(struct tty3270 *tp) 1473 { 1474 int i, attr; 1475 1476 for (i = 0; i <= tp->esc_npar; i++) { 1477 attr = tp->esc_par[i]; 1478 switch (attr) { 1479 case 0: /* Reset */ 1480 tty3270_reset_attributes(&tp->attributes); 1481 break; 1482 /* Highlight. */ 1483 case 4: /* Start underlining. */ 1484 tp->attributes.highlight = TTY3270_HIGHLIGHT_UNDERSCORE; 1485 break; 1486 case 5: /* Start blink. */ 1487 tp->attributes.highlight = TTY3270_HIGHLIGHT_BLINK; 1488 break; 1489 case 7: /* Start reverse. */ 1490 tp->attributes.highlight = TTY3270_HIGHLIGHT_REVERSE; 1491 break; 1492 case 24: /* End underlining */ 1493 tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_UNDERSCORE; 1494 break; 1495 case 25: /* End blink. */ 1496 tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_BLINK; 1497 break; 1498 case 27: /* End reverse. */ 1499 tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_REVERSE; 1500 break; 1501 /* Foreground color. */ 1502 case 30: /* Black */ 1503 case 31: /* Red */ 1504 case 32: /* Green */ 1505 case 33: /* Yellow */ 1506 case 34: /* Blue */ 1507 case 35: /* Magenta */ 1508 case 36: /* Cyan */ 1509 case 37: /* White */ 1510 case 39: /* Black */ 1511 tp->attributes.f_color = attr - 30; 1512 break; 1513 /* Background color. */ 1514 case 40: /* Black */ 1515 case 41: /* Red */ 1516 case 42: /* Green */ 1517 case 43: /* Yellow */ 1518 case 44: /* Blue */ 1519 case 45: /* Magenta */ 1520 case 46: /* Cyan */ 1521 case 47: /* White */ 1522 case 49: /* Black */ 1523 tp->attributes.b_color = attr - 40; 1524 break; 1525 } 1526 } 1527 } 1528 1529 static inline int tty3270_getpar(struct tty3270 *tp, int ix) 1530 { 1531 return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1; 1532 } 1533 1534 static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy) 1535 { 1536 struct tty3270_line *line; 1537 struct tty3270_cell *cell; 1538 int max_cx = max(0, cx); 1539 int max_cy = max(0, cy); 1540 1541 tp->cx = min_t(int, tp->view.cols - 1, max_cx); 1542 line = tty3270_get_write_line(tp, tp->cy); 1543 while (line->len < tp->cx) { 1544 cell = line->cells + line->len; 1545 cell->character = ' '; 1546 cell->attributes = tp->attributes; 1547 line->len++; 1548 } 1549 tp->cy = min_t(int, tty3270_tty_rows(tp) - 1, max_cy); 1550 } 1551 1552 /* 1553 * Process escape sequences. Known sequences: 1554 * Esc 7 Save Cursor Position 1555 * Esc 8 Restore Cursor Position 1556 * Esc [ Pn ; Pn ; .. m Set attributes 1557 * Esc [ Pn ; Pn H Cursor Position 1558 * Esc [ Pn ; Pn f Cursor Position 1559 * Esc [ Pn A Cursor Up 1560 * Esc [ Pn B Cursor Down 1561 * Esc [ Pn C Cursor Forward 1562 * Esc [ Pn D Cursor Backward 1563 * Esc [ Pn G Cursor Horizontal Absolute 1564 * Esc [ Pn X Erase Characters 1565 * Esc [ Ps J Erase in Display 1566 * Esc [ Ps K Erase in Line 1567 * // FIXME: add all the new ones. 1568 * 1569 * Pn is a numeric parameter, a string of zero or more decimal digits. 1570 * Ps is a selective parameter. 1571 */ 1572 static void tty3270_escape_sequence(struct tty3270 *tp, u8 ch) 1573 { 1574 enum { ES_NORMAL, ES_ESC, ES_SQUARE, ES_PAREN, ES_GETPARS }; 1575 1576 if (tp->esc_state == ES_NORMAL) { 1577 if (ch == 0x1b) 1578 /* Starting new escape sequence. */ 1579 tp->esc_state = ES_ESC; 1580 return; 1581 } 1582 if (tp->esc_state == ES_ESC) { 1583 tp->esc_state = ES_NORMAL; 1584 switch (ch) { 1585 case '[': 1586 tp->esc_state = ES_SQUARE; 1587 break; 1588 case '(': 1589 tp->esc_state = ES_PAREN; 1590 break; 1591 case 'E': 1592 tty3270_cr(tp); 1593 tty3270_lf(tp); 1594 break; 1595 case 'M': 1596 tty3270_ri(tp); 1597 break; 1598 case 'D': 1599 tty3270_lf(tp); 1600 break; 1601 case 'Z': /* Respond ID. */ 1602 kbd_puts_queue(&tp->port, "\033[?6c"); 1603 break; 1604 case '7': /* Save cursor position. */ 1605 tp->saved_cx = tp->cx; 1606 tp->saved_cy = tp->cy; 1607 tp->saved_attributes = tp->attributes; 1608 break; 1609 case '8': /* Restore cursor position. */ 1610 tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy); 1611 tp->attributes = tp->saved_attributes; 1612 break; 1613 case 'c': /* Reset terminal. */ 1614 tp->cx = 0; 1615 tp->cy = 0; 1616 tp->saved_cx = 0; 1617 tp->saved_cy = 0; 1618 tty3270_reset_attributes(&tp->attributes); 1619 tty3270_reset_attributes(&tp->saved_attributes); 1620 tty3270_erase_display(tp, 2); 1621 break; 1622 } 1623 return; 1624 } 1625 1626 switch (tp->esc_state) { 1627 case ES_PAREN: 1628 tp->esc_state = ES_NORMAL; 1629 switch (ch) { 1630 case 'B': 1631 tp->attributes.alternate_charset = 0; 1632 break; 1633 case '0': 1634 tp->attributes.alternate_charset = 1; 1635 break; 1636 } 1637 return; 1638 case ES_SQUARE: 1639 tp->esc_state = ES_GETPARS; 1640 memset(tp->esc_par, 0, sizeof(tp->esc_par)); 1641 tp->esc_npar = 0; 1642 tp->esc_ques = (ch == '?'); 1643 if (tp->esc_ques) 1644 return; 1645 fallthrough; 1646 case ES_GETPARS: 1647 if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) { 1648 tp->esc_npar++; 1649 return; 1650 } 1651 if (ch >= '0' && ch <= '9') { 1652 tp->esc_par[tp->esc_npar] *= 10; 1653 tp->esc_par[tp->esc_npar] += ch - '0'; 1654 return; 1655 } 1656 break; 1657 default: 1658 break; 1659 } 1660 tp->esc_state = ES_NORMAL; 1661 if (ch == 'n' && !tp->esc_ques) { 1662 if (tp->esc_par[0] == 5) /* Status report. */ 1663 kbd_puts_queue(&tp->port, "\033[0n"); 1664 else if (tp->esc_par[0] == 6) { /* Cursor report. */ 1665 char buf[40]; 1666 1667 sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1); 1668 kbd_puts_queue(&tp->port, buf); 1669 } 1670 return; 1671 } 1672 if (tp->esc_ques) 1673 return; 1674 switch (ch) { 1675 case 'm': 1676 tty3270_set_attributes(tp); 1677 break; 1678 case 'H': /* Set cursor position. */ 1679 case 'f': 1680 tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1, 1681 tty3270_getpar(tp, 0) - 1); 1682 break; 1683 case 'd': /* Set y position. */ 1684 tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1); 1685 break; 1686 case 'A': /* Cursor up. */ 1687 case 'F': 1688 tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0)); 1689 break; 1690 case 'B': /* Cursor down. */ 1691 case 'e': 1692 case 'E': 1693 tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0)); 1694 break; 1695 case 'C': /* Cursor forward. */ 1696 case 'a': 1697 tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy); 1698 break; 1699 case 'D': /* Cursor backward. */ 1700 tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy); 1701 break; 1702 case 'G': /* Set x position. */ 1703 case '`': 1704 tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy); 1705 break; 1706 case 'X': /* Erase Characters. */ 1707 tty3270_erase_characters(tp, tty3270_getpar(tp, 0)); 1708 break; 1709 case 'J': /* Erase display. */ 1710 tty3270_erase_display(tp, tp->esc_par[0]); 1711 break; 1712 case 'K': /* Erase line. */ 1713 tty3270_erase_line(tp, tp->esc_par[0]); 1714 break; 1715 case 'P': /* Delete characters. */ 1716 tty3270_delete_characters(tp, tty3270_getpar(tp, 0)); 1717 break; 1718 case '@': /* Insert characters. */ 1719 tty3270_insert_characters(tp, tty3270_getpar(tp, 0)); 1720 break; 1721 case 's': /* Save cursor position. */ 1722 tp->saved_cx = tp->cx; 1723 tp->saved_cy = tp->cy; 1724 tp->saved_attributes = tp->attributes; 1725 break; 1726 case 'u': /* Restore cursor position. */ 1727 tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy); 1728 tp->attributes = tp->saved_attributes; 1729 break; 1730 } 1731 } 1732 1733 /* 1734 * String write routine for 3270 ttys 1735 */ 1736 static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty, 1737 const u8 *buf, size_t count) 1738 { 1739 int i_msg, i; 1740 1741 spin_lock_irq(&tp->view.lock); 1742 for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) { 1743 if (tp->esc_state != 0) { 1744 /* Continue escape sequence. */ 1745 tty3270_escape_sequence(tp, buf[i_msg]); 1746 continue; 1747 } 1748 1749 switch (buf[i_msg]) { 1750 case 0x00: 1751 break; 1752 case 0x07: /* '\a' -- Alarm */ 1753 tp->wcc |= TW_PLUSALARM; 1754 break; 1755 case 0x08: /* Backspace. */ 1756 if (tp->cx > 0) { 1757 tp->cx--; 1758 tty3270_put_character(tp, ' '); 1759 } 1760 break; 1761 case 0x09: /* '\t' -- Tabulate */ 1762 for (i = tp->cx % 8; i < 8; i++) { 1763 if (tp->cx >= tp->view.cols) { 1764 tty3270_cr(tp); 1765 tty3270_lf(tp); 1766 break; 1767 } 1768 tty3270_put_character(tp, ' '); 1769 tp->cx++; 1770 } 1771 break; 1772 case 0x0a: /* '\n' -- New Line */ 1773 tty3270_cr(tp); 1774 tty3270_lf(tp); 1775 break; 1776 case 0x0c: /* '\f' -- Form Feed */ 1777 tty3270_erase_display(tp, 2); 1778 tp->cx = 0; 1779 tp->cy = 0; 1780 break; 1781 case 0x0d: /* '\r' -- Carriage Return */ 1782 tp->cx = 0; 1783 break; 1784 case 0x0e: 1785 tp->attributes.alternate_charset = 1; 1786 break; 1787 case 0x0f: /* SuSE "exit alternate mode" */ 1788 tp->attributes.alternate_charset = 0; 1789 break; 1790 case 0x1b: /* Start escape sequence. */ 1791 tty3270_escape_sequence(tp, buf[i_msg]); 1792 break; 1793 default: /* Insert normal character. */ 1794 if (tp->cx >= tp->view.cols) { 1795 tty3270_cr(tp); 1796 tty3270_lf(tp); 1797 } 1798 tty3270_put_character(tp, buf[i_msg]); 1799 tp->cx++; 1800 break; 1801 } 1802 } 1803 /* Setup timer to update display after 1/10 second */ 1804 tp->update_flags |= TTY_UPDATE_LINES; 1805 if (!timer_pending(&tp->timer)) 1806 tty3270_set_timer(tp, msecs_to_jiffies(100)); 1807 1808 spin_unlock_irq(&tp->view.lock); 1809 } 1810 1811 /* 1812 * String write routine for 3270 ttys 1813 */ 1814 static ssize_t tty3270_write(struct tty_struct *tty, const u8 *buf, 1815 size_t count) 1816 { 1817 struct tty3270 *tp; 1818 1819 tp = tty->driver_data; 1820 if (!tp) 1821 return 0; 1822 if (tp->char_count > 0) { 1823 tty3270_do_write(tp, tty, tp->char_buf, tp->char_count); 1824 tp->char_count = 0; 1825 } 1826 tty3270_do_write(tp, tty, buf, count); 1827 return count; 1828 } 1829 1830 /* 1831 * Put single characters to the ttys character buffer 1832 */ 1833 static int tty3270_put_char(struct tty_struct *tty, u8 ch) 1834 { 1835 struct tty3270 *tp; 1836 1837 tp = tty->driver_data; 1838 if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE) 1839 return 0; 1840 tp->char_buf[tp->char_count++] = ch; 1841 return 1; 1842 } 1843 1844 /* 1845 * Flush all characters from the ttys characeter buffer put there 1846 * by tty3270_put_char. 1847 */ 1848 static void tty3270_flush_chars(struct tty_struct *tty) 1849 { 1850 struct tty3270 *tp; 1851 1852 tp = tty->driver_data; 1853 if (!tp) 1854 return; 1855 if (tp->char_count > 0) { 1856 tty3270_do_write(tp, tty, tp->char_buf, tp->char_count); 1857 tp->char_count = 0; 1858 } 1859 } 1860 1861 /* 1862 * Check for visible/invisible input switches 1863 */ 1864 static void tty3270_set_termios(struct tty_struct *tty, const struct ktermios *old) 1865 { 1866 struct tty3270 *tp; 1867 int new; 1868 1869 tp = tty->driver_data; 1870 if (!tp) 1871 return; 1872 spin_lock_irq(&tp->view.lock); 1873 if (L_ICANON(tty)) { 1874 new = L_ECHO(tty) ? TF_INPUT : TF_INPUTN; 1875 if (new != tp->inattr) { 1876 tp->inattr = new; 1877 tty3270_update_prompt(tp, ""); 1878 tty3270_set_timer(tp, 1); 1879 } 1880 } 1881 spin_unlock_irq(&tp->view.lock); 1882 } 1883 1884 /* 1885 * Disable reading from a 3270 tty 1886 */ 1887 static void tty3270_throttle(struct tty_struct *tty) 1888 { 1889 struct tty3270 *tp; 1890 1891 tp = tty->driver_data; 1892 if (!tp) 1893 return; 1894 tp->throttle = 1; 1895 } 1896 1897 /* 1898 * Enable reading from a 3270 tty 1899 */ 1900 static void tty3270_unthrottle(struct tty_struct *tty) 1901 { 1902 struct tty3270 *tp; 1903 1904 tp = tty->driver_data; 1905 if (!tp) 1906 return; 1907 tp->throttle = 0; 1908 if (tp->attn) 1909 tty3270_issue_read(tp, 1); 1910 } 1911 1912 /* 1913 * Hang up the tty device. 1914 */ 1915 static void tty3270_hangup(struct tty_struct *tty) 1916 { 1917 struct tty3270 *tp; 1918 1919 tp = tty->driver_data; 1920 if (!tp) 1921 return; 1922 spin_lock_irq(&tp->view.lock); 1923 tp->cx = 0; 1924 tp->cy = 0; 1925 tp->saved_cx = 0; 1926 tp->saved_cy = 0; 1927 tty3270_reset_attributes(&tp->attributes); 1928 tty3270_reset_attributes(&tp->saved_attributes); 1929 tty3270_blank_screen(tp); 1930 tp->update_flags = TTY_UPDATE_ALL; 1931 spin_unlock_irq(&tp->view.lock); 1932 tty3270_set_timer(tp, 1); 1933 } 1934 1935 static void tty3270_wait_until_sent(struct tty_struct *tty, int timeout) 1936 { 1937 } 1938 1939 static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd, 1940 unsigned long arg) 1941 { 1942 struct tty3270 *tp; 1943 1944 tp = tty->driver_data; 1945 if (!tp) 1946 return -ENODEV; 1947 if (tty_io_error(tty)) 1948 return -EIO; 1949 return kbd_ioctl(tp->kbd, cmd, arg); 1950 } 1951 1952 #ifdef CONFIG_COMPAT 1953 static long tty3270_compat_ioctl(struct tty_struct *tty, 1954 unsigned int cmd, unsigned long arg) 1955 { 1956 struct tty3270 *tp; 1957 1958 tp = tty->driver_data; 1959 if (!tp) 1960 return -ENODEV; 1961 if (tty_io_error(tty)) 1962 return -EIO; 1963 return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg)); 1964 } 1965 #endif 1966 1967 static const struct tty_operations tty3270_ops = { 1968 .install = tty3270_install, 1969 .cleanup = tty3270_cleanup, 1970 .open = tty3270_open, 1971 .close = tty3270_close, 1972 .write = tty3270_write, 1973 .put_char = tty3270_put_char, 1974 .flush_chars = tty3270_flush_chars, 1975 .write_room = tty3270_write_room, 1976 .throttle = tty3270_throttle, 1977 .unthrottle = tty3270_unthrottle, 1978 .hangup = tty3270_hangup, 1979 .wait_until_sent = tty3270_wait_until_sent, 1980 .ioctl = tty3270_ioctl, 1981 #ifdef CONFIG_COMPAT 1982 .compat_ioctl = tty3270_compat_ioctl, 1983 #endif 1984 .set_termios = tty3270_set_termios 1985 }; 1986 1987 static void tty3270_create_cb(int minor) 1988 { 1989 tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL); 1990 } 1991 1992 static void tty3270_destroy_cb(int minor) 1993 { 1994 tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR); 1995 } 1996 1997 static struct raw3270_notifier tty3270_notifier = { 1998 .create = tty3270_create_cb, 1999 .destroy = tty3270_destroy_cb, 2000 }; 2001 2002 /* 2003 * 3270 tty registration code called from tty_init(). 2004 * Most kernel services (incl. kmalloc) are available at this poimt. 2005 */ 2006 static int __init tty3270_init(void) 2007 { 2008 struct tty_driver *driver; 2009 int ret; 2010 2011 driver = tty_alloc_driver(RAW3270_MAXDEVS, 2012 TTY_DRIVER_REAL_RAW | 2013 TTY_DRIVER_DYNAMIC_DEV | 2014 TTY_DRIVER_RESET_TERMIOS); 2015 if (IS_ERR(driver)) 2016 return PTR_ERR(driver); 2017 2018 /* 2019 * Initialize the tty_driver structure 2020 * Entries in tty3270_driver that are NOT initialized: 2021 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc 2022 */ 2023 driver->driver_name = "tty3270"; 2024 driver->name = "3270/tty"; 2025 driver->major = IBM_TTY3270_MAJOR; 2026 driver->minor_start = RAW3270_FIRSTMINOR; 2027 driver->name_base = RAW3270_FIRSTMINOR; 2028 driver->type = TTY_DRIVER_TYPE_SYSTEM; 2029 driver->subtype = SYSTEM_TYPE_TTY; 2030 driver->init_termios = tty_std_termios; 2031 tty_set_operations(driver, &tty3270_ops); 2032 ret = tty_register_driver(driver); 2033 if (ret) { 2034 tty_driver_kref_put(driver); 2035 return ret; 2036 } 2037 tty3270_driver = driver; 2038 raw3270_register_notifier(&tty3270_notifier); 2039 return 0; 2040 } 2041 2042 static void __exit tty3270_exit(void) 2043 { 2044 struct tty_driver *driver; 2045 2046 raw3270_unregister_notifier(&tty3270_notifier); 2047 driver = tty3270_driver; 2048 tty3270_driver = NULL; 2049 tty_unregister_driver(driver); 2050 tty_driver_kref_put(driver); 2051 tty3270_del_views(); 2052 } 2053 2054 #if IS_ENABLED(CONFIG_TN3270_CONSOLE) 2055 2056 static struct tty3270 *condev; 2057 2058 static void 2059 con3270_write(struct console *co, const char *str, unsigned int count) 2060 { 2061 struct tty3270 *tp = co->data; 2062 unsigned long flags; 2063 u8 c; 2064 2065 spin_lock_irqsave(&tp->view.lock, flags); 2066 while (count--) { 2067 c = *str++; 2068 if (c == 0x0a) { 2069 tty3270_cr(tp); 2070 tty3270_lf(tp); 2071 } else { 2072 if (tp->cx >= tp->view.cols) { 2073 tty3270_cr(tp); 2074 tty3270_lf(tp); 2075 } 2076 tty3270_put_character(tp, c); 2077 tp->cx++; 2078 } 2079 } 2080 spin_unlock_irqrestore(&tp->view.lock, flags); 2081 } 2082 2083 static struct tty_driver * 2084 con3270_device(struct console *c, int *index) 2085 { 2086 *index = c->index; 2087 return tty3270_driver; 2088 } 2089 2090 static void 2091 con3270_wait_write(struct tty3270 *tp) 2092 { 2093 while (!tp->write) { 2094 raw3270_wait_cons_dev(tp->view.dev); 2095 barrier(); 2096 } 2097 } 2098 2099 /* 2100 * The below function is called as a panic/reboot notifier before the 2101 * system enters a disabled, endless loop. 2102 * 2103 * Notice we must use the spin_trylock() alternative, to prevent lockups 2104 * in atomic context (panic routine runs with secondary CPUs, local IRQs 2105 * and preemption disabled). 2106 */ 2107 static int con3270_notify(struct notifier_block *self, 2108 unsigned long event, void *data) 2109 { 2110 struct tty3270 *tp; 2111 unsigned long flags; 2112 int rc; 2113 2114 tp = condev; 2115 if (!tp->view.dev) 2116 return NOTIFY_DONE; 2117 if (!raw3270_view_lock_unavailable(&tp->view)) { 2118 rc = raw3270_activate_view(&tp->view); 2119 if (rc) 2120 return NOTIFY_DONE; 2121 } 2122 if (!spin_trylock_irqsave(&tp->view.lock, flags)) 2123 return NOTIFY_DONE; 2124 con3270_wait_write(tp); 2125 tp->nr_up = 0; 2126 tp->update_flags = TTY_UPDATE_ALL; 2127 while (tp->update_flags != 0) { 2128 spin_unlock_irqrestore(&tp->view.lock, flags); 2129 tty3270_update(&tp->timer); 2130 spin_lock_irqsave(&tp->view.lock, flags); 2131 con3270_wait_write(tp); 2132 } 2133 spin_unlock_irqrestore(&tp->view.lock, flags); 2134 return NOTIFY_DONE; 2135 } 2136 2137 static struct notifier_block on_panic_nb = { 2138 .notifier_call = con3270_notify, 2139 .priority = INT_MIN + 1, /* run the callback late */ 2140 }; 2141 2142 static struct notifier_block on_reboot_nb = { 2143 .notifier_call = con3270_notify, 2144 .priority = INT_MIN + 1, /* run the callback late */ 2145 }; 2146 2147 static struct console con3270 = { 2148 .name = "tty3270", 2149 .write = con3270_write, 2150 .device = con3270_device, 2151 .flags = CON_PRINTBUFFER, 2152 }; 2153 2154 static int __init 2155 con3270_init(void) 2156 { 2157 struct raw3270_view *view; 2158 struct raw3270 *rp; 2159 struct tty3270 *tp; 2160 int rc; 2161 2162 /* Check if 3270 is to be the console */ 2163 if (!CONSOLE_IS_3270) 2164 return -ENODEV; 2165 2166 /* Set the console mode for VM */ 2167 if (machine_is_vm()) { 2168 cpcmd("TERM CONMODE 3270", NULL, 0, NULL); 2169 cpcmd("TERM AUTOCR OFF", NULL, 0, NULL); 2170 } 2171 2172 rp = raw3270_setup_console(); 2173 if (IS_ERR(rp)) 2174 return PTR_ERR(rp); 2175 2176 /* Check if the tty3270 is already there. */ 2177 view = raw3270_find_view(&tty3270_fn, RAW3270_FIRSTMINOR); 2178 if (IS_ERR(view)) { 2179 rc = tty3270_create_view(0, &tp); 2180 if (rc) 2181 return rc; 2182 } else { 2183 tp = container_of(view, struct tty3270, view); 2184 tp->inattr = TF_INPUT; 2185 } 2186 con3270.data = tp; 2187 condev = tp; 2188 atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); 2189 register_reboot_notifier(&on_reboot_nb); 2190 register_console(&con3270); 2191 return 0; 2192 } 2193 console_initcall(con3270_init); 2194 #endif 2195 2196 MODULE_DESCRIPTION("IBM/3270 Driver - tty functions"); 2197 MODULE_LICENSE("GPL"); 2198 MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR); 2199 2200 module_init(tty3270_init); 2201 module_exit(tty3270_exit); 2202