]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.61 1.1.61
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:43 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:43 +0000 (15:09 -0500)
42 files changed:
CREDITS
Makefile
drivers/block/README.sbpcd
drivers/block/cdu31a.c
drivers/block/floppy.c
drivers/block/mcd.c
drivers/block/sbpcd.c
drivers/char/tpqic02.c
drivers/net/CONFIG
drivers/net/Makefile
drivers/net/README.ewrk3 [new file with mode: 0644]
drivers/net/Space.c
drivers/net/ewrk3.c [new file with mode: 0644]
drivers/net/ewrk3.h [new file with mode: 0644]
fs/block_dev.c
fs/minix/inode.c
fs/msdos/fat.c
fs/msdos/file.c
fs/msdos/inode.c
fs/msdos/misc.c
fs/read_write.c
fs/umsdos/inode.c
fs/xiafs/bitmap.c
include/linux/cdrom.h
include/linux/ipc.h
include/linux/msdos_fs.h
include/linux/msg.h
include/linux/sched.h
include/linux/sem.h
include/linux/shm.h
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
kernel/exit.c
kernel/ksyms.c
mm/memory.c
net/inet/af_inet.c
net/inet/ip.c
net/inet/proc.c
net/inet/route.c
net/inet/tcp.c

diff --git a/CREDITS b/CREDITS
index 6d06f3777b8ec3116937e0915c066e73d3c12248..c31d9c853985f6930f8fffa210470243dd32c7fe 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -64,7 +64,7 @@ S: 6369 BG Simpelveld
 S: The Netherlands
 
 N: Hennus Bergman
-E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home]
+E: hennus@sky.ow.org [My uucp-fed Linux box at home]
 D: Author and maintainer of the QIC-02 tape driver
 S: The Netherlands
 
index b01ddd01d706b74dd4fb1748267f7bca687c108c..ef29c2ef79d70925e770de8c10f1c96c80f3d750 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 60
+SUBLEVEL = 61
 
 ARCH = i386
 
index 371072a46834ca8c0ad9694912309e3d2f371972..8bfb26e5f74c4dc0c9e3bcb03e09e390710f3912 100644 (file)
@@ -1,4 +1,4 @@
-This README belongs to release 2.6 or newer of the SoundBlaster Pro
+This README belongs to release 2.7 or newer of the SoundBlaster Pro
 (Matsushita, Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
 
 The driver is able to drive the whole family of "traditional" IDE-style (that
@@ -6,6 +6,14 @@ has nothing to do with the new "Enhanced IDE" drive standard) Matsushita,
 Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The
 well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563.
 
+There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-562
+with a special controller board. This drive is supported (the interface is
+of the "LaserMate" type), and it is possibly the best buy today (cheaper than
+an internal drive, and you can use it as an internal, too - f.e. plug it into
+a soundcard). If you own such a drive, please mail me the DOS driver (gzipped
+and uuencoded) and the specifications (exact name, address range etc.) I still
+have to confirm my opinion. ;-)
+
 This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives.
 The matter that some other brand's drives work with newer sound card
 interfaces does NOT make the drives compatible. :-)
@@ -49,8 +57,8 @@ to change old drives to any ID, too. He writes in this sense:
 
 To use more than 4 drives (now that the single-speed CR-521's are as cheap as
 50$), you need a second interface card and you have to "duplicate" the driver.
-Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE
-accordingly.
+Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE (at top
+of sbpcd2.c) accordingly.
 
 The driver supports reading of data from the CD and playing of audio tracks.
 The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
@@ -72,9 +80,10 @@ the beginning of each single frame.
 The software interface possibly may change a bit the day the SCSI driver
 supports it too.
 
-MultiSession is supported, "ManySession" (not recommended, see below)
-alternatively.
-Photo CDs work, too (even with my "old" CR-521).
+With the CR-562 and CR-563 drives, MultiSession is supported, "ManySession"
+(not recommended, see below) alternatively.
+Photo CDs work, too (the "old" drives like CR-521 can access only the first
+session of a photoCD).
 At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
 photo CD image files.
 
@@ -189,6 +198,57 @@ distribution) which MUST get handled with a block_size of 1024. Generally,
 one can say all the CDs which hold files of the name YMTRANS.TBL are defective;
 do not use block=2048 with those.
 
+At the beginning of sbpcd.c, you will find some "#define"s (f.e. EJECT and
+JUKEBOX). With that, you can configure the driver for some special things.
+The following program disables the auto-eject feature during runtime:
+
+/*=================== begin program ========================================*/
+/*
+ * set the "eject" switch (enable/disable auto-ejecting)
+ *
+ * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
+ *          may be used & enhanced freely
+ *
+ * Disables or enables the auto-eject feature at run time.
+ * Works only if a CD is in the drive (just like the feature itself ;-) 
+ * Useful for a "quiet" shutdown or for weird audio player programs.
+ */
+#define EJECT 0 /* 0: disable, 1: enable auto-ejecting */
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+
+static char arg=EJECT;
+static int drive;
+static int err;
+
+main(int argc, char *argv[])
+{
+/*
+ * open /dev/cdrom
+ */
+  drive=open("/dev/cdrom", 0);
+  if (drive<0)
+    {
+      fprintf(stderr, "can't open drive /dev/cdrom.\n");
+      exit (-1);
+    }
+/*
+ * set EJECT_SW
+ */
+  err=ioctl(drive, CDROMEJECT_SW, arg);
+  if (err!=0)
+    {
+      fprintf(stderr, "can't set EJECT_SW (error %d).\n", err);
+      exit (-1);
+    }
+  else
+    fprintf(stdout, "EJECT_SW set to %d\n", arg);
+}
+/*===================== end program ========================================*/
+
+
 
 Auto-probing at boot time:
 --------------------------
index 5b353b28453c19a411e4556a9bdf9e4f0101af2e..eea03cf6f9b794d74e8335f726576836ac5541e1 100644 (file)
@@ -2856,8 +2856,8 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
       {
         if (request_irq(irq_used, cdu31a_interrupt, SA_INTERRUPT, "cdu31a"))
         {
-           irq_used = 0;
            printk("Unable to grab IRQ%d for the CDU31A driver\n", irq_used);
+           irq_used = 0;
         }
       }
       
index c9a48e6cdd1506c2be3b5d3354638fc45482e381..26f91348fd96c1093af646da9ce46223bbfe03d9 100644 (file)
@@ -348,6 +348,7 @@ struct floppy_struct *current_type[N_DRIVE] = {
 struct floppy_struct user_params[N_DRIVE];
 
 static int floppy_sizes[256];
+static int floppy_blocksizes[256] = { 0, };
 
 /*
  * The driver is trying to determine the correct media format
@@ -2848,7 +2849,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
        if (floppy_grab_irq_and_dma())
                return -EBUSY;
 
-       if(filp->f_flags & O_EXCL)
+       if (filp->f_flags & O_EXCL)
                UDRS->fd_ref = -1;
        else
                UDRS->fd_ref++;
@@ -2956,7 +2957,10 @@ static int floppy_revalidate(dev_t dev)
                        UDRS->generation++;
                        if(!current_type[drive] && !TYPE(dev)){
                                /* auto-sensing */
-                               if (!(bh = getblk(dev,0,1024))){
+                               int size = floppy_blocksizes[MINOR(dev)];
+                               if (!size)
+                                       size = 1024;
+                               if (!(bh = getblk(dev,0,size))){
                                        redo_fd_request();
                                        return 1;
                                }
@@ -3062,6 +3066,7 @@ void floppy_init(void)
                        floppy_sizes[i] = MAX_DISK_SIZE;
 
        blk_size[MAJOR_NR] = floppy_sizes;
+       blksize_size[MAJOR_NR] = floppy_blocksizes;
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
        timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
        timer_active &= ~(1 << FLOPPY_TIMER);
index b661dfed67481c6078c89bfe9c0f3090be3b1788..42dab90619683990da3e72f18887ed0ccd9389e9 100644 (file)
@@ -1182,7 +1182,6 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
 
        mcd_invalidate_buffers();
        mcdPresent = 1;
-       printk("\n");
        return mem_start;
 }
 
index b3ee220a68ee1c32782b3b679c670cd21c21f5ce..f6075a9ad29031241d94576c96e7933d059a235e 100644 (file)
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 2.6.
+ *  NOTE:     This is release 2.7.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
  *
  *  2.6  Nothing new.  
  *       
+ *  2.7  Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly:
+ *       0 disables, 1 enables auto-ejecting. Useful to keep the tray in
+ *       during shutdown.
+ *       
  *  TODO
  *
  *     disk change detection
 
 #include "blk.h"
 
-#define VERSION "2.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "2.7 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
@@ -303,6 +307,9 @@ static int autoprobe[] =
   0x320, 2, /* SPEA Media FX */
   0x340, 2, /* SPEA Media FX */
   0x350, 2, /* SPEA Media FX */
+/* due to incomplete address decoding of the SbPro card, these must be last */
+  0x630, 0, /* "sound card #9" (default) */
+  0x650, 0, /* "sound card #9" */
 #if 0
 /* some "hazardous" locations (ethernet cards) */
   0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
@@ -310,9 +317,6 @@ static int autoprobe[] =
   0x370, 0, /* Lasermate, CI-101P */
   0x290, 1, /* Soundblaster 16 */
   0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
-/* excluded due to incomplete address decoding of the SbPro card */
-  0x630, 0, /* "sound card #9" (default) */
-  0x650, 0, /* "sound card #9" */
 #endif
 };
 
@@ -390,6 +394,7 @@ static int sbpcd_debug =  (1<<DBG_INF) |
 #else
 static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_TOC) |
+                          (1<<DBG_MUL) |
                           (1<<DBG_UPC);
 #endif
 #endif
@@ -481,6 +486,7 @@ static struct {
 
   char drive_model[4];
   char firmware_version[4];
+  char f_eject; /* auto-eject flag: 0 or 1 */
   u_char *sbp_buf; /* Pointer to internal data buffer,
                            space allocated during sbpcd_init() */
   int sbp_first_frame;  /* First frame in buffer */
@@ -2390,7 +2396,7 @@ static int sbp_status(void)
 /*==========================================================================*/
 /*==========================================================================*/
 /*
- * ioctl support, adopted from scsi/sr_ioctl.c and mcd.c
+ * ioctl support
  */
 static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                       u_long arg)
@@ -2583,6 +2589,12 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
       DriveStruct[d].audio_state=0;
       return (0);
       
+    case CDROMEJECT_SW:
+      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT_SW entered.\n"));
+      if (!new_drive) return (0);
+      DriveStruct[d].f_eject=arg;
+      return (0);
+      
     case CDROMVOLCTRL:   /* Volume control */
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n"));
       st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
@@ -2918,7 +2930,9 @@ request_loop:
     }
 
   DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect));
+#if 0
   DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
+#endif
 
   sbp_transfer();
   /* if we satisfied the request from the buffer, we're done. */
@@ -3007,7 +3021,7 @@ static void sbp_read_cmd(void)
          DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
                         blk2msf(DriveStruct[d].lba_multi+16),
                          blk2msf(block)));
-         block=DriveStruct[d].lba_multi+16;
+         block=DriveStruct[d].lba_multi+block;
        }
 #endif MANY_SESSION
     }
@@ -3323,9 +3337,7 @@ static void sbpcd_release(struct inode * ip, struct file * file)
          do
            i=yy_LockDoor(0);
          while (i!=0);
-#if EJECT
-         if (new_drive) yy_SpinDown();
-#endif
+         if (DriveStruct[d].f_eject) yy_SpinDown();
        }
     }
 }
@@ -3550,6 +3562,12 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
       DriveStruct[d].sbp_current = 0;       /* Frame being currently read */
       DriveStruct[d].CD_changed=1;
       DriveStruct[d].frame_size=CD_FRAMESIZE;
+#if EJECT
+      if (new_drive) DriveStruct[d].f_eject=1;
+      else DriveStruct[d].f_eject=0;
+#else
+      DriveStruct[d].f_eject=0;
+#endif
 
       xx_ReadStatus();
       i=ResponseStatus();  /* returns orig. status or p_busy_new */
index 34c732f870ede559e8918a621f16f611bf86be63..ac717b6a66e406648bb5e64a419236a29fd615fd 100644 (file)
@@ -1,10 +1,9 @@
-/* $Id: tpqic02.c,v 0.4.1.4 1994/07/21 02:15:45 root Exp root $
+/* $Id: tpqic02.c,v 0.4.1.5 1994/10/29 02:46:13 root Exp root $
  *
- * Driver for tape drive support for Linux-i386 1.1.30
+ * Driver for tape drive support for Linux-i386 1.1.58
  *
  * Copyright (c) 1992, 1993, 1994 by H. H. Bergman. All rights reserved.
- * Current e-mail address: hennus@sky.nl.mugnet.org [This is a UUCP link.]
- * Secondary e-mail address: csg279@wing.rug.nl [IP connected, but flaky]
+ * Current e-mail address: hennus@sky.ow.org [This is a UUCP link.]
  * [If you are unable to reach me directly, try the TAPE mailing list
  * channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as
  * the first line in your message.]
@@ -35,6 +34,9 @@
  * You are not allowed to change this line nor the text above.
  *
  * $Log: tpqic02.c,v $
+ * Revision 0.4.1.5  1994/10/29  02:46:13  root
+ * Minor cleanups.
+ *
  * Revision 0.4.1.4  1994/07/21  02:15:45  root
  * ifdef'd DDI. Exception masks.
  *
  * Also, be careful to avoid IO conflicts with other devices!
  */
 
-#include <linux/config.h>
+#include <linux/autoconf.h>
 
-/* skip this driver if not required for this configuration */
-#if CONFIG_QIC02_TAPE
 
 /*
 #define TDEBUG
  */
 
 #ifdef CONFIG_QIC02_DYNCONF
-/* This may hold the dynamic configuration info for the interface
- * card+drive info in future versions.
+/* This holds the dynamic configuration info for the interface
+ * card+drive info if runtime configuration has been selected.
  */
 struct mtconfiginfo qic02_tape_dynconf = { 0, };       /* user settable */
 struct qic02_ccb qic02_tape_ccb = { 0, };              /* private stuff */
@@ -256,8 +256,8 @@ static volatile struct mtget ioctl_status;  /* current generic status */
 
 static volatile struct tpstatus tperror;       /* last drive status */
 
-static char rcs_revision[] = "$Revision: 0.4.1.4 $";
-static char rcs_date[] = "$Date: 1994/07/21 02:15:45 $";
+static char rcs_revision[] = "$Revision: 0.4.1.5 $";
+static char rcs_date[] = "$Date: 1994/10/29 02:46:13 $";
 
 /* Flag bits for status and outstanding requests.
  * (Could all be put in one bit-field-struct.)
@@ -285,7 +285,7 @@ static volatile unsigned long dma_bytes_done;
 static volatile unsigned dma_mode = 0;         /* !=0 also means DMA in use */
 static                 flag need_rewind = YES;
 
-static dev_t current_tape_dev = QIC02_TAPE_MAJOR << 8;
+static dev_t current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0);
 static int extra_blocks_left = BLOCKS_BEYOND_EW;
 
 
@@ -570,7 +570,9 @@ static void report_error(int s)
 #endif
 
 
-/* perform appropriate action for certain exceptions */
+/* Perform appropriate action for certain exceptions.
+ * should return a value to indicate stop/continue (in case of bad blocks)
+ */
 static void handle_exception(int exnr, int exbits)
 {
        if (exnr==EXC_NCART) {
@@ -1358,9 +1360,7 @@ static int do_ioctl_cmd(int cmd)
                        return do_qic_cmd(QCMD_REWIND, TIM_R);
 
                case MTOFFL:
-                       tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline"); /*---*/
-                       /******* What exactly are we supposed to do, to take it offline????
-                        *****/
+                       tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline");
                        /* Doing a drive select will clear (unlock) the current drive.
                         * But that requires support for multiple drives and locking.
                         */
@@ -1927,8 +1927,9 @@ static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf,
        }
 
        if (TP_DIAGS(current_tape_dev))
+               /* can't print a ``long long'' (for filp->f_pos), so chop it */
                printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
-                       MINOR(dev), buf, count, filp->f_pos, flags);
+                       MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
 
        if (count % TAPE_BLKSIZE) {     /* Only allow mod 512 bytes at a time. */
                tpqputs(TPQD_BLKSZ, "Wrong block size");
@@ -2100,8 +2101,9 @@ static int qic02_tape_write(struct inode * inode, struct file * filp, char * buf
        }
 
        if (TP_DIAGS(current_tape_dev))
+               /* can't print a ``long long'' (for filp->f_pos), so chop it */
                printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
-                       MINOR(dev), buf, count, filp->f_pos, flags);
+                       MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
 
        if (count % TAPE_BLKSIZE) {     /* only allow mod 512 bytes at a time */
                tpqputs(TPQD_BLKSZ, "Wrong block size");
@@ -2587,7 +2589,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
                if (!suser())
                        return -EPERM;
                verify_area(VERIFY_READ, (int *) ioarg, sizeof(int));
-               c = get_fs_long((int *) ioarg);
+               c = get_user_long((int *) ioarg);
                if (c==0) {
                        QIC02_TAPE_DEBUG = 0;
                        return 0;
@@ -2619,7 +2621,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
                stp = (char *) &qic02_tape_dynconf;
                argp = (char *) ioarg;
                for (i=0; i<sizeof(qic02_tape_dynconf); i++) 
-                       put_fs_byte(*stp++, argp++);
+                       put_user_byte(*stp++, argp++);
                return 0;
 
        } else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) {
@@ -2646,7 +2648,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
                stp = (char *) &qic02_tape_dynconf;
                argp = (char *) ioarg;
                for (i=0; i<sizeof(qic02_tape_dynconf); i++)
-                       *stp++ = get_fs_byte(argp++);
+                       *stp++ = get_user_byte(argp++);
                if (status_zombie==NO)
                        qic02_release_resources();      /* and go zombie */
                if (update_ifc_masks(qic02_tape_dynconf.ifc_type))
@@ -2678,7 +2680,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
                stp = (char *) &operation;
                argp = (char *) ioarg;
                for (i=0; i<sizeof(operation); i++)
-                       *stp++ = get_fs_byte(argp++);
+                       *stp++ = get_user_byte(argp++);
 
                /* ---note: mt_count is signed, negative seeks must be
                 * ---      translated to seeks in opposite direction!
@@ -2740,7 +2742,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
                stp = (char *) &ioctl_status;
                argp = (char *) ioarg;
                for (i=0; i<sizeof(ioctl_status); i++) 
-                       put_fs_byte(*stp++, argp++);
+                       put_user_byte(*stp++, argp++);
                return 0;
 
 
@@ -2773,7 +2775,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
                stp = (char *) &ioctl_tell;
                argp = (char *) ioarg;
                for (i=0; i<sizeof(ioctl_tell); i++) 
-                       put_fs_byte(*stp++, argp++);
+                       put_user_byte(*stp++, argp++);
                return 0;
 
        } else
@@ -2793,7 +2795,10 @@ static struct file_operations qic02_tape_fops = {
        NULL,                           /* mmap not allowed */
        qic02_tape_open,                /* open */
        qic02_tape_release,             /* release */
-       NULL                            /* fsync */
+       NULL,                           /* fsync */
+       NULL,                           /* fasync */
+       NULL,                           /* check_media_change */
+       NULL                            /* revalidate */
 };
 
 /* align `a' at `size' bytes. `size' must be a power of 2 */
@@ -2870,7 +2875,6 @@ static int qic02_get_resources(void)
 
 
 
-/* init() is called from chr_dev_init() in drivers/char/mem.c */
 long qic02_tape_init(long kmem_start)
        /* Shouldn't this be a caddr_t ? */
 {
@@ -2969,5 +2973,3 @@ long qic02_tape_init(long kmem_start)
        return kmem_start;
 } /* qic02_tape_init */
 
-
-#endif /* CONFIG_QIC02_TAPE */
index eaa1bdd297ab21160b54d047fb2d21558bf7eab6..c8381b572cc41c0c13fb34370f206ea67949d9fe 100644 (file)
 #        DE620_IO      The DE620 I/O-port address (0x378 == default)
 #        DE620_IRQ     The DE620 IRQ number to use (IRQ7 == default)
 #        DE620_DEBUG   Enable or disable DE600 debugging (default off)
-#  DEPCA               The DIGITAL series of AT Ethernet Cards (DE100, DE200)
-#        DEPCA_IRQ     Set the desired IRQ (=0, for autoprobe)
-#        DEPCA_DEBUG   Set the desired debug level
+#  DEPCA               The DIGITAL series of LANCE based Ethernet Cards
+#                      (DEPCA, DE100, DE200/1/2, DE210, DE422 (EISA))
+#  EWRK3               The DIGITAL series of AT Ethernet Cards (DE203/4/5)
+#       EWRK3_DEBUG    Set the desired debug level
 #
 
 # The following options exist, but cannot be set in this file.
@@ -57,4 +58,5 @@ EL2_OPTS      = #-DEL2_AUI
 NE_OPTS                =
 HP_OPTS                =
 PLIP_OPTS      =
-DEPCA_OPTS     = -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1
+DEPCA_OPTS     = -DDEPCA_DEBUG=1
+EWRK3_OPTS     = -DEWRK3_DEBUG=1
index 6f5f98525b76f8b9cba05928610dac8a87a36618..3df08613013d2dd156e5fbe68bd19e80d85fea48 100644 (file)
@@ -142,6 +142,11 @@ NETDRV_OBJS := $(NETDRV_OBJS) depca.o
 depca.o: depca.c CONFIG
        $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 endif
+ifdef CONFIG_EWRK3
+NETDRV_OBJS := $(NETDRV_OBJS) ewrk3.o
+ewrk3.o: ewrk3.c CONFIG
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
+endif
 ifdef CONFIG_ATP
 NETDRV_OBJS := $(NETDRV_OBJS) atp.o
 endif
diff --git a/drivers/net/README.ewrk3 b/drivers/net/README.ewrk3
new file mode 100644 (file)
index 0000000..395d373
--- /dev/null
@@ -0,0 +1,43 @@
+The EtherWORKS 3  driver in this distribution is  designed to  work with all
+kernels   >  1.1.33   (approx)  and  includes  tools   in  the  'ewrk3tools'
+subdirectory   to  allow  set   up of   the   card,  similar  to  the  MSDOS
+'NICSETUP.EXE' tools provided on  the DOS drivers  disk (type 'make' in that
+subdirectory to make the tools).
+
+The supported cards  are  DE203, DE204 and  DE205.  All other cards are  NOT
+supported - refer  to the depca files for   running the LANCE based  network
+cards from Digital.
+
+The ability to load  this driver as a  loadable module has been included and
+used extensively  during the driver  development (to save those  long reboot
+sequences). To utilise this ability, you have to do 8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) edit the  source code near  line 1750 to reflect  the I/O address and
+    IRQ you're using.
+    3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the ewrk3 configuration turned off and reboot.
+    5) insmod ewrk3.o
+    6) run the net startup bits for your new eth?? interface manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    Note that autoprobing is not allowed in loadable modules - the system is
+    already up and running and you're messing with interrupts.
+
+    To unload a module, turn off the associated interface 
+    'ifconfig eth?? down' then 'rmmod ewrk3'.
+
+The performance we've  achieved so far  has been measured through the 'ttcp'
+tool   at 975kB/s.  This  measures  the  total  tcp  stack performance which
+includes the   card,  so don't  expect   to get   much nearer  the  1.25MB/s
+theoretical ethernet rate.
+
+
+Enjoy!
+
+Dave
index 3f05f253d6d1dff7ad01fbc6cc1a07007bb2c66a..4a82265e58adcd4405cdd09a0fec4beeabeac430 100644 (file)
@@ -49,6 +49,7 @@ extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
 extern int depca_probe(struct device *);
+extern int ewrk3_probe(struct device *);
 extern int el1_probe(struct device *);
 extern int el16_probe(struct device *);
 extern int elplus_probe(struct device *);
@@ -108,6 +109,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_DEPCA            /* DEC DEPCA */
        && depca_probe(dev)
 #endif
