Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
49d7127a
Commit
49d7127a
authored
Nov 17, 2002
by
Martin Schwidefsky
Committed by
Linus Torvalds
Nov 17, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] s390: sclp driver part 1.
Reworked sclp driver part 1.
parent
e540dbf8
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
67 additions
and
3513 deletions
+67
-3513
arch/s390/defconfig
arch/s390/defconfig
+4
-3
arch/s390/kernel/setup.c
arch/s390/kernel/setup.c
+11
-11
arch/s390x/defconfig
arch/s390x/defconfig
+4
-3
arch/s390x/kernel/setup.c
arch/s390x/kernel/setup.c
+11
-11
drivers/char/tty_io.c
drivers/char/tty_io.c
+6
-7
drivers/s390/Kconfig
drivers/s390/Kconfig
+15
-9
drivers/s390/char/Makefile
drivers/s390/char/Makefile
+10
-15
drivers/s390/char/hwc.h
drivers/s390/char/hwc.h
+0
-280
drivers/s390/char/hwc_con.c
drivers/s390/char/hwc_con.c
+0
-92
drivers/s390/char/hwc_cpi.c
drivers/s390/char/hwc_cpi.c
+0
-212
drivers/s390/char/hwc_rw.c
drivers/s390/char/hwc_rw.c
+0
-2456
drivers/s390/char/hwc_rw.h
drivers/s390/char/hwc_rw.h
+0
-132
drivers/s390/char/hwc_tty.c
drivers/s390/char/hwc_tty.c
+0
-276
include/asm-s390/setup.h
include/asm-s390/setup.h
+3
-3
include/asm-s390x/setup.h
include/asm-s390x/setup.h
+3
-3
No files found.
arch/s390/defconfig
View file @
49d7127a
...
...
@@ -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
#
...
...
arch/s390/kernel/setup.c
View file @
49d7127a
...
...
@@ -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
}
}
...
...
arch/s390x/defconfig
View file @
49d7127a
...
...
@@ -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
#
...
...
arch/s390x/kernel/setup.c
View file @
49d7127a
...
...
@@ -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
}
}
...
...
drivers/char/tty_io.c
View file @
49d7127a
...
...
@@ -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
();
...
...
drivers/s390/Kconfig
View file @
49d7127a
...
...
@@ -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.
...
...
drivers/s390/char/Makefile
View file @
49d7127a
...
...
@@ -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
deleted
100644 → 0
View file @
e540dbf8
/*
* 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
deleted
100644 → 0
View file @
e540dbf8
/*
* 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
;
}
drivers/s390/char/hwc_cpi.c
deleted
100644 → 0
View file @
e540dbf8
/*
* 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
);
}
drivers/s390/char/hwc_rw.c
deleted
100644 → 0
View file @
e540dbf8
/*
* drivers/s390/char/hwc_rw.c
* driver: reading from and writing to system console on S/390 via HWC
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
*
*
*
*
*
*
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
#include <asm/types.h>
#include <asm/bitops.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/s390_ext.h>
#include <asm/irq.h>
#ifndef MIN
#define MIN(a,b) (((a<b) ? a : b))
#endif
extern
void
ctrl_alt_del
(
void
);
#define HWC_RW_PRINT_HEADER "hwc low level driver: "
#define USE_VM_DETECTION
#define DEFAULT_CASE_DELIMITER '%'
#undef DUMP_HWC_INIT_ERROR
#undef DUMP_HWC_WRITE_ERROR
#undef DUMP_HWC_WRITE_LIST_ERROR
#undef DUMP_HWC_READ_ERROR
#undef DUMP_HWCB_INPUT
#undef BUFFER_STRESS_TEST
typedef
struct
{
unsigned
char
*
next
;
unsigned
short
int
mto_char_sum
;
unsigned
char
mto_number
;
unsigned
char
times_lost
;
unsigned
short
int
mto_number_lost
;
unsigned
long
int
mto_char_sum_lost
;
}
__attribute__
((
packed
))
hwcb_list_t
;
#define MAX_HWCB_ROOM (PAGE_SIZE - sizeof(hwcb_list_t))
#define MAX_MESSAGE_SIZE (MAX_HWCB_ROOM - sizeof(write_hwcb_t))
#define BUF_HWCB hwc_data.hwcb_list_tail
#define OUT_HWCB hwc_data.hwcb_list_head
#define ALL_HWCB_MTO hwc_data.mto_number
#define ALL_HWCB_CHAR hwc_data.mto_char_sum
#define _LIST(hwcb) ((hwcb_list_t*)(&(hwcb)[PAGE_SIZE-sizeof(hwcb_list_t)]))
#define _HWCB_CHAR(hwcb) (_LIST(hwcb)->mto_char_sum)
#define _HWCB_MTO(hwcb) (_LIST(hwcb)->mto_number)
#define _HWCB_CHAR_LOST(hwcb) (_LIST(hwcb)->mto_char_sum_lost)
#define _HWCB_MTO_LOST(hwcb) (_LIST(hwcb)->mto_number_lost)
#define _HWCB_TIMES_LOST(hwcb) (_LIST(hwcb)->times_lost)
#define _HWCB_NEXT(hwcb) (_LIST(hwcb)->next)
#define BUF_HWCB_CHAR _HWCB_CHAR(BUF_HWCB)
#define BUF_HWCB_MTO _HWCB_MTO(BUF_HWCB)
#define BUF_HWCB_NEXT _HWCB_NEXT(BUF_HWCB)
#define OUT_HWCB_CHAR _HWCB_CHAR(OUT_HWCB)
#define OUT_HWCB_MTO _HWCB_MTO(OUT_HWCB)
#define OUT_HWCB_NEXT _HWCB_NEXT(OUT_HWCB)
#define BUF_HWCB_CHAR_LOST _HWCB_CHAR_LOST(BUF_HWCB)
#define BUF_HWCB_MTO_LOST _HWCB_MTO_LOST(BUF_HWCB)
#define OUT_HWCB_CHAR_LOST _HWCB_CHAR_LOST(OUT_HWCB)
#define OUT_HWCB_MTO_LOST _HWCB_MTO_LOST(OUT_HWCB)
#define BUF_HWCB_TIMES_LOST _HWCB_TIMES_LOST(BUF_HWCB)
#include "hwc.h"
#define __HWC_RW_C__
#include "hwc_rw.h"
#undef __HWC_RW_C__
static
unsigned
char
_obuf
[
MAX_HWCB_ROOM
];
static
unsigned
char
_page
[
PAGE_SIZE
]
__attribute__
((
aligned
(
PAGE_SIZE
)));
typedef
unsigned
long
kmem_pages_t
;
#define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
#define HWC_WTIMER_RUNS 1
#define HWC_FLUSH 2
#define HWC_INIT 4
#define HWC_BROKEN 8
#define HWC_INTERRUPT 16
#define HWC_PTIMER_RUNS 32
static
struct
{
hwc_ioctls_t
ioctls
;
hwc_ioctls_t
init_ioctls
;
unsigned
char
*
hwcb_list_head
;
unsigned
char
*
hwcb_list_tail
;
unsigned
short
int
mto_number
;
unsigned
int
mto_char_sum
;
unsigned
char
hwcb_count
;
unsigned
long
kmem_start
;
unsigned
long
kmem_end
;
kmem_pages_t
kmem_pages
;
unsigned
char
*
obuf
;
unsigned
short
int
obuf_cursor
;
unsigned
short
int
obuf_count
;
unsigned
short
int
obuf_start
;
unsigned
char
*
page
;
u32
current_servc
;
unsigned
char
*
current_hwcb
;
unsigned
char
write_nonprio
:
1
;
unsigned
char
write_prio
:
1
;
unsigned
char
read_nonprio
:
1
;
unsigned
char
read_prio
:
1
;
unsigned
char
read_statechange
:
1
;
unsigned
char
sig_quiesce
:
1
;
unsigned
char
flags
;
hwc_high_level_calls_t
*
calls
;
hwc_request_t
*
request
;
spinlock_t
lock
;
struct
timer_list
write_timer
;
struct
timer_list
poll_timer
;
}
hwc_data
=
{
{
},
{
8
,
0
,
80
,
1
,
MAX_KMEM_PAGES
,
MAX_KMEM_PAGES
,
0
,
0x6c
},
NULL
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
,
_obuf
,
0
,
0
,
0
,
_page
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
NULL
,
NULL
};
static
unsigned
long
cr0
__attribute__
((
aligned
(
8
)));
static
unsigned
long
cr0_save
__attribute__
((
aligned
(
8
)));
static
unsigned
char
psw_mask
__attribute__
((
aligned
(
8
)));
static
ext_int_info_t
ext_int_info_hwc
;
#define DELAYED_WRITE 0
#define IMMEDIATE_WRITE 1
static
signed
int
do_hwc_write
(
int
from_user
,
unsigned
char
*
,
unsigned
int
,
unsigned
char
);
unsigned
char
hwc_ip_buf
[
512
];
static
asmlinkage
int
internal_print
(
char
write_time
,
char
*
fmt
,...)
{
va_list
args
;
int
i
;
va_start
(
args
,
fmt
);
i
=
vsprintf
(
hwc_ip_buf
,
fmt
,
args
);
va_end
(
args
);
return
do_hwc_write
(
0
,
hwc_ip_buf
,
i
,
write_time
);
}
int
hwc_printk
(
const
char
*
fmt
,...)
{
va_list
args
;
int
i
;
unsigned
long
flags
;
int
retval
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
i
=
vsprintf
(
hwc_ip_buf
,
fmt
,
args
);
va_end
(
args
);
retval
=
do_hwc_write
(
0
,
hwc_ip_buf
,
i
,
IMMEDIATE_WRITE
);
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
return
retval
;
}
#ifdef DUMP_HWCB_INPUT
static
void
dump_storage_area
(
unsigned
char
*
area
,
unsigned
short
int
count
)
{
unsigned
short
int
index
;
ioctl_nl_t
old_final_nl
;
if
(
!
area
||
!
count
)
return
;
old_final_nl
=
hwc_data
.
ioctls
.
final_nl
;
hwc_data
.
ioctls
.
final_nl
=
1
;
internal_print
(
DELAYED_WRITE
,
"
\n
%8x "
,
area
);
for
(
index
=
0
;
index
<
count
;
index
++
)
{
if
(
area
[
index
]
<=
0xF
)
internal_print
(
DELAYED_WRITE
,
"0%x"
,
area
[
index
]);
else
internal_print
(
DELAYED_WRITE
,
"%x"
,
area
[
index
]);
if
((
index
&
0xF
)
==
0xF
)
internal_print
(
DELAYED_WRITE
,
"
\n
%8x "
,
&
area
[
index
+
1
]);
else
if
((
index
&
3
)
==
3
)
internal_print
(
DELAYED_WRITE
,
" "
);
}
internal_print
(
IMMEDIATE_WRITE
,
"
\n
"
);
hwc_data
.
ioctls
.
final_nl
=
old_final_nl
;
}
#endif
static
inline
u32
service_call
(
u32
hwc_command_word
,
unsigned
char
hwcb
[])
{
unsigned
int
condition_code
=
1
;
__asm__
__volatile__
(
"L 1, 0(%0)
\n\t
"
"LRA 2, 0(%1)
\n\t
"
".long 0xB2200012
\n\t
"
:
:
"a"
(
&
hwc_command_word
),
"a"
(
hwcb
)
:
"1"
,
"2"
,
"memory"
);
__asm__
__volatile__
(
"IPM %0
\n\t
"
"SRL %0, 28
\n\t
"
:
"=r"
(
condition_code
));
return
condition_code
;
}
static
inline
unsigned
long
hwc_ext_int_param
(
void
)
{
u32
param
;
__asm__
__volatile__
(
"L %0,128
\n\t
"
:
"=r"
(
param
));
return
(
unsigned
long
)
param
;
}
static
int
prepare_write_hwcb
(
void
)
{
write_hwcb_t
*
hwcb
;
if
(
!
BUF_HWCB
)
return
-
ENOMEM
;
BUF_HWCB_MTO
=
0
;
BUF_HWCB_CHAR
=
0
;
hwcb
=
(
write_hwcb_t
*
)
BUF_HWCB
;
memcpy
(
hwcb
,
&
write_hwcb_template
,
sizeof
(
write_hwcb_t
));
return
0
;
}
static
int
sane_write_hwcb
(
void
)
{
unsigned
short
int
lost_msg
;
unsigned
int
lost_char
;
unsigned
char
lost_hwcb
;
unsigned
char
*
bad_addr
;
unsigned
long
page
;
int
page_nr
;
if
(
!
OUT_HWCB
)
return
-
ENOMEM
;
if
((
unsigned
long
)
OUT_HWCB
&
0xFFF
)
{
bad_addr
=
OUT_HWCB
;
#ifdef DUMP_HWC_WRITE_LIST_ERROR
__asm__
(
"LHI 1,0xe30
\n\t
"
"LRA 2,0(%0)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
bad_addr
)
:
"1"
,
"2"
);
#endif
hwc_data
.
kmem_pages
=
0
;
if
((
unsigned
long
)
BUF_HWCB
&
0xFFF
)
{
lost_hwcb
=
hwc_data
.
hwcb_count
;
lost_msg
=
ALL_HWCB_MTO
;
lost_char
=
ALL_HWCB_CHAR
;
OUT_HWCB
=
NULL
;
BUF_HWCB
=
NULL
;
ALL_HWCB_MTO
=
0
;
ALL_HWCB_CHAR
=
0
;
hwc_data
.
hwcb_count
=
0
;
}
else
{
lost_hwcb
=
hwc_data
.
hwcb_count
-
1
;
lost_msg
=
ALL_HWCB_MTO
-
BUF_HWCB_MTO
;
lost_char
=
ALL_HWCB_CHAR
-
BUF_HWCB_CHAR
;
OUT_HWCB
=
BUF_HWCB
;
ALL_HWCB_MTO
=
BUF_HWCB_MTO
;
ALL_HWCB_CHAR
=
BUF_HWCB_CHAR
;
hwc_data
.
hwcb_count
=
1
;
page
=
(
unsigned
long
)
BUF_HWCB
;
if
(
page
>=
hwc_data
.
kmem_start
&&
page
<=
hwc_data
.
kmem_end
)
{
page_nr
=
(
int
)
((
page
-
hwc_data
.
kmem_start
)
>>
12
);
set_bit
(
page_nr
,
&
hwc_data
.
kmem_pages
);
}
}
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"found invalid HWCB at address 0x%lx. List corrupted. "
"Lost %i HWCBs with %i characters within up to %i "
"messages. Saved %i HWCB with last %i characters i"
"within up to %i messages.
\n
"
,
(
unsigned
long
)
bad_addr
,
lost_hwcb
,
lost_char
,
lost_msg
,
hwc_data
.
hwcb_count
,
ALL_HWCB_CHAR
,
ALL_HWCB_MTO
);
}
return
0
;
}
static
int
reuse_write_hwcb
(
void
)
{
int
retval
;
if
(
hwc_data
.
hwcb_count
<
2
)
#ifdef DUMP_HWC_WRITE_LIST_ERROR
__asm__
(
"LHI 1,0xe31
\n\t
"
"LRA 2,0(%0)
\n\t
"
"LRA 3,0(%1)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
BUF_HWCB
),
"a"
(
OUT_HWCB
)
:
"1"
,
"2"
,
"3"
);
#else
return
-
EPERM
;
#endif
if
(
hwc_data
.
current_hwcb
==
OUT_HWCB
)
{
if
(
hwc_data
.
hwcb_count
>
2
)
{
BUF_HWCB_NEXT
=
OUT_HWCB_NEXT
;
BUF_HWCB
=
OUT_HWCB_NEXT
;
OUT_HWCB_NEXT
=
BUF_HWCB_NEXT
;
BUF_HWCB_NEXT
=
NULL
;
}
}
else
{
BUF_HWCB_NEXT
=
OUT_HWCB
;
BUF_HWCB
=
OUT_HWCB
;
OUT_HWCB
=
OUT_HWCB_NEXT
;
BUF_HWCB_NEXT
=
NULL
;
}
BUF_HWCB_TIMES_LOST
+=
1
;
BUF_HWCB_CHAR_LOST
+=
BUF_HWCB_CHAR
;
BUF_HWCB_MTO_LOST
+=
BUF_HWCB_MTO
;
ALL_HWCB_MTO
-=
BUF_HWCB_MTO
;
ALL_HWCB_CHAR
-=
BUF_HWCB_CHAR
;
retval
=
prepare_write_hwcb
();
if
(
hwc_data
.
hwcb_count
==
hwc_data
.
ioctls
.
max_hwcb
)
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"reached my own limit of "
"allowed buffer space for output (%i HWCBs = %li "
"bytes), skipped content of oldest HWCB %i time(s) "
"(%i lines = %i characters)
\n
"
,
hwc_data
.
ioctls
.
max_hwcb
,
hwc_data
.
ioctls
.
max_hwcb
*
PAGE_SIZE
,
BUF_HWCB_TIMES_LOST
,
BUF_HWCB_MTO_LOST
,
BUF_HWCB_CHAR_LOST
);
else
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"page allocation failed, "
"could not expand buffer for output (currently in "
"use: %i HWCBs = %li bytes), skipped content of "
"oldest HWCB %i time(s) (%i lines = %i characters)
\n
"
,
hwc_data
.
hwcb_count
,
hwc_data
.
hwcb_count
*
PAGE_SIZE
,
BUF_HWCB_TIMES_LOST
,
BUF_HWCB_MTO_LOST
,
BUF_HWCB_CHAR_LOST
);
return
retval
;
}
static
int
allocate_write_hwcb
(
void
)
{
unsigned
char
*
page
;
int
page_nr
;
if
(
hwc_data
.
hwcb_count
==
hwc_data
.
ioctls
.
max_hwcb
)
return
-
ENOMEM
;
page_nr
=
find_first_zero_bit
(
&
hwc_data
.
kmem_pages
,
MAX_KMEM_PAGES
);
if
(
page_nr
<
hwc_data
.
ioctls
.
kmem_hwcb
)
{
page
=
(
unsigned
char
*
)
(
hwc_data
.
kmem_start
+
(
page_nr
<<
12
));
set_bit
(
page_nr
,
&
hwc_data
.
kmem_pages
);
}
else
page
=
(
unsigned
char
*
)
__get_free_page
(
GFP_ATOMIC
|
GFP_DMA
);
if
(
!
page
)
return
-
ENOMEM
;
if
(
!
OUT_HWCB
)
OUT_HWCB
=
page
;
else
BUF_HWCB_NEXT
=
page
;
BUF_HWCB
=
page
;
BUF_HWCB_NEXT
=
NULL
;
hwc_data
.
hwcb_count
++
;
prepare_write_hwcb
();
BUF_HWCB_TIMES_LOST
=
0
;
BUF_HWCB_MTO_LOST
=
0
;
BUF_HWCB_CHAR_LOST
=
0
;
#ifdef BUFFER_STRESS_TEST
internal_print
(
DELAYED_WRITE
,
"*** "
HWC_RW_PRINT_HEADER
"page #%i at 0x%x for buffering allocated. ***
\n
"
,
hwc_data
.
hwcb_count
,
page
);
#endif
return
0
;
}
static
int
release_write_hwcb
(
void
)
{
unsigned
long
page
;
int
page_nr
;
if
(
!
hwc_data
.
hwcb_count
)
return
-
ENODATA
;
if
(
hwc_data
.
hwcb_count
==
1
)
{
prepare_write_hwcb
();
ALL_HWCB_CHAR
=
0
;
ALL_HWCB_MTO
=
0
;
BUF_HWCB_TIMES_LOST
=
0
;
BUF_HWCB_MTO_LOST
=
0
;
BUF_HWCB_CHAR_LOST
=
0
;
}
else
{
page
=
(
unsigned
long
)
OUT_HWCB
;
ALL_HWCB_MTO
-=
OUT_HWCB_MTO
;
ALL_HWCB_CHAR
-=
OUT_HWCB_CHAR
;
hwc_data
.
hwcb_count
--
;
OUT_HWCB
=
OUT_HWCB_NEXT
;
if
(
page
>=
hwc_data
.
kmem_start
&&
page
<=
hwc_data
.
kmem_end
)
{
/*memset((void *) page, 0, PAGE_SIZE); */
page_nr
=
(
int
)
((
page
-
hwc_data
.
kmem_start
)
>>
12
);
clear_bit
(
page_nr
,
&
hwc_data
.
kmem_pages
);
}
else
free_page
(
page
);
#ifdef BUFFER_STRESS_TEST
internal_print
(
DELAYED_WRITE
,
"*** "
HWC_RW_PRINT_HEADER
"page at 0x%x released, %i pages still in use ***
\n
"
,
page
,
hwc_data
.
hwcb_count
);
#endif
}
return
0
;
}
static
int
add_mto
(
unsigned
char
*
message
,
unsigned
short
int
count
)
{
unsigned
short
int
mto_size
;
write_hwcb_t
*
hwcb
;
mto_t
*
mto
;
void
*
dest
;
if
(
!
BUF_HWCB
)
return
-
ENOMEM
;
if
(
BUF_HWCB
==
hwc_data
.
current_hwcb
)
return
-
ENOMEM
;
mto_size
=
sizeof
(
mto_t
)
+
count
;
hwcb
=
(
write_hwcb_t
*
)
BUF_HWCB
;
if
((
MAX_HWCB_ROOM
-
hwcb
->
length
)
<
mto_size
)
return
-
ENOMEM
;
mto
=
(
mto_t
*
)
(((
unsigned
long
)
hwcb
)
+
hwcb
->
length
);
memcpy
(
mto
,
&
mto_template
,
sizeof
(
mto_t
));
dest
=
(
void
*
)
(((
unsigned
long
)
mto
)
+
sizeof
(
mto_t
));
memcpy
(
dest
,
message
,
count
);
mto
->
length
+=
count
;
hwcb
->
length
+=
mto_size
;
hwcb
->
msgbuf
.
length
+=
mto_size
;
hwcb
->
msgbuf
.
mdb
.
length
+=
mto_size
;
BUF_HWCB_MTO
++
;
ALL_HWCB_MTO
++
;
BUF_HWCB_CHAR
+=
count
;
ALL_HWCB_CHAR
+=
count
;
return
count
;
}
static
int
write_event_data_1
(
void
);
static
void
do_poll_hwc
(
unsigned
long
data
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
write_event_data_1
();
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
}
void
start_poll_hwc
(
void
)
{
init_timer
(
&
hwc_data
.
poll_timer
);
hwc_data
.
poll_timer
.
function
=
do_poll_hwc
;
hwc_data
.
poll_timer
.
data
=
(
unsigned
long
)
NULL
;
hwc_data
.
poll_timer
.
expires
=
jiffies
+
2
*
HZ
;
add_timer
(
&
hwc_data
.
poll_timer
);
hwc_data
.
flags
|=
HWC_PTIMER_RUNS
;
}
static
int
write_event_data_1
(
void
)
{
unsigned
short
int
condition_code
;
int
retval
;
write_hwcb_t
*
hwcb
=
(
write_hwcb_t
*
)
OUT_HWCB
;
if
((
!
hwc_data
.
write_prio
)
&&
(
!
hwc_data
.
write_nonprio
)
&&
hwc_data
.
read_statechange
)
return
-
EOPNOTSUPP
;
if
(
hwc_data
.
current_servc
)
return
-
EBUSY
;
retval
=
sane_write_hwcb
();
if
(
retval
<
0
)
return
-
EIO
;
if
(
!
OUT_HWCB_MTO
)
return
-
ENODATA
;
if
(
!
hwc_data
.
write_nonprio
&&
hwc_data
.
write_prio
)
hwcb
->
msgbuf
.
type
=
ET_PMsgCmd
;
else
hwcb
->
msgbuf
.
type
=
ET_Msg
;
condition_code
=
service_call
(
HWC_CMDW_WRITEDATA
,
OUT_HWCB
);
#ifdef DUMP_HWC_WRITE_ERROR
if
(
condition_code
!=
HWC_COMMAND_INITIATED
)
__asm__
(
"LHI 1,0xe20
\n\t
"
"L 2,0(%0)
\n\t
"
"LRA 3,0(%1)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
&
condition_code
),
"a"
(
OUT_HWCB
)
:
"1"
,
"2"
,
"3"
);
#endif
switch
(
condition_code
)
{
case
HWC_COMMAND_INITIATED
:
hwc_data
.
current_servc
=
HWC_CMDW_WRITEDATA
;
hwc_data
.
current_hwcb
=
OUT_HWCB
;
retval
=
condition_code
;
break
;
case
HWC_BUSY
:
retval
=
-
EBUSY
;
break
;
case
HWC_NOT_OPERATIONAL
:
start_poll_hwc
();
default:
retval
=
-
EIO
;
}
return
retval
;
}
static
void
flush_hwcbs
(
void
)
{
while
(
hwc_data
.
hwcb_count
>
1
)
release_write_hwcb
();
release_write_hwcb
();
hwc_data
.
flags
&=
~
HWC_FLUSH
;
}
static
int
write_event_data_2
(
u32
ext_int_param
)
{
write_hwcb_t
*
hwcb
;
int
retval
=
0
;
#ifdef DUMP_HWC_WRITE_ERROR
if
((
ext_int_param
&
HWC_EXT_INT_PARAM_ADDR
)
!=
(
unsigned
long
)
hwc_data
.
current_hwcb
)
{
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"write_event_data_2 : "
"HWCB address does not fit "
"(expected: 0x%lx, got: 0x%lx).
\n
"
,
(
unsigned
long
)
hwc_data
.
current_hwcb
,
ext_int_param
);
return
-
EINVAL
;
}
#endif
hwcb
=
(
write_hwcb_t
*
)
OUT_HWCB
;
#ifdef DUMP_HWC_WRITE_LIST_ERROR
if
(((
unsigned
char
*
)
hwcb
)
!=
hwc_data
.
current_hwcb
)
{
__asm__
(
"LHI 1,0xe22
\n\t
"
"LRA 2,0(%0)
\n\t
"
"LRA 3,0(%1)
\n\t
"
"LRA 4,0(%2)
\n\t
"
"LRA 5,0(%3)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
OUT_HWCB
),
"a"
(
hwc_data
.
current_hwcb
),
"a"
(
BUF_HWCB
),
"a"
(
hwcb
)
:
"1"
,
"2"
,
"3"
,
"4"
,
"5"
);
}
#endif
#ifdef DUMP_HWC_WRITE_ERROR
if
(
hwcb
->
response_code
!=
0x0020
)
{
__asm__
(
"LHI 1,0xe21
\n\t
"
"LRA 2,0(%0)
\n\t
"
"LRA 3,0(%1)
\n\t
"
"LRA 4,0(%2)
\n\t
"
"LH 5,0(%3)
\n\t
"
"SRL 5,8
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
OUT_HWCB
),
"a"
(
hwc_data
.
current_hwcb
),
"a"
(
BUF_HWCB
),
"a"
(
&
(
hwc_data
.
hwcb_count
))
:
"1"
,
"2"
,
"3"
,
"4"
,
"5"
);
}
#endif
switch
(
hwcb
->
response_code
)
{
case
0x0020
:
retval
=
OUT_HWCB_CHAR
;
release_write_hwcb
();
break
;
case
0x0040
:
case
0x0340
:
case
0x40F0
:
if
(
!
hwc_data
.
read_statechange
)
{
hwcb
->
response_code
=
0
;
start_poll_hwc
();
}
retval
=
-
EIO
;
break
;
default:
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"write_event_data_2 : "
"failed operation "
"(response code: 0x%x "
"HWCB address: 0x%x).
\n
"
,
hwcb
->
response_code
,
hwcb
);
retval
=
-
EIO
;
}
if
(
retval
==
-
EIO
)
{
hwcb
->
control_mask
[
0
]
=
0
;
hwcb
->
control_mask
[
1
]
=
0
;
hwcb
->
control_mask
[
2
]
=
0
;
hwcb
->
response_code
=
0
;
}
hwc_data
.
current_servc
=
0
;
hwc_data
.
current_hwcb
=
NULL
;
if
(
hwc_data
.
flags
&
HWC_FLUSH
)
flush_hwcbs
();
return
retval
;
}
static
void
do_put_line
(
unsigned
char
*
message
,
unsigned
short
count
)
{
if
(
add_mto
(
message
,
count
)
!=
count
)
{
if
(
allocate_write_hwcb
()
<
0
)
reuse_write_hwcb
();
#ifdef DUMP_HWC_WRITE_LIST_ERROR
if
(
add_mto
(
message
,
count
)
!=
count
)
__asm__
(
"LHI 1,0xe32
\n\t
"
"LRA 2,0(%0)
\n\t
"
"L 3,0(%1)
\n\t
"
"LRA 4,0(%2)
\n\t
"
"LRA 5,0(%3)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
message
),
"a"
(
&
hwc_data
.
kmem_pages
),
"a"
(
BUF_HWCB
),
"a"
(
OUT_HWCB
)
:
"1"
,
"2"
,
"3"
,
"4"
,
"5"
);
#else
add_mto
(
message
,
count
);
#endif
}
}
static
void
put_line
(
unsigned
char
*
message
,
unsigned
short
count
)
{
if
((
!
hwc_data
.
obuf_start
)
&&
(
hwc_data
.
flags
&
HWC_WTIMER_RUNS
))
{
del_timer
(
&
hwc_data
.
write_timer
);
hwc_data
.
flags
&=
~
HWC_WTIMER_RUNS
;
}
hwc_data
.
obuf_start
+=
count
;
do_put_line
(
message
,
count
);
hwc_data
.
obuf_start
-=
count
;
}
static
void
set_alarm
(
void
)
{
write_hwcb_t
*
hwcb
;
if
((
!
BUF_HWCB
)
||
(
BUF_HWCB
==
hwc_data
.
current_hwcb
))
allocate_write_hwcb
();
hwcb
=
(
write_hwcb_t
*
)
BUF_HWCB
;
hwcb
->
msgbuf
.
mdb
.
mdb_body
.
go
.
general_msg_flags
|=
GMF_SndAlrm
;
}
static
void
hwc_write_timeout
(
unsigned
long
data
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
hwc_data
.
obuf_start
=
hwc_data
.
obuf_count
;
if
(
hwc_data
.
obuf_count
)
put_line
(
hwc_data
.
obuf
,
hwc_data
.
obuf_count
);
hwc_data
.
obuf_start
=
0
;
hwc_data
.
obuf_cursor
=
0
;
hwc_data
.
obuf_count
=
0
;
write_event_data_1
();
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
}
static
int
do_hwc_write
(
int
from_user
,
unsigned
char
*
msg
,
unsigned
int
count
,
unsigned
char
write_time
)
{
unsigned
int
i_msg
=
0
;
unsigned
short
int
spaces
=
0
;
unsigned
int
processed_characters
=
0
;
unsigned
char
ch
;
unsigned
short
int
obuf_count
;
unsigned
short
int
obuf_cursor
;
unsigned
short
int
obuf_columns
;
if
(
hwc_data
.
obuf_start
)
{
obuf_cursor
=
0
;
obuf_count
=
0
;
obuf_columns
=
MIN
(
hwc_data
.
ioctls
.
columns
,
MAX_MESSAGE_SIZE
-
hwc_data
.
obuf_start
);
}
else
{
obuf_cursor
=
hwc_data
.
obuf_cursor
;
obuf_count
=
hwc_data
.
obuf_count
;
obuf_columns
=
hwc_data
.
ioctls
.
columns
;
}
for
(
i_msg
=
0
;
i_msg
<
count
;
i_msg
++
)
{
if
(
from_user
)
get_user
(
ch
,
msg
+
i_msg
);
else
ch
=
msg
[
i_msg
];
processed_characters
++
;
if
((
obuf_cursor
==
obuf_columns
)
&&
(
ch
!=
'\n'
)
&&
(
ch
!=
'\t'
))
{
put_line
(
&
hwc_data
.
obuf
[
hwc_data
.
obuf_start
],
obuf_columns
);
obuf_cursor
=
0
;
obuf_count
=
0
;
}
switch
(
ch
)
{
case
'\n'
:
put_line
(
&
hwc_data
.
obuf
[
hwc_data
.
obuf_start
],
obuf_count
);
obuf_cursor
=
0
;
obuf_count
=
0
;
break
;
case
'\a'
:
hwc_data
.
obuf_start
+=
obuf_count
;
set_alarm
();
hwc_data
.
obuf_start
-=
obuf_count
;
break
;
case
'\t'
:
do
{
if
(
obuf_cursor
<
obuf_columns
)
{
hwc_data
.
obuf
[
hwc_data
.
obuf_start
+
obuf_cursor
]
=
HWC_ASCEBC
(
' '
);
obuf_cursor
++
;
}
else
break
;
}
while
(
obuf_cursor
%
hwc_data
.
ioctls
.
width_htab
);
break
;
case
'\f'
:
case
'\v'
:
spaces
=
obuf_cursor
;
put_line
(
&
hwc_data
.
obuf
[
hwc_data
.
obuf_start
],
obuf_count
);
obuf_count
=
obuf_cursor
;
while
(
spaces
)
{
hwc_data
.
obuf
[
hwc_data
.
obuf_start
+
obuf_cursor
-
spaces
]
=
HWC_ASCEBC
(
' '
);
spaces
--
;
}
break
;
case
'\b'
:
if
(
obuf_cursor
)
obuf_cursor
--
;
break
;
case
'\r'
:
obuf_cursor
=
0
;
break
;
case
0x00
:
put_line
(
&
hwc_data
.
obuf
[
hwc_data
.
obuf_start
],
obuf_count
);
obuf_cursor
=
0
;
obuf_count
=
0
;
goto
out
;
default:
if
(
isprint
(
ch
))
hwc_data
.
obuf
[
hwc_data
.
obuf_start
+
obuf_cursor
++
]
=
HWC_ASCEBC
(
ch
);
}
if
(
obuf_cursor
>
obuf_count
)
obuf_count
=
obuf_cursor
;
}
if
(
obuf_cursor
)
{
if
(
hwc_data
.
obuf_start
||
(
hwc_data
.
ioctls
.
final_nl
==
0
))
{
put_line
(
&
hwc_data
.
obuf
[
hwc_data
.
obuf_start
],
obuf_count
);
obuf_cursor
=
0
;
obuf_count
=
0
;
}
else
{
if
(
hwc_data
.
ioctls
.
final_nl
>
0
)
{
if
(
hwc_data
.
flags
&
HWC_WTIMER_RUNS
)
{
mod_timer
(
&
hwc_data
.
write_timer
,
jiffies
+
hwc_data
.
ioctls
.
final_nl
*
HZ
/
10
);
}
else
{
init_timer
(
&
hwc_data
.
write_timer
);
hwc_data
.
write_timer
.
function
=
hwc_write_timeout
;
hwc_data
.
write_timer
.
data
=
(
unsigned
long
)
NULL
;
hwc_data
.
write_timer
.
expires
=
jiffies
+
hwc_data
.
ioctls
.
final_nl
*
HZ
/
10
;
add_timer
(
&
hwc_data
.
write_timer
);
hwc_data
.
flags
|=
HWC_WTIMER_RUNS
;
}
}
else
;
}
}
else
;
out:
if
(
!
hwc_data
.
obuf_start
)
{
hwc_data
.
obuf_cursor
=
obuf_cursor
;
hwc_data
.
obuf_count
=
obuf_count
;
}
if
(
write_time
==
IMMEDIATE_WRITE
)
write_event_data_1
();
return
processed_characters
;
}
signed
int
hwc_write
(
int
from_user
,
const
unsigned
char
*
msg
,
unsigned
int
count
)
{
unsigned
long
flags
;
int
retval
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
retval
=
do_hwc_write
(
from_user
,
(
unsigned
char
*
)
msg
,
count
,
IMMEDIATE_WRITE
);
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
return
retval
;
}
unsigned
int
hwc_chars_in_buffer
(
unsigned
char
flag
)
{
unsigned
short
int
number
=
0
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
if
(
flag
&
IN_HWCB
)
number
+=
ALL_HWCB_CHAR
;
if
(
flag
&
IN_WRITE_BUF
)
number
+=
hwc_data
.
obuf_cursor
;
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
return
number
;
}
static
inline
int
nr_setbits
(
kmem_pages_t
arg
)
{
int
i
;
int
nr
=
0
;
for
(
i
=
0
;
i
<
(
sizeof
(
arg
)
<<
3
);
i
++
)
{
if
(
arg
&
1
)
nr
++
;
arg
>>=
1
;
}
return
nr
;
}
unsigned
int
hwc_write_room
(
unsigned
char
flag
)
{
unsigned
int
number
=
0
;
unsigned
long
flags
;
write_hwcb_t
*
hwcb
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
if
(
flag
&
IN_HWCB
)
{
if
(
BUF_HWCB
)
{
hwcb
=
(
write_hwcb_t
*
)
BUF_HWCB
;
number
+=
MAX_HWCB_ROOM
-
hwcb
->
length
;
}
number
+=
(
hwc_data
.
ioctls
.
kmem_hwcb
-
nr_setbits
(
hwc_data
.
kmem_pages
))
*
(
MAX_HWCB_ROOM
-
(
sizeof
(
write_hwcb_t
)
+
sizeof
(
mto_t
)));
}
if
(
flag
&
IN_WRITE_BUF
)
number
+=
MAX_HWCB_ROOM
-
hwc_data
.
obuf_cursor
;
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
return
number
;
}
void
hwc_flush_buffer
(
unsigned
char
flag
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
if
(
flag
&
IN_HWCB
)
{
if
(
hwc_data
.
current_servc
!=
HWC_CMDW_WRITEDATA
)
flush_hwcbs
();
else
hwc_data
.
flags
|=
HWC_FLUSH
;
}
if
(
flag
&
IN_WRITE_BUF
)
{
hwc_data
.
obuf_cursor
=
0
;
hwc_data
.
obuf_count
=
0
;
}
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
}
unsigned
short
int
seperate_cases
(
unsigned
char
*
buf
,
unsigned
short
int
count
)
{
unsigned
short
int
i_in
;
unsigned
short
int
i_out
=
0
;
unsigned
char
_case
=
0
;
for
(
i_in
=
0
;
i_in
<
count
;
i_in
++
)
{
if
(
buf
[
i_in
]
==
hwc_data
.
ioctls
.
delim
)
{
if
((
i_in
+
1
<
count
)
&&
(
buf
[
i_in
+
1
]
==
hwc_data
.
ioctls
.
delim
))
{
buf
[
i_out
]
=
hwc_data
.
ioctls
.
delim
;
i_out
++
;
i_in
++
;
}
else
_case
=
~
_case
;
}
else
{
if
(
_case
)
{
if
(
hwc_data
.
ioctls
.
tolower
)
buf
[
i_out
]
=
_ebc_toupper
[
buf
[
i_in
]];
else
buf
[
i_out
]
=
_ebc_tolower
[
buf
[
i_in
]];
}
else
buf
[
i_out
]
=
buf
[
i_in
];
i_out
++
;
}
}
return
i_out
;
}
#ifdef DUMP_HWCB_INPUT
static
int
gds_vector_name
(
u16
id
,
unsigned
char
name
[])
{
int
retval
=
0
;
switch
(
id
)
{
case
GDS_ID_MDSMU
:
name
=
"Multiple Domain Support Message Unit"
;
break
;
case
GDS_ID_MDSRouteInfo
:
name
=
"MDS Routing Information"
;
break
;
case
GDS_ID_AgUnWrkCorr
:
name
=
"Agent Unit of Work Correlator"
;
break
;
case
GDS_ID_SNACondReport
:
name
=
"SNA Condition Report"
;
break
;
case
GDS_ID_CPMSU
:
name
=
"CP Management Services Unit"
;
break
;
case
GDS_ID_RoutTargInstr
:
name
=
"Routing and Targeting Instructions"
;
break
;
case
GDS_ID_OpReq
:
name
=
"Operate Request"
;
break
;
case
GDS_ID_TextCmd
:
name
=
"Text Command"
;
break
;
default:
name
=
"unknown GDS variable"
;
retval
=
-
EINVAL
;
}
return
retval
;
}
#endif
inline
static
gds_vector_t
*
find_gds_vector
(
gds_vector_t
*
start
,
void
*
end
,
u16
id
)
{
gds_vector_t
*
vec
;
gds_vector_t
*
retval
=
NULL
;
vec
=
start
;
while
(((
void
*
)
vec
)
<
end
)
{
if
(
vec
->
gds_id
==
id
)
{
#ifdef DUMP_HWCB_INPUT
int
retval_name
;
unsigned
char
name
[
64
];
retval_name
=
gds_vector_name
(
id
,
name
);
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"%s at 0x%x up to 0x%x, length: %d"
,
name
,
(
unsigned
long
)
vec
,
((
unsigned
long
)
vec
)
+
vec
->
length
-
1
,
vec
->
length
);
if
(
retval_name
<
0
)
internal_print
(
IMMEDIATE_WRITE
,
", id: 0x%x
\n
"
,
vec
->
gds_id
);
else
internal_print
(
IMMEDIATE_WRITE
,
"
\n
"
);
#endif
retval
=
vec
;
break
;
}
vec
=
(
gds_vector_t
*
)
(((
unsigned
long
)
vec
)
+
vec
->
length
);
}
return
retval
;
}
inline
static
gds_subvector_t
*
find_gds_subvector
(
gds_subvector_t
*
start
,
void
*
end
,
u8
key
)
{
gds_subvector_t
*
subvec
;
gds_subvector_t
*
retval
=
NULL
;
subvec
=
start
;
while
(((
void
*
)
subvec
)
<
end
)
{
if
(
subvec
->
key
==
key
)
{
retval
=
subvec
;
break
;
}
subvec
=
(
gds_subvector_t
*
)
(((
unsigned
long
)
subvec
)
+
subvec
->
length
);
}
return
retval
;
}
inline
static
int
get_input
(
void
*
start
,
void
*
end
)
{
int
count
;
count
=
((
unsigned
long
)
end
)
-
((
unsigned
long
)
start
);
if
(
hwc_data
.
ioctls
.
tolower
)
EBC_TOLOWER
(
start
,
count
);
if
(
hwc_data
.
ioctls
.
delim
)
count
=
seperate_cases
(
start
,
count
);
HWC_EBCASC_STR
(
start
,
count
);
if
(
hwc_data
.
ioctls
.
echo
)
do_hwc_write
(
0
,
start
,
count
,
IMMEDIATE_WRITE
);
if
(
hwc_data
.
calls
!=
NULL
)
if
(
hwc_data
.
calls
->
move_input
!=
NULL
)
(
hwc_data
.
calls
->
move_input
)
(
start
,
count
);
return
count
;
}
inline
static
int
eval_selfdeftextmsg
(
gds_subvector_t
*
start
,
void
*
end
)
{
gds_subvector_t
*
subvec
;
void
*
subvec_data
;
void
*
subvec_end
;
int
retval
=
0
;
subvec
=
start
;
while
(((
void
*
)
subvec
)
<
end
)
{
subvec
=
find_gds_subvector
(
subvec
,
end
,
0x30
);
if
(
!
subvec
)
break
;
subvec_data
=
(
void
*
)
(((
unsigned
long
)
subvec
)
+
sizeof
(
gds_subvector_t
));
subvec_end
=
(
void
*
)
(((
unsigned
long
)
subvec
)
+
subvec
->
length
);
retval
+=
get_input
(
subvec_data
,
subvec_end
);
subvec
=
(
gds_subvector_t
*
)
subvec_end
;
}
return
retval
;
}
inline
static
int
eval_textcmd
(
gds_subvector_t
*
start
,
void
*
end
)
{
gds_subvector_t
*
subvec
;
gds_subvector_t
*
subvec_data
;
void
*
subvec_end
;
int
retval
=
0
;
subvec
=
start
;
while
(((
void
*
)
subvec
)
<
end
)
{
subvec
=
find_gds_subvector
(
subvec
,
end
,
GDS_KEY_SelfDefTextMsg
);
if
(
!
subvec
)
break
;
subvec_data
=
(
gds_subvector_t
*
)
(((
unsigned
long
)
subvec
)
+
sizeof
(
gds_subvector_t
));
subvec_end
=
(
void
*
)
(((
unsigned
long
)
subvec
)
+
subvec
->
length
);
retval
+=
eval_selfdeftextmsg
(
subvec_data
,
subvec_end
);
subvec
=
(
gds_subvector_t
*
)
subvec_end
;
}
return
retval
;
}
inline
static
int
eval_cpmsu
(
gds_vector_t
*
start
,
void
*
end
)
{
gds_vector_t
*
vec
;
gds_subvector_t
*
vec_data
;
void
*
vec_end
;
int
retval
=
0
;
vec
=
start
;
while
(((
void
*
)
vec
)
<
end
)
{
vec
=
find_gds_vector
(
vec
,
end
,
GDS_ID_TextCmd
);
if
(
!
vec
)
break
;
vec_data
=
(
gds_subvector_t
*
)
(((
unsigned
long
)
vec
)
+
sizeof
(
gds_vector_t
));
vec_end
=
(
void
*
)
(((
unsigned
long
)
vec
)
+
vec
->
length
);
retval
+=
eval_textcmd
(
vec_data
,
vec_end
);
vec
=
(
gds_vector_t
*
)
vec_end
;
}
return
retval
;
}
inline
static
int
eval_mdsmu
(
gds_vector_t
*
start
,
void
*
end
)
{
gds_vector_t
*
vec
;
gds_vector_t
*
vec_data
;
void
*
vec_end
;
int
retval
=
0
;
vec
=
find_gds_vector
(
start
,
end
,
GDS_ID_CPMSU
);
if
(
vec
)
{
vec_data
=
(
gds_vector_t
*
)
(((
unsigned
long
)
vec
)
+
sizeof
(
gds_vector_t
));
vec_end
=
(
void
*
)
(((
unsigned
long
)
vec
)
+
vec
->
length
);
retval
=
eval_cpmsu
(
vec_data
,
vec_end
);
}
return
retval
;
}
static
int
eval_evbuf
(
gds_vector_t
*
start
,
void
*
end
)
{
gds_vector_t
*
vec
;
gds_vector_t
*
vec_data
;
void
*
vec_end
;
int
retval
=
0
;
vec
=
find_gds_vector
(
start
,
end
,
GDS_ID_MDSMU
);
if
(
vec
)
{
vec_data
=
(
gds_vector_t
*
)
(((
unsigned
long
)
vec
)
+
sizeof
(
gds_vector_t
));
vec_end
=
(
void
*
)
(((
unsigned
long
)
vec
)
+
vec
->
length
);
retval
=
eval_mdsmu
(
vec_data
,
vec_end
);
}
return
retval
;
}
static
inline
int
eval_hwc_receive_mask
(
_hwcb_mask_t
mask
)
{
hwc_data
.
write_nonprio
=
((
mask
&
ET_Msg_Mask
)
==
ET_Msg_Mask
);
hwc_data
.
write_prio
=
((
mask
&
ET_PMsgCmd_Mask
)
==
ET_PMsgCmd_Mask
);
if
(
hwc_data
.
write_prio
||
hwc_data
.
write_nonprio
)
{
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can write messages
\n
"
);
return
0
;
}
else
{
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can not write messages
\n
"
);
return
-
1
;
}
}
static
inline
int
eval_hwc_send_mask
(
_hwcb_mask_t
mask
)
{
hwc_data
.
read_statechange
=
((
mask
&
ET_StateChange_Mask
)
==
ET_StateChange_Mask
);
if
(
hwc_data
.
read_statechange
)
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can read state change notifications
\n
"
);
else
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can not read state change notifications
\n
"
);
hwc_data
.
sig_quiesce
=
((
mask
&
ET_SigQuiesce_Mask
)
==
ET_SigQuiesce_Mask
);
if
(
hwc_data
.
sig_quiesce
)
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can receive signal quiesce
\n
"
);
else
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can not receive signal quiesce
\n
"
);
hwc_data
.
read_nonprio
=
((
mask
&
ET_OpCmd_Mask
)
==
ET_OpCmd_Mask
);
if
(
hwc_data
.
read_nonprio
)
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can read commands
\n
"
);
hwc_data
.
read_prio
=
((
mask
&
ET_PMsgCmd_Mask
)
==
ET_PMsgCmd_Mask
);
if
(
hwc_data
.
read_prio
)
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can read priority commands
\n
"
);
if
(
hwc_data
.
read_prio
||
hwc_data
.
read_nonprio
)
{
return
0
;
}
else
{
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"can not read commands from operator
\n
"
);
return
-
1
;
}
}
static
int
eval_statechangebuf
(
statechangebuf_t
*
scbuf
)
{
int
retval
=
0
;
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"HWC state change detected
\n
"
);
if
(
scbuf
->
validity_hwc_active_facility_mask
)
{
}
if
(
scbuf
->
validity_hwc_receive_mask
)
{
if
(
scbuf
->
mask_length
!=
4
)
{
#ifdef DUMP_HWC_INIT_ERROR
__asm__
(
"LHI 1,0xe50
\n\t
"
"LRA 2,0(%0)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
scbuf
)
:
"1"
,
"2"
);
#endif
}
else
{
retval
+=
eval_hwc_receive_mask
(
scbuf
->
hwc_receive_mask
);
}
}
if
(
scbuf
->
validity_hwc_send_mask
)
{
if
(
scbuf
->
mask_length
!=
4
)
{
#ifdef DUMP_HWC_INIT_ERROR
__asm__
(
"LHI 1,0xe51
\n\t
"
"LRA 2,0(%0)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
scbuf
)
:
"1"
,
"2"
);
#endif
}
else
{
retval
+=
eval_hwc_send_mask
(
scbuf
->
hwc_send_mask
);
}
}
if
(
scbuf
->
validity_read_data_function_mask
)
{
}
return
retval
;
}
#ifdef CONFIG_SMP
static
volatile
unsigned
long
cpu_quiesce_map
;
static
void
do_load_quiesce_psw
(
void
)
{
psw_t
quiesce_psw
;
clear_bit
(
smp_processor_id
(),
&
cpu_quiesce_map
);
if
(
smp_processor_id
()
==
0
)
{
while
(
cpu_quiesce_map
!=
0
)
;
quiesce_psw
.
mask
=
PSW_BASE_BITS
|
PSW_MASK_WAIT
;
quiesce_psw
.
addr
=
0xfff
;
__load_psw
(
quiesce_psw
);
}
signal_processor
(
smp_processor_id
(),
sigp_stop
);
}
static
void
do_machine_quiesce
(
void
)
{
cpu_quiesce_map
=
cpu_online_map
;
smp_call_function
(
do_load_quiesce_psw
,
NULL
,
0
,
0
);
do_load_quiesce_psw
();
}
#else
static
void
do_machine_quiesce
(
void
)
{
psw_t
quiesce_psw
;
quiesce_psw
.
mask
=
PSW_BASE_BITS
|
PSW_MASK_WAIT
;
queisce_psw
.
addr
=
0xfff
;
__load_psw
(
quiesce_psw
);
}
#endif
static
int
process_evbufs
(
void
*
start
,
void
*
end
)
{
int
retval
=
0
;
evbuf_t
*
evbuf
;
void
*
evbuf_end
;
gds_vector_t
*
evbuf_data
;
evbuf
=
(
evbuf_t
*
)
start
;
while
(((
void
*
)
evbuf
)
<
end
)
{
evbuf_data
=
(
gds_vector_t
*
)
(((
unsigned
long
)
evbuf
)
+
sizeof
(
evbuf_t
));
evbuf_end
=
(
void
*
)
(((
unsigned
long
)
evbuf
)
+
evbuf
->
length
);
switch
(
evbuf
->
type
)
{
case
ET_OpCmd
:
case
ET_CntlProgOpCmd
:
case
ET_PMsgCmd
:
#ifdef DUMP_HWCB_INPUT
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"event buffer "
"at 0x%x up to 0x%x, length: %d
\n
"
,
(
unsigned
long
)
evbuf
,
(
unsigned
long
)
(
evbuf_end
-
1
),
evbuf
->
length
);
dump_storage_area
((
void
*
)
evbuf
,
evbuf
->
length
);
#endif
retval
+=
eval_evbuf
(
evbuf_data
,
evbuf_end
);
break
;
case
ET_StateChange
:
retval
+=
eval_statechangebuf
((
statechangebuf_t
*
)
evbuf
);
break
;
case
ET_SigQuiesce
:
_machine_restart
=
do_machine_quiesce
;
_machine_halt
=
do_machine_quiesce
;
_machine_power_off
=
do_machine_quiesce
;
ctrl_alt_del
();
break
;
default:
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: "
"unknown event buffer found, "
"type 0x%x"
,
evbuf
->
type
);
retval
=
-
ENOSYS
;
}
evbuf
=
(
evbuf_t
*
)
evbuf_end
;
}
return
retval
;
}
static
int
unconditional_read_1
(
void
)
{
unsigned
short
int
condition_code
;
read_hwcb_t
*
hwcb
=
(
read_hwcb_t
*
)
hwc_data
.
page
;
int
retval
;
#if 0
if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
return -EOPNOTSUPP;
if (hwc_data.current_servc)
return -EBUSY;
#endif
memset
(
hwcb
,
0x00
,
PAGE_SIZE
);
memcpy
(
hwcb
,
&
read_hwcb_template
,
sizeof
(
read_hwcb_t
));
condition_code
=
service_call
(
HWC_CMDW_READDATA
,
hwc_data
.
page
);
#ifdef DUMP_HWC_READ_ERROR
if
(
condition_code
==
HWC_NOT_OPERATIONAL
)
__asm__
(
"LHI 1,0xe40
\n\t
"
"L 2,0(%0)
\n\t
"
"LRA 3,0(%1)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
&
condition_code
),
"a"
(
hwc_data
.
page
)
:
"1"
,
"2"
,
"3"
);
#endif
switch
(
condition_code
)
{
case
HWC_COMMAND_INITIATED
:
hwc_data
.
current_servc
=
HWC_CMDW_READDATA
;
hwc_data
.
current_hwcb
=
hwc_data
.
page
;
retval
=
condition_code
;
break
;
case
HWC_BUSY
:
retval
=
-
EBUSY
;
break
;
default:
retval
=
-
EIO
;
}
return
retval
;
}
static
int
unconditional_read_2
(
u32
ext_int_param
)
{
read_hwcb_t
*
hwcb
=
(
read_hwcb_t
*
)
hwc_data
.
page
;
#ifdef DUMP_HWC_READ_ERROR
if
((
hwcb
->
response_code
!=
0x0020
)
&&
(
hwcb
->
response_code
!=
0x0220
)
&&
(
hwcb
->
response_code
!=
0x60F0
)
&&
(
hwcb
->
response_code
!=
0x62F0
))
__asm__
(
"LHI 1,0xe41
\n\t
"
"LRA 2,0(%0)
\n\t
"
"L 3,0(%1)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
hwc_data
.
page
),
"a"
(
&
(
hwcb
->
response_code
))
:
"1"
,
"2"
,
"3"
);
#endif
hwc_data
.
current_servc
=
0
;
hwc_data
.
current_hwcb
=
NULL
;
switch
(
hwcb
->
response_code
)
{
case
0x0020
:
case
0x0220
:
return
process_evbufs
(
(
void
*
)
(((
unsigned
long
)
hwcb
)
+
sizeof
(
read_hwcb_t
)),
(
void
*
)
(((
unsigned
long
)
hwcb
)
+
hwcb
->
length
));
case
0x60F0
:
case
0x62F0
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: "
"got interrupt and tried to read input, "
"but nothing found (response code=0x%x).
\n
"
,
hwcb
->
response_code
);
return
0
;
case
0x0100
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: HWCB boundary violation - this "
"must not occur in a correct driver, please contact "
"author
\n
"
);
return
-
EIO
;
case
0x0300
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: "
"insufficient HWCB length - this must not occur in a "
"correct driver, please contact author
\n
"
);
return
-
EIO
;
case
0x01F0
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: "
"invalid command - this must not occur in a correct "
"driver, please contact author
\n
"
);
return
-
EIO
;
case
0x40F0
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: invalid function code
\n
"
);
return
-
EIO
;
case
0x70F0
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: invalid selection mask
\n
"
);
return
-
EIO
;
case
0x0040
:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: HWC equipment check
\n
"
);
return
-
EIO
;
default:
internal_print
(
IMMEDIATE_WRITE
,
HWC_RW_PRINT_HEADER
"unconditional read: invalid response code %x - this "
"must not occur in a correct driver, please contact "
"author
\n
"
,
hwcb
->
response_code
);
return
-
EIO
;
}
}
static
int
write_event_mask_1
(
void
)
{
unsigned
int
condition_code
;
int
retval
;
condition_code
=
service_call
(
HWC_CMDW_WRITEMASK
,
hwc_data
.
page
);
#ifdef DUMP_HWC_INIT_ERROR
if
(
condition_code
==
HWC_NOT_OPERATIONAL
)
__asm__
(
"LHI 1,0xe10
\n\t
"
"L 2,0(%0)
\n\t
"
"LRA 3,0(%1)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
&
condition_code
),
"a"
(
hwc_data
.
page
)
:
"1"
,
"2"
,
"3"
);
#endif
switch
(
condition_code
)
{
case
HWC_COMMAND_INITIATED
:
hwc_data
.
current_servc
=
HWC_CMDW_WRITEMASK
;
hwc_data
.
current_hwcb
=
hwc_data
.
page
;
retval
=
condition_code
;
break
;
case
HWC_BUSY
:
retval
=
-
EBUSY
;
break
;
default:
retval
=
-
EIO
;
}
return
retval
;
}
static
int
write_event_mask_2
(
u32
ext_int_param
)
{
init_hwcb_t
*
hwcb
=
(
init_hwcb_t
*
)
hwc_data
.
page
;
int
retval
=
0
;
if
(
hwcb
->
response_code
!=
0x0020
)
{
#ifdef DUMP_HWC_INIT_ERROR
__asm__
(
"LHI 1,0xe11
\n\t
"
"LRA 2,0(%0)
\n\t
"
"L 3,0(%1)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
hwcb
),
"a"
(
&
(
hwcb
->
response_code
))
:
"1"
,
"2"
,
"3"
);
#else
retval
=
-
1
;
#endif
}
else
{
if
(
hwcb
->
mask_length
!=
4
)
{
#ifdef DUMP_HWC_INIT_ERROR
__asm__
(
"LHI 1,0xe52
\n\t
"
"LRA 2,0(%0)
\n\t
"
"J .+0
\n\t
"
:
:
"a"
(
hwcb
)
:
"1"
,
"2"
);
#endif
}
else
{
retval
+=
eval_hwc_receive_mask
(
hwcb
->
hwc_receive_mask
);
retval
+=
eval_hwc_send_mask
(
hwcb
->
hwc_send_mask
);
}
}
hwc_data
.
current_servc
=
0
;
hwc_data
.
current_hwcb
=
NULL
;
return
retval
;
}
static
int
set_hwc_ioctls
(
hwc_ioctls_t
*
ioctls
,
char
correct
)
{
int
retval
=
0
;
hwc_ioctls_t
tmp
;
if
(
ioctls
->
width_htab
>
MAX_MESSAGE_SIZE
)
{
if
(
correct
)
tmp
.
width_htab
=
MAX_MESSAGE_SIZE
;
else
retval
=
-
EINVAL
;
}
else
tmp
.
width_htab
=
ioctls
->
width_htab
;
tmp
.
echo
=
ioctls
->
echo
;
if
(
ioctls
->
columns
>
MAX_MESSAGE_SIZE
)
{
if
(
correct
)
tmp
.
columns
=
MAX_MESSAGE_SIZE
;
else
retval
=
-
EINVAL
;
}
else
tmp
.
columns
=
ioctls
->
columns
;
tmp
.
final_nl
=
ioctls
->
final_nl
;
if
(
ioctls
->
max_hwcb
<
2
)
{
if
(
correct
)
tmp
.
max_hwcb
=
2
;
else
retval
=
-
EINVAL
;
}
else
tmp
.
max_hwcb
=
ioctls
->
max_hwcb
;
tmp
.
tolower
=
ioctls
->
tolower
;
if
(
ioctls
->
kmem_hwcb
>
ioctls
->
max_hwcb
)
{
if
(
correct
)
tmp
.
kmem_hwcb
=
ioctls
->
max_hwcb
;
else
retval
=
-
EINVAL
;
}
else
tmp
.
kmem_hwcb
=
ioctls
->
kmem_hwcb
;
if
(
ioctls
->
kmem_hwcb
>
MAX_KMEM_PAGES
)
{
if
(
correct
)
ioctls
->
kmem_hwcb
=
MAX_KMEM_PAGES
;
else
retval
=
-
EINVAL
;
}
if
(
ioctls
->
kmem_hwcb
<
2
)
{
if
(
correct
)
ioctls
->
kmem_hwcb
=
2
;
else
retval
=
-
EINVAL
;
}
tmp
.
delim
=
ioctls
->
delim
;
if
(
!
(
retval
<
0
))
hwc_data
.
ioctls
=
tmp
;
return
retval
;
}
int
do_hwc_init
(
void
)
{
int
retval
;
memcpy
(
hwc_data
.
page
,
&
init_hwcb_template
,
sizeof
(
init_hwcb_t
));
do
{
retval
=
write_event_mask_1
();
if
(
retval
==
-
EBUSY
)
{
hwc_data
.
flags
|=
HWC_INIT
;
__ctl_store
(
cr0
,
0
,
0
);
cr0_save
=
cr0
;
cr0
|=
0x00000200
;
cr0
&=
0xFFFFF3AC
;
__ctl_load
(
cr0
,
0
,
0
);
asm
volatile
(
"STOSM %0,0x01"
:
"=m"
(
psw_mask
)
::
"memory"
);
while
(
!
(
hwc_data
.
flags
&
HWC_INTERRUPT
))
barrier
();
asm
volatile
(
"STNSM %0,0xFE"
:
"=m"
(
psw_mask
)
::
"memory"
);
__ctl_load
(
cr0_save
,
0
,
0
);
hwc_data
.
flags
&=
~
HWC_INIT
;
}
}
while
(
retval
==
-
EBUSY
);
if
(
retval
==
-
EIO
)
{
hwc_data
.
flags
|=
HWC_BROKEN
;
printk
(
HWC_RW_PRINT_HEADER
"HWC not operational
\n
"
);
}
return
retval
;
}
void
hwc_interrupt_handler
(
struct
pt_regs
*
regs
,
__u16
code
);
int
hwc_init
(
void
)
{
int
retval
;
#ifdef BUFFER_STRESS_TEST
init_hwcb_t
*
hwcb
;
int
i
;
#endif
if
(
register_early_external_interrupt
(
0x2401
,
hwc_interrupt_handler
,
&
ext_int_info_hwc
)
!=
0
)
panic
(
"Couldn't request external interrupts 0x2401"
);
spin_lock_init
(
&
hwc_data
.
lock
);
#ifdef USE_VM_DETECTION
if
(
MACHINE_IS_VM
)
{
if
(
hwc_data
.
init_ioctls
.
columns
>
76
)
hwc_data
.
init_ioctls
.
columns
=
76
;
hwc_data
.
init_ioctls
.
tolower
=
1
;
if
(
!
hwc_data
.
init_ioctls
.
delim
)
hwc_data
.
init_ioctls
.
delim
=
DEFAULT_CASE_DELIMITER
;
}
else
{
hwc_data
.
init_ioctls
.
tolower
=
0
;
hwc_data
.
init_ioctls
.
delim
=
0
;
}
#endif
retval
=
set_hwc_ioctls
(
&
hwc_data
.
init_ioctls
,
1
);
hwc_data
.
kmem_start
=
(
unsigned
long
)
alloc_bootmem_low_pages
(
hwc_data
.
ioctls
.
kmem_hwcb
*
PAGE_SIZE
);
hwc_data
.
kmem_end
=
hwc_data
.
kmem_start
+
hwc_data
.
ioctls
.
kmem_hwcb
*
PAGE_SIZE
-
1
;
retval
=
do_hwc_init
();
ctl_set_bit
(
0
,
9
);
#ifdef BUFFER_STRESS_TEST
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"use %i bytes for buffering.
\n
"
,
hwc_data
.
ioctls
.
kmem_hwcb
*
PAGE_SIZE
);
for
(
i
=
0
;
i
<
500
;
i
++
)
{
hwcb
=
(
init_hwcb_t
*
)
BUF_HWCB
;
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"This is stress test message #%i, free: %i bytes
\n
"
,
i
,
MAX_HWCB_ROOM
-
(
hwcb
->
length
+
sizeof
(
mto_t
)));
}
#endif
return
/*retval */
0
;
}
signed
int
hwc_register_calls
(
hwc_high_level_calls_t
*
calls
)
{
if
(
calls
==
NULL
)
return
-
EINVAL
;
if
(
hwc_data
.
calls
!=
NULL
)
return
-
EBUSY
;
hwc_data
.
calls
=
calls
;
return
0
;
}
signed
int
hwc_unregister_calls
(
hwc_high_level_calls_t
*
calls
)
{
if
(
hwc_data
.
calls
==
NULL
)
return
-
EINVAL
;
if
(
calls
!=
hwc_data
.
calls
)
return
-
EINVAL
;
hwc_data
.
calls
=
NULL
;
return
0
;
}
int
hwc_send
(
hwc_request_t
*
req
)
{
unsigned
long
flags
;
int
retval
;
int
cc
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
if
(
!
req
||
!
req
->
callback
||
!
req
->
block
)
{
retval
=
-
EINVAL
;
goto
unlock
;
}
if
(
hwc_data
.
request
)
{
retval
=
-
ENOTSUPP
;
goto
unlock
;
}
cc
=
service_call
(
req
->
word
,
req
->
block
);
switch
(
cc
)
{
case
0
:
hwc_data
.
request
=
req
;
hwc_data
.
current_servc
=
req
->
word
;
hwc_data
.
current_hwcb
=
req
->
block
;
retval
=
0
;
break
;
case
2
:
retval
=
-
EBUSY
;
break
;
default:
retval
=
-
ENOSYS
;
}
unlock:
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
return
retval
;
}
EXPORT_SYMBOL
(
hwc_send
);
void
do_hwc_callback
(
u32
ext_int_param
)
{
if
(
!
hwc_data
.
request
||
!
hwc_data
.
request
->
callback
)
return
;
if
((
ext_int_param
&
HWC_EXT_INT_PARAM_ADDR
)
!=
(
unsigned
long
)
hwc_data
.
request
->
block
)
return
;
hwc_data
.
request
->
callback
(
hwc_data
.
request
);
hwc_data
.
request
=
NULL
;
hwc_data
.
current_hwcb
=
NULL
;
hwc_data
.
current_servc
=
0
;
}
void
hwc_do_interrupt
(
u32
ext_int_param
)
{
u32
finished_hwcb
=
ext_int_param
&
HWC_EXT_INT_PARAM_ADDR
;
u32
evbuf_pending
=
ext_int_param
&
HWC_EXT_INT_PARAM_PEND
;
if
(
hwc_data
.
flags
&
HWC_PTIMER_RUNS
)
{
del_timer
(
&
hwc_data
.
poll_timer
);
hwc_data
.
flags
&=
~
HWC_PTIMER_RUNS
;
}
if
(
finished_hwcb
)
{
if
((
unsigned
long
)
hwc_data
.
current_hwcb
!=
finished_hwcb
)
{
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"interrupt: mismatch: "
"ext. int param. (0x%x) vs. "
"current HWCB (0x%x)
\n
"
,
ext_int_param
,
hwc_data
.
current_hwcb
);
}
else
{
if
(
hwc_data
.
request
)
{
do_hwc_callback
(
ext_int_param
);
}
else
{
switch
(
hwc_data
.
current_servc
)
{
case
HWC_CMDW_WRITEMASK
:
write_event_mask_2
(
ext_int_param
);
break
;
case
HWC_CMDW_WRITEDATA
:
write_event_data_2
(
ext_int_param
);
break
;
case
HWC_CMDW_READDATA
:
unconditional_read_2
(
ext_int_param
);
break
;
default:
break
;
}
}
}
}
else
{
if
(
hwc_data
.
current_hwcb
)
{
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"interrupt: mismatch: "
"ext. int. param. (0x%x) vs. "
"current HWCB (0x%x)
\n
"
,
ext_int_param
,
hwc_data
.
current_hwcb
);
}
}
if
(
evbuf_pending
)
{
unconditional_read_1
();
}
else
{
write_event_data_1
();
}
if
(
!
hwc_data
.
calls
||
!
hwc_data
.
calls
->
wake_up
)
return
;
(
hwc_data
.
calls
->
wake_up
)
();
}
void
hwc_interrupt_handler
(
struct
pt_regs
*
regs
,
__u16
code
)
{
u32
ext_int_param
=
hwc_ext_int_param
();
irq_enter
();
if
(
hwc_data
.
flags
&
HWC_INIT
)
{
hwc_data
.
flags
|=
HWC_INTERRUPT
;
}
else
if
(
hwc_data
.
flags
&
HWC_BROKEN
)
{
if
(
!
do_hwc_init
())
{
hwc_data
.
flags
&=
~
HWC_BROKEN
;
internal_print
(
DELAYED_WRITE
,
HWC_RW_PRINT_HEADER
"delayed HWC setup after"
" temporary breakdown"
" (ext. int. parameter=0x%x)
\n
"
,
ext_int_param
);
}
}
else
{
spin_lock
(
&
hwc_data
.
lock
);
hwc_do_interrupt
(
ext_int_param
);
spin_unlock
(
&
hwc_data
.
lock
);
}
irq_exit
();
}
void
hwc_unblank
(
void
)
{
spin_lock
(
&
hwc_data
.
lock
);
spin_unlock
(
&
hwc_data
.
lock
);
__ctl_store
(
cr0
,
0
,
0
);
cr0_save
=
cr0
;
cr0
|=
0x00000200
;
cr0
&=
0xFFFFF3AC
;
__ctl_load
(
cr0
,
0
,
0
);
asm
volatile
(
"STOSM %0,0x01"
:
"=m"
(
psw_mask
)
::
"memory"
);
while
(
ALL_HWCB_CHAR
)
barrier
();
asm
volatile
(
"STNSM %0,0xFE"
:
"=m"
(
psw_mask
)
::
"memory"
);
__ctl_load
(
cr0_save
,
0
,
0
);
}
int
hwc_ioctl
(
unsigned
int
cmd
,
unsigned
long
arg
)
{
hwc_ioctls_t
tmp
=
hwc_data
.
ioctls
;
int
retval
=
0
;
unsigned
long
flags
;
unsigned
int
obuf
;
spin_lock_irqsave
(
&
hwc_data
.
lock
,
flags
);
switch
(
cmd
)
{
case
TIOCHWCSHTAB
:
if
(
get_user
(
tmp
.
width_htab
,
(
ioctl_htab_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCSECHO
:
if
(
get_user
(
tmp
.
echo
,
(
ioctl_echo_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCSCOLS
:
if
(
get_user
(
tmp
.
columns
,
(
ioctl_cols_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCSNL
:
if
(
get_user
(
tmp
.
final_nl
,
(
ioctl_nl_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCSOBUF
:
if
(
get_user
(
obuf
,
(
unsigned
int
*
)
arg
))
goto
fault
;
if
(
obuf
&
0xFFF
)
tmp
.
max_hwcb
=
(((
obuf
|
0xFFF
)
+
1
)
>>
12
);
else
tmp
.
max_hwcb
=
(
obuf
>>
12
);
break
;
case
TIOCHWCSCASE
:
if
(
get_user
(
tmp
.
tolower
,
(
ioctl_case_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCSDELIM
:
if
(
get_user
(
tmp
.
delim
,
(
ioctl_delim_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCSINIT
:
retval
=
set_hwc_ioctls
(
&
hwc_data
.
init_ioctls
,
1
);
break
;
case
TIOCHWCGHTAB
:
if
(
put_user
(
tmp
.
width_htab
,
(
ioctl_htab_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGECHO
:
if
(
put_user
(
tmp
.
echo
,
(
ioctl_echo_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGCOLS
:
if
(
put_user
(
tmp
.
columns
,
(
ioctl_cols_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGNL
:
if
(
put_user
(
tmp
.
final_nl
,
(
ioctl_nl_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGOBUF
:
if
(
put_user
(
tmp
.
max_hwcb
,
(
ioctl_obuf_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGKBUF
:
if
(
put_user
(
tmp
.
kmem_hwcb
,
(
ioctl_obuf_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGCASE
:
if
(
put_user
(
tmp
.
tolower
,
(
ioctl_case_t
*
)
arg
))
goto
fault
;
break
;
case
TIOCHWCGDELIM
:
if
(
put_user
(
tmp
.
delim
,
(
ioctl_delim_t
*
)
arg
))
goto
fault
;
break
;
#if 0
case TIOCHWCGINIT:
if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
goto fault;
break;
case TIOCHWCGCURR:
if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg))
goto fault;
break;
#endif
default:
goto
noioctlcmd
;
}
if
(
_IOC_DIR
(
cmd
)
==
_IOC_WRITE
)
retval
=
set_hwc_ioctls
(
&
tmp
,
0
);
goto
out
;
fault:
retval
=
-
EFAULT
;
goto
out
;
noioctlcmd:
retval
=
-
ENOIOCTLCMD
;
out:
spin_unlock_irqrestore
(
&
hwc_data
.
lock
,
flags
);
return
retval
;
}
drivers/s390/char/hwc_rw.h
deleted
100644 → 0
View file @
e540dbf8
/*
* 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
deleted
100644 → 0
View file @
e540dbf8
/*
* 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
,
"
\025
2n"
,
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
"
);
}
include/asm-s390/setup.h
View file @
49d7127a
...
...
@@ -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)
...
...
include/asm-s390x/setup.h
View file @
49d7127a
...
...
@@ -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)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment