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