+#ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
+        && ewrk3_probe(dev)
+#endif
 #ifdef CONFIG_EL1              /* 3c501 */
        && el1_probe(dev)
 #endif
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
new file mode 100644 (file)
index 0000000..f1ab8e5
--- /dev/null
@@ -0,0 +1,1835 @@
+/*  ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for linux.
+
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 Digital Equipment Corporation.
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+
+    This driver is written for the Digital Equipment Corporation series
+    of EtherWORKS ethernet cards:
+
+       DE203 Turbo (BNC)
+       DE204 Turbo (TP)
+       DE205 Turbo (TP BNC)
+
+    The driver has been tested on a relatively busy  network using the DE205
+    card and benchmarked with 'ttcp': it transferred 16M  of data at 975kB/s
+    (7.8Mb/s) to a DECstation 5000/200.
+
+    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
+    Equipment Corporation, 550 King Street, Littleton MA 01460.
+
+    =========================================================================
+    This driver has been written  substantially  from scratch, although  its
+    inheritance of style and stack interface from 'depca.c' and in turn from
+    Donald Becker's 'lance.c' should be obvious.
+
+    The  DE203/4/5 boards  all  use a new proprietary   chip in place of the
+    LANCE chip used in prior cards  (DEPCA, DE100, DE200/1/2, DE210, DE422).
+    Use the depca.c driver in the standard distribution  for the LANCE based
+    cards from DIGITAL; this driver will not work with them.
+
+    The DE203/4/5 cards have 2  main modes: shared memory  and I/O only. I/O
+    only makes  all the card accesses through  I/O transactions and  no high
+    (shared)  memory is used. This  mode provides a >48% performance penalty
+    and  is deprecated in this  driver,  although allowed to provide initial
+    setup when hardstrapped.
+
+    The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is
+    no point in using any mode other than the 2kB  mode - their performances
+    are virtually identical, although the driver has  been tested in the 2kB
+    and 32kB modes. I would suggest you uncomment the line:
+
+                             FORCE_2K_MODE;
+
+    to allow the driver to configure the card as a  2kB card at your current
+    base  address, thus leaving more  room to clutter  your  system box with
+    other memory hungry boards.
+
+    Upto 21 ISA and 7 EISA cards can be supported under this driver, limited
+    primarily by the  available  IRQ   lines.   I have   checked   different
+    configurations  of multiple depca  cards and  ewrk3 cards  and  have not
+    found a problem yet (provided you have at least depca.c v0.38) ...
+
+    The board IRQ setting   must be at  an unused  IRQ which is  auto-probed
+    using  Donald  Becker's autoprobe  routines.   All  these cards   are at
+    {5,10,11,15}.
+
+    No 16MB memory  limitation should exist with this  driver as DMA is  not
+    used and the common memory area is in low memory on the network card (my
+    current system has 20MB and I've not had problems yet).
+
+    The ability to load  this driver as a  loadable module has been included
+    and used  extensively during the  driver development (to save those long
+    reboot sequences). To utilise this ability, you have to do 8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) edit the  source code near  line 1340 to reflect  the I/O address and
+    IRQ you're using.
+    3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the ewrk3 configuration turned off and reboot.
+    5) insmod ewrk3.o
+    6) run the net startup bits for your new eth?? interface manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    Note that autoprobing is not allowed in loadable modules - the system is
+    already up and running and you're messing with interrupts.
+
+    To unload a module, turn off the associated interface 
+    'ifconfig eth?? down' then 'rmmod ewrk3'.
+
+    Promiscuous   mode has been  turned  off  in this driver,   but  all the
+    multicast  address bits  have been   turned on. This  improved the  send
+    performance on a busy network by about 13%.
+
+    Ioctl's have now been provided (primarily because  I wanted to grab some
+    packet size statistics). They  are patterned after 'plipconfig.c' from a
+    suggestion by Alan Cox.  Using these  ioctls, you can enable promiscuous
+    mode, add/delete multicast  addresses, change the hardware address,  get
+    packet size distribution statistics and muck around with the control and
+    status register. I'll add others if and when the need arises.
+
+    TO DO:
+    ------
+
+
+    Revision History
+    ----------------
+
+    Version   Date        Description
+  
+      0.1     26-aug-94   Initial writing. ALPHA code release.
+      0.11    31-aug-94   Fixed: 2k mode memory base calc., 
+                                 LeMAC version calc.,
+                                IRQ vector assignments during autoprobe.
+      0.12    31-aug-94   Tested working on LeMAC2 (DE20[345]-AC) card.
+                          Fixed up MCA hash table algorithm.
+      0.20     4-sep-94   Added IOCTL functionality.
+      0.21    14-sep-94   Added I/O mode.
+      0.21axp 15-sep-94   Special version for ALPHA AXP Linux V1.0
+      0.22    16-sep-94   Added more IOCTLs & tidied up.
+      0.23    21-sep-94   Added transmit cut through
+      0.24    31-oct-94   Added uid checks in some ioctls
+      0.30     1-nov-94   BETA code release
+
+    =========================================================================
+*/
+
+static char *version = "ewrk3.c:v0.30 11/1/94 davies@wanton.lkg.dec.com\n";
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/segment.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include "/linux/tools/version.h"
+#endif /* MODULE */
+
+#include "ewrk3.h"
+
+#ifdef EWRK3_DEBUG
+static int ewrk3_debug = EWRK3_DEBUG;
+#else
+static int ewrk3_debug = 1;
+#endif
+
+#ifndef PROBE_LENGTH
+#define PROBE_LENGTH    32
+#endif
+
+#ifndef PROBE_SEQUENCE
+#define PROBE_SEQUENCE "FF0055AAFF0055AA"
+#endif
+
+#ifndef EWRK3_SIGNATURE
+#define EWRK3_SIGNATURE {"DE203","DE204","DE205",""}
+#define EWRK3_NAME_LENGTH 8
+#endif
+
+#ifndef EWRK3_RAM_BASE_ADDRESSES
+#define EWRK3_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0x00000}
+#endif
+
+/*
+** Sets up the search areas for the autoprobe. You can disable an area
+** by writing a zero into the corresponding bit position in EWRK3_IO_SEARCH.
+** The LSb -> I/O 0x100. Each bit increments the I/O location searched by 0x20.
+** Bit 24 -> I/O 0x400.
+**
+** By default, probes at locations:
+**             0x1e0   (may conflict with hard disk)
+**             0x320   (may conflict with hard disk)
+**             0x3e0   (may conflict with floppy disk)
+**
+** are disabled.
+*/
+
+#define EWRK3_IO_BASE 0x100             /* Start address for probe search */
+#define EWRK3_IOP_INC 0x20              /* I/O address increment */
+#define EWRK3_IO_SEARCH 0x007dff7f      /* probe search mask */
+static long mem_chkd = EWRK3_IO_SEARCH; /* holds which I/O addrs should be */
+                                       /* checked, for multi-EWRK3 case */
+
+#ifndef MAX_NUM_EWRK3S
+#define MAX_NUM_EWRK3S 21
+#endif
+
+#ifndef EWRK3_EISA_IO_PORTS 
+#define EWRK3_EISA_IO_PORTS 0x0c00      /* I/O port base address, slot 0 */
+#endif
+
+#ifndef MAX_EISA_SLOTS
+#define MAX_EISA_SLOTS 8
+#define EISA_SLOT_INC 0x1000
+#endif
+
+#ifndef CRC_POLYNOMIAL
+#define CRC_POLYNOMIAL 0x04c11db7       /* Ethernet CRC polynomial */
+#endif /* CRC_POLYNOMIAL */
+
+/*
+** EtherWORKS 3 shared memory window sizes
+*/
+#define IO_ONLY         0x00
+#define SHMEM_2K        0x800
+#define SHMEM_32K       0x8000
+#define SHMEM_64K       0x10000
+
+/*
+** EtherWORKS 3 IRQ ENABLE/DISABLE
+*/
+static unsigned char irq_mask = TNEM|TXDM|RNEM|RXDM;
+
+#define ENABLE_IRQs \
+  icr |= irq_mask;\
+  outb(icr, EWRK3_ICR)                      /* Enable the IRQs */
+
+#define DISABLE_IRQs \
+  icr = inb(EWRK3_ICR);\
+  icr &= ~irq_mask;\
+  outb(icr, EWRK3_ICR)                      /* Disable the IRQs */
+
+/*
+** EtherWORKS 3 START/STOP
+*/
+#define START_EWRK3 \
+  csr = inb(EWRK3_CSR);\
+  csr &= ~(TXD|RXD);\
+  outb(csr, EWRK3_CSR)                      /* Enable the TX and/or RX */
+
+#define STOP_EWRK3 \
+  csr = (TXD|RXD);\
+  outb(csr, EWRK3_CSR)                      /* Disable the TX and/or RX */
+
+/*
+** The EtherWORKS 3 private structure
+*/
+#define EWRK3_PKT_STAT_SZ 16
+#define EWRK3_PKT_BIN_SZ  128           /* Should be >=100 unless you
+                                           increase EWRK3_PKT_STAT_SZ */
+
+struct ewrk3_private {
+    long shmem_base;                    /* Shared memory start address */
+    long shmem_length;                  /* Shared memory window length */
+    struct enet_statistics stats;       /* Public stats */
+    struct {
+      unsigned long bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */
+      unsigned long unicast;
+      unsigned long multicast;
+      unsigned long broadcast;
+      unsigned long excessive_collisions;
+      unsigned long tx_underruns;
+      unsigned long excessive_underruns;
+    } pktStats;
+    short mPage;                        /* Maximum 2kB Page number */
+    unsigned char lemac;                /* Chip rev. level */
+    unsigned char hard_strapped;        /* Don't allow a full open */
+    unsigned char lock;                 /* Lock the page register */
+    unsigned char txc;                  /* Transmit cut through */
+};
+
+/*
+** Force the EtherWORKS 3 card to be in 2kB MODE
+*/
+#define FORCE_2K_MODE \
+  shmem_length = SHMEM_2K;\
+  outb(((mem_start - 0x80000) >> 11), EWRK3_MBR)
+
+/*
+** Public Functions
+*/
+static int ewrk3_open(struct device *dev);
+static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev);
+static void ewrk3_interrupt(int reg_ptr);
+static int ewrk3_close(struct device *dev);
+static struct enet_statistics *ewrk3_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static int ewrk3_ioctl(struct device *dev, struct ifreq *rq);
+
+/*
+** Private functions
+*/
+static int  ewrk3_hw_init(struct device *dev, short iobase);
+static void ewrk3_init(struct device *dev);
+static int  ewrk3_rx(struct device *dev);
+static int  ewrk3_tx(struct device *dev);
+
+static void EthwrkSignature(char * name, char *eeprom_image);
+static int  DevicePresent(short iobase);
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table);
+
+static int  Read_EEPROM(short iobase, unsigned char eaddr);
+static int  Write_EEPROM(short data, short iobase, unsigned char eaddr);
+static unsigned char aprom_crc (struct device *dev, unsigned char *eeprom_image, char chipType);
+
+#ifndef MODULE
+static struct device *isa_probe(struct device *dev);
+static struct device *eisa_probe(struct device *dev);
+static struct device *alloc_device(struct device *dev, int iobase);
+
+static int num_ewrk3s = 0, num_eth = 0, autoprobed = 0;
+static unsigned char irq[] = {5,0,10,3,11,9,15,12};
+
+#else
+int  init_module(void);
+void cleanup_module(void);
+
+#endif /* MODULE */
+
+/*
+** Miscellaneous defines...
+*/
+#define INIT_EWRK3 {\
+    int i;\
+    outb(EEPROM_INIT, EWRK3_IOPR);\
+    for (i=0;i<5000;i++) inb(EWRK3_CSR);\
+                  }
+
+
+\f
+
+int ewrk3_probe(struct device *dev)
+{
+  int base_addr = dev->base_addr;
+  int status = -ENODEV;
+#ifndef MODULE
+  struct device *eth0;
+#endif
+
+  if (base_addr > 0x0ff) {           /* Check a single specified location. */
+    if (((mem_chkd >> ((base_addr - EWRK3_IO_BASE)/ EWRK3_IOP_INC))&0x01)==0) {
+      if (DevicePresent(base_addr) == 0) { /* Is EWRK3 really here? */
+       status = ewrk3_hw_init(dev, base_addr);
+      } else {
+       printk("ewrk3_probe(): No device found\n");
+      }
+    } else {
+      status = ewrk3_hw_init(dev, base_addr); /* Yes there is h/w */
+    }
+  } else if (base_addr > 0) {         /* Don't probe at all. */
+    status = -ENXIO;
+
+#ifdef MODULE
+  } else {
+    printk("Autoprobing is not supported when loading a module based driver.\n");
+    status = -EIO;
+#else
+  } else if (!autoprobed) {           /* First probe for the EWRK3 test */
+                                      /* pattern in ROM */
+    eth0=isa_probe(dev);
+    eth0=eisa_probe(eth0);
+    if (dev->priv) status=0;
+    autoprobed = 1;
+  } else {
+    status = -ENXIO;
+#endif /* MODULE */
+    
+  }
+
+  if (status) dev->base_addr = base_addr;
+
+  return status;
+}
+
+static int
+ewrk3_hw_init(struct device *dev, short iobase)
+{
+  struct ewrk3_private *lp;
+  int i, status=0;
+  unsigned long mem_start, shmem_length;
+  char name[EWRK3_NAME_LENGTH + 1];
+  unsigned char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
+  unsigned char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
+
+  /*
+  ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
+  ** This also disables the EISA_ENABLE bit in the EISA Control Register.
+  */
+  if (iobase > 0x400) eisa_cr = inb(EISA_CR);
+  INIT_EWRK3;
+
+  nicsr = inb(EWRK3_CSR);
+
+  /*
+  ** Disable & mask all board interrupts
+  */
+  DISABLE_IRQs;
+
+  if (nicsr == TXD|RXD) {
+
+    /*
+    ** Check that the EEPROM is alive and well and not living on Pluto...
+    */
+    for (chksum=0, i=0; i<EEPROM_MAX; i+=2) {
+      union {
+       short val;
+       char c[2];
+      } tmp;
+
+      tmp.val = (short)Read_EEPROM(iobase, (i>>1));
+      eeprom_image[i] = tmp.c[0];
+      eeprom_image[i+1] = tmp.c[1];
+
+      chksum += eeprom_image[i] + eeprom_image[i+1];
+    }
+
+    if (chksum != 0) {                             /* Bad EEPROM Data! */
+      printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
+      status = -ENXIO;
+    } else {
+      /* 
+      ** Now find out what kind of EWRK3 we have.
+      */
+      EthwrkSignature(name, eeprom_image);
+
+      if (*name != '\0') {                         /* found a EWRK3 device */
+       dev->base_addr = iobase;
+      
+       if (iobase > 0x400) {
+         outb(eisa_cr, EISA_CR);                  /* Rewrite the EISA CR */
+       }
+
+       lemac = eeprom_image[EEPROM_CHIPVER];
+       cmr = inb(EWRK3_CMR);
+
+       if (((lemac == LeMAC) && ((cmr & NO_EEPROM) != NO_EEPROM)) ||
+           ((lemac == LeMAC2) && !(cmr & HS))) {
+         printk("%s: %s at %#3x", dev->name, name, iobase);
+         hard_strapped = 1;
+       } else if ((iobase&0x0fff)==EWRK3_EISA_IO_PORTS) {
+                                                  /* EISA slot address */
+         printk("%s: %s at %#3x (EISA slot %d)", 
+                                dev->name, name, iobase, ((iobase>>12)&0x0f));
+       } else {                                   /* ISA port address */
+         printk("%s: %s at %#3x", dev->name, name, iobase);
+       }
+       
+       if (!status) {
+         printk(", h/w address ");
+         if (lemac == LeMAC2) {
+           for (i = 0;i < ETH_ALEN - 1;i++) { /* get the ethernet address */
+             printk("%2.2x:", dev->dev_addr[i] = 
+                                             eeprom_image[EEPROM_PADDR0 + i]);
+             outb(eeprom_image[EEPROM_PADDR0 + i], EWRK3_PAR0 + i);
+           }
+           printk("%2.2x,\n",dev->dev_addr[i] = eeprom_image[EEPROM_PADDR0 + i]);
+           outb(eeprom_image[EEPROM_PADDR0 + i], EWRK3_PAR0 + i);
+         } else {
+           DevicePresent(iobase);          /* needed after the EWRK3_INIT */
+           for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
+             printk("%2.2x:", dev->dev_addr[i] = inb(EWRK3_APROM));
+             outb(dev->dev_addr[i], EWRK3_PAR0 + i);
+           }
+           printk("%2.2x,\n", dev->dev_addr[i] = inb(EWRK3_APROM));
+           outb(dev->dev_addr[i], EWRK3_PAR0 + i);
+         }
+
+         if (aprom_crc(dev, eeprom_image, lemac)) {
+           printk("      which has an EEPROM CRC error.\n");
+           status = -ENXIO;
+         } else {
+           if (lemac == LeMAC2) {            /* Special LeMAC2 CMR things */
+             cmr &= ~(RA | WB | LINK | POLARITY | _0WS);         
+             if (eeprom_image[EEPROM_MISC0] & READ_AHEAD)    cmr |= RA;
+             if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND)  cmr |= WB;
+             if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL)  cmr |= POLARITY;
+             if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) cmr |= LINK;
+             if (eeprom_image[EEPROM_MISC0] & _0WS_ENA)      cmr |= _0WS;
+           }
+           if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)      cmr |= DRAM;
+           outb(cmr, EWRK3_CMR);
+
+           cr = inb(EWRK3_CR);               /* Set up the Control Register */
+           cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
+           if (cr & SETUP_APD) cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS;
+           cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS;
+           cr |= eeprom_image[EEPROM_MISC0] & ENA_16;
+           outb(cr, EWRK3_CR);
+
+           /* 
+           ** Determine the base address and window length for the EWRK3
+           ** RAM from the memory base register.
+           */
+           mem_start = inb(EWRK3_MBR);
+           shmem_length = 0;
+           if (mem_start != 0) {
+             if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {
+               mem_start *= SHMEM_64K;
+               shmem_length = SHMEM_64K;
+             } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {
+               mem_start *= SHMEM_32K;
+               shmem_length = SHMEM_32K;
+             } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {
+               mem_start = mem_start * SHMEM_2K + 0x80000;
+               shmem_length = SHMEM_2K;
+             } else {
+               status = -ENXIO;
+             }
+           }
+         
+           /*
+           ** See the top of this source code for comments about
+           ** uncommenting this line.
+           */
+/*         FORCE_2K_MODE;*/
+
+           if (!status) {
+             if (hard_strapped) {
+               printk("      is hard strapped.\n");
+             } else if (mem_start) {
+               printk("      has a %dk RAM window", (int)(shmem_length >> 10));
+               printk(" at 0x%.5lx", mem_start);
+             } else {
+               printk("      is in I/O only mode");
+             }
+           
+             /* private area & initialise */
+             dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), 
+                                                                  GFP_KERNEL);
+             lp = (struct ewrk3_private *)dev->priv;
+             memset(dev->priv, 0, sizeof(struct ewrk3_private));
+             lp->shmem_base = mem_start;
+             lp->shmem_length = shmem_length;
+             lp->lemac = lemac;
+             lp->hard_strapped = hard_strapped;
+
+             lp->mPage = 64;
+             if (cmr & DRAM) lp->mPage <<= 1 ;     /* 2 DRAMS on module */ 
+
+             if (!hard_strapped) {
+               /*
+               ** Enable EWRK3 board interrupts for autoprobing
+               */
+               icr |= IE;                         /* Enable interrupts */
+               outb(icr, EWRK3_ICR);
+           
+               /* The DMA channel may be passed in on this parameter. */
+               dev->dma = 0;
+       
+               /* To auto-IRQ we enable the initialization-done and DMA err,
+                  interrupts. For now we will always get a DMA error. */
+               if (dev->irq < 2) {
+#ifndef MODULE
+                 unsigned char irqnum;
+             
+                 autoirq_setup(0);
+
+                 /* 
+                 ** Trigger a TNE interrupt.
+                 */
+                 icr |=TNEM;
+                 outb(1,EWRK3_TDQ);          /* Write to the TX done queue */
+                 outb(icr, EWRK3_ICR);       /* Unmask the TXD interrupt */
+             
+                 irqnum = irq[((icr & IRQ_SEL) >> 4)];
+             
+                 dev->irq = autoirq_report(1);
+                 if ((dev->irq) && (irqnum == dev->irq)) {
+                   printk(" and uses IRQ%d.\n", dev->irq);
+                 } else {
+                   if (!dev->irq) {
+                     printk(" and failed to detect IRQ line.\n");
+                   } else if ((irqnum == 1) && (lemac == LeMAC2)) {
+                     printk(" and an illegal IRQ line detected.\n");
+                   } else {
+                     printk(", but incorrect IRQ line detected.\n");
+                   }
+                   status = -ENXIO;
+                 }
+               
+                 DISABLE_IRQs;                 /* Mask all interrupts */
+
+#endif /* MODULE */
+               } else {
+                 printk(" and requires IRQ%d.\n", dev->irq);
+               }
+             }
+           } else {
+             status = -ENXIO;
+           }
+         }
+       }
+      } else {
+       status = -ENXIO;
+      }
+    }
+
+    if (!status) {
+      if (ewrk3_debug > 0) {
+       printk(version);
+      }
+      
+      /* The EWRK3-specific entries in the device structure. */
+      dev->open = &ewrk3_open;
+      dev->hard_start_xmit = &ewrk3_queue_pkt;
+      dev->stop = &ewrk3_close;
+      dev->get_stats = &ewrk3_get_stats;
+#ifdef HAVE_MULTICAST
+      dev->set_multicast_list = &set_multicast_list;
+#endif
+      dev->do_ioctl = &ewrk3_ioctl;
+
+      dev->mem_start = 0;
+       
+      /* Fill in the generic field of the device structure. */
+      ether_setup(dev);
+    }
+  } else {
+    status = -ENXIO;
+  }
+
+  return status;
+}
+
+\f
+static int
+ewrk3_open(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int i, iobase = dev->base_addr;
+  int status = 0;
+  unsigned char icr, csr;
+
+  /*
+  ** Stop the TX and RX...
+  */
+  STOP_EWRK3;
+
+  if (!lp->hard_strapped) {
+    if (request_irq(dev->irq, &ewrk3_interrupt, 0, "ewrk3")) {
+      printk("ewrk3_open(): Requested IRQ%d is busy\n",dev->irq);
+      status = -EAGAIN;
+    } else {
+
+      irq2dev_map[dev->irq] = dev;
+
+      /* 
+      ** Re-initialize the EWRK3... 
+      */
+      ewrk3_init(dev);
+
+      if (ewrk3_debug > 1){
+       printk("%s: ewrk3 open with irq %d\n",dev->name,dev->irq);
+       printk("\tphysical address: ");
+       for (i=0;i<6;i++){
+         printk("%2.2x:",(short)dev->dev_addr[i]);
+       }
+       printk("\n");
+       printk("\tchecked memory: 0x%08lx\n",mem_chkd);
+       if (lp->shmem_length == 0) {
+         printk("\tno shared memory, I/O only mode\n");
+       } else {
+         printk("\tstart of shared memory: 0x%08lx\n",lp->shmem_base);
+         printk("\twindow length: 0x%04lx\n",lp->shmem_length);
+       }
+       printk("\t# of DRAMS: %d\n",((inb(EWRK3_CMR) & 0x02) ? 2 : 1));
+       printk("\tcsr:  0x%02x\n", inb(EWRK3_CSR));
+       printk("\tcr:   0x%02x\n", inb(EWRK3_CR));
+       printk("\ticr:  0x%02x\n", inb(EWRK3_ICR));
+       printk("\tcmr:  0x%02x\n", inb(EWRK3_CMR));
+       printk("\tfmqc: 0x%02x\n", inb(EWRK3_FMQC));
+      }
+
+      dev->tbusy = 0;                         
+      dev->start = 1;
+      dev->interrupt = UNMASK_INTERRUPTS;
+
+      /*
+      ** Unmask EWRK3 board interrupts
+      */
+      icr = inb(EWRK3_ICR);
+      ENABLE_IRQs;
+
+    }
+  } else {
+    dev->start = 0;
+    dev->tbusy = 1;
+    printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);
+    printk("      Run the 'ewrk3setup' utility or remove the hard straps.\n");
+  }
+
+#ifdef MODULE
+    MOD_INC_USE_COUNT;
+#endif       
+
+
+  return status;
+}
+
+/*
+** Initialize the EtherWORKS 3 operating conditions
+*/
+static void
+ewrk3_init(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  char csr, page;
+  short iobase = dev->base_addr;
+  
+  /* 
+  ** Enable all multicasts 
+  */
+  set_multicast_list(dev, HASH_TABLE_LEN, NULL);
+
+  /*
+  ** Clean out any remaining entries in all the queues here
+  */
+  while (inb(EWRK3_TQ));
+  while (inb(EWRK3_TDQ));
+  while (inb(EWRK3_RQ));
+  while (inb(EWRK3_FMQ));
+
+  /*
+  ** Write a clean free memory queue
+  */
+  for (page=1;page<lp->mPage;page++) {      /* Write the free page numbers */
+    outb(page, EWRK3_FMQ);                  /* to the Free Memory Queue */
+  }
+
+  lp->lock = 0;                             /* Ensure there are no locks */
+
+  START_EWRK3;                              /* Enable the TX and/or RX */
+}
+
+/* 
+** Writes a socket buffer to the free page queue
+*/
+static int
+ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  int status = 0;
+  unsigned char icr, csr;
+
+  /* Transmitter timeout, serious problems. */
+  if (dev->tbusy || lp->lock) {
+    int tickssofar = jiffies - dev->trans_start;
+    if (tickssofar < 10) {
+      status = -1;
+    } else if (!lp->hard_strapped) {
+      printk("%s: transmit timed/locked out, status %04x, resetting.\n",
+                                                  dev->name, inb(EWRK3_CSR));
+       
+      /*
+      ** Mask all board interrupts
+      */
+      DISABLE_IRQs;
+
+      /*
+      ** Stop the TX and RX...
+      */
+      STOP_EWRK3;
+
+      ewrk3_init(dev);
+
+      /*
+      ** Unmask EWRK3 board interrupts
+      */
+      ENABLE_IRQs;
+
+      dev->tbusy=0;
+      dev->trans_start = jiffies;
+    }
+  } else if (skb == NULL) {
+    dev_tint(dev);
+  } else if (skb->len > 0) {
+
+    /* 
+    ** Block a timer-based transmit from overlapping.  This could better be
+    ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well. 
+    */
+    if (set_bit(0, (void*)&dev->tbusy) != 0)
+      printk("%s: Transmitter access conflict.\n", dev->name);
+
+    DISABLE_IRQs;                      /* So that the page # remains correct */
+    
+    /* 
+    ** Get a free page from the FMQ when resources are available
+    */
+    if (inb(EWRK3_FMQC) > 0) {
+      unsigned char *buf;
+      unsigned char page;
+
+      if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
+       buf = NULL;
+
+       /*
+       ** Set up shared memory window and pointer into the window
+       */
+       while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+       if (lp->shmem_length == IO_ONLY) {
+         outb(page, EWRK3_IOPR);
+       } else if (lp->shmem_length == SHMEM_2K) {
+         buf = (char *) lp->shmem_base;
+         outb(page, EWRK3_MPR);
+       } else if (lp->shmem_length == SHMEM_32K) {
+         buf = (char *)((((short)page << 11) & 0x7800) + lp->shmem_base);
+         outb((page >> 4), EWRK3_MPR);
+       } else if (lp->shmem_length == SHMEM_64K) {
+         buf = (char *)((((short)page << 11) & 0xf800) + lp->shmem_base);
+         outb((page >> 5), EWRK3_MPR);
+       } else {
+         status = -1;
+         printk("%s: Oops - your private data area is hosed!\n",dev->name);
+       }
+
+       if (!status) {
+
+          /* 
+         ** Set up the buffer control structures and copy the data from
+         ** the socket buffer to the shared memory .
+         */
+
+         if (lp->shmem_length == IO_ONLY) {
+           int i;
+           unsigned char *p = skb->data;
+           
+           outb((char)(QMODE | PAD | IFC), EWRK3_DATA);
+           outb((char)(skb->len & 0xff), EWRK3_DATA);
+           outb((char)((skb->len >> 8) & 0xff), EWRK3_DATA);
+           outb((char)0x04, EWRK3_DATA);
+           for (i=0; i<skb->len; i++) {
+             outb(*p++, EWRK3_DATA);
+           }
+           outb(page, EWRK3_TQ);                     /* Start sending pkt */
+         } else {
+           *buf++ = (char)(QMODE | PAD | IFC);       /* control byte */
+           *buf++ = (char)(skb->len & 0xff);         /* length (16 bit xfer)*/
+           if (lp->txc) {
+             *buf++ = (char)(((skb->len >> 8) & 0xff) | XCT);
+             *buf++ = 0x04;                          /* index byte */
+             *(buf + skb->len) = 0x00;               /* Write the XCT flag */
+             memcpy(buf, skb->data, PRELOAD);        /* Write PRELOAD bytes */
+             outb(page, EWRK3_TQ);                   /* Start sending pkt */
+             memcpy(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
+             *(buf + skb->len) = 0xff;               /* Write the XCT flag */
+           } else {
+             *buf++ = (char)((skb->len >> 8) & 0xff);
+             *buf++ = 0x04;                          /* index byte */
+             memcpy(buf, skb->data, skb->len);       /* Write data bytes */
+             outb(page, EWRK3_TQ);                   /* Start sending pkt */
+           }
+         }
+
+         dev->trans_start = jiffies;
+
+         dev_kfree_skb (skb, FREE_WRITE);
+
+        } else {              /* return unused page to the free memory queue */
+         outb(page, EWRK3_FMQ);
+       }
+       lp->lock = 0;         /* unlock the page register */
+      } else {
+       printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
+                                                        (unsigned char) page);
+      }
+    } else {
+      printk("ewrk3_queue_pkt(): No free resources...\n");
+      printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));
+    }
+    
+    /* Check for free resources: clear 'tbusy' if there are some */
+    if (inb(EWRK3_FMQC) > 0) {
+      dev->tbusy = 0;
+    }
+
+    ENABLE_IRQs;
+  }
+
+  return status;
+}
+
+/*
+** The EWRK3 interrupt handler. 
+*/
+static void
+ewrk3_interrupt(int reg_ptr)
+{
+    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
+    struct ewrk3_private *lp;
+    int iobase;
+    unsigned char icr, cr, csr;
+
+    if (dev == NULL) {
+       printk ("ewrk3_interrupt(): irq %d for unknown device.\n", irq);
+    } else {
+      lp = (struct ewrk3_private *)dev->priv;
+      iobase = dev->base_addr;
+
+      if (dev->interrupt)
+       printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+      dev->interrupt = MASK_INTERRUPTS;
+
+      /* get the interrupt information */
+      csr = inb(EWRK3_CSR);
+
+      /* 
+      ** Mask the EWRK3 board interrupts and turn on the LED 
+      */
+      DISABLE_IRQs;
+
+      cr = inb(EWRK3_CR);
+      cr |= LED;
+      outb(cr, EWRK3_CR);
+
+      if (csr & RNE)             /* Rx interrupt (packet[s] arrived) */
+       ewrk3_rx(dev);
+
+      if (csr & TNE)             /* Tx interrupt (packet sent) */
+        ewrk3_tx(dev);
+
+      /*
+      ** Now deal with the TX/RX disable flags. These are set when there
+      ** are no more resources. If resources free up then enable these
+      ** interrupts, otherwise mask them - failure to do this will result
+      ** in the system hanging in an interrupt loop.
+      */
+      if (inb(EWRK3_FMQC)) {      /* any resources available? */
+       irq_mask |= TXDM|RXDM;    /* enable the interrupt source */
+       csr &= ~(TXD|RXD);        /* ensure restart of a stalled TX or RX */
+       outb(csr, EWRK3_CSR);
+       dev->tbusy = 0;           /* clear TX busy flag */
+       mark_bh(NET_BH);
+      } else {
+       irq_mask &= ~(TXDM|RXDM); /* disable the interrupt source */
+      }
+
+      /* Unmask the EWRK3 board interrupts and turn off the LED */
+      cr &= ~LED;
+      outb(cr, EWRK3_CR);
+
+      dev->interrupt = UNMASK_INTERRUPTS;
+
+      ENABLE_IRQs;
+    }
+
+    return;
+}
+
+static int
+ewrk3_rx(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int i, iobase = dev->base_addr;
+  unsigned char page, tmpPage = 0, tmpLock = 0, *buf;
+  int status = 0;
+
+  while (inb(EWRK3_RQC) && !status) {        /* Whilst there's incoming data */
+    if ((page = inb(EWRK3_RQ)) < lp->mPage) {/* Get next entry's buffer page */
+      buf = NULL;
+
+      /*
+      ** Preempt any process using the current page register. Check for
+      ** an existing lock to reduce time taken in I/O transactions.
+      */
+      if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) {   /* Assert lock */
+       if (lp->shmem_length == IO_ONLY) {              /* Get existing page */
+         tmpPage = inb(EWRK3_IOPR);
+       } else {
+         tmpPage = inb(EWRK3_MPR);
+       }
+      }
+
+      /*
+      ** Set up shared memory window and pointer into the window
+      */
+      if (lp->shmem_length == IO_ONLY) {
+       outb(page, EWRK3_IOPR);
+      } else if (lp->shmem_length == SHMEM_2K) {
+       buf = (char *) lp->shmem_base;
+       outb(page, EWRK3_MPR);
+      } else if (lp->shmem_length == SHMEM_32K) {
+       buf = (char *)((((short)page << 11) & 0x7800) + lp->shmem_base);
+       outb((page >> 4), EWRK3_MPR);
+      } else if (lp->shmem_length == SHMEM_64K) {
+       buf = (char *)((((short)page << 11) & 0xf800) + lp->shmem_base);
+       outb((page >> 5), EWRK3_MPR);
+      } else {
+       status = -1;
+       printk("%s: Oops - your private data area is hosed!\n",dev->name);
+      }
+
+      if (!status) {
+       char rx_status;
+       int pkt_len;
+
+       if (lp->shmem_length == IO_ONLY) {
+         rx_status = inb(EWRK3_DATA);
+         pkt_len = inb(EWRK3_DATA);
+         pkt_len |= ((unsigned short)inb(EWRK3_DATA) << 8);
+       } else {
+         rx_status = (char)(*buf++);
+         pkt_len = (short)(*buf+((*(buf+1))<<8));
+         buf+=3;
+       }
+
+       if (!(rx_status & ROK)) {           /* There was an error. */
+         lp->stats.rx_errors++;            /* Update the error stats. */
+         if (rx_status & DBE) lp->stats.rx_frame_errors++;
+         if (rx_status & CRC) lp->stats.rx_crc_errors++;
+         if (rx_status & PLL) lp->stats.rx_fifo_errors++;
+       } else {
+         struct sk_buff *skb;
+
+          if ((skb = alloc_skb(pkt_len, GFP_ATOMIC)) != NULL) {
+           skb->len = pkt_len;
+           skb->dev = dev;
+
+           if (lp->shmem_length == IO_ONLY) {
+             unsigned char *p = skb->data;
+
+             *p = inb(EWRK3_DATA);         /* dummy read */
+             for (i=0; i<skb->len; i++) {
+               *p++ = inb(EWRK3_DATA);
+             }
+           } else {
+             memcpy(skb->data, buf, pkt_len);
+           }
+
+           /* 
+           ** Notify the upper protocol layers that there is another 
+           ** packet to handle
+           */
+           netif_rx(skb);
+
+           /*
+           ** Update stats
+           */
+           lp->stats.rx_packets++;
+           for (i=1; i<EWRK3_PKT_STAT_SZ-1; i++) {
+             if (pkt_len < i*EWRK3_PKT_BIN_SZ) {
+               lp->pktStats.bins[i]++;
+               i = EWRK3_PKT_STAT_SZ;
+             }
+           }
+           buf = skb->data;                  /* Look at the dest addr */
+           if (buf[0] & 0x01) {              /* Multicast/Broadcast */
+             if ((*(long *)&buf[0] == -1) && (*(short *)&buf[4] == -1)) {
+               lp->pktStats.broadcast++;
+             } else {
+               lp->pktStats.multicast++;
+             }
+           } else if ((*(long *)&buf[0] == *(long *)&dev->dev_addr[0]) &&
+                      (*(short *)&buf[4] == *(short *)&dev->dev_addr[4])) {
+             lp->pktStats.unicast++;
+           }
+
+           lp->pktStats.bins[0]++;           /* Duplicates stats.rx_packets */
+           if (lp->pktStats.bins[0] == 0) {  /* Reset counters */
+             memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+           }
+         } else {
+           printk("%s: Insufficient memory; nuking packet.\n", dev->name);
+           lp->stats.rx_dropped++;           /* Really, deferred. */
+           break;
+         }
+        }
+      }
+      /*
+      ** Return the received buffer to the free memory queue
+      */
+      outb(page, EWRK3_FMQ);
+
+      if (tmpLock) {                          /* If a lock was preempted */
+       if (lp->shmem_length == IO_ONLY) {    /* Replace old page */
+         outb(tmpPage, EWRK3_IOPR);
+       } else {
+         outb(tmpPage, EWRK3_MPR);
+       }
+      }
+      lp->lock = 0;                           /* Unlock the page register */
+    } else {
+      printk("ewrk3_rx(): Illegal page number, page %d\n",page);
+      printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));
+    }
+  }
+  return status;
+}
+
+/*
+** Buffer sent - check for TX buffer errors.
+*/
+static int
+ewrk3_tx(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  unsigned char tx_status;
+
+  while ((tx_status = inb(EWRK3_TDQ)) > 0) {  /* Whilst there's old buffers */
+    if (tx_status & VSTS) {                   /* The status is valid */
+      if (tx_status & MAC_TXE) {
+       lp->stats.tx_errors++;
+       if (tx_status & MAC_NCL)    lp->stats.tx_carrier_errors++;
+       if (tx_status & MAC_LCL)    lp->stats.tx_window_errors++;
+       if (tx_status & MAC_CTU) {
+         if ((tx_status & MAC_COLL) ^ MAC_XUR) {
+           lp->pktStats.tx_underruns++;
+         } else {
+           lp->pktStats.excessive_underruns++;
+         }
+       } else  if (tx_status & MAC_COLL) {
+         if ((tx_status & MAC_COLL) ^ MAC_XCOLL) {
+           lp->stats.collisions++;
+         } else {
+           lp->pktStats.excessive_collisions++;
+         }
+       }
+      } else {
+       lp->stats.tx_packets++;
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int
+ewrk3_close(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  unsigned char icr, csr;
+
+  dev->start = 0;
+  dev->tbusy = 1;
+
+  if (ewrk3_debug > 1) {
+    printk("%s: Shutting down ethercard, status was %2.2x.\n",
+          dev->name, inb(EWRK3_CSR));
+  }
+
+  /* 
+  ** We stop the EWRK3 here... mask interrupts and stop TX & RX
+  */
+  DISABLE_IRQs;
+
+  STOP_EWRK3;
+
+  /*
+  ** Clean out the TX and RX queues here (note that one entry
+  ** may get added to either the TXD or RX queues if the the TX or RX
+  ** just starts processing a packet before the STOP_EWRK3 command
+  ** is received. This will be flushed in the ewrk3_open() call).
+  */
+  while (inb(EWRK3_TQ));
+  while (inb(EWRK3_TDQ));
+  while (inb(EWRK3_RQ));
+
+  if (!lp->hard_strapped) {
+    free_irq(dev->irq);
+    
+    irq2dev_map[dev->irq] = 0;
+  }
+
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif    
+
+  return 0;
+}
+
+static struct enet_statistics *
+ewrk3_get_stats(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+
+  /* Null body since there is no framing error counter */
+    
+  return &lp->stats;
+}
+
+/*
+** Set or clear the multicast filter for this adaptor.
+** num_addrs == -1     Promiscuous mode, receive all packets
+** num_addrs == 0      Normal mode, clear multicast list
+** num_addrs > 0       Multicast mode, receive normal and MC packets, and do
+**                     best-effort filtering.
+*/
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  char *multicast_table;
+  unsigned char csr;
+
+  csr = inb(EWRK3_CSR);
+
+  if (lp->shmem_length == IO_ONLY) {
+    multicast_table = (char *) PAGE0_HTE;
+  } else {
+    multicast_table = (char *)(lp->shmem_base + PAGE0_HTE);
+  }
+
+  if (num_addrs >= 0) {
+    SetMulticastFilter(dev, num_addrs, (char *)addrs, multicast_table);
+    csr &= ~PME;
+    csr |= MCE;
+    outb(csr, EWRK3_CSR);
+  } else {                             /* set promiscuous mode */
+    csr |= PME;
+    csr &= ~MCE;
+    outb(csr, EWRK3_CSR);
+  }
+}
+
+/*
+** Calculate the hash code and update the logical address filter
+** from a list of ethernet multicast addresses.
+** Derived from a 'C' program in the AMD data book:
+** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", 
+** Pub #17781, Rev. A, May 1993
+**
+*/
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  char j, ctrl, bit, octet;
+  short *p = (short *) multicast_table;
+  unsigned short hashcode;
+  int i;
+  long int crc, poly = (long int) CRC_POLYNOMIAL;
+
+  while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+
+  if (lp->shmem_length == IO_ONLY) {
+    outb(0, EWRK3_IOPR);
+    outw((short)((long)multicast_table), EWRK3_PIR1);
+  } else {
+    outb(0, EWRK3_MPR);
+  }
+
+  if (num_addrs == HASH_TABLE_LEN) {
+    for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+      if (lp->shmem_length == IO_ONLY) {
+       outb(0xff, EWRK3_DATA);
+      } else {                /* memset didn't work here */
+       *p++ = 0xffff;
+       i++;
+      }
+    }
+  } else if (num_addrs == 0) {
+    if (lp->shmem_length == IO_ONLY) {
+      for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+       outb(0x00, EWRK3_DATA);
+      } 
+    } else {
+      memset(multicast_table, 0, (HASH_TABLE_LEN >> 3));
+    }
+  } else {
+    for (i=0;i<num_addrs;i++) {              /* for each address in the list */
+      if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* multicast address? */ 
+       crc = (long int) 0xffffffff;         /* init CRC for each address */
+       for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
+         for(j=0;j<8;j++) {                 /* process each address bit */
+           bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
+           ctrl = ((crc < 0) ? 1 : 0);      /* shift the control bit */
+           crc <<= 1;                       /* shift the CRC */
+           if (bit ^ ctrl) {                /* (bit) XOR (control bit) */
+             crc ^= poly;                   /* (CRC) XOR (polynomial) */
+           }
+         }
+       }
+       hashcode = (crc & 0x01);             /* hashcode is 9 LSb of CRC ... */
+       for (j=0;j<8;j++) {                  /* ... in reverse order. */
+         hashcode <<= 1;
+         crc >>= 1;
+         hashcode |= (crc & 0x01);
+       }                                      
+       octet = hashcode >> 3;               /* bit[3-8] -> octet in filter */
+                                            /* bit[0-2] -> bit in octet */
+       if (lp->shmem_length == IO_ONLY) {
+         unsigned char tmp;
+
+         outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
+         tmp = inb(EWRK3_DATA);
+         tmp |= (1 << (hashcode & 0x07));
+         outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
+         outb(tmp, EWRK3_DATA); 
+       } else {
+         multicast_table[octet] |= (1 << (hashcode & 0x07));
+       }
+      }
+    }
+  }
+
+  lp->lock = 0;                              /* Unlock the page register */
+
+  return;
+}
+
+#ifndef MODULE
+/*
+** ISA bus I/O device probe
+*/
+static struct device *isa_probe(struct device *dev)
+{
+  int i, iobase, status;
+  unsigned long int tmp = mem_chkd;
+
+  for (status = -ENODEV, iobase = EWRK3_IO_BASE,i = 0; 
+       i < 24;
+       iobase += EWRK3_IOP_INC, i++) {
+    if (tmp & 0x01) {
+      if (DevicePresent(iobase) == 0) {
+/*
+** Device found. Mark its (I/O) location for future reference. Only 24
+** EtherWORKS devices can exist between 0x100 and 0x3e0.
+*/
+       if (num_ewrk3s > 0) {        /* only gets here in autoprobe */
+         dev = alloc_device(dev, iobase);
+       } else {
+         if ((status = ewrk3_hw_init(dev, iobase)) == 0) {
+           num_ewrk3s++;
+         }
+       }
+       num_eth++;
+      } else {
+       mem_chkd &= ~(0x01 << ((iobase - EWRK3_IO_BASE)/EWRK3_IOP_INC));
+      }
+    }
+    tmp >>= 1;
+  }
+
+  return dev;
+}
+
+/*
+** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
+** the motherboard.
+*/
+static struct device *eisa_probe(struct device *dev)
+{
+  int i, iobase = EWRK3_EISA_IO_PORTS;
+  int status;
+
+  iobase+=EISA_SLOT_INC;            /* get the first slot address */
+  for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+
+    if (DevicePresent(iobase) == 0) {
+/*
+** Device found. Mark its slot location for future reference. Only 7
+** EtherWORKS devices can exist in EISA space....
+*/
+      mem_chkd |= (0x01 << (i + 24));
+      if (num_ewrk3s > 0) {        /* only gets here in autoprobe */
+       dev = alloc_device(dev, iobase);
+      } else {
+       if ((status = ewrk3_hw_init(dev, iobase)) == 0) {
+         num_ewrk3s++;
+       }
+      }
+      num_eth++;
+    }
+  }
+  return dev;
+}
+
+/*
+** Allocate the device by pointing to the next available space in the
+** device structure. Should one not be available, it is created.
+*/
+static struct device *alloc_device(struct device *dev, int iobase)
+{
+  /*
+  ** Check the device structures for an end of list or unused device
+  */
+  while (dev->next != NULL) {
+    if (dev->next->base_addr == 0xffe0) break;
+    dev = dev->next;         /* walk through eth device list */
+    num_eth++;               /* increment eth device number */
+  }
+
+  /*
+  ** If no more device structures, malloc one up. If memory could
+  ** not be allocated, print an error message.
+  */
+  if (dev->next == NULL) {
+    dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+                                        GFP_KERNEL);
+    if (dev->next == NULL) {
+      printk("eth%d: Device not initialised, insufficient memory\n",
+            num_eth);
+    }
+  }
+  
+  /*
+  ** If the memory was allocated, point to the new memory area
+  ** and initialize it (name, I/O address, next device (NULL) and
+  ** initialisation probe routine).
+  */
+  if ((dev->next != NULL) &&
+      (num_eth > 0) && (num_eth < 9999)) {
+    dev = dev->next;                    /* point to the new device */
+    dev->name = (char *)(dev + sizeof(struct device));
+    sprintf(dev->name,"eth%d", num_eth);/* New device name */
+    dev->base_addr = iobase;            /* assign the io address */
+    dev->next = NULL;                   /* mark the end of list */
+    dev->init = &ewrk3_probe;           /* initialisation routine */
+    num_ewrk3s++;
+  }
+
+  return dev;
+}
+#endif    /* MODULE */
+
+/*
+** Read the EWRK3 EEPROM using this routine
+*/
+static int Read_EEPROM(short iobase, unsigned char eaddr)
+{
+  int i;
+
+  outb((eaddr & 0x3f), EWRK3_PIR1);     /* set up 6 bits of address info */
+  outb(EEPROM_RD, EWRK3_IOPR);          /* issue read command */
+  for (i=0;i<5000;i++) inb(EWRK3_CSR);  /* wait 1msec */
+
+  return inw(EWRK3_EPROM1);             /* 16 bits data return */
+}
+
+/*
+** Write the EWRK3 EEPROM using this routine
+*/
+static int Write_EEPROM(short data, short iobase, unsigned char eaddr)
+{
+  int i;
+
+  outb(EEPROM_WR_EN, EWRK3_IOPR);       /* issue write enable command */
+  for (i=0;i<5000;i++) inb(EWRK3_CSR);  /* wait 1msec */
+  outw(data, EWRK3_EPROM1);             /* write data to register */
+  outb((eaddr & 0x3f), EWRK3_PIR1);     /* set up 6 bits of address info */
+  outb(EEPROM_WR, EWRK3_IOPR);          /* issue write command */
+  for (i=0;i<75000;i++) inb(EWRK3_CSR); /* wait 15msec */
+  outb(EEPROM_WR_DIS, EWRK3_IOPR);      /* issue write disable command */
+  for (i=0;i<5000;i++) inb(EWRK3_CSR);  /* wait 1msec */
+
+  return 0;
+}
+
+/*
+** Look for a particular board name in the on-board EEPROM.
+*/
+static void EthwrkSignature(char *name, char *eeprom_image)
+{
+  unsigned long i,j,k;
+  char signatures[][EWRK3_NAME_LENGTH] = EWRK3_SIGNATURE;
+
+  strcpy(name, "");
+  for (i=0;*signatures[i] != '\0' && *name == '\0';i++) {
+    for (j=EEPROM_PNAME7,k=0;j<=EEPROM_PNAME0 && k<strlen(signatures[i]);j++) {
+      if (signatures[i][k] == eeprom_image[j]) {          /* track signature */
+       k++;
+      } else {                         /* lost signature; begin search again */
+       k=0;
+      }
+    }
+    if (k == strlen(signatures[i])) {
+      for (k=0; k<EWRK3_NAME_LENGTH; k++) {
+       name[k] = eeprom_image[EEPROM_PNAME7 + k];
+       name[EWRK3_NAME_LENGTH] = '\0';
+      }
+    }
+  }
+
+  return;                                   /* return the device name string */
+}
+
+/*
+** Look for a special sequence in the Ethernet station address PROM that
+** is common across all EWRK3 products.
+*/
+
+static int DevicePresent(short iobase)
+{
+  static short fp=1,sigLength=0;
+  static char devSig[] = PROBE_SEQUENCE;
+  char data;
+  int i, j, status = 0;
+  static char asc2hex(char value);
+
+/* 
+** Convert the ascii signature to a hex equivalent & pack in place 
+*/
+  if (fp) {                               /* only do this once!... */
+    for (i=0,j=0;devSig[i] != '\0' && !status;i+=2,j++) {
+      if ((devSig[i]=asc2hex(devSig[i]))>=0) {
+       devSig[i]<<=4;
+       if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){
+         devSig[j]=devSig[i]+devSig[i+1];
+       } else {
+         status= -1;
+       }
+      } else {
+       status= -1;
+      }
+    }
+    sigLength=j;
+    fp = 0;
+  }
+
+/* 
+** Search the Ethernet address ROM for the signature. Since the ROM address
+** counter can start at an arbitrary point, the search must include the entire
+** probe sequence length plus the (length_of_the_signature - 1).
+** Stop the search IMMEDIATELY after the signature is found so that the
+** PROM address counter is correctly positioned at the start of the
+** ethernet address for later read out.
+*/
+  if (!status) {
+    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+      data = inb(EWRK3_APROM);
+      if (devSig[j] == data) {    /* track signature */
+       j++;
+      } else {                    /* lost signature; begin search again */
+       j=0;
+      }
+    }
+
+    if (j!=sigLength) {
+      status = -ENODEV;           /* search failed */
+    }
+  }
+
+  return status;
+}
+
+static unsigned char aprom_crc(struct device *dev, unsigned char *eeprom_image, char chipType)
+{
+  long k;
+  unsigned short j,chksum;
+  unsigned char crc, lfsr, sd, status = 0;
+  int iobase = dev->base_addr;
+
+  if (chipType == LeMAC2) {
+    for (crc=0x6a, j=0; j<ETH_ALEN; j++) {
+      for (sd=inb(EWRK3_PAR0+j), k=0; k<8; k++, sd >>= 1) {
+       lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7;
+       crc = (crc >> 1) + lfsr;
+      }
+    }
+    if (crc != eeprom_image[EEPROM_PA_CRC]) status = -1;
+  } else {
+    for (k=0,j=0;j<3;j++) {
+      k <<= 1 ;
+      if (k > 0xffff) k-=0xffff;
+      k += inw(EWRK3_PAR0 + (j<<1));
+      if (k > 0xffff) k-=0xffff;
+    }
+    if (k == 0xffff) k=0;
+    chksum = inb(EWRK3_APROM);
+    chksum |= (inb(EWRK3_APROM)<<8);
+    if (k != chksum) status = -1;
+  }
+
+  return status;
+}
+
+/*
+** Perform IOCTL call functions here. Some are privileged operations and the
+** effective uid is checked in those cases.
+*/
+static int ewrk3_ioctl(struct device *dev, struct ifreq *rq)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data;
+  int i, j, iobase = dev->base_addr, status = 0;
+  unsigned char csr;
+  union {
+    unsigned char addr[HASH_TABLE_LEN * ETH_ALEN];
+    unsigned short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+  } tmp;
+
+  switch(ioc->cmd) {
+  case EWRK3_GET_HWADDR:             /* Get the hardware address */
+    for (i=0; i<ETH_ALEN; i++) {
+      tmp.addr[i] = dev->dev_addr[i];
+    }
+    ioc->len = ETH_ALEN;
+    memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+
+    break;
+  case EWRK3_SET_HWADDR:             /* Set the hardware address */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr |= (TXD|RXD);
+      outb(csr, EWRK3_CSR);                  /* Disable the TX and RX */
+
+      memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+      for (i=0; i<ETH_ALEN; i++) {
+       dev->dev_addr[i] = tmp.addr[i];
+       outb(tmp.addr[i], EWRK3_PAR0 + i);
+      }
+
+      csr &= ~(TXD|RXD);                       /* Enable the TX and RX */
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_SET_PROM:               /* Set Promiscuous Mode */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr |= PME;
+      csr &= ~MCE;
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_CLR_PROM:               /* Clear Promiscuous Mode */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr &= ~PME;
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_SAY_BOO:                /* Say "Boo!" to the kernel log file */
+    printk("%s: Boo!\n", dev->name);
+
+    break;
+  case EWRK3_GET_MCA:                /* Get the multicast address table */
+    while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+    if (lp->shmem_length == IO_ONLY) {
+      outb(0, EWRK3_IOPR);
+      outw(PAGE0_HTE, EWRK3_PIR1);
+      for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+       tmp.addr[i] = inb(EWRK3_DATA);
+      }
+    } else {
+      outb(0, EWRK3_MPR);
+      memcpy(tmp.addr, (char *)(lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3));
+    }
+    ioc->len = (HASH_TABLE_LEN >> 3);
+    memcpy_tofs(ioc->data, tmp.addr, ioc->len); 
+    lp->lock = 0;                               /* Unlock the page register */
+
+    break;
+  case EWRK3_SET_MCA:                /* Set a multicast address */
+    if (suser()) {
+      if (ioc->len != HASH_TABLE_LEN) {         /* MCA changes */
+       memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+      }
+      set_multicast_list(dev, ioc->len, tmp.addr);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_CLR_MCA:                /* Clear all multicast addresses */
+    if (suser()) {
+      set_multicast_list(dev, 0, NULL);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_MCA_EN:                 /* Enable multicast addressing */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr |= MCE;
+      csr &= ~PME;
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_STATS:              /* Get the driver statistics */
+    cli();
+    memcpy_tofs(ioc->data, &lp->pktStats, sizeof(lp->pktStats)); 
+    ioc->len = EWRK3_PKT_STAT_SZ;
+    sti();
+
+    break;
+  case EWRK3_CLR_STATS:              /* Zero out the driver statistics */
+    if (suser()) {
+      cli();
+      memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+      sti();
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_CSR:                /* Get the CSR Register contents */
+    tmp.addr[0] = inb(EWRK3_CSR);
+    memcpy_tofs(ioc->data, tmp.addr, 1);
+
+    break;
+  case EWRK3_SET_CSR:                /* Set the CSR Register contents */
+    if (suser()) {
+      memcpy_fromfs(tmp.addr, ioc->data, 1);
+      outb(tmp.addr[0], EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_EEPROM:             /* Get the EEPROM contents */
+    if (suser()) {
+      for (i=0; i<(EEPROM_MAX>>1); i++) {
+       tmp.val[i] = (short)Read_EEPROM(iobase, i);
+      }
+      i = EEPROM_MAX;
+      tmp.addr[i++] = inb(EWRK3_CMR);            /* Config/Management Reg. */
+      for (j=0;j<ETH_ALEN;j++) {
+       tmp.addr[i++] = inb(EWRK3_PAR0 + j);
+      }
+      ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_SET_EEPROM:             /* Set the EEPROM contents */
+    if (suser()) {
+      memcpy_fromfs(tmp.addr, ioc->data, EEPROM_MAX);
+      for (i=0; i<(EEPROM_MAX>>1); i++) {
+       Write_EEPROM(tmp.val[i], iobase, i);
+      }
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_CMR:                /* Get the CMR Register contents */
+    tmp.addr[0] = inb(EWRK3_CMR);
+    memcpy_tofs(ioc->data, tmp.addr, 1);
+
+    break;
+  case EWRK3_SET_TX_CUT_THRU:        /* Set TX cut through mode */
+    if (suser()) {
+      lp->txc = 1;
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_CLR_TX_CUT_THRU:        /* Clear TX cut through mode */
+    if (suser()) {
+      lp->txc = 0;
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  default:
+    status = -EOPNOTSUPP;
+  }
+
+  return status;
+}
+
+static char asc2hex(char value)
+{
+  value -= 0x30;                  /* normalise to 0..9 range */
+  if (value >= 0) {
+    if (value > 9) {              /* but may not be 10..15 */
+      value &= 0x1f;              /* make A..F & a..f be the same */
+      value -= 0x07;              /* normalise to 10..15 range */
+      if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */
+       value = -1;               /* ...signal error */
+      }
+    }
+  } else {                        /* outside 0..9 range... */
+    value = -1;                   /* ...signal error */
+  }
+  return value;                   /* return hex char or error */
+}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device thisEthwrk = {
+  "        ", /* device name inserted by /linux/drivers/net/net_init.c */
+  0, 0, 0, 0,
+  0x300, 5,  /* I/O address, IRQ <--- EDIT THIS LINE FOR YOUR CONFIGURATION */
+  0, 0, 0, NULL, ewrk3_probe };
+       
+int
+init_module(void)
+{
+  if (register_netdev(&thisEthwrk) != 0)
+    return -EIO;
+  return 0;
+}
+
+void
+cleanup_module(void)
+{
+  if (MOD_IN_USE) {
+    printk("%s: device busy, remove delayed\n",thisEthwrk.name);
+  } else {
+    unregister_netdev(&thisEthwrk);
+  }
+}
+#endif /* MODULE */
+
+\f
+/*
+ * Local variables:
+ *  kernel-compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c"
+ *
+ *  module-compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c"
+ * End:
+ */
+
+
+
diff --git a/drivers/net/ewrk3.h b/drivers/net/ewrk3.h
new file mode 100644 (file)
index 0000000..7625a0c
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 Digital Equipment Corporation.
+
+    This software may be used and distributed according to  the terms of the
+    GNU Public License, incorporated herein by reference.
+
+    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
+    Equipment Corporation, 550 King Street, Littleton MA 01460.
+
+    =========================================================================
+*/
+
+/*
+** I/O Address Register Map
+*/
+#define EWRK3_CSR    iobase+0x00   /* Control and Status Register */
+#define EWRK3_CR     iobase+0x01   /* Control Register */
+#define EWRK3_ICR    iobase+0x02   /* Interrupt Control Register */
+#define EWRK3_TSR    iobase+0x03   /* Transmit Status Register */
+#define EWRK3_RSVD1  iobase+0x04   /* RESERVED */
+#define EWRK3_RSVD2  iobase+0x05   /* RESERVED */
+#define EWRK3_FMQ    iobase+0x06   /* Free Memory Queue */
+#define EWRK3_FMQC   iobase+0x07   /* Free Memory Queue Counter */
+#define EWRK3_RQ     iobase+0x08   /* Receive Queue */
+#define EWRK3_RQC    iobase+0x09   /* Receive Queue Counter */
+#define EWRK3_TQ     iobase+0x0a   /* Transmit Queue */
+#define EWRK3_TQC    iobase+0x0b   /* Transmit Queue Counter */
+#define EWRK3_TDQ    iobase+0x0c   /* Transmit Done Queue */
+#define EWRK3_TDQC   iobase+0x0d   /* Transmit Done Queue Counter */
+#define EWRK3_PIR1   iobase+0x0e   /* Page Index Register 1 */
+#define EWRK3_PIR2   iobase+0x0f   /* Page Index Register 2 */
+#define EWRK3_DATA   iobase+0x10   /* Data Register */
+#define EWRK3_IOPR   iobase+0x11   /* I/O Page Register */
+#define EWRK3_IOBR   iobase+0x12   /* I/O Base Register */
+#define EWRK3_MPR    iobase+0x13   /* Memory Page Register */
+#define EWRK3_MBR    iobase+0x14   /* Memory Base Register */
+#define EWRK3_APROM  iobase+0x15   /* Address PROM */
+#define EWRK3_EPROM1 iobase+0x16   /* EEPROM Data Register 1 */
+#define EWRK3_EPROM2 iobase+0x17   /* EEPROM Data Register 2 */
+#define EWRK3_PAR0   iobase+0x18   /* Physical Address Register 0 */
+#define EWRK3_PAR1   iobase+0x19   /* Physical Address Register 1 */
+#define EWRK3_PAR2   iobase+0x1a   /* Physical Address Register 2 */
+#define EWRK3_PAR3   iobase+0x1b   /* Physical Address Register 3 */
+#define EWRK3_PAR4   iobase+0x1c   /* Physical Address Register 4 */
+#define EWRK3_PAR5   iobase+0x1d   /* Physical Address Register 5 */
+#define EWRK3_CMR    iobase+0x1e   /* Configuration/Management Register */
+
+/*
+** Control Page Map
+*/
+#define PAGE0_FMQ     0x000         /* Free Memory Queue */
+#define PAGE0_RQ      0x080         /* Receive Queue */
+#define PAGE0_TQ      0x100         /* Transmit Queue */
+#define PAGE0_TDQ     0x180         /* Transmit Done Queue */
+#define PAGE0_HTE     0x200         /* Hash Table Entries */
+#define PAGE0_RSVD    0x240         /* RESERVED */
+#define PAGE0_USRD    0x600         /* User Data */
+
+/*
+** Control and Status Register bit definitions (EWRK3_CSR)
+*/
+#define RA             0x80        /* Runt Accept */
+#define PME            0x40        /* Promiscuous Mode Enable */
+#define MCE            0x20        /* Multicast Enable */ 
+#define TNE            0x08        /* TX Done Queue Not Empty */
+#define RNE            0x04        /* RX Queue Not Empty */
+#define TXD            0x02        /* TX Disable */
+#define RXD            0x01        /* RX Disable */
+
+/*
+** Control Register bit definitions (EWRK3_CR)
+*/
+#define APD            0x80    /* Auto Port Disable */
+#define PSEL           0x40    /* Port Select (0->TP port) */
+#define LBCK           0x20    /* LoopBaCK enable */
+#define FDUP           0x10    /* Full DUPlex enable */
+#define FBUS           0x08    /* Fast BUS enable (ISA clk > 8.33MHz) */
+#define EN_16          0x04    /* ENable 16 bit memory accesses */
+#define LED            0x02    /* LED (1-> turn on) */
+
+/*
+** Interrupt Control Register bit definitions (EWRK3_ICR)
+*/
+#define IE             0x80    /* Interrupt Enable */
+#define IS             0x60    /* Interrupt Selected */
+#define TNEM           0x08    /* TNE Mask (0->mask) */
+#define RNEM           0x04    /* RNE Mask (0->mask) */
+#define TXDM           0x02    /* TXD Mask (0->mask) */
+#define RXDM           0x01    /* RXD Mask (0->mask) */
+
+/*
+** Transmit Status Register bit definitions (EWRK3_TSR)
+*/
+#define NCL            0x80    /* No Carrier Loopback */
+#define ID             0x40    /* Initially Deferred */
+#define LCL            0x20    /* Late CoLlision */
+#define ECL            0x10    /* Excessive CoLlisions */
+#define RCNTR          0x0f    /* Retries CouNTeR */
+
+/*
+** I/O Page Register bit definitions (EWRK3_IOPR)
+*/
+#define EEPROM_INIT    0xc0    /* EEPROM INIT command */
+#define EEPROM_WR_EN   0xc8    /* EEPROM WRITE ENABLE command */
+#define EEPROM_WR      0xd0    /* EEPROM WRITE command */
+#define EEPROM_WR_DIS  0xd8    /* EEPROM WRITE DISABLE command */
+#define EEPROM_RD      0xe0    /* EEPROM READ command */
+
+/*
+** I/O Base Register bit definitions (EWRK3_IOBR)
+*/
+#define EISA           0x20    /* Enable EISA ID and Control Registers */
+#define IOB            0x1f    /* Compare bits for I/O Base Address */
+
+/*
+** I/O Congiguration/Management Register bit definitions (EWRK3_CMR)
+*/
+#define RA              0x80    /* Read Ahead */
+#define WB              0x40    /* Write Behind */
+#define LINK           0x20    /* 0->TP */
+#define POLARITY       0x10    /* Informational */
+#define NO_EEPROM      0x0c    /* NO_EEPROM<1:0> pin status */
+#define HS             0x08    /* Hard Strapped pin status (LeMAC2) */
+#define PNP             0x04    /* Plug 'n Play */
+#define DRAM           0x02    /* 0-> 1DRAM, 1-> 2 DRAM on board */
+#define _0WS            0x01    /* Zero Wait State */
+
+/* 
+** MAC Receive Status Register bit definitions
+*/
+
+#define ROK            0x80    /* Receive OK summary */
+#define IAM            0x10    /* Individual Address Match */
+#define MCM            0x08    /* MultiCast Match */
+#define DBE            0x04    /* Dribble Bit Error */
+#define CRC            0x02    /* CRC error */
+#define PLL            0x01    /* Phase Lock Lost */
+
+/* 
+** MAC Transmit Control Register bit definitions
+*/
+
+#define SQEE           0x40    /* SQE Enable - look for heartbeat  */
+#define SED            0x20    /* Stop when Error Detected */
+#define QMODE          0x10    /* Q_MODE */
+#define LAB             0x08   /* Less Aggressive Backoff */
+#define PAD            0x04    /* PAD Runt Packets */
+#define IFC            0x02    /* Insert Frame Check */
+#define ISA            0x01    /* Insert Source Address */
+
+/* 
+** MAC Transmit Status Register bit definitions
+*/
+
+#define VSTS           0x80    /* Valid STatuS */
+#define MAC_CTU        0x40    /* Cut Through Used */
+#define MAC_SQE        0x20    /* Signal Quality Error */
+#define MAC_NCL        0x10    /* No Carrier Loopback */
+#define MAC_LCL         0x08   /* Late Collision */
+#define MAC_ID         0x04    /* Initially Deferred */
+#define MAC_COLL       0x03    /* COLLision status */
+#define MAC_XCOLL       0x03    /* Excessive Collisions */
+#define MAC_MCOLL       0x02    /* Multiple Collisions */
+#define MAC_OCOLL       0x01    /* One Collision */
+#define MAC_NOCOLL      0x00    /* No Collisions */
+#define MAC_XUR         0x03    /* Excessive Underruns */
+#define MAC_TXE         0x7f    /* TX Errors */
+
+/* 
+** EISA Configuration Register bit definitions 
+*/
+
+#define EISA_ID0      iobase + 0x0c80  /* EISA ID Register 0 */ 
+#define EISA_ID1      iobase + 0x0c81  /* EISA ID Register 1 */ 
+#define EISA_ID2      iobase + 0x0c82  /* EISA ID Register 2 */ 
+#define EISA_ID3      iobase + 0x0c83  /* EISA ID Register 3 */ 
+#define EISA_CR       iobase + 0x0c84  /* EISA Control Register */
+
+/*
+** EEPROM BYTES
+*/
+#define EEPROM_MEMB     0x00
+#define EEPROM_IOB      0x01
+#define EEPROM_EISA_ID0 0x02
+#define EEPROM_EISA_ID1 0x03
+#define EEPROM_EISA_ID2 0x04
+#define EEPROM_EISA_ID3 0x05
+#define EEPROM_MISC0    0x06
+#define EEPROM_MISC1    0x07
+#define EEPROM_PNAME7   0x08
+#define EEPROM_PNAME6   0x09
+#define EEPROM_PNAME5   0x0a
+#define EEPROM_PNAME4   0x0b
+#define EEPROM_PNAME3   0x0c
+#define EEPROM_PNAME2   0x0d
+#define EEPROM_PNAME1   0x0e
+#define EEPROM_PNAME0   0x0f
+#define EEPROM_SWFLAGS  0x10
+#define EEPROM_HWCAT    0x11
+#define EEPROM_NETMAN2  0x12
+#define EEPROM_REVLVL   0x13
+#define EEPROM_NETMAN0  0x14
+#define EEPROM_NETMAN1  0x15
+#define EEPROM_CHIPVER  0x16
+#define EEPROM_SETUP    0x17
+#define EEPROM_PADDR0   0x18
+#define EEPROM_PADDR1   0x19
+#define EEPROM_PADDR2   0x1a
+#define EEPROM_PADDR3   0x1b
+#define EEPROM_PADDR4   0x1c
+#define EEPROM_PADDR5   0x1d
+#define EEPROM_PA_CRC   0x1e
+#define EEPROM_CHKSUM   0x1f
+
+/*
+** EEPROM bytes for checksumming
+*/
+#define EEPROM_MAX      32             /* bytes */
+
+/*
+** EEPROM MISCELLANEOUS FLAGS
+*/
+#define RBE_SHADOW     0x0100  /* Remote Boot Enable Shadow */ 
+#define READ_AHEAD      0x0080  /* Read Ahead feature */
+#define IRQ_SEL2        0x0070  /* IRQ line selection (LeMAC2) */
+#define IRQ_SEL         0x0060  /* IRQ line selection */
+#define FAST_BUS        0x0008  /* ISA Bus speeds > 8.33MHz */
+#define ENA_16          0x0004  /* Enables 16 bit memory transfers */
+#define WRITE_BEHIND    0x0002  /* Write Behind feature */
+#define _0WS_ENA        0x0001  /* Zero Wait State Enable */
+
+/*
+** EEPROM NETWORK MANAGEMENT FLAGS
+*/
+#define NETMAN_POL      0x04    /* Polarity defeat */
+#define NETMAN_LINK     0x02    /* Link defeat */
+#define NETMAN_CCE      0x01    /* Custom Counters Enable */
+
+/*
+** EEPROM SW FLAGS
+*/
+#define SW_SQE         0x10    /* Signal Quality Error */ 
+#define SW_LAB         0x08    /* Less Aggressive Backoff */
+#define SW_INIT                0x04    /* Initialized */
+#define SW_TIMEOUT             0x02    /* 0:2.5 mins, 1: 30 secs */
+#define SW_REMOTE              0x01    /* Remote Boot Enable -> 1 */
+
+/*
+** EEPROM SETUP FLAGS
+*/
+#define SETUP_APD      0x80    /* AutoPort Disable */
+#define SETUP_PS       0x40    /* Port Select */
+#define SETUP_MP       0x20    /* MultiPort */
+#define SETUP_1TP      0x10    /* 1 port, TP */
+#define SETUP_1COAX    0x00    /* 1 port, Coax */
+#define SETUP_DRAM     0x02    /* Number of DRAMS on board */
+
+/*
+** EEPROM MANAGEMENT FLAGS
+*/
+#define MGMT_CCE       0x01    /* Custom Counters Enable */
+
+/*
+** EEPROM VERSIONS
+*/
+#define LeMAC           0x11
+#define LeMAC2          0x12
+
+/*
+** Miscellaneous
+*/
+
+#define EEPROM_WAIT_TIME 1000    /* Number of microseconds */
+#define EISA_EN         0x0001   /* Enable EISA bus buffers */
+
+#define HASH_TABLE_LEN   512     /* Bits */
+
+#define XCT 0x80                 /* Transmit Cut Through */
+#define PRELOAD 16               /* 4 long words */
+
+#define MASK_INTERRUPTS   1
+#define UNMASK_INTERRUPTS 0
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define        EWRK3IOCTL      SIOCDEVPRIVATE
+
+struct ewrk3_ioctl {
+       unsigned short cmd;                /* Command to run */
+       unsigned short len;                /* Length of the data buffer */
+       unsigned char  *data;              /* Pointer to the data buffer */
+};
+
+/* 
+** Recognised commands for the driver 
+*/
+#define EWRK3_GET_HWADDR       0x01 /* Get the hardware address */
+#define EWRK3_SET_HWADDR       0x02 /* Get the hardware address */
+#define EWRK3_SET_PROM         0x03 /* Set Promiscuous Mode */
+#define EWRK3_CLR_PROM         0x04 /* Clear Promiscuous Mode */
+#define EWRK3_SAY_BOO          0x05 /* Say "Boo!" to the kernel log file */
+#define EWRK3_GET_MCA          0x06 /* Get a multicast address */
+#define EWRK3_SET_MCA          0x07 /* Set a multicast address */
+#define EWRK3_CLR_MCA          0x08 /* Clear a multicast address */
+#define EWRK3_MCA_EN           0x09 /* Enable a multicast address group */
+#define EWRK3_GET_STATS        0x0a /* Get the driver statistics */
+#define EWRK3_CLR_STATS        0x0b /* Zero out the driver statistics */
+#define EWRK3_GET_CSR          0x0c /* Get the CSR Register contents */
+#define EWRK3_SET_CSR          0x0d /* Set the CSR Register contents */
+#define EWRK3_GET_EEPROM       0x0e /* Get the EEPROM contents */
+#define EWRK3_SET_EEPROM       0x0f /* Set the EEPROM contents */
+#define EWRK3_GET_CMR          0x10 /* Get the CMR Register contents */
+#define EWRK3_CLR_TX_CUT_THRU          0x11 /* Clear the TX cut through mode */
+#define EWRK3_SET_TX_CUT_THRU  0x12 /* Set the TX cut through mode */
index 387d65cc81f3af77b74e0aca75095299f75e0e71..7344d34e3cd7bdeb0a95547a5ddff857ae0e5b5a 100644 (file)
@@ -24,7 +24,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
        loff_t offset;
        int chars;
        int written = 0;
-       int cluster_list[4];
+       int cluster_list[8];
        struct buffer_head * bhlist[NBUF];
        int blocks_per_cluster;
        unsigned int size;
@@ -159,7 +159,7 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
        int blocksize_bits, i;
        unsigned int blocks, rblocks, left;
        int bhrequest, uptodate;
-       int cluster_list[4];
+       int cluster_list[8];
        int blocks_per_cluster;
        struct buffer_head ** bhb, ** bhe;
        struct buffer_head * buflist[NBUF];
index da27827b8a68196de5b21f087b15020103f25868..2aeb538ee69a52770d2b64eeb5fc0004a6b3710c 100644 (file)
@@ -122,6 +122,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
        if (32 != sizeof (struct minix_inode))
                panic("bad i-node size");
        lock_super(s);
+       set_blocksize(dev, BLOCK_SIZE);
        if (!(bh = bread(dev,1,BLOCK_SIZE))) {
                s->s_dev=0;
                unlock_super(s);
index 9ddcdc76470fa9ef9b5f9a3345d459a3704aaed3..651e58b2446171125238bdfe6d244378efb41e59 100644 (file)
@@ -20,7 +20,6 @@ int fat_access(struct super_block *sb,int nr,int new_value)
 {
        struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
        unsigned char *p_first,*p_last;
-       void *data,*data2,*c_data,*c_data2;
        int first,last,next,copy;
 
        if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0;
@@ -30,17 +29,15 @@ int fat_access(struct super_block *sb,int nr,int new_value)
                last = first+1;
        }
        if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
-           SECTOR_BITS),&data))) {
+           SECTOR_BITS)))) {
                printk("bread in fat_access failed\n");
                return 0;
        }
-       if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) {
+       if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
                bh2 = bh;
-               data2 = data;
-       }
        else {
                if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
-                   >> SECTOR_BITS),&data2))) {
+                   >> SECTOR_BITS)))) {
                        brelse(bh);
                        printk("bread in fat_access failed\n");
                        return 0;
@@ -48,13 +45,13 @@ int fat_access(struct super_block *sb,int nr,int new_value)
        }
        if (MSDOS_SB(sb)->fat_bits == 16) {
                p_first = p_last = NULL; /* GCC needs that stuff */
-               next = CF_LE_W(((unsigned short *) data)[(first &
+               next = CF_LE_W(((unsigned short *) bh->b_data)[(first &
                    (SECTOR_SIZE-1)) >> 1]);
                if (next >= 0xfff7) next = -1;
        }
        else {
-               p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)];
-               p_last = &((unsigned char *) data2)[(first+1) &
+               p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)];
+               p_last = &((unsigned char *) bh2->b_data)[(first+1) &
                    (SECTOR_SIZE-1)];
                if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
                else next = (*p_first+(*p_last << 8)) & 0xfff;
@@ -62,7 +59,7 @@ int fat_access(struct super_block *sb,int nr,int new_value)
        }
        if (new_value != -1) {
                if (MSDOS_SB(sb)->fat_bits == 16)
-                       ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >>
+                       ((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
                            1] = CT_LE_W(new_value);
                else {
                        if (nr & 1) {
@@ -79,25 +76,25 @@ int fat_access(struct super_block *sb,int nr,int new_value)
                for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
                        if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->
                            fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
-                           fat_length*copy,&c_data))) break;
-                       memcpy(c_data,data,SECTOR_SIZE);
+                           fat_length*copy))) break;
+                       memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
                        mark_buffer_dirty(c_bh, 1);
-                       if (data != data2 || bh != bh2) {
+                       if (bh != bh2) {
                                if (!(c_bh2 = msdos_sread(sb->s_dev,
                                    MSDOS_SB(sb)->fat_start+(first >>
                                    SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
-                                   +1,&c_data2))) {
+                                   +1))) {
                                        brelse(c_bh);
                                        break;
                                }
-                               memcpy(c_data2,data2,SECTOR_SIZE);
+                               memcpy(c_bh2->b_data,bh2->b_data,SECTOR_SIZE);
                                brelse(c_bh2);
                        }
                        brelse(c_bh);
                }
        }
        brelse(bh);
-       if (data != data2) brelse(bh2);
+       if (bh != bh2) brelse(bh2);
        return next;
 }
 
index ce556aa72279b2b55c16c58fb78346e4d466da8e..8e62f2c70e886bb86d55dac5878b6c1d89bb30c7 100644 (file)
@@ -30,7 +30,7 @@ static struct file_operations msdos_file_operations = {
        NULL,                   /* readdir - bad */
        NULL,                   /* select - default */
        NULL,                   /* ioctl - default */
-       generic_mmap,   /* mmap */
+       generic_mmap,           /* mmap */
        NULL,                   /* no special open is needed */
        NULL,                   /* release */
        file_fsync              /* fsync */
@@ -52,7 +52,7 @@ struct inode_operations msdos_file_inode_operations = {
        msdos_bmap,             /* bmap */
        msdos_truncate,         /* truncate */
        NULL,                   /* permission */
-       NULL            /* smap */
+       NULL                    /* smap */
 };
 
 /*
@@ -127,12 +127,11 @@ int msdos_file_read(
                        int sector;
                        if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
                                break;
-                       if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
+                       if (!(bh = msdos_sread(inode->i_dev,sector)))
                                break;
                }else{
                        bh = pre.bhlist[pre.nolist];
                        pre.bhlist[pre.nolist++] = NULL;
-                       data = bh->b_data;
                        wait_on_buffer(bh);
                        if (!bh->b_uptodate){
                                /* read error  ? */
@@ -140,6 +139,7 @@ int msdos_file_read(
                                break;
                        }
                }
+               data = bh->b_data;
                offset = filp->f_pos & (SECTOR_SIZE-1);
                filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
                if (MSDOS_I(inode)->i_binary) {
@@ -183,7 +183,6 @@ int msdos_file_write(
        int error,carry;
        char *start,*to,ch;
        struct buffer_head *bh;
-       void *data;
        int binary_mode = MSDOS_I(inode)->i_binary;
 
        if (!inode) {
@@ -211,25 +210,28 @@ int msdos_file_write(
                }
                offset = filp->f_pos & (SECTOR_SIZE-1);
                size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
-               if (binary_mode && offset == 0 && size == SECTOR_SIZE){
+               if (binary_mode
+                       && offset == 0
+                       && (size == SECTOR_SIZE
+                               || filp->f_pos + size >= inode->i_size)){
                        /* No need to read the block first since we will */
                        /* completely overwrite it */
+                       /* or at least write past the end of file */
                        if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
                                error = -EIO;
                                break;
                        }
-                       data = bh->b_data;
-               }else if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
+               }else if (!(bh = msdos_sread(inode->i_dev,sector))) {
                        error = -EIO;
                        break;
                }
                if (binary_mode) {
-                       memcpy_fromfs(data+offset,buf,written = size);
+                       memcpy_fromfs(bh->b_data+offset,buf,written = size);
                        buf += size;
                }
                else {
                        written = left = SECTOR_SIZE-offset;
-                       to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1));
+                       to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
                        if (carry) {
                                *to++ = '\n';
                                left--;
index 73885c9e27d4d9f23bd637df8aa77d88dcf083d4..c2f4ae35f2bac256ad3d34bf6f1f1d509fa7e7ef 100644 (file)
@@ -172,20 +172,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data,
        }
        cache_init();
        lock_super(s);
-       if (MAJOR(s->s_dev) == FLOPPY_MAJOR){
-               /* Patch for floppy which lacks a table ??? */
-               static int tbdef[]={
-                       1024,1024,1024,1024,1024,
-                       1024,1024,1024,1024,1024,
-                       1024,1024,1024,1024,1024,
-                       1024,1024,1024,1024,1024,
-                       1024,1024,1024,1024,1024,
-                       1024,1024,1024,1024,1024,
-                       1024,1024,1024,1024,1024,
-               };
-               blksize_size[FLOPPY_MAJOR] = tbdef;
-       }
-       set_blocksize (s->s_dev,SECTOR_SIZE);
+       set_blocksize(s->s_dev, SECTOR_SIZE);
        bh = bread(s->s_dev, 0, SECTOR_SIZE);
        unlock_super(s);
        if (bh == NULL) {
index 9b1497fcfac2cd3523e89061181e9ddc1707620c..630198afa2859a406cfa85feee4921f9e691bff6 100644 (file)
@@ -256,7 +256,6 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
     struct msdos_dir_entry **de)
 {
        int sector,offset;
-       void *data;
 
        while (1) {
                offset = *pos;
@@ -270,12 +269,12 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
                if (*bh)
                        brelse(*bh);
                PRINTK (("get_entry sector apres brelse\n"));
-               if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
+               if (!(*bh = msdos_sread(dir->i_dev,sector))) {
                        printk("Directory sread (sector %d) failed\n",sector);
                        continue;
                }
                PRINTK (("get_entry apres sread\n"));
-               *de = (struct msdos_dir_entry *) (data+(offset &
+               *de = (struct msdos_dir_entry *) ((*bh)->b_data+(offset &
                    (SECTOR_SIZE-1)));
                return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
                    MSDOS_DIR_BITS);
@@ -344,7 +343,8 @@ static int raw_scan_sector(struct super_block *sb,int sector,char *name,
        struct inode *inode;
        int entry,start,done;
 
-       if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
+       if (!(bh = msdos_sread(sb->s_dev,sector))) return -EIO;
+       data = (struct msdos_dir_entry *) bh->b_data;
        for (entry = 0; entry < MSDOS_DPS; entry++) {
                if (name) RSS_NAME
                else {
index 9c3b43d9858fe5195fa83342fc6ff9e4d2be1e8a..5f457b9cb61f799d7e0a8c67cfc93fdfbc984a86 100644 (file)
@@ -33,7 +33,10 @@ asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int
                return -EBADF;
        error = -ENOTDIR;
        if (file->f_op && file->f_op->readdir) {
-               error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent));
+               int size = count;
+               if (count == 1)
+                       size = sizeof(*dirent);
+               error = verify_area(VERIFY_WRITE, dirent, size);
                if (!error)
                        error = file->f_op->readdir(inode,file,dirent,count);
        }
index 6a2d292b427836468d13db9933c9f5877eedda18..b0f5ef16bee30d1bcfa33e4ad157351bcb6ed129 100644 (file)
@@ -273,7 +273,13 @@ void UMSDOS_write_inode(struct inode *inode)
        newattrs.ia_atime = inode->i_atime;
        newattrs.ia_ctime = inode->i_ctime;
        newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
+       /*
+               UMSDOS_notify_change is convenient to call here
+               to update the EMD entry associated with this inode.
+               But it has the side effect to re"dirt" the inode.
+       */
        UMSDOS_notify_change (inode, &newattrs);
+       inode->i_dirt = 0;
 }
 
 int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
@@ -319,6 +325,7 @@ int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
                                struct file filp;
                                struct umsdos_dirent entry;
                                filp.f_pos = inode->u.umsdos_i.pos;
+                               filp.f_reada = 0;
                                PRINTK (("pos = %d ",filp.f_pos));
                                /* Read only the start of the entry since we don't touch */
                                /* the name */
index 089829481fb2be1c20f0b7e9c3c64bab944ba31e..4dee5cfbb7242bf280e0c724ef4ab1874e62ae3f 100644 (file)
@@ -35,7 +35,6 @@ static int find_first_zero(struct buffer_head *bh, int start_bit, int end_bit)
 
     int end, i, j, tmp;
     u_long *bmap;
-    char res;
 
     bmap=(u_long *)bh->b_data;
     end = end_bit >> 5;
index 7588dcb2c4c0e304bd77366c7e7593ef8a3138fe..f7e7d7b5c980cbd16f591ff7d0944528a7885b97 100644 (file)
@@ -377,10 +377,16 @@ struct cdrom_read_audio
                                                 /* read type-1 data            */
 /*
  * preliminary extension for transferring audio frames
- * currently used by sbpcd.c
+ * currently used by cdu31a.c and sbpcd.c
  * (still may change if other drivers will use it, too):
  */
 #define        CDROMREADAUDIO          0x530e          /* (struct cdrom_read_audio)    */
+/*
+ * preliminary extension for enable (1) / disable (0) auto-ejecting
+ * currently used by sbpcd.c
+ * (still may change if other drivers will use it, too):
+ */
+#define        CDROMEJECT_SW           0x530f          /* arg: 0 or 1 */
 
 #endif  _LINUX_CDROM_H
 
index 197c6aeb532b9baede46f63d4e5ebb67046b62df..a7a841724d683dc0b35994f56a8f1e15479efc8b 100644 (file)
@@ -39,7 +39,7 @@ struct ipc_perm
 #define IPC_NOID       ((void *) -2)           /* being allocated/destroyed */
 
 /* 
- * These are used to wrap system calls. See ipc/util.c, libipc.c 
+ * These are used to wrap system calls. See ipc/util.c.
  */
 struct ipc_kludge {
     struct msgbuf *msgp;
index 2909691d0b89b4e0ed5e0befa67107bb6165c9f5..dd6699a0d85310cc0987c7709a4be9c6eca939b5 100644 (file)
@@ -110,13 +110,9 @@ struct fat_cache {
 
 #ifdef __KERNEL__
 
-static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
+static inline struct buffer_head *msdos_sread(int dev,int sector)
 {
-       struct buffer_head *bh = bread(dev,sector, 512);
-       if (bh != NULL){
-               *start = bh->b_data;    /* From the time of 1024 bytes block */
-       }
-       return bh;
+       return bread(dev,sector,SECTOR_SIZE);
 }
 
 
index d345466cb0454811549a1ad08ae7a674175c2a93..f31a08038b5af961af3c066346aa453da7a7a8c5 100644 (file)
@@ -6,15 +6,6 @@
 #define MSG_NOERROR     010000  /* no error if message is too big */
 #define MSG_EXCEPT      020000  /* recv any msg except of specified type.*/
 
-
-/* one msg structure for each message */
-struct msg {
-    struct msg *msg_next;   /* next message on queue */
-    long  msg_type;          
-    char *msg_spot;         /* message text address */
-    short msg_ts;           /* message text size */
-};
-
 /* one msqid structure for each queue on the system */
 struct msqid_ds {
     struct ipc_perm msg_perm;
@@ -32,14 +23,13 @@ struct msqid_ds {
     ushort msg_lrpid;       /* last receive pid */
 };
 
-
 /* message buffer for msgsnd and msgrcv calls */
 struct msgbuf {
     long mtype;         /* type of message */
     char mtext[1];      /* message text */
 };
 
-
+/* buffer for msgctl calls IPC_INFO, MSG_INFO */
 struct msginfo {
     int msgpool;
     int msgmap; 
@@ -65,6 +55,14 @@ struct msginfo {
 
 #ifdef __KERNEL__
 
+/* one msg structure for each message */
+struct msg {
+    struct msg *msg_next;   /* next message on queue */
+    long  msg_type;          
+    char *msg_spot;         /* message text address */
+    short msg_ts;           /* message text size */
+};
+
 /* ipcs ctl commands */
 #define MSG_STAT 11
 #define MSG_INFO 12
index 935d1fbd2ee68e5642c9563e6643d57eb457b966..23b212d38b921fb4d073ee2956399de4b6e91a32 100644 (file)
@@ -290,7 +290,7 @@ struct task_struct {
        struct tty_struct *tty; /* NULL if no tty */
 /* shm stuff */
        struct shm_desc *shm;
-       struct sem_undo *semun;
+       struct sem_undo *semundo;
 /* ldt for this task - used by Wine.  If NULL, default_ldt is used */
        struct desc_struct *ldt;
 /* tss for this task */
index 02d535ff941f8a6bcb1ab24d4cd68b82d6d3b62c..52189879b822c3fdcf9a98ca8e8df5a1d9258339 100644 (file)
@@ -26,16 +26,7 @@ struct semid_ds {
   ushort          sem_nsems;      /* no. of semaphores in array */
 };
 
-
-/* One semaphore structure for each semaphore in the system. */
-struct sem {
-  short   sempid;         /* pid of last operation */
-  ushort  semval;         /* current value */
-  ushort  semncnt;        /* num procs awaiting increase in semval */
-  ushort  semzcnt;        /* num procs awaiting semval = 0 */
-};
-
-/* semop system calls takes an array of these.*/
+/* semop system calls takes an array of these. */
 struct sembuf {
   ushort  sem_num;        /* semaphore index in array */
   short   sem_op;         /* semaphore operation */
@@ -44,12 +35,13 @@ struct sembuf {
 
 /* arg for semctl system calls. */
 union semun {
-  int val;               /* value for SETVAL */
-  struct semid_ds *buf;  /* buffer for IPC_STAT & IPC_SET */
-  ushort *array;         /* array for GETALL & SETALL */
+  int val;                     /* value for SETVAL */
+  struct semid_ds *buf;                /* buffer for IPC_STAT & IPC_SET */
+  ushort *array;               /* array for GETALL & SETALL */
+  struct seminfo *__buf;       /* buffer for IPC_INFO */
+  void *__pad;
 };
 
-
 struct  seminfo {
     int semmap; 
     int semmni; 
@@ -77,6 +69,15 @@ struct  seminfo {
 #define SEMUSZ  20             /* sizeof struct sem_undo */ 
 
 #ifdef __KERNEL__
+
+/* One semaphore structure for each semaphore in the system. */
+struct sem {
+  short   sempid;         /* pid of last operation */
+  ushort  semval;         /* current value */
+  ushort  semncnt;        /* num procs awaiting increase in semval */
+  ushort  semzcnt;        /* num procs awaiting semval = 0 */
+};
+
 /* ipcs ctl cmds */
 #define SEM_STAT 18    
 #define SEM_INFO 19
index 4328318fafb540ead1793cf44b8a885f13045f50..8be580984bd046fdfca9d98363a8ad6341b03ebb 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/ipc.h>
 
 struct shmid_ds {
-       struct  ipc_perm shm_perm;      /* operation perms */
+       struct ipc_perm shm_perm;       /* operation perms */
        int     shm_segsz;              /* size of segment (bytes) */
        time_t  shm_atime;              /* last attach time */
        time_t  shm_dtime;              /* last detach time */
@@ -12,9 +12,9 @@ struct shmid_ds {
        unsigned short  shm_lpid;       /* pid of last operator */
        short   shm_nattch;             /* no. of current attaches */
        /* the following are private */
-       unsigned short   shm_npages;  /* size of segment (pages) */
-       unsigned long   *shm_pages;   /* array of ptrs to frames -> SHMMAX */ 
-       struct shm_desc *attaches;    /* descriptors for attaches */
+       unsigned short   shm_npages;    /* size of segment (pages) */
+       unsigned long   *shm_pages;     /* array of ptrs to frames -> SHMMAX */ 
+       struct shm_desc *attaches;      /* descriptors for attaches */
 };
 
 /* mode for attach */
@@ -34,34 +34,35 @@ struct      shminfo {
     int shmall;        
 };
 
+/* address range for shared memory attaches if no address passed to shmat() */
 #define SHM_RANGE_START        0x40000000
 #define SHM_RANGE_END  0x60000000
 
-                               /* _SHM_ID_BITS is a variable you can adjust to */
-                               /* tune the kernel.  It determines the value of */
-                               /* SHMMNI, which specifies the maximum no. of */
-                               /* shared segments (system wide).  SRB. */
-#define _SHM_ID_BITS   7               /* keep as low as possible */
-                                       /* a static array is declared */
-                                       /* using SHMMNI */
+/* format of page table entries that correspond to shared memory pages
+   currently out in swap space (see also mm/swap.c):
+   bit 0 (PAGE_PRESENT) is  = 0
+   bits 7..1 (SWP_TYPE) are = SHM_SWP_TYPE
+   bits 31..8 are used like this:
+   bits 14..8 (SHM_ID) the id of the shared memory segment
+   bits 29..15 (SHM_IDX) the index of the page within the shared memory segment
+                    (actually only bits 24..15 get used since SHMMAX is so low)
+   bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
+*/
 
-#define __SHM_IDX_BITS (BITS_PER_PTR-2-SHM_IDX_SHIFT)
-
-/* !!!!!!!?????
- * Why reserve the two (2) high bits of the signature (shm_sgn) field?
- * Since, as far as I can see, only the high bit is used (SHM_READ_ONLY).
- *                                             SRB.
- */
-
-#define _SHM_IDX_BITS  (__SHM_IDX_BITS+PAGE_SHIFT>=BITS_PER_PTR?\
- BITS_PER_PTR-PAGE_SHIFT-1:__SHM_IDX_BITS)     /* sanity check */
-
-/* not present page table entry format bit 0 is 0, low byte defined in mm.h */
 #define SHM_ID_SHIFT   8
+/* Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
+   there is a static array of size SHMMNI. */
+#define _SHM_ID_BITS   7
 #define SHM_ID_MASK    ((1<<_SHM_ID_BITS)-1)
+
 #define SHM_IDX_SHIFT  (SHM_ID_SHIFT+_SHM_ID_BITS)
+#define _SHM_IDX_BITS  15
 #define SHM_IDX_MASK   ((1<<_SHM_IDX_BITS)-1)
-#define SHM_READ_ONLY  (1<<(BITS_PER_PTR-1))
+
+#define SHM_READ_ONLY  (1<<31)
+
+/* We must have SHM_ID_SHIFT + _SHM_ID_BITS + _SHM_IDX_BITS + 1 <= 32
+   and SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS). */
 
 #define SHMMAX 0x3fa000                                /* max shared seg size (bytes) */
 #define SHMMIN 1        /* really PAGE_SIZE */ /* min shared seg size (bytes) */
@@ -106,4 +107,3 @@ struct      shm_desc {
 
 #endif /* _LINUX_SHM_H_ */
 
-
index aedbd4fd8f8e9a8c2cd3b7e827cc3410552867ca..04aa123280b09556c60ee1f4cdf77724bd8e3d8b 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -29,7 +29,7 @@ void msg_init (void)
 {
        int id;
        
-       for (id=0; id < MSGMNI; id++) 
+       for (id = 0; id < MSGMNI; id++) 
                msgque[id] = (struct msqid_ds *) IPC_UNUSED;
        msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
        msg_lock = NULL;
@@ -53,14 +53,14 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
                return err;
        if ((mtype = get_fs_long (&msgp->mtype)) < 1)
                return -EINVAL;
-       id = msqid % MSGMNI;
+       id = (unsigned int) msqid % MSGMNI;
        msq = msgque [id];
        if (msq == IPC_UNUSED || msq == IPC_NOID)
                return -EINVAL;
        ipcp = &msq->msg_perm; 
 
  slept:
-       if (ipcp->seq != (msqid / MSGMNI)
+       if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI
                return -EIDRM;
        if (ipcperms(ipcp, S_IWUGO)) 
                return -EACCES;
@@ -83,7 +83,7 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
        memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
        
        if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
-               || ipcp->seq != msqid / MSGMNI) {
+               || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
                kfree(msgh);
                return -EIDRM;
        }
@@ -125,7 +125,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
        if (err)
                return err;
 
-       id = msqid % MSGMNI;
+       id = (unsigned int) msqid % MSGMNI;
        msq = msgque [id];
        if (msq == IPC_NOID || msq == IPC_UNUSED)
                return -EINVAL;
@@ -138,7 +138,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
         *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
         */
        while (!nmsg) {
-               if(ipcp->seq != msqid / MSGMNI)
+               if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
                        return -EIDRM;
                if (ipcperms (ipcp, S_IRUGO))
                        return -EACCES;
@@ -174,7 +174,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
                        if (nmsg ==  msq->msg_first)
                                msq->msg_first = nmsg->msg_next;
                        else {
-                               for (tmsg= msq->msg_first; tmsg; 
+                               for (tmsg = msq->msg_first; tmsg; 
                                     tmsg = tmsg->msg_next)
                                        if (tmsg->msg_next == nmsg) 
                                                break;
@@ -213,7 +213,7 @@ static int findkey (key_t key)
        int id;
        struct msqid_ds *msq;
        
-       for (id=0; id <= max_msqid; id++) {
+       for (id = 0; id <= max_msqid; id++) {
                while ((msq = msgque[id]) == IPC_NOID) 
                        interruptible_sleep_on (&msg_lock);
                if (msq == IPC_UNUSED)
@@ -230,7 +230,7 @@ static int newque (key_t key, int msgflg)
        struct msqid_ds *msq;
        struct ipc_perm *ipcp;
 
-       for (id=0; id < MSGMNI; id++) 
+       for (id = 0; id < MSGMNI; id++) 
                if (msgque[id] == IPC_UNUSED) {
                        msgque[id] = (struct msqid_ds *) IPC_NOID;
                        goto found;
@@ -250,7 +250,7 @@ found:
        ipcp->key = key;
        ipcp->cuid = ipcp->uid = current->euid;
        ipcp->gid = ipcp->cgid = current->egid;
-       ipcp->seq = msg_seq;
+       msq->msg_perm.seq = msg_seq;
        msq->msg_first = msq->msg_last = NULL;
        msq->rwait = msq->wwait = NULL;
        msq->msg_cbytes = msq->msg_qnum = 0;
@@ -264,7 +264,7 @@ found:
        used_queues++;
        if (msg_lock)
                wake_up (&msg_lock);
-       return (int) msg_seq * MSGMNI + id;
+       return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 }
 
 int sys_msgget (key_t key, int msgflg)
@@ -286,7 +286,7 @@ int sys_msgget (key_t key, int msgflg)
                return -EIDRM;
        if (ipcperms(&msq->msg_perm, msgflg))
                return -EACCES;
-       return msq->msg_perm.seq * MSGMNI +id;
+       return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 } 
 
 static void freeque (int id)
@@ -295,7 +295,7 @@ static void freeque (int id)
        struct msg *msgp, *msgh;
 
        msq->msg_perm.seq++;
-       msg_seq++;
+       msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
        msgbytes -= msq->msg_cbytes;
        if (id == max_msqid)
                while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
@@ -319,7 +319,8 @@ static void freeque (int id)
 int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
 {
        int id, err;
-       struct msqid_ds *msq, tbuf;
+       struct msqid_ds *msq;
+       struct msqid_ds tbuf;
        struct ipc_perm *ipcp;
        
        if (msqid < 0 || cmd < 0)
@@ -353,7 +354,7 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
        case MSG_STAT:
                if (!buf)
                        return -EFAULT;
-               err = verify_area (VERIFY_WRITE, buf, sizeof (*msq));
+               err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
                if (err)
                        return err;
                if (msqid > max_msqid)
@@ -363,46 +364,62 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
                        return -EINVAL;
                if (ipcperms (&msq->msg_perm, S_IRUGO))
                        return -EACCES;
-               id = msqid + msq->msg_perm.seq * MSGMNI; 
-               memcpy_tofs (buf, msq, sizeof(*msq));
+               id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
+               tbuf.msg_perm   = msq->msg_perm;
+               tbuf.msg_stime  = msq->msg_stime;
+               tbuf.msg_rtime  = msq->msg_rtime;
+               tbuf.msg_ctime  = msq->msg_ctime;
+               tbuf.msg_cbytes = msq->msg_cbytes;
+               tbuf.msg_qnum   = msq->msg_qnum;
+               tbuf.msg_qbytes = msq->msg_qbytes;
+               tbuf.msg_lspid  = msq->msg_lspid;
+               tbuf.msg_lrpid  = msq->msg_lrpid;
+               memcpy_tofs (buf, &tbuf, sizeof(*buf));
                return id;
        case IPC_SET:
                if (!buf)
                        return -EFAULT;
+               err = verify_area (VERIFY_READ, buf, sizeof (*buf));
+               if (err)
+                       return err;
                memcpy_fromfs (&tbuf, buf, sizeof (*buf));
                break;
        case IPC_STAT:
                if (!buf)
                        return -EFAULT;
-               err = verify_area (VERIFY_WRITE, buf, sizeof(*msq));
+               err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
                if (err)
                        return err;
                break;
        }
 
-       id = msqid % MSGMNI;
+       id = (unsigned int) msqid % MSGMNI;
        msq = msgque [id];
        if (msq == IPC_UNUSED || msq == IPC_NOID)
                return -EINVAL;
-       ipcp = &msq->msg_perm;
-       if (ipcp->seq != msqid / MSGMNI)
+       if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
                return -EIDRM;
+       ipcp = &msq->msg_perm;
 
        switch (cmd) {
        case IPC_STAT:
                if (ipcperms (ipcp, S_IRUGO))
                        return -EACCES;
-               memcpy_tofs (buf, msq, sizeof (*msq));
+               tbuf.msg_perm   = msq->msg_perm;
+               tbuf.msg_stime  = msq->msg_stime;
+               tbuf.msg_rtime  = msq->msg_rtime;
+               tbuf.msg_ctime  = msq->msg_ctime;
+               tbuf.msg_cbytes = msq->msg_cbytes;
+               tbuf.msg_qnum   = msq->msg_qnum;
+               tbuf.msg_qbytes = msq->msg_qbytes;
+               tbuf.msg_lspid  = msq->msg_lspid;
+               tbuf.msg_lrpid  = msq->msg_lrpid;
+               memcpy_tofs (buf, &tbuf, sizeof (*buf));
                return 0;
-               break;
-       case IPC_RMID: case IPC_SET:
+       case IPC_SET:
                if (!suser() && current->euid != ipcp->cuid && 
                    current->euid != ipcp->uid)
                        return -EPERM;
-               if (cmd == IPC_RMID) {
-                       freeque (id); 
-                       return 0;
-               }
                if (tbuf.msg_qbytes > MSGMNB && !suser())
                        return -EPERM;
                msq->msg_qbytes = tbuf.msg_qbytes;
@@ -411,10 +428,14 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
                ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
                        (S_IRWXUGO & tbuf.msg_perm.mode);
                msq->msg_ctime = CURRENT_TIME;
-               break;
+               return 0;
+       case IPC_RMID:
+               if (!suser() && current->euid != ipcp->cuid && 
+                   current->euid != ipcp->uid)
+                       return -EPERM;
+               freeque (id); 
+               return 0;
        default:
                return -EINVAL;
-               break;
        }
-       return 0;
 }
index 072cf55988a6046083661d7b5a1e4139baa5c8f9..0aeaf588b0490d67126d821a020cb6e39916d1d0 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -26,11 +26,11 @@ static unsigned short sem_seq = 0;
 
 void sem_init (void)
 {
-       int i=0;
+       int i;
        
        sem_lock = NULL;
        used_sems = used_semids = max_semid = sem_seq = 0;
-       for (i=0; i < SEMMNI; i++)
+       for (i = 0; i < SEMMNI; i++)
                semary[i] = (struct semid_ds *) IPC_UNUSED;
        return;
 }
@@ -40,7 +40,7 @@ static int findkey (key_t key)
        int id;
        struct semid_ds *sma;
        
-       for (id=0; id <= max_semid; id++) {
+       for (id = 0; id <= max_semid; id++) {
                while ((sma = semary[id]) == IPC_NOID) 
                        interruptible_sleep_on (&sem_lock);
                if (sma == IPC_UNUSED)
@@ -62,7 +62,7 @@ static int newary (key_t key, int nsems, int semflg)
                return -EINVAL;
        if (used_sems + nsems > SEMMNS)
                return -ENOSPC;
-       for (id=0; id < SEMMNI; id++) 
+       for (id = 0; id < SEMMNI; id++) 
                if (semary[id] == IPC_UNUSED) {
                        semary[id] = (struct semid_ds *) IPC_NOID;
                        goto found;
@@ -86,7 +86,7 @@ found:
        ipcp->key = key;
        ipcp->cuid = ipcp->uid = current->euid;
        ipcp->gid = ipcp->cgid = current->egid;
-       ipcp->seq = sem_seq;
+       sma->sem_perm.seq = sem_seq;
        sma->eventn = sma->eventz = NULL;
        sma->sem_nsems = nsems;
        sma->sem_ctime = CURRENT_TIME;
@@ -96,7 +96,7 @@ found:
        semary[id] = sma;
        if (sem_lock)
                wake_up (&sem_lock);
-       return (int) sem_seq * SEMMNI + id;
+       return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
 }
 
 int sys_semget (key_t key, int nsems, int semflg)
@@ -120,7 +120,7 @@ int sys_semget (key_t key, int nsems, int semflg)
                return -EINVAL;
        if (ipcperms(&sma->sem_perm, semflg))
                return -EACCES;
-       return sma->sem_perm.seq*SEMMNI + id;
+       return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
 } 
 
 static void freeary (int id)
@@ -129,13 +129,13 @@ static void freeary (int id)
        struct sem_undo *un;
 
        sma->sem_perm.seq++;
-       sem_seq++;
+       sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */
        used_sems -= sma->sem_nsems;
        if (id == max_semid)
                while (max_semid && (semary[--max_semid] == IPC_UNUSED));
        semary[id] = (struct semid_ds *) IPC_UNUSED;
        used_semids--;
-       for (un=sma->undo; un; un=un->id_next)
+       for (un = sma->undo; un; un = un->id_next)
                un->semadj = 0;
        while (sma->eventz || sma->eventn) {
                if (sma->eventz)
@@ -148,16 +148,19 @@ static void freeary (int id)
        return;
 }
 
-int sys_semctl (int semid, int semnum, int cmd, void *arg)
+int sys_semctl (int semid, int semnum, int cmd, union semun arg)
 {
+       struct semid_ds *buf = NULL;
+       struct semid_ds tbuf;
        int i, id, val = 0;
-       struct semid_ds *sma, *buf = NULL, tbuf;
+       struct semid_ds *sma;
        struct ipc_perm *ipcp;
        struct sem *curr;
        struct sem_undo *un;
-       ushort nsems, *array = NULL;
+       unsigned int nsems;
+       ushort *array = NULL;
        ushort sem_io[SEMMSL];
-       
+
        if (semid < 0 || semnum < 0 || cmd < 0)
                return -EINVAL;
 
@@ -165,9 +168,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
        case IPC_INFO: 
        case SEM_INFO: 
        {
-               struct seminfo seminfo, *tmp;
-               if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg)))
-                       return -EFAULT;
+               struct seminfo seminfo, *tmp = arg.__buf;
                seminfo.semmni = SEMMNI;
                seminfo.semmns = SEMMNS;
                seminfo.semmsl = SEMMSL;
@@ -182,7 +183,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
                        seminfo.semusz = used_semids;
                        seminfo.semaem = used_sems;
                }
-               i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
+               i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
                if (i)
                        return i;
                memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo));
@@ -190,9 +191,8 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
        }
 
        case SEM_STAT:
-               if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg)))
-                       return -EFAULT;
-               i = verify_area (VERIFY_WRITE, buf, sizeof (*sma));
+               buf = arg.buf;
+               i = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
                if (i)
                        return i;
                if (semid > max_semid)
@@ -202,18 +202,22 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
                        return -EINVAL;
                if (ipcperms (&sma->sem_perm, S_IRUGO))
                        return -EACCES;
-               id = semid + sma->sem_perm.seq * SEMMNI; 
-               memcpy_tofs (buf, sma, sizeof(*sma));
+               id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
+               tbuf.sem_perm   = sma->sem_perm;
+               tbuf.sem_otime  = sma->sem_otime;
+               tbuf.sem_ctime  = sma->sem_ctime;
+               tbuf.sem_nsems  = sma->sem_nsems;
+               memcpy_tofs (buf, &tbuf, sizeof(*buf));
                return id;
        }
 
-       id = semid % SEMMNI;
+       id = (unsigned int) semid % SEMMNI;
        sma = semary [id];
        if (sma == IPC_UNUSED || sma == IPC_NOID)
                return -EINVAL;
        ipcp = &sma->sem_perm;
        nsems = sma->sem_nsems;
-       if (ipcp->seq != semid / SEMMNI)
+       if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
                return -EIDRM;
        if (semnum >= nsems)
                return -EINVAL;
@@ -233,17 +237,15 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
                case GETNCNT: return curr->semncnt;
                case GETZCNT: return curr->semzcnt;
                case GETALL:
-                       if (!arg || ! (array = (ushort *) get_fs_long((int *) arg)))
-                               return -EFAULT;
-                       i = verify_area (VERIFY_WRITE, array, nsems*sizeof(short));
+                       array = arg.array;
+                       i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
                        if (i)
                                return i;
                }
                break;
-       case SETVAL: 
-               if (!arg)
-                       return -EFAULT;
-               if ((val = (int) get_fs_long ((int *) arg))  > SEMVMX || val < 0) 
+       case SETVAL:
+               val = arg.val;
+               if (val > SEMVMX || val < 0) 
                        return -ERANGE;
                break;
        case IPC_RMID:
@@ -254,40 +256,37 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
                }
                return -EPERM;
        case SETALL: /* arg is a pointer to an array of ushort */
-               if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) )
-                       return -EFAULT;
-               if ((i = verify_area (VERIFY_READ, array, sizeof tbuf)))
+               array = arg.array;
+               if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
                        return i;
                memcpy_fromfs (sem_io, array, nsems*sizeof(ushort));
-               for (i=0; i< nsems; i++)
+               for (i = 0; i < nsems; i++)
                        if (sem_io[i] > SEMVMX)
                                return -ERANGE;
                break;
        case IPC_STAT:
-               if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) 
-                       return -EFAULT;
-               if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*sma))))
+               buf = arg.buf;
+               if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
                        return i;
                break;
        case IPC_SET:
-               if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) 
-                       return -EFAULT;
-               if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf)))
+               buf = arg.buf;
+               if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
                        return i;
-               memcpy_fromfs (&tbuf, buf, sizeof tbuf);
+               memcpy_fromfs (&tbuf, buf, sizeof (*buf));
                break;
        }
        
        if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
                return -EIDRM;
-       if (ipcp->seq != semid / SEMMNI)
+       if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
                return -EIDRM;
        
        switch (cmd) {
        case GETALL:
                if (ipcperms (ipcp, S_IRUGO))
                        return -EACCES;
-               for (i=0; i< sma->sem_nsems; i++)
+               for (i = 0; i < sma->sem_nsems; i++)
                        sem_io[i] = sma->sem_base[i].semval;
                memcpy_tofs (array, sem_io, nsems*sizeof(ushort));
                break;
@@ -318,12 +317,16 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
        case IPC_STAT:
                if (ipcperms (ipcp, S_IRUGO))
                        return -EACCES;
-               memcpy_tofs (buf, sma, sizeof (*sma));
+               tbuf.sem_perm   = sma->sem_perm;
+               tbuf.sem_otime  = sma->sem_otime;
+               tbuf.sem_ctime  = sma->sem_ctime;
+               tbuf.sem_nsems  = sma->sem_nsems;
+               memcpy_tofs (buf, &tbuf, sizeof(*buf));
                break;
        case SETALL:
                if (ipcperms (ipcp, S_IWUGO))
                        return -EACCES;
-               for (i=0; i<nsems; i++) 
+               for (i = 0; i < nsems; i++) 
                        sma->sem_base[i].semval = sem_io[i];
                for (un = sma->undo; un; un = un->id_next)
                        un->semadj = 0;
@@ -354,11 +357,13 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
                return -E2BIG;
        if (!tsops) 
                return -EFAULT;
+       if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
+               return i;
        memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));  
-       id = semid % SEMMNI;
+       id = (unsigned int) semid % SEMMNI;
        if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
                return -EINVAL;
-       for (i=0; i<nsops; i++) { 
+       for (i = 0; i < nsops; i++) { 
                sop = &sops[i];
                if (sop->sem_num > sma->sem_nsems)
                        return -EFBIG;
@@ -376,10 +381,10 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
         * ensure every sop with undo gets an undo structure 
         */
        if (undos) {
-               for (i=0; i<nsops; i++) {
+               for (i = 0; i < nsops; i++) {
                        if (!(sops[i].sem_flg & SEM_UNDO))
                                continue;
-                       for (un = current->semun; un; un = un->proc_next) 
+                       for (un = current->semundo; un; un = un->proc_next) 
                                if ((un->semid == semid) && 
                                    (un->sem_num == sops[i].sem_num))
                                        break;
@@ -392,17 +397,17 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
                        un->semid = semid;
                        un->semadj = 0;
                        un->sem_num = sops[i].sem_num;
-                       un->proc_next = current->semun;
-                       current->semun = un;
+                       un->proc_next = current->semundo;
+                       current->semundo = un;
                        un->id_next = sma->undo;
                        sma->undo = un;
                }
        }
        
  slept:
-       if (sma->sem_perm.seq != semid / SEMMNI) 
+       if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) 
                return -EIDRM;
-       for (i=0; i<nsops; i++) {
+       for (i = 0; i < nsops; i++) {
                sop = &sops[i];
                curr = &sma->sem_base[sop->sem_num];
                if (sop->sem_op + curr->semval > SEMVMX)
@@ -429,7 +434,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
                }
        }
        
-       for (i=0; i<nsops; i++) {
+       for (i = 0; i < nsops; i++) {
                sop = &sops[i];
                curr = &sma->sem_base[sop->sem_num];
                curr->sempid = current->pid;
@@ -437,7 +442,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
                        semzcnt++;
                if (!(sop->sem_flg & SEM_UNDO))
                        continue;
-               for (un = current->semun; un; un = un->proc_next) 
+               for (un = current->semundo; un; un = un->proc_next) 
                        if ((un->semid == semid) && 
                            (un->sem_num == sop->sem_num))
                                break;
@@ -466,11 +471,11 @@ void sem_exit (void)
        struct semid_ds *sma;
        struct sem *sem = NULL;
        
-       for (up = &current->semun; (u = *up); *up = u->proc_next, kfree(u)) {
-               sma = semary[u->semid % SEMMNI];
+       for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
+               sma = semary[(unsigned int) u->semid % SEMMNI];
                if (sma == IPC_UNUSED || sma == IPC_NOID) 
                        continue;
-               if (sma->sem_perm.seq != u->semid / SEMMNI)
+               if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
                        continue;
                for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
                        if (u == un) 
@@ -483,7 +488,7 @@ found:
                if (!un->semadj)
                        continue;
                while (1) {
-                       if (sma->sem_perm.seq != un->semid / SEMMNI)
+                       if (sma->sem_perm.seq != (unsigned int) un->semid / SEMMNI)
                                break;
                        sem = &sma->sem_base[un->sem_num];
                        if (sem->semval + un->semadj >= 0) {
@@ -503,6 +508,6 @@ found:
                        sem->semncnt--;
                }
        }
-       current->semun = NULL;
+       current->semundo = NULL;
        return;
 }
index d510a75dba7c8acdc2807f1a376428e44df061bc..21eb96bc79468fd33f9a7dfc356492baf9bb5679 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1,31 +1,30 @@
 /*
  * linux/ipc/shm.c
- * Copyright (C) 1992, 1993 Krishna Balasubramanian 
+ * Copyright (C) 1992, 1993 Krishna Balasubramanian
  *         Many improvements/fixes by Bruno Haible.
- * assume user segments start at 0x0
  */
 
 #include <linux/errno.h>
 #include <asm/segment.h>
 #include <linux/sched.h>
-#include <linux/ipc.h> 
+#include <linux/ipc.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
 
-extern int ipcperms (struct ipc_perm *ipcp, short semflg);
-extern unsigned int get_swap_page(void);
+extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
+extern unsigned int get_swap_page (void);
 static int findkey (key_t key);
 static int newseg (key_t key, int shmflg, int size);
 static int shm_map (struct shm_desc *shmd, int remap);
 static void killseg (int id);
-static unsigned long shm_swap_in(struct vm_area_struct *, unsigned long);
+static unsigned long shm_swap_in (struct vm_area_struct *, unsigned long);
 
-static int shm_tot = 0;  /* total number of shared memory pages */
+static int shm_tot = 0; /* total number of shared memory pages */
 static int shm_rss = 0; /* number of shared memory pages that are in memory */
 static int shm_swp = 0; /* number of shared memory pages that are in swap */
 static int max_shmid = 0; /* every used id is <= max_shmid */
-static struct wait_queue *shm_lock = NULL;
+static struct wait_queue *shm_lock = NULL; /* calling findkey() may need to wait */
 static struct shmid_ds *shm_segs[SHMMNI];
 
 static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
@@ -38,31 +37,31 @@ static ulong used_segs = 0;
 void shm_init (void)
 {
        int id;
-    
-               for (id = 0; id < SHMMNI; id++) 
+
+       for (id = 0; id < SHMMNI; id++)
                shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
        shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
        shm_lock = NULL;
        return;
 }
 
-static int findkey (key_t key)    
+static int findkey (key_t key)
 {
        int id;
        struct shmid_ds *shp;
-       
-       for (id=0; id <= max_shmid; id++) {
-               while ((shp = shm_segs[id]) == IPC_NOID) 
+
+       for (id = 0; id <= max_shmid; id++) {
+               while ((shp = shm_segs[id]) == IPC_NOID)
                        sleep_on (&shm_lock);
                if (shp == IPC_UNUSED)
                        continue;
-               if (key == shp->shm_perm.key) 
+               if (key == shp->shm_perm.key)
                        return id;
        }
        return -1;
 }
 
-/* 
+/*
  * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID.
  */
 static int newseg (key_t key, int shmflg, int size)
@@ -75,7 +74,7 @@ static int newseg (key_t key, int shmflg, int size)
                return -EINVAL;
        if (shm_tot + numpages >= SHMALL)
                return -ENOSPC;
-       for (id=0; id < SHMMNI; id++)
+       for (id = 0; id < SHMMNI; id++)
                if (shm_segs[id] == IPC_UNUSED) {
                        shm_segs[id] = (struct shmid_ds *) IPC_NOID;
                        goto found;
@@ -100,7 +99,7 @@ found:
                return -ENOMEM;
        }
 
-       for (i=0; i< numpages; shp->shm_pages[i++] = 0);
+       for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
        shm_tot += numpages;
        shp->shm_perm.key = key;
        shp->shm_perm.mode = (shmflg & S_IRWXUGO);
@@ -121,23 +120,23 @@ found:
        used_segs++;
        if (shm_lock)
                wake_up (&shm_lock);
-       return id + (int)shm_seq*SHMMNI;
+       return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
 }
 
 int sys_shmget (key_t key, int size, int shmflg)
 {
        struct shmid_ds *shp;
        int id = 0;
-       
+
        if (size < 0 || size > SHMMAX)
                return -EINVAL;
-       if (key == IPC_PRIVATE) 
+       if (key == IPC_PRIVATE)
                return newseg(key, shmflg, size);
        if ((id = findkey (key)) == -1) {
                if (!(shmflg & IPC_CREAT))
                        return -ENOENT;
                return newseg(key, shmflg, size);
-       } 
+       }
        if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
                return -EEXIST;
        shp = shm_segs[id];
@@ -147,10 +146,10 @@ int sys_shmget (key_t key, int size, int shmflg)
                return -EINVAL;
        if (ipcperms (&shp->shm_perm, shmflg))
                return -EACCES;
-       return shp->shm_perm.seq*SHMMNI + id;
+       return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
 }
 
-/* 
+/*
  * Only called after testing nattch and SHM_DEST.
  * Here pages, pgtable and shmid_ds are freed.
  */
@@ -166,20 +165,20 @@ static void killseg (int id)
                return;
        }
        shp->shm_perm.seq++;     /* for shmat */
-       numpages = shp->shm_npages; 
-       shm_seq++;
+       shm_seq = (shm_seq+1) % ((unsigned)(1<<31)/SHMMNI); /* increment, but avoid overflow */
        shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
        used_segs--;
-       if (id == max_shmid) 
+       if (id == max_shmid)
                while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));
        if (!shp->shm_pages) {
                printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
                return;
        }
