diff options
Diffstat (limited to 'drivers/s390/char/tty3270.c')
-rw-r--r-- | drivers/s390/char/tty3270.c | 86 |
1 files changed, 71 insertions, 15 deletions
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index e96fc7fd9498..0a9f219fdc7c 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -92,6 +92,7 @@ struct tty3270 { unsigned char inattr; /* Visible/invisible input. */ int throttle, attn; /* tty throttle/unthrottle. */ struct tasklet_struct readlet; /* Tasklet to issue read request. */ + struct tasklet_struct hanglet; /* Tasklet to hang up the tty. */ struct kbd_data *kbd; /* key_maps stuff. */ /* Escape sequence parsing. */ @@ -319,6 +320,27 @@ tty3270_blank_line(struct tty3270 *tp) } /* + * Create a blank screen and remove all lines from the history. + */ +static void +tty3270_blank_screen(struct tty3270 *tp) +{ + struct string *s, *n; + int i; + + for (i = 0; i < tp->view.rows - 2; i++) + tp->screen[i].len = 0; + tp->nr_up = 0; + list_for_each_entry_safe(s, n, &tp->lines, list) { + list_del(&s->list); + if (!list_empty(&s->update)) + list_del(&s->update); + tp->nr_lines--; + free_string(&tp->freemem, s); + } +} + +/* * Write request completion callback. */ static void @@ -405,7 +427,10 @@ tty3270_update(struct tty3270 *tp) if (raw3270_request_add_data(wrq, str, len) != 0) break; list_del_init(&s->update); - sba = s->string + s->len - 3; + if (s->string[s->len - 4] == TO_RA) + sba = s->string + s->len - 3; + else + sba = invalid_sba; } if (list_empty(&tp->update)) updated |= TTY_UPDATE_LIST; @@ -622,6 +647,16 @@ tty3270_issue_read(struct tty3270 *tp, int lock) } /* + * Hang up the tty + */ +static void +tty3270_hangup_tasklet(struct tty3270 *tp) +{ + tty_port_tty_hangup(&tp->port, true); + raw3270_put_view(&tp->view); +} + +/* * Switch to the tty view. */ static int @@ -642,7 +677,7 @@ tty3270_deactivate(struct raw3270_view *view) del_timer(&tp->timer); } -static int +static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Schedule tasklet to read aid. */ @@ -654,17 +689,19 @@ tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { rq->rc = -EIO; - else + raw3270_get_view(&tp->view); + tasklet_schedule(&tp->hanglet); + } else { /* Normal end. Copy residual count. */ rq->rescnt = irb->scsw.cmd.count; + } } else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { /* Interrupt without an outstanding request -> update all */ tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); } - return RAW3270_IO_DONE; } /* @@ -716,6 +753,9 @@ tty3270_alloc_view(void) tasklet_init(&tp->readlet, (void (*)(unsigned long)) tty3270_read_tasklet, (unsigned long) tp->read); + tasklet_init(&tp->hanglet, + (void (*)(unsigned long)) tty3270_hangup_tasklet, + (unsigned long) tp); INIT_WORK(&tp->resize_work, tty3270_resize_work); return tp; @@ -814,6 +854,7 @@ static void tty3270_resize_work(struct work_struct *work) return; /* Switch to new output size */ spin_lock_bh(&tp->view.lock); + tty3270_blank_screen(tp); oscreen = tp->screen; orows = tp->view.rows; tp->view.model = tp->n_model; @@ -824,7 +865,6 @@ static void tty3270_resize_work(struct work_struct *work) free_string(&tp->freemem, tp->status); tty3270_create_prompt(tp); tty3270_create_status(tp); - tp->nr_up = 0; while (tp->nr_lines < tp->view.rows - 2) tty3270_blank_line(tp); tp->update_flags = TTY_UPDATE_ALL; @@ -838,6 +878,7 @@ static void tty3270_resize_work(struct work_struct *work) ws.ws_row = tp->view.rows - 2; ws.ws_col = tp->view.cols; tty_do_resize(tty, &ws); + tty_kref_put(tty); } static void @@ -845,6 +886,8 @@ tty3270_resize(struct raw3270_view *view, int model, int rows, int cols) { struct tty3270 *tp = container_of(view, struct tty3270, view); + if (tp->n_model == model && tp->n_rows == rows && tp->n_cols == cols) + return; tp->n_model = model; tp->n_rows = rows; tp->n_cols = cols; @@ -923,10 +966,8 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; tp->port.low_latency = 0; - /* why to reassign? */ - tty_port_tty_set(&tp->port, tty); tp->inattr = TF_INPUT; - return tty_port_install(&tp->port, driver, tty); + goto port_install; } if (tty3270_max_index < tty->index + 1) tty3270_max_index = tty->index + 1; @@ -952,7 +993,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) return rc; } - tty_port_tty_set(&tp->port, tty); tp->port.low_latency = 0; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; @@ -974,6 +1014,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) raw3270_activate_view(&tp->view); +port_install: rc = tty_port_install(&tp->port, driver, tty); if (rc) { raw3270_put_view(&tp->view); @@ -1010,18 +1051,18 @@ tty3270_close(struct tty_struct *tty, struct file * filp) if (tty->count > 1) return; - if (tp) { - tty->driver_data = NULL; + if (tp) tty_port_tty_set(&tp->port, NULL); - } } static void tty3270_cleanup(struct tty_struct *tty) { struct tty3270 *tp = tty->driver_data; - if (tp) + if (tp) { + tty->driver_data = NULL; raw3270_put_view(&tp->view); + } } /* @@ -1788,7 +1829,22 @@ tty3270_unthrottle(struct tty_struct * tty) static void tty3270_hangup(struct tty_struct *tty) { - // FIXME: implement + struct tty3270 *tp; + + tp = tty->driver_data; + if (!tp) + return; + spin_lock_bh(&tp->view.lock); + tp->cx = tp->saved_cx = 0; + tp->cy = tp->saved_cy = 0; + tp->highlight = tp->saved_highlight = TAX_RESET; + tp->f_color = tp->saved_f_color = TAC_RESET; + tty3270_blank_screen(tp); + while (tp->nr_lines < tp->view.rows - 2) + tty3270_blank_line(tp); + tp->update_flags = TTY_UPDATE_ALL; + spin_unlock_bh(&tp->view.lock); + tty3270_set_timer(tp, 1); } static void |