Commit b168ffdf authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14v

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