📄 con3270.c
字号:
/* * drivers/s390/char/con3270.c * IBM/3270 Driver - console view. * * Author(s): * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation */#include <linux/config.h>#include <linux/bootmem.h>#include <linux/console.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/list.h>#include <linux/types.h>#include <asm/ccwdev.h>#include <asm/cio.h>#include <asm/cpcmd.h>#include <asm/ebcdic.h>#include "raw3270.h"#include "ctrlchar.h"#define CON3270_OUTPUT_BUFFER_SIZE 1024#define CON3270_STRING_PAGES 4static struct raw3270_fn con3270_fn;/* * Main 3270 console view data structure. */struct con3270 { struct raw3270_view view; spinlock_t lock; struct list_head freemem; /* list of free memory for strings. */ /* Output stuff. */ struct list_head lines; /* list of lines. */ struct list_head update; /* list of lines to update. */ int line_nr; /* line number for next update. */ int nr_lines; /* # lines in list. */ int nr_up; /* # lines up in history. */ unsigned long update_flags; /* Update indication bits. */ struct string *cline; /* current output line. */ struct string *status; /* last line of display. */ struct raw3270_request *write; /* single write request. */ struct timer_list timer; /* Input stuff. */ struct string *input; /* input string for read request. */ struct raw3270_request *read; /* single read request. */ struct raw3270_request *kreset; /* single keyboard reset request. */ struct tasklet_struct readlet; /* tasklet to issue read request. */};static struct con3270 *condev;/* con3270->update_flags. See con3270_update for details. */#define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */#define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */#define CON_UPDATE_STATUS 4 /* Update status line. */#define CON_UPDATE_ALL 7static void con3270_update(struct con3270 *);/* * Setup timeout for a device. On timeout trigger an update. */voidcon3270_set_timer(struct con3270 *cp, int expires){ if (expires == 0) { if (timer_pending(&cp->timer)) del_timer(&cp->timer); return; } if (timer_pending(&cp->timer) && mod_timer(&cp->timer, jiffies + expires)) return; cp->timer.function = (void (*)(unsigned long)) con3270_update; cp->timer.data = (unsigned long) cp; cp->timer.expires = jiffies + expires; add_timer(&cp->timer);}/* * The status line is the last line of the screen. It shows the string * "console view" in the lower left corner and "Running"/"More..."/"Holding" * in the lower right corner of the screen. */static voidcon3270_update_status(struct con3270 *cp){ char *str; str = (cp->nr_up != 0) ? "History" : "Running"; memcpy(cp->status->string + 24, str, 7); codepage_convert(cp->view.ascebc, cp->status->string + 24, 7); cp->update_flags |= CON_UPDATE_STATUS;}static voidcon3270_create_status(struct con3270 *cp){ static const unsigned char blueprint[] = { TO_SBA, 0, 0, TO_SF,TF_LOG,TO_SA,TAT_COLOR, TAC_GREEN, 'c','o','n','s','o','l','e',' ','v','i','e','w', TO_RA,0,0,0,'R','u','n','n','i','n','g',TO_SF,TF_LOG }; cp->status = alloc_string(&cp->freemem, sizeof(blueprint)); /* Copy blueprint to status line */ memcpy(cp->status->string, blueprint, sizeof(blueprint)); /* Set TO_RA addresses. */ raw3270_buffer_address(cp->view.dev, cp->status->string + 1, cp->view.cols * (cp->view.rows - 1)); raw3270_buffer_address(cp->view.dev, cp->status->string + 21, cp->view.cols * cp->view.rows - 8); /* Convert strings to ebcdic. */ codepage_convert(cp->view.ascebc, cp->status->string + 8, 12); codepage_convert(cp->view.ascebc, cp->status->string + 24, 7);}/* * Set output offsets to 3270 datastream fragment of a console string. */static voidcon3270_update_string(struct con3270 *cp, struct string *s, int nr){ if (s->len >= cp->view.cols - 5) return; raw3270_buffer_address(cp->view.dev, s->string + s->len - 3, cp->view.cols * (nr + 1));}/* * Rebuild update list to print all lines. */static voidcon3270_rebuild_update(struct con3270 *cp){ struct string *s, *n; int nr; /* * Throw away update list and create a new one, * containing all lines that will fit on the screen. */ list_for_each_entry_safe(s, n, &cp->update, update) list_del_init(&s->update); nr = cp->view.rows - 2 + cp->nr_up; list_for_each_entry_reverse(s, &cp->lines, list) { if (nr < cp->view.rows - 1) list_add(&s->update, &cp->update); if (--nr < 0) break; } cp->line_nr = 0; cp->update_flags |= CON_UPDATE_LIST;}/* * Alloc string for size bytes. Free strings from history if necessary. */static struct string *con3270_alloc_string(struct con3270 *cp, size_t size){ struct string *s, *n; s = alloc_string(&cp->freemem, size); if (s) return s; list_for_each_entry_safe(s, n, &cp->lines, list) { list_del(&s->list); if (!list_empty(&s->update)) list_del(&s->update); cp->nr_lines--; if (free_string(&cp->freemem, s) >= size) break; } s = alloc_string(&cp->freemem, size); BUG_ON(!s); if (cp->nr_up != 0 && cp->nr_up + cp->view.rows > cp->nr_lines) { cp->nr_up = cp->nr_lines - cp->view.rows + 1; con3270_rebuild_update(cp); con3270_update_status(cp); } return s;}/* * Write completion callback. */static voidcon3270_write_callback(struct raw3270_request *rq, void *data){ raw3270_request_reset(rq); xchg(&((struct con3270 *) rq->view)->write, rq);}/* * Update console display. */static voidcon3270_update(struct con3270 *cp){ struct raw3270_request *wrq; char wcc, prolog[6]; unsigned long flags; unsigned long updated; struct string *s, *n; int rc; if (cp->view.dev) raw3270_activate_view(&cp->view); wrq = xchg(&cp->write, 0); if (!wrq) { con3270_set_timer(cp, 1); return; } spin_lock_irqsave(&cp->view.lock, flags); updated = 0; if (cp->update_flags & CON_UPDATE_ERASE) { /* Use erase write alternate to initialize display. */ raw3270_request_set_cmd(wrq, TC_EWRITEA); updated |= CON_UPDATE_ERASE; } else raw3270_request_set_cmd(wrq, TC_WRITE); wcc = TW_NONE; raw3270_request_add_data(wrq, &wcc, 1); /* * Update status line. */ if (cp->update_flags & CON_UPDATE_STATUS) if (raw3270_request_add_data(wrq, cp->status->string, cp->status->len) == 0) updated |= CON_UPDATE_STATUS; if (cp->update_flags & CON_UPDATE_LIST) { prolog[0] = TO_SBA; prolog[3] = TO_SA; prolog[4] = TAT_COLOR; prolog[5] = TAC_TURQ; raw3270_buffer_address(cp->view.dev, prolog + 1, cp->view.cols * cp->line_nr); raw3270_request_add_data(wrq, prolog, 6); /* Write strings in the update list to the screen. */ list_for_each_entry_safe(s, n, &cp->update, update) { if (s != cp->cline) con3270_update_string(cp, s, cp->line_nr); if (raw3270_request_add_data(wrq, s->string, s->len) != 0) break; list_del_init(&s->update); if (s != cp->cline) cp->line_nr++; } if (list_empty(&cp->update)) updated |= CON_UPDATE_LIST; } wrq->callback = con3270_write_callback; rc = raw3270_start(&cp->view, wrq); if (rc == 0) { cp->update_flags &= ~updated; if (cp->update_flags) con3270_set_timer(cp, 1); } else { raw3270_request_reset(wrq); xchg(&cp->write, wrq); } spin_unlock_irqrestore(&cp->view.lock, flags);}/* * Read tasklet. */static voidcon3270_read_tasklet(struct raw3270_request *rrq){ static char kreset_data = TW_KR; struct con3270 *cp; unsigned long flags; int nr_up, deactivate; cp = (struct con3270 *) rrq->view; spin_lock_irqsave(&cp->view.lock, flags); nr_up = cp->nr_up; deactivate = 0; /* Check aid byte. */ switch (cp->input->string[0]) { case 0x7d: /* enter: jump to bottom. */ nr_up = 0; break; case 0xf3: /* PF3: deactivate the console view. */ deactivate = 1; break; case 0x6d: /* clear: start from scratch. */ con3270_rebuild_update(cp); cp->update_flags = CON_UPDATE_ALL; con3270_set_timer(cp, 1); break; case 0xf7: /* PF7: do a page up in the console log. */ nr_up += cp->view.rows - 2; if (nr_up + cp->view.rows - 1 > cp->nr_lines) { nr_up = cp->nr_lines - cp->view.rows + 1; if (nr_up < 0) nr_up = 0; } break; case 0xf8: /* PF8: do a page down in the console log. */ nr_up -= cp->view.rows - 2; if (nr_up < 0) nr_up = 0; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -