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
b168ffdf
Commit
b168ffdf
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 0.99.14v
parent
bfeedc98
Changes
37
Show whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
1167 additions
and
939 deletions
+1167
-939
Makefile
Makefile
+1
-1
drivers/FPU-emu/errors.c
drivers/FPU-emu/errors.c
+8
-6
drivers/FPU-emu/fpu_emu.h
drivers/FPU-emu/fpu_emu.h
+3
-3
drivers/FPU-emu/fpu_entry.c
drivers/FPU-emu/fpu_entry.c
+6
-1
drivers/FPU-emu/fpu_system.h
drivers/FPU-emu/fpu_system.h
+19
-1
drivers/FPU-emu/get_address.c
drivers/FPU-emu/get_address.c
+19
-13
drivers/FPU-emu/load_store.c
drivers/FPU-emu/load_store.c
+4
-3
drivers/FPU-emu/poly_sin.c
drivers/FPU-emu/poly_sin.c
+5
-5
drivers/FPU-emu/reg_ld_str.c
drivers/FPU-emu/reg_ld_str.c
+71
-56
drivers/FPU-emu/version.h
drivers/FPU-emu/version.h
+1
-1
drivers/char/atixlmouse.c
drivers/char/atixlmouse.c
+0
-1
drivers/char/busmouse.c
drivers/char/busmouse.c
+0
-1
drivers/char/console.c
drivers/char/console.c
+2
-1
drivers/char/keyboard.c
drivers/char/keyboard.c
+29
-10
drivers/char/msbusmouse.c
drivers/char/msbusmouse.c
+0
-1
drivers/char/pty.c
drivers/char/pty.c
+31
-23
drivers/char/serial.c
drivers/char/serial.c
+7
-9
drivers/char/tty_io.c
drivers/char/tty_io.c
+503
-402
drivers/char/tty_ioctl.c
drivers/char/tty_ioctl.c
+218
-241
drivers/net/8390.c
drivers/net/8390.c
+0
-1
drivers/net/lance.c
drivers/net/lance.c
+8
-1
drivers/net/slip.c
drivers/net/slip.c
+0
-2
fs/open.c
fs/open.c
+4
-0
include/linux/kernel.h
include/linux/kernel.h
+0
-5
include/linux/mm.h
include/linux/mm.h
+18
-1
include/linux/sched.h
include/linux/sched.h
+15
-15
include/linux/termios.h
include/linux/termios.h
+1
-0
include/linux/tty.h
include/linux/tty.h
+81
-45
kernel/fork.c
kernel/fork.c
+2
-1
kernel/ksyms.S
kernel/ksyms.S
+1
-1
kernel/sys.c
kernel/sys.c
+1
-2
mm/memory.c
mm/memory.c
+1
-10
net/inet/ip.c
net/inet/ip.c
+2
-1
net/inet/skbuff.c
net/inet/skbuff.c
+35
-0
net/inet/skbuff.h
net/inet/skbuff.h
+3
-1
net/inet/tcp.c
net/inet/tcp.c
+68
-73
net/socket.c
net/socket.c
+0
-1
No files found.
Makefile
View file @
b168ffdf
VERSION
=
0.99
PATCHLEVEL
=
14
ALPHA
=
u
ALPHA
=
v
all
:
Version zImage
...
...
drivers/FPU-emu/errors.c
View file @
b168ffdf
...
...
@@ -38,7 +38,8 @@ void Un_impl(void)
{
unsigned
char
byte1
,
FPU_modrm
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
/* No need to verify_area(), we have previously fetched these bytes. */
byte1
=
get_fs_byte
((
unsigned
char
*
)
FPU_ORIG_EIP
);
FPU_modrm
=
get_fs_byte
(
1
+
(
unsigned
char
*
)
FPU_ORIG_EIP
);
...
...
@@ -49,7 +50,7 @@ void Un_impl(void)
printk
(
"%02x (%02x+%d)
\n
"
,
FPU_modrm
,
FPU_modrm
&
0xf8
,
FPU_modrm
&
7
);
else
printk
(
"/%d
\n
"
,
(
FPU_modrm
>>
3
)
&
7
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
EXCEPTION
(
EX_Invalid
);
...
...
@@ -65,7 +66,8 @@ void emu_printall()
"DeNorm"
,
"Inf"
,
"NaN"
,
"Empty"
};
unsigned
char
byte1
,
FPU_modrm
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
/* No need to verify_area(), we have previously fetched these bytes. */
byte1
=
get_fs_byte
((
unsigned
char
*
)
FPU_ORIG_EIP
);
FPU_modrm
=
get_fs_byte
(
1
+
(
unsigned
char
*
)
FPU_ORIG_EIP
);
partial_status
=
status_word
();
...
...
@@ -154,7 +156,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
(
long
)(
FPU_loaded_data
.
sigl
&
0xFFFF
),
FPU_loaded_data
.
exp
-
EXP_BIAS
+
1
);
printk
(
"%s
\n
"
,
tag_desc
[(
int
)
(
unsigned
)
FPU_loaded_data
.
tag
]);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
}
...
...
@@ -261,7 +263,7 @@ void exception(int n)
}
}
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
if
(
(
~
control_word
&
n
&
CW_Exceptions
)
||
(
n
==
EX_INTERNAL
)
)
{
#ifdef PRINT_MESSAGES
...
...
@@ -303,7 +305,7 @@ void exception(int n)
*/
/* regs[0].tag |= TW_FPU_Interrupt; */
}
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
#ifdef __DEBUG__
math_abort
(
FPU_info
,
SIGFPE
);
...
...
drivers/FPU-emu/fpu_emu.h
View file @
b168ffdf
/*---------------------------------------------------------------------------+
| fpu_emu.h |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -62,8 +62,8 @@
#ifdef PARANOID
extern
char
emulating
;
# define RE_ENTRANT_CHECK_OFF emulating = 0
;
# define RE_ENTRANT_CHECK_ON emulating = 1
;
# define RE_ENTRANT_CHECK_OFF emulating = 0
# define RE_ENTRANT_CHECK_ON emulating = 1
#else
# define RE_ENTRANT_CHECK_OFF
# define RE_ENTRANT_CHECK_ON
...
...
drivers/FPU-emu/fpu_entry.c
View file @
b168ffdf
...
...
@@ -209,6 +209,7 @@ asmlinkage void math_emulate(long arg)
do_another_FPU_instruction:
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
code
=
get_fs_word
((
unsigned
short
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
;
...
...
@@ -301,6 +302,7 @@ asmlinkage void math_emulate(long arg)
{
FPU_EIP
++
;
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
code
=
get_fs_word
((
unsigned
short
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
;
}
...
...
@@ -560,6 +562,7 @@ asmlinkage void math_emulate(long arg)
unsigned
char
next
;
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
next
=
get_fs_byte
((
unsigned
char
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
;
if
(
valid_prefix
(
next
)
)
...
...
@@ -591,8 +594,10 @@ static int valid_prefix(unsigned char byte)
case
PREFIX_GS
:
case
OP_SIZE_PREFIX
:
/* Used often by gcc, but has no effect. */
FPU_EIP
++
;
RE_ENTRANT_CHECK_OFF
;
byte
=
get_fs_byte
((
unsigned
char
*
)
(
++
FPU_EIP
));
FPU_code_verify_area
(
1
);
byte
=
get_fs_byte
((
unsigned
char
*
)
(
FPU_EIP
));
RE_ENTRANT_CHECK_ON
;
break
;
case
FWAIT_OPCODE
:
...
...
drivers/FPU-emu/fpu_system.h
View file @
b168ffdf
/*---------------------------------------------------------------------------+
| fpu_system.h |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
...
...
@@ -41,6 +42,23 @@
#define data_operand_offset (I387.soft.foo)
#define operand_selector (I387.soft.fos)
#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
math_abort(FPU_info,SIGSEGV)
#undef FPU_IGNORE_CODE_SEGV
#ifdef FPU_IGNORE_CODE_SEGV
/* verify_area() is very expensive, and causes the emulator to run
about 20% slower if applied to the code. Anyway, errors due to bad
code addresses should be much rarer than errors due to bad data
addresses. */
#define FPU_code_verify_area(z)
#else
/* A simpler test than verify_area() can probably be done for
FPU_code_verify_area() because the only possible error is to step
past the upper boundary of a legal code area. */
#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
#endif
/* ######## temporary and ugly ;-) */
#define FPU_data_address ((void *)(I387.soft.twd))
...
...
drivers/FPU-emu/get_address.c
View file @
b168ffdf
...
...
@@ -3,7 +3,7 @@
| |
| Get the effective address from an FPU instruction. |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -46,9 +46,10 @@ static void *sib(int mod)
unsigned
char
ss
,
index
,
base
;
long
offset
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
base
=
get_fs_byte
((
char
*
)
FPU_EIP
);
/* The SIB byte */
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_EIP
++
;
ss
=
base
>>
6
;
index
=
(
base
>>
3
)
&
7
;
...
...
@@ -74,17 +75,19 @@ static void *sib(int mod)
if
(
mod
==
1
)
{
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
offset
+=
(
signed
char
)
get_fs_byte
((
char
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_EIP
++
;
}
else
if
(
mod
==
2
||
base
==
5
)
/* The second condition also has mod==0 */
{
/* 32 bit displacment */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
4
);
offset
+=
(
signed
)
get_fs_long
((
unsigned
long
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_EIP
+=
4
;
}
...
...
@@ -135,9 +138,10 @@ void get_address(unsigned char FPU_modrm)
if
(
FPU_rm
==
5
)
{
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
4
);
offset
=
get_fs_long
((
unsigned
long
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_EIP
+=
4
;
FPU_data_address
=
(
void
*
)
offset
;
return
;
...
...
@@ -150,16 +154,18 @@ void get_address(unsigned char FPU_modrm)
}
case
1
:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
offset
=
(
signed
char
)
get_fs_byte
((
char
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_EIP
++
;
break
;
case
2
:
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
4
);
offset
=
(
signed
)
get_fs_long
((
unsigned
long
*
)
FPU_EIP
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_EIP
+=
4
;
break
;
case
3
:
...
...
drivers/FPU-emu/load_store.c
View file @
b168ffdf
...
...
@@ -4,7 +4,7 @@
| This file contains most of the code to interpret the FPU instructions |
| which load and store from user memory. |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -168,6 +168,7 @@ switch ( type )
break
;
case
024
:
/* fldcw */
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
FPU_data_address
,
2
);
control_word
=
get_fs_word
((
unsigned
short
*
)
FPU_data_address
);
RE_ENTRANT_CHECK_ON
;
if
(
partial_status
&
~
control_word
&
CW_Exceptions
)
...
...
@@ -206,7 +207,7 @@ switch ( type )
break
;
case
034
:
/* fstcw m16int */
RE_ENTRANT_CHECK_OFF
;
verify_area
(
VERIFY_WRITE
,
FPU_data_address
,
2
);
FPU_
verify_area
(
VERIFY_WRITE
,
FPU_data_address
,
2
);
put_fs_word
(
control_word
,
(
short
*
)
FPU_data_address
);
RE_ENTRANT_CHECK_ON
;
NO_NET_DATA_EFFECT
;
...
...
@@ -220,7 +221,7 @@ switch ( type )
break
;
case
036
:
/* fstsw m2byte */
RE_ENTRANT_CHECK_OFF
;
verify_area
(
VERIFY_WRITE
,
FPU_data_address
,
2
);
FPU_
verify_area
(
VERIFY_WRITE
,
FPU_data_address
,
2
);
put_fs_word
(
status_word
(),(
short
*
)
FPU_data_address
);
RE_ENTRANT_CHECK_ON
;
NO_NET_DATA_EFFECT
;
...
...
drivers/FPU-emu/poly_sin.c
View file @
b168ffdf
...
...
@@ -3,7 +3,7 @@
| |
| Computation of an approximation of the sin function by a polynomial |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -128,20 +128,20 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result)
)
{
#ifdef DEBUGGING
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
printk
(
"
\n
EXP=%d, MS=%08x, LS=%08x
\n
"
,
result
->
exp
,
result
->
sigh
,
result
->
sigl
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
#endif DEBUGGING
EXCEPTION
(
EX_INTERNAL
|
0x103
);
}
#ifdef DEBUGGING
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
printk
(
"
\n
***CORRECTING ILLEGAL RESULT*** in poly_sin() computation
\n
"
);
printk
(
"EXP=%d, MS=%08x, LS=%08x
\n
"
,
result
->
exp
,
result
->
sigh
,
result
->
sigl
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
#endif DEBUGGING
result
->
sigl
=
0
;
/* Truncate the result to 1.00 */
...
...
drivers/FPU-emu/reg_ld_str.c
View file @
b168ffdf
...
...
@@ -3,7 +3,7 @@
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -49,13 +49,14 @@ int reg_load_extended(void)
long
double
*
s
=
(
long
double
*
)
FPU_data_address
;
unsigned
long
sigl
,
sigh
,
exp
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
s
,
10
);
/* Use temporary variables here because FPU_loaded data is
static and hence re-entrancy problems can arise */
sigl
=
get_fs_long
((
unsigned
long
*
)
s
);
sigh
=
get_fs_long
(
1
+
(
unsigned
long
*
)
s
);
exp
=
get_fs_word
(
4
+
(
unsigned
short
*
)
s
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
FPU_loaded_data
.
tag
=
TW_Valid
;
/* Default */
FPU_loaded_data
.
sigl
=
sigl
;
...
...
@@ -150,10 +151,11 @@ int reg_load_double(void)
int
exp
;
unsigned
m64
,
l64
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
dfloat
,
8
);
m64
=
get_fs_long
(
1
+
(
unsigned
long
*
)
dfloat
);
l64
=
get_fs_long
((
unsigned
long
*
)
dfloat
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
if
(
m64
&
0x80000000
)
FPU_loaded_data
.
sign
=
SIGN_NEG
;
...
...
@@ -227,9 +229,10 @@ int reg_load_single(void)
unsigned
m32
;
int
exp
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
single
,
4
);
m32
=
get_fs_long
((
unsigned
long
*
)
single
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
if
(
m32
&
0x80000000
)
FPU_loaded_data
.
sign
=
SIGN_NEG
;
...
...
@@ -295,10 +298,11 @@ void reg_load_int64(void)
int
e
;
long
long
s
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
_s
,
8
);
((
unsigned
long
*
)
&
s
)[
0
]
=
get_fs_long
((
unsigned
long
*
)
_s
);
((
unsigned
long
*
)
&
s
)[
1
]
=
get_fs_long
(
1
+
(
unsigned
long
*
)
_s
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
if
(
s
==
0
)
{
reg_move
(
&
CONST_Z
,
&
FPU_loaded_data
);
return
;
}
...
...
@@ -326,9 +330,10 @@ void reg_load_int32(void)
long
s
;
int
e
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
_s
,
4
);
s
=
(
long
)
get_fs_long
((
unsigned
long
*
)
_s
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
if
(
s
==
0
)
{
reg_move
(
&
CONST_Z
,
&
FPU_loaded_data
);
return
;
}
...
...
@@ -356,10 +361,11 @@ void reg_load_int16(void)
short
*
_s
=
(
short
*
)
FPU_data_address
;
int
s
,
e
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
_s
,
2
);
/* Cast as short to get the sign extended. */
s
=
(
short
)
get_fs_word
((
unsigned
short
*
)
_s
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
if
(
s
==
0
)
{
reg_move
(
&
CONST_Z
,
&
FPU_loaded_data
);
return
;
}
...
...
@@ -390,12 +396,15 @@ void reg_load_bcd(void)
unsigned
char
bcd
;
long
long
l
=
0
;
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
s
,
10
);
RE_ENTRANT_CHECK_ON
;
for
(
pos
=
8
;
pos
>=
0
;
pos
--
)
{
l
*=
10
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
bcd
=
(
unsigned
char
)
get_fs_byte
((
unsigned
char
*
)
s
+
pos
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
l
+=
bcd
>>
4
;
l
*=
10
;
l
+=
bcd
&
0x0f
;
...
...
@@ -403,11 +412,11 @@ void reg_load_bcd(void)
/* Finish all access to user memory before putting stuff into
the static FPU_loaded_data */
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_loaded_data
.
sign
=
((
unsigned
char
)
get_fs_byte
((
unsigned
char
*
)
s
+
9
))
&
0x80
?
SIGN_NEG
:
SIGN_POS
;
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
if
(
l
==
0
)
{
...
...
@@ -438,7 +447,9 @@ int reg_store_extended(void)
if
(
FPU_st0_tag
!=
TW_Empty
)
{
verify_area
(
VERIFY_WRITE
,
d
,
10
);
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_WRITE
,
d
,
10
);
RE_ENTRANT_CHECK_ON
;
write_to_extended
(
FPU_st0_ptr
,
(
char
*
)
FPU_data_address
);
return
1
;
}
...
...
@@ -450,7 +461,7 @@ int reg_store_extended(void)
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF
;
verify_area
(
VERIFY_WRITE
,
d
,
10
);
FPU_
verify_area
(
VERIFY_WRITE
,
d
,
10
);
put_fs_long
(
0
,
(
unsigned
long
*
)
d
);
put_fs_long
(
0xc0000000
,
1
+
(
unsigned
long
*
)
d
);
put_fs_word
(
0xffff
,
4
+
(
short
*
)
d
);
...
...
@@ -635,11 +646,11 @@ int reg_store_double(void)
{
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,(
void
*
)
dfloat
,
8
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,(
void
*
)
dfloat
,
8
);
put_fs_long
(
0
,
(
unsigned
long
*
)
dfloat
);
put_fs_long
(
0xfff80000
,
1
+
(
unsigned
long
*
)
dfloat
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
else
...
...
@@ -648,11 +659,11 @@ int reg_store_double(void)
if
(
FPU_st0_ptr
->
sign
)
l
[
1
]
|=
0x80000000
;
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,(
void
*
)
dfloat
,
8
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,(
void
*
)
dfloat
,
8
);
put_fs_long
(
l
[
0
],
(
unsigned
long
*
)
dfloat
);
put_fs_long
(
l
[
1
],
1
+
(
unsigned
long
*
)
dfloat
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
...
...
@@ -819,10 +830,10 @@ int reg_store_single(void)
{
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,(
void
*
)
single
,
4
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,(
void
*
)
single
,
4
);
put_fs_long
(
0xffc00000
,
(
unsigned
long
*
)
single
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
else
...
...
@@ -838,10 +849,10 @@ int reg_store_single(void)
if
(
FPU_st0_ptr
->
sign
)
templ
|=
0x80000000
;
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,(
void
*
)
single
,
4
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,(
void
*
)
single
,
4
);
put_fs_long
(
templ
,(
unsigned
long
*
)
single
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
...
...
@@ -896,11 +907,11 @@ int reg_store_int64(void)
tll
=
-
tll
;
}
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,(
void
*
)
d
,
8
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,(
void
*
)
d
,
8
);
put_fs_long
(((
long
*
)
&
tll
)[
0
],(
unsigned
long
*
)
d
);
put_fs_long
(((
long
*
)
&
tll
)[
1
],
1
+
(
unsigned
long
*
)
d
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
...
...
@@ -951,10 +962,10 @@ int reg_store_int32(void)
t
.
sigl
=
-
(
long
)
t
.
sigl
;
}
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,
d
,
4
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,
d
,
4
);
put_fs_long
(
t
.
sigl
,
(
unsigned
long
*
)
d
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
...
...
@@ -1005,10 +1016,10 @@ int reg_store_int16(void)
t
.
sigl
=
-
t
.
sigl
;
}
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,
d
,
2
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,
d
,
2
);
put_fs_word
((
short
)
t
.
sigl
,(
short
*
)
d
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
...
...
@@ -1045,14 +1056,14 @@ int reg_store_bcd(void)
if
(
control_word
&
CW_Invalid
)
{
/* Produce the QNaN "indefinite" */
RE_ENTRANT_CHECK_OFF
verify_area
(
VERIFY_WRITE
,
d
,
10
);
RE_ENTRANT_CHECK_OFF
;
FPU_
verify_area
(
VERIFY_WRITE
,
d
,
10
);
for
(
i
=
0
;
i
<
7
;
i
++
)
put_fs_byte
(
0
,
(
unsigned
char
*
)
d
+
i
);
/* These bytes "undefined" */
put_fs_byte
(
0xc0
,
(
unsigned
char
*
)
d
+
7
);
/* This byte "undefined" */
put_fs_byte
(
0xff
,
(
unsigned
char
*
)
d
+
8
);
put_fs_byte
(
0xff
,
(
unsigned
char
*
)
d
+
9
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
else
...
...
@@ -1064,18 +1075,20 @@ int reg_store_bcd(void)
set_precision_flag
(
precision_loss
);
}
verify_area
(
VERIFY_WRITE
,
d
,
10
);
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_WRITE
,
d
,
10
);
RE_ENTRANT_CHECK_ON
;
for
(
i
=
0
;
i
<
9
;
i
++
)
{
b
=
div_small
(
&
ll
,
10
);
b
|=
(
div_small
(
&
ll
,
10
))
<<
4
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
put_fs_byte
(
b
,(
unsigned
char
*
)
d
+
i
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
}
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
put_fs_byte
(
sign
,(
unsigned
char
*
)
d
+
9
);
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
return
1
;
}
...
...
@@ -1157,7 +1170,8 @@ char *fldenv(void)
unsigned
char
tag
;
int
i
;
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_READ
,
s
,
0x1c
);
control_word
=
get_fs_word
((
unsigned
short
*
)
s
);
partial_status
=
get_fs_word
((
unsigned
short
*
)
(
s
+
4
));
tag_word
=
get_fs_word
((
unsigned
short
*
)
(
s
+
8
));
...
...
@@ -1165,7 +1179,7 @@ char *fldenv(void)
cs_selector
=
get_fs_long
((
unsigned
long
*
)
(
s
+
0x10
));
data_operand_offset
=
get_fs_long
((
unsigned
long
*
)
(
s
+
0x14
));
operand_selector
=
get_fs_long
((
unsigned
long
*
)
(
s
+
0x18
));
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
top
=
(
partial_status
>>
SW_Top_Shift
)
&
7
;
...
...
@@ -1275,9 +1289,8 @@ char *fstenv(void)
{
char
*
d
=
(
char
*
)
FPU_data_address
;
verify_area
(
VERIFY_WRITE
,
d
,
28
);
RE_ENTRANT_CHECK_OFF
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_WRITE
,
d
,
28
);
#ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */
put_fs_long
(
0xffff0040
|
(
control_word
&
~
0xe080
),
(
unsigned
long
*
)
d
);
...
...
@@ -1297,7 +1310,7 @@ char *fstenv(void)
#else
put_fs_long
(
operand_selector
,
(
unsigned
long
*
)
(
d
+
0x18
));
#endif PECULIAR_486
RE_ENTRANT_CHECK_ON
RE_ENTRANT_CHECK_ON
;
control_word
|=
CW_Exceptions
;
partial_status
&=
~
(
SW_Summary
|
SW_Backward
);
...
...
@@ -1312,7 +1325,9 @@ void fsave(void)
int
i
;
d
=
fstenv
();
verify_area
(
VERIFY_WRITE
,
d
,
80
);
RE_ENTRANT_CHECK_OFF
;
FPU_verify_area
(
VERIFY_WRITE
,
d
,
80
);
RE_ENTRANT_CHECK_ON
;
for
(
i
=
0
;
i
<
8
;
i
++
)
write_to_extended
(
&
regs
[(
top
+
i
)
&
7
],
d
+
10
*
i
);
...
...
@@ -1324,7 +1339,7 @@ void fsave(void)
/*
A call to this function must be preceeded by a call to
verify_area() to verify access to the 10 bytes at d
FPU_
verify_area() to verify access to the 10 bytes at d
*/
static
void
write_to_extended
(
FPU_REG
*
rp
,
char
*
d
)
{
...
...
drivers/FPU-emu/version.h
View file @
b168ffdf
...
...
@@ -9,5 +9,5 @@
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version Beta 1.
7
"
#define FPU_VERSION "wm-FPU-emu version Beta 1.
8
"
drivers/char/atixlmouse.c
View file @
b168ffdf
...
...
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
...
...
drivers/char/busmouse.c
View file @
b168ffdf
...
...
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
...
...
drivers/char/console.c
View file @
b168ffdf
...
...
@@ -967,7 +967,6 @@ void con_write(struct tty_struct * tty)
int
c
;
unsigned
int
currcons
;
wake_up_interruptible
(
&
tty
->
write_q
.
proc_list
);
currcons
=
tty
->
line
-
1
;
if
(
currcons
>=
NR_CONSOLES
)
{
printk
(
"con_write: illegal tty (%d)
\n
"
,
currcons
);
...
...
@@ -1279,6 +1278,8 @@ void con_write(struct tty_struct * tty)
if
(
vcmode
!=
KD_GRAPHICS
)
set_cursor
(
currcons
);
enable_bh
(
KEYBOARD_BH
);
if
(
LEFT
(
&
tty
->
write_q
)
>
WAKEUP_CHARS
)
wake_up_interruptible
(
&
tty
->
write_q
.
proc_list
);
}
void
do_keyboard_interrupt
(
void
)
...
...
drivers/char/keyboard.c
View file @
b168ffdf
...
...
@@ -126,6 +126,8 @@ static unsigned char handle_diacr(unsigned char);
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
static
struct
pt_regs
*
pt_regs
;
static
int
got_break
=
0
;
static
inline
void
kb_wait
(
void
)
{
int
i
;
...
...
@@ -343,7 +345,6 @@ static void put_queue(int ch)
if
(
LEFT
(
qp
))
{
qp
->
buf
[
qp
->
head
]
=
ch
;
INC
(
qp
->
head
);
wake_up_interruptible
(
&
qp
->
proc_list
);
}
}
...
...
@@ -364,7 +365,6 @@ static void puts_queue(char *cp)
INC
(
qp
->
head
);
}
}
wake_up_interruptible
(
&
qp
->
proc_list
);
}
static
void
applkey
(
int
key
,
char
mode
)
...
...
@@ -419,13 +419,13 @@ static void hold(void)
{
if
(
rep
||
!
tty
)
return
;
if
(
vc_kbd_flag
(
kbd
,
VC_SCROLLOCK
))
/* pressing srcoll lock 2nd time sends ^Q, ChN */
put_queue
(
START_CHAR
(
tty
));
else
/* pressing scroll lock 1st time sends ^S, ChN */
put_queue
(
STOP_CHAR
(
tty
));
chg_vc_kbd_flag
(
kbd
,
VC_SCROLLOCK
);
/* pressing scroll lock 2nd time sends ^Q, ChN */
/* now done directly without regard to ISIG -- jlc */
if
(
!
vc_kbd_flag
(
kbd
,
VC_SCROLLOCK
))
stop_tty
(
tty
);
else
start_tty
(
tty
);
}
static
void
num
(
void
)
...
...
@@ -453,8 +453,7 @@ static void lastcons(void)
static
void
send_intr
(
void
)
{
if
(
tty
)
put_queue
(
INTR_CHAR
(
tty
));
got_break
=
1
;
}
static
void
scrll_forw
(
void
)
...
...
@@ -814,6 +813,26 @@ static void kbd_bh(void * unused)
}
want_console
=
-
1
;
}
if
(
got_break
)
{
if
(
tty
&&
!
I_IGNBRK
(
tty
))
{
if
(
I_BRKINT
(
tty
))
{
flush_input
(
tty
);
flush_output
(
tty
);
if
(
tty
->
pgrp
>
0
)
kill_pg
(
tty
->
pgrp
,
SIGINT
,
1
);
}
else
{
cli
();
if
(
LEFT
(
&
tty
->
read_q
)
>=
2
)
{
set_bit
(
tty
->
read_q
.
head
,
&
tty
->
readq_flags
);
put_queue
(
TTY_BREAK
);
put_queue
(
0
);
}
sti
();
}
}
got_break
=
0
;
}
do_keyboard_interrupt
();
cli
();
if
((
inb_p
(
0x64
)
&
kbd_read_mask
)
==
0x01
)
...
...
drivers/char/msbusmouse.c
View file @
b168ffdf
...
...
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
...
...
drivers/char/pty.c
View file @
b168ffdf
...
...
@@ -17,17 +17,20 @@
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#define MIN(a,b) ((a) < (b) ? (a) : (b))
static
void
pty_close
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
{
if
(
!
tty
)
return
;
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
{
if
(
tty
->
count
>
1
)
return
;
printk
(
"master pty_close: count = %d!!
\n
"
,
tty
->
count
)
;
}
else
{
if
(
tty
->
count
>
2
)
return
;
...
...
@@ -40,32 +43,39 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
wake_up_interruptible
(
&
tty
->
link
->
read_q
.
proc_list
);
wake_up_interruptible
(
&
tty
->
link
->
write_q
.
proc_list
);
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
{
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
tty_hangup
(
tty
->
link
);
flush_input
(
tty
);
flush_output
(
tty
);
else
{
start_tty
(
tty
);
set_bit
(
TTY_SLAVE_CLOSED
,
&
tty
->
link
->
flags
);
}
}
static
inline
void
pty_copy
(
struct
tty_struct
*
from
,
struct
tty_struct
*
to
)
{
int
c
;
unsigned
long
count
,
n
;
struct
tty_queue
*
fq
,
*
tq
;
while
(
!
from
->
stopped
&&
!
EMPTY
(
&
from
->
write_q
))
{
if
(
FULL
(
&
to
->
read_q
))
{
TTY_READ_FLUSH
(
to
);
if
(
FULL
(
&
to
->
read_q
))
break
;
continue
;
}
c
=
get_tty_queue
(
&
from
->
write_q
);
put_tty_queue
(
c
,
&
to
->
read_q
);
if
(
current
->
signal
&
~
current
->
blocked
)
break
;
if
(
from
->
stopped
||
EMPTY
(
&
from
->
write_q
))
return
;
fq
=
&
from
->
write_q
;
/* Bypass the read_q if this is a pty master. */
tq
=
IS_A_PTY_MASTER
(
to
->
line
)
?
&
to
->
secondary
:
&
to
->
read_q
;
count
=
MIN
(
CHARS
(
fq
),
LEFT
(
tq
));
while
(
count
)
{
n
=
MIN
(
MIN
(
TTY_BUF_SIZE
-
fq
->
tail
,
TTY_BUF_SIZE
-
tq
->
head
),
count
);
memcpy
(
&
tq
->
buf
[
tq
->
head
],
&
fq
->
buf
[
fq
->
tail
],
n
);
count
-=
n
;
fq
->
tail
=
(
fq
->
tail
+
n
)
&
(
TTY_BUF_SIZE
-
1
);
tq
->
head
=
(
tq
->
head
+
n
)
&
(
TTY_BUF_SIZE
-
1
);
}
if
(
IS_A_PTY_MASTER
(
to
->
line
))
wake_up_interruptible
(
&
tq
->
proc_list
);
else
TTY_READ_FLUSH
(
to
);
if
(
!
FULL
(
&
from
->
write_q
)
)
wake_up_interruptible
(
&
f
rom
->
write_q
.
proc_list
);
if
(
LEFT
(
fq
)
>
WAKEUP_CHARS
)
wake_up_interruptible
(
&
f
q
->
proc_list
);
if
(
from
->
write_data_cnt
)
{
set_bit
(
from
->
line
,
&
tty_check_write
);
mark_bh
(
TTY_BH
);
...
...
@@ -87,10 +97,8 @@ int pty_open(struct tty_struct *tty, struct file * filp)
{
if
(
!
tty
||
!
tty
->
link
)
return
-
ENODEV
;
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
clear_bit
(
TTY_SLAVE_OPENED
,
&
tty
->
flags
);
else
set_bit
(
TTY_SLAVE_OPENED
,
&
tty
->
link
->
flags
);
if
(
IS_A_PTY_SLAVE
(
tty
->
line
))
clear_bit
(
TTY_SLAVE_CLOSED
,
&
tty
->
link
->
flags
);
tty
->
write
=
tty
->
link
->
write
=
pty_write
;
tty
->
close
=
tty
->
link
->
close
=
pty_close
;
wake_up_interruptible
(
&
tty
->
read_q
.
proc_list
);
...
...
drivers/char/serial.c
View file @
b168ffdf
...
...
@@ -58,8 +58,6 @@
#undef ISR_HACK
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
/*
* rs_event - Bitfield of serial lines that events pending
* to be processed at the next clock tick.
...
...
@@ -418,7 +416,7 @@ static inline int check_modem_status(struct async_struct *info)
status
=
serial_in
(
info
,
UART_MSR
);
if
((
status
&
UART_MSR_DDCD
)
&&
!
C_LOCAL
(
info
->
tty
))
{
if
((
status
&
UART_MSR_DDCD
)
&&
!
C_
C
LOCAL
(
info
->
tty
))
{
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk
(
"ttys%d CD now %s..."
,
info
->
line
,
(
status
&
UART_MSR_DCD
)
?
"on"
:
"off"
);
...
...
@@ -433,7 +431,7 @@ static inline int check_modem_status(struct async_struct *info)
rs_sched_event
(
info
,
RS_EVENT_HANGUP
);
}
}
if
(
C_RTSCTS
(
info
->
tty
))
{
if
(
C_
C
RTSCTS
(
info
->
tty
))
{
if
(
info
->
tty
->
hw_stopped
)
{
if
(
status
&
UART_MSR_CTS
)
{
#ifdef SERIAL_DEBUG_INTR
...
...
@@ -562,7 +560,7 @@ static inline void handle_rs_break(struct async_struct *info)
if
(
info
->
flags
&
ASYNC_SAK
)
do_SAK
(
info
->
tty
);
if
(
I_BRKINT
(
info
->
tty
))
{
if
(
!
I_IGNBRK
(
info
->
tty
)
&&
I_BRKINT
(
info
->
tty
))
{
flush_input
(
info
->
tty
);
flush_output
(
info
->
tty
);
if
(
info
->
tty
->
pgrp
>
0
)
...
...
@@ -1066,7 +1064,7 @@ static void rs_throttle(struct tty_struct * tty, int status)
switch
(
status
)
{
case
TTY_THROTTLE_RQ_FULL
:
info
=
rs_table
+
DEV_TO_SL
(
tty
->
line
);
if
(
tty
->
termios
->
c_iflag
&
IXOFF
)
{
if
(
I_IXOFF
(
tty
)
)
{
info
->
x_char
=
STOP_CHAR
(
tty
);
}
else
{
mcr
=
serial_inp
(
info
,
UART_MCR
);
...
...
@@ -1076,7 +1074,7 @@ static void rs_throttle(struct tty_struct * tty, int status)
break
;
case
TTY_THROTTLE_RQ_AVAIL
:
info
=
rs_table
+
DEV_TO_SL
(
tty
->
line
);
if
(
tty
->
termios
->
c_iflag
&
IXOFF
)
{
if
(
I_IXOFF
(
tty
)
)
{
if
(
info
->
x_char
)
info
->
x_char
=
0
;
else
...
...
@@ -1382,7 +1380,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
error
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
long
));
if
(
error
)
return
error
;
put_fs_long
(
C_LOCAL
(
tty
)
?
1
:
0
,
put_fs_long
(
C_
C
LOCAL
(
tty
)
?
1
:
0
,
(
unsigned
long
*
)
arg
);
return
0
;
case
TIOCSSOFTCAR
:
...
...
@@ -1591,7 +1589,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
{
struct
wait_queue
wait
=
{
current
,
NULL
};
int
retval
;
int
do_clocal
=
C_LOCAL
(
tty
);
int
do_clocal
=
C_
C
LOCAL
(
tty
);
/*
* If the device is in the middle of being closed, then block
...
...
drivers/char/tty_io.c
View file @
b168ffdf
...
...
@@ -32,6 +32,9 @@
* Added functionality to the OPOST tty handling. No delays, but all
* other bits should be there.
* -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
*
* Rewrote canonical mode and added more termios flags.
* -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
*/
#include <linux/types.h>
...
...
@@ -98,7 +101,7 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
return
0
;
}
void
put_tty_queue
(
char
c
,
struct
tty_queue
*
queue
)
void
put_tty_queue
(
unsigned
char
c
,
struct
tty_queue
*
queue
)
{
int
head
;
unsigned
long
flags
;
...
...
@@ -121,8 +124,8 @@ int get_tty_queue(struct tty_queue * queue)
save_flags
(
flags
);
cli
();
if
(
queue
->
tail
!=
queue
->
head
)
{
result
=
0xff
&
queue
->
buf
[
queue
->
tail
];
queue
->
tail
=
(
queue
->
tail
+
1
)
&
(
TTY_BUF_SIZE
-
1
);
result
=
queue
->
buf
[
queue
->
tail
];
INC
(
queue
->
tail
);
}
restore_flags
(
flags
);
return
result
;
...
...
@@ -499,7 +502,220 @@ void wait_for_keypress(void)
sleep_on
(
&
keypress_wait
);
}
void
copy_to_cooked
(
struct
tty_struct
*
tty
)
void
stop_tty
(
struct
tty_struct
*
tty
)
{
if
(
tty
->
stopped
)
return
;
tty
->
stopped
=
1
;
if
(
tty
->
link
&&
tty
->
link
->
packet
)
{
tty
->
ctrl_status
&=
~
TIOCPKT_START
;
tty
->
ctrl_status
|=
TIOCPKT_STOP
;
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
}
if
(
tty
->
stop
)
(
tty
->
stop
)(
tty
);
if
(
IS_A_CONSOLE
(
tty
->
line
))
{
set_vc_kbd_flag
(
kbd_table
+
fg_console
,
VC_SCROLLOCK
);
set_leds
();
}
}
void
start_tty
(
struct
tty_struct
*
tty
)
{
if
(
!
tty
->
stopped
)
return
;
tty
->
stopped
=
0
;
if
(
tty
->
link
&&
tty
->
link
->
packet
)
{
tty
->
ctrl_status
&=
~
TIOCPKT_STOP
;
tty
->
ctrl_status
|=
TIOCPKT_START
;
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
}
if
(
tty
->
start
)
(
tty
->
start
)(
tty
);
if
(
IS_A_CONSOLE
(
tty
->
line
))
{
clr_vc_kbd_flag
(
kbd_table
+
fg_console
,
VC_SCROLLOCK
);
set_leds
();
}
TTY_WRITE_FLUSH
(
tty
);
}
/* Perform OPOST processing. Returns -1 when the write_q becomes full
and the character must be retried. */
static
int
opost
(
unsigned
char
c
,
struct
tty_struct
*
tty
)
{
if
(
FULL
(
&
tty
->
write_q
))
return
-
1
;
if
(
O_OPOST
(
tty
))
{
switch
(
c
)
{
case
'\n'
:
if
(
O_ONLRET
(
tty
))
tty
->
column
=
0
;
if
(
O_ONLCR
(
tty
))
{
if
(
LEFT
(
&
tty
->
write_q
)
<
2
)
return
-
1
;
put_tty_queue
(
'\r'
,
&
tty
->
write_q
);
tty
->
column
=
0
;
}
tty
->
canon_column
=
tty
->
column
;
break
;
case
'\r'
:
if
(
O_ONOCR
(
tty
)
&&
tty
->
column
==
0
)
return
0
;
if
(
O_OCRNL
(
tty
))
{
c
=
'\n'
;
if
(
O_ONLRET
(
tty
))
tty
->
canon_column
=
tty
->
column
=
0
;
break
;
}
tty
->
canon_column
=
tty
->
column
=
0
;
break
;
case
'\t'
:
if
(
O_TABDLY
(
tty
)
==
XTABS
)
{
if
(
LEFT
(
&
tty
->
write_q
)
<
8
)
return
-
1
;
do
put_tty_queue
(
' '
,
&
tty
->
write_q
);
while
(
++
tty
->
column
%
8
);
return
0
;
}
tty
->
column
=
(
tty
->
column
|
7
)
+
1
;
break
;
case
'\b'
:
if
(
tty
->
column
>
0
)
tty
->
column
--
;
break
;
default:
if
(
O_OLCUC
(
tty
))
c
=
toupper
(
c
);
if
(
!
iscntrl
(
c
))
tty
->
column
++
;
break
;
}
}
put_tty_queue
(
c
,
&
tty
->
write_q
);
return
0
;
}
/* Must be called only when L_ECHO(tty) is true. */
static
void
echo_char
(
unsigned
char
c
,
struct
tty_struct
*
tty
)
{
if
(
L_ECHOCTL
(
tty
)
&&
iscntrl
(
c
)
&&
c
!=
'\t'
)
{
opost
(
'^'
,
tty
);
opost
(
c
^
0100
,
tty
);
}
else
opost
(
c
,
tty
);
}
static
void
eraser
(
unsigned
char
c
,
struct
tty_struct
*
tty
)
{
enum
{
ERASE
,
WERASE
,
KILL
}
kill_type
;
int
seen_alnums
;
if
(
tty
->
secondary
.
head
==
tty
->
canon_head
)
{
/* opost('\a', tty); */
/* what do you think? */
return
;
}
if
(
c
==
ERASE_CHAR
(
tty
))
kill_type
=
ERASE
;
else
if
(
c
==
WERASE_CHAR
(
tty
))
kill_type
=
WERASE
;
else
{
if
(
!
L_ECHO
(
tty
))
{
tty
->
secondary
.
head
=
tty
->
canon_head
;
return
;
}
if
(
!
L_ECHOK
(
tty
)
||
!
L_ECHOKE
(
tty
))
{
tty
->
secondary
.
head
=
tty
->
canon_head
;
if
(
tty
->
erasing
)
{
opost
(
'/'
,
tty
);
tty
->
erasing
=
0
;
}
echo_char
(
KILL_CHAR
(
tty
),
tty
);
/* Add a newline if ECHOK is on and ECHOKE is off. */
if
(
L_ECHOK
(
tty
))
opost
(
'\n'
,
tty
);
return
;
}
kill_type
=
KILL
;
}
seen_alnums
=
0
;
while
(
tty
->
secondary
.
head
!=
tty
->
canon_head
)
{
c
=
LAST
(
&
tty
->
secondary
);
if
(
kill_type
==
WERASE
)
{
/* Equivalent to BSD's ALTWERASE. */
if
(
isalnum
(
c
)
||
c
==
'_'
)
seen_alnums
++
;
else
if
(
seen_alnums
)
break
;
}
DEC
(
tty
->
secondary
.
head
);
if
(
L_ECHO
(
tty
))
{
if
(
L_ECHOPRT
(
tty
))
{
if
(
!
tty
->
erasing
)
{
opost
(
'\\'
,
tty
);
tty
->
erasing
=
1
;
}
echo_char
(
c
,
tty
);
}
else
if
(
!
L_ECHOE
(
tty
))
{
echo_char
(
ERASE_CHAR
(
tty
),
tty
);
}
else
if
(
c
==
'\t'
)
{
unsigned
int
col
=
tty
->
canon_column
;
unsigned
long
tail
=
tty
->
canon_head
;
/* Find the column of the last char. */
while
(
tail
!=
tty
->
secondary
.
head
)
{
c
=
tty
->
secondary
.
buf
[
tail
];
if
(
c
==
'\t'
)
col
=
(
col
|
7
)
+
1
;
else
if
(
iscntrl
(
c
))
{
if
(
L_ECHOCTL
(
tty
))
col
+=
2
;
}
else
col
++
;
INC
(
tail
);
}
/* Now backup to that column. */
while
(
tty
->
column
>
col
)
{
/* Can't use opost here. */
put_tty_queue
(
'\b'
,
&
tty
->
write_q
);
tty
->
column
--
;
}
}
else
{
if
(
iscntrl
(
c
)
&&
L_ECHOCTL
(
tty
))
{
opost
(
'\b'
,
tty
);
opost
(
' '
,
tty
);
opost
(
'\b'
,
tty
);
}
if
(
!
iscntrl
(
c
)
||
L_ECHOCTL
(
tty
))
{
opost
(
'\b'
,
tty
);
opost
(
' '
,
tty
);
opost
(
'\b'
,
tty
);
}
}
}
if
(
kill_type
==
ERASE
)
break
;
}
if
(
tty
->
erasing
&&
tty
->
secondary
.
head
==
tty
->
canon_head
)
{
opost
(
'/'
,
tty
);
tty
->
erasing
=
0
;
}
}
static
void
isig
(
int
sig
,
struct
tty_struct
*
tty
)
{
kill_pg
(
tty
->
pgrp
,
sig
,
1
);
if
(
!
L_NOFLSH
(
tty
))
{
flush_input
(
tty
);
flush_output
(
tty
);
}
}
static
void
copy_to_cooked
(
struct
tty_struct
*
tty
)
{
int
c
,
special_flag
;
unsigned
long
flags
;
...
...
@@ -525,19 +741,18 @@ void copy_to_cooked(struct tty_struct * tty)
if
(
c
==
0
)
break
;
save_flags
(
flags
);
cli
();
if
(
tty
->
read_q
.
tail
!=
tty
->
read_q
.
head
)
{
c
=
0xff
&
tty
->
read_q
.
buf
[
tty
->
read_q
.
tail
];
if
(
!
EMPTY
(
&
tty
->
read_q
)
)
{
c
=
tty
->
read_q
.
buf
[
tty
->
read_q
.
tail
];
special_flag
=
clear_bit
(
tty
->
read_q
.
tail
,
&
tty
->
readq_flags
);
tty
->
read_q
.
tail
=
(
tty
->
read_q
.
tail
+
1
)
&
(
TTY_BUF_SIZE
-
1
);
INC
(
tty
->
read_q
.
tail
);
restore_flags
(
flags
);
}
else
{
restore_flags
(
flags
);
break
;
}
if
(
special_flag
)
{
tty
->
char_error
=
c
&
7
;
tty
->
char_error
=
c
;
continue
;
}
if
(
tty
->
char_error
)
{
...
...
@@ -545,6 +760,9 @@ void copy_to_cooked(struct tty_struct * tty)
tty
->
char_error
=
0
;
if
(
I_IGNBRK
(
tty
))
continue
;
/* A break is handled by the lower levels. */
if
(
I_BRKINT
(
tty
))
continue
;
if
(
I_PARMRK
(
tty
))
{
put_tty_queue
(
'\377'
,
&
tty
->
secondary
);
put_tty_queue
(
'\0'
,
&
tty
->
secondary
);
...
...
@@ -570,157 +788,131 @@ void copy_to_cooked(struct tty_struct * tty)
put_tty_queue
(
'\0'
,
&
tty
->
secondary
);
continue
;
}
if
(
I_
STR
P
(
tty
))
if
(
I_
ISTRI
P
(
tty
))
c
&=
0x7f
;
else
if
(
I_PARMRK
(
tty
)
&&
(
c
==
'\377'
))
put_tty_queue
(
'\377'
,
&
tty
->
secondary
);
if
(
c
==
13
)
{
if
(
I_CRNL
(
tty
))
c
=
10
;
else
if
(
I_NOCR
(
tty
))
if
(
!
tty
->
lnext
)
{
if
(
c
==
'\r'
)
{
if
(
I_IGNCR
(
tty
))
continue
;
}
else
if
(
c
==
10
&&
I_NLCR
(
tty
))
c
=
13
;
if
(
I_UCLC
(
tty
))
if
(
I_ICRNL
(
tty
))
c
=
'\n'
;
}
else
if
(
c
==
'\n'
&&
I_INLCR
(
tty
))
c
=
'\r'
;
}
if
(
I_IUCLC
(
tty
)
&&
L_IEXTEN
(
tty
))
c
=
tolower
(
c
);
if
(
c
==
__DISABLED_CHAR
)
tty
->
lnext
=
1
;
if
(
L_CANON
(
tty
)
&&
!
tty
->
lnext
)
{
if
(
c
==
ERASE_CHAR
(
tty
)
||
c
==
KILL_CHAR
(
tty
)
||
c
==
WERASE_CHAR
(
tty
))
{
int
seen_alnums
=
(
c
==
WERASE_CHAR
(
tty
))
?
0
:
-
1
;
int
cc
;
/* deal with killing in the input line */
while
(
!
(
EMPTY
(
&
tty
->
secondary
)
||
(
cc
=
LAST
(
&
tty
->
secondary
))
==
10
||
((
EOF_CHAR
(
tty
)
!=
__DISABLED_CHAR
)
&&
(
cc
==
EOF_CHAR
(
tty
)))))
{
/* if killing just a word, kill all
non-alnum chars, then all alnum
chars. */
if
(
seen_alnums
>=
0
)
{
if
(
isalnum
(
cc
))
seen_alnums
++
;
else
if
(
seen_alnums
)
break
;
if
(
L_ICANON
(
tty
)
&&
!
tty
->
lnext
)
{
if
(
c
==
ERASE_CHAR
(
tty
)
||
c
==
KILL_CHAR
(
tty
)
||
(
c
==
WERASE_CHAR
(
tty
)
&&
L_IEXTEN
(
tty
)))
{
eraser
(
c
,
tty
);
continue
;
}
if
(
c
==
LNEXT_CHAR
(
tty
)
&&
L_IEXTEN
(
tty
))
{
tty
->
lnext
=
1
;
if
(
L_ECHO
(
tty
))
{
int
ct
=
1
;
if
(
cc
<
32
)
ct
=
(
L_ECHOCTL
(
tty
)
?
2
:
0
);
while
(
ct
--
)
{
put_tty_queue
(
'\b'
,
&
tty
->
write_q
);
put_tty_queue
(
' '
,
&
tty
->
write_q
);
put_tty_queue
(
'\b'
,
&
tty
->
write_q
);
if
(
tty
->
erasing
)
{
opost
(
'/'
,
tty
);
tty
->
erasing
=
0
;
}
if
(
L_ECHOCTL
(
tty
))
{
opost
(
'^'
,
tty
);
opost
(
'\b'
,
tty
);
}
DEC
(
tty
->
secondary
.
head
);
if
(
c
==
ERASE_CHAR
(
tty
))
break
;
}
continue
;
}
if
(
c
==
LNEXT_CHAR
(
tty
))
{
tty
->
lnext
=
1
;
if
(
L_ECHO
(
tty
))
{
put_tty_queue
(
'^'
,
&
tty
->
write_q
);
put_tty_queue
(
'\b'
,
&
tty
->
write_q
);
if
(
c
==
REPRINT_CHAR
(
tty
)
&&
L_ECHO
(
tty
)
&&
L_IEXTEN
(
tty
))
{
unsigned
long
tail
=
tty
->
canon_head
;
if
(
tty
->
erasing
)
{
opost
(
'/'
,
tty
);
tty
->
erasing
=
0
;
}
echo_char
(
c
,
tty
);
opost
(
'\n'
,
tty
);
while
(
tail
!=
tty
->
secondary
.
head
)
{
echo_char
(
tty
->
secondary
.
buf
[
tail
],
tty
);
INC
(
tail
);
}
continue
;
}
}
if
(
I_IXON
(
tty
)
&&
!
tty
->
lnext
)
{
if
(
c
==
STOP_CHAR
(
tty
))
{
tty
->
ctrl_status
&=
~
(
TIOCPKT_START
);
tty
->
ctrl_status
|=
TIOCPKT_STOP
;
if
(
tty
->
link
)
wake_up_interruptible
(
&
tty
->
link
->
except_q
);
tty
->
stopped
=
1
;
if
(
tty
->
stop
)
(
tty
->
stop
)(
tty
);
if
(
IS_A_CONSOLE
(
tty
->
line
))
{
set_vc_kbd_flag
(
kbd_table
+
fg_console
,
VC_SCROLLOCK
);
set_leds
();
}
if
((
tty
->
stopped
&&
I_IXANY
(
tty
)
&&
L_IEXTEN
(
tty
))
||
c
==
START_CHAR
(
tty
))
{
start_tty
(
tty
);
continue
;
}
if
(((
I_IXANY
(
tty
))
&&
tty
->
stopped
)
||
(
c
==
START_CHAR
(
tty
)))
{
tty
->
ctrl_status
&=
~
(
TIOCPKT_STOP
);
tty
->
ctrl_status
|=
TIOCPKT_START
;
tty
->
stopped
=
0
;
if
(
tty
->
link
)
wake_up_interruptible
(
&
tty
->
link
->
except_q
);
if
(
tty
->
start
)
(
tty
->
start
)(
tty
);
if
(
IS_A_CONSOLE
(
tty
->
line
))
{
clr_vc_kbd_flag
(
kbd_table
+
fg_console
,
VC_SCROLLOCK
);
set_leds
();
}
if
(
c
==
STOP_CHAR
(
tty
))
{
stop_tty
(
tty
);
continue
;
}
}
if
(
L_ISIG
(
tty
)
&&
!
tty
->
lnext
)
{
if
(
c
==
INTR_CHAR
(
tty
))
{
kill_pg
(
tty
->
pgrp
,
SIGINT
,
1
);
if
(
!
_L_FLAG
(
tty
,
NOFLSH
))
{
flush_input
(
tty
);
flush_output
(
tty
);
}
isig
(
SIGINT
,
tty
);
continue
;
}
if
(
c
==
QUIT_CHAR
(
tty
))
{
kill_pg
(
tty
->
pgrp
,
SIGQUIT
,
1
);
if
(
!
_L_FLAG
(
tty
,
NOFLSH
))
{
flush_input
(
tty
);
flush_output
(
tty
);
}
isig
(
SIGQUIT
,
tty
);
continue
;
}
if
(
c
==
SUSPEND_CHAR
(
tty
))
{
if
(
!
is_orphaned_pgrp
(
tty
->
pgrp
))
{
kill_pg
(
tty
->
pgrp
,
SIGTSTP
,
1
);
if
(
!
_L_FLAG
(
tty
,
NOFLSH
))
{
flush_input
(
tty
);
flush_output
(
tty
);
}
}
if
(
c
==
SUSP_CHAR
(
tty
))
{
if
(
!
is_orphaned_pgrp
(
tty
->
pgrp
))
isig
(
SIGTSTP
,
tty
);
continue
;
}
}
if
(
c
==
10
||
(
EOF_CHAR
(
tty
)
!=
__DISABLED_CHAR
&&
c
==
EOF_CHAR
(
tty
)))
tty
->
secondary
.
data
++
;
if
((
c
==
10
)
&&
(
L_ECHO
(
tty
)
||
(
L_CANON
(
tty
)
&&
L_ECHONL
(
tty
))))
{
put_tty_queue
(
'\n'
,
&
tty
->
write_q
);
put_tty_queue
(
'\r'
,
&
tty
->
write_q
);
if
(
tty
->
erasing
)
{
opost
(
'/'
,
tty
);
tty
->
erasing
=
0
;
}
if
(
c
==
'\n'
&&
!
tty
->
lnext
)
{
if
(
L_ECHO
(
tty
)
||
(
L_ICANON
(
tty
)
&&
L_ECHONL
(
tty
)))
opost
(
'\n'
,
tty
);
}
else
if
(
L_ECHO
(
tty
))
{
if
(
c
<
32
&&
L_ECHOCTL
(
tty
))
{
put_tty_queue
(
'^'
,
&
tty
->
write_q
);
put_tty_queue
(
c
+
'A'
-
1
,
&
tty
->
write_q
);
if
(
EOF_CHAR
(
tty
)
!=
__DISABLED_CHAR
&&
c
==
EOF_CHAR
(
tty
)
&&
!
tty
->
lnext
)
{
put_tty_queue
(
'\b'
,
&
tty
->
write_q
);
put_tty_queue
(
'\b'
,
&
tty
->
write_q
);
/* Don't echo the EOF char in canonical mode. Sun
handles this differently by echoing the char and
then backspacing, but that's a hack. */
if
(
c
!=
EOF_CHAR
(
tty
)
||
!
L_ICANON
(
tty
)
||
tty
->
lnext
)
{
/* Record the column of first canon char. */
if
(
tty
->
canon_head
==
tty
->
secondary
.
head
)
tty
->
canon_column
=
tty
->
column
;
echo_char
(
c
,
tty
);
}
}
else
put_tty_queue
(
c
,
&
tty
->
write_q
);
}
tty
->
lnext
=
0
;
if
(
I_PARMRK
(
tty
)
&&
c
==
(
unsigned
char
)
'\377'
&&
(
c
!=
EOF_CHAR
(
tty
)
||
!
L_ICANON
(
tty
)
||
tty
->
lnext
))
put_tty_queue
(
c
,
&
tty
->
secondary
);
if
(
L_ICANON
(
tty
)
&&
!
tty
->
lnext
&&
(
c
==
'\n'
||
c
==
EOF_CHAR
(
tty
)
||
c
==
EOL_CHAR
(
tty
)
||
(
c
==
EOL2_CHAR
(
tty
)
&&
L_IEXTEN
(
tty
))))
{
if
(
c
==
EOF_CHAR
(
tty
))
c
=
__DISABLED_CHAR
;
set_bit
(
tty
->
secondary
.
head
,
&
tty
->
secondary_flags
);
put_tty_queue
(
c
,
&
tty
->
secondary
);
tty
->
canon_head
=
tty
->
secondary
.
head
;
tty
->
canon_data
++
;
}
else
put_tty_queue
(
c
,
&
tty
->
secondary
);
tty
->
lnext
=
0
;
}
if
(
!
EMPTY
(
&
tty
->
write_q
))
TTY_WRITE_FLUSH
(
tty
);
if
(
!
EMPTY
(
&
tty
->
secondary
))
if
(
L_ICANON
(
tty
)
?
tty
->
canon_data
:
!
EMPTY
(
&
tty
->
secondary
))
wake_up_interruptible
(
&
tty
->
secondary
.
proc_list
);
if
(
tty
->
write_q
.
proc_list
&&
LEFT
(
&
tty
->
write_q
)
>
TTY_BUF_SIZE
/
2
)
wake_up_interruptible
(
&
tty
->
write_q
.
proc_list
);
if
(
tty
->
throttle
&&
(
LEFT
(
&
tty
->
read_q
)
>=
RQ_THRESHOLD_HW
)
&&
clear_bit
(
TTY_RQ_THROTTLED
,
&
tty
->
flags
))
tty
->
throttle
(
tty
,
TTY_THROTTLE_RQ_AVAIL
);
if
(
tty
->
throttle
&&
(
LEFT
(
&
tty
->
secondary
)
>=
SQ_THRESHOLD_HW
)
&&
clear_bit
(
TTY_SQ_THROTTLED
,
&
tty
->
flags
))
tty
->
throttle
(
tty
,
TTY_THROTTLE_SQ_AVAIL
);
}
int
is_ignored
(
int
sig
)
...
...
@@ -729,278 +921,205 @@ int is_ignored(int sig)
(
current
->
sigaction
[
sig
-
1
].
sa_handler
==
SIG_IGN
));
}
static
int
available_canon_input
(
struct
tty_struct
*
);
static
void
__wait_for_canon_input
(
struct
file
*
file
,
struct
tty_struct
*
);
static
void
wait_for_canon_input
(
struct
file
*
file
,
struct
tty_struct
*
tty
)
static
inline
int
input_available_p
(
struct
tty_struct
*
tty
)
{
if
(
!
available_canon_input
(
tty
))
{
if
(
current
->
signal
&
~
current
->
blocked
)
return
;
__wait_for_canon_input
(
file
,
tty
);
}
/* Avoid calling TTY_READ_FLUSH unnecessarily. */
if
(
L_ICANON
(
tty
))
{
if
(
tty
->
canon_data
||
FULL
(
&
tty
->
read_q
))
return
1
;
}
else
if
(
!
EMPTY
(
&
tty
->
secondary
))
return
1
;
/* Shuffle any pending data down the queues. */
TTY_READ_FLUSH
(
tty
);
if
(
tty
->
link
)
TTY_WRITE_FLUSH
(
tty
->
link
);
if
(
L_ICANON
(
tty
))
{
if
(
tty
->
canon_data
||
FULL
(
&
tty
->
read_q
))
return
1
;
}
else
if
(
!
EMPTY
(
&
tty
->
secondary
))
return
1
;
return
0
;
}
static
int
read_chan
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
char
*
buf
,
int
nr
)
static
int
read_chan
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
char
*
buf
,
unsigned
int
nr
)
{
struct
wait_queue
wait
=
{
current
,
NULL
};
int
c
;
char
*
b
=
buf
;
int
minimum
,
time
;
unsigned
char
*
b
=
buf
;
int
minimum
,
time
;
int
retval
=
0
;
if
(
L_CANON
(
tty
))
minimum
=
time
=
current
->
timeout
=
0
;
else
{
time
=
10L
*
tty
->
termios
->
c_cc
[
VTIME
];
minimum
=
tty
->
termios
->
c_cc
[
VMIN
];
if
(
L_ICANON
(
tty
))
{
minimum
=
time
=
0
;
current
->
timeout
=
(
unsigned
long
)
-
1
;
}
else
{
time
=
(
HZ
/
10
)
*
TIME_CHAR
(
tty
);
minimum
=
MIN_CHAR
(
tty
);
if
(
minimum
)
current
->
timeout
=
0xffffffff
;
current
->
timeout
=
(
unsigned
long
)
-
1
;
else
{
if
(
time
)
if
(
time
)
{
current
->
timeout
=
time
+
jiffies
;
else
current
->
timeout
=
0
;
time
=
0
;
}
else
current
->
timeout
=
0
;
minimum
=
1
;
}
}
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
time
=
current
->
timeout
=
0
;
if
(
L_CANON
(
tty
)
&&
!
available_canon_input
(
tty
))
return
-
EAGAIN
;
}
else
if
(
L_CANON
(
tty
))
{
wait_for_canon_input
(
file
,
tty
);
if
(
current
->
signal
&
~
current
->
blocked
)
return
-
ERESTARTSYS
;
}
if
(
minimum
>
nr
)
minimum
=
nr
;
/* deal with packet mode: First test for status change */
if
(
tty
->
packet
&&
tty
->
link
&&
tty
->
link
->
ctrl_status
)
{
put_fs_byte
(
tty
->
link
->
ctrl_status
,
b
);
tty
->
link
->
ctrl_status
=
0
;
return
1
;
}
/* now bump the buffer up one. */
if
(
tty
->
packet
)
{
put_fs_byte
(
0
,
b
++
);
nr
--
;
/* this really shouldn't happen, but we need to
put it here. */
if
(
nr
==
0
)
return
1
;
}
add_wait_queue
(
&
tty
->
secondary
.
proc_list
,
&
wait
);
while
(
nr
>
0
)
{
if
(
tty_hung_up_p
(
file
))
{
file
->
f_flags
&=
~
O_NONBLOCK
;
break
;
/* force read() to return 0 */
}
TTY_READ_FLUSH
(
tty
);
if
(
tty
->
link
)
TTY_WRITE_FLUSH
(
tty
->
link
);
while
(
nr
>
0
&&
((
c
=
get_tty_queue
(
&
tty
->
secondary
))
>=
0
))
{
if
((
EOF_CHAR
(
tty
)
!=
__DISABLED_CHAR
&&
c
==
EOF_CHAR
(
tty
))
||
c
==
10
)
tty
->
secondary
.
data
--
;
if
((
EOF_CHAR
(
tty
)
!=
__DISABLED_CHAR
&&
c
==
EOF_CHAR
(
tty
))
&&
L_CANON
(
tty
))
break
;
put_fs_byte
(
c
,
b
++
);
nr
--
;
if
(
time
)
current
->
timeout
=
time
+
jiffies
;
if
(
c
==
10
&&
L_CANON
(
tty
))
break
;
};
wake_up_interruptible
(
&
tty
->
read_q
.
proc_list
);
/*
* If there is enough space in the secondary queue
* now, let the low-level driver know.
*/
if
(
tty
->
throttle
&&
(
LEFT
(
&
tty
->
secondary
)
>=
SQ_THRESHOLD_HW
)
&&
clear_bit
(
TTY_SQ_THROTTLED
,
&
tty
->
flags
))
tty
->
throttle
(
tty
,
TTY_THROTTLE_SQ_AVAIL
);
if
(
tty
->
link
)
{
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
{
if
((
tty
->
flags
&
(
1
<<
TTY_SLAVE_OPENED
))
&&
tty
->
link
->
count
<=
1
)
{
file
->
f_flags
&=
~
O_NONBLOCK
;
while
(
1
)
{
/* Job control check -- must be done at start and after
every sleep (POSIX.1 7.1.1.4). */
/* don't stop on /dev/console */
if
(
file
->
f_inode
->
i_rdev
!=
CONSOLE_DEV
&&
current
->
tty
==
tty
->
line
)
{
if
(
tty
->
pgrp
<=
0
)
printk
(
"read_chan: tty->pgrp <= 0!
\n
"
);
else
if
(
current
->
pgrp
!=
tty
->
pgrp
)
{
if
(
is_ignored
(
SIGTTIN
)
||
is_orphaned_pgrp
(
current
->
pgrp
))
{
retval
=
-
EIO
;
break
;
}
}
else
if
(
!
tty
->
link
->
count
)
{
file
->
f_flags
&=
~
O_NONBLOCK
;
kill_pg
(
current
->
pgrp
,
SIGTTIN
,
1
);
retval
=
-
ERESTARTSYS
;
break
;
}
}
if
(
b
-
buf
>=
minimum
||
!
current
->
timeout
)
/* First test for status change. */
if
(
tty
->
packet
&&
tty
->
link
->
ctrl_status
)
{
if
(
b
!=
buf
)
break
;
if
(
current
->
signal
&
~
current
->
blocked
)
put_fs_byte
(
tty
->
link
->
ctrl_status
,
b
++
);
tty
->
link
->
ctrl_status
=
0
;
break
;
TTY_READ_FLUSH
(
tty
);
if
(
tty
->
link
)
TTY_WRITE_FLUSH
(
tty
->
link
);
if
(
!
EMPTY
(
&
tty
->
secondary
))
continue
;
current
->
state
=
TASK_INTERRUPTIBLE
;
if
(
EMPTY
(
&
tty
->
secondary
))
schedule
();
current
->
state
=
TASK_RUNNING
;
}
remove_wait_queue
(
&
tty
->
secondary
.
proc_list
,
&
wait
);
TTY_READ_FLUSH
(
tty
);
if
(
tty
->
link
&&
tty
->
link
->
write
)
TTY_WRITE_FLUSH
(
tty
->
link
);
current
->
timeout
=
0
;
/* packet mode sticks in an extra 0. If that's all we've got,
we should count it a zero bytes. */
if
(
tty
->
packet
)
{
if
((
b
-
buf
)
>
1
)
return
b
-
buf
;
}
else
{
if
(
b
-
buf
)
return
b
-
buf
;
}
if
(
current
->
signal
&
~
current
->
blocked
)
return
-
ERESTARTSYS
;
if
(
file
->
f_flags
&
O_NONBLOCK
)
return
-
EAGAIN
;
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
return
-
EIO
;
return
0
;
}
static
void
__wait_for_canon_input
(
struct
file
*
file
,
struct
tty_struct
*
tty
)
{
struct
wait_queue
wait
=
{
current
,
NULL
};
add_wait_queue
(
&
tty
->
secondary
.
proc_list
,
&
wait
);
while
(
1
)
{
/* This statement must be first before checking for input
so that any interrupt will set the state back to
TASK_RUNNING. */
current
->
state
=
TASK_INTERRUPTIBLE
;
if
(
available_canon_input
(
tty
))
break
;
if
(
current
->
signal
&
~
current
->
blocked
)
if
(
!
input_available_p
(
tty
))
{
if
(
tty
->
flags
&
(
1
<<
TTY_SLAVE_CLOSED
))
{
retval
=
-
EIO
;
break
;
}
if
(
tty_hung_up_p
(
file
))
break
;
schedule
();
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
&
tty
->
secondary
.
proc_list
,
&
wait
);
}
static
int
available_canon_input
(
struct
tty_struct
*
tty
)
{
TTY_READ_FLUSH
(
tty
);
if
(
tty
->
link
)
if
(
tty
->
link
->
count
)
TTY_WRITE_FLUSH
(
tty
->
link
);
else
return
1
;
if
(
FULL
(
&
tty
->
read_q
))
return
1
;
if
(
tty
->
secondary
.
data
)
return
1
;
return
0
;
}
static
int
write_chan
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
char
*
buf
,
int
nr
)
{
struct
wait_queue
wait
=
{
current
,
NULL
};
char
c
,
*
b
=
buf
;
if
(
nr
<
0
)
return
-
EINVAL
;
if
(
!
nr
)
return
0
;
add_wait_queue
(
&
tty
->
write_q
.
proc_list
,
&
wait
);
while
(
nr
>
0
)
{
if
(
current
->
signal
&
~
current
->
blocked
)
if
(
!
current
->
timeout
)
break
;
if
(
tty_hung_up_p
(
file
))
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
retval
=
-
EAGAIN
;
break
;
if
(
tty
->
link
&&
!
tty
->
link
->
count
)
{
send_sig
(
SIGPIPE
,
current
,
0
);
}
if
(
current
->
signal
&
~
current
->
blocked
)
{
retval
=
-
ERESTARTSYS
;
break
;
}
current
->
state
=
TASK_INTERRUPTIBLE
;
if
(
FULL
(
&
tty
->
write_q
))
{
TTY_WRITE_FLUSH
(
tty
);
if
(
FULL
(
&
tty
->
write_q
))
schedule
();
current
->
state
=
TASK_RUNNING
;
continue
;
}
current
->
state
=
TASK_RUNNING
;
while
(
nr
>
0
&&
!
FULL
(
&
tty
->
write_q
))
{
c
=
get_fs_byte
(
b
);
if
(
O_POST
(
tty
))
{
switch
(
c
)
{
case
'\n'
:
if
(
O_NLRET
(
tty
))
{
tty
->
column
=
0
;
/* Deal with packet mode. */
if
(
tty
->
packet
&&
b
==
buf
)
{
put_fs_byte
(
TIOCPKT_DATA
,
b
++
);
nr
--
;
}
if
(
O_NLCR
(
tty
))
{
if
(
!
set_bit
(
TTY_CR_PENDING
,
&
tty
->
flags
))
{
c
=
'\r'
;
tty
->
column
=
0
;
b
--
;
nr
++
;
}
else
{
clear_bit
(
TTY_CR_PENDING
,
&
tty
->
flags
);
while
(
nr
>
0
)
{
int
eol
;
cli
();
if
(
EMPTY
(
&
tty
->
secondary
))
{
sti
();
break
;
}
eol
=
clear_bit
(
tty
->
secondary
.
tail
,
&
tty
->
secondary_flags
);
c
=
tty
->
secondary
.
buf
[
tty
->
secondary
.
tail
];
INC
(
tty
->
secondary
.
tail
);
sti
();
if
(
eol
)
{
if
(
--
tty
->
canon_data
<
0
)
{
printk
(
"read_chan: canon_data < 0!
\n
"
);
tty
->
canon_data
=
0
;
}
if
(
c
==
__DISABLED_CHAR
)
break
;
case
'\r'
:
if
(
O_NOCR
(
tty
)
&&
tty
->
column
==
0
)
{
b
++
;
nr
--
;
continue
;
}
if
(
O_CRNL
(
tty
))
{
c
=
'\n'
;
if
(
O_NLRET
(
tty
))
tty
->
column
=
0
;
put_fs_byte
(
c
,
b
++
);
nr
--
;
break
;
}
tty
->
column
=
0
;
put_fs_byte
(
c
,
b
++
);
nr
--
;
}
/* If there is enough space in the secondary queue now, let the
low-level driver know. */
if
(
tty
->
throttle
&&
(
LEFT
(
&
tty
->
secondary
)
>=
SQ_THRESHOLD_HW
)
&&
!
clear_bit
(
TTY_SQ_THROTTLED
,
&
tty
->
flags
))
tty
->
throttle
(
tty
,
TTY_THROTTLE_SQ_AVAIL
);
/* XXX packet mode's status byte is mistakenly counted */
if
(
b
-
buf
>=
minimum
||
!
nr
)
break
;
case
'\t'
:
if
(
O_TABDLY
(
tty
)
==
XTABS
)
{
c
=
' '
;
tty
->
column
++
;
if
(
tty
->
column
%
8
!=
0
)
{
b
--
;
nr
++
;
if
(
time
)
current
->
timeout
=
time
+
jiffies
;
}
remove_wait_queue
(
&
tty
->
secondary
.
proc_list
,
&
wait
);
current
->
state
=
TASK_RUNNING
;
current
->
timeout
=
0
;
return
(
b
-
buf
)
?
b
-
buf
:
retval
;
}
static
int
write_chan
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
char
*
buf
,
unsigned
int
nr
)
{
struct
wait_queue
wait
=
{
current
,
NULL
};
int
c
;
unsigned
char
*
b
=
buf
;
int
retval
=
0
;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
if
(
L_TOSTOP
(
tty
)
&&
file
->
f_inode
->
i_rdev
!=
CONSOLE_DEV
)
{
retval
=
check_change
(
tty
,
tty
->
line
);
if
(
retval
)
return
retval
;
}
break
;
case
'\b'
:
tty
->
column
--
;
break
;
default:
if
(
O_LCUC
(
tty
))
c
=
toupper
(
c
);
tty
->
column
++
;
add_wait_queue
(
&
tty
->
write_q
.
proc_list
,
&
wait
);
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
if
(
current
->
signal
&
~
current
->
blocked
)
{
retval
=
-
ERESTARTSYS
;
break
;
}
if
(
tty_hung_up_p
(
file
)
||
(
tty
->
link
&&
!
tty
->
link
->
count
))
{
retval
=
-
EIO
;
break
;
}
while
(
nr
>
0
)
{
c
=
get_fs_byte
(
b
);
/* Care is needed here: opost() can abort even
if the write_q is not full. */
if
(
opost
(
c
,
tty
)
<
0
)
break
;
b
++
;
nr
--
;
put_tty_queue
(
c
,
&
tty
->
write_q
);
}
if
(
need_resched
)
TTY_WRITE_FLUSH
(
tty
);
if
(
!
nr
)
break
;
if
(
EMPTY
(
&
tty
->
write_q
)
&&
!
need_resched
)
continue
;
schedule
();
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
&
tty
->
write_q
.
proc_list
,
&
wait
);
TTY_WRITE_FLUSH
(
tty
);
if
(
b
-
buf
)
return
b
-
buf
;
if
(
tty
->
link
&&
!
tty
->
link
->
count
)
return
-
EPIPE
;
if
(
current
->
signal
&
~
current
->
blocked
)
return
-
ERESTARTSYS
;
return
0
;
return
(
b
-
buf
)
?
b
-
buf
:
retval
;
}
static
int
tty_read
(
struct
inode
*
inode
,
struct
file
*
file
,
char
*
buf
,
int
count
)
...
...
@@ -1017,6 +1136,12 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
tty
=
TTY_TABLE
(
dev
);
if
(
!
tty
||
(
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
)))
return
-
EIO
;
/* This check not only needs to be done before reading, but also
whenever read_chan() gets woken up after sleeping, so I've
moved it to there. This should only be done for the N_TTY
line discipline, anyway. Same goes for write_chan(). -- jlc. */
#if 0
if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
(tty->pgrp > 0) &&
(current->tty == dev) &&
...
...
@@ -1027,8 +1152,10 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
(void) kill_pg(current->pgrp, SIGTTIN, 1);
return -ERESTARTSYS;
}
#endif
if
(
ldiscs
[
tty
->
disc
].
read
)
i
=
(
ldiscs
[
tty
->
disc
].
read
)(
tty
,
file
,
buf
,
count
);
/* XXX casts are for what kernel-wide prototypes should be. */
i
=
(
ldiscs
[
tty
->
disc
].
read
)(
tty
,
file
,(
unsigned
char
*
)
buf
,(
unsigned
int
)
count
);
else
i
=
-
EIO
;
if
(
i
>
0
)
...
...
@@ -1054,6 +1181,7 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
tty
=
TTY_TABLE
(
dev
);
if
(
!
tty
||
!
tty
->
write
||
(
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
)))
return
-
EIO
;
#if 0
if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == dev) && (tty->pgrp != current->pgrp)) {
if (is_orphaned_pgrp(current->pgrp))
...
...
@@ -1063,8 +1191,10 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
return -ERESTARTSYS;
}
}
#endif
if
(
ldiscs
[
tty
->
disc
].
write
)
i
=
(
ldiscs
[
tty
->
disc
].
write
)(
tty
,
file
,
buf
,
count
);
/* XXX casts are for what kernel-wide prototypes should be. */
i
=
(
ldiscs
[
tty
->
disc
].
write
)(
tty
,
file
,(
unsigned
char
*
)
buf
,(
unsigned
int
)
count
);
else
i
=
-
EIO
;
if
(
i
>
0
)
...
...
@@ -1349,6 +1479,7 @@ static int tty_open(struct inode * inode, struct file * filp)
if
(
test_bit
(
TTY_EXCLUSIVE
,
&
tty
->
flags
)
&&
!
suser
())
return
-
EBUSY
;
#if 0
/* clean up the packet stuff. */
/*
* Why is this not done in init_dev? Right here, if another
...
...
@@ -1358,9 +1489,12 @@ static int tty_open(struct inode * inode, struct file * filp)
*
* Not to worry, a pty master can only be opened once.
* And rlogind and telnetd both use packet mode. -- jrs
*
* Not needed. These are cleared in initialize_tty_struct. -- jlc
*/
tty->ctrl_status = 0;
tty->packet = 0;
#endif
if
(
tty
->
open
)
{
retval
=
tty
->
open
(
tty
,
filp
);
...
...
@@ -1441,26 +1575,16 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
{
switch
(
sel_type
)
{
case
SEL_IN
:
if
(
L_CANON
(
tty
))
{
if
(
available_canon_input
(
tty
))
return
1
;
}
else
if
(
!
EMPTY
(
&
tty
->
secondary
))
if
(
input_available_p
(
tty
))
return
1
;
if
(
tty
->
link
)
{
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
{
if
((
tty
->
flags
&
(
1
<<
TTY_SLAVE_OPENED
))
&&
tty
->
link
->
count
<=
1
)
/* fall through */
case
SEL_EX
:
if
(
tty
->
packet
&&
tty
->
link
->
ctrl_status
)
return
1
;
}
else
{
if
(
!
tty
->
link
->
count
)
if
(
tty
->
flags
&
(
1
<<
TTY_SLAVE_CLOSED
))
return
1
;
}
}
/* see if the status byte can be read. */
if
(
tty
->
packet
&&
tty
->
link
&&
tty
->
link
->
ctrl_status
)
if
(
tty_hung_up_p
(
file
))
return
1
;
select_wait
(
&
tty
->
secondary
.
proc_list
,
wait
);
return
0
;
case
SEL_OUT
:
...
...
@@ -1468,22 +1592,6 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
return
1
;
select_wait
(
&
tty
->
write_q
.
proc_list
,
wait
);
return
0
;
case
SEL_EX
:
if
(
tty
->
link
)
{
if
(
IS_A_PTY_MASTER
(
tty
->
line
))
{
if
((
tty
->
flags
&
(
1
<<
TTY_SLAVE_OPENED
))
&&
tty
->
link
->
count
<=
1
)
return
1
;
if
(
tty
->
packet
&&
tty
->
link
->
ctrl_status
)
return
1
;
}
else
{
if
(
!
tty
->
link
->
count
)
return
1
;
}
}
select_wait
(
&
tty
->
except_q
,
wait
);
return
0
;
}
return
0
;
}
...
...
@@ -1645,8 +1753,6 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
tty
->
line
=
line
;
tty
->
disc
=
N_TTY
;
tty
->
pgrp
=
-
1
;
tty
->
winsize
.
ws_row
=
0
;
tty
->
winsize
.
ws_col
=
0
;
if
(
IS_A_CONSOLE
(
line
))
{
tty
->
open
=
con_open
;
tty
->
winsize
.
ws_row
=
video_num_lines
;
...
...
@@ -1656,31 +1762,26 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
}
else
if
IS_A_PTY
(
line
)
{
tty
->
open
=
pty_open
;
}
tty
->
except_q
=
NULL
;
}
static
void
initialize_termios
(
int
line
,
struct
termios
*
tp
)
{
memset
(
tp
,
0
,
sizeof
(
struct
termios
));
memcpy
(
tp
->
c_cc
,
INIT_C_CC
,
NCCS
);
if
(
IS_A_CONSOLE
(
line
))
{
if
(
IS_A_CONSOLE
(
line
)
||
IS_A_PTY_SLAVE
(
line
)
)
{
tp
->
c_iflag
=
ICRNL
|
IXON
;
tp
->
c_oflag
=
OPOST
|
ONLCR
;
tp
->
c_cflag
=
B38400
|
CS8
|
CREAD
;
tp
->
c_lflag
=
ISIG
|
ICANON
|
ECHO
|
ECHOCTL
|
ECHOKE
;
tp
->
c_lflag
=
ISIG
|
ICANON
|
ECHO
|
ECHOE
|
ECHOK
|
ECHOCTL
|
ECHOKE
|
IEXTEN
;
}
else
if
(
IS_A_SERIAL
(
line
))
{
tp
->
c_
cflag
=
B9600
|
CS8
|
CREAD
|
HUPCL
|
CLOCAL
;
tp
->
c_
iflag
=
ICRNL
|
IXON
;
tp
->
c_oflag
=
OPOST
|
ONLCR
|
XTABS
;
}
else
if
(
IS_A_PTY_MASTER
(
line
))
{
tp
->
c_cflag
=
B9600
|
CS8
|
CREAD
|
HUPCL
|
CLOCAL
;
tp
->
c_lflag
=
ISIG
|
ICANON
|
ECHO
|
ECHOE
|
ECHOK
|
ECHOCTL
|
ECHOKE
|
IEXTEN
;
}
else
if
(
IS_A_PTY_MASTER
(
line
))
tp
->
c_cflag
=
B9600
|
CS8
|
CREAD
;
}
else
if
(
IS_A_PTY_SLAVE
(
line
))
{
tp
->
c_iflag
=
ICRNL
|
IXON
;
tp
->
c_oflag
=
OPOST
|
ONLCR
;
tp
->
c_cflag
=
B38400
|
CS8
|
CREAD
;
tp
->
c_lflag
=
ISIG
|
ICANON
|
ECHO
|
ECHOCTL
|
ECHOKE
;
}
}
static
struct
tty_ldisc
tty_ldisc_N_TTY
=
{
...
...
drivers/char/tty_ioctl.c
View file @
b168ffdf
...
...
@@ -17,6 +17,7 @@
#include <linux/major.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm/bitops.h>
...
...
@@ -41,44 +42,43 @@ extern int paste_selection(struct tty_struct *tty);
static
int
tty_set_ldisc
(
struct
tty_struct
*
tty
,
int
ldisc
);
static
void
flush
(
struct
tty_queue
*
queue
)
void
flush_input
(
struct
tty_struct
*
tty
)
{
if
(
queue
)
{
cli
();
queue
->
head
=
queue
->
tail
;
tty
->
read_q
.
head
=
tty
->
read_q
.
tail
=
0
;
tty
->
secondary
.
head
=
tty
->
secondary
.
tail
=
0
;
tty
->
canon_head
=
tty
->
canon_data
=
tty
->
erasing
=
0
;
memset
(
&
tty
->
readq_flags
,
0
,
sizeof
tty
->
readq_flags
);
memset
(
&
tty
->
secondary_flags
,
0
,
sizeof
tty
->
secondary_flags
);
sti
();
wake_up_interruptible
(
&
queue
->
proc_list
);
}
}
void
flush_input
(
struct
tty_struct
*
tty
)
{
if
(
!
tty
->
link
)
return
;
/* No cli() since ptys don't use interrupts. */
tty
->
link
->
write_q
.
head
=
tty
->
link
->
write_q
.
tail
=
0
;
wake_up_interruptible
(
&
tty
->
link
->
write_q
.
proc_list
);
if
(
tty
->
link
->
packet
)
{
tty
->
ctrl_status
|=
TIOCPKT_FLUSHREAD
;
if
(
tty
->
link
)
wake_up_interruptible
(
&
tty
->
link
->
except_q
);
flush
(
&
tty
->
read_q
);
wake_up_interruptible
(
&
tty
->
read_q
.
proc_list
);
flush
(
&
tty
->
secondary
);
tty
->
secondary
.
data
=
0
;
if
((
tty
=
tty
->
link
)
!=
NULL
)
{
flush
(
&
tty
->
write_q
);
wake_up_interruptible
(
&
tty
->
write_q
.
proc_list
);
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
}
}
void
flush_output
(
struct
tty_struct
*
tty
)
{
tty
->
ctrl_status
|=
TIOCPKT_FLUSHWRITE
;
if
(
tty
->
link
)
wake_up_interruptible
(
&
tty
->
link
->
except_q
);
flush
(
&
tty
->
write_q
);
cli
();
tty
->
write_q
.
head
=
tty
->
write_q
.
tail
=
0
;
sti
();
wake_up_interruptible
(
&
tty
->
write_q
.
proc_list
);
if
((
tty
=
tty
->
link
)
!=
NULL
)
{
flush
(
&
tty
->
read_q
);
wake_up_interruptible
(
&
tty
->
read_q
.
proc_list
);
flush
(
&
tty
->
secondary
);
tty
->
secondary
.
data
=
0
;
if
(
!
tty
->
link
)
return
;
/* No cli() since ptys don't use interrupts. */
tty
->
link
->
read_q
.
head
=
tty
->
link
->
read_q
.
tail
=
0
;
tty
->
link
->
secondary
.
head
=
tty
->
link
->
secondary
.
tail
=
0
;
tty
->
link
->
canon_head
=
tty
->
link
->
canon_data
=
tty
->
link
->
erasing
=
0
;
memset
(
&
tty
->
link
->
readq_flags
,
0
,
sizeof
tty
->
readq_flags
);
memset
(
&
tty
->
link
->
secondary_flags
,
0
,
sizeof
tty
->
secondary_flags
);
if
(
tty
->
link
->
packet
)
{
tty
->
ctrl_status
|=
TIOCPKT_FLUSHWRITE
;
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
}
}
...
...
@@ -156,65 +156,61 @@ static void unset_locked_termios(struct termios *termios,
old
->
c_cc
[
i
]
:
termios
->
c_cc
[
i
];
}
static
int
get_termios
(
struct
tty_struct
*
tty
,
struct
termios
*
termios
)
{
int
i
;
i
=
verify_area
(
VERIFY_WRITE
,
termios
,
sizeof
(
*
termios
));
if
(
i
)
return
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
*
termios
))
;
i
++
)
put_fs_byte
(
((
char
*
)
tty
->
termios
)[
i
]
,
i
+
(
char
*
)
termios
);
return
0
;
}
static
int
check_change
(
struct
tty_struct
*
tty
,
int
channel
)
int
check_change
(
struct
tty_struct
*
tty
,
int
channel
)
{
/* If we try to set the state of terminal and we're not in the
foreground, send a SIGTTOU. If the signal is blocked or
ignored, go ahead and perform the operation. POSIX 7.2) */
if
(
current
->
tty
!=
channel
)
return
0
;
if
(
tty
->
pgrp
<=
0
||
tty
->
pgrp
==
current
->
pgrp
)
if
(
tty
->
pgrp
<=
0
)
{
printk
(
"check_change: tty->pgrp <= 0!
\n
"
);
return
0
;
}
if
(
current
->
pgrp
==
tty
->
pgrp
)
return
0
;
if
(
is_orphaned_pgrp
(
current
->
pgrp
))
return
-
EIO
;
if
(
is_ignored
(
SIGTTOU
))
return
0
;
if
(
is_orphaned_pgrp
(
current
->
pgrp
))
return
-
EIO
;
(
void
)
kill_pg
(
current
->
pgrp
,
SIGTTOU
,
1
);
return
-
ERESTARTSYS
;
}
static
int
set_termios
(
struct
tty_struct
*
tty
,
struct
termios
*
termios
,
int
channel
)
static
int
set_termios_2
(
struct
tty_struct
*
tty
,
struct
termios
*
termios
)
{
int
i
,
old_flow
,
new_flow
;
struct
termios
old_termios
=
*
tty
->
termios
;
int
canon_change
;
i
=
check_change
(
tty
,
channel
);
if
(
i
)
return
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
*
termios
))
;
i
++
)
((
char
*
)
tty
->
termios
)[
i
]
=
get_fs_byte
(
i
+
(
char
*
)
termios
);
canon_change
=
(
old_termios
.
c_lflag
^
termios
->
c_lflag
)
&
ICANON
;
cli
();
*
tty
->
termios
=
*
termios
;
if
(
canon_change
)
{
memset
(
&
tty
->
secondary_flags
,
0
,
sizeof
tty
->
secondary_flags
);
tty
->
canon_head
=
tty
->
secondary
.
tail
;
tty
->
canon_data
=
0
;
tty
->
erasing
=
0
;
}
sti
();
if
(
canon_change
&&
!
(
tty
->
termios
->
c_lflag
&
ICANON
)
&&
!
EMPTY
(
&
tty
->
secondary
))
/* Get characters left over from canonical mode. */
wake_up_interruptible
(
&
tty
->
secondary
.
proc_list
);
/* see if packet mode change of state */
old_flow
=
(
old_termios
.
c_iflag
&
IXON
)
&&
(
old_termios
.
c_cc
[
VSTOP
]
==
'\023'
)
&&
(
old_termios
.
c_cc
[
VSTART
]
==
'\021'
);
new_flow
=
(
tty
->
termios
->
c_iflag
&
IXON
)
&&
(
tty
->
termios
->
c_cc
[
VSTOP
]
==
'\023'
)
&&
(
tty
->
termios
->
c_cc
[
VSTART
]
==
'\021'
);
if
(
old_flow
!=
new_flow
)
{
tty
->
ctrl_status
&=
~
(
TIOCPKT_DOSTOP
|
TIOCPKT_NOSTOP
);
if
(
new_flow
)
/* The BSD man page pty.4 says that TIOCPKT_NOSTOP should be sent
if the new state differs from ^S/^Q, but that's a bad way of
detecting a new flow control scheme. Instead, a status byte
is only sent if IXON has changed. */
if
(
tty
->
link
&&
tty
->
link
->
packet
&&
(
old_termios
.
c_iflag
^
tty
->
termios
->
c_iflag
)
&
IXON
)
{
tty
->
ctrl_status
&=
~
(
TIOCPKT_DOSTOP
|
TIOCPKT_NOSTOP
);
if
(
tty
->
termios
->
c_iflag
&
IXON
)
tty
->
ctrl_status
|=
TIOCPKT_DOSTOP
;
else
tty
->
ctrl_status
|=
TIOCPKT_NOSTOP
;
if
(
tty
->
link
)
wake_up_interruptible
(
&
tty
->
link
->
except_q
);
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
}
#if 0
...
...
@@ -241,12 +237,21 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
return
0
;
}
static
int
set_termios
(
struct
tty_struct
*
tty
,
struct
termios
*
termios
,
int
channel
)
{
struct
termios
tmp_termios
;
memcpy_fromfs
(
&
tmp_termios
,
termios
,
sizeof
(
struct
termios
));
return
set_termios_2
(
tty
,
&
tmp_termios
);
}
static
int
get_termio
(
struct
tty_struct
*
tty
,
struct
termio
*
termio
)
{
int
i
;
struct
termio
tmp_termio
;
i
=
verify_area
(
VERIFY_WRITE
,
termio
,
sizeof
(
*
termio
));
i
=
verify_area
(
VERIFY_WRITE
,
termio
,
sizeof
(
struct
termio
));
if
(
i
)
return
i
;
tmp_termio
.
c_iflag
=
tty
->
termios
->
c_iflag
;
...
...
@@ -256,128 +261,41 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
tmp_termio
.
c_line
=
tty
->
termios
->
c_line
;
for
(
i
=
0
;
i
<
NCC
;
i
++
)
tmp_termio
.
c_cc
[
i
]
=
tty
->
termios
->
c_cc
[
i
];
for
(
i
=
0
;
i
<
(
sizeof
(
*
termio
))
;
i
++
)
put_fs_byte
(
((
char
*
)
&
tmp_termio
)[
i
]
,
i
+
(
char
*
)
termio
);
memcpy_tofs
(
termio
,
&
tmp_termio
,
sizeof
(
struct
termio
));
return
0
;
}
static
int
set_termio
(
struct
tty_struct
*
tty
,
struct
termio
*
termio
,
int
channel
)
{
int
i
,
old_flow
,
new_flow
;
struct
termio
tmp_termio
;
struct
termios
old_termios
=
*
tty
->
termios
;
struct
termios
tmp_
termios
;
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
tmp_termios
=
*
tty
->
termios
;
memcpy_fromfs
(
&
tmp_termio
,
termio
,
sizeof
(
struct
termio
));
i
=
check_change
(
tty
,
channel
);
if
(
i
)
return
i
;
memcpy_fromfs
(
&
tmp_termio
,
termio
,
sizeof
(
*
termio
));
SET_LOW_BITS
(
tty
->
termios
->
c_iflag
,
tmp_termio
.
c_iflag
);
SET_LOW_BITS
(
tty
->
termios
->
c_oflag
,
tmp_termio
.
c_oflag
);
SET_LOW_BITS
(
tty
->
termios
->
c_cflag
,
tmp_termio
.
c_cflag
);
SET_LOW_BITS
(
tty
->
termios
->
c_lflag
,
tmp_termio
.
c_lflag
);
memcpy
(
tty
->
termios
->
c_cc
,
tmp_termio
.
c_cc
,
NCC
);
/* see if packet mode change of state */
old_flow
=
(
old_termios
.
c_iflag
&
IXON
)
&&
(
old_termios
.
c_cc
[
VSTOP
]
==
'\023'
)
&&
(
old_termios
.
c_cc
[
VSTART
]
==
'\021'
);
new_flow
=
(
tty
->
termios
->
c_iflag
&
IXON
)
&&
(
tty
->
termios
->
c_cc
[
VSTOP
]
==
'\023'
)
&&
(
tty
->
termios
->
c_cc
[
VSTART
]
==
'\021'
);
if
(
old_flow
!=
new_flow
)
{
tty
->
ctrl_status
&=
~
(
TIOCPKT_DOSTOP
|
TIOCPKT_NOSTOP
);
if
(
new_flow
)
tty
->
ctrl_status
|=
TIOCPKT_DOSTOP
;
else
tty
->
ctrl_status
|=
TIOCPKT_NOSTOP
;
if
(
tty
->
link
)
wake_up_interruptible
(
&
tty
->
link
->
except_q
);
}
unset_locked_termios
(
tty
->
termios
,
&
old_termios
,
termios_locked
[
tty
->
line
]);
#if 0
retval = tty_set_ldisc(tty, tmp_termio.c_line);
if (retval)
return retval;
#endif
if
(
tty
->
set_termios
)
(
*
tty
->
set_termios
)(
tty
,
&
old_termios
);
return
0
;
}
static
int
get_lcktrmios
(
struct
tty_struct
*
tty
,
struct
termios
*
termios
,
int
channel
)
{
int
i
;
i
=
verify_area
(
VERIFY_WRITE
,
termios
,
sizeof
(
*
termios
));
if
(
i
)
return
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
*
termios
))
;
i
++
)
put_fs_byte
(
((
char
*
)
termios_locked
[
channel
])[
i
],
i
+
(
char
*
)
termios
);
return
0
;
}
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
static
int
set_lcktrmios
(
struct
tty_struct
*
tty
,
struct
termios
*
termios
,
int
channel
)
{
int
i
;
SET_LOW_BITS
(
tmp_termios
.
c_iflag
,
tmp_termio
.
c_iflag
);
SET_LOW_BITS
(
tmp_termios
.
c_oflag
,
tmp_termio
.
c_oflag
);
SET_LOW_BITS
(
tmp_termios
.
c_cflag
,
tmp_termio
.
c_cflag
);
SET_LOW_BITS
(
tmp_termios
.
c_lflag
,
tmp_termio
.
c_lflag
);
memcpy
(
&
tmp_termios
.
c_cc
,
&
tmp_termio
.
c_cc
,
NCC
);
if
(
!
suser
())
return
-
EPERM
;
for
(
i
=
0
;
i
<
(
sizeof
(
*
termios
))
;
i
++
)
((
char
*
)
termios_locked
[
channel
])[
i
]
=
get_fs_byte
(
i
+
(
char
*
)
termios
);
#undef SET_LOW_BITS
return
0
;
return
set_termios_2
(
tty
,
&
tmp_termios
)
;
}
static
int
set_window_size
(
struct
tty_struct
*
tty
,
struct
winsize
*
ws
)
{
int
i
,
changed
;
char
c
,
*
tmp
;
struct
winsize
tmp_ws
;
if
(
!
ws
)
return
-
EINVAL
;
tmp
=
(
char
*
)
&
tty
->
winsize
;
changed
=
0
;
for
(
i
=
0
;
i
<
sizeof
(
*
ws
)
;
i
++
,
tmp
++
)
{
c
=
get_fs_byte
(
i
+
(
char
*
)
ws
);
if
(
c
==
*
tmp
)
continue
;
changed
=
1
;
*
tmp
=
c
;
}
if
(
changed
)
memcpy_fromfs
(
&
tmp_ws
,
ws
,
sizeof
(
struct
winsize
));
if
(
memcmp
(
&
tmp_ws
,
&
tty
->
winsize
,
sizeof
(
struct
winsize
))
&&
tty
->
pgrp
>
0
)
kill_pg
(
tty
->
pgrp
,
SIGWINCH
,
1
);
return
0
;
}
static
int
get_window_size
(
struct
tty_struct
*
tty
,
struct
winsize
*
ws
)
{
int
i
;
char
*
tmp
;
if
(
!
ws
)
return
-
EINVAL
;
i
=
verify_area
(
VERIFY_WRITE
,
ws
,
sizeof
(
*
ws
));
if
(
i
)
return
i
;
tmp
=
(
char
*
)
ws
;
for
(
i
=
0
;
i
<
sizeof
(
struct
winsize
)
;
i
++
,
tmp
++
)
put_fs_byte
(((
char
*
)
&
tty
->
winsize
)[
i
],
tmp
);
tty
->
winsize
=
tmp_ws
;
return
0
;
}
...
...
@@ -406,20 +324,19 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return
0
;
}
static
int
inq_canon
(
struct
tty_struct
*
tty
)
static
unsigned
long
inq_canon
(
struct
tty_struct
*
tty
)
{
int
nr
,
head
,
tail
;
if
(
!
tty
->
secondary
.
data
)
if
(
!
tty
->
canon_
data
)
return
0
;
head
=
tty
->
secondary
.
head
;
head
=
tty
->
canon_
head
;
tail
=
tty
->
secondary
.
tail
;
nr
=
(
head
-
tail
)
&
(
TTY_BUF_SIZE
-
1
);
/* Skip EOF-chars.. */
if
(
EOF_CHAR
(
tty
)
==
__DISABLED_CHAR
)
return
nr
;
while
(
head
!=
tail
)
{
if
(
tty
->
secondary
.
buf
[
tail
]
==
EOF_CHAR
(
tty
))
if
(
test_bit
(
tail
,
&
tty
->
secondary_flags
)
&&
tty
->
secondary
.
buf
[
tail
]
==
__DISABLED_CHAR
)
nr
--
;
INC
(
tail
);
}
...
...
@@ -432,7 +349,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
struct
tty_struct
*
tty
;
struct
tty_struct
*
other_tty
;
struct
tty_struct
*
termios_tty
;
in
t
pgrp
;
pid_
t
pgrp
;
int
dev
;
int
termios_dev
;
int
retval
;
...
...
@@ -449,68 +366,93 @@ int tty_ioctl(struct inode * inode, struct file * file,
other_tty
=
tty_table
[
PTY_OTHER
(
dev
)];
else
other_tty
=
NULL
;
termios_tty
=
tty
;
termios_dev
=
dev
;
if
(
IS_A_PTY_MASTER
(
dev
))
{
termios_tty
=
other_tty
;
termios_dev
=
PTY_OTHER
(
dev
);
}
else
{
termios_tty
=
tty
;
termios_dev
=
dev
;
}
switch
(
cmd
)
{
case
TCGETS
:
return
get_termios
(
termios_tty
,(
struct
termios
*
)
arg
);
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
termios
));
if
(
retval
)
return
retval
;
memcpy_tofs
((
struct
termios
*
)
arg
,
termios_tty
->
termios
,
sizeof
(
struct
termios
));
return
0
;
case
TCSETSF
:
flush_input
(
tty
);
/* fallthrough */
case
TCSETSW
:
wait_until_sent
(
tty
);
/* fallthrough */
case
TCSETS
:
return
set_termios
(
termios_tty
,(
struct
termios
*
)
arg
,
termios_dev
);
retval
=
check_change
(
termios_tty
,
termios_dev
);
if
(
retval
)
return
retval
;
if
(
cmd
==
TCSETSF
||
cmd
==
TCSETSW
)
{
if
(
cmd
==
TCSETSF
)
flush_input
(
tty
);
wait_until_sent
(
tty
);
}
return
set_termios
(
termios_tty
,
(
struct
termios
*
)
arg
,
termios_dev
);
case
TCGETA
:
return
get_termio
(
termios_tty
,(
struct
termio
*
)
arg
);
case
TCSETAF
:
flush_input
(
tty
);
/* fallthrough */
case
TCSETAW
:
wait_until_sent
(
tty
);
/* fallthrough */
case
TCSETA
:
return
set_termio
(
termios_tty
,(
struct
termio
*
)
arg
,
termios_dev
);
retval
=
check_change
(
termios_tty
,
termios_dev
);
if
(
retval
)
return
retval
;
if
(
cmd
==
TCSETAF
||
cmd
==
TCSETAW
)
{
if
(
cmd
==
TCSETAF
)
flush_input
(
tty
);
wait_until_sent
(
tty
);
}
return
set_termio
(
termios_tty
,
(
struct
termio
*
)
arg
,
termios_dev
);
case
TCXONC
:
retval
=
check_change
(
tty
,
dev
);
if
(
retval
)
return
retval
;
switch
(
arg
)
{
case
TCOOFF
:
tty
->
stopped
=
1
;
if
(
tty
->
stop
)
(
tty
->
stop
)(
tty
);
TTY_WRITE_FLUSH
(
tty
);
return
0
;
stop_tty
(
tty
);
break
;
case
TCOON
:
tty
->
stopped
=
0
;
if
(
tty
->
start
)
(
tty
->
start
)(
tty
);
TTY_WRITE_FLUSH
(
tty
);
return
0
;
start_tty
(
tty
);
break
;
case
TCIOFF
:
if
(
STOP_CHAR
(
tty
))
if
(
STOP_CHAR
(
tty
)
!=
__DISABLED_CHAR
)
put_tty_queue
(
STOP_CHAR
(
tty
),
&
tty
->
write_q
);
return
0
;
break
;
case
TCION
:
if
(
START_CHAR
(
tty
))
if
(
START_CHAR
(
tty
)
!=
__DISABLED_CHAR
)
put_tty_queue
(
START_CHAR
(
tty
),
&
tty
->
write_q
);
return
0
;
break
;
default:
return
-
EINVAL
;
}
return
-
EINVAL
;
/* not implemented */
return
0
;
case
TCFLSH
:
if
(
arg
==
0
)
retval
=
check_change
(
tty
,
dev
);
if
(
retval
)
return
retval
;
switch
(
arg
)
{
case
TCIFLUSH
:
flush_input
(
tty
);
else
if
(
arg
==
1
)
flush_output
(
tty
);
else
if
(
arg
==
2
)
{
break
;
case
TCIOFLUSH
:
flush_input
(
tty
);
/* fall through */
case
TCOFLUSH
:
flush_output
(
tty
);
}
else
break
;
default:
return
-
EINVAL
;
}
return
0
;
case
TIOCEXCL
:
set_bit
(
TTY_EXCLUSIVE
,
&
tty
->
flags
);
...
...
@@ -550,16 +492,21 @@ int tty_ioctl(struct inode * inode, struct file * file,
tty
->
pgrp
=
current
->
pgrp
;
return
0
;
case
TIOCGPGRP
:
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
4
);
if
(
!
retval
)
put_fs_long
(
termios_tty
->
pgrp
,(
unsigned
long
*
)
arg
);
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
pid_t
));
if
(
retval
)
return
retval
;
put_fs_long
(
termios_tty
->
pgrp
,
(
pid_t
*
)
arg
);
return
0
;
case
TIOCSPGRP
:
retval
=
check_change
(
tty
,
dev
);
if
(
retval
)
return
retval
;
if
((
current
->
tty
<
0
)
||
(
current
->
tty
!=
termios_dev
)
||
(
termios_tty
->
session
!=
current
->
session
))
return
-
ENOTTY
;
pgrp
=
get_fs_long
((
unsigned
long
*
)
arg
);
pgrp
=
get_fs_long
((
pid_t
*
)
arg
);
if
(
pgrp
<
0
)
return
-
EINVAL
;
if
(
session_of_pgrp
(
pgrp
)
!=
current
->
session
)
...
...
@@ -567,16 +514,19 @@ int tty_ioctl(struct inode * inode, struct file * file,
termios_tty
->
pgrp
=
pgrp
;
return
0
;
case
TIOCOUTQ
:
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
4
);
if
(
!
retval
)
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
unsigned
long
));
if
(
retval
)
return
retval
;
put_fs_long
(
CHARS
(
&
tty
->
write_q
),
(
unsigned
long
*
)
arg
);
return
retval
;
return
0
;
case
TIOCINQ
:
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
4
);
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
unsigned
long
));
if
(
retval
)
return
retval
;
if
(
L_CANON
(
tty
))
if
(
L_
I
CANON
(
tty
))
put_fs_long
(
inq_canon
(
tty
),
(
unsigned
long
*
)
arg
);
else
...
...
@@ -587,17 +537,20 @@ int tty_ioctl(struct inode * inode, struct file * file,
if
((
current
->
tty
!=
dev
)
&&
!
suser
())
return
-
EACCES
;
put_tty_queue
(
get_fs_byte
((
char
*
)
arg
),
&
tty
->
read_q
);
TTY_READ_FLUSH
(
tty
);
return
0
;
case
TIOCGWINSZ
:
return
get_window_size
(
tty
,(
struct
winsize
*
)
arg
);
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
winsize
));
if
(
retval
)
return
retval
;
memcpy_tofs
((
struct
winsize
*
)
arg
,
&
tty
->
winsize
,
sizeof
(
struct
winsize
));
return
0
;
case
TIOCSWINSZ
:
if
(
IS_A_PTY_MASTER
(
dev
))
set_window_size
(
other_tty
,(
struct
winsize
*
)
arg
);
return
set_window_size
(
tty
,(
struct
winsize
*
)
arg
);
case
TIOCGSOFTCAR
:
return
-
EINVAL
;
/* not implemented */
case
TIOCSSOFTCAR
:
return
-
EINVAL
;
/* not implemented */
case
TIOCLINUX
:
switch
(
get_fs_byte
((
char
*
)
arg
))
{
...
...
@@ -647,31 +600,55 @@ int tty_ioctl(struct inode * inode, struct file * file,
current
->
tty
=
-
1
;
return
0
;
case
TIOCGETD
:
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
4
);
if
(
!
retval
)
put_fs_long
(
tty
->
disc
,
(
unsigned
long
*
)
arg
);
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
unsigned
long
));
if
(
retval
)
return
retval
;
put_fs_long
(
tty
->
disc
,
(
unsigned
long
*
)
arg
);
return
0
;
case
TIOCSETD
:
retval
=
check_change
(
tty
,
dev
);
if
(
retval
)
return
retval
;
arg
=
get_fs_long
((
unsigned
long
*
)
arg
);
return
tty_set_ldisc
(
tty
,
arg
);
case
TIOCGLCKTRMIOS
:
arg
=
get_fs_long
((
unsigned
long
*
)
arg
);
return
get_lcktrmios
(
tty
,
(
struct
termios
*
)
arg
,
termios_dev
);
retval
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
termios
));
if
(
retval
)
return
retval
;
memcpy_tofs
((
struct
termios
*
)
arg
,
&
termios_locked
[
termios_dev
],
sizeof
(
struct
termios
));
return
0
;
case
TIOCSLCKTRMIOS
:
if
(
!
suser
())
return
-
EPERM
;
arg
=
get_fs_long
((
unsigned
long
*
)
arg
);
return
set_lcktrmios
(
tty
,
(
struct
termios
*
)
arg
,
termios_dev
);
memcpy_fromfs
(
&
termios_locked
[
termios_dev
],
(
struct
termios
*
)
arg
,
sizeof
(
struct
termios
));
return
0
;
case
TIOCPKT
:
if
(
!
IS_A_PTY_MASTER
(
dev
))
return
-
EINVAL
;
retval
=
verify_area
(
VERIFY_READ
,
(
unsigned
long
*
)
arg
,
sizeof
(
unsigned
long
));
retval
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
unsigned
long
));
if
(
retval
)
return
retval
;
tty
->
packet
=
(
get_fs_long
((
unsigned
long
*
)
arg
)
!=
0
);
if
(
get_fs_long
(
arg
))
{
if
(
!
tty
->
packet
)
{
tty
->
packet
=
1
;
tty
->
ctrl_status
=
0
;
}
}
else
tty
->
packet
=
0
;
return
0
;
case
TCSBRK
:
case
TCSBRKP
:
retval
=
check_change
(
tty
,
dev
);
if
(
retval
)
return
retval
;
wait_until_sent
(
tty
);
if
(
!
tty
->
ioctl
)
return
0
;
...
...
drivers/net/8390.c
View file @
b168ffdf
...
...
@@ -36,7 +36,6 @@ static char *version =
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
...
...
drivers/net/lance.c
View file @
b168ffdf
...
...
@@ -563,8 +563,12 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
if
(
skb
->
free
)
kfree_skb
(
skb
,
FREE_WRITE
);
}
else
{
/* Gimme!!! */
if
(
skb
->
free
==
0
)
skb_kept_by_device
(
skb
);
lp
->
tx_ring
[
entry
].
base
=
(
int
)(
skb
+
1
)
|
0x83000000
;
}
lp
->
cur_tx
++
;
/* Trigger an immediate send poll. */
...
...
@@ -648,6 +652,9 @@ lance_interrupt(int reg_ptr)
struct
sk_buff
*
skb
=
((
struct
sk_buff
*
)
databuff
)
-
1
;
if
(
skb
->
free
)
kfree_skb
(
skb
,
FREE_WRITE
);
else
skb_device_release
(
skb
,
FREE_WRITE
);
/* Warning: skb may well vanish at the point you call device_release! */
}
dirty_tx
++
;
}
...
...
drivers/net/slip.c
View file @
b168ffdf
...
...
@@ -31,13 +31,11 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/termios.h>
#include <linux/sockios.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/tty.h>
#include <linux/in.h>
#include "inet.h"
#include "dev.h"
...
...
fs/open.c
View file @
b168ffdf
...
...
@@ -262,6 +262,8 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
return
-
EPERM
;
if
(
IS_RDONLY
(
inode
))
return
-
EROFS
;
if
(
mode
==
(
mode_t
)
-
1
)
mode
=
inode
->
i_mode
;
inode
->
i_mode
=
(
mode
&
S_IALLUGO
)
|
(
inode
->
i_mode
&
~
S_IALLUGO
);
if
(
!
suser
()
&&
!
in_group_p
(
inode
->
i_gid
))
inode
->
i_mode
&=
~
S_ISGID
;
...
...
@@ -286,6 +288,8 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
iput
(
inode
);
return
-
EROFS
;
}
if
(
mode
==
(
mode_t
)
-
1
)
mode
=
inode
->
i_mode
;
inode
->
i_mode
=
(
mode
&
S_IALLUGO
)
|
(
inode
->
i_mode
&
~
S_IALLUGO
);
if
(
!
suser
()
&&
!
in_group_p
(
inode
->
i_gid
))
inode
->
i_mode
&=
~
S_ISGID
;
...
...
include/linux/kernel.h
View file @
b168ffdf
...
...
@@ -14,11 +14,6 @@
#define LONG_MAX ((long)(~0UL>>1))
#define ULONG_MAX (~0UL)
#define VERIFY_READ 0
#define VERIFY_WRITE 1
int
verify_area
(
int
type
,
void
*
addr
,
unsigned
long
count
);
#define KERN_EMERG "<0>"
/* system is unusable */
#define KERN_ALERT "<1>"
/* action must be taken immediately */
#define KERN_CRIT "<2>"
/* critical conditions */
...
...
include/linux/mm.h
View file @
b168ffdf
...
...
@@ -2,9 +2,26 @@
#define _LINUX_MM_H
#include <linux/page.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
int
__verify_write
(
unsigned
long
addr
,
unsigned
long
count
);
extern
inline
int
verify_area
(
int
type
,
void
*
addr
,
unsigned
long
size
)
{
if
(
TASK_SIZE
<=
(
unsigned
long
)
addr
)
return
-
EFAULT
;
if
(
size
>
TASK_SIZE
-
(
unsigned
long
)
addr
)
return
-
EFAULT
;
if
(
wp_works_ok
||
type
==
VERIFY_READ
||
!
size
)
return
0
;
return
__verify_write
((
unsigned
long
)
addr
,
size
);
}
/*
* Linux kernel virtual memory manager primitives.
* The idea being to have a "virtual" mm in the same way
...
...
include/linux/sched.h
View file @
b168ffdf
...
...
@@ -13,6 +13,21 @@
#define HZ 100
/*
* System setup flags..
*/
extern
int
hard_math
;
extern
int
x86
;
extern
int
ignore_irq13
;
extern
int
wp_works_ok
;
/*
* Bus types (default is ISA, but people can check others with these..)
* MCA_bus hardcoded to 0 for now.
*/
extern
int
EISA_bus
;
#define MCA_bus 0
#include <linux/tasks.h>
#include <asm/system.h>
...
...
@@ -290,21 +305,6 @@ extern unsigned long volatile jiffies;
extern
struct
timeval
xtime
;
extern
int
need_resched
;
/*
* System setup flags..
*/
extern
int
hard_math
;
extern
int
x86
;
extern
int
ignore_irq13
;
extern
int
wp_works_ok
;
/*
* Bus types (default is ISA, but people can check others with these..)
* MCA_bus hardcoded to 0 for now.
*/
extern
int
EISA_bus
;
#define MCA_bus 0
#define CURRENT_TIME (xtime.tv_sec)
extern
void
sleep_on
(
struct
wait_queue
**
p
);
...
...
include/linux/termios.h
View file @
b168ffdf
...
...
@@ -51,6 +51,7 @@
#define TIOCSLCKTRMIOS 0x5457
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
#define TIOCPKT_FLUSHWRITE 2
#define TIOCPKT_STOP 4
...
...
include/linux/tty.h
View file @
b168ffdf
...
...
@@ -62,7 +62,6 @@ extern struct screen_info screen_info;
#define TTY_BUF_SIZE 1024
/* Must be a power of 2 */
struct
tty_queue
{
unsigned
long
data
;
unsigned
long
head
;
unsigned
long
tail
;
struct
wait_queue
*
proc_list
;
...
...
@@ -143,60 +142,88 @@ struct serial_struct {
#define FULL(a) (!LEFT(a))
#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
extern
void
put_tty_queue
(
char
c
,
struct
tty_queue
*
queue
);
extern
void
put_tty_queue
(
unsigned
char
c
,
struct
tty_queue
*
queue
);
extern
int
get_tty_queue
(
struct
tty_queue
*
queue
);
#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
#define SUSPEND_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT])
#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & f)
#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & f)
#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & f)
#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & f)
#define L_CANON(tty) _L_FLAG((tty),ICANON)
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f))
#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f))
#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f))
#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f))
#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
#define I_INPCK(tty) _I_FLAG((tty),INPCK)
#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
#define I_NLCR(tty) _I_FLAG((tty),INLCR)
#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
#define I_INLCR(tty) _I_FLAG((tty),INLCR)
#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
#define I_IXON(tty) _I_FLAG((tty),IXON)
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
#define I_STRP(tty) _I_FLAG((tty),ISTRIP)
#define O_POST(tty) _O_FLAG((tty),OPOST)
#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
#define O_NOCR(tty) _O_FLAG((tty),ONOCR)
#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
#define O_OPOST(tty) _O_FLAG((tty),OPOST)
#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
#define O_OFILL(tty) _O_FLAG((tty),OFILL)
#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
#define C_CREAD(tty) _C_FLAG((tty),CREAD)
#define C_PARENB(tty) _C_FLAG((tty),PARENB)
#define C_PARODD(tty) _C_FLAG((tty),PARODD)
#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
#define C_LOCAL(tty) _C_FLAG((tty),CLOCAL)
#define C_RTSCTS(tty) _C_FLAG((tty),CRTSCTS)
#define C_SPEED(tty) ((tty)->termios->c_cflag & CBAUD)
#define C_HUP(tty) (C_SPEED((tty)) == B0)
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ICANON(tty) _L_FLAG((tty),ICANON)
#define L_XCASE(tty) _L_FLAG((tty),XCASE)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
/*
* Where all of the state associated with a tty is kept while the tty
...
...
@@ -218,12 +245,13 @@ struct tty_struct {
int
session
;
unsigned
char
stopped
:
1
,
hw_stopped
:
1
,
packet
:
1
,
lnext
:
1
;
unsigned
char
char_error
:
3
;
unsigned
char
erasing
:
1
;
unsigned
char
ctrl_status
;
short
line
;
int
disc
;
int
flags
;
int
count
;
int
column
;
unsigned
int
column
;
struct
winsize
winsize
;
int
(
*
open
)(
struct
tty_struct
*
tty
,
struct
file
*
filp
);
void
(
*
close
)(
struct
tty_struct
*
tty
,
struct
file
*
filp
);
...
...
@@ -241,10 +269,13 @@ struct tty_struct {
void
(
*
write_data_callback
)(
void
*
data
);
void
*
write_data_arg
;
int
readq_flags
[
TTY_BUF_SIZE
/
32
];
int
secondary_flags
[
TTY_BUF_SIZE
/
32
];
int
canon_data
;
unsigned
long
canon_head
;
unsigned
int
canon_column
;
struct
tty_queue
read_q
;
struct
tty_queue
write_q
;
struct
tty_queue
secondary
;
struct
wait_queue
*
except_q
;
void
*
disc_data
;
};
...
...
@@ -256,9 +287,9 @@ struct tty_ldisc {
int
(
*
open
)(
struct
tty_struct
*
);
void
(
*
close
)(
struct
tty_struct
*
);
int
(
*
read
)(
struct
tty_struct
*
tty
,
struct
file
*
file
,
char
*
buf
,
int
nr
);
unsigned
char
*
buf
,
unsigned
int
nr
);
int
(
*
write
)(
struct
tty_struct
*
tty
,
struct
file
*
file
,
char
*
buf
,
int
nr
);
unsigned
char
*
buf
,
unsigned
int
nr
);
int
(
*
ioctl
)(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
);
int
(
*
select
)(
struct
tty_struct
*
tty
,
struct
inode
*
inode
,
...
...
@@ -313,12 +344,11 @@ struct tty_ldisc {
*/
#define TTY_WRITE_BUSY 0
#define TTY_READ_BUSY 1
#define TTY_CR_PENDING 2
#define TTY_SQ_THROTTLED 3
#define TTY_RQ_THROTTLED 4
#define TTY_IO_ERROR 5
#define TTY_SLAVE_OPENED 6
#define TTY_EXCLUSIVE 7
#define TTY_SQ_THROTTLED 2
#define TTY_RQ_THROTTLED 3
#define TTY_IO_ERROR 4
#define TTY_SLAVE_CLOSED 5
#define TTY_EXCLUSIVE 6
/*
* When a break, frame error, or parity error happens, these codes are
...
...
@@ -336,6 +366,10 @@ struct tty_ldisc {
extern
void
tty_write_flush
(
struct
tty_struct
*
);
extern
void
tty_read_flush
(
struct
tty_struct
*
);
/* Number of chars that must be available in a write queue before
the queue is awakened. */
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
extern
struct
tty_struct
*
tty_table
[];
extern
struct
termios
*
tty_termios
[];
extern
struct
termios
*
termios_locked
[];
...
...
@@ -366,7 +400,9 @@ extern long tty_init(long);
extern
void
flush_input
(
struct
tty_struct
*
tty
);
extern
void
flush_output
(
struct
tty_struct
*
tty
);
extern
void
wait_until_sent
(
struct
tty_struct
*
tty
);
extern
void
copy_to_cooked
(
struct
tty_struct
*
tty
);
extern
int
check_change
(
struct
tty_struct
*
tty
,
int
channel
);
extern
void
stop_tty
(
struct
tty_struct
*
tty
);
extern
void
start_tty
(
struct
tty_struct
*
tty
);
extern
int
tty_register_ldisc
(
int
disc
,
struct
tty_ldisc
*
new_ldisc
);
extern
int
tty_read_raw_data
(
struct
tty_struct
*
tty
,
unsigned
char
*
bufp
,
int
buflen
);
...
...
kernel/fork.c
View file @
b168ffdf
...
...
@@ -56,7 +56,8 @@ static int find_empty_process(void)
}
if
(
task
[
i
]
->
uid
==
current
->
uid
)
this_user_tasks
++
;
if
(
task
[
i
]
->
pid
==
last_pid
||
task
[
i
]
->
pgrp
==
last_pid
)
if
(
task
[
i
]
->
pid
==
last_pid
||
task
[
i
]
->
pgrp
==
last_pid
||
task
[
i
]
->
session
==
last_pid
)
goto
repeat
;
}
if
(
tasks_free
<=
MIN_TASKS_LEFT_FOR_ROOT
||
...
...
kernel/ksyms.S
View file @
b168ffdf
...
...
@@ -9,7 +9,7 @@
_register_chrdev
_unregister_chrdev
_
verify_area
_
__verify_write
_wake_up_interruptible
_current
...
...
kernel/sys.c
View file @
b168ffdf
...
...
@@ -7,7 +7,6 @@
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/times.h>
#include <linux/utsname.h>
...
...
@@ -510,7 +509,7 @@ asmlinkage int sys_getpgrp(void)
asmlinkage
int
sys_setsid
(
void
)
{
if
(
current
->
leader
&&
!
suser
()
)
if
(
current
->
leader
)
return
-
EPERM
;
current
->
leader
=
1
;
current
->
session
=
current
->
pgrp
=
current
->
pid
;
...
...
mm/memory.c
View file @
b168ffdf
...
...
@@ -651,17 +651,8 @@ void do_wp_page(unsigned long error_code, unsigned long address,
*
pg_table
=
0
;
}
int
verify_area
(
int
type
,
void
*
addr
,
unsigned
long
size
)
int
__verify_write
(
unsigned
long
start
,
unsigned
long
size
)
{
unsigned
long
start
;
start
=
(
unsigned
long
)
addr
;
if
(
start
>=
TASK_SIZE
)
return
-
EFAULT
;
if
(
size
>
TASK_SIZE
-
start
)
return
-
EFAULT
;
if
(
wp_works_ok
||
type
==
VERIFY_READ
||
!
size
)
return
0
;
size
--
;
size
+=
start
&
~
PAGE_MASK
;
size
>>=
PAGE_SHIFT
;
...
...
net/inet/ip.c
View file @
b168ffdf
...
...
@@ -1464,7 +1464,8 @@ ip_retransmit(struct sock *sk, int all)
/* If the interface is (still) up and running, kick it. */
if
(
dev
->
flags
&
IFF_UP
)
{
if
(
sk
)
dev
->
queue_xmit
(
skb
,
dev
,
sk
->
priority
);
if
(
sk
&&
!
skb_device_locked
(
skb
))
dev
->
queue_xmit
(
skb
,
dev
,
sk
->
priority
);
/* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
...
...
net/inet/skbuff.c
View file @
b168ffdf
...
...
@@ -381,6 +381,12 @@ void kfree_skb(struct sk_buff *skb, int rw)
return
;
}
IS_SKB
(
skb
);
if
(
skb
->
lock
)
{
skb
->
free
=
1
;
/* Free when unlocked */
return
;
}
if
(
skb
->
free
==
2
)
printk
(
"Warning: kfree_skb passed an skb that nobody set the free flag on!
\n
"
);
if
(
skb
->
list
)
...
...
@@ -424,6 +430,7 @@ void kfree_skb(struct sk_buff *skb, int rw)
return
NULL
;
skb
->
free
=
2
;
/* Invalid so we pick up forgetful users */
skb
->
list
=
0
;
/* Not on a list */
skb
->
lock
=
0
;
skb
->
truesize
=
size
;
skb
->
mem_len
=
size
;
skb
->
mem_addr
=
skb
;
...
...
@@ -452,3 +459,31 @@ void kfree_skbmem(void *mem,unsigned size)
}
}
/*
* Skbuff device locking
*/
void
skb_kept_by_device
(
struct
sk_buff
*
skb
)
{
skb
->
lock
++
;
}
void
skb_device_release
(
struct
sk_buff
*
skb
,
int
mode
)
{
unsigned
long
flags
;
save_flags
(
flags
);
skb
->
lock
--
;
if
(
skb
->
lock
==
0
)
{
if
(
skb
->
free
==
1
)
kfree_skb
(
skb
,
mode
);
}
restore_flags
(
flags
);
}
int
skb_device_locked
(
struct
sk_buff
*
skb
)
{
if
(
skb
->
lock
)
return
1
;
return
0
;
}
net/inet/skbuff.h
View file @
b168ffdf
...
...
@@ -99,7 +99,9 @@ extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
extern
struct
sk_buff
*
skb_peek_copy
(
struct
sk_buff
*
volatile
*
list
);
extern
struct
sk_buff
*
alloc_skb
(
unsigned
int
size
,
int
priority
);
extern
void
kfree_skbmem
(
void
*
mem
,
unsigned
size
);
extern
void
skb_kept_by_device
(
struct
sk_buff
*
skb
);
extern
void
skb_device_release
(
struct
sk_buff
*
skb
,
int
mode
);
extern
int
skb_device_locked
(
struct
sk_buff
*
skb
);
extern
void
skb_check
(
struct
sk_buff
*
skb
,
int
,
char
*
);
#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
...
...
net/inet/tcp.c
View file @
b168ffdf
...
...
@@ -583,8 +583,7 @@ tcp_check(struct tcphdr *th, int len,
}
void
tcp_send_check
(
struct
tcphdr
*
th
,
unsigned
long
saddr
,
void
tcp_send_check
(
struct
tcphdr
*
th
,
unsigned
long
saddr
,
unsigned
long
daddr
,
int
len
,
struct
sock
*
sk
)
{
th
->
check
=
0
;
...
...
@@ -592,55 +591,33 @@ tcp_send_check(struct tcphdr *th, unsigned long saddr,
return
;
}
static
struct
sk_buff
*
dequeue_partial
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
skb
=
sk
->
send_tmp
;
if
(
skb
)
{
sk
->
send_tmp
=
skb
->
next
;
skb
->
next
=
NULL
;
}
restore_flags
(
flags
);
return
skb
;
}
static
void
enqueue_partial
(
struct
sk_buff
*
skb
,
struct
sock
*
sk
)
static
void
tcp_send_skb
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
unsigned
long
flags
;
int
size
;
save_flags
(
flags
);
cli
();
skb
->
next
=
sk
->
send_tmp
;
sk
->
send_tmp
=
skb
;
restore_flags
(
flags
);
}
/* length of packet (not counting length of pre-tcp headers) */
size
=
skb
->
len
-
((
unsigned
char
*
)
skb
->
h
.
th
-
skb
->
data
);
static
void
tcp_send_partial
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
if
(
sk
==
NULL
)
/* sanity check it.. */
if
(
size
<
sizeof
(
struct
tcphdr
)
||
size
>
skb
->
len
)
{
printk
(
"tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)
\n
"
,
skb
,
skb
->
data
,
skb
->
h
.
th
,
skb
->
len
);
kfree_skb
(
skb
,
FREE_WRITE
);
return
;
while
((
skb
=
dequeue_partial
(
sk
))
!=
NULL
)
{
}
/* If we have queued a header size packet.. */
if
(
skb
->
len
-
(
unsigned
long
)
skb
->
h
.
th
+
(
unsigned
long
)
skb
->
data
==
sizeof
(
struct
tcphdr
))
{
if
(
size
==
sizeof
(
struct
tcphdr
))
{
/* If its got a syn or fin its notionally included in the size..*/
if
(
!
skb
->
h
.
th
->
syn
&&
!
skb
->
h
.
th
->
fin
)
{
printk
(
"tcp_send_
partial
: attempt to queue a bogon.
\n
"
);
printk
(
"tcp_send_
skb
: attempt to queue a bogon.
\n
"
);
kfree_skb
(
skb
,
FREE_WRITE
);
return
;
}
}
/* We need to complete and send the packet. */
tcp_send_check
(
skb
->
h
.
th
,
sk
->
saddr
,
sk
->
daddr
,
skb
->
len
-
(
unsigned
long
)
skb
->
h
.
th
+
(
unsigned
long
)
skb
->
data
,
sk
);
tcp_send_check
(
skb
->
h
.
th
,
sk
->
saddr
,
sk
->
daddr
,
size
,
sk
);
skb
->
h
.
seq
=
sk
->
send_seq
;
if
(
after
(
sk
->
send_seq
,
sk
->
window_seq
)
||
...
...
@@ -664,9 +641,49 @@ static void tcp_send_partial(struct sock *sk)
reset_timer
(
sk
,
TIME_PROBE0
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
}
else
{
sk
->
prot
->
queue_xmit
(
sk
,
skb
->
dev
,
skb
,
0
);
sk
->
prot
->
queue_xmit
(
sk
,
skb
->
dev
,
skb
,
0
);
}
}
static
struct
sk_buff
*
dequeue_partial
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
skb
=
sk
->
send_tmp
;
if
(
skb
)
{
sk
->
send_tmp
=
skb
->
next
;
skb
->
next
=
NULL
;
}
restore_flags
(
flags
);
return
skb
;
}
static
void
enqueue_partial
(
struct
sk_buff
*
skb
,
struct
sock
*
sk
)
{
struct
sk_buff
*
tmp
;
unsigned
long
flags
;
skb
->
next
=
NULL
;
save_flags
(
flags
);
cli
();
tmp
=
sk
->
send_tmp
;
sk
->
send_tmp
=
skb
;
restore_flags
(
flags
);
if
(
tmp
)
tcp_send_skb
(
sk
,
tmp
);
}
static
void
tcp_send_partial
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
if
(
sk
==
NULL
)
return
;
while
((
skb
=
dequeue_partial
(
sk
))
!=
NULL
)
tcp_send_skb
(
sk
,
skb
);
}
...
...
@@ -901,6 +918,7 @@ tcp_write(struct sock *sk, unsigned char *from,
continue
;
}
#if 0
/*
* We also need to worry about the window.
* If window < 1/4 offered window, don't use it. That's
...
...
@@ -915,6 +933,10 @@ tcp_write(struct sock *sk, unsigned char *from,
copy = sk->mtu;
copy = min(copy, sk->mtu);
copy = min(copy, len);
#else
/* This also prevents silly windows by simply ignoring the offered window.. */
copy
=
min
(
sk
->
mtu
,
len
);
#endif
/* We should really check the window here also. */
if
(
sk
->
packets_out
&&
copy
<
sk
->
mtu
&&
!
(
flags
&
MSG_OOB
))
{
...
...
@@ -1011,34 +1033,7 @@ tcp_write(struct sock *sk, unsigned char *from,
enqueue_partial
(
send_tmp
,
sk
);
continue
;
}
tcp_send_check
((
struct
tcphdr
*
)
buff
,
sk
->
saddr
,
sk
->
daddr
,
copy
+
sizeof
(
struct
tcphdr
),
sk
);
skb
->
h
.
seq
=
sk
->
send_seq
;
if
(
after
(
sk
->
send_seq
,
sk
->
window_seq
)
||
(
sk
->
retransmits
&&
sk
->
timeout
==
TIME_WRITE
)
||
sk
->
packets_out
>=
sk
->
cong_window
)
{
DPRINTF
((
DBG_TCP
,
"sk->cong_window = %d, sk->packets_out = %d
\n
"
,
sk
->
cong_window
,
sk
->
packets_out
));
DPRINTF
((
DBG_TCP
,
"sk->send_seq = %d, sk->window_seq = %d
\n
"
,
sk
->
send_seq
,
sk
->
window_seq
));
skb
->
next
=
NULL
;
skb
->
magic
=
TCP_WRITE_QUEUE_MAGIC
;
if
(
sk
->
wback
==
NULL
)
{
sk
->
wfront
=
skb
;
}
else
{
sk
->
wback
->
next
=
skb
;
}
sk
->
wback
=
skb
;
if
(
before
(
sk
->
window_seq
,
sk
->
wfront
->
h
.
seq
)
&&
sk
->
send_head
==
NULL
&&
sk
->
ack_backlog
==
0
)
reset_timer
(
sk
,
TIME_PROBE0
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
}
else
{
prot
->
queue_xmit
(
sk
,
dev
,
skb
,
0
);
}
tcp_send_skb
(
sk
,
skb
);
}
sk
->
err
=
0
;
...
...
@@ -3604,7 +3599,7 @@ tcp_send_probe0(struct sock *sk)
len
=
hlen
+
sizeof
(
struct
tcphdr
)
+
(
data
?
1
:
0
);
/* Allocate buffer. */
if
((
skb2
=
alloc_skb
(
sizeof
(
struct
sk_buff
)
+
len
,
GFP_KERNEL
))
==
NULL
)
{
if
((
skb2
=
alloc_skb
(
sizeof
(
struct
sk_buff
)
+
len
,
GFP_ATOMIC
))
==
NULL
)
{
/* printk("alloc failed raw %x th %x hlen %d data %d len %d\n",
raw, skb->h.th, hlen, data, len); */
reset_timer
(
sk
,
TIME_PROBE0
,
10
);
/* try again real soon */
...
...
net/socket.c
View file @
b168ffdf
...
...
@@ -28,7 +28,6 @@
#include <linux/stat.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
#include <linux/net.h>
#include <linux/ddi.h>
...
...
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