📄 tty3270.c
字号:
*/static voidtty3270_issue_read(struct tty3270 *tp, int lock){ struct raw3270_request *rrq; int rc; rrq = xchg(&tp->read, 0); if (!rrq) /* Read already scheduled. */ return; rrq->callback = tty3270_read_callback; rrq->callback_data = tp; raw3270_request_set_cmd(rrq, TC_READMOD); raw3270_request_set_data(rrq, tp->input->string, tp->input->len); /* Issue the read modified request. */ if (lock) { rc = raw3270_start(&tp->view, rrq); } else rc = raw3270_start_irq(&tp->view, rrq); if (rc) { raw3270_request_reset(rrq); xchg(&tp->read, rrq); }}/* * Switch to the tty view. */static inttty3270_activate(struct raw3270_view *view){ struct tty3270 *tp; unsigned long flags; tp = (struct tty3270 *) view; spin_lock_irqsave(&tp->view.lock, flags); tp->nr_up = 0; tty3270_rebuild_update(tp); tty3270_update_status(tp); tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); spin_unlock_irqrestore(&tp->view.lock, flags); return 0;}static voidtty3270_deactivate(struct raw3270_view *view){}static inttty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb){ /* Handle ATTN. Schedule tasklet to read aid. */ if (irb->scsw.dstat & DEV_STAT_ATTENTION) { if (!tp->throttle) tty3270_issue_read(tp, 0); else tp->attn = 1; } if (rq) { if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE;}/* * Allocate tty3270 structure. */static struct tty3270 *tty3270_alloc_view(void){ struct tty3270 *tp; int pages; tp = kmalloc(sizeof(struct tty3270),GFP_KERNEL); if (!tp) goto out_err; memset(tp, 0, sizeof(struct tty3270)); tp->freemem_pages = kmalloc(sizeof(void *) * TTY3270_STRING_PAGES, GFP_KERNEL); if (!tp->freemem_pages) goto out_tp; INIT_LIST_HEAD(&tp->freemem); init_timer(&tp->timer); for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) { tp->freemem_pages[pages] = (void *) __get_free_pages(GFP_KERNEL|GFP_DMA, 0); if (!tp->freemem_pages[pages]) goto out_pages; add_string_memory(&tp->freemem, tp->freemem_pages[pages], PAGE_SIZE); } tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE); if (IS_ERR(tp->write)) goto out_pages; tp->read = raw3270_request_alloc(0); if (IS_ERR(tp->read)) goto out_write; tp->kreset = raw3270_request_alloc(1); if (IS_ERR(tp->kreset)) goto out_read; tp->kbd = kbd_alloc(); if (!tp->kbd) goto out_reset; return tp;out_reset: raw3270_request_free(tp->kreset);out_read: raw3270_request_free(tp->read);out_write: raw3270_request_free(tp->write);out_pages: while (pages--) free_pages((unsigned long) tp->freemem_pages[pages], 0); kfree(tp->freemem_pages);out_tp: kfree(tp);out_err: return ERR_PTR(-ENOMEM);}/* * Free tty3270 structure. */static voidtty3270_free_view(struct tty3270 *tp){ int pages; kbd_free(tp->kbd); raw3270_request_free(tp->kreset); raw3270_request_free(tp->read); raw3270_request_free(tp->write); for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) free_pages((unsigned long) tp->freemem_pages[pages], 0); kfree(tp->freemem_pages); kfree(tp);}/* * Allocate tty3270 screen. */static inttty3270_alloc_screen(struct tty3270 *tp){ unsigned long size; int lines; size = sizeof(struct tty3270_line) * (tp->view.rows - 2); tp->screen = kmalloc(size, GFP_KERNEL); if (!tp->screen) goto out_err; memset(tp->screen, 0, size); for (lines = 0; lines < tp->view.rows - 2; lines++) { size = sizeof(struct tty3270_cell) * tp->view.cols; tp->screen[lines].cells = kmalloc(size, GFP_KERNEL); if (!tp->screen[lines].cells) goto out_screen; memset(tp->screen[lines].cells, 0, size); } return 0;out_screen: while (lines--) kfree(tp->screen[lines].cells); kfree(tp->screen);out_err: return -ENOMEM;}/* * Free tty3270 screen. */static voidtty3270_free_screen(struct tty3270 *tp){ int lines; for (lines = 0; lines < tp->view.rows - 2; lines++) kfree(tp->screen[lines].cells); kfree(tp->screen);}/* * Unlink tty3270 data structure from tty. */static voidtty3270_release(struct raw3270_view *view){ struct tty3270 *tp; struct tty_struct *tty; tp = (struct tty3270 *) view; tty = tp->tty; if (tty) { tty->driver_data = 0; tp->tty = tp->kbd->tty = 0; tty_hangup(tty); raw3270_put_view(&tp->view); }}/* * Free tty3270 data structure */static voidtty3270_free(struct raw3270_view *view){ tty3270_free_screen((struct tty3270 *) view); tty3270_free_view((struct tty3270 *) view);}/* * Delayed freeing of tty3270 views. */static voidtty3270_del_views(void){ struct tty3270 *tp; int i; for (i = 0; i < tty3270_max_index; i++) { tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR); if (!IS_ERR(tp)) raw3270_del_view(&tp->view); }}struct raw3270_fn tty3270_fn = { .activate = tty3270_activate, .deactivate = tty3270_deactivate, .intv = (void *) tty3270_irq, .release = tty3270_release, .free = tty3270_free};/* * This routine is called whenever a 3270 tty is opened. */static inttty3270_open(struct tty_struct *tty, struct file * filp){ struct tty3270 *tp; int i, rc; if (tty->count > 1) return 0; /* Check if the tty3270 is already there. */ tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); if (!IS_ERR(tp)) { tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; tty->low_latency = 0; tp->tty = tty; tp->kbd->tty = tty; tp->inattr = TF_INPUT; return 0; } if (tty3270_max_index < tty->index + 1) tty3270_max_index = tty->index + 1; /* Quick exit if there is no device for tty->index. */ if (PTR_ERR(tp) == -ENODEV) return -ENODEV; /* Allocate tty3270 structure on first open. */ tp = tty3270_alloc_view(); if (IS_ERR(tp)) return PTR_ERR(tp); INIT_LIST_HEAD(&tp->lines); INIT_LIST_HEAD(&tp->update); INIT_LIST_HEAD(&tp->rcl_lines); tp->rcl_max = 20; init_timer(&tp->timer); tasklet_init(&tp->readlet, (void (*)(unsigned long)) tty3270_read_tasklet, (unsigned long) tp->read); rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index + RAW3270_FIRSTMINOR); if (rc) { tty3270_free_view(tp); return rc; } rc = tty3270_alloc_screen(tp); if (rc) { raw3270_put_view(&tp->view); raw3270_del_view(&tp->view); return rc; } tp->tty = tty; tty->low_latency = 0; tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; tty3270_create_prompt(tp); tty3270_create_status(tp); tty3270_update_status(tp); /* Create blank line for every line in the tty output area. */ for (i = 0; i < tp->view.rows - 2; i++) tty3270_blank_line(tp); tp->kbd->tty = tty; tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty; tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward; tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward; tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward; kbd_ascebc(tp->kbd, tp->view.ascebc); raw3270_activate_view(&tp->view); return 0;}/* * This routine is called when the 3270 tty is closed. We wait * for the remaining request to be completed. Then we clean up. */static voidtty3270_close(struct tty_struct *tty, struct file * filp){ struct tty3270 *tp; if (tty->count > 1) return; tp = (struct tty3270 *) tty->driver_data; if (tp) { tty->driver_data = 0; tp->tty = tp->kbd->tty = 0; raw3270_put_view(&tp->view); }}/* * We always have room. */static inttty3270_write_room(struct tty_struct *tty){ return INT_MAX;}/* * Insert character into the screen at the current position with the * current color and highlight. This function does NOT do cursor movement. */static voidtty3270_put_character(struct tty3270 *tp, char ch){ struct tty3270_line *line; struct tty3270_cell *cell; line = tp->screen + tp->cy; if (line->len <= tp->cx) { while (line->len < tp->cx) { cell = line->cells + line->len; cell->character = tp->view.ascebc[' ']; cell->highlight = tp->highlight; cell->f_color = tp->f_color; line->len++; } line->len++; } cell = line->cells + tp->cx; cell->character = tp->view.ascebc[(unsigned int) ch]; cell->highlight = tp->highlight; cell->f_color = tp->f_color;}/* * Convert a tty3270_line to a 3270 data fragment usable for output. */static voidtty3270_convert_line(struct tty3270 *tp, int line_nr){ struct tty3270_line *line; struct tty3270_cell *cell; struct string *s, *n; unsigned char highlight; unsigned char f_color; char *cp; int flen, i; /* Determine how long the fragment will be. */ flen = 3; /* Prefix (TO_SBA). */ line = tp->screen + line_nr; flen += line->len; highlight = TAX_RESET; f_color = TAC_RESET; for (i = 0, cell = line->cells; i < line->len; i++, cell++) { if (cell->highlight != highlight) { flen += 3; /* TO_SA to switch highlight. */ highlight = cell->highlight; } if (cell->f_color != f_color) { flen += 3; /* TO_SA to switch color. */ f_color = cell->f_color; } } if (highlight != TAX_RESET) flen += 3; /* TO_SA to reset hightlight. */ if (f_color != TAC_RESET) flen += 3; /* TO_SA to reset color. */ if (line->len < tp->view.cols) flen += 4; /* Postfix (TO_RA). */ /* Find the line in the list. */ i = tp->view.rows - 2 - line_nr; list_for_each_entry_reverse(s, &tp->lines, list) if (--i <= 0) break; /* * Check if the line needs to get reallocated. */ if (s->len != flen) { /* Reallocate string. */ n = tty3270_alloc_string(tp, flen); list_add(&n->list, &s->list); list_del_init(&s->list); if (!list_empty(&s->update)) list_del_init(&s->update); free_string(&tp->freemem, s); s = n; } /* Write 3270 data fragment. */ cp = s->string; *cp++ = TO_SBA; *cp++ = 0; *cp++ = 0; highlight = TAX_RESET; f_color = TAC_RESET; for (i = 0, cell = line->cells; i < line->len; i++, cell++) { if (cell->highlight != highlight) { *cp++ = TO_SA; *cp++ = TAT_EXTHI; *cp++ = cell->highlight; highlight = cell->highlight; } if (cell->f_color != f_color) { *cp++ = TO_SA; *cp++ = TAT_COLOR; *cp++ = cell->f_color; f_color = cell->f_color; } *cp++ = cell->character; } if (highlight != TAX_RESET) { *cp++ = TO_SA; *cp++ = TAT_EXTHI; *cp++ = TAX_RESET; } if (f_color != TAC_RESET) { *cp++ = TO_SA; *cp++ = TAT_COLOR; *cp++ = TAC_RESET; } if (line->len < tp->view.cols) { *cp++ = TO_RA; *cp++ = 0; *cp++ = 0; *cp++ = 0; } if (tp->nr_up + line_nr < tp->view.rows - 2) { /* Line is currently visible on screen. */ tty3270_update_string(tp, s, line_nr); /* Add line to update list. */ if (list_empty(&s->update)) { list_add_tail(&s->update, &tp->update); tp->update_flags |= TTY_UPDATE_LIST; } }}/* * Do carriage return. */static voidtty3270_cr(struct tty3270 *tp){ tp->cx = 0;}/* * Do line feed. */static voidtty3270_lf(struct tty3270 *tp){ struct tty3270_line temp; int i; tty3270_convert_line(tp, tp->cy); if (tp->cy < tp->view.rows - 3) { tp->cy++; return; } /* Last line just filled up. Add new, blank line. */ tty3270_blank_line(tp); temp = tp->screen[0]; temp.len = 0; for (i = 0; i < tp->view.rows - 3; i++) tp->screen[i] = tp->screen[i+1]; tp->screen[tp->view.rows - 3] = temp; tty3270_rebuild_update(tp);}static voidtty3270_ri(struct tty3270 *tp){ if (tp->cy > 0) { tty3270_convert_line(tp, tp->cy); tp->cy--; }}/* * Insert characters at current position. */static voidtty3270_insert_characters(struct tty3270 *tp, int n){ struct tty3270_line *line; int k; line = tp->screen + tp->cy; while (line->len < tp->cx) { line->cells[line->len].character = tp->view.ascebc[' ']; line->cells[line->len].highlight = TAX_RESET; line->cells[line->len].f_color = TAC_RESET; line->len++; } if (n > tp->view.cols - tp->cx) n = tp->view.cols - tp->cx; k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n); while (k--) line->cells[tp->cx + n + k] = line->cells[tp->cx + k]; line->len += n; if (line->len > tp->view.cols) line->len = tp->view.cols; while (n-- > 0) { line->cells[tp->cx + n].character = tp->view.ascebc[' ']; line->cells[tp->cx + n].highlight = tp->highlight; line->cells[tp->cx + n].f_color = tp->f_color; }}/* * Delete characters at current position. */static voidtty3270_delete_characters(struct tty3270 *tp, int n){ struct tty3270_line *line; int i; line = tp->screen + tp->cy; if (line->len <= tp->cx) return; if (line->len - tp->cx <= n) { line->len = tp->cx; return; } for (i = tp->cx; i + n < line->len; i++) line->cells[i] = line->cells[i + n]; line->len -= n;}/* * Erase characters at current position. */static voidtty3270_erase_characters(struct tty3270 *tp, int n){ struct tty3270_line *line; struct tty3270_cell *cell; line = tp->screen + tp->cy; while (line->len > tp->cx && n-- > 0) { cell = line->cells + tp->cx++; cell->character = ' '; cell->highlight = TAX_RESET; cell->f_color = TAC_RESET; } tp->cx += n; tp->cx = min_t(int, tp->cx, tp->view.cols - 1);}/* * Erase line, 3 different cases: * Esc [ 0 K Erase from current position to end of line inclusive * Esc [ 1 K Erase from beginning of line to current position inclusive * Esc [ 2 K Erase entire line (without moving cursor) */static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -