Commit 49d7127a authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: sclp driver part 1.

Reworked sclp driver part 1.
parent e540dbf8
......@@ -108,9 +108,10 @@ CONFIG_UNIX98_PTY_COUNT=2048
# CONFIG_TN3270 is not set
CONFIG_TN3215=y
CONFIG_TN3215_CONSOLE=y
CONFIG_HWC=y
CONFIG_HWC_CONSOLE=y
CONFIG_HWC_CPI=m
CONFIG_SCLP=y
CONFIG_SCLP_TTY=y
CONFIG_SCLP_CONSOLE=y
CONFIG_SCLP_CPI=m
CONFIG_S390_TAPE=m
#
......
......@@ -164,9 +164,9 @@ __setup("condev=", condev_setup);
static int __init conmode_setup(char *str)
{
#if defined(CONFIG_HWC_CONSOLE)
if (strncmp(str, "hwc", 4) == 0)
SET_CONSOLE_HWC;
#if defined(CONFIG_SCLP_CONSOLE)
if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
SET_CONSOLE_SCLP;
#endif
#if defined(CONFIG_TN3215_CONSOLE)
if (strncmp(str, "3215", 5) == 0)
......@@ -198,8 +198,8 @@ static void __init conmode_default(void)
*/
cpcmd("TERM CONMODE 3215", NULL, 0);
if (ptr == NULL) {
#if defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#if defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
return;
}
......@@ -208,16 +208,16 @@ static void __init conmode_default(void)
SET_CONSOLE_3270;
#elif defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215;
#elif defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#elif defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
} else if (strncmp(ptr + 8, "3215", 4) == 0) {
#if defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215;
#elif defined(CONFIG_TN3270_CONSOLE)
SET_CONSOLE_3270;
#elif defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#elif defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
}
} else if (MACHINE_IS_P390) {
......@@ -227,8 +227,8 @@ static void __init conmode_default(void)
SET_CONSOLE_3270;
#endif
} else {
#if defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#if defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
}
}
......
......@@ -166,9 +166,10 @@ CONFIG_UNIX98_PTY_COUNT=2048
# CONFIG_TN3270 is not set
CONFIG_TN3215=y
CONFIG_TN3215_CONSOLE=y
CONFIG_HWC=y
CONFIG_HWC_CONSOLE=y
CONFIG_HWC_CPI=m
CONFIG_SCLP=y
CONFIG_SCLP_TTY=y
CONFIG_SCLP_CONSOLE=y
CONFIG_SCLP_CPI=m
CONFIG_S390_TAPE=m
#
......
......@@ -164,9 +164,9 @@ __setup("condev=", condev_setup);
static int __init conmode_setup(char *str)
{
#if defined(CONFIG_HWC_CONSOLE)
if (strncmp(str, "hwc", 4) == 0)
SET_CONSOLE_HWC;
#if defined(CONFIG_SCLP_CONSOLE)
if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
SET_CONSOLE_SCLP;
#endif
#if defined(CONFIG_TN3215_CONSOLE)
if (strncmp(str, "3215", 5) == 0)
......@@ -198,8 +198,8 @@ static void __init conmode_default(void)
*/
cpcmd("TERM CONMODE 3215", NULL, 0);
if (ptr == NULL) {
#if defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#if defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
return;
}
......@@ -208,16 +208,16 @@ static void __init conmode_default(void)
SET_CONSOLE_3270;
#elif defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215;
#elif defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#elif defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
} else if (strncmp(ptr + 8, "3215", 4) == 0) {
#if defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215;
#elif defined(CONFIG_TN3270_CONSOLE)
SET_CONSOLE_3270;
#elif defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#elif defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
}
} else if (MACHINE_IS_P390) {
......@@ -227,8 +227,8 @@ static void __init conmode_default(void)
SET_CONSOLE_3270;
#endif
} else {
#if defined(CONFIG_HWC_CONSOLE)
SET_CONSOLE_HWC;
#if defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
#endif
}
}
......
......@@ -146,10 +146,9 @@ extern long serial167_console_init(void);
extern void console_8xx_init(void);
extern int rs_8xx_init(void);
extern void mac_scc_console_init(void);
extern void hwc_console_init(void);
extern void hwc_tty_init(void);
extern void sclp_console_init(void);
extern void sclp_tty_init(void);
extern void con3215_init(void);
extern void tty3215_init(void);
extern void tub3270_con_init(void);
extern void tub3270_init(void);
extern void uart_console_init(void);
......@@ -2208,8 +2207,8 @@ void __init console_init(void)
#ifdef CONFIG_TN3215
con3215_init();
#endif
#ifdef CONFIG_HWC
hwc_console_init();
#ifdef CONFIG_SCLP_CONSOLE
sclp_console_init();
#endif
#ifdef CONFIG_STDIO_CONSOLE
stdio_console_init();
......@@ -2349,8 +2348,8 @@ void __init tty_init(void)
#ifdef CONFIG_TN3215
tty3215_init();
#endif
#ifdef CONFIG_HWC
hwc_tty_init();
#ifdef CONFIG_SCLP
sclp_tty_init();
#endif
#ifdef CONFIG_A2232
a2232board_init();
......
......@@ -257,24 +257,30 @@ config TN3215_CONSOLE
Include support for using an IBM 3215 line-mode terminal as a
Linux system console.
config HWC
bool "Support for HWC line mode terminal"
config SCLP
bool "Support for SCLP"
help
Include support for IBM HWC line-mode terminals.
Include support for the SCLP interface to the service element.
config HWC_CONSOLE
bool "console on HWC line mode terminal"
depends on HWC
config SCLP_TTY
bool "Support for SCLP line mode terminal"
depends on SCLP
help
Include support for IBM SCLP line-mode terminals.
config SCLP_CONSOLE
bool "Support for console on SCLP line mode terminal"
depends on SCLP_TTY
help
Include support for using an IBM HWC line-mode terminal as the Linux
system console.
config HWC_CPI
config SCLP_CPI
tristate "Control-Program Identification"
depends on HWC
depends on SCLP
help
This option enables the hardware console interface for system
identification This is commonly used for workload management and
identification. This is commonly used for workload management and
gives you a nice name for the system on the service element.
Please select this option as a module since built-in operation is
completely untested.
......
......@@ -2,28 +2,23 @@
# S/390 character devices
#
export-objs := hwc_rw.o tape.o tape34xx.o
export-objs := sclp_rw.o tape_core.o tape_devmap.o tape_std.o
tub3270-objs := tuball.o tubfs.o tubtty.o \
tubttyaid.o tubttybld.o tubttyscl.o \
tubttyrcl.o tubttysiz.o
tape390-$(CONFIG_S390_TAPE_CHAR) += tapechar.o
tape390-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o
tape390-objs := tape.o tape34xx.o $(sort $(tape390-y))
tape_3480_mod-objs := tape3480.o
tape_3490_mod-objs := tape3490.o
obj-y += ctrlchar.o
obj-$(CONFIG_TN3215) += con3215.o
obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o
obj-$(CONFIG_HWC_CPI) += hwc_cpi.o
obj-$(CONFIG_SCLP) += sclp.o
obj-$(CONFIG_SCLP_TTY) += sclp_rw.o sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
obj-$(CONFIG_TN3270) += tub3270.o
obj-$(CONFIG_S390_TAPE) += tape390.o
obj-$(CONFIG_S390_TAPE_3480) += tape_3480_mod.o
obj-$(CONFIG_S390_TAPE_3490) += tape_3490_mod.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)
obj-$(CONFIG_S390_TAPE) += tape.o
obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
include $(TOPDIR)/Rules.make
/*
* drivers/s390/char/hwc.h
*
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
*
*
*
*/
#ifndef __HWC_H__
#define __HWC_H__
#define HWC_EXT_INT_PARAM_ADDR 0xFFFFFFF8
#define HWC_EXT_INT_PARAM_PEND 0x00000001
#define ET_OpCmd 0x01
#define ET_Msg 0x02
#define ET_StateChange 0x08
#define ET_PMsgCmd 0x09
#define ET_CntlProgOpCmd 0x20
#define ET_CntlProgIdent 0x0B
#define ET_SigQuiesce 0x1D
#define ET_OpCmd_Mask 0x80000000
#define ET_Msg_Mask 0x40000000
#define ET_StateChange_Mask 0x01000000
#define ET_PMsgCmd_Mask 0x00800000
#define ET_CtlProgOpCmd_Mask 0x00000001
#define ET_CtlProgIdent_Mask 0x00200000
#define ET_SigQuiesce_Mask 0x00000008
#define GMF_DOM 0x8000
#define GMF_SndAlrm 0x4000
#define GMF_HoldMsg 0x2000
#define LTF_CntlText 0x8000
#define LTF_LabelText 0x4000
#define LTF_DataText 0x2000
#define LTF_EndText 0x1000
#define LTF_PromptText 0x0800
#define HWC_COMMAND_INITIATED 0
#define HWC_BUSY 2
#define HWC_NOT_OPERATIONAL 3
#define hwc_cmdw_t u32;
#define HWC_CMDW_READDATA 0x00770005
#define HWC_CMDW_WRITEDATA 0x00760005
#define HWC_CMDW_WRITEMASK 0x00780005
#define GDS_ID_MDSMU 0x1310
#define GDS_ID_MDSRouteInfo 0x1311
#define GDS_ID_AgUnWrkCorr 0x1549
#define GDS_ID_SNACondReport 0x1532
#define GDS_ID_CPMSU 0x1212
#define GDS_ID_RoutTargInstr 0x154D
#define GDS_ID_OpReq 0x8070
#define GDS_ID_TextCmd 0x1320
#define GDS_KEY_SelfDefTextMsg 0x31
#define _HWCB_HEADER u16 length; \
u8 function_code; \
u8 control_mask[3]; \
u16 response_code;
#define _EBUF_HEADER u16 length; \
u8 type; \
u8 flags; \
u16 _reserved;
typedef struct {
_EBUF_HEADER
} __attribute__ ((packed))
evbuf_t;
#define _MDB_HEADER u16 length; \
u16 type; \
u32 tag; \
u32 revision_code;
#define _GO_HEADER u16 length; \
u16 type; \
u32 domid; \
u8 hhmmss_time[8]; \
u8 th_time[3]; \
u8 _reserved_0; \
u8 dddyyyy_date[7]; \
u8 _reserved_1; \
u16 general_msg_flags; \
u8 _reserved_2[10]; \
u8 originating_system_name[8]; \
u8 job_guest_name[8];
#define _MTO_HEADER u16 length; \
u16 type; \
u16 line_type_flags; \
u8 alarm_control; \
u8 _reserved[3];
typedef struct {
_GO_HEADER
} __attribute__ ((packed))
go_t;
typedef struct {
go_t go;
} __attribute__ ((packed))
mdb_body_t;
typedef struct {
_MDB_HEADER
mdb_body_t mdb_body;
} __attribute__ ((packed))
mdb_t;
typedef struct {
_EBUF_HEADER
mdb_t mdb;
} __attribute__ ((packed))
msgbuf_t;
typedef struct {
_HWCB_HEADER
msgbuf_t msgbuf;
} __attribute__ ((packed))
write_hwcb_t;
typedef struct {
_MTO_HEADER
} __attribute__ ((packed))
mto_t;
/* FIXME: don't define static variables in a header!!! */
#warning
static write_hwcb_t write_hwcb_template =
{
sizeof (write_hwcb_t),
0x00,
{
0x00,
0x00,
0x00
},
0x0000,
{
sizeof (msgbuf_t),
ET_Msg,
0x00,
0x0000,
{
sizeof (mdb_t),
0x0001,
0xD4C4C240,
0x00000001,
{
{
sizeof (go_t),
0x0001
}
}
}
}
};
#warning
static mto_t mto_template =
{
sizeof (mto_t),
0x0004,
LTF_EndText,
0x00
};
typedef u32 _hwcb_mask_t;
typedef struct {
_HWCB_HEADER
u16 _reserved;
u16 mask_length;
_hwcb_mask_t cp_receive_mask;
_hwcb_mask_t cp_send_mask;
_hwcb_mask_t hwc_receive_mask;
_hwcb_mask_t hwc_send_mask;
} __attribute__ ((packed))
init_hwcb_t;
#warning
static init_hwcb_t init_hwcb_template =
{
sizeof (init_hwcb_t),
0x00,
{
0x00,
0x00,
0x00
},
0x0000,
0x0000,
sizeof (_hwcb_mask_t),
ET_OpCmd_Mask | ET_PMsgCmd_Mask |
ET_StateChange_Mask | ET_SigQuiesce_Mask,
ET_Msg_Mask | ET_PMsgCmd_Mask | ET_CtlProgIdent_Mask
};
typedef struct {
_EBUF_HEADER
u8 validity_hwc_active_facility_mask:1;
u8 validity_hwc_receive_mask:1;
u8 validity_hwc_send_mask:1;
u8 validity_read_data_function_mask:1;
u16 _zeros:12;
u16 mask_length;
u64 hwc_active_facility_mask;
_hwcb_mask_t hwc_receive_mask;
_hwcb_mask_t hwc_send_mask;
u32 read_data_function_mask;
} __attribute__ ((packed))
statechangebuf_t;
#define _GDS_VECTOR_HEADER u16 length; \
u16 gds_id;
#define _GDS_SUBVECTOR_HEADER u8 length; \
u8 key;
typedef struct {
_GDS_VECTOR_HEADER
} __attribute__ ((packed))
gds_vector_t;
typedef struct {
_GDS_SUBVECTOR_HEADER
} __attribute__ ((packed))
gds_subvector_t;
typedef struct {
_HWCB_HEADER
} __attribute__ ((packed))
read_hwcb_t;
#warning
static read_hwcb_t read_hwcb_template =
{
PAGE_SIZE,
0x00,
{
0x00,
0x00,
0x80
}
};
#endif /* __HWC_H__ */
/*
* drivers/s390/char/hwc_con.c
* HWC line mode console driver
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/kdev_t.h>
#include <linux/string.h>
#include <linux/console.h>
#include <linux/fs.h>
#include <linux/init.h>
#include "hwc_rw.h"
#ifdef CONFIG_HWC_CONSOLE
#define hwc_console_major 4
#define hwc_console_minor 64
#define hwc_console_name "console"
void hwc_console_write (struct console *, const char *, unsigned int);
kdev_t hwc_console_device (struct console *);
void hwc_console_unblank (void);
#define HWC_CON_PRINT_HEADER "hwc console driver: "
struct console hwc_console =
{
name:hwc_console_name,
write:hwc_console_write,
device:hwc_console_device,
unblank:hwc_console_unblank,
flags:CON_PRINTBUFFER,
};
void
hwc_console_write (
struct console *console,
const char *message,
unsigned int count)
{
if (kdev_val (console->device (console)) !=
kdev_val (hwc_console.device (&hwc_console))) {
hwc_printk (KERN_WARNING HWC_CON_PRINT_HEADER
"hwc_console_write() called with wrong "
"device number");
return;
}
hwc_write (0, message, count);
}
kdev_t
hwc_console_device (struct console * c)
{
return mk_kdev (hwc_console_major, hwc_console_minor);
}
void
hwc_console_unblank (void)
{
hwc_unblank ();
}
#endif
void __init
hwc_console_init (void)
{
if (!MACHINE_HAS_HWC)
return;
if (hwc_init () == 0) {
#ifdef CONFIG_HWC_CONSOLE
if (CONSOLE_IS_HWC)
register_console (&hwc_console);
#endif
} else
panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !");
return;
}
/*
* Author: Martin Peschke <mpeschke@de.ibm.com>
* Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
*/
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/sched.h>
#include <asm/semaphore.h>
#include <asm/ebcdic.h>
#include "hwc_rw.h"
#include "hwc.h"
#define CPI_RETRIES 3
#define CPI_SLEEP_TICKS 50
#define CPI_LENGTH_SYSTEM_TYPE 8
#define CPI_LENGTH_SYSTEM_NAME 8
#define CPI_LENGTH_SYSPLEX_NAME 8
typedef struct {
_EBUF_HEADER
u8 id_format;
u8 reserved0;
u8 system_type[CPI_LENGTH_SYSTEM_TYPE];
u64 reserved1;
u8 system_name[CPI_LENGTH_SYSTEM_NAME];
u64 reserved2;
u64 system_level;
u64 reserved3;
u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
u8 reserved4[16];
} __attribute__ ((packed))
cpi_evbuf_t;
typedef struct _cpi_hwcb_t {
_HWCB_HEADER
cpi_evbuf_t cpi_evbuf;
} __attribute__ ((packed))
cpi_hwcb_t;
cpi_hwcb_t *cpi_hwcb;
static int __init cpi_module_init (void);
static void __exit cpi_module_exit (void);
module_init (cpi_module_init);
module_exit (cpi_module_exit);
MODULE_AUTHOR (
"Martin Peschke, IBM Deutschland Entwicklung GmbH "
"<mpeschke@de.ibm.com>");
MODULE_DESCRIPTION (
"identify this operating system instance to the S/390 or zSeries hardware");
static char *system_name = NULL;
MODULE_PARM (system_name, "s");
MODULE_PARM_DESC (system_name, "e.g. hostname - max. 8 characters");
static char *sysplex_name = NULL;
#ifdef ALLOW_SYSPLEX_NAME
MODULE_PARM (sysplex_name, "s");
MODULE_PARM_DESC (sysplex_name, "if applicable - max. 8 characters");
#endif
static char *system_type = "LINUX";
hwc_request_t cpi_request =
{};
hwc_callback_t cpi_callback;
static DECLARE_MUTEX_LOCKED (sem);
static int __init
cpi_module_init (void)
{
int retval;
int system_type_length;
int system_name_length;
int sysplex_name_length = 0;
int retries;
if (!MACHINE_HAS_HWC) {
printk ("cpi: bug: hardware console not present\n");
retval = -EINVAL;
goto out;
}
if (!system_type) {
printk ("cpi: bug: no system type specified\n");
retval = -EINVAL;
goto out;
}
system_type_length = strlen (system_type);
if (system_type_length > CPI_LENGTH_SYSTEM_NAME) {
printk ("cpi: bug: system type has length of %i characters - "
"only %i characters supported\n",
system_type_length,
CPI_LENGTH_SYSTEM_TYPE);
retval = -EINVAL;
goto out;
}
if (!system_name) {
printk ("cpi: no system name specified\n");
retval = -EINVAL;
goto out;
}
system_name_length = strlen (system_name);
if (system_name_length > CPI_LENGTH_SYSTEM_NAME) {
printk ("cpi: system name has length of %i characters - "
"only %i characters supported\n",
system_name_length,
CPI_LENGTH_SYSTEM_NAME);
retval = -EINVAL;
goto out;
}
if (sysplex_name) {
sysplex_name_length = strlen (sysplex_name);
if (sysplex_name_length > CPI_LENGTH_SYSPLEX_NAME) {
printk ("cpi: sysplex name has length of %i characters - "
"only %i characters supported\n",
sysplex_name_length,
CPI_LENGTH_SYSPLEX_NAME);
retval = -EINVAL;
goto out;
}
}
cpi_hwcb = kmalloc (sizeof (cpi_hwcb_t), GFP_KERNEL);
if (!cpi_hwcb) {
printk ("cpi: no storage to fulfill request\n");
retval = -ENOMEM;
goto out;
}
memset (cpi_hwcb, 0, sizeof (cpi_hwcb_t));
cpi_hwcb->length = sizeof (cpi_hwcb_t);
cpi_hwcb->cpi_evbuf.length = sizeof (cpi_evbuf_t);
cpi_hwcb->cpi_evbuf.type = 0x0B;
memset (cpi_hwcb->cpi_evbuf.system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
memcpy (cpi_hwcb->cpi_evbuf.system_type, system_type, system_type_length);
HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
memset (cpi_hwcb->cpi_evbuf.system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
memcpy (cpi_hwcb->cpi_evbuf.system_name, system_name, system_name_length);
HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
cpi_hwcb->cpi_evbuf.system_level = LINUX_VERSION_CODE;
if (sysplex_name) {
memset (cpi_hwcb->cpi_evbuf.sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
memcpy (cpi_hwcb->cpi_evbuf.sysplex_name, sysplex_name, sysplex_name_length);
HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
EBC_TOUPPER (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
}
cpi_request.block = cpi_hwcb;
cpi_request.word = HWC_CMDW_WRITEDATA;
cpi_request.callback = cpi_callback;
for (retries = CPI_RETRIES; retries; retries--) {
retval = hwc_send (&cpi_request);
if (retval) {
set_current_state (TASK_INTERRUPTIBLE);
schedule_timeout (CPI_SLEEP_TICKS);
} else {
down (&sem);
switch (cpi_hwcb->response_code) {
case 0x0020:
printk ("cpi: succeeded\n");
break;
default:
printk ("cpi: failed with response code 0x%x\n",
cpi_hwcb->response_code);
}
goto free;
}
}
printk ("cpi: failed (%i)\n", retval);
free:
kfree (cpi_hwcb);
out:
return retval;
}
static void __exit
cpi_module_exit (void)
{
printk ("cpi: exit\n");
}
void
cpi_callback (hwc_request_t * req)
{
up (&sem);
}
This diff is collapsed.
/*
* drivers/s390/char/hwc_rw.h
* interface to the HWC-read/write driver
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
*/
#ifndef __HWC_RW_H__
#define __HWC_RW_H__
#include <linux/ioctl.h>
typedef struct {
void (*move_input) (unsigned char *, unsigned int);
void (*wake_up) (void);
} hwc_high_level_calls_t;
struct _hwc_request;
typedef void hwc_callback_t (struct _hwc_request *);
typedef struct _hwc_request {
void *block;
u32 word;
hwc_callback_t *callback;
void *data;
} __attribute__ ((packed))
hwc_request_t;
#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
#define HWC_ASCEBC_STR(s,c) ((MACHINE_IS_VM ? ASCEBC(s,c) : ASCEBC_500(s,c)))
#define IN_HWCB 1
#define IN_WRITE_BUF 2
#define IN_BUFS_TOTAL (IN_HWCB | IN_WRITE_BUF)
typedef unsigned short int ioctl_htab_t;
typedef unsigned char ioctl_echo_t;
typedef unsigned short int ioctl_cols_t;
typedef signed char ioctl_nl_t;
typedef unsigned short int ioctl_obuf_t;
typedef unsigned char ioctl_case_t;
typedef unsigned char ioctl_delim_t;
typedef struct {
ioctl_htab_t width_htab;
ioctl_echo_t echo;
ioctl_cols_t columns;
ioctl_nl_t final_nl;
ioctl_obuf_t max_hwcb;
ioctl_obuf_t kmem_hwcb;
ioctl_case_t tolower;
ioctl_delim_t delim;
} hwc_ioctls_t;
extern hwc_ioctls_t _hwc_ioctls;
#define HWC_IOCTL_LETTER 'B'
#define TIOCHWCSHTAB _IOW(HWC_IOCTL_LETTER, 0, _hwc_ioctls.width_htab)
#define TIOCHWCSECHO _IOW(HWC_IOCTL_LETTER, 1, _hwc_ioctls.echo)
#define TIOCHWCSCOLS _IOW(HWC_IOCTL_LETTER, 2, _hwc_ioctls.columns)
#define TIOCHWCSNL _IOW(HWC_IOCTL_LETTER, 4, _hwc_ioctls.final_nl)
#define TIOCHWCSOBUF _IOW(HWC_IOCTL_LETTER, 5, _hwc_ioctls.max_hwcb)
#define TIOCHWCSINIT _IO(HWC_IOCTL_LETTER, 6)
#define TIOCHWCSCASE _IOW(HWC_IOCTL_LETTER, 7, _hwc_ioctls.tolower)
#define TIOCHWCSDELIM _IOW(HWC_IOCTL_LETTER, 9, _hwc_ioctls.delim)
#define TIOCHWCGHTAB _IOR(HWC_IOCTL_LETTER, 10, _hwc_ioctls.width_htab)
#define TIOCHWCGECHO _IOR(HWC_IOCTL_LETTER, 11, _hwc_ioctls.echo)
#define TIOCHWCGCOLS _IOR(HWC_IOCTL_LETTER, 12, _hwc_ioctls.columns)
#define TIOCHWCGNL _IOR(HWC_IOCTL_LETTER, 14, _hwc_ioctls.final_nl)
#define TIOCHWCGOBUF _IOR(HWC_IOCTL_LETTER, 15, _hwc_ioctls.max_hwcb)
#define TIOCHWCGINIT _IOR(HWC_IOCTL_LETTER, 16, _hwc_ioctls)
#define TIOCHWCGCASE _IOR(HWC_IOCTL_LETTER, 17, _hwc_ioctls.tolower)
#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.delim)
#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls.max_hwcb)
#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls)
#ifndef __HWC_RW_C__
extern int hwc_init (void);
extern int hwc_write (int from_user, const unsigned char *, unsigned int);
extern unsigned int hwc_chars_in_buffer (unsigned char);
extern unsigned int hwc_write_room (unsigned char);
extern void hwc_flush_buffer (unsigned char);
extern void hwc_unblank (void);
extern signed int hwc_ioctl (unsigned int, unsigned long);
extern void do_hwc_interrupt (void);
extern int hwc_printk (const char *,...);
extern signed int hwc_register_calls (hwc_high_level_calls_t *);
extern signed int hwc_unregister_calls (hwc_high_level_calls_t *);
extern int hwc_send (hwc_request_t *);
#endif
#endif
/*
* drivers/s390/char/hwc_tty.c
* HWC line mode terminal driver.
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
*
* Thanks to Martin Schwidefsky.
*/
#include <linux/config.h>
#include <linux/major.h>
#include <linux/termios.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include "hwc_rw.h"
#include "ctrlchar.h"
#define HWC_TTY_PRINT_HEADER "hwc tty driver: "
#define HWC_TTY_BUF_SIZE 512
typedef struct {
struct tty_struct *tty;
unsigned char buf[HWC_TTY_BUF_SIZE];
unsigned short int buf_count;
spinlock_t lock;
hwc_high_level_calls_t calls;
} hwc_tty_data_struct;
static hwc_tty_data_struct hwc_tty_data =
{ /* NULL/0 */ };
static struct tty_driver hwc_tty_driver;
static struct tty_struct *hwc_tty_table[1];
static struct termios *hwc_tty_termios[1];
static struct termios *hwc_tty_termios_locked[1];
static int hwc_tty_refcount = 0;
extern struct termios tty_std_termios;
void hwc_tty_wake_up (void);
void hwc_tty_input (unsigned char *, unsigned int);
static int
hwc_tty_open (struct tty_struct *tty,
struct file *filp)
{
if (minor (tty->device) - tty->driver.minor_start)
return -ENODEV;
tty->driver_data = &hwc_tty_data;
hwc_tty_data.buf_count = 0;
hwc_tty_data.tty = tty;
tty->low_latency = 0;
hwc_tty_data.calls.wake_up = hwc_tty_wake_up;
hwc_tty_data.calls.move_input = hwc_tty_input;
hwc_register_calls (&(hwc_tty_data.calls));
return 0;
}
static void
hwc_tty_close (struct tty_struct *tty,
struct file *filp)
{
if (minor (tty->device) != tty->driver.minor_start) {
printk (KERN_WARNING HWC_TTY_PRINT_HEADER
"do not close hwc tty because of wrong device number");
return;
}
if (tty->count > 1)
return;
hwc_tty_data.tty = NULL;
hwc_unregister_calls (&(hwc_tty_data.calls));
}
static int
hwc_tty_write_room (struct tty_struct *tty)
{
int retval;
retval = hwc_write_room (IN_BUFS_TOTAL);
return retval;
}
static int
hwc_tty_write (struct tty_struct *tty,
int from_user,
const unsigned char *buf,
int count)
{
int retval;
if (hwc_tty_data.buf_count > 0) {
hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
hwc_tty_data.buf_count = 0;
}
retval = hwc_write (from_user, buf, count);
return retval;
}
static void
hwc_tty_put_char (struct tty_struct *tty,
unsigned char ch)
{
unsigned long flags;
spin_lock_irqsave (&hwc_tty_data.lock, flags);
if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE) {
hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
hwc_tty_data.buf_count = 0;
}
hwc_tty_data.buf[hwc_tty_data.buf_count] = ch;
hwc_tty_data.buf_count++;
spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
}
static void
hwc_tty_flush_chars (struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave (&hwc_tty_data.lock, flags);
hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
hwc_tty_data.buf_count = 0;
spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
}
static int
hwc_tty_chars_in_buffer (struct tty_struct *tty)
{
int retval;
retval = hwc_chars_in_buffer (IN_BUFS_TOTAL);
return retval;
}
static void
hwc_tty_flush_buffer (struct tty_struct *tty)
{
hwc_tty_wake_up ();
}
static int
hwc_tty_ioctl (
struct tty_struct *tty,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
return hwc_ioctl (cmd, arg);
}
void
hwc_tty_wake_up (void)
{
if (hwc_tty_data.tty == NULL)
return;
if ((hwc_tty_data.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
hwc_tty_data.tty->ldisc.write_wakeup)
(hwc_tty_data.tty->ldisc.write_wakeup) (hwc_tty_data.tty);
wake_up_interruptible (&hwc_tty_data.tty->write_wait);
}
void
hwc_tty_input (unsigned char *buf, unsigned int count)
{
struct tty_struct *tty = hwc_tty_data.tty;
if (tty != NULL) {
unsigned int cchar = ctrlchar_handle(buf, count, tty);
switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ:
return;
case CTRLCHAR_CTRL:
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = cchar;
break;
case CTRLCHAR_NONE:
memcpy (tty->flip.char_buf_ptr, buf, count);
if (count < 2 || (
strncmp (buf + count - 2, "^n", 2) ||
strncmp (buf + count - 2, "\0252n", 2))) {
tty->flip.char_buf_ptr[count] = '\n';
count++;
} else
count -= 2;
memset (tty->flip.flag_buf_ptr, TTY_NORMAL, count);
tty->flip.char_buf_ptr += count;
tty->flip.flag_buf_ptr += count;
tty->flip.count += count;
break;
}
tty_flip_buffer_push (tty);
hwc_tty_wake_up ();
}
}
void
hwc_tty_init (void)
{
if (!CONSOLE_IS_HWC)
return;
memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
hwc_tty_driver.driver_name = "tty_hwc";
hwc_tty_driver.name = "ttyS";
hwc_tty_driver.name_base = 0;
hwc_tty_driver.major = TTY_MAJOR;
hwc_tty_driver.minor_start = 64;
hwc_tty_driver.num = 1;
hwc_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM;
hwc_tty_driver.subtype = SYSTEM_TYPE_TTY;
hwc_tty_driver.init_termios = tty_std_termios;
hwc_tty_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
hwc_tty_driver.init_termios.c_oflag = ONLCR;
hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO;
hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW;
hwc_tty_driver.refcount = &hwc_tty_refcount;
hwc_tty_driver.table = hwc_tty_table;
hwc_tty_driver.termios = hwc_tty_termios;
hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
hwc_tty_driver.open = hwc_tty_open;
hwc_tty_driver.close = hwc_tty_close;
hwc_tty_driver.write = hwc_tty_write;
hwc_tty_driver.put_char = hwc_tty_put_char;
hwc_tty_driver.flush_chars = hwc_tty_flush_chars;
hwc_tty_driver.write_room = hwc_tty_write_room;
hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer;
hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer;
hwc_tty_driver.ioctl = hwc_tty_ioctl;
hwc_tty_driver.throttle = NULL;
hwc_tty_driver.unthrottle = NULL;
hwc_tty_driver.send_xchar = NULL;
hwc_tty_driver.set_termios = NULL;
hwc_tty_driver.set_ldisc = NULL;
hwc_tty_driver.stop = NULL;
hwc_tty_driver.start = NULL;
hwc_tty_driver.hangup = NULL;
hwc_tty_driver.break_ctl = NULL;
hwc_tty_driver.wait_until_sent = NULL;
hwc_tty_driver.read_proc = NULL;
hwc_tty_driver.write_proc = NULL;
if (tty_register_driver (&hwc_tty_driver))
panic ("Couldn't register hwc_tty driver\n");
}
......@@ -31,7 +31,7 @@ extern unsigned long machine_flags;
#define MACHINE_HAS_CSP (machine_flags & 8)
#define MACHINE_HAS_MVPG (machine_flags & 16)
#define MACHINE_HAS_HWC (!MACHINE_IS_P390)
#define MACHINE_HAS_SCLP (!MACHINE_IS_P390)
/*
* Console mode. Override with conmode=
......@@ -40,10 +40,10 @@ extern unsigned int console_mode;
extern unsigned int console_device;
#define CONSOLE_IS_UNDEFINED (console_mode == 0)
#define CONSOLE_IS_HWC (console_mode == 1)
#define CONSOLE_IS_SCLP (console_mode == 1)
#define CONSOLE_IS_3215 (console_mode == 2)
#define CONSOLE_IS_3270 (console_mode == 3)
#define SET_CONSOLE_HWC do { console_mode = 1; } while (0)
#define SET_CONSOLE_SCLP do { console_mode = 1; } while (0)
#define SET_CONSOLE_3215 do { console_mode = 2; } while (0)
#define SET_CONSOLE_3270 do { console_mode = 3; } while (0)
......
......@@ -30,7 +30,7 @@ extern unsigned long machine_flags;
#define MACHINE_HAS_MVPG (machine_flags & 16)
#define MACHINE_HAS_DIAG44 (machine_flags & 32)
#define MACHINE_HAS_HWC (!MACHINE_IS_P390)
#define MACHINE_HAS_SCLP (!MACHINE_IS_P390)
/*
* Console mode. Override with conmode=
......@@ -39,10 +39,10 @@ extern unsigned int console_mode;
extern unsigned int console_device;
#define CONSOLE_IS_UNDEFINED (console_mode == 0)
#define CONSOLE_IS_HWC (console_mode == 1)
#define CONSOLE_IS_SCLP (console_mode == 1)
#define CONSOLE_IS_3215 (console_mode == 2)
#define CONSOLE_IS_3270 (console_mode == 3)
#define SET_CONSOLE_HWC do { console_mode = 1; } while (0)
#define SET_CONSOLE_SCLP do { console_mode = 1; } while (0)
#define SET_CONSOLE_3215 do { console_mode = 2; } while (0)
#define SET_CONSOLE_3270 do { console_mode = 3; } while (0)
......
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