⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty3270.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  drivers/s390/char/tty3270.c *    IBM/3270 Driver - tty functions. * *  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/module.h>#include <linux/types.h>#include <linux/kdev_t.h>#include <linux/tty.h>#include <linux/vt_kern.h>#include <linux/init.h>#include <linux/console.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/bootmem.h>#include <asm/ccwdev.h>#include <asm/cio.h>#include <asm/ebcdic.h>#include <asm/uaccess.h>#include "raw3270.h"#include "keyboard.h"#define TTY3270_CHAR_BUF_SIZE 256#define TTY3270_OUTPUT_BUFFER_SIZE 1024#define TTY3270_STRING_PAGES 5struct tty_driver *tty3270_driver;static int tty3270_max_index;struct raw3270_fn tty3270_fn;struct tty3270_cell {	unsigned char character;	unsigned char highlight;	unsigned char f_color;};struct tty3270_line {	struct tty3270_cell *cells;	int len;};#define ESCAPE_NPAR 8/* * The main tty view data structure. * FIXME: * 1) describe line orientation & lines list concept against screen * 2) describe conversion of screen to lines * 3) describe line format. */struct tty3270 {	struct raw3270_view view;	struct tty_struct *tty;		/* Pointer to tty structure */	void **freemem_pages;		/* Array of pages used for freemem. */	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. */	unsigned char wcc;		/* Write control character. */	int nr_lines;			/* # lines in list. */	int nr_up;			/* # lines up in history. */	unsigned long update_flags;	/* Update indication bits. */	struct string *status;		/* Lower right of display. */	struct raw3270_request *write;	/* Single write request. */	struct timer_list timer;	/* Output delay timer. */	/* Current tty screen. */	unsigned int cx, cy;		/* Current output position. */	unsigned int highlight;		/* Blink/reverse/underscore */	unsigned int f_color;		/* Foreground color */	struct tty3270_line *screen;	/* Input stuff. */	struct string *prompt;		/* Output string for input area. */	struct string *input;		/* Input string for read request. */	struct raw3270_request *read;	/* Single read request. */	struct raw3270_request *kreset;	/* Single keyboard reset request. */	unsigned char inattr;		/* Visible/invisible input. */	int throttle, attn;		/* tty throttle/unthrottle. */	struct tasklet_struct readlet;	/* Tasklet to issue read request. */	struct kbd_data *kbd;		/* key_maps stuff. */	/* Escape sequence parsing. */	int esc_state, esc_ques, esc_npar;	int esc_par[ESCAPE_NPAR];	unsigned int saved_cx, saved_cy;	unsigned int saved_highlight, saved_f_color;	/* Command recalling. */	struct list_head rcl_lines;	/* List of recallable lines. */	struct list_head *rcl_walk;	/* Point in rcl_lines list. */	int rcl_nr, rcl_max;		/* Number/max number of rcl_lines. */	/* Character array for put_char/flush_chars. */	unsigned int char_count;	char char_buf[TTY3270_CHAR_BUF_SIZE];};/* tty3270->update_flags. See tty3270_update for details. */#define TTY_UPDATE_ERASE	1	/* Use EWRITEA instead of WRITE. */#define TTY_UPDATE_LIST		2	/* Update lines in tty3270->update. */#define TTY_UPDATE_INPUT	4	/* Update input line. */#define TTY_UPDATE_STATUS	8	/* Update status line. */#define TTY_UPDATE_ALL		15static void tty3270_update(struct tty3270 *);/* * Setup timeout for a device. On timeout trigger an update. */voidtty3270_set_timer(struct tty3270 *tp, int expires){	if (expires == 0) {		if (timer_pending(&tp->timer) && del_timer(&tp->timer))			raw3270_put_view(&tp->view);		return;	}	if (timer_pending(&tp->timer) &&	    mod_timer(&tp->timer, jiffies + expires))		return;	raw3270_get_view(&tp->view);	tp->timer.function = (void (*)(unsigned long)) tty3270_update;	tp->timer.data = (unsigned long) tp;	tp->timer.expires = jiffies + expires;	add_timer(&tp->timer);}/* * The input line are the two last lines of the screen. */static voidtty3270_update_prompt(struct tty3270 *tp, char *input, int count){	struct string *line;	unsigned int off;	line = tp->prompt;	if (count != 0)		line->string[5] = TF_INMDT;	else		line->string[5] = tp->inattr;	if (count > tp->view.cols * 2 - 11)		count = tp->view.cols * 2 - 11;	memcpy(line->string + 6, input, count);	line->string[6 + count] = TO_IC;	/* Clear to end of input line. */	if (count < tp->view.cols * 2 - 11) {		line->string[7 + count] = TO_RA;		line->string[10 + count] = 0;		off = tp->view.cols * tp->view.rows - 9;		raw3270_buffer_address(tp->view.dev, line->string+count+8, off);		line->len = 11 + count;	} else		line->len = 7 + count;	tp->update_flags |= TTY_UPDATE_INPUT;}static voidtty3270_create_prompt(struct tty3270 *tp){	static const unsigned char blueprint[] =		{ TO_SBA, 0, 0, 0x6e, TO_SF, TF_INPUT,		  /* empty input string */		  TO_IC, TO_RA, 0, 0, 0 };	struct string *line;	unsigned int offset;	line = alloc_string(&tp->freemem,			    sizeof(blueprint) + tp->view.cols * 2 - 9);	tp->prompt = line;	tp->inattr = TF_INPUT;	/* Copy blueprint to status line */	memcpy(line->string, blueprint, sizeof(blueprint));	line->len = sizeof(blueprint);	/* Set output offsets. */	offset = tp->view.cols * (tp->view.rows - 2);	raw3270_buffer_address(tp->view.dev, line->string + 1, offset);	offset = tp->view.cols * tp->view.rows - 9;	raw3270_buffer_address(tp->view.dev, line->string + 8, offset);	/* Allocate input string for reading. */	tp->input = alloc_string(&tp->freemem, tp->view.cols * 2 - 9 + 6);}/* * The status line is the last line of the screen. It shows the string * "Running"/"Holding" in the lower right corner of the screen. */static voidtty3270_update_status(struct tty3270 * tp){	char *str;	str = (tp->nr_up != 0) ? "History" : "Running";	memcpy(tp->status->string + 8, str, 7);	codepage_convert(tp->view.ascebc, tp->status->string + 8, 7);	tp->update_flags |= TTY_UPDATE_STATUS;}static voidtty3270_create_status(struct tty3270 * tp){	static const unsigned char blueprint[] =		{ TO_SBA, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR, TAC_GREEN,		  0, 0, 0, 0, 0, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR,		  TAC_RESET };	struct string *line;	unsigned int offset;	line = alloc_string(&tp->freemem,sizeof(blueprint));	tp->status = line;	/* Copy blueprint to status line */	memcpy(line->string, blueprint, sizeof(blueprint));	/* Set address to start of status string (= last 9 characters). */	offset = tp->view.cols * tp->view.rows - 9;	raw3270_buffer_address(tp->view.dev, line->string + 1, offset);}/* * Set output offsets to 3270 datastream fragment of a tty string. * (TO_SBA offset at the start and TO_RA offset at the end of the string) */static voidtty3270_update_string(struct tty3270 *tp, struct string *line, int nr){	unsigned char *cp;	raw3270_buffer_address(tp->view.dev, line->string + 1,			       tp->view.cols * nr);	cp = line->string + line->len - 4;	if (*cp == TO_RA)		raw3270_buffer_address(tp->view.dev, cp + 1,				       tp->view.cols * (nr + 1));}/* * Rebuild update list to print all lines. */static voidtty3270_rebuild_update(struct tty3270 *tp){	struct string *s, *n;	int line, nr_up;	/* 	 * 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, &tp->update, update)		list_del_init(&s->update);	line = tp->view.rows - 3;	nr_up = tp->nr_up;	list_for_each_entry_reverse(s, &tp->lines, list) {		if (nr_up > 0) {			nr_up--;			continue;		}		tty3270_update_string(tp, s, line);		list_add(&s->update, &tp->update);		if (--line < 0)			break;	}	tp->update_flags |= TTY_UPDATE_LIST;}/* * Alloc string for size bytes. If there is not enough room in * freemem, free strings until there is room. */static struct string *tty3270_alloc_string(struct tty3270 *tp, size_t size){	struct string *s, *n;	s = alloc_string(&tp->freemem, size);	if (s)		return s;	list_for_each_entry_safe(s, n, &tp->lines, list) {		BUG_ON(tp->nr_lines <= tp->view.rows - 2);		list_del(&s->list);		if (!list_empty(&s->update))			list_del(&s->update);		tp->nr_lines--;		if (free_string(&tp->freemem, s) >= size)			break;	}	s = alloc_string(&tp->freemem, size);	BUG_ON(!s);	if (tp->nr_up != 0 &&	    tp->nr_up + tp->view.rows - 2 >= tp->nr_lines) {		tp->nr_up = tp->nr_lines - tp->view.rows + 2;		tty3270_rebuild_update(tp);		tty3270_update_status(tp);	}	return s;}/* * Add an empty line to the list. */static voidtty3270_blank_line(struct tty3270 *tp){	static const unsigned char blueprint[] =		{ TO_SBA, 0, 0, TO_SA, TAT_EXTHI, TAX_RESET,		  TO_SA, TAT_COLOR, TAC_RESET, TO_RA, 0, 0, 0 };	struct string *s;	s = tty3270_alloc_string(tp, sizeof(blueprint));	memcpy(s->string, blueprint, sizeof(blueprint));	s->len = sizeof(blueprint);	list_add_tail(&s->list, &tp->lines);	tp->nr_lines++;	if (tp->nr_up != 0)		tp->nr_up++;}/* * Write request completion callback. */static voidtty3270_write_callback(struct raw3270_request *rq, void *data){	struct tty3270 *tp;	tp = (struct tty3270 *) rq->view;	if (rq->rc != 0) {		/* Write wasn't successfull. Refresh all. */		tty3270_rebuild_update(tp);		tp->update_flags = TTY_UPDATE_ALL;		tty3270_set_timer(tp, 1);	}	raw3270_request_reset(rq);	xchg(&tp->write, rq);}/* * Update 3270 display. */static voidtty3270_update(struct tty3270 *tp){	static char invalid_sba[2] = { 0xff, 0xff };	struct raw3270_request *wrq;	unsigned long updated;	struct string *s, *n;	char *sba, *str;	int rc, len;	wrq = xchg(&tp->write, 0);	if (!wrq) {		tty3270_set_timer(tp, 1);		return;	}	spin_lock(&tp->view.lock);	updated = 0;	if (tp->update_flags & TTY_UPDATE_ERASE) {		/* Use erase write alternate to erase display. */		raw3270_request_set_cmd(wrq, TC_EWRITEA);		updated |= TTY_UPDATE_ERASE;	} else		raw3270_request_set_cmd(wrq, TC_WRITE);	raw3270_request_add_data(wrq, &tp->wcc, 1);	tp->wcc = TW_NONE;	/*	 * Update status line.	 */	if (tp->update_flags & TTY_UPDATE_STATUS)		if (raw3270_request_add_data(wrq, tp->status->string,					     tp->status->len) == 0)			updated |= TTY_UPDATE_STATUS;	/*	 * Write input line.	 */	if (tp->update_flags & TTY_UPDATE_INPUT)		if (raw3270_request_add_data(wrq, tp->prompt->string,					     tp->prompt->len) == 0)			updated |= TTY_UPDATE_INPUT;	sba = invalid_sba;		if (tp->update_flags & TTY_UPDATE_LIST) {		/* Write strings in the update list to the screen. */		list_for_each_entry_safe(s, n, &tp->update, update) {			str = s->string;			len = s->len;			/*			 * Skip TO_SBA at the start of the string if the			 * last output position matches the start address			 * of this line.			 */			if (s->string[1] == sba[0] && s->string[2] == sba[1])				str += 3, len -= 3;			if (raw3270_request_add_data(wrq, str, len) != 0)				break;			list_del_init(&s->update);			sba = s->string + s->len - 3;		}		if (list_empty(&tp->update))			updated |= TTY_UPDATE_LIST;	}	wrq->callback = tty3270_write_callback;	rc = raw3270_start(&tp->view, wrq);	if (rc == 0) {		tp->update_flags &= ~updated;		if (tp->update_flags)			tty3270_set_timer(tp, 1);	} else {		raw3270_request_reset(wrq);		xchg(&tp->write, wrq);	}	spin_unlock(&tp->view.lock);	raw3270_put_view(&tp->view);}/* * Command recalling. */static voidtty3270_rcl_add(struct tty3270 *tp, char *input, int len){	struct string *s;	tp->rcl_walk = 0;	if (len <= 0)		return;	if (tp->rcl_nr >= tp->rcl_max) {		s = list_entry(tp->rcl_lines.next, struct string, list);		list_del(&s->list);		free_string(&tp->freemem, s);		tp->rcl_nr--;	}	s = tty3270_alloc_string(tp, len);	memcpy(s->string, input, len);	list_add_tail(&s->list, &tp->rcl_lines);	tp->rcl_nr++;}static voidtty3270_rcl_backward(struct kbd_data *kbd){	struct tty3270 *tp;	struct string *s;	tp = kbd->tty->driver_data;	spin_lock_bh(&tp->view.lock);	if (tp->inattr == TF_INPUT) {		if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)			tp->rcl_walk = tp->rcl_walk->prev;		else if (!list_empty(&tp->rcl_lines))			tp->rcl_walk = tp->rcl_lines.prev;		s = tp->rcl_walk ? 			list_entry(tp->rcl_walk, struct string, list) : 0;		if (tp->rcl_walk) {			s = list_entry(tp->rcl_walk, struct string, list);			tty3270_update_prompt(tp, s->string, s->len);		} else			tty3270_update_prompt(tp, 0, 0);		tty3270_set_timer(tp, 1);	}	spin_unlock_bh(&tp->view.lock);}/* * Deactivate tty view. */static voidtty3270_exit_tty(struct kbd_data *kbd){	struct tty3270 *tp;	tp = kbd->tty->driver_data;	raw3270_deactivate_view(&tp->view);}/* * Scroll forward in history. */static voidtty3270_scroll_forward(struct kbd_data *kbd){	struct tty3270 *tp;	int nr_up;	tp = kbd->tty->driver_data;	spin_lock_bh(&tp->view.lock);	nr_up = tp->nr_up - tp->view.rows + 2;	if (nr_up < 0)		nr_up = 0;	if (nr_up != tp->nr_up) {		tp->nr_up = nr_up;		tty3270_rebuild_update(tp);		tty3270_update_status(tp);		tty3270_set_timer(tp, 1);	}	spin_unlock_bh(&tp->view.lock);}/* * Scroll backward in history. */static voidtty3270_scroll_backward(struct kbd_data *kbd){	struct tty3270 *tp;	int nr_up;	tp = kbd->tty->driver_data;	spin_lock_bh(&tp->view.lock);	nr_up = tp->nr_up + tp->view.rows - 2;	if (nr_up + tp->view.rows - 2 > tp->nr_lines)		nr_up = tp->nr_lines - tp->view.rows + 2;	if (nr_up != tp->nr_up) {		tp->nr_up = nr_up;		tty3270_rebuild_update(tp);		tty3270_update_status(tp);		tty3270_set_timer(tp, 1);	}	spin_unlock_bh(&tp->view.lock);}/* * Pass input line to tty. */static voidtty3270_read_tasklet(struct raw3270_request *rrq){	static char kreset_data = TW_KR;	struct tty3270 *tp;	char *input;	int len;	tp = (struct tty3270 *) rrq->view;	spin_lock_bh(&tp->view.lock);	/*	 * Two AID keys are special: For 0x7d (enter) the input line	 * has to be emitted to the tty and for 0x6d the screen	 * needs to be redrawn.	 */	input = 0;	len = 0;	if (tp->input->string[0] == 0x7d) {		/* Enter: write input to tty. */		input = tp->input->string + 6;		len = tp->input->len - 6 - rrq->rescnt;		if (tp->inattr != TF_INPUTN)			tty3270_rcl_add(tp, input, len);		if (tp->nr_up > 0) {			tp->nr_up = 0;			tty3270_rebuild_update(tp);			tty3270_update_status(tp);		}		/* Clear input area. */		tty3270_update_prompt(tp, 0, 0);		tty3270_set_timer(tp, 1);	} else if (tp->input->string[0] == 0x6d) {		/* Display has been cleared. Redraw. */		tty3270_rebuild_update(tp);		tp->update_flags = TTY_UPDATE_ALL;		tty3270_set_timer(tp, 1);	}	spin_unlock_bh(&tp->view.lock);	/* Start keyboard reset command. */	raw3270_request_reset(tp->kreset);	raw3270_request_set_cmd(tp->kreset, TC_WRITE);	raw3270_request_add_data(tp->kreset, &kreset_data, 1);	raw3270_start(&tp->view, tp->kreset);	/* Emit input string. */	if (tp->tty) {		while (len-- > 0)			kbd_keycode(tp->kbd, *input++);		/* Emit keycode for AID byte. */		kbd_keycode(tp->kbd, 256 + tp->input->string[0]);	}	raw3270_request_reset(rrq);	xchg(&tp->read, rrq);	raw3270_put_view(&tp->view);}/* * Read request completion callback. */static voidtty3270_read_callback(struct raw3270_request *rq, void *data){	raw3270_get_view(rq->view);	/* Schedule tasklet to pass input to tty. */	tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);}/* * Issue a read request. Call with device lock.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -