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