-       for (i=0; i< numpages ; i++) {
+       numpages = shp->shm_npages;
+       for (i = 0; i < numpages ; i++) {
                if (!(page = shp->shm_pages[i]))
                        continue;
-               if (page & 1) {
+               if (page & PAGE_PRESENT) {
                        free_page (page & PAGE_MASK);
                        shm_rss--;
                } else {
@@ -195,10 +194,11 @@ static void killseg (int id)
 
 int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 {
-       struct shmid_ds *shp, tbuf;
+       struct shmid_ds tbuf;
+       struct shmid_ds *shp;
        struct ipc_perm *ipcp;
        int id, err;
-       
+
        if (cmd < 0 || shmid < 0)
                return -EINVAL;
        if (cmd == IPC_SET) {
@@ -211,7 +211,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
        }
 
        switch (cmd) { /* replace with proc interface ? */
-       case IPC_INFO: 
+       case IPC_INFO:
        {
                struct shminfo shminfo;
                if (!buf)
@@ -227,15 +227,15 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                memcpy_tofs (buf, &shminfo, sizeof(struct shminfo));
                return max_shmid;
        }
-       case SHM_INFO: 
-       { 
+       case SHM_INFO:
+       {
                struct shm_info shm_info;
                if (!buf)
                        return -EFAULT;
                err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));
                if (err)
                        return err;
-               shm_info.used_ids = used_segs; 
+               shm_info.used_ids = used_segs;
                shm_info.shm_rss = shm_rss;
                shm_info.shm_tot = shm_tot;
                shm_info.shm_swp = shm_swp;
@@ -247,7 +247,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
        case SHM_STAT:
                if (!buf)
                        return -EFAULT;
-               err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));
+               err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
                if (err)
                        return err;
                if (shmid > max_shmid)
@@ -257,18 +257,26 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                        return -EINVAL;
                if (ipcperms (&shp->shm_perm, S_IRUGO))
                        return -EACCES;
-               id = shmid + shp->shm_perm.seq * SHMMNI; 
-               memcpy_tofs (buf, shp, sizeof(*shp));
+               id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid;
+               tbuf.shm_perm   = shp->shm_perm;
+               tbuf.shm_segsz  = shp->shm_segsz;
+               tbuf.shm_atime  = shp->shm_atime;
+               tbuf.shm_dtime  = shp->shm_dtime;
+               tbuf.shm_ctime  = shp->shm_ctime;
+               tbuf.shm_cpid   = shp->shm_cpid;
+               tbuf.shm_lpid   = shp->shm_lpid;
+               tbuf.shm_nattch = shp->shm_nattch;
+               memcpy_tofs (buf, &tbuf, sizeof(*buf));
                return id;
        }
-       
-       shp = shm_segs[id = shmid % SHMMNI];
+
+       shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
        if (shp == IPC_UNUSED || shp == IPC_NOID)
                return -EINVAL;
-       ipcp = &shp->shm_perm;
-       if (ipcp->seq != shmid / SHMMNI) 
+       if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
                return -EIDRM;
-       
+       ipcp = &shp->shm_perm;
+
        switch (cmd) {
        case SHM_UNLOCK:
                if (!suser())
@@ -292,10 +300,18 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                        return -EACCES;
                if (!buf)
                        return -EFAULT;
-               err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));
+               err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
                if (err)
                        return err;
-               memcpy_tofs (buf, shp, sizeof(*shp));
+               tbuf.shm_perm   = shp->shm_perm;
+               tbuf.shm_segsz  = shp->shm_segsz;
+               tbuf.shm_atime  = shp->shm_atime;
+               tbuf.shm_dtime  = shp->shm_dtime;
+               tbuf.shm_ctime  = shp->shm_ctime;
+               tbuf.shm_cpid   = shp->shm_cpid;
+               tbuf.shm_lpid   = shp->shm_lpid;
+               tbuf.shm_nattch = shp->shm_nattch;
+               memcpy_tofs (buf, &tbuf, sizeof(*buf));
                break;
        case IPC_SET:
                if (suser() || current->euid == shp->shm_perm.uid ||
@@ -312,7 +328,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                if (suser() || current->euid == shp->shm_perm.uid ||
                    current->euid == shp->shm_perm.cuid) {
                        shp->shm_perm.mode |= SHM_DEST;
-                       if (shp->shm_nattch <= 0) 
+                       if (shp->shm_nattch <= 0)
                                killseg (id);
                        break;
                }
@@ -334,9 +350,9 @@ static int shm_map (struct shm_desc *shmd, int remap)
        unsigned long *page_table;
        unsigned long tmp, shm_sgn;
        unsigned long page_dir = shmd->task->tss.cr3;
-       
+
        /* check that the range is unmapped and has page_tables */
-       for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) { 
+       for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) {
                page_table = PAGE_DIR_OFFSET(page_dir,tmp);
                if (*page_table & PAGE_PRESENT) {
                        page_table = (ulong *) (PAGE_MASK & *page_table);
@@ -353,10 +369,10 @@ static int shm_map (struct shm_desc *shmd, int remap)
                                invalid++;
                        }
                        continue;
-               }  
+               }
              {
                unsigned long new_pt;
-               if(!(new_pt = get_free_page(GFP_KERNEL)))       /* clearing needed?  SRB. */
+               if (!(new_pt = get_free_page(GFP_KERNEL)))
                        return -ENOMEM;
                *page_table = new_pt | PAGE_TABLE;
                tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
@@ -366,8 +382,8 @@ static int shm_map (struct shm_desc *shmd, int remap)
 
        /* map page range */
        shm_sgn = shmd->shm_sgn;
-       for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, 
-            shm_sgn += (1 << SHM_IDX_SHIFT)) { 
+       for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE,
+            shm_sgn += (1 << SHM_IDX_SHIFT)) {
                page_table = PAGE_DIR_OFFSET(page_dir,tmp);
                page_table = (ulong *) (PAGE_MASK & *page_table);
                page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
@@ -404,7 +420,7 @@ static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
        vma->vm_task = current;
        vma->vm_start = addr;
        vma->vm_end = addr + len;
-       vma->vm_flags = VM_SHM | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC;
+       vma->vm_flags = VM_SHM | VM_SHARED | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC;
        if (readonly)
                vma->vm_page_prot = PAGE_READONLY;
        else {
@@ -420,10 +436,9 @@ static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
        return 0;
 }
 
-/* 
+/*
  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
  * raddr is needed to return addresses above 2Gig.
- * Specific attaches are allowed over the executable....
  */
 int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
@@ -432,17 +447,17 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
        int err;
        unsigned int id;
        unsigned long addr;
-       
+
        if (shmid < 0)
                return -EINVAL;
 
        if (raddr) {
-               err = verify_area(VERIFY_WRITE, raddr, sizeof(long));
+               err = verify_area(VERIFY_WRITE, raddr, sizeof(ulong));
                if (err)
                        return err;
        }
 
-       shp = shm_segs[id = shmid % SHMMNI];
+       shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
        if (shp == IPC_UNUSED || shp == IPC_NOID)
                return -EINVAL;
 
@@ -450,7 +465,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                if (shmflg & SHM_REMAP)
                        return -EINVAL;
                /* set addr below  all current unspecified attaches */
-               addr = SHM_RANGE_END; 
+               addr = SHM_RANGE_END;
                for (shmd = current->shm; shmd; shmd = shmd->task_next) {
                        if (shmd->start < SHM_RANGE_START)
                                continue;
@@ -459,7 +474,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                }
                addr = (addr - shp->shm_segsz) & PAGE_MASK;
        } else if (addr & (SHMLBA-1)) {
-               if (shmflg & SHM_RND) 
+               if (shmflg & SHM_RND)
                        addr &= ~(SHMLBA-1);       /* round down */
                else
                        return -EINVAL;
@@ -470,26 +485,26 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                for (shmd = current->shm; shmd; shmd = shmd->task_next) {
                        if (addr >= shmd->start && addr < shmd->end)
                                return -EINVAL;
-                       if (addr + shp->shm_segsz >= shmd->start && 
+                       if (addr + shp->shm_segsz >= shmd->start &&
                            addr + shp->shm_segsz < shmd->end)
                                return -EINVAL;
                }
 
        if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
                return -EACCES;
-       if (shp->shm_perm.seq != shmid / SHMMNI) 
+       if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
                return -EIDRM;
 
        shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL);
        if (!shmd)
                return -ENOMEM;
-       if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) {
+       if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
                kfree(shmd);
                return -EIDRM;
        }
        shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
                (shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0);
-               shmd->start = addr;
+       shmd->start = addr;
        shmd->end = addr + shp->shm_npages * PAGE_SIZE;
        shmd->task = current;
 
@@ -506,7 +521,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                kfree(shmd);
                return err;
        }
-               
+
        shmd->task_next = current->shm;
        current->shm = shmd;
        shmd->seg_next = shp->attaches;
@@ -526,28 +541,28 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
  */
 static void detach (struct shm_desc **shmdp)
 {
-       struct shm_desc *shmd = *shmdp; 
-       struct shmid_ds *shp;
-       int id;
-       
+       struct shm_desc *shmd = *shmdp;
+       struct shmid_ds *shp;
+       int id;
+
        id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
-       shp = shm_segs[id];
-       *shmdp = shmd->task_next;
-       for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
+       shp = shm_segs[id];
+       *shmdp = shmd->task_next;
+       for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
                if (*shmdp == shmd) {
-                       *shmdp = shmd->seg_next; 
-                       goto found; 
+                       *shmdp = shmd->seg_next;
+                       goto found;
                }
-       printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
-       
+       printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
+
  found:
        do_munmap(shmd->start, shp->shm_segsz);
        kfree(shmd);
-       shp->shm_lpid = current->pid;
+       shp->shm_lpid = current->pid;
        shp->shm_dtime = CURRENT_TIME;
        if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
                killseg (id); /* sleeps */
-       return;
+       return;
 }
 
 /*
@@ -556,9 +571,9 @@ static void detach (struct shm_desc **shmdp)
  */
 int sys_shmdt (char *shmaddr)
 {
-       struct shm_desc *shmd, **shmdp; 
-       
-       for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { 
+       struct shm_desc *shmd, **shmdp;
+
+       for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) {
                if (shmd->start == (ulong) shmaddr) {
                        detach (shmdp);
                        return 0;
@@ -567,17 +582,17 @@ int sys_shmdt (char *shmaddr)
        return -EINVAL;
 }
 
-/* 
- * detach all attached segments. 
+/*
+ * detach all attached segments.
  */
 void shm_exit (void)
 {
-       while (current->shm) 
+       while (current->shm)
                detach(&current->shm);
-       return;
+       return;
 }
 
-/* 
+/*
  * copy the parent shm descriptors and update nattch
  * parent is stuck in fork so an attach on each segment is assured.
  * copy_page_tables does the mapping.
@@ -588,17 +603,17 @@ int shm_fork (struct task_struct *p1, struct task_struct *p2)
        struct shmid_ds *shp;
        int id;
 
-       p2->semun = NULL;
+       p2->semundo = NULL;
        p2->shm = NULL;
         if (!p1->shm)
                return 0;
        for (shmd = p1->shm; shmd; shmd = shmd->task_next) {
                tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL);
                if (!tmp) {
-                       while (new_desc) { 
-                               tmp = new_desc->task_next; 
+                       while (new_desc) {
+                               tmp = new_desc->task_next;
                                kfree(new_desc);
-                               new_desc = tmp; 
+                               new_desc = tmp;
                        }
                        free_page_tables (p2);
                        return -ENOMEM;
@@ -670,7 +685,7 @@ static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code
                }
                shm_rss++;
                shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY);
-       } else 
+       } else
                --current->mm->maj_flt;  /* was incremented in do_no_page */
 
 done:
@@ -683,7 +698,7 @@ done:
 }
 
 /*
- * Goes through counter = (shm_rss << prio) present shm pages. 
+ * Goes through counter = (shm_rss << prio) present shm pages.
  */
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
@@ -704,7 +719,7 @@ int shm_swap (int prio)
  check_id:
        shp = shm_segs[swap_id];
        if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) {
-               swap_idx = 0; 
+               swap_idx = 0;
                if (++swap_id > max_shmid)
                        swap_id = 0;
                goto check_id;
@@ -712,8 +727,8 @@ int shm_swap (int prio)
        id = swap_id;
 
  check_table:
-       idx = swap_idx++; 
-       if (idx  >= shp->shm_npages) { 
+       idx = swap_idx++;
+       if (idx >= shp->shm_npages) {
                swap_idx = 0;
                if (++swap_id > max_shmid)
                        swap_id = 0;
@@ -743,12 +758,12 @@ int shm_swap (int prio)
                        continue;
                }
                pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);
-               if (!(*pte & 1)) { 
-                       printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", 
+               if (!(*pte & PAGE_PRESENT)) {
+                       printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
                                        id, shmd->start, idx);
                        *pte = 0;
                        continue;
-               } 
+               }
                pte = (ulong *) (PAGE_MASK & *pte);
                pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
                tmp = *pte;
@@ -756,7 +771,7 @@ int shm_swap (int prio)
                        continue;
                if (tmp & PAGE_ACCESSED) {
                        *pte &= ~PAGE_ACCESSED;
-                       continue;  
+                       continue;
                }
                tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;
                *pte = tmp;
@@ -765,7 +780,7 @@ int shm_swap (int prio)
                invalid++;
        }
 
-       if (mem_map[MAP_NR(page)] != 1) 
+       if (mem_map[MAP_NR(page)] != 1)
                goto check_table;
        page &= PAGE_MASK;
        shp->shm_pages[idx] = swap_nr;
index e2e3007fe87b477175305e4afccd54632ec9d996..9c6e030ced26092d122195c90891723690936ddb 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/stat.h>
 
 void ipc_init (void);
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr); 
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr);
 
 #ifdef CONFIG_SYSVIPC
 
@@ -21,16 +21,16 @@ int ipcperms (struct ipc_perm *ipcp, short flag);
 extern void sem_init (void), msg_init (void), shm_init (void);
 extern int sys_semget (key_t key, int nsems, int semflg);
 extern int sys_semop (int semid, struct sembuf *sops, unsigned nsops);
-extern int sys_semctl (int semid, int semnum, int cmd, void *arg);
+extern int sys_semctl (int semid, int semnum, int cmd, union semun arg);
 extern int sys_msgget (key_t key, int msgflg);
 extern int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
 extern int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
                       int msgflg);
 extern int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
-extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
 extern int sys_shmget (key_t key, int size, int flag);
 extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr);
 extern int sys_shmdt (char *shmaddr);
+extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
 
 void ipc_init (void)
 {
@@ -71,8 +71,16 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
                        return sys_semop (first, (struct sembuf *)ptr, second);
                case SEMGET:
                        return sys_semget (first, second, third);
-               case SEMCTL:
-                       return sys_semctl (first, second, third, ptr);
+               case SEMCTL: {
+                       union semun fourth;
+                       int err;
+                       if (!ptr)
+                               return -EINVAL;
+                       if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
+                               return err;
+                       fourth.__pad = (void *) get_fs_long(ptr);
+                       return sys_semctl (first, second, third, fourth);
+                       }
                default:
                        return -EINVAL;
                }
@@ -82,10 +90,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
                        return sys_msgsnd (first, (struct msgbuf *) ptr, 
                                           second, third);
                case MSGRCV: {
-                       struct ipc_kludge tmp; 
+                       struct ipc_kludge tmp;
+                       int err;
                        if (!ptr)
                                return -EINVAL;
-                       memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, 
+                       if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+                               return err;
+                       memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
                                       sizeof (tmp));
                        return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
                                                third);
@@ -93,14 +104,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
                case MSGGET:
                        return sys_msgget ((key_t) first, second);
                case MSGCTL:
-                       return sys_msgctl (first, second, 
-                                               (struct msqid_ds *) ptr);
+                       return sys_msgctl (first, second, (struct msqid_ds *) ptr);
                default:
                        return -EINVAL;
                }
        if (call <= SHMCTL) 
                switch (call) {
-               case SHMAT: /* returning shmaddr > 2G will screw up */
+               case SHMAT:
                        return sys_shmat (first, (char *) ptr, second, 
                                                        (ulong *) third);
                case SHMDT: 
@@ -108,8 +118,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
                case SHMGET:
                        return sys_shmget (first, second, third);
                case SHMCTL:
-                       return sys_shmctl (first, second, 
-                                               (struct shmid_ds *) ptr);
+                       return sys_shmctl (first, second, (struct shmid_ds *) ptr);
                default:
                        return -EINVAL;
                }
index 8e5e39b8530177e1faa7ff50b899f4704b27f0d1..0f14d7486417bfd3872d4bcaf61a1d62de7434b0 100644 (file)
@@ -411,7 +411,7 @@ NORET_TYPE void do_exit(long code)
                intr_count = 0;
        }
 fake_volatile:
-       if (current->semun)
+       if (current->semundo)
                sem_exit();
        if (current->shm)
                shm_exit();
index 4986662c0b582f27cff8434cd72e8d457e871c98..2981ec15db6892ad28180fb430e405b727672801 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/locks.h>
+#include <linux/string.h>
 #ifdef CONFIG_INET
 #include <linux/net.h>
 #include <linux/netdevice.h>
@@ -46,7 +47,6 @@ extern void (*do_floppy)(void);
 #endif
 
 extern int sys_tz;
-extern int ___strtok;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 
@@ -92,6 +92,13 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
        X(open_namei),
        X(inode_setattr),
        X(inode_change_ok),
+       X(generic_mmap),
+       X(set_blocksize),
+       X(getblk),
+       X(bread),
+       X(brelse),
+       X(ll_rw_block),
+       X(__wait_on_buffer),
 
        /* device registration */
        X(register_chrdev),
@@ -156,6 +163,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
        X(printk),
        X(sprintf),
        X(vsprintf),
+       X(simple_strtoul),
        X(system_utsname),
        X(sys_call_table),
 
@@ -206,26 +214,16 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
 #endif
        /* Added to make file system as module */
        X(set_writetime),
-       X(getblk),
-       X(inode_setattr),
        X(sys_tz),
-       X(inode_change_ok),
        X(__wait_on_super),
        X(file_fsync),
-       X(simple_strtoul),
-       X(generic_mmap),
-       X(set_blocksize),
        X(clear_inode),
        X(refile_buffer),
        X(___strtok),
-       X(brelse),
-       X(bread),
        X(init_fifo),
        X(super_blocks),
        X(chrdev_inode_operations),
        X(blkdev_inode_operations),
-       X(ll_rw_block),
-       X(__wait_on_buffer),
        X(read_ahead),
        /********************************************************
         * Do not add anything below this line,
index ebaa521a9812c9e90b026af2675317a721fa0704..8a2fd66895458fac343ce986c7c44a760043d06b 100644 (file)
@@ -319,7 +319,7 @@ int unmap_page_range(unsigned long from, unsigned long size)
                for (pc = pcnt; pc--; page_table++) {
                        if ((page = *page_table) != 0) {
                                *page_table = 0;
-                               if (1 & page) {
+                               if (PAGE_PRESENT & page) {
                                        if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
                                                if (current->mm->rss > 0)
                                                        --current->mm->rss;
index a3256105ed5b3a4f5e9cd6079f34a07d73c6210e..9cfefd1525f8d896f570f179198cad8821d1a9c5 100644 (file)
@@ -624,7 +624,7 @@ static int inet_create(struct socket *sock, int protocol)
        sk->prot = prot;
        sk->sleep = sock->wait;
        sk->daddr = 0;
-       sk->saddr = ip_my_addr();
+       sk->saddr = 0 /* ip_my_addr() */;
        sk->err = 0;
        sk->next = NULL;
        sk->pair = NULL;
@@ -749,6 +749,7 @@ static int inet_release(struct socket *sock, struct socket *peer)
        /* This will destroy it. */
        release_sock(sk);
        sock->data = NULL;
+       sk->socket = NULL;
        return(0);
 }
 
@@ -1261,6 +1262,10 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 /*
  * This routine must find a socket given a TCP or UDP header.
  * Everything is assumed to be in net order.
+ *
+ * We give priority to more closely bound ports: if some socket
+ * is bound to a particular foreign address, it will get the packet
+ * rather than somebody listening to any address..
  */
 
 struct sock *get_sock(struct proto *prot, unsigned short num,
@@ -1268,6 +1273,8 @@ struct sock *get_sock(struct proto *prot, unsigned short num,
                                unsigned short rnum, unsigned long laddr)
 {
        struct sock *s;
+       struct sock *result = NULL;
+       int badness = -1;
        unsigned short hnum;
 
        hnum = ntohs(num);
@@ -1284,21 +1291,41 @@ struct sock *get_sock(struct proto *prot, unsigned short num,
        for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
                        s != NULL; s = s->next) 
        {
+               int score = 0;
+
                if (s->num != hnum) 
                        continue;
+
                if(s->dead && (s->state == TCP_CLOSE))
                        continue;
-               if(ip_addr_match(s->saddr,laddr) == 0)
-                       continue;
-               if(prot == &udp_prot)
+               /* local address matches? */
+               if (s->saddr) {
+                       if (s->saddr != laddr)
+                               continue;
+                       score++;
+               }
+               /* remote address matches? */
+               if (s->daddr) {
+                       if (s->daddr != raddr)
+                               continue;
+                       score++;
+               }
+               /* remote port matches? */
+               if (s->dummy_th.dest) {
+                       if (s->dummy_th.dest != rnum)
+                               continue;
+                       score++;
+               }
+               /* perfect match? */
+               if (score == 3)
                        return s;
-               if(ip_addr_match(s->daddr,raddr)==0)
-                       continue;
-               if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) 
+               /* no, check if this is the best so far.. */
+               if (score <= badness)
                        continue;
-               return(s);
+               result = s;
+               badness = score;
        }
-       return(NULL);
+       return result;
 }
 
 static struct proto_ops inet_proto_ops = {
index d34435601d4cbc8258a0390eb4edddedd50b9cac..6771be20b643e12453cf039f8203140cb1852945 100644 (file)
@@ -200,13 +200,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
        int tmp;
        unsigned long src;
 
-       /*
-        *      If there is no 'from' address as yet, then make it our loopback
-        */
-
-       if (saddr == 0)
-               saddr = ip_my_addr();
-
        buff = skb->data;
 
        /*
@@ -255,6 +248,12 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
                raddr = (rt == NULL) ? 0 : rt->rt_gateway;
        }
 
+       /*
+        *      No source addr so make it our addr
+        */
+       if (saddr == 0)
+               saddr = src;
+
        /*
         *      No gateway so aim at the real destination
         */
index 1565bdf8b28bb851cfcb8666eee3e25ecc4ccefb..78f3e7317a0da81ef31392eb52a0b264c02f49fe 100644 (file)
@@ -95,7 +95,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                                format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
                                format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
                                timer_active, sp->timer.expires, (unsigned) sp->retransmits,
-                               sp->dead?0:SOCK_INODE(sp->socket)->i_uid);
+                               sp->socket?SOCK_INODE(sp->socket)->i_uid:0);
                        if (timer_active)
                                add_timer(&sp->timer);
                        /*
index 4d63a8e23db88a05a0853d9e370d6af59c6b7786..dbf7f769dde4896658bc4a9ed1978e6c390f4d01 100644 (file)
@@ -542,9 +542,9 @@ struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned l
                /*
                 *      broadcast addresses can be special cases.. 
                 */
-                
-               if ((rt->rt_gateway == 0) &&
-                   (rt->rt_dev->flags & IFF_BROADCAST) &&
+               if (rt->rt_flags & RTF_GATEWAY)
+                       continue;                
+               if ((rt->rt_dev->flags & IFF_BROADCAST) &&
                    (rt->rt_dev->pa_brdaddr == daddr))
                        break;
        }
index 2f81c506eb8770614b7657bd61e2e7a77e033a59..91e843fc03372e3becc3718bd30031f262483e23 100644 (file)
  *             Michael Pall    :       Undo the last fix in tcp_read_urg() (multi URG PUSH broke rlogin).
  *             Michael Pall    :       Fix the multi URG PUSH problem in tcp_readable(), select() after URG works now.
  *             Michael Pall    :       recv(...,MSG_OOB) never blocks in the BSD api.
+ *             Alan Cox        :       Changed the semantics of sk->socket to 
+ *                                     fix a race and a signal problem with
+ *                                     accept() and async I/O.
+ *             Alan Cox        :       Relaxed the rules on tcp_sendto().
  *
  *
  * To Fix:
@@ -1227,7 +1231,7 @@ static int tcp_sendto(struct sock *sk, unsigned char *from,
 {
        if (flags & ~(MSG_OOB|MSG_DONTROUTE))
                return -EINVAL;
-       if (!tcp_connected(sk->state))
+       if (sk->state == TCP_CLOSE)
                return -ENOTCONN;
        if (addr_len < sizeof(*addr))
                return -EINVAL;
@@ -2084,6 +2088,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        newsk->dummy_th.res2 = 0;
        newsk->acked_seq = skb->h.th->seq + 1;
        newsk->copied_seq = skb->h.th->seq;
+       newsk->socket = NULL;
 
        /*
         *      Grab the ttl and tos values and use them