Commit f51320a5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: new 3270 driver.

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

New 3270 device driver.
parent c29c6072
......@@ -2526,17 +2526,17 @@ Your cooperation is appreciated.
1 = /dev/dri/card1 Second graphics card
...
227 char IBM 3270 terminal block-mode access
227 char IBM 3270 terminal Unix tty access
1 = /dev/3270/tty1 First 3270 terminal
2 = /dev/3270/tty2 Seconds 3270 terminal
...
228 char IBM 3270 terminal block-mode access
0 = /dev/3270/tub Controlling interface
1 = /dev/3270/tub1 First 3270 terminal
2 = /dev/3270/tub2 Second 3270 terminal
...
228 char IBM 3270 terminal Unix tty access
1 = /dev/3270/tty1 First 3270 terminal
2 = /dev/3270/tty2 Seconds 3270 terminal
...
229 char IBM iSeries virtual console
0 = /dev/iseries/vtty0 First console port
1 = /dev/iseries/vtty1 Second console port
......
......@@ -159,7 +159,8 @@ CONFIG_UNIX98_PTY_COUNT=2048
#
# S/390 character device drivers
#
# CONFIG_TN3270 is not set
CONFIG_TN3270=y
CONFIG_TN3270_CONSOLE=y
CONFIG_TN3215=y
CONFIG_TN3215_CONSOLE=y
CONFIG_CCW_CONSOLE=y
......
......@@ -2,18 +2,20 @@
# S/390 character devices
#
tub3270-objs := tuball.o tubfs.o tubtty.o \
tubttyaid.o tubttybld.o tubttyscl.o \
tubttyrcl.o tubttysiz.o
obj-y += ctrlchar.o keyboard.o defkeymap.o
tub3270-objs := raw3270.o tty3270.o fs3270.o
obj-$(CONFIG_TN3270) += tub3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
obj-y += ctrlchar.o
obj-$(CONFIG_TN3215) += con3215.o
obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
obj-$(CONFIG_TN3270) += tub3270.o
tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
tape-$(CONFIG_PROC_FS) += tape_proc.o
tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
......
This diff is collapsed.
/* Do not edit this file! It was automatically generated by */
/* loadkeys --mktable defkeymap.map > defkeymap.c */
#include <linux/types.h>
#include <linux/keyboard.h>
#include <linux/kd.h>
u_short plain_map[NR_KEYS] = {
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
0xf020, 0xf000, 0xf0e2, 0xf0e4, 0xf0e0, 0xf0e1, 0xf0e3, 0xf0e5,
0xf0e7, 0xf0f1, 0xf0a2, 0xf02e, 0xf03c, 0xf028, 0xf02b, 0xf07c,
0xf026, 0xf0e9, 0xf0e2, 0xf0eb, 0xf0e8, 0xf0ed, 0xf0ee, 0xf0ef,
0xf0ec, 0xf0df, 0xf021, 0xf024, 0xf02a, 0xf029, 0xf03b, 0xf0ac,
0xf02d, 0xf02f, 0xf0c2, 0xf0c4, 0xf0c0, 0xf0c1, 0xf0c3, 0xf0c5,
0xf0c7, 0xf0d1, 0xf0a6, 0xf02c, 0xf025, 0xf05f, 0xf03e, 0xf03f,
0xf0f8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0c8, 0xf0cd, 0xf0ce, 0xf0cf,
0xf0cc, 0xf060, 0xf03a, 0xf023, 0xf040, 0xf027, 0xf03d, 0xf022,
};
static u_short shift_map[NR_KEYS] = {
0xf0d8, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
0xf068, 0xf069, 0xf0ab, 0xf0bb, 0xf0f0, 0xf0fd, 0xf0fe, 0xf0b1,
0xf0b0, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f, 0xf070,
0xf071, 0xf072, 0xf000, 0xf000, 0xf0e6, 0xf0b8, 0xf0c6, 0xf0a4,
0xf0b5, 0xf07e, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077, 0xf078,
0xf079, 0xf07a, 0xf0a1, 0xf0bf, 0xf0d0, 0xf0dd, 0xf0de, 0xf0ae,
0xf402, 0xf0a3, 0xf0a5, 0xf0b7, 0xf0a9, 0xf0a7, 0xf0b6, 0xf0bc,
0xf0bd, 0xf0be, 0xf05b, 0xf05d, 0xf000, 0xf0a8, 0xf0b4, 0xf0d7,
0xf07b, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
0xf048, 0xf049, 0xf000, 0xf0f4, 0xf0f6, 0xf0f2, 0xf0f3, 0xf0f5,
0xf07d, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f, 0xf050,
0xf051, 0xf052, 0xf0b9, 0xf0fb, 0xf0fc, 0xf0f9, 0xf0fa, 0xf0ff,
0xf05c, 0xf0f7, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057, 0xf058,
0xf059, 0xf05a, 0xf0b2, 0xf0d4, 0xf0d6, 0xf0d2, 0xf0d3, 0xf0d5,
0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
0xf038, 0xf039, 0xf0b3, 0xf0db, 0xf0dc, 0xf0d9, 0xf0da, 0xf000,
};
static u_short ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf11f, 0xf120, 0xf121, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf01a, 0xf003, 0xf212, 0xf004, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf109, 0xf10a, 0xf206, 0xf00a, 0xf200, 0xf200,
};
static u_short shift_ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111, 0xf112,
0xf113, 0xf11e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf100, 0xf101, 0xf211, 0xf103, 0xf104, 0xf105, 0xf20b,
0xf20a, 0xf108, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
};
ushort *key_maps[MAX_NR_KEYMAPS] = {
plain_map, shift_map, 0, 0,
ctrl_map, shift_ctrl_map, 0
};
unsigned int keymap_count = 4;
/*
* Philosophy: most people do not define more strings, but they who do
* often want quite a lot of string space. So, we statically allocate
* the default and allocate dynamically in chunks of 512 bytes.
*/
char func_buf[] = {
'\033', '[', '[', 'A', 0,
'\033', '[', '[', 'B', 0,
'\033', '[', '[', 'C', 0,
'\033', '[', '[', 'D', 0,
'\033', '[', '[', 'E', 0,
'\033', '[', '1', '7', '~', 0,
'\033', '[', '1', '8', '~', 0,
'\033', '[', '1', '9', '~', 0,
'\033', '[', '2', '0', '~', 0,
'\033', '[', '2', '1', '~', 0,
'\033', '[', '2', '3', '~', 0,
'\033', '[', '2', '4', '~', 0,
'\033', '[', '2', '5', '~', 0,
'\033', '[', '2', '6', '~', 0,
'\033', '[', '2', '8', '~', 0,
'\033', '[', '2', '9', '~', 0,
'\033', '[', '3', '1', '~', 0,
'\033', '[', '3', '2', '~', 0,
'\033', '[', '3', '3', '~', 0,
'\033', '[', '3', '4', '~', 0,
};
char *funcbufptr = func_buf;
int funcbufsize = sizeof(func_buf);
int funcbufleft = 0; /* space left */
char *func_table[MAX_NR_FUNC] = {
func_buf + 0,
func_buf + 5,
func_buf + 10,
func_buf + 15,
func_buf + 20,
func_buf + 25,
func_buf + 31,
func_buf + 37,
func_buf + 43,
func_buf + 49,
func_buf + 55,
func_buf + 61,
func_buf + 67,
func_buf + 73,
func_buf + 79,
func_buf + 85,
func_buf + 91,
func_buf + 97,
func_buf + 103,
func_buf + 109,
0,
};
struct kbdiacr accent_table[MAX_DIACR] = {
{'^', 'c', '\003'}, {'^', 'd', '\004'},
{'^', 'z', '\032'}, {'^', '\012', '\000'},
};
unsigned int accent_table_size = 4;
# Default keymap for 3270 (ebcdic codepage 037).
keymaps 0-1,4-5
keycode 0 = nul Oslash
keycode 1 = nul a
keycode 2 = nul b
keycode 3 = nul c
keycode 4 = nul d
keycode 5 = nul e
keycode 6 = nul f
keycode 7 = nul g
keycode 8 = nul h
keycode 9 = nul i
keycode 10 = nul guillemotleft
keycode 11 = nul guillemotright
keycode 12 = nul eth
keycode 13 = nul yacute
keycode 14 = nul thorn
keycode 15 = nul plusminus
keycode 16 = nul degree
keycode 17 = nul j
keycode 18 = nul k
keycode 19 = nul l
keycode 20 = nul m
keycode 21 = nul n
keycode 22 = nul o
keycode 23 = nul p
keycode 24 = nul q
keycode 25 = nul r
keycode 26 = nul nul
keycode 27 = nul nul
keycode 28 = nul ae
keycode 29 = nul cedilla
keycode 30 = nul AE
keycode 31 = nul currency
keycode 32 = nul mu
keycode 33 = nul tilde
keycode 34 = nul s
keycode 35 = nul t
keycode 36 = nul u
keycode 37 = nul v
keycode 38 = nul w
keycode 39 = nul x
keycode 40 = nul y
keycode 41 = nul z
keycode 42 = nul exclamdown
keycode 43 = nul questiondown
keycode 44 = nul ETH
keycode 45 = nul Yacute
keycode 46 = nul THORN
keycode 47 = nul registered
keycode 48 = nul dead_circumflex
keycode 49 = nul sterling
keycode 50 = nul yen
keycode 51 = nul periodcentered
keycode 52 = nul copyright
keycode 53 = nul section
keycode 54 = nul paragraph
keycode 55 = nul onequarter
keycode 56 = nul onehalf
keycode 57 = nul threequarters
keycode 58 = nul bracketleft
keycode 59 = nul bracketright
keycode 60 = nul nul
keycode 61 = nul diaeresis
keycode 62 = nul acute
keycode 63 = nul multiply
keycode 64 = space braceleft
keycode 65 = nul A
keycode 66 = acircumflex B
keycode 67 = adiaeresis C
keycode 68 = agrave D
keycode 69 = aacute E
keycode 70 = atilde F
keycode 71 = aring G
keycode 72 = ccedilla H
keycode 73 = ntilde I
keycode 74 = cent nul
keycode 75 = period ocircumflex
keycode 76 = less odiaeresis
keycode 77 = parenleft ograve
keycode 78 = plus oacute
keycode 79 = bar otilde
keycode 80 = ampersand braceright
keycode 81 = eacute J
keycode 82 = acircumflex K
keycode 83 = ediaeresis L
keycode 84 = egrave M
keycode 85 = iacute N
keycode 86 = icircumflex O
keycode 87 = idiaeresis P
keycode 88 = igrave Q
keycode 89 = ssharp R
keycode 90 = exclam onesuperior
keycode 91 = dollar ucircumflex
keycode 92 = asterisk udiaeresis
keycode 93 = parenright ugrave
keycode 94 = semicolon uacute
keycode 95 = notsign ydiaeresis
keycode 96 = minus backslash
keycode 97 = slash division
keycode 98 = Acircumflex S
keycode 99 = Adiaeresis T
keycode 100 = Agrave U
keycode 101 = Aacute V
keycode 102 = Atilde W
keycode 103 = Aring X
keycode 104 = Ccedilla Y
keycode 105 = Ntilde Z
keycode 106 = brokenbar twosuperior
keycode 107 = comma Ocircumflex
keycode 108 = percent Odiaeresis
keycode 109 = underscore Ograve
keycode 110 = greater Oacute
keycode 111 = question Otilde
keycode 112 = oslash zero
keycode 113 = Eacute one
keycode 114 = Ecircumflex two
keycode 115 = Ediaeresis three
keycode 116 = Egrave four
keycode 117 = Iacute five
keycode 118 = Icircumflex six
keycode 119 = Idiaeresis seven
keycode 120 = Igrave eight
keycode 121 = grave nine
keycode 122 = colon threesuperior
keycode 123 = numbersign Ucircumflex
keycode 124 = at Udiaeresis
keycode 125 = apostrophe Ugrave
keycode 126 = equal Uacute
keycode 127 = quotedbl nul
# AID keys
control keycode 74 = F22
control keycode 75 = F23
control keycode 76 = F24
control keycode 107 = Control_z # PA3
control keycode 108 = Control_c # PA1
control keycode 109 = KeyboardSignal # Clear
control keycode 110 = Control_d # PA2
control keycode 122 = F10
control keycode 123 = F11 # F11
control keycode 124 = Last_Console # F12
control keycode 125 = Linefeed
shift control keycode 65 = F13
shift control keycode 66 = F14
shift control keycode 67 = F15
shift control keycode 68 = F16
shift control keycode 69 = F17
shift control keycode 70 = F18
shift control keycode 71 = F19
shift control keycode 72 = F20
shift control keycode 73 = F21
shift control keycode 113 = F1
shift control keycode 114 = F2
shift control keycode 115 = Incr_Console
shift control keycode 116 = F4
shift control keycode 117 = F5
shift control keycode 118 = F6
shift control keycode 119 = Scroll_Backward
shift control keycode 120 = Scroll_Forward
shift control keycode 121 = F9
string F1 = "\033[[A"
string F2 = "\033[[B"
string F3 = "\033[[C"
string F4 = "\033[[D"
string F5 = "\033[[E"
string F6 = "\033[17~"
string F7 = "\033[18~"
string F8 = "\033[19~"
string F9 = "\033[20~"
string F10 = "\033[21~"
string F11 = "\033[23~"
string F12 = "\033[24~"
string F13 = "\033[25~"
string F14 = "\033[26~"
string F15 = "\033[28~"
string F16 = "\033[29~"
string F17 = "\033[31~"
string F18 = "\033[32~"
string F19 = "\033[33~"
string F20 = "\033[34~"
# string F21 ??
# string F22 ??
# string F23 ??
# string F24 ??
compose '^' 'c' to Control_c
compose '^' 'd' to Control_d
compose '^' 'z' to Control_z
compose '^' '\012' to nul
/*
* drivers/s390/char/fs3270.c
* IBM/3270 Driver - fullscreen driver.
*
* Author(s):
* Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
* Rewritten for 2.5/2.6 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 <asm/idals.h>
#include "raw3270.h"
#include "ctrlchar.h"
struct raw3270_fn fs3270_fn;
struct fs3270 {
struct raw3270_view view;
pid_t fs_pid; /* Pid of controlling program. */
int read_command; /* ccw command to use for reads. */
int write_command; /* ccw command to use for writes. */
int attention; /* Got attention. */
struct raw3270_request *clear; /* single clear request. */
wait_queue_head_t attn_wait; /* Attention wait queue. */
};
static void
fs3270_wake_up(struct raw3270_request *rq, void *data)
{
wake_up((wait_queue_head_t *) data);
}
static int
fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
{
wait_queue_head_t wq;
int rc;
init_waitqueue_head(&wq);
rq->callback = fs3270_wake_up;
rq->callback_data = &wq;
rc = raw3270_start(view, rq);
if (rc)
return rc;
/* Started sucessfully. Now wait for completion. */
wait_event(wq, raw3270_request_final(rq));
return rq->rc;
}
static void
fs3270_reset_callback(struct raw3270_request *rq, void *data)
{
raw3270_request_reset(rq);
}
/*
* Switch to the fullscreen view.
*/
static int
fs3270_activate(struct raw3270_view *view)
{
struct fs3270 *fp;
fp = (struct fs3270 *) view;
raw3270_request_set_cmd(fp->clear, TC_EWRITEA);
fp->clear->callback = fs3270_reset_callback;
return raw3270_start(view, fp->clear);
}
/*
* Shutdown fullscreen view.
*/
static void
fs3270_deactivate(struct raw3270_view *view)
{
// FIXME: is this a good idea? The user program using fullscreen 3270
// will die just because a console message appeared. On the other
// hand the fullscreen device is unoperational now.
struct fs3270 *fp;
fp = (struct fs3270 *) view;
if (fp->fs_pid != 0)
kill_proc(fp->fs_pid, SIGHUP, 1);
fp->fs_pid = 0;
}
static int
fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
{
/* Handle ATTN. Set indication and wake waiters for attention. */
if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
fp->attention = 1;
wake_up(&fp->attn_wait);
}
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;
}
/*
* Process reads from fullscreen 3270.
*/
static ssize_t
fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
struct idal_buffer *ib;
int rc;
if (count == 0 || count > 65535)
return -EINVAL;
fp = filp->private_data;
if (!fp)
return -ENODEV;
ib = idal_buffer_alloc(count, 0);
if (!ib)
return -ENOMEM;
rq = raw3270_request_alloc(0);
if (!IS_ERR(rq)) {
if (fp->read_command == 0 && fp->write_command != 0)
fp->read_command = 6;
raw3270_request_set_cmd(rq, fp->read_command ? : 2);
raw3270_request_set_idal(rq, ib);
wait_event(fp->attn_wait, fp->attention);
rc = fs3270_do_io(&fp->view, rq);
if (rc == 0 && idal_buffer_to_user(ib, data, count))
rc = -EFAULT;
raw3270_request_free(rq);
} else
rc = PTR_ERR(rq);
idal_buffer_free(ib);
return rc;
}
/*
* Process writes to fullscreen 3270.
*/
static ssize_t
fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
struct idal_buffer *ib;
int write_command;
int rc;
fp = filp->private_data;
if (!fp)
return -ENODEV;
ib = idal_buffer_alloc(count, 0);
if (!ib)
return -ENOMEM;
rq = raw3270_request_alloc(0);
if (!IS_ERR(rq)) {
if (idal_buffer_from_user(ib, data, count) == 0) {
write_command = fp->write_command ? : 1;
if (write_command == 5)
write_command = 13;
raw3270_request_set_cmd(rq, write_command);
raw3270_request_set_idal(rq, ib);
rc = fs3270_do_io(&fp->view, rq);
} else
rc = -EFAULT;
raw3270_request_free(rq);
} else
rc = PTR_ERR(rq);
idal_buffer_free(ib);
return rc;
}
/*
* process ioctl commands for the tube driver
*/
static int
fs3270_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct fs3270 *fp;
struct raw3270_iocb iocb;
int rc;
fp = filp->private_data;
if (!fp)
return -ENODEV;
rc = 0;
switch (cmd) {
case TUBICMD:
fp->read_command = arg;
break;
case TUBOCMD:
fp->write_command = arg;
break;
case TUBGETI:
rc = put_user(fp->read_command, (char *) arg);
break;
case TUBGETO:
rc = put_user(fp->write_command,(char *) arg);
break;
case TUBGETMOD:
iocb.model = fp->view.model;
iocb.line_cnt = fp->view.rows;
iocb.col_cnt = fp->view.cols;
iocb.pf_cnt = 24;
iocb.re_cnt = 20;
iocb.map = 0;
if (copy_to_user((char *) arg, &iocb,
sizeof(struct raw3270_iocb)))
rc = -EFAULT;
break;
}
return rc;
}
/*
* Allocate tty3270 structure.
*/
static struct fs3270 *
fs3270_alloc_view(void)
{
struct fs3270 *fp;
fp = (struct fs3270 *) kmalloc(sizeof(struct fs3270),GFP_KERNEL);
if (!fp)
return ERR_PTR(-ENOMEM);
memset(fp, 0, sizeof(struct fs3270));
fp->clear = raw3270_request_alloc(0);
if (!IS_ERR(fp->clear)) {
kfree(fp);
return ERR_PTR(-ENOMEM);
}
return fp;
}
/*
* Free tty3270 structure.
*/
static void
fs3270_free_view(struct raw3270_view *view)
{
raw3270_request_free(((struct fs3270 *) view)->clear);
kfree(view);
}
/*
* Unlink fs3270 data structure from filp.
*/
static void
fs3270_release(struct raw3270_view *view)
{
}
/* View to a 3270 device. Can be console, tty or fullscreen. */
struct raw3270_fn fs3270_fn = {
.activate = fs3270_activate,
.deactivate = fs3270_deactivate,
.intv = (void *) fs3270_irq,
.release = fs3270_release,
.free = fs3270_free_view
};
/*
* This routine is called whenever a 3270 fullscreen device is opened.
*/
static int
fs3270_open(struct inode *inode, struct file *filp)
{
struct fs3270 *fp;
int minor, rc;
if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR)
return -ENODEV;
minor = iminor(filp->f_dentry->d_inode);
/* Check if some other program is already using fullscreen mode. */
fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
if (!IS_ERR(fp)) {
raw3270_put_view(&fp->view);
return -EBUSY;
}
/* Allocate fullscreen view structure. */
fp = fs3270_alloc_view();
if (IS_ERR(fp))
return PTR_ERR(fp);
init_waitqueue_head(&fp->attn_wait);
fp->fs_pid = current->pid;
rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
if (rc) {
fs3270_free_view(&fp->view);
return rc;
}
rc = raw3270_activate_view(&fp->view);
if (rc) {
raw3270_del_view(&fp->view);
return rc;
}
filp->private_data = fp;
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 int
fs3270_close(struct inode *inode, struct file *filp)
{
struct fs3270 *fp;
fp = filp->private_data;
filp->private_data = 0;
if (fp)
raw3270_del_view(&fp->view);
return 0;
}
static struct file_operations fs3270_fops = {
.owner = THIS_MODULE, /* owner */
.read = fs3270_read, /* read */
.write = fs3270_write, /* write */
.ioctl = fs3270_ioctl, /* ioctl */
.open = fs3270_open, /* open */
.release = fs3270_close, /* release */
};
/*
* 3270 fullscreen driver initialization.
*/
static int __init
fs3270_init(void)
{
int rc;
rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
if (rc) {
printk(KERN_ERR "fs3270 can't get major number %d: errno %d\n",
IBM_FS3270_MAJOR, rc);
return rc;
}
return 0;
}
static void __exit
fs3270_exit(void)
{
unregister_chrdev(IBM_FS3270_MAJOR, "fs3270");
}
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);
module_init(fs3270_init);
module_exit(fs3270_exit);
This diff is collapsed.
/*
* drivers/s390/char/keyboard.h
* ebcdic keycode functions for s390 console drivers
*
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
*/
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/keyboard.h>
#define NR_FN_HANDLER 20
struct kbd_data;
typedef void (fn_handler_fn)(struct kbd_data *);
/*
* FIXME: explain key_maps tricks.
*/
struct kbd_data {
struct tty_struct *tty;
unsigned short **key_maps;
char **func_table;
fn_handler_fn **fn_handler;
struct kbdiacr *accent_table;
unsigned int accent_table_size;
unsigned char diacr;
unsigned short sysrq;
};
struct kbd_data *kbd_alloc(void);
void kbd_free(struct kbd_data *);
void kbd_ascebc(struct kbd_data *, unsigned char *);
void kbd_keycode(struct kbd_data *, unsigned int);
int kbd_ioctl(struct kbd_data *, struct file *, unsigned int, unsigned long);
/*
* Helper Functions.
*/
extern inline void
kbd_put_queue(struct tty_struct *tty, int ch)
{
tty_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty);
}
extern inline void
kbd_puts_queue(struct tty_struct *tty, char *cp)
{
while (*cp)
tty_insert_flip_char(tty, *cp++, 0);
tty_schedule_flip(tty);
}
This diff is collapsed.
/*
* drivers/s390/char/raw3270.h
* IBM/3270 Driver
*
* 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 <asm/idals.h>
#include <asm/ioctl.h>
/* ioctls for fullscreen 3270 */
#define TUBICMD _IO('3', 3) /* set ccw command for fs reads. */
#define TUBOCMD _IO('3', 4) /* set ccw command for fs writes. */
#define TUBGETI _IO('3', 7) /* get ccw command for fs reads. */
#define TUBGETO _IO('3', 8) /* get ccw command for fs writes. */
#define TUBSETMOD _IO('3',12) /* FIXME: what does it do ?*/
#define TUBGETMOD _IO('3',13) /* FIXME: what does it do ?*/
/* Local Channel Commands */
#define TC_WRITE 0x01 /* Write */
#define TC_EWRITE 0x05 /* Erase write */
#define TC_READMOD 0x06 /* Read modified */
#define TC_EWRITEA 0x0d /* Erase write alternate */
#define TC_WRITESF 0x11 /* Write structured field */
/* Buffer Control Orders */
#define TO_SF 0x1d /* Start field */
#define TO_SBA 0x11 /* Set buffer address */
#define TO_IC 0x13 /* Insert cursor */
#define TO_PT 0x05 /* Program tab */
#define TO_RA 0x3c /* Repeat to address */
#define TO_SFE 0x29 /* Start field extended */
#define TO_EUA 0x12 /* Erase unprotected to address */
#define TO_MF 0x2c /* Modify field */
#define TO_SA 0x28 /* Set attribute */
/* Field Attribute Bytes */
#define TF_INPUT 0x40 /* Visible input */
#define TF_INPUTN 0x4c /* Invisible input */
#define TF_INMDT 0xc1 /* Visible, Set-MDT */
#define TF_LOG 0x60
/* Character Attribute Bytes */
#define TAT_RESET 0x00
#define TAT_FIELD 0xc0
#define TAT_EXTHI 0x41
#define TAT_COLOR 0x42
#define TAT_CHARS 0x43
#define TAT_TRANS 0x46
/* Extended-Highlighting Bytes */
#define TAX_RESET 0x00
#define TAX_BLINK 0xf1
#define TAX_REVER 0xf2
#define TAX_UNDER 0xf4
/* Reset value */
#define TAR_RESET 0x00
/* Color values */
#define TAC_RESET 0x00
#define TAC_BLUE 0xf1
#define TAC_RED 0xf2
#define TAC_PINK 0xf3
#define TAC_GREEN 0xf4
#define TAC_TURQ 0xf5
#define TAC_YELLOW 0xf6
#define TAC_WHITE 0xf7
#define TAC_DEFAULT 0x00
/* Write Control Characters */
#define TW_NONE 0x40 /* No particular action */
#define TW_KR 0xc2 /* Keyboard restore */
#define TW_PLUSALARM 0x04 /* Add this bit for alarm */
#define RAW3270_MAXDEVS 256
int raw3270_init(void);
void raw3270_exit(void);
/* For TUBGETMOD and TUBSETMOD. Should include. */
struct raw3270_iocb {
short model;
short line_cnt;
short col_cnt;
short pf_cnt;
short re_cnt;
short map;
};
struct raw3270;
struct raw3270_view;
/* 3270 CCW request */
struct raw3270_request {
struct list_head list; /* list head for request queueing. */
struct raw3270_view *view; /* view of this request */
struct ccw1 ccw; /* single ccw. */
void *buffer; /* output buffer. */
size_t size; /* size of output buffer. */
int rescnt; /* residual count from devstat. */
int rc; /* return code for this request. */
/* Callback for delivering final status. */
void (*callback)(struct raw3270_request *, void *);
void *callback_data;
};
struct raw3270_request *raw3270_request_alloc(size_t size);
struct raw3270_request *raw3270_request_alloc_bootmem(size_t size);
void raw3270_request_free(struct raw3270_request *);
void raw3270_request_reset(struct raw3270_request *);
void raw3270_request_set_cmd(struct raw3270_request *, u8 cmd);
int raw3270_request_add_data(struct raw3270_request *, void *, size_t);
void raw3270_request_set_data(struct raw3270_request *, void *, size_t);
void raw3270_request_set_idal(struct raw3270_request *, struct idal_buffer *);
static inline int
raw3270_request_final(struct raw3270_request *rq)
{
return list_empty(&rq->list);
}
void raw3270_buffer_address(struct raw3270 *, char *, unsigned short);
/* Return value of *intv (see raw3270_fn below) can be one of the following: */
#define RAW3270_IO_DONE 0 /* request finished */
#define RAW3270_IO_BUSY 1 /* request still active */
#define RAW3270_IO_RETRY 2 /* retry current request */
#define RAW3270_IO_STOP 3 /* kill current request */
/*
* Functions of a 3270 view.
*/
struct raw3270_fn {
int (*activate)(struct raw3270_view *);
void (*deactivate)(struct raw3270_view *);
int (*intv)(struct raw3270_view *,
struct raw3270_request *, struct irb *);
void (*release)(struct raw3270_view *);
void (*free)(struct raw3270_view *);
};
/*
* View structure chaining. The raw3270_view structure is meant to
* be embedded at the start of the real view data structure, e.g.:
* struct example {
* struct raw3270_view view;
* ...
* };
*/
struct raw3270_view {
struct list_head list;
spinlock_t lock;
atomic_t ref_count;
struct raw3270 *dev;
struct raw3270_fn *fn;
unsigned int model;
unsigned int rows, cols; /* # of rows & colums of the view */
unsigned char *ascebc; /* ascii -> ebcdic table */
};
int raw3270_add_view(struct raw3270_view *, struct raw3270_fn *, int);
int raw3270_activate_view(struct raw3270_view *);
void raw3270_del_view(struct raw3270_view *);
void raw3270_deactivate_view(struct raw3270_view *);
struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int);
int raw3270_start(struct raw3270_view *, struct raw3270_request *);
int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
/* Reference count inliner for view structures. */
static inline void
raw3270_get_view(struct raw3270_view *view)
{
atomic_inc(&view->ref_count);
}
extern wait_queue_head_t raw3270_wait_queue;
static inline void
raw3270_put_view(struct raw3270_view *view)
{
if (atomic_dec_return(&view->ref_count) == 0)
wake_up(&raw3270_wait_queue);
}
struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
void raw3270_wait_cons_dev(struct raw3270 *);
/*
* Little memory allocator for string objects.
*/
struct string
{
struct list_head list;
struct list_head update;
unsigned long size;
unsigned long len;
char string[0];
} __attribute__ ((aligned(8)));
static inline struct string *
alloc_string(struct list_head *free_list, unsigned long len)
{
struct string *cs, *tmp;
unsigned long size;
size = (len + 7L) & -8L;
list_for_each_entry(cs, free_list, list) {
if (cs->size < size)
continue;
if (cs->size > size + sizeof(struct string)) {
char *endaddr = (char *) (cs + 1) + cs->size;
tmp = (struct string *) (endaddr - size) - 1;
tmp->size = size;
cs->size -= size + sizeof(struct string);
cs = tmp;
} else
list_del(&cs->list);
cs->len = len;
INIT_LIST_HEAD(&cs->list);
INIT_LIST_HEAD(&cs->update);
return cs;
}
return 0;
}
static inline unsigned long
free_string(struct list_head *free_list, struct string *cs)
{
struct string *tmp;
struct list_head *p, *left;
/* Find out the left neighbour in free memory list. */
left = free_list;
list_for_each(p, free_list) {
if (list_entry(p, struct string, list) > cs)
break;
left = p;
}
/* Try to merge with right neighbour = next element from left. */
if (left->next != free_list) {
tmp = list_entry(left->next, struct string, list);
if ((char *) (cs + 1) + cs->size == (char *) tmp) {
list_del(&tmp->list);
cs->size += tmp->size + sizeof(struct string);
}
}
/* Try to merge with left neighbour. */
if (left != free_list) {
tmp = list_entry(left, struct string, list);
if ((char *) (tmp + 1) + tmp->size == (char *) cs) {
tmp->size += cs->size + sizeof(struct string);
return tmp->size;
}
}
__list_add(&cs->list, left, left->next);
return cs->size;
}
static inline void
add_string_memory(struct list_head *free_list, void *mem, unsigned long size)
{
struct string *cs;
cs = (struct string *) mem;
cs->size = size - sizeof(struct string);
free_string(free_list, cs);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
*
* tubttyaid.c -- Linemode Attention-ID functionality
*
*
*
*
*
* Author: Richard Hitt
*/
#include "tubio.h"
#define PA1_STR "^C"
#define PF3_STR "^D"
#define PF9_STR "\033j"
#define PF10_STR "\033k"
#define PF11_STR "\033j"
/* other AID-key default strings */
static aid_t aidtab[64] = {
/* 00 */ { 0, 0 },
/* C1 = PF13 */ { TA_DOSTRING, 0 },
/* C2 = PF14 */ { TA_DOSTRING, 0 },
/* C3 = PF15 */ { TA_DOSTRING, 0 },
/* C4 = PF16 */ { TA_DOSTRING, 0 },
/* C5 = PF17 */ { TA_DOSTRING, 0 },
/* C6 = PF18 */ { TA_DOSTRING, 0 },
/* C7 = PF19 */ { TA_DOSTRING, 0 },
/* C8 = PF20 */ { TA_DOSTRING, 0 },
/* C9 = PF21 */ { TA_DOSTRING, 0 },
/* 4A = PF22 */ { TA_DOSTRING, 0 },
/* 4B = PF23 */ { TA_DOSTRING, 0 },
/* 4C = PF24 */ { TA_DOSTRING, 0 },
/* 0D */ { 0, 0 },
/* 0E */ { 0, 0 },
/* 0F */ { 0, 0 },
/* 10 */ { 0, 0 },
/* 11 */ { 0, 0 },
/* 12 */ { 0, 0 },
/* 13 */ { 0, 0 },
/* 14 */ { 0, 0 },
/* 15 */ { 0, 0 },
/* 16 */ { 0, 0 },
/* 17 */ { 0, 0 },
/* 18 */ { 0, 0 },
/* 19 */ { 0, 0 },
/* 1A */ { 0, 0 },
/* 1B */ { 0, 0 },
/* 1C */ { 0, 0 },
/* 1D */ { 0, 0 },
/* 1E */ { 0, 0 },
/* 1F */ { 0, 0 },
/* 60 = NoAID */ { 0, 0 },
/* 21 */ { 0, 0 },
/* 22 */ { 0, 0 },
/* 23 */ { 0, 0 },
/* 24 */ { 0, 0 },
/* 25 */ { 0, 0 },
/* E6 = OpRdr */ { 0, 0 },
/* E7 = MSRdr */ { 0, 0 },
/* E8 = NoAID */ { 0, 0 },
/* 29 */ { 0, 0 },
/* 2A */ { 0, 0 },
/* 6B = PA3 */ { TA_SHORTREAD, 0 },
/* 6C = PA1 */ { TA_SHORTREAD | TA_DOSTRING, PA1_STR },
/* 6D = CLEAR */ { TA_SHORTREAD | TA_CLEARKEY, 0 },
/* 6E = PA2 */ { TA_SHORTREAD | TA_CLEARLOG, 0 },
/* 2F */ { 0, 0 },
/* F0 = TstRq */ { 0, 0 },
/* F1 = PF1 */ { TA_DOSTRING, 0 },
/* F2 = PF2 */ { TA_DOSTRING, 0 },
/* F3 = PF3 */ { TA_DOSTRING, PF3_STR },
/* F4 = PF4 */ { TA_DOSTRING, 0 },
/* F5 = PF5 */ { TA_DOSTRING, 0 },
/* F6 = PF6 */ { TA_DOSTRING, 0 },
/* F7 = PF7 */ { TA_DOSTRING, 0 },
/* F8 = PF8 */ { TA_DOSTRING, 0 },
/* F9 = PF9 */ { TA_DOSTRING, PF9_STR },
/* 7A = PF10 */ { TA_DOSTRING, PF10_STR },
/* 7B = PF11 */ { TA_DOSTRING, PF11_STR },
/* 7C = PF12 */ { TA_DOSTRING, 0 },
/* 7D = ENTER */ { TA_DOENTER, 0 },
/* 7E = Pen */ { 0, 0 },
/* 3F */ { 0, 0 },
};
int
tty3270_aid_init(tub_t *tubp)
{
memcpy(tubp->tty_aid, aidtab, sizeof aidtab);
tubp->tty_aidinit = 1;
return 0;
}
void
tty3270_aid_fini(tub_t *tubp)
{
int i;
char *sp;
if (tubp->tty_aidinit == 0)
return;
for (i = 0; i < 64; i++) {
if ((sp = tubp->tty_aid[i].string) == NULL)
continue;
if (sp == aidtab[i].string)
continue;
kfree(sp);
}
tubp->tty_aidinit = 0;
}
void
tty3270_aid_reinit(tub_t *tubp)
{
tty3270_aid_fini(tubp);
tty3270_aid_init(tubp);
}
int
tty3270_aid_get(tub_t *tubp, int aid, int *aidflags, char **aidstring)
{
aid_t *ap;
ap = AIDENTRY(aid, tubp);
*aidflags = ap->aid;
*aidstring = ap->string;
return 0;
}
/*
* tty3270_aid_set() -- write_proc extension
* Parse written string as an AID name. Return 0 if it's not.
* Otherwise absorb the string and return count or -error.
*/
int
tty3270_aid_set(tub_t *tubp, char *buf, int count)
{
char name[8];
char *sp;
int aidn, aidx;
aid_t *ap;
int len;
char *pfp;
if (tubp->tty_aidinit == 0)
return 0;
if (count < 3) /* If AID-key name too short */
return 0;
name[0] = buf[0] < 0x60? buf[0]: (buf[0] & 0x5f);
name[1] = buf[1] < 0x60? buf[1]: (buf[1] & 0x5f);
if (name[0] == 'P' && name[1] == 'F') {
aidn = simple_strtoul(buf+2, &sp, 10);
if (aidn < 1 || aidn > 24)
return 0;
aidx = aidn > 12? aidn - 12: aidn + 0x30;
ap = &tubp->tty_aid[aidx];
} else if (name[0] == 'P' && name[1] == 'A') {
aidn = simple_strtoul(buf+2, &sp, 10);
if (aidn < 1 || aidn > 3)
return 0;
switch(aidn) {
case 1: aidx = 0x2c; break;
case 2: aidx = 0x2e; break;
case 3: aidx = 0x2b; break;
default: aidx = 0; break;
}
ap = &tubp->tty_aid[aidx];
} else {
return 0;
}
if (*sp == '\0') {
tubp->tty_showaidx = ap - tubp->tty_aid;
return count;
} else if (*sp == '=') {
len = strlen(++sp);
if (len == 0) {
if (ap->string != NULL &&
ap->string != aidtab[aidx].string)
kfree(ap->string);
ap->string = aidtab[aidx].string;
ap->aid = aidtab[aidx].aid;
return count;
}
if ((pfp = kmalloc(len + 1, GFP_KERNEL)) == NULL)
return -ENOMEM;
if (ap->string != NULL &&
ap->string != aidtab[aidx].string)
kfree(ap->string);
if (sp[len - 1] == '\n') {
ap->aid = TA_DOSTRING;
sp[len - 1] = '\0';
len--;
} else {
ap->aid = TA_DOSTRINGD;
}
memcpy(pfp, sp, len + 1);
ap->string = pfp;
return count;
} else {
return -EINVAL;
}
}
This diff is collapsed.
This diff is collapsed.
/*
* IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC
*
* tubttyscl.c -- Linemode tty driver scroll-timing functions
*
*
*
*
*
* Author: Richard Hitt
*/
#include "tubio.h"
void tty3270_scl_settimer(tub_t *);
void tty3270_scl_resettimer(tub_t *);
static void tty3270_scl_timeout(unsigned long);
void
tty3270_scl_settimer(tub_t *tubp)
{
struct timer_list *tp = &tubp->tty_stimer;
if (tubp->flags & TUB_SCROLLTIMING)
return;
if (tubp->tty_scrolltime == 0)
return;
init_timer(tp);
tp->expires = jiffies + HZ * tubp->tty_scrolltime;
tp->data = (unsigned long)tubp;
tp->function = tty3270_scl_timeout;
add_timer(tp);
tubp->flags |= TUB_SCROLLTIMING;
}
void
tty3270_scl_resettimer(tub_t *tubp)
{
struct timer_list *tp = &tubp->tty_stimer;
if ((tubp->flags & TUB_SCROLLTIMING) == 0)
return;
del_timer(tp);
tubp->flags &= ~TUB_SCROLLTIMING;
}
static void
tty3270_scl_timeout(unsigned long data)
{
tub_t *tubp = (void *)data;
long flags;
TUBLOCK(tubp->irq, flags);
tubp->stat = TBS_RUNNING;
tty3270_scl_resettimer(tubp);
tubp->cmd = TBC_CLRUPDLOG;
tty3270_build(tubp);
TUBUNLOCK(tubp->irq, flags);
}
int
tty3270_scl_set(tub_t *tubp, char *buf, int count)
{
if (strncmp(buf, "scrolltime=", 11) == 0) {
tubp->tty_scrolltime =
simple_strtoul(buf + 11, 0, 0);
return count;
}
return 0;
}
int
tty3270_scl_init(tub_t *tubp)
{
extern int tubscrolltime;
tubp->tty_scrolltime = tubscrolltime;
if (tubp->tty_scrolltime < 0)
tubp->tty_scrolltime = DEFAULT_SCROLLTIME;
return 0;
}
void
tty3270_scl_fini(tub_t *tubp)
{
if ((tubp->flags & TUB_OPEN_STET) == 0)
tty3270_scl_resettimer(tubp);
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment