]> git.neil.brown.name Git - history.git/commitdiff
Import 0.99.14v 0.99.14v
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:20 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:20 +0000 (15:09 -0500)
37 files changed:
Makefile
drivers/FPU-emu/errors.c
drivers/FPU-emu/fpu_emu.h
drivers/FPU-emu/fpu_entry.c
drivers/FPU-emu/fpu_system.h
drivers/FPU-emu/get_address.c
drivers/FPU-emu/load_store.c
drivers/FPU-emu/poly_sin.c
drivers/FPU-emu/reg_ld_str.c
drivers/FPU-emu/version.h
drivers/char/atixlmouse.c
drivers/char/busmouse.c
drivers/char/console.c
drivers/char/keyboard.c
drivers/char/msbusmouse.c
drivers/char/pty.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/net/8390.c
drivers/net/lance.c
drivers/net/slip.c
fs/open.c
include/linux/kernel.h
include/linux/mm.h
include/linux/sched.h
include/linux/termios.h
include/linux/tty.h
kernel/fork.c
kernel/ksyms.S
kernel/sys.c
mm/memory.c
net/inet/ip.c
net/inet/skbuff.c
net/inet/skbuff.h
net/inet/tcp.c
net/socket.c

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