]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.82 1.3.82
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:45 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:45 +0000 (15:10 -0500)
131 files changed:
Documentation/Configure.help
Documentation/cdrom/aztcd
Documentation/devices.tex
Documentation/devices.txt
Documentation/nfsroot.txt [new file with mode: 0644]
Makefile
Rules.make
arch/alpha/config.in
arch/alpha/defconfig
arch/alpha/kernel/ksyms.c
arch/alpha/kernel/setup.c
arch/i386/boot/setup.S
arch/i386/defconfig
arch/i386/kernel/irq.c
drivers/block/floppy.c
drivers/block/ide-cd.c
drivers/block/ide.c
drivers/block/md.c
drivers/block/triton.c
drivers/cdrom/aztcd.c
drivers/cdrom/cdu31a.c
drivers/cdrom/cm206.c
drivers/cdrom/gscd.c
drivers/cdrom/isp16.c
drivers/cdrom/mcd.c
drivers/cdrom/optcd.c
drivers/cdrom/sjcd.c
drivers/cdrom/sonycd535.c
drivers/char/atixlmouse.c
drivers/char/busmouse.c
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/misc.c
drivers/char/msbusmouse.c
drivers/char/psaux.c
drivers/char/stallion.c
drivers/net/3c501.c
drivers/net/3c509.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/lance.c
drivers/net/lance32.c [new file with mode: 0644]
drivers/net/plip.c
drivers/net/ppp.c
drivers/net/sdla.c
drivers/net/slhc.c
drivers/net/slip.c
drivers/net/strip.c [new file with mode: 0644]
drivers/pci/pci.c
drivers/scsi/53c7,8xx.c
drivers/scsi/Config.in
drivers/scsi/aha1542.c
drivers/scsi/scsi.c
drivers/scsi/seagate.c
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/sound/.version.orig [deleted file]
drivers/sound/Readme.cards
fs/fat/inode.c
fs/nfs/Makefile
fs/nfs/README [new file with mode: 0644]
fs/nfs/bio.c [new file with mode: 0644]
fs/nfs/cache.c [deleted file]
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/nfsiod.c [new file with mode: 0644]
fs/nfs/nfsroot.c
fs/nfs/proc.c
fs/nfs/rpcsock.c
fs/nfs/sock.c
include/asm-alpha/hwrpb.h
include/asm-i386/system.h
include/asm-i386/termios.h
include/linux/ax25.h
include/linux/aztcd.h
include/linux/cdrom.h
include/linux/if_arp.h
include/linux/if_strip.h [new file with mode: 0644]
include/linux/miscdevice.h
include/linux/nfs_fs.h
include/linux/nfsiod.h [new file with mode: 0644]
include/linux/rpcsock.h
include/linux/sysctl.h
include/linux/tqueue.h
include/net/ax25.h
include/net/sock.h
init/main.c
kernel/exit.c
kernel/ksyms.c
kernel/sched.c
kernel/softirq.c
kernel/sysctl.c
mm/filemap.c
net/802/Makefile
net/802/sysctl_net_802.c [new file with mode: 0644]
net/Makefile
net/appletalk/Makefile
net/appletalk/ddp.c
net/appletalk/sysctl_net_atalk.c [new file with mode: 0644]
net/ax25/Makefile
net/ax25/af_ax25.c
net/ax25/ax25_in.c
net/ax25/ax25_out.c
net/ax25/ax25_route.c
net/ax25/ax25_subr.c
net/ax25/ax25_timer.c
net/ax25/sysctl_net_ax25.c [new file with mode: 0644]
net/core/Makefile
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c [new file with mode: 0644]
net/ethernet/Makefile
net/ethernet/sysctl_net_ether.c [new file with mode: 0644]
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/ip_masq.c
net/ipv4/sysctl_net_ipv4.c [new file with mode: 0644]
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipx/Makefile
net/ipx/af_ipx.c
net/ipx/sysctl_net_ipx.c [new file with mode: 0644]
net/netrom/Makefile
net/netrom/af_netrom.c
net/netrom/sysctl_net_netrom.c [new file with mode: 0644]
net/sysctl_net.c [new file with mode: 0644]
net/unix/Makefile
net/unix/af_unix.c
net/unix/sysctl_net_unix.c [new file with mode: 0644]

index 0a56df15da0282792b2d8e31ae932f055ce23d63..5658a195f11b636f28616996ec8cddb7298be6ad 100644 (file)
@@ -642,13 +642,13 @@ CONFIG_MODVERSIONS
 
 Kernel daemon support
 CONFIG_KERNELD
-  Normally when you have selected some drivers and/or filesystems
-  to be created as loadable modules, you also have the responsibility
-  to load the corresponding module (via insmod/modprobe) before you
-  use it.  If you select Y here, the kernel will take care of this
-  all by itself, together with a user level daemon; "kerneld".
-  Note that "kerneld" will also automatically unload all unused
-  modules, so you don't have to use "rmmod" either.
+  Normally when you have selected some drivers and/or filesystems to
+  be created as loadable modules, you also have the responsibility to
+  load the corresponding module (via insmod/modprobe) before you can
+  use it.  If you select Y here, the kernel will take care of this all
+  by itself, together with the user level daemon "kerneld".  Note that
+  "kerneld" will also automatically unload all unused modules, so you
+  don't have to use "rmmod" either.
   There are some other "kernel callouts" that will be available
   later on, such as a user level "beeper" and a generic screen blanker.
   The "kerneld" daemon is included in "modules-1.2.8" and later.
@@ -882,7 +882,10 @@ CONFIG_NO_PATH_MTU_DISCOVERY
   over the net. "Path MTU Discovery" means that, instead of always
   sending very small chunks, we start out sending big ones and if we
   then discover that some host along the way likes its chunks smaller,
-  we adjust to a smaller size. This is good, so say N.
+  we adjust to a smaller size. This is good, so most people say
+  N. However, some versions of DOS NCSA telnet (and other software)
+  are broken and can only connect to your Linux machine if you say Y
+  here.
 
 Disable NAGLE algorithm (normally enabled)
 CONFIG_TCP_NAGLE_OFF
@@ -1386,18 +1389,20 @@ CONFIG_SCSI_AM53C974
 
 IOMEGA Parallel Port ZIP drive SCSI support
 CONFIG_SCSI_PPA
-  This driver supports the parallel port version of IOMEGA's ZIP
-  drive (a 100Mb removable media device).  For more information 
-  about this driver and how to use it you should read the file
-  drivers/scsi/README.ppa.  You should also read the SCSI-HOWTO,
-  which is available via anonymous ftp from sunsite.unc.edu in
-  the directory /pub/Linux/docs/HOWTO.  This driver is also available
-  as a module which can be inserted in and removed from the
-  running kernel whenever you want. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. Note that 
-  you can say N here if you have the SCSI version of the ZIP drive: 
-  it will be supported automatically if you enabled the generic
-  "SCSI disk support", above.
+  This driver supports the parallel port version of IOMEGA's ZIP drive
+  (a 100Mb removable media device).  For more information about this
+  driver and how to use it you should read the file
+  drivers/scsi/README.ppa.  You should also read the SCSI-HOWTO, which
+  is available via anonymous ftp from sunsite.unc.edu in the directory
+  /pub/Linux/docs/HOWTO.  This driver is also available as a module
+  which can be inserted in and removed from the running kernel
+  whenever you want. If you want to use any two of a parallel port ZIP
+  drive, a parallel printer or PLIP on the same parallel port, you
+  should compile the drivers as modules and only insert them as
+  needed. To compile this driver as a module, say M here and read
+  Documentation/modules.txt. Note that you can say N here if you have
+  the SCSI version of the ZIP drive: it will be supported
+  automatically if you enabled the generic "SCSI disk support", above.
 
 Network device support?
 CONFIG_NETDEVICES
@@ -1523,6 +1528,21 @@ CONFIG_PPP_LOTS
   running in parallel. This is mainly useful if you intend your linux
   box to act as a dial-in PPP server. Most people can say N.
 
+STRIP (Starmode Radio IP) support
+CONFIG_STRIP
+  Say Y if you have a Metricom radio and intend to use Starmode Radio IP.
+  STRIP is a radio protocol developed for the MosquitoNet project
+  (http://mosquitonet.stanford.edu/) to send Internet traffic using Metricom
+  radios.  Metricom radios are small, battery powered, 100kbit/sec packet
+  radio transceivers, about the size and weight of a cellular telephone.
+  (You may also have heard them called "Metricom modems" but we avoid the
+  term "modem" because it misleads many people into thinking that you can
+  plug a Metricom modem into a phone line and use it as a modem.)
+  You can use STRIP on any Linux machine with a serial port, although
+  it is obviously most useful for people with laptop computers. If you
+  think you might get a Metricom radio in the future, there is no harm in
+  saying yes to STRIP now, except that it makes the kernel a bit bigger.
+
 Z8530 SCC kiss emulation driver for AX.2
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
@@ -1573,14 +1593,15 @@ CONFIG_EQUALIZER
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
-FRAD (Frame Relay Access Device) support
-CONFIG_FRAD
+Frame Relay (DLCI) support
+CONFIG_DLCI
   This is support for the frame relay protocol; frame relay is a fast
   low-cost way to connect to a remote internet access provider or to
-  form a private wide area network. The one physical line to your
-  local entry point or "switch" carries several logical
-  point-to-point connections to other sites connected to the frame
-  relay network. For a general explanation of the protocol, check out
+  form a private wide area network. The one physical line from your
+  box to the local "switch" (i.e. the entry point to the frame relay
+  network) can carry several logical point-to-point connections to
+  other computers connected to the frame relay network. For a general
+  explanation of the protocol, check out
   http://frame-relay.indiana.edu/4000/4000index.html on the WWW. (To
   browse the WWW, you need to have access to a machine on the Internet
   that has one of the programs lynx, netscape or Mosaic.) To use frame
@@ -2525,7 +2546,7 @@ CONFIG_UMSDOS_FS
 /proc filesystem support
 CONFIG_PROC_FS
   This is a virtual filesystem providing information about the status
-  of the system. "Virtual" means that it doesn't take any space on
+  of the system. "Virtual" means that it doesn't take up any space on
   your harddisk: the files are created on the fly when you access
   them. Also, you cannot read the files with less: you need to use
   more or cat. The filesystem is explained in the Kernel Hacker's
@@ -2683,15 +2704,15 @@ CONFIG_NCP_FS
 
 Standard/generic serial support
 CONFIG_SERIAL
-  This selects whether you want to include the driver for the
-  standard (0x3F8, 0x2F8, etc.) serial ports. Most people will
-  say "y" here, so that they can use serial mice, modems and
-  similar devices. People who might say "n" here are those that
-  are setting up dedicated ethernet WWW/ftp servers, or users
-  that have one of the various bus mice instead of a serial mouse.
-  Note that the Cyclades and Stallion drivers do not need this
-  driver built in for them to work. They are completely independent
-  of each other.
+  This selects whether you want to include the driver for the standard
+  serial ports.  People who might say N here are those that are
+  setting up dedicated ethernet WWW/ftp servers, or users that have
+  one of the various bus mice instead of a serial mouse.  Note that
+  the Cyclades and Stallion drivers do not need this driver to be
+  built in for them to work. They are completely independent of each
+  other. Most people will say Y here however, so that they can use
+  serial mice, modems and similar devices connecting to the standard
+  serial ports.
 
 Cyclades async mux support
 CONFIG_CYCLADES
index 74e54c31472257933be08342cacf66d3ca0173c6..31764cb12761ecb572e2dff323262d2bed2a2996 100644 (file)
@@ -1,13 +1,13 @@
-$Id: README.aztcd,v 2.10 1995/12/03 11:55:14 root Exp root $
+$Id: README.aztcd,v 2.20 1996/03/12 18:31:33 root Exp root $
           Readme-File /usr/src/Documentation/cdrom/aztcd
            for Aztech CD-ROM CDA268-01A, ORCHID CD-3110,
                   OKANO/WEARNES CDD110, Conrad TXC
                            CD-ROM Driver 
-                       Version 2.0 and newer
+                       Version 2.2 and newer
                    (for other drives see 6.-8.)
 
 NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE
-      A PROPRIETARY INTERFACE (implemented on a sound card or on a
+      A PROPRIETARY INTERFACE (implemented on a sound card or on an
       ISA-AT-bus card). 
       IT WILL DEFINITELY NOT WORK WITH CD-ROM DRIVES WITH *IDE*-INTERFACE,
       such as the Aztech CDA269-031SE !!! IF YOU'RE USING A CD-ROM DRIVE
@@ -40,9 +40,9 @@ Contents of this file:
 1. NOTE 
 This software has been successfully in alpha and beta test and is part of
 the standard kernel since kernel 1.1.8x since December 1994. It works with
-time with AZTECH CDA268-01A, ORCHID CDS-3110, ORCHID/WEARNES CDD110 and
+with AZTECH CDA268-01A, ORCHID CDS-3110, ORCHID/WEARNES CDD110 and
 CONRAD TXC (Nr.99 31 23 -series 04) and has proven to be stable with kernel 
-versions 1.0.9 to 1.3.35. But with any software there still may be bugs in it. 
+versions 1.0.9 to 1.3.72. But with any software there still may be bugs in it. 
 So if you encounter problems, you are invited to help us improve this software. 
 Please send me a detailed bug report (see chapter BUG REPORTS). You are also 
 invited in helping us to increase the number of drives, which are supported.
@@ -84,7 +84,7 @@ If the message looks correct, as user 'root' you should be able to mount the
 drive by
           mount -t iso9660 -r /dev/aztcd0 /mnt
 and use it as any other filesystem. (If this does not work, check if
-  /dev/aztcd0 and /mnt do exist and create them, if necessary by doing
+/dev/aztcd0 and /mnt do exist and create them, if necessary by doing
       mknod /dev/aztcd0 b 29 0
       mkdir /mnt                       
 
@@ -108,7 +108,7 @@ filesystem, you have to recompile your kernel:
   CD268, an ORCHID CD-3110 or ORCHID/WEARNES CDD110 that's the only item you 
   have to set up. If you have a soundcard, read chapter 4.2.
   Users of other drives should read chapter OTHER DRIVES of this file.
-  You also can configure that address by LILO boot parameter aztcd=... 
+  You also can configure that address by kernel boot parameter aztcd=... 
 - There are some other points, which may be configured, e.g. auto-eject the
   CD when umounting a drive, tray locking etc., see aztcd.h for details.
 - Build a new kernel, configure it for 'Aztech/Orchid/Okano/Wearnes support' 
@@ -116,7 +116,7 @@ filesystem, you have to recompile your kernel:
   'Aztech... support', if you want to use aztcd as a run time loadable module. 
   But in any case you must have the ISO9660-filesystem included in your
   kernel.
-- Activate the new kernel, normally this is done by running lilo (don't for-
+- Activate the new kernel, normally this is done by running LILO (don't for-
   get to configure it before and to keep a copy of your old kernel in case
   something goes wrong!).
 - Reboot
@@ -254,7 +254,7 @@ CD-ROMs to the volunteers, who provided the CD-ROM support for Linux. My
 snail mail address for such 'stuff' is
            Prof. Dr. W. Zimmermann
            Fachhochschule fuer Technik Esslingen
-           Fachbereich NT
+           Fachbereich IT
            Flandernstrasse 101
            D-73732 Esslingen
            Germany
@@ -460,8 +460,8 @@ and also were very patient with the problems which occurred.
 Reinhard Max delivered the information for the CDROM-interface of the
 SoundWave32 soundcards.
 
-Jochen Koch and Olaf Kaluza delivered the information for supporting Conrad's TXC
-drive.
+Jochen Kunz and Olaf Kaluza delivered the information for supporting Conrad's 
+TXC drive.
 
 Anybody, who is interested in these items should have a look at 'ftp.gwdg.de',
 directory 'pub/linux/cdrom' and at 'ftp.cdrom.com', directory 'pub/cdrom'.
@@ -472,11 +472,9 @@ an example on how to do this, you will find a tiny CD Player for audio CDs
 named 'cdplay.c'. It allows you to play audio CDs. You can play a specified 
 track, pause and resume or skip tracks forward and backwards. If you quit the 
 program without stopping the  drive, playing is continued. You can also 
-(mis)use cdplay to read and hexdump data disks.
-'cdplay.c' can be found as a separate file in package AZTECH.CDROM.Vxx.tgz.
-If you don't have it, you can find the code in the APPENDIX of this file,
-which you should cut out with an editor and store in a separate file
-'cdplay.c'. To compile it and make it executable, do
+(mis)use cdplay to read and hexdump data disks. You can find the code in the 
+APPENDIX of this file, which you should cut out with an editor and store in a 
+separate file 'cdplay.c'. To compile it and make it executable, do
   gcc -s -Wall -O2 -L/usr/lib cdplay.c -o /usr/local/bin/cdplay # compiles it
   chmod +755 /usr/local/bin/cdplay                              # makes it executable
   ln -s /dev/aztcd0 /dev/cdrom                                  # creates a link
@@ -503,18 +501,21 @@ as always when you are doing systems programming and kernel hacking, you
 should have a backup copy of your system in a safe place (and you also
 should try before, how to restore from a backup copy)!
 
+A reworked and improved version called 'cdtester.c', which has yet more
+features for testing CDROM-drives can be found in
+/usr/src/linux/Documentation/cdrom/sbpcd, written by E.Moenkeberg.
 
 Werner Zimmermann
 Fachhochschule fuer Technik Esslingen
 (EMail: zimmerma@rz.fht-esslingen.de)
-October 21, 1995
+Maerz 16, 1995
 
 ---------------------------------------------------------------------------
 APPENDIX: Source code of cdplay.c
 
 /* Tiny Audio CD Player
 
-   Copyright 1994, 1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
+   Copyright 1994, 1995, 1996 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
 
 This program originally was written to test the audio functions of the
 AZTECH.CDROM-driver, but it should work with every CD-ROM drive. Before 
@@ -564,7 +565,7 @@ int main(void)
          } azt;
   struct cdrom_volctrl  volctrl;
 
-  printf("\nMini-Audio CD-Player V0.71   (C) 1994,1995  W.Zimmermann\n");
+  printf("\nMini-Audio CD-Player V0.72   (C) 1994,1995,1996  W.Zimmermann\n");
   handle=open("/dev/cdrom",O_RDWR);
   ioctl(handle,CDROMRESUME);
   
index 073bd83943fa259241ca3a796791cd903ef86b1a..164902425cf5fef341fcfdca2e0ffa1ab39b8498 100644 (file)
@@ -42,7 +42,7 @@ foo \kill}%
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: March 9, 1996}
+\date{Last revised: April 1, 1996}
 \maketitle
 %
 \noindent
@@ -158,7 +158,8 @@ an unreasonable effort.
 \major{45}{}{char }{isdn4linux ISDN BRI driver}
 \major{46}{}{char }{Comtrol Rocketport serial card}
 \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
-\major{48}{--59}{}{Unallocated}
+\major{48}{}{char }{Matter replicator}
+\major{49}{--59}{}{Unallocated}
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
@@ -411,6 +412,7 @@ physical disks.
        \minor{131}{/dev/temperature}{Machine internal temperature}
        \minor{132}{/dev/hwtrap}{Hardware fault trap}
        \minor{133}{/dev/exttrp}{External device trap}
+       \minor{134}{/dev/apm_bios}{Advanced Power Management BIOS}
 \end{devicelist}
 
 \noindent
@@ -980,7 +982,15 @@ driver with this number should not cause ill effects to the system
 \end{devicelist}
 
 \begin{devicelist}
-\major{48}{--59}{}{Unallocated}
+\major{48}{}{char }{Matter replicator}
+       \minor{0}{/dev/replicator}{Matter replicator}
+\end{devicelist}
+
+\noindent
+See RFC 1437 for the data format accepted by this device.
+
+\begin{devicelist}
+\major{49}{--59}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
index 4e1b0ac381733907ae52af78c9a1567948146ab9..6d45ac69aeac302e9e5f89eb81ab169a11721758 100644 (file)
@@ -2,7 +2,7 @@
 
             Maintained by H. Peter Anvin <hpa@zytor.com>
 
-                    Last revised: March 9, 1996
+                    Last revised: April 1, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -237,6 +237,7 @@ an unreasonable effort.
                131 = /dev/temperature  Machine internal temperature
                132 = /dev/hwtrap       Hardware fault trap
                133 = /dev/exttrp       External device trap
+               134 = /dev/apm_bios     Advanced Power Management BIOS
 
  11 char       Raw keyboard device
                  0 = /dev/kbd          Raw keyboard device
@@ -672,7 +673,12 @@ an unreasonable effort.
                  1 = /dev/cur1         Callout device corresponding to ttyR1
                      ...
 
- 48-59         UNALLOCATED
+ 48 char       Matter replicator
+                 0 = /dev/replicator   Matter replicator
+
+               See RFC 1437 for the data format accepted by this device.
+
+ 49-59         UNALLOCATED
 
  60-63         LOCAL/EXPERIMENTAL USE
                Allocated for local/experimental use.  For devices not
diff --git a/Documentation/nfsroot.txt b/Documentation/nfsroot.txt
new file mode 100644 (file)
index 0000000..f404a15
--- /dev/null
@@ -0,0 +1,204 @@
+Mounting the root filesystem via NFS (nfsroot)
+==============================================
+
+Written 1996 by Gero Kuhlmann <gero@gkminix.han.de>
+
+
+
+If you want to use a diskless system, as an X-terminal or printer
+server for example, you have to put your root filesystem onto a
+non-disk device. This can either be a ramdisk (see initrd.txt in
+this directory for further information) or a filesystem mounted
+via NFS. The following text describes on how to use NFS for the
+root filesystem. For the rest of this text 'client' means the
+diskless system, and 'server' means the NFS server.
+
+
+
+
+1.) Enabling nfsroot capabilities
+    -----------------------------
+
+In order to use nfsroot you have to select support for NFS during
+kernel configuration. Note that NFS cannot be loaded as a module
+in this case. The configuration script will then ask you wether
+you want to use nfsroot, and if yes what kind of auto configuration
+system you want to use. Selecting both BOOTP and RARP is safe.
+
+
+
+
+2.) Kernel command line
+    -------------------
+
+When the kernel has been loaded by a boot loader (either by loadlin,
+LILO or a network boot program) it has to be told what root fs device
+to use, and where to find the server and the name of the directory
+on the server to mount as root. This can be established by a couple
+of kernel command line parameters:
+
+
+root=/dev/nfs
+
+  This is necessary to enable the pseudo-NFS-device. Note that it's not a
+  real device but just a synonym to tell the kernel to use NFS instead of
+  a real device.
+
+
+nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
+
+  If the nfsroot parameter is NOT give on the command line, the default
+  "/tftpboot/%s" will be used.
+
+  <server-ip>  Specifies the IP address of the NFS server. If this field
+               is not given, the default address as determined by the
+               nfsaddrs variable (see below) is used. One use of this
+               parameter is for example to allow using different servers
+               for RARP and NFS. Usually you can leave this blank.
+
+  <root-dir>   Name of the directory on the server to mount as root. If
+               there is a "%s" token in the string, the token will be
+               replaced by the ASCII-representation of the client's IP
+               address.
+
+  <nfs-options>        Standard NFS options. All options are seperated by commas.
+               If the options field is not given, the following defaults
+               will be used:
+                       port            = as given by server portmap daemon
+                       rsize           = 1024
+                       wsize           = 1024
+                       timeo           = 7
+                       retrans         = 3
+                       acregmin        = 3
+                       acregmax        = 60
+                       acdirmin        = 30
+                       acdirmax        = 60
+                       flags           = hard, nointr, noposix, cto, ac
+
+
+nfsaddrs=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
+
+  If this parameter is missing on the kernel command line, all fields are
+  assumed to be empty, and the below mentioned defaults apply. In general
+  this means that the kernel tries to configure everything using both
+  RARP and BOOTP (depending on what has been enabled during kernel confi-
+  guration, and if both what protocol answer got in first).
+
+  <client-ip>  IP address of the client. If empty, the address will either
+               be determined by RARP or BOOTP. What protocol is used de-
+               pends on what has been enabled during kernel configuration
+               and on the <autoconf> parameter. If this parameter is not
+               empty, neither RARP nor BOOTP will be used.
+
+  <server-ip>  IP address of the NFS server. If RARP is used to determine
+               the client address and this parameter is NOT empty only
+               replies from the specified server are accepted. To use
+               different RARP and NFS server, specify your RARP server
+               here (or leave it blank), and specify your NFS server in
+               the nfsroot paremeter (see above). If this entry is blank
+               the address of the server is used which answered the RARP
+               or BOOTP request.
+
+  <gw-ip>      IP address of a gateway if the server in on a different
+               subnet. If this entry is empty no gateway is used and the
+               server is assumed to be on the local network, unless a
+               value has been received by BOOTP.
+
+  <netmask>    Netmask for local network interface. If this is empty,
+               the netmask is derived from the client IP address, un-
+               less a value has been received by BOOTP.
+
+  <hostname>   Name of the client. If empty, the client IP address is
+               used in ASCII-notation, or the value received by BOOTP.
+
+  <device>     Name of network device to use. If this is empty, all
+               devices are used for RARP requests, and the first one
+               found for BOOTP. For NFS the device is used on which
+               either RARP or BOOTP replies have been received. If
+               you only have one device you can safely leave this blank.
+
+  <autoconf>   Method to use for autoconfiguration. If this is either
+               'rarp' or 'bootp' the specified protocol is being used.
+               If the value is 'both' or empty, both protocols are used
+               so far as they have been enabled during kernel configura-
+               tion. 'none' means no autoconfiguration. In this case you
+               have to specify all necessary values in the fields before.
+
+  The <autoconf> parameter can appear alone as the value to the nfsaddrs
+  parameter (without all the ':' characters before) in which case auto-
+  configuration is used. However, the 'none' value is not available in
+  that case.
+
+
+
+
+3.) Kernel loader
+    -------------
+
+To get the kernel into memory different approaches can be used. They
+depend on what facilities are available:
+
+
+3.1)  Writing the kernel onto a floppy using dd:
+       As always you can just write the kernel onto a floppy using dd,
+       but then it's not possible to use kernel command lines at all.
+       To substitute the 'root=' parameter, create a dummy device on any
+       linux system with major number 0 and minor number 255 using mknod:
+
+               mknod /dev/boot255 c 0 255
+
+       Then copy the kernel zImage file onto a floppy using dd:
+
+               dd if=/usr/src/linux/arch/i386/boot/zImage of=/dev/fd0
+
+       And finally use rdev to set the root device:
+
+               rdev /dev/fd0 /dev/boot255
+
+       You can then remove the dummy device /dev/boot255 again. There
+       is no real device available for it.
+       The other two kernel command line parameters cannot be substi-
+       tuted with rdev. Therefore, using this method the kernel will
+       by default use RARP and/or BOOTP, and if it gets an answer via
+       RARP will mount the directory /tftpboot/<client-ip>/ as it's
+       root. If it got a BOOTP answer the directory name in that answer
+       is used.
+
+
+3.2) Using LILO
+       When using LILO you can specify all necessary command line
+       parameters with the 'append=' command in the LILO configuration
+       file. However, to use the 'root=' command you also need to
+       setup a dummy device as described in 3.1 above. How to use
+       LILO and it's 'append=' command please refer to the LILO
+       documentation.
+
+3.3) Using loadlin
+       When you want to boot Linux from a DOS command prompt without
+       having a local hard disk to mount as root, you can use loadlin.
+       I was told that it works, but haven't used it myself yet. In
+       general you should be able to create a kernel command line simi-
+       lar to how LILO is doing it. Please refer to the loadlin docu-
+       mentation for further information.
+
+3.4) Using a bootrom
+       This is probably the most elegant way of booting a diskless
+       client. With a bootrom the kernel gets loaded using the TFTP
+       protocol. As far as I know no commercial bootroms already
+       support booting Linux over the network, but there are two
+       free implementations of a bootrom available on sunsite.unc.edu
+       and it's mirrors. They are called 'netboot-nfs' and 'etherboot'.
+       Both contain everything you need to boot a diskless Linux client.
+
+
+
+
+4.) Credits
+    -------
+
+  The nfsroot code in the kernel has been written by me, Gero Kuhlmann
+  <gero@gkminix.han.de>, with the BOOTP code and a couple of bug fixes
+  contributed by Martin Mares <mj@k332.feld.cvut.cz>. In order to write
+  the initial version of nfsroot I would like to thank Jens-Uwe Mager
+  <jum@anubis.han.de> for his help.
+
index e448e6d16e2026731ac89419e42b3bfacc49bafc..91bbbf1bea310ae5e339e163bf34d505d6e64760 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 81
+SUBLEVEL = 82
 
 ARCH = i386
 
index 5a2c36e0f70a7b74653e060ff616def2250e7762..1049c899be9799628be7a1bb678433436a305b74 100644 (file)
@@ -150,7 +150,7 @@ $(MODINCL)/%.ver: %.c
        @if [ ! -x /sbin/genksyms ]; then echo "Please read: README.modules"; fi
        $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< | /sbin/genksyms -w $(MODINCL)
 
-$(SYMTAB_OBJS:.o=.ver): $(TOPDIR)/include/linux/autoconf.h
+$(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h
 
 $(TOPDIR)/include/linux/modversions.h: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver))
        @echo updating $(TOPDIR)/include/linux/modversions.h
index e191b39736c54de929bf837e9deac8419ae1dcc9..aa083f1a2bcefa3fbd7738ebc59e741b86b1725a 100644 (file)
@@ -15,6 +15,7 @@ bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
   MODULES=y
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
 endmenu
 
index eb8348157226d55f05b42cf184615749a5b835f4..3e7b5a3166a3fff44cab2ab4a0a251bf9f371fe0 100644 (file)
@@ -7,6 +7,7 @@
 #
 CONFIG_MODULES=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_KERNELD is not set
 
 #
 # General setup
@@ -130,10 +131,11 @@ CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 # CONFIG_SLIP is not set
 # CONFIG_PPP is not set
+# CONFIG_STRIP is not set
 # CONFIG_SCC is not set
 # CONFIG_PLIP is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_FRAD is not set
+# CONFIG_DLCI is not set
 # CONFIG_NET_ALPHA is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_LANCE is not set
@@ -184,6 +186,7 @@ CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
 # CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
index 7ad09542e905566f401b2d718eb2a9ea3b6fc231..b77eb54b68f884bc5dfc7e31ffbb3db64939ed46 100644 (file)
@@ -33,6 +33,12 @@ static struct symbol_table arch_symbol_table = {
        X(_outb),
        X(_outw),
        X(_outl),
+       X(_readb),
+       X(_readw),
+       X(_readl),
+       X(_writeb),
+       X(_writew),
+       X(_writel),
        X(__divl),
        X(__reml),
        X(__divq),
index 1f911c674486ae5ff775ed8cfcc49d7ed1fdf347..e5f5efeec0b643e6e6e0207bd25b6b2a73fda817 100644 (file)
@@ -174,7 +174,8 @@ int get_cpuinfo(char *buffer)
                "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen",
                "Pelican", "8", "Sable", "AXPvme", "Noname",
                "Turbolaser", "Avanti", "Mustang", "Alcor", "16",
-               "Mikasa", "18", "EB66", "EB64+"
+               "Mikasa", "18", "EB66", "EB64+", "21", "22", "23",
+               "24", "25", "EB164"
        };
        struct percpu_struct *cpu;
        unsigned int cpu_index;
index 9e36136e54b427a623ef86385d29350a1050192b..201a2936b25c8927b951fa31f6259ce48782d91d 100644 (file)
@@ -114,10 +114,12 @@ start_of_setup:
        mov     dl,#0x81
        int     0x13
 
+#ifdef SAFE_RESET_DISK_CONTROLLER
 ! Reset the disk controller.
        mov     ax,#0x0000
        mov     dl,#0x80
        int     0x13
+#endif
 
 ! set DS=CS, we know that SETUPSEG == CS at this point
        mov     ax,cs           ! aka #SETUPSEG
index e94ed401bdb625837067a4b20b842c56254831b0..738bb42bd0bac0bbcceb06f0435f2d5c174ab0f1 100644 (file)
@@ -88,10 +88,11 @@ CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 # CONFIG_SLIP is not set
 # CONFIG_PPP is not set
+# CONFIG_STRIP is not set
 # CONFIG_SCC is not set
 # CONFIG_PLIP is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_FRAD is not set
+# CONFIG_DLCI is not set
 # CONFIG_NET_ALPHA is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_LANCE is not set
index b60390933756f8317b422cc43357d7f94691485a..92f73fea8a9c01bb04f35230711ce7f5035bcc4a 100644 (file)
@@ -263,27 +263,28 @@ int get_smp_prof_list(char *buf) {
        unsigned long sum_spins_sys_idle = 0;
        unsigned long sum_smp_idle_count = 0;
 
-       for (i=0;i<=smp_num_cpus;i++) {
-               sum_spins+=smp_spins[i];
-               sum_spins_syscall+=smp_spins_syscall[i];
-               sum_spins_sys_idle+=smp_spins_sys_idle[i];
-               sum_smp_idle_count+=smp_idle_count[i];
+       for (i=0;i<smp_num_cpus;i++) {
+               int cpunum = cpu_logical_map[i];
+               sum_spins+=smp_spins[cpunum];
+               sum_spins_syscall+=smp_spins_syscall[cpunum];
+               sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
+               sum_smp_idle_count+=smp_idle_count[cpunum];
        }
 
-       len += sprintf(buf+len,"CPUS: %10i \n", 
-               0==smp_num_cpus?1:smp_num_cpus);
+       len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
        len += sprintf(buf+len,"            SUM ");
        for (i=0;i<smp_num_cpus;i++)
-               len += sprintf(buf+len,"        P%1d ",i);
+               len += sprintf(buf+len,"        P%1d ",cpu_logical_map[i]);
        len += sprintf(buf+len,"\n");
        for (i = 0 ; i < NR_IRQS ; i++) {
                action = *(i + irq_action);
-               if (!action->handler)
+               if (!action || !action->handler)
                        continue;
                len += sprintf(buf+len, "%3d: %10d ",
                        i, kstat.interrupts[i]);
                for (j=0;j<smp_num_cpus;j++)
-                       len+=sprintf(buf+len, "%10d ",int_count[j][i]);
+                       len+=sprintf(buf+len, "%10d ",
+                               int_count[cpu_logical_map[j]][i]);
                len += sprintf(buf+len, "%c %s\n",
                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
                        action->name);
@@ -297,7 +298,7 @@ int get_smp_prof_list(char *buf) {
                sum_spins);
 
        for (i=0;i<smp_num_cpus;i++)
-               len+=sprintf(buf+len," %10lu",smp_spins[i]);
+               len+=sprintf(buf+len," %10lu",smp_spins[cpu_logical_map[i]]);
 
        len +=sprintf(buf+len,"   spins from int\n");
 
@@ -305,7 +306,7 @@ int get_smp_prof_list(char *buf) {
                sum_spins_syscall);
 
        for (i=0;i<smp_num_cpus;i++)
-               len+=sprintf(buf+len," %10lu",smp_spins_syscall[i]);
+               len+=sprintf(buf+len," %10lu",smp_spins_syscall[cpu_logical_map[i]]);
 
        len +=sprintf(buf+len,"   spins from syscall\n");
 
@@ -313,13 +314,13 @@ int get_smp_prof_list(char *buf) {
                sum_spins_sys_idle);
 
        for (i=0;i<smp_num_cpus;i++)
-               len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[i]);
+               len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[cpu_logical_map[i]]);
 
        len +=sprintf(buf+len,"   spins from sysidle\n");
        len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
 
        for (i=0;i<smp_num_cpus;i++)
-               len+=sprintf(buf+len," %10lu",smp_idle_count[i]);
+               len+=sprintf(buf+len," %10lu",smp_idle_count[cpu_logical_map[i]]);
 
        len +=sprintf(buf+len,"   idle ticks\n");
 
index 1468b011fd6f1a267535d64d478266cb01708bc0..e3cab9941c461f35891de1e48ba3b0fa9fb39b72 100644 (file)
@@ -2592,7 +2592,8 @@ static void redo_fd_request(void)
                floppy_off(current_drive);
 
        if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
-               DPRINT("current not active!\n");
+               CLEAR_INTR;
+               unlock_fdc();
                return;
        }
 
@@ -3335,7 +3336,7 @@ static void config_types(void)
                               sizeof(struct floppy_drive_params));
                if (UDP->cmos){
                        if (first)
-                               printk("Floppy drive(s): ");
+                               printk(KERN_INFO "Floppy drive(s): ");
                        else
                                printk(", ");
                        first=0;
@@ -3622,7 +3623,7 @@ static char get_fdc_version(void)
        if ((r = result()) <= 0x00)
                return FDC_NONE;        /* No FDC present ??? */
        if ((r==1) && (reply_buffer[0] == 0x80)){
-               printk("FDC %d is a 8272A\n",fdc);
+               printk(KERN_INFO "FDC %d is a 8272A\n",fdc);
                return FDC_8272A;       /* 8272a/765 don't know DUMPREGS */
        }
        if (r != 10) {
@@ -3633,7 +3634,7 @@ static char get_fdc_version(void)
        output_byte(FD_VERSION);
        r = result();
        if ((r == 1) && (reply_buffer[0] == 0x80)){
-               printk("FDC %d is a 82072\n",fdc);
+               printk(KERN_INFO "FDC %d is a 82072\n",fdc);
                return FDC_82072;               /* 82072 doesn't know VERSION */
        }
        if ((r != 1) || (reply_buffer[0] != 0x90)) {
@@ -3644,7 +3645,7 @@ static char get_fdc_version(void)
        output_byte(FD_UNLOCK);
        r = result();
        if ((r == 1) && (reply_buffer[0] == 0x80)){
-               printk("FDC %d is a pre-1991 82077\n", fdc);
+               printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc);
                return FDC_82077_ORIG;  /* Pre-1991 82077 doesn't know LOCK/UNLOCK */
        }
        if ((r != 1) || (reply_buffer[0] != 0x00)) {
@@ -3660,7 +3661,7 @@ static char get_fdc_version(void)
                return FDC_UNKNOWN;
        }
        if (reply_buffer[0] == 0x80) {
-               printk("FDC %d is a post-1991 82077\n",fdc);
+               printk(KERN_INFO "FDC %d is a post-1991 82077\n",fdc);
                return FDC_82077;       /* Revised 82077AA passes all the tests */
        }
        switch (reply_buffer[0] >> 5) {
@@ -3672,23 +3673,23 @@ static char get_fdc_version(void)
                                return FDC_UNKNOWN;
                        }
                        if (!(reply_buffer[0] & 0x40)) {
-                               printk("FDC %d is a 3Volt 82078SL.\n",fdc);
+                               printk(KERN_INFO "FDC %d is a 3Volt 82078SL.\n",fdc);
                                return FDC_82078;
                        }
                        /* Either a 82078-1 or a 82078SL running at 5Volt */
-                       printk("FDC %d is a 82078-1.\n",fdc);
+                       printk(KERN_INFO "FDC %d is a 82078-1.\n",fdc);
                        return FDC_82078_1;
                case 0x1:
-                       printk("FDC %d is a 44pin 82078\n",fdc);
+                       printk(KERN_INFO "FDC %d is a 44pin 82078\n",fdc);
                        return FDC_82078;
                case 0x2:
-                       printk("FDC %d is a S82078B\n", fdc);
+                       printk(KERN_INFO "FDC %d is a S82078B\n", fdc);
                        return FDC_S82078B;
                case 0x3:
-                       printk("FDC %d is a National Semiconductor PC87306\n", fdc);
+                       printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n", fdc);
                        return FDC_87306;
                default:
-                       printk("FDC %d init: 82077 variant with PARTID=%d.\n",
+                       printk(KERN_INFO "FDC %d init: 82077 variant with PARTID=%d.\n",
                               fdc, reply_buffer[0] >> 5);
                        return FDC_82077_UNKN;
        }
@@ -4061,7 +4062,7 @@ extern "C" {
 #endif
 int init_module(void)
 {
-       printk("inserting floppy driver for %s\n", kernel_version);
+       printk(KERN_INFO "inserting floppy driver for %s\n", kernel_version);
                
        mod_setup("floppy=", floppy_setup);
                
index 6a100146ccc4a7044e7d40141dae0463289865b8..22361857f8bcb7615940af911525963aed2ffbd6 100644 (file)
@@ -2105,6 +2105,14 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
        return 0;
       }
 
+    case CDROMCLOSETRAY:
+      {
+        if (drive->usage > 1)
+          return -EBUSY;
+
+        return cdrom_eject (drive, 1, NULL);
+      }
+
     case CDROMPAUSE:
       return cdrom_pause (drive, 1, NULL);
 
index 4a71e38a989bed13b1e8788de5d7e1787cb618aa..6c23e893362100b8814340b2b9b0df21d444f71b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 5.35  Mar 23, 1996
+ *  linux/drivers/block/ide.c  Version 5.36  Mar 30, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
  *                     fix cdrom ioctl problem from 5.33
  * Version 5.35                cosmetic changes
  *                     fix cli() problem in try_to_identify()
+ * Version 5.36                fixes to optional PCMCIA support
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -3233,7 +3234,7 @@ int ide_register(int io_base, int ctl_port, int irq)
                hwif = &ide_hwifs[index];
                if (hwif->present) {
                        if (hwif->io_base == io_base || hwif->ctl_port == ctl_port)
-                               break;
+                               break; /* this ide port already exists */
                } else {
                        hwif->io_base = io_base;
                        hwif->ctl_port = ctl_port;
@@ -3241,10 +3242,10 @@ int ide_register(int io_base, int ctl_port, int irq)
                        hwif->noprobe = 0;
                        if (!hwif_init(index))
                                break;
-                       hwif->gd->real_devices = hwif->drives[0].name;
                        for (i = 0; i < hwif->gd->nr_real; i++)
                                revalidate_disk(MKDEV(hwif->major, i<<PARTN_BITS));
                        rc = index;
+                       break;
                }
        }
        restore_flags(flags);
@@ -3253,7 +3254,7 @@ int ide_register(int io_base, int ctl_port, int irq)
 
 void ide_unregister (unsigned int index)
 {
-       struct gendisk *prev_gd, *gd;
+       struct gendisk *gd, **gdp;
        ide_hwif_t *hwif, *g;
        ide_hwgroup_t *hwgroup;
        int irq_count = 0;
@@ -3283,6 +3284,14 @@ void ide_unregister (unsigned int index)
        if (irq_count == 1)
                free_irq(hwif->irq, hwgroup);
 
+       /*
+        * Note that we only release the standard ports,
+        * and do not even try to handle any extra ports
+        * allocated for weird IDE interface chipsets.
+        */
+       release_region(hwif->io_base, 8);
+       release_region(hwif->ctl_port, 1);
+
        /*
         * Remove us from the hwgroup, and free
         * the hwgroup if we were the only member
@@ -3304,18 +3313,13 @@ void ide_unregister (unsigned int index)
        kfree(blksize_size[hwif->major]);
        blk_dev[hwif->major].request_fn = NULL;
        blksize_size[hwif->major] = NULL;
-       gd = gendisk_head; prev_gd = NULL;
-       while (gd && (gd != hwif->gd)) {
-               prev_gd = gd;
-               gd = gd->next;
-       }
-       if (gd != hwif->gd)
+       for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+               if (*gdp == hwif->gd)
+                       break;
+       if (*gdp == NULL)
                printk("gd not in disk chain!\n");
        else {
-               if (prev_gd != NULL)
-                       prev_gd->next = gd->next;
-               else
-                       gendisk_head = gd->next;
+               gd = *gdp; *gdp = gd->next;
                kfree(gd->sizes);
                kfree(gd->part);
                kfree(gd);
index 0476402f1b82ed7f8195ccfa97f11c996176dd33..ce9c63847b37318e56696b5d8d17fc2bf5367316 100644 (file)
@@ -389,6 +389,7 @@ static inline int remap_request (int minor, struct request *req)
 static void do_md_request (void)
 {
   int minor;
+  long flags;
   struct request *req;
     
   while (1)
@@ -396,12 +397,13 @@ static void do_md_request (void)
 #ifdef MD_COUNT_SIZE
     int reqsize, chunksize;
 #endif
-    
+
+    save_flags (flags);
     cli ();
     req = blk_dev[MD_MAJOR].current_request;
     if (!req || (req->rq_status == RQ_INACTIVE))
     {
-      sti ();
+      restore_flags (flags);
       return;
     }
     
@@ -414,7 +416,7 @@ static void do_md_request (void)
 #endif
     
     blk_dev[MD_MAJOR].current_request = req->next;
-    sti ();
+    restore_flags (flags);
 
     minor = MINOR(req->rq_dev);
     if ((MAJOR(req->rq_dev) != MD_MAJOR) || (minor >= MAX_REAL))
@@ -486,7 +488,7 @@ void make_md_request (struct request *pending, int n)
 
       while (req && !found)
       {
-       if (req->rq_status!=RQ_ACTIVE)
+       if (req->rq_status!=RQ_ACTIVE && &blk_dev[major].plug!=req)
          printk ("Saw bad status request !\n");
 
        if (req->rq_dev == dev &&
index 6ed1f2eb39b28d647046642001e64b3bc31f6ebc..b57ff567dd31fee4d7c6d007df219ce99e990ec2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/triton.c       Version 1.08  Mar 13, 1996
+ *  linux/drivers/block/triton.c       Version 1.09  Mar 31, 1996
  *
  *  Copyright (c) 1995-1996  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  * known to work fine with this interface under Linux.
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
-                                "Maxtor 71260 AT",
+                                /* "Maxtor 71260 AT", known-bad! */
                                 "CONNER CTMA 4000"};
 
 /*
index 192a0b1c319054b9057c0c76f82043c9041d0aa1..1a251220a4b77c46f0bdcfd28e841c45f4d2af23 100644 (file)
@@ -1,8 +1,8 @@
-#define AZT_VERSION "2.1"
-/*      $Id: aztcd.c,v 2.10 1995/12/03 11:55:09 root Exp root $
+#define AZT_VERSION "2.2"
+/*      $Id: aztcd.c,v 2.20 1996/03/12 18:31:23 root Exp root $
        linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
 
-       Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
+       Copyright (C) 1994,95,96 Werner Zimmermann(zimmerma@rz.fht-esslingen.de)
 
        based on Mitsumi CDROM driver by  Martin Hariss and preworks by
        Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby 
                 with kernel 1.3.33. Will definitely not work with older kernels.
                 Programming done by Linus himself.
                 Werner Zimmermann, October 11, 1995
-       V1.90   Support for Conrad TXC drives, thank's to Jochen Koch and Olaf Kaluza.
+       V1.90   Support for Conrad TXC drives, thank's to Jochen Kunz and Olaf Kaluza.
                Werner Zimmermann, October 21, 1995
         V2.00   Changed #include "blk.h" to <linux/blk.h> as the directory
                 structure was changed. README.aztcd is now /usr/src/docu-
@@ -1545,7 +1545,7 @@ int aztcd_init(void)
          printk("aztcd: no Aztech CD-ROM Initialization");
           return -EIO;
        }
-       printk("aztcd: Aztech,Orchid,Okano,Wearnes,TXC CD-ROM Driver (C) 1994,1995 W.Zimmermann\n");
+       printk("aztcd: Aztech,Orchid,Okano,Wearnes,Txc CD-ROM Driver (C) 1994,95,96 W.Zimmermann\n");
        printk("aztcd: DriverVersion=%s BaseAddress=0x%x  For IDE/ATAPI-drives use ide-cd.c\n",AZT_VERSION,azt_port);
        printk("aztcd: If you have problems, read /usr/src/linux/Documentation/cdrom/aztcd\n");
 
@@ -1562,7 +1562,7 @@ int aztcd_init(void)
                  return -EIO;
           }
         else                
-           { printk("aztcd: Soundwave32 card detected at %x  Version %x\n",
+           { printk(KERN_INFO "aztcd: Soundwave32 card detected at %x  Version %x\n",
                 AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
             outw(AZT_SW32_INIT,AZT_SW32_CONFIG_REG);
             for (count=0;count<10000;count++);          /*delay a bit*/         
@@ -1643,7 +1643,7 @@ int aztcd_init(void)
         }
        if (count>30) max_count=30;  /*print max.30 chars of the version string*/
        else          max_count=count;
-       printk("aztcd: FirmwareVersion=");
+       printk(KERN_INFO "aztcd: FirmwareVersion=");
        for (count=1;count<max_count;count++) printk("%c",result[count]);
        printk("<<>> ");
 
@@ -2098,6 +2098,6 @@ void cleanup_module(void)
       return;
     }
    release_region(azt_port,4);
-   printk("aztcd module released.\n");
+   printk(KERN_INFO "aztcd module released.\n");
 }   
 #endif MODULE
index b20f1dda9484a4fd1385664c6153565e7b36a0b6..5db4d7f5938c588402dfec994af00e14b3ad6c4a 100644 (file)
@@ -3092,11 +3092,11 @@ cdu31a_init(void)
         }
       }
       
-      printk("Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
+      printk(KERN_INFO "Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
             drive_config.vendor_id,
             drive_config.product_id,
             drive_config.product_rev_level);
-      printk("  Capabilities: %s",
+      printk(KERN_INFO "  Capabilities: %s",
             load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]);
       if (SONY_HWC_AUDIO_PLAYBACK(drive_config))
       {
@@ -3173,6 +3173,6 @@ cleanup_module(void)
       free_irq(cdu31a_irq, NULL);
 
    release_region(cdu31a_port,4);
-   printk("cdu31a module released.\n");
+   printk(KERN_INFO "cdu31a module released.\n");
 }   
 #endif MODULE
index 6561f9722c95f90c1d0e3274ce8f66aea9eb8e30..2996fdb6cd326ed51bdd31a79e1256e32242710b 100644 (file)
@@ -1119,7 +1119,7 @@ int cm206_init(void)
   uch e=0;
   long int size=sizeof(struct cm206_struct);
 
-  printk("cm206: v" VERSION);
+  printk(KERN_INFO "cm206: v" VERSION);
   cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
   if (!cm206_base) {
     printk(" can't find adapter!\n");
@@ -1151,7 +1151,7 @@ int cm206_init(void)
       return -EIO;
     }
   e = send_receive_polled(c_gimme);
-  printk("Firmware revision %d", e & dcf_revision_code);
+  printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code);
   if (e & dcf_transfer_rate) printk(" double");
   else printk(" single");
   printk(" speed drive");
@@ -1176,7 +1176,7 @@ int cm206_init(void)
   cd->adapter_last = -1;
   cd->timer.function = cm206_timeout;
   cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97;
-  printk("%d kB adapter memory available, "  
+  printk(KERN_INFO "%d kB adapter memory available, "  
         " %ld bytes kernel memory used.\n", cd->max_sectors*2, size);
   return 0;
 }
@@ -1212,7 +1212,7 @@ int init_module(void)
 void cleanup_module(void)
 {
   cleanup(4);
-  printk("cm206 removed\n");
+  printk(KERN_INFO "cm206 removed\n");
 }
       
 #else /* !MODULE */
index b105a894938018c5d3a8b85c5eb3a570790a2382..85f624e6b917a5206fa18750c1327e8c27f53542 100644 (file)
@@ -967,7 +967,7 @@ long err;
      }
      else
      {
-        printk ( "Happy GoldStar !\n" );
+        printk (KERN_INFO "Happy GoldStar !\n" );
         return 0;
      }    
 }
@@ -982,7 +982,7 @@ void cleanup_module (void)
    }
 
    release_region (gscd_port,4);
-   printk( "GoldStar-module released.\n" );
+   printk(KERN_INFO "GoldStar-module released.\n" );
 }
 #endif
 
@@ -1001,8 +1001,8 @@ int my_gscd_init (void)
 int i;
 int result;
 
-        printk ("GSCD: version %s\n", GSCD_VERSION);
-        printk ("GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port);
+        printk (KERN_INFO "GSCD: version %s\n", GSCD_VERSION);
+        printk (KERN_INFO "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port);
 
         if (check_region(gscd_port, 4)) 
         {
@@ -1041,7 +1041,7 @@ int result;
         while ( drv_states[i] != 0 )
         {
            curr_drv_state = drv_states[i];
-           printk ( "GSCD: Reset unit %d ... ",i );
+           printk (KERN_INFO "GSCD: Reset unit %d ... ",i );
            cc_Reset ();
            printk ( "done\n" );
            i++;
@@ -1062,7 +1062,7 @@ int result;
 
        request_region(gscd_port, 4, "gscd");
 
-        printk ( "GSCD: GoldStar CD-ROM Drive found.\n" );
+        printk (KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n" );
        return 0;
 }
 
index 36aa45315a56ced013e755263e48b208a162ac9f..2637cdb363a04a05bb542c38bc52eaedb34d8551 100644 (file)
@@ -93,7 +93,7 @@ isp16_init(void)
 {
   u_char expected_drive;
 
-  printk("ISP16: configuration cdrom interface, version %d.%d.\n", ISP16_VERSION_MAJOR,
+  printk(KERN_INFO "ISP16: configuration cdrom interface, version %d.%d.\n", ISP16_VERSION_MAJOR,
     ISP16_VERSION_MINOR);
 
   if ( !strcmp(isp16_cdrom_type, "noisp16") ) {
@@ -111,7 +111,7 @@ isp16_init(void)
     return(-EIO);
   }
 
-  printk("ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n",
+  printk(KERN_INFO "ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n",
     (isp16_type==2) ? 9 : 8);
 
   if ( !strcmp(isp16_cdrom_type, "Sanyo") )
@@ -132,7 +132,7 @@ isp16_init(void)
     printk("ISP16: cdrom interface has not been properly configured.\n");
     return(-EIO);
   }
-  printk("ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d,"
+  printk(KERN_INFO "ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d,"
     " type %s.\n", isp16_cdrom_base, isp16_cdrom_irq, isp16_cdrom_dma,
     isp16_cdrom_type);
   return(0);
@@ -310,6 +310,6 @@ int init_module(void)
 void cleanup_module(void)
 {
        release_region(ISP16_IO_BASE, ISP16_IO_SIZE);
-       printk("ISP16: module released.\n");
+       printk(KERN_INFO "ISP16: module released.\n");
 }
 #endif /* MODULE */
index 9971ddd5b85259c4f90d654c5506fd6d5e691af3..98183d9b917754eaaf0761dba44b918df949fd73 100644 (file)
@@ -1172,7 +1172,7 @@ int mcd_init(void)
           return -EIO;
        }
 
-       printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
+       printk(KERN_INFO "mcd=0x%x,%d: ", mcd_port, mcd_irq);
 
        if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
        {
@@ -1627,6 +1627,6 @@ void cleanup_module(void)
      }
   release_region(mcd_port,4);
   free_irq(mcd_irq, NULL);
-  printk("mcd module released.\n");
+  printk(KERN_INFO "mcd module released.\n");
 }
 #endif MODULE
index 6035b67f7674298cbd0734257d558d18843f46fb..fdac53acb9ac7774e37b7a2ff4a4b10a18f2b136 100644 (file)
@@ -2059,7 +2059,7 @@ int optcd_init(void)
        read_ahead[MAJOR_NR] = 4;
        request_region(optcd_port, 4, "optcd");
 
-       printk("optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
+       printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
        return 0;
 }
 
@@ -2078,6 +2078,6 @@ void cleanup_module(void)
                return;
        }
        release_region(optcd_port, 4);
-       printk("optcd: module released.\n");
+       printk(KERN_INFO "optcd: module released.\n");
 }
 #endif MODULE
index fc57f801a2e77b68d8d55835d3cd492046519906..22e69431e9b3575fbae14bcd8705c7167cb037d1 100644 (file)
@@ -1447,7 +1447,7 @@ static struct {
 int sjcd_init( void ){
   int i;
 
-  printk("SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
+  printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
     SJCD_VERSION_MINOR);
 
 #if defined( SJCD_TRACE )
@@ -1473,7 +1473,7 @@ int sjcd_init( void ){
    * Check for card. Since we are booting now, we can't use standard
    * wait algorithm.
    */
-  printk( "SJCD: Resetting: " );
+  printk(KERN_INFO "SJCD: Resetting: " );
   sjcd_send_cmd( SCMD_RESET );
   for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
     unsigned long timer;
@@ -1494,7 +1494,7 @@ int sjcd_init( void ){
   /*
    * Get and print out cdrom version.
    */
-  printk( "SJCD: Getting version: " );
+  printk(KERN_INFO "SJCD: Getting version: " );
   sjcd_send_cmd( SCMD_GET_VERSION );
   for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
     unsigned long timer;
@@ -1525,7 +1525,7 @@ int sjcd_init( void ){
    * Check and print out the tray state. (if it is needed?).
    */
   if( !sjcd_status_valid ){
-    printk( "SJCD: Getting status: " );
+    printk(KERN_INFO "SJCD: Getting status: " );
     sjcd_send_cmd( SCMD_GET_STATUS );
     for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
       unsigned long timer;
@@ -1544,7 +1544,7 @@ int sjcd_init( void ){
     } else printk( "\n" );
   }
 
-  printk("SJCD: Status: port=0x%x.\n", sjcd_base);
+  printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base);
 
   sjcd_present++;
   return( 0 );
@@ -1573,6 +1573,6 @@ void cleanup_module(void)
   if ( sjcd_cleanup() )
     printk( "SJCD: module: cannot be removed.\n" );
   else
-    printk( "SJCD: module: removed.\n");
+    printk(KERN_INFO "SJCD: module: removed.\n");
 }
 #endif
index 97ccb544bb4dd2547c395ddae6754ce96c8e5f32..ce79146a6d05b563508b9dfeabbe5835d0176c98 100644 (file)
@@ -1512,7 +1512,7 @@ sony535_init(void)
        sony535_irq_used = 0;
 
 #if DEBUG > 0
-       printk(CDU535_MESSAGE_NAME ": probing base address %03X\n",
+       printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n",
                        sony535_cd_base_io);
 #endif
        if (check_region(sony535_cd_base_io,4)) {
@@ -1579,7 +1579,7 @@ sony535_init(void)
                                sony_buffer_size = SONY535_BUFFER_SIZE;
                                sony_buffer_sectors = sony_buffer_size / 2048;
 
-                               printk(CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
+                               printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
                                           drive_config.vendor_id,
                                           drive_config.product_id,
                                           drive_config.product_rev_level);
@@ -1684,6 +1684,6 @@ cleanup_module(void)
        if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
                printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
        else
-               printk(CDU535_HANDLE " module released\n");
+               printk(KERN_INFO CDU535_HANDLE " module released\n");
 }
 #endif /* MODULE */
index 3db41b06ee2b2744d163c49323693e7b633d722a..67ed7dd4a238c0fb6a852b7f58b30ac0b2510ce4 100644 (file)
@@ -207,7 +207,7 @@ int atixl_busmouse_init(void)
        b = inb( ATIXL_MSE_SIGNATURE_PORT );
        c = inb( ATIXL_MSE_SIGNATURE_PORT );
        if (( a != b ) && ( a == c ))
-               printk("\nATI Inport ");
+               printk(KERN_INFO "\nATI Inport ");
        else{
                mouse.present = 0;
                return -EIO;
index 69f387ab091ce5413f44a0dbcb3b8ba689873de6..75663af5642de951e127beaea6f632edfb58effb 100644 (file)
@@ -270,7 +270,7 @@ int bus_mouse_init(void)
        mouse.dx = 0;
        mouse.dy = 0;
        mouse.wait = NULL;
-       printk("Logitech bus mouse detected, using IRQ %d.\n",
+       printk(KERN_INFO "Logitech bus mouse detected, using IRQ %d.\n",
               mouse_irq);
        misc_register(&bus_mouse);
        return 0;
index e497343d9115a99000c3e88ea23c0b43ece1ef4a..f4c58d423270f4daea1050a693914704e7da00b4 100644 (file)
@@ -792,7 +792,7 @@ void cleanup_module()
        printk("cleanup_module()\n");
 #endif
 
-       printk("Unloading %s: version %s\n", stli_drvname, stli_drvversion);
+       printk(KERN_INFO "Unloading %s: version %s\n", stli_drvname, stli_drvversion);
 
        save_flags(flags);
        cli();
@@ -4499,7 +4499,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 
 int stli_init()
 {
-       printk("%s: version %s\n", stli_drvname, stli_drvversion);
+       printk(KERN_INFO "%s: version %s\n", stli_drvname, stli_drvversion);
 
        stli_initbrds();
 
index 8ddd95d53067906bc1c7330acc43c3a5ec7ce96a..1c4742fdd4773b6b5dd3f994a68419fbb1042244 100644 (file)
@@ -553,7 +553,7 @@ static int lp_probe(int offset)
        if (testvalue == LP_DUMMY) {
                LP_F(offset) |= LP_EXIST;
                lp_reset(offset);
-               printk("lp%d at 0x%04x, ", offset, base);
+               printk(KERN_INFO "lp%d at 0x%04x, ", offset, base);
                request_region(base, size, "lp");
                if (LP_IRQ(offset))
                        printk("(irq = %d)\n", LP_IRQ(offset));
index 2de6c9f52f8c918ac2fff96a784efc64cb693cb0..57f14d46627db610d7cc62a3863b5f2a3e902020 100644 (file)
  *
  * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
  *
- * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-May-96
+ * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
+ *
+ * Handling of mouse minor numbers for kerneld:
+ *  Idea by Jacques Gelinas <jack@solucorp.qc.ca>,
+ *  adapted by Bjorn Ekwall <bj0rn@blox.se>
+ *  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/malloc.h>
@@ -37,6 +42,9 @@
 
 #include <linux/tty.h> /* needed by selection.h */
 #include "selection.h" /* export its symbols */
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 /*
  * Head entry for the doubly linked miscdevice list
@@ -76,17 +84,25 @@ static int misc_open(struct inode * inode, struct file * file)
        struct miscdevice *c = misc_list.next;
        file->f_op = NULL;
 
-       while (c != &misc_list) {
-               if (c->minor == minor) {
-                       file->f_op = c->fops;
-                       break;
-               }
+       while ((c != &misc_list) && (c->minor != minor))
                c = c->next;
+       if (c == &misc_list) {
+#ifdef CONFIG_KERNELD
+               char modname[20];
+               sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
+               request_module(modname);
+               c = misc_list.next;
+               while ((c != &misc_list) && (c->minor != minor))
+                       c = c->next;
+               if (c == &misc_list)
+#endif
+                       return -ENODEV;
        }
 
-       if (file->f_op == NULL)
+       if ((file->f_op = c->fops))
+               return file->f_op->open(inode,file);
+       else
                return -ENODEV;
-        return file->f_op->open(inode,file);
 }
 
 static struct file_operations misc_fops = {
@@ -145,7 +161,7 @@ int misc_deregister(struct miscdevice * misc)
 
 void cleanup_module(void)
 {
-       unregister_chrdev(MOUSE_MAJOR, "misc");
+       unregister_chrdev(MISC_MAJOR, "misc");
 }
 
 #endif
index 19ad1c01831d60a5b45770be9928e7450e384b9d..9831f3ff617338e5cf30a7aa8fac889cc45584c4 100644 (file)
@@ -204,7 +204,7 @@ int ms_bus_mouse_init(void)
                return -EIO;
        MS_MSE_INT_OFF();
        request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
-       printk("Microsoft BusMouse detected and installed.\n");
+       printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
        misc_register(&ms_bus_mouse);
        return 0;
 }
index 226d79e0c797a27bb95b4724a13b42c6a129e54f..1e1a3e8666ba3dde3af2d7c778a5ae63f172f40b 100644 (file)
@@ -491,7 +491,7 @@ int psaux_init(void)
 
 #ifdef CONFIG_82C710_MOUSE
        if ((qp_found = probe_qp())) {
-               printk("82C710 type pointing device detected -- driver installed.\n");
+               printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
 /*             printk("82C710 address = %x (should be 0x310)\n", qp_data); */
                qp_present = 1;
                psaux_fops.write = write_qp;
@@ -500,7 +500,7 @@ int psaux_init(void)
        } else
 #endif
        if (aux_device_present == 0xaa) {
-               printk("PS/2 auxiliary pointing device detected -- driver installed.\n");
+               printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
                aux_present = 1;
                kbd_read_mask = AUX_OBUF_FULL;
        } else {
index e70addbb35d62f30e4dc155ee08701a8d68379b5..d27e80a19c91c653fb783672363eceb77eae5c6e 100644 (file)
@@ -580,7 +580,7 @@ void cleanup_module()
        printk("cleanup_module()\n");
 #endif
 
-       printk("Unloading %s: version %s\n", stl_drvname, stl_drvversion);
+       printk(KERN_INFO "Unloading %s: version %s\n", stl_drvname, stl_drvversion);
 
        save_flags(flags);
        cli();
@@ -3131,7 +3131,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
 
 int stl_init(void)
 {
-       printk("%s: version %s\n", stl_drvname, stl_drvversion);
+       printk(KERN_INFO "%s: version %s\n", stl_drvname, stl_drvversion);
 
        stl_initbrds();
 
index bbbdc3f60bb244aaffa0211751af7faf6bfee72c..623546f63ce3cbdabe1076278d35b991e29677ef 100644 (file)
@@ -559,8 +559,9 @@ static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                         *      FIXME: is there a logic to whether to keep on trying or
                         *      reset immediately ?
                         */
-                       printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"
-                          " gp=%03x rp=%03x.\n", dev->name, txsr, axsr,
+                       if(el_debug>1)
+                               printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"
+                                       " gp=%03x rp=%03x.\n", dev->name, txsr, axsr,
                        inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));
                        dev->tbusy = 0;
                        mark_bh(NET_BH);
index b660a2d911b53999c97b6098b48376c1f39b4a8e..7de60114e16883828d0c91b654ae45d9b002ebb8 100644 (file)
@@ -1,8 +1,8 @@
 /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */
 /*
-       Written 1993,1994 by Donald Becker.
+       Written 1993-1995 by Donald Becker.
 
-       Copyright 1994 by Donald Becker.
+       Copyright 1994,1995 by Donald Becker.
        Copyright 1993 United States Government as represented by the
        Director, National Security Agency.      This software may be used and
        distributed according to the terms of the GNU Public License,
        packet latency but lower overhead.  If interrupts are disabled for an
        unusually long time it could also result in missed packets, but in
        practice this rarely happens.
-       
-       
+
+
        FIXES:
-               Alan Cox:       Removed the 'Unexpected interrupt' bug.
+               Alan Cox:       Removed the 'Unexpected interrupt' bug.
+               Michael Meskes: Upgraded to Donald Becker's version 1.07.
 */
 
-static const  char *version = "3c509.c:1.03 10/8/94 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/module.h>
 
@@ -64,7 +65,6 @@ int el3_debug = 2;
 #define EL3_DATA 0x00
 #define EL3_CMD 0x0e
 #define EL3_STATUS 0x0e
-#define ID_PORT 0x100
 #define         EEPROM_READ 0x80
 
 #define EL3_IO_EXTENT  16
@@ -78,11 +78,16 @@ enum c509cmd {
        TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
        RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
        TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
-       FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrMask = 14<<11,
-       SetReadZero = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+       FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+       SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
        SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
        StatsDisable = 22<<11, StopCoax = 23<<11,};
 
+enum c509status {
+       IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+       TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+       IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000, };
+
 /* The SetRxFilter command accepts the following classes: */
 enum RxFilter {
        RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
@@ -110,6 +115,7 @@ struct el3_private {
        int head, size;
        struct sk_buff *queue[SKB_QUEUE_SIZE];
 };
+static int id_port = 0x100;
 
 static ushort id_read_eeprom(int index);
 static ushort read_eeprom(short ioaddr, int index);
@@ -120,7 +126,9 @@ static void update_stats(int addr, struct device *dev);
 static struct enet_statistics *el3_get_stats(struct device *dev);
 static int el3_rx(struct device *dev);
 static int el3_close(struct device *dev);
+#ifdef HAVE_MULTICAST
 static void set_multicast_list(struct device *dev);
+#endif
 
 \f
 
@@ -178,31 +186,46 @@ int el3_probe(struct device *dev)
        }
 #endif
 
+       /* Reset the ISA PnP mechanism on 3c509b. */
+       outb(0x02, 0x279);           /* Select PnP config control register. */
+       outb(0x02, 0xA79);           /* Return to WaitForKey state. */
+       /* Select an open I/O location at 0x1*0 to do contention select. */
+       for (id_port = 0x100; id_port < 0x200; id_port += 0x10) {
+               outb(0x00, id_port);
+               outb(0xff, id_port);
+               if (inb(id_port) & 0x01)
+                       break;
+       }
+       if (id_port >= 0x200) {             /* GCC optimizes this test out. */
+               /* Rare -- do we really need a warning? */
+               printk(" WARNING: No I/O port available for 3c509 activation.\n");
+               return -ENODEV;
+       }
        /* Next check for all ISA bus boards by sending the ID sequence to the
           ID_PORT.  We find cards past the first by setting the 'current_tag'
           on cards as they are found.  Cards with their tag set will not
           respond to subsequent ID sequences. */
 
-       if (check_region(ID_PORT,1)) {
+       if (check_region(id_port,1)) {
          static int once = 1;
-         if (once) printk("3c509: Somebody has reserved 0x%x, can't do ID_PORT lookup, nor card auto-probing\n",ID_PORT);
-         once = 0;
-         return -ENODEV;
-       }
+         if (once) printk("3c509: Somebody has reserved 0x%x, can't do ID_PORT lookup, nor card auto-probing\n",id_port);
+          once = 0;
+          return -ENODEV;
+        }
 
-       outb(0x00, ID_PORT);
-       outb(0x00, ID_PORT);
+       outb(0x00, id_port);
+       outb(0x00, id_port);
        for(i = 0; i < 255; i++) {
-               outb(lrs_state, ID_PORT);
+               outb(lrs_state, id_port);
                lrs_state <<= 1;
                lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
        }
 
        /* For the first probe, clear all board's tag registers. */
        if (current_tag == 0)
-               outb(0xd0, ID_PORT);
+               outb(0xd0, id_port);
        else                            /* Otherwise kill off already-found boards. */
-               outb(0xd8, ID_PORT);
+               outb(0xd8, id_port);
 
        if (id_read_eeprom(7) != 0x6d50) {
                return -ENODEV;
@@ -220,18 +243,21 @@ int el3_probe(struct device *dev)
                if_port = iobase >> 14;
                ioaddr = 0x200 + ((iobase & 0x1f) << 4);
        }
-       irq = id_read_eeprom(9) >> 12;
+       if (dev->irq > 1  &&  dev->irq < 16)
+               irq = dev->irq;
+       else
+               irq = id_read_eeprom(9) >> 12;
 
        if (dev->base_addr != 0
-               &&      dev->base_addr != (unsigned short)ioaddr) {
+               &&      dev->base_addr != (unsigned short)ioaddr) {
                return -ENODEV;
        }
 
        /* Set the adaptor tag so that the next card can be found. */
-       outb(0xd0 + ++current_tag, ID_PORT);
+       outb(0xd0 + ++current_tag, id_port);
 
        /* Activate the adaptor at the EEPROM location. */
-       outb(0xff, ID_PORT);
+       outb((ioaddr >> 4) | 0xe0, id_port);
 
        EL3WINDOW(0);
        if (inw(ioaddr) != 0x6d50)
@@ -270,7 +296,9 @@ int el3_probe(struct device *dev)
        dev->hard_start_xmit = &el3_start_xmit;
        dev->stop = &el3_close;
        dev->get_stats = &el3_get_stats;
-       dev->set_multicast_list = &set_multicast_list;
+#ifdef HAVE_MULTICAST
+               dev->set_multicast_list = &set_multicast_list;
+#endif
 
        /* Fill in the generic fields of the device structure. */
        ether_setup(dev);
@@ -298,14 +326,14 @@ static ushort id_read_eeprom(int index)
 
        /* Issue read command, and pause for at least 162 us. for it to complete.
           Assume extra-fast 16Mhz bus. */
-       outb(EEPROM_READ + index, ID_PORT);
+       outb(EEPROM_READ + index, id_port);
 
        /* This should really be done by looking at one of the timer channels. */
        for (timer = 0; timer < 162*4 + 400; timer++)
                SLOW_DOWN_IO;
 
        for (bit = 15; bit >= 0; bit--)
-               word = (word << 1) + (inb(ID_PORT) & 0x01);
+               word = (word << 1) + (inb(id_port) & 0x01);
 
        if (el3_debug > 3)
                printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
@@ -323,10 +351,12 @@ el3_open(struct device *dev)
 
        outw(TxReset, ioaddr + EL3_CMD);
        outw(RxReset, ioaddr + EL3_CMD);
-       outw(SetReadZero | 0x00, ioaddr + EL3_CMD);
+       outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
-       if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev))
+       if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev)) {
+               irq2dev_map[dev->irq] = NULL;
                return -EAGAIN;
+       }
 
        EL3WINDOW(0);
        if (el3_debug > 3)
@@ -336,7 +366,6 @@ el3_open(struct device *dev)
        /* Activate board: this is probably unnecessary. */
        outw(0x0001, ioaddr + 4);
 
-
        /* Set the IRQ line. */
        outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
 
@@ -360,8 +389,8 @@ el3_open(struct device *dev)
        EL3WINDOW(6);
        for (i = 0; i < 9; i++)
                inb(ioaddr + i);
-       inb(ioaddr + 10);
-       inb(ioaddr + 12);
+       inw(ioaddr + 10);
+       inw(ioaddr + 12);
 
        /* Switch to register set 1 for normal use. */
        EL3WINDOW(1);
@@ -377,9 +406,12 @@ el3_open(struct device *dev)
        outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
        outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
        /* Allow status bits to be seen. */
-       outw(SetReadZero | 0xff, ioaddr + EL3_CMD);
-       outw(AckIntr | 0x69, ioaddr + EL3_CMD); /* Ack IRQ */
-       outw(SetIntrMask | 0x98, ioaddr + EL3_CMD); /* Set interrupt mask. */
+       outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+       /* Ack all pending events, and set active indicator mask. */
+       outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+                ioaddr + EL3_CMD);
+       outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull,
+                ioaddr + EL3_CMD);
 
        if (el3_debug > 3)
                printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
@@ -389,40 +421,80 @@ el3_open(struct device *dev)
        return 0;                                       /* Always succeed */
 }
 
-static void
-el3_tx(struct device *dev)
+static int
+el3_start_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct el3_private *lp = (struct el3_private *)dev->priv;
        int ioaddr = dev->base_addr;
-       struct sk_buff * skb;
 
-       if (el3_debug > 5)
-               printk("        TX room bit was handled.\n");
+       /* Transmitter timeout, serious problems. */
+       if (dev->tbusy) {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 40)
+                       return 1;
+               printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "
+                          "Tx FIFO room %d.\n",
+                          dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
+                          inw(ioaddr + TX_FREE));
+               lp->stats.tx_errors++;
+               dev->trans_start = jiffies;
+               /* Issue TX_RESET and TX_START commands. */
+               outw(TxReset, ioaddr + EL3_CMD);
+               outw(TxEnable, ioaddr + EL3_CMD);
+               dev->tbusy = 0;
+       }
 
-       outw(AckIntr | 0x08, ioaddr + EL3_CMD);
-       if (!lp->size)
-               return;
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
 
-       /* There's room in the FIFO for a full-sized packet. */
-       while (inw(ioaddr + TX_FREE) > 1536) {
-               skb = lp->queue[lp->head];
-               lp->head = (lp->head + 1) & (SKB_QUEUE_SIZE-1);
-               lp->size--;
+       if (skb->len <= 0)
+               return 0;
 
+       if (el3_debug > 4) {
+               printk("%s: el3_start_xmit(length = %ld) called, status %4.4x.\n",
+                          dev->name, skb->len, inw(ioaddr + EL3_STATUS));
+       }
+#if 0
+#ifndef final_version
+       {       /* Error-checking code, delete someday. */
+               ushort status = inw(ioaddr + EL3_STATUS);
+               if (status & 0x0001             /* IRQ line active, missed one. */
+                       && inw(ioaddr + EL3_STATUS) & 1) {                      /* Make sure. */
+                       printk("%s: Missed interrupt, status then %04x now %04x"
+                                  "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
+                                  inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
+                                  inw(ioaddr + RX_STATUS));
+                       /* Fake interrupt trigger by masking, acknowledge interrupts. */
+                       outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
+                       outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+                                ioaddr + EL3_CMD);
+                       outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+               }
+       }
+#endif
+#endif
+       /* Avoid timer-based retransmission conflicts. */
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk("%s: Transmitter access conflict.\n", dev->name);
+       else {
                /* Put out the doubleword header... */
                outw(skb->len, ioaddr + TX_FIFO);
                outw(0x00, ioaddr + TX_FIFO);
                /* ... and the packet rounded to a doubleword. */
                outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 
-               /* free the skb, we're done with it */
-               dev_kfree_skb(skb, FREE_WRITE);
                dev->trans_start = jiffies;
-               if (!lp->size)
-                       return;
+               if (inw(ioaddr + TX_FREE) > 1536) {
+                       dev->tbusy = 0;
+               } else
+                       /* Interrupt us when the FIFO has room for max-sized packet. */
+                       outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
        }
-       /* Interrupt us when the FIFO has room for max-sized packet. */
-       outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+
+       dev_kfree_skb (skb, FREE_WRITE);
+
        /* Clear the Tx status stack. */
        {
                short tx_status;
@@ -435,44 +507,6 @@ el3_tx(struct device *dev)
                        outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
                }
        }
-}
-
-static int
-el3_start_xmit(struct sk_buff *skb, struct device *dev)
-{
-       struct el3_private *lp = (struct el3_private *)dev->priv;
-       unsigned long flags;
-       int ioaddr = dev->base_addr;
-
-       save_flags(flags);
-       cli();
-       /*
-        * Do we have room in the send queue?
-        */
-       if (lp->size < SKB_QUEUE_SIZE) {
-               int tail = (lp->head + lp->size) & (SKB_QUEUE_SIZE-1);
-               lp->queue[tail] = skb;
-               lp->size++;
-               /* fake a transmit interrupt to get it started */
-               el3_tx(dev);
-               restore_flags(flags);
-               return 0;
-       }
-
-       /*
-        * No space, check if we might have timed out?
-        */
-       if (jiffies - dev->trans_start > HZ) {
-               printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-                          dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
-               dev->trans_start = jiffies;
-               /* Issue TX_RESET and TX_START commands. */
-               outw(TxReset, ioaddr + EL3_CMD);
-               outw(TxEnable, ioaddr + EL3_CMD);
-       }
-       /* free the skb, we might as well drop it on the floor */
-       dev_kfree_skb(skb, FREE_WRITE);
-       restore_flags(flags);
        return 0;
 }
 
@@ -499,16 +533,40 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        if (el3_debug > 4)
                printk("%s: interrupt, status %4.4x.\n", dev->name, status);
 
-       while ((status = inw(ioaddr + EL3_STATUS)) & 0x91) {
+       while ((status = inw(ioaddr + EL3_STATUS)) &
+                  (IntLatch | RxComplete | StatsFull)) {
 
-               if (status & 0x10)
+               if (status & RxComplete)
                        el3_rx(dev);
 
-               if (status & 0x08)
-                       el3_tx(dev);
-
-               if (status & 0x80)                              /* Statistics full. */
-                       update_stats(ioaddr, dev);
+               if (status & TxAvailable) {
+                       if (el3_debug > 5)
+                               printk("        TX room bit was handled.\n");
+                       /* There's room in the FIFO for a full-sized packet. */
+                       outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }
+               if (status & (AdapterFailure | RxEarly | StatsFull)) {
+                       /* Handle all uncommon interrupts. */
+                       if (status & StatsFull)                         /* Empty statistics. */
+                               update_stats(ioaddr, dev);
+                       if (status & RxEarly) {                         /* Rx early is unused. */
+                               el3_rx(dev);
+                               outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+                       }
+                       if (status & AdapterFailure) {
+                               /* Adapter failure requires Rx reset and reinit. */
+                               outw(RxReset, ioaddr + EL3_CMD);
+                               /* Set the Rx filter to the current state. */
+                               outw(SetRxFilter | RxStation | RxBroadcast
+                                        | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)
+                                        | (dev->flags & IFF_PROMISC ? RxProm : 0),
+                                        ioaddr + EL3_CMD);
+                               outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+                               outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+                       }
+               }
 
                if (++i > 10) {
                        printk("%s: Infinite loop in interrupt, status %4.4x.\n",
@@ -518,8 +576,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        break;
                }
                /* Acknowledge the IRQ. */
-               outw(AckIntr | 0x41, ioaddr + EL3_CMD); /* Ack IRQ */
-
+               outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */
        }
 
        if (el3_debug > 4) {
@@ -610,7 +667,7 @@ el3_rx(struct device *dev)
                                           pkt_len, rx_status);
                        if (skb != NULL) {
                                skb->dev = dev;
-                               skb_reserve(skb,2);     /* Align IP on 16 byte boundaries */
+                               skb_reserve(skb,2);     /* Align IP on 16 byte */
 
                                /* 'skb->data' points to the start of sk_buff data area. */
                                insl(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
@@ -635,11 +692,12 @@ el3_rx(struct device *dev)
        return 0;
 }
 
-/* 
- *     Set or clear the multicast filter for this adaptor.
+#ifdef HAVE_MULTICAST
+/*
+ *     Set or clear the multicast filter for this adaptor.
  */
-static void set_multicast_list(struct device *dev)
+static void
+set_multicast_list(struct device *dev)
 {
        short ioaddr = dev->base_addr;
        if (el3_debug > 1) {
@@ -649,18 +707,17 @@ static void set_multicast_list(struct device *dev)
                        printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
                }
        }
-       if (dev->flags&IFF_PROMISC) 
-       {
+       if (dev->flags&IFF_PROMISC) {
                outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
                         ioaddr + EL3_CMD);
        }
-       else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) 
-       {
-               outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-       } 
+       else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {
+               outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
+       }
        else
-               outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
 }
+#endif
 
 static int
 el3_close(struct device *dev)
@@ -703,22 +760,14 @@ el3_close(struct device *dev)
 #ifdef MODULE
 static char devicename[9] = { 0, };
 static struct device dev_3c509 = {
-       devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-       0, 0, 0, 0,
-       0, 0,
-       0, 0, 0, NULL, el3_probe };
-
-static int io = 0;
-static int irq = 0;
+        devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+        0, 0, 0, 0,
+        0, 0,
+        0, 0, 0, NULL, el3_probe };
 
 int
 init_module(void)
 {
-       dev_3c509.base_addr = io;
-       dev_3c509.irq       = irq;
-       if (!EISA_bus && !io) {
-               printk("3c509: WARNING! Module load-time probing works reliably only for EISA-bus!\n");
-       }
        if (register_netdev(&dev_3c509) != 0)
                return -EIO;
        return 0;
@@ -727,11 +776,16 @@ init_module(void)
 void
 cleanup_module(void)
 {
-       unregister_netdev(&dev_3c509);
-       kfree_s(dev_3c509.priv,sizeof(struct el3_private));
-       dev_3c509.priv=NULL;
-       /* If we don't do this, we can't re-insmod it later. */
-       release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
+       if (MOD_IN_USE)
+               printk("3c509: device busy, remove delayed\n");
+       else
+       {
+               unregister_netdev(&dev_3c509);
+               kfree_s(dev_3c509.priv,sizeof(struct el3_private));
+               dev_3c509.priv=NULL;
+               /* If we don't do this, we can't re-insmod it later. */
+               release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
+       }
 }
 #endif /* MODULE */
 \f
index cb843d30f771a32514543a99901c07c923849b9c..35fed8e55f94e44ae1c93a1d3686d13b595c38fb 100644 (file)
@@ -11,15 +11,16 @@ tristate 'PPP (point-to-point) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
   comment 'CCP compressors for PPP are only built as modules.'
 fi
+tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
 tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
 tristate 'PLIP (parallel port) support' CONFIG_PLIP
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 
-tristate 'FRAD (Frame Relay Access Device) support' CONFIG_FRAD
-if [ "$CONFIG_FRAD" = "y" -o "$CONFIG_FRAD" = "m" ]; then
+tristate 'DLCI (Frame relay) support' CONFIG_DLCI
+if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
   int '  Max open DLCI' CONFIG_DLCI_COUNT 24
   int '  Max DLCI per device' CONFIG_DLCI_MAX 8
-  tristate '  Sangoma S502A FRAD support' CONFIG_SDLA
+  tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA
 fi
 
 bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA
@@ -30,6 +31,9 @@ if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
   tristate 'SMC 9194 support' CONFIG_SMC9194
 fi
 bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+if [ "$CONFIG_LANCE" = "y" ]; then
+  bool 'AMD PCInet32 (VLB and PCI) support' CONFIG_LANCE32
+fi  
 bool '3COM cards' CONFIG_NET_VENDOR_3COM
 if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
   tristate '3c501 support' CONFIG_EL1
@@ -97,3 +101,4 @@ if [ "$CONFIG_ARCNET" != "n" ]; then
   bool '  Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
   bool '  Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
 fi
+
index 8d181bb78485b2aafdd27946e889755d10dc2442..644eacd0f6afd97e8fa6e85bf18384c489915cac 100644 (file)
@@ -178,6 +178,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_STRIP),y)
+L_OBJS += strip.o
+else
+  ifeq ($(CONFIG_STRIP),m)
+  M_OBJS += strip.o
+  endif
+endif
+
 ifeq ($(CONFIG_DE650),y)
 ETDRV_OBJS := $(L_OBJS) de650.o
 CONFIG_8390_BUILTIN = y
@@ -217,6 +225,9 @@ endif
 
 ifeq ($(CONFIG_LANCE),y)
 L_OBJS += lance.o
+  ifeq ($(CONFIG_LANCE32),y)
+  L_OBJS += lance32.o
+  endif
 endif
 
 ifeq ($(CONFIG_AT1700),y)
@@ -431,10 +442,10 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_FRAD),y)
+ifeq ($(CONFIG_DLCI),y)
 L_OBJS += dlci.o 
 else
-  ifeq ($(CONFIG_FRAD),m)
+  ifeq ($(CONFIG_DLCI),m)
   M_OBJS += dlci.o
   endif
 endif
@@ -482,6 +493,9 @@ plip.o:     plip.c CONFIG
 slip.o:        slip.c CONFIG
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
 
+strip.o: strip.c CONFIG
+       $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
 dummy.o: dummy.c CONFIG
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
 
index 1da81e7858621f7ae6beef95deadc10f5dc91ca9..e69f4e3d3ea70fc5b37bf609315ceba81ccf08cf 100644 (file)
@@ -198,7 +198,7 @@ ethif_probe(struct device *dev)
 
 /* This must be AFTER the various FRADs so it initializes FIRST! */
        
-#ifdef CONFIG_FRAD
+#ifdef CONFIG_DLCI
     extern int dlci_init(struct device *);
     static struct device dlci_dev = { "dlci", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, dlci_init, };
 #   undef NEXT_DEV
@@ -279,6 +279,14 @@ static struct device slip_bootstrap = {
 #define NEXT_DEV (&slip_bootstrap)
 #endif /* SLIP */
   
+#if defined(CONFIG_STRIP)
+extern int strip_init_ctrl_dev(struct device *);
+static struct device strip_bootstrap = {
+    "strip_proto", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, strip_init_ctrl_dev, };
+#undef NEXT_DEV
+#define NEXT_DEV (&strip_bootstrap)
+#endif   /* STRIP */
+    
 #if defined(CONFIG_PPP)
 extern int ppp_init(struct device *);
 static struct device ppp_bootstrap = {
index 360d504460d6c297914daa281345e8ff536bb64b..f3017e2f22aa128ba1b1df2cf1c3dd33866921a7 100644 (file)
@@ -32,7 +32,7 @@
                                                           SAW
 */
 
-static const char *version = "lance.c:v1.08.01 Mar 6 1996 saw@shade.msu.ru\n";
+static const char *version = "lance.c:v1.08.02 Mar 17 1996 tsbogend@bigbug.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -159,6 +159,14 @@ tx_full and tbusy flags.
 #define LANCE_KMALLOC(x) \
        ((void *) (((unsigned long)kmalloc((x)+7, GFP_DMA | GFP_KERNEL)+7) & ~7))
 
+/*
+ * Changes:
+ *     Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
+ *     - added support for Linux/Alpha, but removed most of it, because
+ *        it worked only for the PCI chip. 
+ *      - added hook for the 32bit lance driver
+ */
+
 /* Set the number of Tx and Rx buffers, using Log_2(# buffers).
    Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
    That translates to 4 and 4 (16 == 2^^4). */
@@ -186,25 +194,25 @@ tx_full and tbusy flags.
 
 /* The LANCE Rx and Tx ring descriptors. */
 struct lance_rx_head {
-       int base;
-       short buf_length;                       /* This length is 2s complement (negative)! */
-       short msg_length;                       /* This length is "normal". */
+       s32 base;
+       s16 buf_length;                 /* This length is 2s complement (negative)! */
+       s16 msg_length;                 /* This length is "normal". */
 };
 
 struct lance_tx_head {
-       int       base;
-       short length;                           /* Length is 2s complement (negative)! */
-       short misc;
+       s32 base;
+       s16 length;                             /* Length is 2s complement (negative)! */
+       s16 misc;
 };
 
 /* The LANCE initialization block, described in databook. */
 struct lance_init_block {
-       unsigned short mode;            /* Pre-set mode (reg. 15) */
-       unsigned char phys_addr[6]; /* Physical ethernet address */
-       unsigned filter[2];                     /* Multicast filter (unused). */
+       u16 mode;               /* Pre-set mode (reg. 15) */
+       u phys_addr[6]; /* Physical ethernet address */
+       u32 filter[2];                  /* Multicast filter (unused). */
        /* Receive and transmit ring base, along with extra bits. */
-       unsigned rx_ring;                       /* Tx and Rx ring base pointers */
-       unsigned tx_ring;
+       u32  rx_ring;                   /* Tx and Rx ring base pointers */
+       u32  tx_ring;
 };
 
 struct lance_private {
@@ -224,7 +232,7 @@ struct lance_private {
        struct enet_statistics stats;
        unsigned char chip_version;     /* See lance_chip_type. */
        char tx_full;
-       char lock;
+       unsigned long lock;
 };
 
 #define LANCE_MUST_PAD          0x00000001
@@ -290,7 +298,9 @@ static void set_multicast_list(struct device *dev);
 
 int lance_init(void)
 {
+#ifndef __alpha__    
        int *port;
+#endif    
 
        if (high_memory <= 16*1024*1024)
                lance_need_isa_bounce_buffers = 0;
@@ -334,6 +344,8 @@ int lance_init(void)
        }
 #endif  /* defined(CONFIG_PCI) */
 
+/* On the Alpha don't look for PCnet chips on the ISA bus */
+#ifndef __alpha__
        for (port = lance_portlist; *port; port++) {
                int ioaddr = *port;
 
@@ -347,6 +359,7 @@ int lance_init(void)
                                lance_probe1(ioaddr);
                }
        }
+#endif
 
        return 0;
 }
@@ -363,6 +376,7 @@ void lance_probe1(int ioaddr)
        int hp_builtin = 0;                                     /* HP on-board ethernet. */
        static int did_version = 0;                     /* Already printed version info. */
 
+#ifndef __alpha__
        /* First we look for special cases.
           Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
           There are two HP versions, check the BIOS for the configuration port.
@@ -379,6 +393,7 @@ void lance_probe1(int ioaddr)
        /* We also recognize the HP Vectra on-board here, but check below. */
        hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00
                                && inb(ioaddr+2) == 0x09);
+#endif
 
        /* Reset the LANCE.      */
        reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */
@@ -423,6 +438,15 @@ void lance_probe1(int ioaddr)
        dev->base_addr = ioaddr;
        request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
+#ifdef CONFIG_LANCE32
+        /* look if it's a PCI or VLB chip */
+        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB) {
+           extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
+           
+           lance32_probe1 (dev, chipname, pci_irq_line);
+           return;
+       }
+#endif    
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
        lp = (struct lance_private *) LANCE_KMALLOC(sizeof(*lp));
        if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
@@ -442,15 +466,15 @@ void lance_probe1(int ioaddr)
                lp->init_block.phys_addr[i] = dev->dev_addr[i];
        lp->init_block.filter[0] = 0x00000000;
        lp->init_block.filter[1] = 0x00000000;
-       lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS;
-       lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS;
+       lp->init_block.rx_ring = ((u32)virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
+       lp->init_block.tx_ring = ((u32)virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
 
        outw(0x0001, ioaddr+LANCE_ADDR);
        inw(ioaddr+LANCE_ADDR);
-       outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA);
+       outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
        outw(0x0002, ioaddr+LANCE_ADDR);
        inw(ioaddr+LANCE_ADDR);
-       outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
+       outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
        outw(0x0000, ioaddr+LANCE_ADDR);
        inw(ioaddr+LANCE_ADDR);
 
@@ -617,15 +641,17 @@ lance_open(struct device *dev)
 
        if (lance_debug > 1)
                printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
-                          dev->name, dev->irq, dev->dma, (int) lp->tx_ring, (int) lp->rx_ring,
-                          (int) &lp->init_block);
+                          dev->name, dev->irq, dev->dma,
+                          (u32) virt_to_bus(lp->tx_ring),
+                          (u32) virt_to_bus(lp->rx_ring),
+                          (u32) virt_to_bus(&lp->init_block));
 
        lance_init_ring(dev);
        /* Re-initialize the LANCE, and start it when done. */
        outw(0x0001, ioaddr+LANCE_ADDR);
-       outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA);
+       outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
        outw(0x0002, ioaddr+LANCE_ADDR);
-       outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
+       outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
 
        outw(0x0004, ioaddr+LANCE_ADDR);
        outw(0x0915, ioaddr+LANCE_DATA);
@@ -648,7 +674,7 @@ lance_open(struct device *dev)
 
        if (lance_debug > 2)
                printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
-                          dev->name, i, (int) &lp->init_block, inw(ioaddr+LANCE_DATA));
+                          dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA));
 
        return 0;                                       /* Always succeed */
 }
@@ -692,7 +718,7 @@ lance_init_ring(struct device *dev)
        lp->dirty_rx = lp->dirty_tx = 0;
 
        for (i = 0; i < RX_RING_SIZE; i++) {
-               lp->rx_ring[i].base = (lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
+               lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
                lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
        }
        /* The Tx buffer address is filled in as needed, but we do need to clear
@@ -706,8 +732,8 @@ lance_init_ring(struct device *dev)
                lp->init_block.phys_addr[i] = dev->dev_addr[i];
        lp->init_block.filter[0] = 0x00000000;
        lp->init_block.filter[1] = 0x00000000;
-       lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS;
-       lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS;
+       lp->init_block.rx_ring = ((u32)virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
+       lp->init_block.tx_ring = ((u32)virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
 }
 
 static void
@@ -815,17 +841,17 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
 
        /* If any part of this buffer is >16M we must copy it to a low-memory
           buffer. */
-       if ((int)(skb->data) + skb->len > 0x01000000) {
+       if ((u32)virt_to_bus(skb->data) + skb->len > 0x01000000) {
                if (lance_debug > 5)
                        printk("%s: bouncing a high-memory packet (%#x).\n",
-                                  dev->name, (int)(skb->data));
+                                  dev->name, (u32)virt_to_bus(skb->data));
                memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);
                lp->tx_ring[entry].base =
-                       (int)(lp->tx_bounce_buffs + entry) | 0x83000000;
+                       ((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
                dev_kfree_skb (skb, FREE_WRITE);
        } else {
                lp->tx_skbuff[entry] = skb;
-               lp->tx_ring[entry].base = (int)(skb->data) | 0x83000000;
+               lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
        }
        lp->cur_tx++;
 
@@ -1033,7 +1059,7 @@ lance_rx(struct device *dev)
                                skb_reserve(skb,2);     /* 16 byte align */
                                skb_put(skb,pkt_len);   /* Make room */
                                eth_copy_and_sum(skb,
-                                       (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
+                                       (unsigned char *)bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),
                                        pkt_len,0);
                                skb->protocol=eth_type_trans(skb,dev);
                                netif_rx(skb);
diff --git a/drivers/net/lance32.c b/drivers/net/lance32.c
new file mode 100644 (file)
index 0000000..da8418a
--- /dev/null
@@ -0,0 +1,833 @@
+/* lance32.c: An AMD PCnet32 ethernet driver for linux. */
+/*
+ *      Copyright 1996 Thomas Bogendoerfer
+ * 
+ *     Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ * 
+ *     Copyright 1993 United States Government as represented by the
+ *     Director, National Security Agency.
+ * 
+ *     This software may be used and distributed according to the terms
+ *     of the GNU Public License, incorporated herein by reference.
+ *
+ *     This driver is for PCnet32 and PCnetPCI based ethercards
+ */
+
+static const char *version = "lance32.c:v0.02 17.3.96 tsbogend@bigbug.franken.de\n";
+
+#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 <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#ifdef LANCE32_DEBUG
+int lance32_debug = LANCE32_DEBUG;
+#else
+int lance32_debug = 1;
+#endif
+
+/*
+ *                             Theory of Operation
+ * 
+ * This driver uses the same software structure as the normal lance
+ * driver. So look for a verbose description in lance.c. The differences
+ * to the normal lance driver is the use of the 32bit mode of PCnet32
+ * and PCnetPCI chips. Because these chips are 32bit chips, there is no
+ * 16MB limitation and we don't need bounce buffers.
+ */
+/*
+ * History:
+ * v0.01:  Initial version
+ *         only tested on Alpha Noname Board
+ * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
+ *         tested on a ASUS SP3G
+ */
+
+
+/*
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
+ * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
+ */
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 4
+#define LANCE_LOG_RX_BUFFERS 4
+#endif
+
+#define TX_RING_SIZE                   (1 << (LANCE_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK               (TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS               ((LANCE_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE                   (1 << (LANCE_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK               (RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS               ((LANCE_LOG_RX_BUFFERS) << 4)
+
+#define PKT_BUF_SZ             1544
+
+/* Offsets from base I/O address. */
+#define LANCE_DATA 0x10
+#define LANCE_ADDR 0x12
+#define LANCE_RESET 0x14
+#define LANCE_BUS_IF 0x16
+#define LANCE_TOTAL_SIZE 0x18
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance32_rx_head {
+       u32 base;
+       s16 buf_length;
+        s16 status;    
+       u32 msg_length;
+       u32 reserved;
+};
+       
+struct lance32_tx_head {
+       u32 base;
+       s16 length;
+        s16 status;
+       u32 misc;
+       u32 reserved;
+};
+
+
+/* The LANCE 32-Bit initialization block, described in databook. */
+struct lance32_init_block {
+       u16 mode;
+       u16 tlen_rlen;
+       u8  phys_addr[6];
+       u16 reserved;
+       u32 filter[2];
+       /* Receive and transmit ring base, along with extra bits. */    
+       u32 rx_ring;
+       u32 tx_ring;
+};
+
+struct lance32_private {
+       /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
+       struct lance32_rx_head   rx_ring[RX_RING_SIZE];
+       struct lance32_tx_head   tx_ring[TX_RING_SIZE];
+       struct lance32_init_block       init_block;
+       const char *name;
+       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+       struct sk_buff* tx_skbuff[TX_RING_SIZE];
+       unsigned long rx_buffs;                 /* Address of Rx and Tx buffers. */
+       int cur_rx, cur_tx;                     /* The next free ring entry */
+       int dirty_rx, dirty_tx;                 /* The ring entries to be free()ed. */
+       int dma;
+       struct enet_statistics stats;
+       char tx_full;
+       unsigned long lock;
+};
+
+static int lance32_open(struct device *dev);
+static void lance32_init_ring(struct device *dev);
+static int lance32_start_xmit(struct sk_buff *skb, struct device *dev);
+static int lance32_rx(struct device *dev);
+static void lance32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int lance32_close(struct device *dev);
+static struct enet_statistics *lance32_get_stats(struct device *dev);
+static void lance32_set_multicast_list(struct device *dev);
+
+\f
+
+/* lance32_probe1 */
+void lance32_probe1(struct device *dev, char *chipname, int pci_irq_line)
+{
+       struct lance32_private *lp;
+        int ioaddr = dev->base_addr;
+       short dma_channels;                                     /* Mark spuriously-busy DMA channels */    
+        int i;
+    
+       /* Make certain the data structures used by the LANCE are 16byte aligned and DMAble. */
+       lp = (struct lance32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
+      
+       memset(lp, 0, sizeof(*lp));
+       dev->priv = lp;
+       lp->name = chipname;
+       lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+
+       lp->init_block.mode = 0x0003;           /* Disable Rx and Tx. */
+        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;    
+       for (i = 0; i < 6; i++)
+               lp->init_block.phys_addr[i] = dev->dev_addr[i];
+       lp->init_block.filter[0] = 0x00000000;
+       lp->init_block.filter[1] = 0x00000000;
+       lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
+       lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
+    
+       /* switch lance to 32bit mode */
+       outw(0x0014, ioaddr+LANCE_ADDR);
+       outw(0x0002, ioaddr+LANCE_BUS_IF);
+
+       outw(0x0001, ioaddr+LANCE_ADDR);
+       inw(ioaddr+LANCE_ADDR);
+       outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
+       outw(0x0002, ioaddr+LANCE_ADDR);
+       inw(ioaddr+LANCE_ADDR);
+       outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
+       outw(0x0000, ioaddr+LANCE_ADDR);
+       inw(ioaddr+LANCE_ADDR);
+    
+       if (pci_irq_line) {
+               dev->dma = 4;                   /* Native bus-master, no DMA channel needed. */
+               dev->irq = pci_irq_line;
+       } else {
+               /* The DMA channel may be passed in PARAM1. */
+               if (dev->mem_start & 0x07)
+                       dev->dma = dev->mem_start & 0x07;
+       }
+
+       if (dev->dma == 0) {
+               /* Read the DMA channel status register, so that we can avoid
+                  stuck DMA channels in the DMA detection below. */
+               dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
+                       (inb(DMA2_STAT_REG) & 0xf0);
+       }
+       if (dev->irq >= 2)
+               printk(" assigned IRQ %d", dev->irq);
+       else {
+               /* To auto-IRQ we enable the initialization-done and DMA error
+                  interrupts. For ISA boards we get a DMA error, but VLB and PCI
+                  boards will work. */
+               autoirq_setup(0);
+
+               /* Trigger an initialization just for the interrupt. */
+               outw(0x0041, ioaddr+LANCE_DATA);
+
+               dev->irq = autoirq_report(1);
+               if (dev->irq)
+                       printk(", probed IRQ %d", dev->irq);
+               else {
+                       printk(", failed to detect IRQ line.\n");
+                       return;
+               }
+
+               /* Check for the initialization done bit, 0x0100, which means
+                  that we don't need a DMA channel. */
+               if (inw(ioaddr+LANCE_DATA) & 0x0100)
+                       dev->dma = 4;
+       }
+
+       if (dev->dma == 4) {
+               printk(", no DMA needed.\n");
+       } else if (dev->dma) {
+               if (request_dma(dev->dma, chipname)) {
+                       printk("DMA %d allocation failed.\n", dev->dma);
+                       return;
+               } else
+                       printk(", assigned DMA %d.\n", dev->dma);
+       } else {                        /* OK, we have to auto-DMA. */
+               for (i = 0; i < 4; i++) {
+                       static const char dmas[] = { 5, 6, 7, 3 };
+                       int dma = dmas[i];
+                       int boguscnt;
+
+                       /* Don't enable a permanently busy DMA channel, or the machine
+                          will hang. */
+                       if (test_bit(dma, &dma_channels))
+                               continue;
+                       outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
+                       if (request_dma(dma, chipname))
+                               continue;
+                       set_dma_mode(dma, DMA_MODE_CASCADE);
+                       enable_dma(dma);
+
+                       /* Trigger an initialization. */
+                       outw(0x0001, ioaddr+LANCE_DATA);
+                       for (boguscnt = 100; boguscnt > 0; --boguscnt)
+                               if (inw(ioaddr+LANCE_DATA) & 0x0900)
+                                       break;
+                       if (inw(ioaddr+LANCE_DATA) & 0x0100) {
+                               dev->dma = dma;
+                               printk(", DMA %d.\n", dev->dma);
+                               break;
+                       } else {
+                               disable_dma(dma);
+                               free_dma(dma);
+                       }
+               }
+               if (i == 4) {                   /* Failure: bail. */
+                       printk("DMA detection failed.\n");
+                       return;
+               }
+       }
+    
+        outw(0x0002, ioaddr+LANCE_ADDR);
+       outw(0x0002, ioaddr+LANCE_BUS_IF);
+
+       if (lance32_debug > 0)
+               printk(version);
+
+       /* The LANCE-specific entries in the device structure. */
+       dev->open = &lance32_open;
+       dev->hard_start_xmit = &lance32_start_xmit;
+       dev->stop = &lance32_close;
+       dev->get_stats = &lance32_get_stats;
+       dev->set_multicast_list = &lance32_set_multicast_list;
+
+       return;
+}
+
+\f
+static int
+lance32_open(struct device *dev)
+{
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int i;
+
+       if (dev->irq == 0 ||
+               request_irq(dev->irq, &lance32_interrupt, 0, lp->name, (void *)dev)) {
+               return -EAGAIN;
+       }
+
+       irq2dev_map[dev->irq] = dev;
+
+       /* Reset the LANCE */
+       inw(ioaddr+LANCE_RESET);
+
+       /* switch lance to 32bit mode */
+       outw(0x0014, ioaddr+LANCE_ADDR);
+       outw(0x0002, ioaddr+LANCE_BUS_IF);
+
+       /* The DMA controller is used as a no-operation slave, "cascade mode". */
+       if (dev->dma != 4) {
+               enable_dma(dev->dma);
+               set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+       }
+
+       /* Turn on auto-select of media (AUI, BNC). */
+       outw(0x0002, ioaddr+LANCE_ADDR);
+       outw(0x0002, ioaddr+LANCE_BUS_IF);
+
+       if (lance32_debug > 1)
+               printk("%s: lance32_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
+                          dev->name, dev->irq, dev->dma,
+                          (u32) virt_to_bus(lp->tx_ring),
+                          (u32) virt_to_bus(lp->rx_ring),
+                          (u32) virt_to_bus(&lp->init_block));
+
+       lance32_init_ring(dev);
+       /* Re-initialize the LANCE, and start it when done. */
+       outw(0x0001, ioaddr+LANCE_ADDR);
+       outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
+       outw(0x0002, ioaddr+LANCE_ADDR);
+       outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
+
+       outw(0x0004, ioaddr+LANCE_ADDR);
+       outw(0x0915, ioaddr+LANCE_DATA);
+
+       outw(0x0000, ioaddr+LANCE_ADDR);
+       outw(0x0001, ioaddr+LANCE_DATA);
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+       i = 0;
+       while (i++ < 100)
+               if (inw(ioaddr+LANCE_DATA) & 0x0100)
+                       break;
+       /* 
+        * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+        * reports that doing so triggers a bug in the '974.
+        */
+       outw(0x0042, ioaddr+LANCE_DATA);
+
+       if (lance32_debug > 2)
+               printk("%s: LANCE32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+                          dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA));
+
+       return 0;                                       /* Always succeed */
+}
+
+/*
+ * The LANCE has been halted for one reason or another (busmaster memory
+ * arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
+ * etc.).  Modern LANCE variants always reload their ring-buffer
+ * configuration when restarted, so we must reinitialize our ring
+ * context before restarting.  As part of this reinitialization,
+ * find all packets still on the Tx ring and pretend that they had been
+ * sent (in effect, drop the packets on the floor) - the higher-level
+ * protocols will time out and retransmit.  It'd be better to shuffle
+ * these skbs to a temp list and then actually re-Tx them after
+ * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
+ */
+
+static void 
+lance32_purge_tx_ring(struct device *dev)
+{
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+       int i;
+
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               if (lp->tx_skbuff[i]) {
+                       dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE);
+                       lp->tx_skbuff[i] = NULL;
+               }
+       }
+}
+
+
+/* Initialize the LANCE Rx and Tx rings. */
+static void
+lance32_init_ring(struct device *dev)
+{
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+       int i;
+
+       lp->lock = 0, lp->tx_full = 0;
+       lp->cur_rx = lp->cur_tx = 0;
+       lp->dirty_rx = lp->dirty_tx = 0;
+
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ);
+               lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
+               lp->rx_ring[i].status = 0x8000;     
+       }
+       /* The Tx buffer address is filled in as needed, but we do need to clear
+          the upper ownership bit. */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               lp->tx_ring[i].base = 0;
+               lp->tx_ring[i].status = 0;
+       }
+
+       lp->init_block.mode = 0x0000;
+        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
+       for (i = 0; i < 6; i++)
+               lp->init_block.phys_addr[i] = dev->dev_addr[i];
+       lp->init_block.filter[0] = 0x00000000;
+       lp->init_block.filter[1] = 0x00000000;
+       lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
+       lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
+}
+
+static void
+lance32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
+{
+       lance32_purge_tx_ring(dev);
+       lance32_init_ring(dev);
+    
+       outw(0x0000,    dev->base_addr + LANCE_ADDR);
+       outw(csr0_bits, dev->base_addr + LANCE_DATA);
+}
+
+static int
+lance32_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int entry;
+       unsigned long flags;
+
+       /* Transmitter timeout, serious problems. */
+       if (dev->tbusy) {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 20)
+                       return 1;
+               outw(0, ioaddr+LANCE_ADDR);
+               printk("%s: transmit timed out, status %4.4x, resetting.\n",
+                          dev->name, inw(ioaddr+LANCE_DATA));
+               outw(0x0004, ioaddr+LANCE_DATA);
+               lp->stats.tx_errors++;
+#ifndef final_version
+               {
+                       int i;
+                       printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+                                  lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+                                  lp->cur_rx);
+                       for (i = 0 ; i < RX_RING_SIZE; i++)
+                               printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+                                          lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+                                          lp->rx_ring[i].msg_length);
+                       for (i = 0 ; i < TX_RING_SIZE; i++)
+                               printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+                                          lp->tx_ring[i].base, -lp->tx_ring[i].length,
+                                          lp->tx_ring[i].misc);
+                       printk("\n");
+               }
+#endif
+               lance32_restart(dev, 0x0043, 1);
+
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+
+               return 0;
+       }
+
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (skb->len <= 0)
+               return 0;
+
+       if (lance32_debug > 3) {
+               outw(0x0000, ioaddr+LANCE_ADDR);
+               printk("%s: lance32_start_xmit() called, csr0 %4.4x.\n", dev->name,
+                          inw(ioaddr+LANCE_DATA));
+               outw(0x0000, ioaddr+LANCE_DATA);
+       }
+
+       /* 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);
+               return 1;
+       }
+
+       if (set_bit(0, (void*)&lp->lock) != 0) {
+               if (lance32_debug > 0)
+                       printk("%s: tx queue lock!.\n", dev->name);
+               /* don't clear dev->tbusy flag. */
+               return 1;
+       }
+
+       /* Fill in a Tx ring entry */
+
+       /* Mask to ring buffer boundary. */
+       entry = lp->cur_tx & TX_RING_MOD_MASK;
+
+       /* Caution: the write order is important here, set the base address
+          with the "ownership" bits last. */
+
+       lp->tx_ring[entry].length = -skb->len;
+
+       lp->tx_ring[entry].misc = 0x00000000;
+
+       lp->tx_skbuff[entry] = skb;
+       lp->tx_ring[entry].base = (u32)virt_to_bus(skb->data);
+        lp->tx_ring[entry].status = 0x8300;
+
+       lp->cur_tx++;
+
+       /* Trigger an immediate send poll. */
+       outw(0x0000, ioaddr+LANCE_ADDR);
+       outw(0x0048, ioaddr+LANCE_DATA);
+
+       dev->trans_start = jiffies;
+
+       save_flags(flags);
+       cli();
+       lp->lock = 0;
+       if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
+               dev->tbusy=0;
+       else
+               lp->tx_full = 1;
+       restore_flags(flags);
+
+       return 0;
+}
+
+/* The LANCE32 interrupt handler. */
+static void
+lance32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct device *dev = (struct device *)dev_id;
+       struct lance32_private *lp;
+       int csr0, ioaddr, boguscnt=10;
+       int must_restart;
+
+       if (dev == NULL) {
+               printk ("lance32_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+
+       ioaddr = dev->base_addr;
+       lp = (struct lance32_private *)dev->priv;
+       if (dev->interrupt)
+               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+       dev->interrupt = 1;
+
+       outw(0x00, dev->base_addr + LANCE_ADDR);
+       while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600
+                  && --boguscnt >= 0) {
+               /* Acknowledge all of the current interrupt sources ASAP. */
+               outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);
+
+               must_restart = 0;
+
+               if (lance32_debug > 5)
+                       printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+                                  dev->name, csr0, inw(dev->base_addr + LANCE_DATA));
+
+               if (csr0 & 0x0400)                      /* Rx interrupt */
+                       lance32_rx(dev);
+
+               if (csr0 & 0x0200) {            /* Tx-done interrupt */
+                       int dirty_tx = lp->dirty_tx;
+
+                       while (dirty_tx < lp->cur_tx) {
+                               int entry = dirty_tx & TX_RING_MOD_MASK;
+                               int status = lp->tx_ring[entry].status;
+                       
+                               if (status < 0)
+                                       break;                  /* It still hasn't been Txed */
+
+                               lp->tx_ring[entry].base = 0;
+
+                               if (status & 0x4000) {
+                                       /* There was an major error, log it. */
+                                       int err_status = lp->tx_ring[entry].misc;
+                                       lp->stats.tx_errors++;
+                                       if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
+                                       if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
+                                       if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+                                       if (err_status & 0x40000000) {
+                                               /* Ackk!  On FIFO errors the Tx unit is turned off! */
+                                               lp->stats.tx_fifo_errors++;
+                                               /* Remove this verbosity later! */
+                                               printk("%s: Tx FIFO error! Status %4.4x.\n",
+                                                          dev->name, csr0);
+                                               /* Restart the chip. */
+                                               must_restart = 1;
+                                       }
+                               } else {
+                                       if (status & 0x1800)
+                                               lp->stats.collisions++;
+                                       lp->stats.tx_packets++;
+                               }
+
+                               /* We must free the original skb */
+                               if (lp->tx_skbuff[entry]) {
+                                       dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE);
+                                       lp->tx_skbuff[entry] = 0;
+                               }
+                               dirty_tx++;
+                       }
+
+#ifndef final_version
+                       if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+                               printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+                                          dirty_tx, lp->cur_tx, lp->tx_full);
+                               dirty_tx += TX_RING_SIZE;
+                       }
+#endif
+
+                       if (lp->tx_full && dev->tbusy
+                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+                               /* The ring is no longer full, clear tbusy. */
+                               lp->tx_full = 0;
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);
+                       }
+
+                       lp->dirty_tx = dirty_tx;
+               }
+
+               /* Log misc errors. */
+               if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
+               if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
+               if (csr0 & 0x0800) {
+                       printk("%s: Bus master arbitration failure, status %4.4x.\n",
+                                  dev->name, csr0);
+                       /* Restart the chip. */
+                       must_restart = 1;
+               }
+
+               if (must_restart) {
+                       /* stop the chip to clear the error condition, then restart */
+                       outw(0x0000, dev->base_addr + LANCE_ADDR);
+                       outw(0x0004, dev->base_addr + LANCE_DATA);
+                       lance32_restart(dev, 0x0002, 0);
+               }
+       }
+
+    /* Clear any other interrupt, and set interrupt enable. */
+    outw(0x0000, dev->base_addr + LANCE_ADDR);
+    outw(0x7940, dev->base_addr + LANCE_DATA);
+
+       if (lance32_debug > 4)
+               printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+                          dev->name, inw(ioaddr + LANCE_ADDR),
+                          inw(dev->base_addr + LANCE_DATA));
+
+       dev->interrupt = 0;
+       return;
+}
+
+static int
+lance32_rx(struct device *dev)
+{
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+       int entry = lp->cur_rx & RX_RING_MOD_MASK;
+       int i;
+               
+       /* If we own the next entry, it's a new packet. Send it up. */
+       while (lp->rx_ring[entry].status >= 0) {
+               int status = lp->rx_ring[entry].status >> 8;
+
+               if (status != 0x03) {                   /* There was an error. */
+                       /* There is a tricky error noted by John Murphy,
+                          <murf@perftech.com> to Russ Nelson: Even with full-sized
+                          buffers it's possible for a jabber packet to use two
+                          buffers, with only the last correctly noting the error. */
+                       if (status & 0x01)      /* Only count a general error at the */
+                               lp->stats.rx_errors++; /* end of a packet.*/
+                       if (status & 0x20) lp->stats.rx_frame_errors++;
+                       if (status & 0x10) lp->stats.rx_over_errors++;
+                       if (status & 0x08) lp->stats.rx_crc_errors++;
+                       if (status & 0x04) lp->stats.rx_fifo_errors++;
+                       lp->rx_ring[entry].status &= 0x03ff;
+               }
+               else 
+               {
+                       /* Malloc up new buffer, compatible with net-2e. */
+                       short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
+                       struct sk_buff *skb;
+                       
+                       if(pkt_len<60)
+                       {
+                               printk("%s: Runt packet!\n",dev->name);
+                               lp->stats.rx_errors++;
+                       }
+                       else
+                       {
+                               skb = dev_alloc_skb(pkt_len+2);
+                               if (skb == NULL) 
+                               {
+                                       printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+                                       for (i=0; i < RX_RING_SIZE; i++)
+                                               if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status < 0)
+                                                       break;
+
+                                       if (i > RX_RING_SIZE -2) 
+                                       {
+                                               lp->stats.rx_dropped++;
+                                               lp->rx_ring[entry].status |= 0x8000;
+                                               lp->cur_rx++;
+                                       }
+                                       break;
+                               }
+                               skb->dev = dev;
+                               skb_reserve(skb,2);     /* 16 byte align */
+                               skb_put(skb,pkt_len);   /* Make room */
+                               eth_copy_and_sum(skb,
+                                       (unsigned char *)bus_to_virt(lp->rx_ring[entry].base),
+                                       pkt_len,0);
+                               skb->protocol=eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                               lp->stats.rx_packets++;
+                       }
+               }
+               /* The docs say that the buffer length isn't touched, but Andrew Boyd
+                  of QNX reports that some revs of the 79C965 clear it. */
+               lp->rx_ring[entry].buf_length = -PKT_BUF_SZ;
+               lp->rx_ring[entry].status |= 0x8000;
+               entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+       }
+
+       /* We should check that at least two ring entries are free.      If not,
+          we should free one and mark stats->rx_dropped++. */
+
+       return 0;
+}
+
+static int
+lance32_close(struct device *dev)
+{
+       int ioaddr = dev->base_addr;
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+
+       dev->start = 0;
+       dev->tbusy = 1;
+
+       outw(112, ioaddr+LANCE_ADDR);
+       lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
+
+       outw(0, ioaddr+LANCE_ADDR);
+
+       if (lance32_debug > 1)
+               printk("%s: Shutting down ethercard, status was %2.2x.\n",
+                          dev->name, inw(ioaddr+LANCE_DATA));
+
+       /* We stop the LANCE here -- it occasionally polls
+          memory if we don't. */
+       outw(0x0004, ioaddr+LANCE_DATA);
+
+       if (dev->dma != 4)
+               disable_dma(dev->dma);
+
+       free_irq(dev->irq, dev);
+
+       irq2dev_map[dev->irq] = 0;
+
+       return 0;
+}
+
+static struct enet_statistics *
+lance32_get_stats(struct device *dev)
+{
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;
+       short ioaddr = dev->base_addr;
+       short saved_addr;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       saved_addr = inw(ioaddr+LANCE_ADDR);
+       outw(112, ioaddr+LANCE_ADDR);
+       lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
+       outw(saved_addr, ioaddr+LANCE_ADDR);
+       restore_flags(flags);
+
+       return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ */
+
+static void lance32_set_multicast_list(struct device *dev)
+{
+       short ioaddr = dev->base_addr;
+
+       outw(0, ioaddr+LANCE_ADDR);
+       outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.  */
+
+       if (dev->flags&IFF_PROMISC) {
+               /* Log any net taps. */
+               printk("%s: Promiscuous mode enabled.\n", dev->name);
+               outw(15, ioaddr+LANCE_ADDR);
+               outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
+       } else {
+               short multicast_table[4];
+               int i;
+               int num_addrs=dev->mc_count;
+               if(dev->flags&IFF_ALLMULTI)
+                       num_addrs=1;
+               /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
+               memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));
+               for (i = 0; i < 4; i++) {
+                       outw(8 + i, ioaddr+LANCE_ADDR);
+                       outw(multicast_table[i], ioaddr+LANCE_DATA);
+               }
+               outw(15, ioaddr+LANCE_ADDR);
+               outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
+       }
+
+       lance32_restart(dev, 0x0142, 0); /*  Resume normal operation */
+
+}
+
+\f
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance32.c"
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
index d7a65bce9d70f24f1310ea1fe0fad3624a7238b9..be08d3ff739cda29d1f8294ec0cd5d17e5a0f678 100644 (file)
@@ -290,12 +290,12 @@ plip_init(struct device *dev)
        nl->nibble      = PLIP_NIBBLE_WAIT;
 
        /* Initialize task queue structures */
-       nl->immediate.next = &tq_last;
+       nl->immediate.next = NULL;
        nl->immediate.sync = 0;
        nl->immediate.routine = (void *)(void *)plip_bh;
        nl->immediate.data = dev;
 
-       nl->deferred.next = &tq_last;
+       nl->deferred.next = NULL;
        nl->deferred.sync = 0;
        nl->deferred.routine = (void *)(void *)plip_kick_bh;
        nl->deferred.data = dev;
index 834e3655c8e733e340f8853116405d3004db651d..d204271d91c1a1c0a59b2ce64bfeafdae92ec234 100644 (file)
@@ -620,10 +620,10 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
 
        ppp->rbuf->size -= 80;  /* reserve space for vj header expansion */
 
-       dev->mem_start  = (__u32) buf_base (new_wbuf);
-       dev->mem_end    = (__u32) (dev->mem_start + mtu);
-       dev->rmem_start = (__u32) buf_base (new_rbuf);
-       dev->rmem_end   = (__u32) (dev->rmem_start + mru);
+       dev->mem_start  = (unsigned long) buf_base (new_wbuf);
+       dev->mem_end    = (unsigned long) (dev->mem_start + mtu);
+       dev->rmem_start = (unsigned long) buf_base (new_rbuf);
+       dev->rmem_end   = (unsigned long) (dev->rmem_start + mru);
 /*
  *  Update the parameters for the new buffer sizes
  */
index 5090bda62faeaa064f292d9f105b391a5ee4177b..770ebc87e130f90bb01e1681cbef5551463900b4 100644 (file)
@@ -393,6 +393,12 @@ static void sdla_errors(struct device *dev, int cmd, int dlci, int ret, int len,
          printk(KERN_ERR "%s: Command timed out!\n", dev->name);
          break;
 
+      case SDLA_RET_CHANNEL_INACTIVE:
+      case SDLA_RET_DLCI_INACTIVE:
+      case SDLA_RET_NO_BUFF:
+         if (cmd == SDLA_INFORMATION_WRITE)
+            break;
+
       default: 
          /*
           * Further processing could be done here 
index 243c2642271fe966e25186b28c7d72565daadfe7..b2696a1a0ddde5adc5d94922a758e5c1467e55c8 100644 (file)
@@ -750,7 +750,7 @@ static void export_slhc_syms(void)
 
 int init_module(void)
 {
-       printk("CSLIP: code copyright 1989 Regents of the University of California\n");
+       printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n");
        export_slhc_syms();
        return 0;
 }
index 9fcca56369309ae1f7397f94a24851be07488f67..3263c31453fb81fe077e62914500b020ec3f4d88 100644 (file)
@@ -1201,7 +1201,7 @@ int slip_init_ctrl_dev(struct device *dummy)
 
        if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */
 
-       printk("SLIP: version %s (dynamic channels, max=%d)"
+       printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"
 #ifdef CONFIG_SLIP_MODE_SLIP6
               " (6 bit encapsulation enabled)"
 #endif
@@ -1211,10 +1211,10 @@ int slip_init_ctrl_dev(struct device *dummy)
        printk("CSLIP: code copyright 1989 Regents of the University of California.\n");
 #endif
 #ifdef CONFIG_AX25
-       printk("AX25: KISS encapsulation enabled.\n");
+       printk(KERN_INFO "AX25: KISS encapsulation enabled.\n");
 #endif
 #ifdef CONFIG_SLIP_SMART
-       printk("SLIP linefill/keepalive option.\n");
+       printk(KERN_INFO "SLIP linefill/keepalive option.\n");
 #endif 
 
        slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL);
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
new file mode 100644 (file)
index 0000000..f02f525
--- /dev/null
@@ -0,0 +1,1494 @@
+/*
+ * Copyright 1996 The Board of Trustees of The Leland Stanford
+ * Junior University. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  Stanford University
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ *
+ * strip.c     This module implements Starmode Radio IP (STRIP)
+ *             for kernel-based devices like TTY.  It interfaces between a
+ *             raw TTY, and the kernel's INET protocol layers (via DDI).
+ *
+ * Version:    @(#)strip.c     0.9.1   3/6/95
+ *
+ * Author:     Stuart Cheshire <cheshire@cs.stanford.edu>
+ *
+ * Fixes:
+ *             Stuart Cheshire:
+ *                     Original version converted from SLIP driver
+ *             Jonathan Stone:
+ *                     change to 1.3 calling conventions
+ *             Stuart Cheshire:
+ *                     v0.9 12th Feb 1996.
+ *                     New byte stuffing (2+6 run-length encoding)
+ *                     New watchdog timer task
+ *                     New Protocol key (SIP0)
+ *                     v0.9.1 3rd March 1996
+ *                     Changed to dynamic device allocation
+ */
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_strip.h>
+#include <net/arp.h>
+#ifdef CONFIG_INET
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#endif
+
+#ifdef MODULE
+#define STRIP_VERSION    "0.9.1-STUART.CHESHIRE-MODULAR"
+#else
+#define STRIP_VERSION    "0.9.1-STUART.CHESHIRE"
+#endif
+
+#define STRIP_MTU 1024
+#define STRIP_MAGIC 0x5303
+
+/*
+ *     Do we still needs all these flags? 
+ */
+
+enum 
+{
+       STR_INUSE = 0,          /* Channel in use       */
+       STR_ESCAPE,                     /* ESC received         */
+       STR_ERROR                       /* Parity, etc. error   */
+}
+STRIP_FLAGS;
+
+struct strip 
+{
+       int magic;
+       /*
+        *      Other useful structures. 
+        */
+
+       /*
+        *      These are pointers to the malloc()ed frame buffers.
+        */
+
+       unsigned char     *rx_buff;             /* buffer for received IP packet*/
+       unsigned char     *sx_buff;             /* buffer for received serial data*/
+       int                sx_count;            /* received serial data counter */
+       unsigned char     *tx_buff;             /* transmitter buffer  */
+       unsigned char     *tx_head;             /* pointer to next byte to XMIT */
+       int                tx_left;             /* bytes left in XMIT queue     */
+
+       /*
+        *      STRIP interface statistics.
+        */
+        
+       unsigned long      rx_packets;          /* inbound frames counter       */
+       unsigned long      tx_packets;          /* outbound frames counter      */
+       unsigned long      rx_errors;           /* Parity, etc. errors          */
+       unsigned long      tx_errors;           /* Planned stuff                */
+       unsigned long      rx_dropped;          /* No memory for skb            */
+       unsigned long      tx_dropped;          /* When MTU change              */
+       unsigned long      rx_over_errors;      /* Frame bigger then STRIP buf. */
+
+       /*
+        *      Internal variables.
+        */
+        
+       struct strip      *next;                /* The next struct in the list  */
+       struct strip     **referrer;            /* The pointer that points to us */
+       unsigned char      flags;               /* Flag values/ mode etc        */
+       int                mtu;                 /* Our mtu (to spot changes!)   */
+       int                buffsize;            /* Max buffers sizes            */
+       long               watchdog_doprobe;    /* Next time to test the radio  */
+       long               watchdog_doreset;    /* Time to do next reset        */
+       struct timer_list  idle_timer;
+
+       struct tty_struct *tty;                 /* ptr to TTY structure         */
+       char               if_name[8];          /* Dynamically generated name   */
+       struct device       dev;                /* Our device stucture          */
+};
+/************************************************************************/
+/* Utility routines for disabling and restoring interrupts             */
+
+typedef unsigned long InterruptStatus;
+
+extern __inline__ InterruptStatus DisableInterrupts(void)
+{
+    InterruptStatus x;
+    save_flags(x);
+    cli();
+    return(x);
+}
+
+extern __inline__ void RestoreInterrupts(InterruptStatus x)
+{
+    restore_flags(x);
+}
+
+/************************************************************************/
+/* Useful structures and definitions                                   */
+
+typedef struct {
+    __u8 c[32];
+} RadioName;
+
+typedef struct {
+    __u8 c[ 4];
+} MetricomKey;
+
+typedef union {
+    __u8 b[ 4];
+    __u32 l;
+} IPaddr;
+
+static const MetricomKey ProtocolKey = 
+{
+    {
+        "SIP0"
+    }
+};
+
+enum 
+{
+    FALSE = 0,
+    TRUE = 1
+};
+
+#define LONG_TIME 0x7FFFFFFF
+
+typedef struct 
+{
+       RadioName   name;       /* The address, with delimiters eg. *0000-1164* */
+       MetricomKey key;        /* Protocol type */
+} STRIP_Header;
+
+typedef struct 
+{
+       STRIP_Header h;
+       __u8 data[4];           /* Placeholder for payload (The IP packet) */
+} STRIP_Packet;
+
+/*
+ *     STRIP_ENCAP_SIZE of an IP packet is the STRIP header at the front,
+ *     byte-stuffing overhead of the payload, plus the CR at the end
+ */
+#define STRIP_ENCAP_SIZE(X) (sizeof(STRIP_Header) + (X)*65L/64L + 2)
+
+/*
+ *     Note: A Metricom packet looks like this: *<address>*<key><payload><CR>
+ *     eg. *0000-1164*SIP0<payload><CR>
+ */
+
+static struct strip *struct_strip_list = NULL;
+
+/************************************************************************/
+/* Byte stuffing/unstuffing routines                                   */
+
+/* Stuffing scheme:
+ * 00    Unused (reserved character)
+ * 01-3F Run of 2-64 different characters
+ * 40-7F Run of 1-64 different characters plus a single zero at the end
+ * 80-BF Run of 1-64 of the same character
+ * C0-FF Run of 1-64 zeroes (ASCII 0)
+ */
+
+typedef enum 
+{
+    Stuff_Diff      = 0x00,
+    Stuff_DiffZero  = 0x40,
+    Stuff_Same      = 0x80,
+    Stuff_Zero      = 0xC0,
+    Stuff_NoCode    = 0xFF,    /* Special code, meaning no code selected */
+    
+    Stuff_CodeMask  = 0xC0,
+    Stuff_CountMask = 0x3F,
+    Stuff_MaxCount  = 0x3F,
+    Stuff_Magic     = 0x0D     /* The value we are eliminating */
+} StuffingCode;
+
+/* StuffData encodes the data starting at "src" for "length" bytes.
+ * It writes it to the buffer pointed to by "dst" (which must be at least
+ * as long as 1 + 65/64 of the input length). The output may be up to 1.6%
+ * larger than the input for pathological input, but will usually be smaller.
+ * StuffData returns the new value of the dst pointer as its result.
+ * "code_ptr_ptr" points to a "__u8 *" which is used to hold encoding state
+ * between calls, allowing an encoded packet to be incrementally built up
+ * from small parts. On the first call, the "__u8 *" pointed to should be
+ * initialized to NULL; between subsequent calls the calling routine should
+ * leave the value alone and simply pass it back unchanged so that the
+ * encoder can recover its current state.
+ */
+
+#define StuffData_FinishBlock(X) \
+(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode)
+
+static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
+{
+       __u8 *end = src + length;
+       __u8 *code_ptr = *code_ptr_ptr;
+       __u8 code = Stuff_NoCode, count = 0;
+    
+       if (!length) 
+               return(dst);
+    
+       if (code_ptr) 
+       {
+               /*
+                *      Recover state from last call, if applicable 
+                */
+               code  = *code_ptr & Stuff_CodeMask;
+               count = *code_ptr & Stuff_CountMask;
+       }
+
+       while (src < end) 
+       {
+               switch (code) 
+               {
+                       /* Stuff_NoCode: If no current code, select one */
+                       case Stuff_NoCode:
+                               /* Record where we're going to put this code */
+                               code_ptr = dst++;
+                               count = 0;      /* Reset the count (zero means one instance) */
+                               /* Tentatively start a new block */
+                               if (*src == 0) 
+                               {
+                                       code = Stuff_Zero;
+                                       src++;
+                               }
+                               else
+                               {
+                                       code = Stuff_Same;
+                                       *dst++ = *src++ ^ Stuff_Magic;
+                               }
+                               /* Note: We optimistically assume run of same -- */
+                               /* which will be fixed later in Stuff_Same */
+                               /* if it turns out not to be true. */
+                               break;
+
+                       /* Stuff_Zero: We already have at least one zero encoded */
+                       case Stuff_Zero:
+                               /* If another zero, count it, else finish this code block */
+                               if (*src == 0) 
+                               {
+                                       count++;
+                                       src++;
+                               }
+                               else 
+                               {
+                                       StuffData_FinishBlock(Stuff_Zero + count);
+                               }
+                               break;
+
+                       /* Stuff_Same: We already have at least one byte encoded */
+                       case Stuff_Same:
+                               /* If another one the same, count it */
+                               if ((*src ^ Stuff_Magic) == code_ptr[1]) 
+                               {
+                                       count++;
+                                       src++;
+                                       break;
+                               }
+                               /* else, this byte does not match this block. */
+                               /* If we already have two or more bytes encoded, */
+                               /* finish this code block */
+                               if (count) 
+                               {
+                                       StuffData_FinishBlock(Stuff_Same + count);
+                                       break;
+                               }
+                               /* else, we only have one so far, */
+                               /* so switch to Stuff_Diff code */
+                               code = Stuff_Diff;
+                               /* and fall through to Stuff_Diff case below */
+                        /* Stuff_Diff: We have at least two *different* bytes encoded */
+                       case Stuff_Diff:
+                               /* If this is a zero, must encode a Stuff_DiffZero, */
+                               /* and begin a new block */
+                               if (*src == 0) 
+                               {
+                                       StuffData_FinishBlock(Stuff_DiffZero + count);
+                               }
+                               /* else, if we have three in a row, it is worth starting */
+                               /* a Stuff_Same block */
+                               else if ((*src ^ Stuff_Magic)==dst[-1] && dst[-1]==dst[-2]) 
+                               {
+                               /* Back off the last two characters we encoded */
+                               code += count-2;
+                               /* Note: "Stuff_Diff + 0" is an illegal code */
+                               if (code == Stuff_Diff + 0) 
+                               {
+                                       code = Stuff_Same + 0;
+                               }
+                               StuffData_FinishBlock(code);
+                               code_ptr = dst-2;
+                               /* dst[-1] already holds the correct value */
+                               count = 2;              /* 2 means three bytes encoded */
+                               code = Stuff_Same;
+                       }
+                       /* else, another different byte, so add it to the block */
+                       else 
+                       {
+                               *dst++ = *src ^ Stuff_Magic;
+                               count++;
+                       }
+                       src++;  /* Consume the byte */
+                       break;
+               }
+               if (count == Stuff_MaxCount) 
+               {
+                       StuffData_FinishBlock(code + count);
+               }
+       }
+       if (code == Stuff_NoCode) 
+       {
+               *code_ptr_ptr = NULL;
+       }
+       else 
+       {
+               *code_ptr_ptr = code_ptr;
+               StuffData_FinishBlock(code + count);
+       }       
+       return(dst);
+}
+
+/* UnStuffData decodes the data at "src", up to (but not including) "end".
+It writes the decoded data into the buffer pointed to by "dst", up to a
+maximum of "dst_length", and returns the new value of "src" so that a
+follow-on call can read more data, continuing from where the first left off.
+
+There are three types of results:
+1. The source data runs out before extracting "dst_length" bytes:
+   UnStuffData returns NULL to indicate failure.
+2. The source data produces exactly "dst_length" bytes:
+   UnStuffData returns new_src = end to indicate that all bytes were consumed.
+3. "dst_length" bytes are extracted, with more remaining.
+   UnStuffData returns new_src < end to indicate that there are more bytes
+   to be read.
+
+Note: The decoding may be dstructive, in that it may alter the source
+data in the process of decoding it (this is necessary to allow a follow-on
+call to resume correctly). */
+
+static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length)
+{
+       __u8 *dst_end = dst + dst_length;
+       /* Sanity check */
+       if (!src || !end || !dst || !dst_length) 
+               return(NULL);
+       while (src < end && dst < dst_end) 
+       {
+               int count = (*src ^ Stuff_Magic) & Stuff_CountMask;
+               switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) 
+               {
+                       case Stuff_Diff:
+                               if (src+1+count >= end) 
+                                       return(NULL);
+                               do 
+                               {
+                                       *dst++ = *++src ^ Stuff_Magic;
+                               }
+                               while(--count >= 0 && dst < dst_end);
+                               if (count < 0) 
+                                       src += 1;
+                               else 
+                               {
+                                       if (count == 0)
+                                               *src = Stuff_Same ^ Stuff_Magic;
+                                       else
+                                               *src = (Stuff_Diff + count) ^ Stuff_Magic;
+                               }
+                               break;
+                       case Stuff_DiffZero:
+                               if (src+1+count >= end) 
+                                       return(NULL);
+                               do 
+                               {
+                                       *dst++ = *++src ^ Stuff_Magic;
+                               }
+                               while(--count >= 0 && dst < dst_end);
+                               if (count < 0)
+                                       *src = Stuff_Zero ^ Stuff_Magic;
+                               else
+                                       *src = (Stuff_DiffZero + count) ^ Stuff_Magic;
+                               break;
+                       case Stuff_Same:
+                               if (src+1 >= end)
+                                       return(NULL);
+                               do 
+                               {
+                                       *dst++ = src[1] ^ Stuff_Magic;
+                               }
+                               while(--count >= 0 && dst < dst_end);
+                               if (count < 0)
+                                       src += 2;
+                               else
+                                       *src = (Stuff_Same + count) ^ Stuff_Magic;
+                               break;
+                       case Stuff_Zero:
+                               do 
+                               {
+                                       *dst++ = 0;
+                               }
+                               while(--count >= 0 && dst < dst_end);
+                               if (count < 0)
+                                       src += 1;
+                               else
+                                       *src = (Stuff_Zero + count) ^ Stuff_Magic;
+                               break;
+               }
+       }
+       if (dst < dst_end) 
+               return(NULL);
+       else
+               return(src);
+}
+
+/************************************************************************/
+/* General routines for STRIP                                          */
+
+/* MTU has been changed by the IP layer. Unfortunately we are not told
+ * about this, but we spot it ourselves and fix things up. We could be in
+ * an upcall from the tty driver, or in an ip packet queue.
+ */
+
+static void strip_changedmtu(struct strip *strip_info)
+{
+       struct device *dev = &strip_info->dev;
+       unsigned char *tbuff, *rbuff, *sbuff, *otbuff, *orbuff, *osbuff;
+       int len;
+       InterruptStatus intstat;
+
+       len = STRIP_ENCAP_SIZE(dev->mtu);
+       if (len < STRIP_ENCAP_SIZE(576)) 
+               len = STRIP_ENCAP_SIZE(576);
+
+       tbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+       rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+       sbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+       if (!tbuff || !rbuff || !sbuff) 
+       {
+               printk("%s: unable to grow strip buffers, MTU change cancelled.\n",
+                       strip_info->dev.name);
+               dev->mtu = strip_info->mtu;
+               if (tbuff)
+                       kfree(tbuff);
+               if (rbuff)
+                       kfree(rbuff);
+               if (sbuff)
+                       kfree(sbuff);
+               return;
+       }
+
+       intstat = DisableInterrupts();
+       otbuff = strip_info->tx_buff; strip_info->tx_buff = tbuff;
+       orbuff = strip_info->rx_buff; strip_info->rx_buff = rbuff;
+       osbuff = strip_info->sx_buff; strip_info->sx_buff = sbuff;
+       if (strip_info->tx_left) 
+       {
+               if (strip_info->tx_left <= len)
+                       memcpy(strip_info->tx_buff, strip_info->tx_head, strip_info->tx_left);
+               else 
+               {
+                       strip_info->tx_left = 0;
+                       strip_info->tx_dropped++;
+               }
+       }
+       strip_info->tx_head = strip_info->tx_buff;
+
+       if (strip_info->sx_count) 
+       {
+               if (strip_info->sx_count <= len)
+                       memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count);
+               else
+               {
+                       strip_info->sx_count = 0;
+                       strip_info->rx_over_errors++;
+                       set_bit(STR_ERROR, &strip_info->flags);
+               }
+       }
+
+       strip_info->mtu      = STRIP_ENCAP_SIZE(dev->mtu);
+       strip_info->buffsize = len;
+
+       RestoreInterrupts(intstat);
+
+       if (otbuff != NULL)
+                kfree(otbuff);
+       if (orbuff != NULL)
+               kfree(orbuff);
+       if (osbuff != NULL)
+               kfree(osbuff);
+}
+
+static void strip_unlock(struct strip *strip_info)
+{
+       strip_info->idle_timer.expires  = jiffies + 2 * HZ;
+       add_timer(&strip_info->idle_timer);
+       if (!clear_bit(0, (void *)&strip_info->dev.tbusy))
+               printk("%s: trying to unlock already unlocked device!\n",
+                       strip_info->dev.name);
+}
+
+/************************************************************************/
+/* Sending routines                                                    */
+
+static void ResetRadio(struct strip *strip_info)
+{      
+       static const char InitString[] = "ate0dt**starmode\r**";
+       strip_info->watchdog_doprobe = jiffies + 10 * HZ;
+       strip_info->watchdog_doreset = jiffies + 1 * HZ;
+       strip_info->tty->driver.write(strip_info->tty, 0,
+               (char *)InitString, sizeof(InitString)-1);
+}
+
+/*
+ * Called by the driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+
+static void strip_write_some_more(struct tty_struct *tty)
+{
+       InterruptStatus intstat;
+       int num_written;
+       struct strip *strip_info = (struct strip *) tty->disc_data;
+
+       /* First make sure we're connected. */
+       if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start)
+               return;
+
+       if (strip_info->tx_left > 0) 
+       {       /* If some data left, send it */
+               /* Must disable interrupts because othewise the write_wakeup might
+                * happen before we've had a chance to update the tx_left and
+                *  tx_head fields
+                */
+               intstat = DisableInterrupts();
+               num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left);
+               strip_info->tx_left -= num_written;
+               strip_info->tx_head += num_written;
+               RestoreInterrupts(intstat);
+       }
+       else                    /* Else start transmission of another packet */
+       {
+               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               strip_unlock(strip_info);
+               mark_bh(NET_BH);
+       }
+}
+
+
+/* Encapsulate one IP datagram. */
+
+static unsigned char *strip_stuff(unsigned char *ptr, struct strip *strip_info, struct sk_buff *skb)
+{
+    __u8         *start;
+    __u8         *stuffstate = NULL;
+    unsigned char  *icp        = skb->data;
+    int             len        = skb->len;
+    MetricomAddress haddr;
+
+    if (len > strip_info->mtu) {               /* Sigh, shouldn't occur BUT ... */
+        printk("%s: Dropping oversized transmit packet!\n", strip_info->dev.name);
+        strip_info->tx_dropped++;
+        return(NULL);
+    }
+
+    if (!arp_query(haddr.c, skb->raddr, &strip_info->dev)) {
+        IPaddr a,b,c;
+        a.l = skb->raddr;
+        b.l = skb->saddr;
+        c.l = skb->daddr;
+        printk("%s: Unknown dest %d.%d.%d.%d s=%d.%d.%d.%d d=%d.%d.%d.%d\n",
+            strip_info->dev.name,
+            a.b[0], a.b[1], a.b[2], a.b[3],
+            b.b[0], b.b[1], b.b[2], b.b[3],
+            c.b[0], c.b[1], c.b[2], c.b[3]);
+        strip_info->tx_dropped++;
+        return(NULL);
+    }
+
+    *ptr++ = '*';
+    ptr[3] = '0' + haddr.s[0] % 10; haddr.s[0] /= 10;
+    ptr[2] = '0' + haddr.s[0] % 10; haddr.s[0] /= 10;
+    ptr[1] = '0' + haddr.s[0] % 10; haddr.s[0] /= 10;
+    ptr[0] = '0' + haddr.s[0] % 10;
+    ptr+=4;
+    *ptr++ = '-';
+    ptr[3] = '0' + haddr.s[1] % 10; haddr.s[1] /= 10;
+    ptr[2] = '0' + haddr.s[1] % 10; haddr.s[1] /= 10;
+    ptr[1] = '0' + haddr.s[1] % 10; haddr.s[1] /= 10;
+    ptr[0] = '0' + haddr.s[1] % 10;
+    ptr+=4;
+    *ptr++ = '*';
+    *ptr++ = ProtocolKey.c[0];                         /* Protocol key */
+    *ptr++ = ProtocolKey.c[1];
+    *ptr++ = ProtocolKey.c[2];
+    *ptr++ = ProtocolKey.c[3];
+
+    start = ptr;
+    ptr = StuffData(icp, len, ptr, &stuffstate);       /* Make payload */
+
+    *ptr++ = 0x0D;                                     /* Put on final delimiter */
+    return(ptr);
+}
+
+/* Encapsulate one IP datagram and stuff into a TTY queue. */
+static void strip_send(struct strip *strip_info, struct sk_buff *skb)
+{
+    unsigned char *ptr;
+
+    /* See if someone has been ifconfigging */
+    if (strip_info->mtu != STRIP_ENCAP_SIZE(strip_info->dev.mtu))
+        strip_changedmtu(strip_info);
+
+    ptr = strip_info->tx_buff;
+
+    /* If we have a packet, encapsulate it and put it in the buffer */
+    if (skb) {
+        ptr = strip_stuff(ptr, strip_info, skb);
+        /* If error, unlock and return */
+        if (!ptr) { strip_unlock(strip_info); return; }
+        strip_info->tx_packets++;      /* Count another successful packet */
+    }
+
+    /* Set up the strip_info ready to send the data */
+    strip_info->tx_head =       strip_info->tx_buff;
+    strip_info->tx_left = ptr - strip_info->tx_buff;
+    strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+
+    /* If watchdog has expired, reset the radio */
+    if ((long)jiffies - strip_info->watchdog_doreset >= 0) {
+        printk("%s: No response: Resetting radio.\n", strip_info->dev.name);
+        ResetRadio(strip_info);
+        /* Note: if there's a packet to send, strip_write_some_more
+                 will do it after the reset has finished */
+        return;
+    }
+    
+    /* No reset.
+     * If it is time for another tickle, tack it on the end of the packet
+     */
+    if ((long)jiffies - strip_info->watchdog_doprobe >= 0) {
+        /* printk("%s: Routine radio test.\n", strip_info->dev.name); */
+        *ptr++ = '*';                  /* Tickle to make radio protest */
+        *ptr++ = '*';
+        strip_info->tx_left += 2;
+        strip_info->watchdog_doprobe = jiffies + 10 * HZ;
+        strip_info->watchdog_doreset = jiffies + 1 * HZ;
+    }
+    
+    /* All ready. Start the transmission */
+    strip_write_some_more(strip_info->tty);
+}
+
+/* Encapsulate an IP datagram and kick it into a TTY queue. */
+static int strip_xmit(struct sk_buff *skb, struct device *dev)
+{
+    struct strip *strip_info = (struct strip *)(dev->priv);
+
+    if (!dev->start) {
+       printk("%s: xmit call when iface is down\n", dev->name);
+       return(1);
+    }
+    if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
+    del_timer(&strip_info->idle_timer);
+    strip_send(strip_info, skb);
+    if (skb) dev_kfree_skb(skb, FREE_WRITE);
+    return(0);
+}
+
+/* IdleTask periodically calls strip_xmit, so even when we have no IP packets
+   to send for an extended period of time, the watchdog processing still gets
+   done to ensure that the radio stays in Starmode */
+
+static void strip_IdleTask(unsigned long parameter)
+{
+       strip_xmit(NULL, (struct device *)parameter);
+}
+
+/************************************************************************/
+/* Receiving routines                                                  */
+
+static int strip_receive_room(struct tty_struct *tty)
+{
+       return 65536;  /* We can handle an infinite amount of data. :-) */
+}
+
+/* Send one completely decapsulated IP datagram to the IP layer. */
+
+static void strip_bump(struct strip *strip_info, __u16 packetlen)
+{
+       int count = sizeof(STRIP_Header) + packetlen;
+       struct sk_buff *skb = dev_alloc_skb(count);
+       if (skb == NULL) 
+       {
+               printk("%s: memory squeeze, dropping packet.\n", 
+                       strip_info->dev.name);
+               strip_info->rx_dropped++;
+               return;
+       }
+       skb->dev = &strip_info->dev;
+       memcpy(skb_put(skb, count), strip_info->rx_buff, count);
+       skb->mac.raw=skb->data;
+       skb->protocol = htons(ETH_P_IP);
+       netif_rx(skb);
+       strip_info->rx_packets++;
+}
+
+static void RecvErr(char *msg, struct strip *strip_info)
+{
+       static const int MAX_RecvErr = 80;
+       __u8 *ptr = strip_info->sx_buff;
+       __u8 *end = strip_info->sx_buff + strip_info->sx_count;
+       __u8 pkt_text[MAX_RecvErr], *p = pkt_text;
+       *p++ = '\"';
+       while (ptr<end && p < &pkt_text[MAX_RecvErr-4]) 
+       {
+               if (*ptr == '\\') 
+               {
+                       *p++ = '\\';
+                       *p++ = '\\';
+               }
+               else 
+               {
+                       if (*ptr >= 32 && *ptr <= 126) 
+                               *p++ = *ptr;
+                       else
+                       {
+                               sprintf(p, "\\%02X", *ptr);
+                               p+= 3;
+                       }
+               }
+               ptr++;
+       }
+       if (ptr == end)
+               *p++ = '\"';
+       *p++ = 0;
+       printk("%-13s%s\n", msg, pkt_text);
+       set_bit(STR_ERROR, &strip_info->flags);
+       strip_info->rx_errors++;
+}
+
+static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, __u8 *msg)
+{
+       static const char ERR_001[] = "ERR_001 Not in StarMode!";
+       static const char ERR_002[] = "ERR_002 Remap handle";
+       static const char ERR_003[] = "ERR_003 Can't resolve name";
+       static const char ERR_004[] = "ERR_004 Name too small or missing";
+       static const char ERR_007[] = "ERR_007 Body too big";
+       static const char ERR_008[] = "ERR_008 Bad character in name";
+
+       if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1))
+               printk("Radio %s is not in StarMode\n", sendername);
+       else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1)) 
+       {
+#ifdef notyet          /*Kernel doesn't have scanf!*/
+               int handle;
+               __u8 newname[64];
+               sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname);
+               printk("Radio name %s is handle %d\n", newname, handle);
+#endif
+       }
+       else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1)) 
+               printk("Radio name <unspecified> is unknown (\"Can't resolve name\" error)\n");
+       else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) 
+               strip_info->watchdog_doreset = jiffies + LONG_TIME;
+        else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1)) 
+        {
+               /*
+                *      Note: This error knocks the radio back into 
+                *      command mode. 
+                */
+               printk("Error! Packet size <unspecified> is too big for radio.");
+               strip_info->watchdog_doreset = jiffies;         /* Do reset ASAP */
+       }
+       else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1)) 
+               printk("Name <unspecified> contains illegal character\n");
+       else 
+               RecvErr("Error Msg:", strip_info);
+}
+
+static void process_packet(struct strip *strip_info)
+{
+    __u8 *ptr = strip_info->sx_buff;
+    __u8 *end = strip_info->sx_buff + strip_info->sx_count;
+    __u8 *name, *name_end;
+    __u16 packetlen;
+
+    /* Ignore empty lines */
+    if (strip_info->sx_count == 0) return;
+
+    /* Catch 'OK' responses which show radio has fallen out of starmode */
+    if (strip_info->sx_count == 2 && ptr[0] == 'O' && ptr[1] == 'K') {
+        printk("%s: Radio is back in AT command mode: Will Reset\n",
+            strip_info->dev.name);
+        strip_info->watchdog_doreset = jiffies;                /* Do reset ASAP */
+        return;
+    }
+
+    /* Check for start of address marker, and then skip over it */
+    if (*ptr != '*') {
+        /* Catch other error messages */
+        if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_')
+            RecvErr_Message(strip_info, NULL, strip_info->sx_buff);
+        else RecvErr("No initial *", strip_info);
+        return;
+    }
+    ptr++;
+
+    /* Skip the return address */
+    name = ptr;
+    while (ptr < end && *ptr != '*') ptr++;
+
+    /* Check for end of address marker, and skip over it */
+    if (ptr == end) {
+        RecvErr("No second *", strip_info);
+        return;
+    }
+    name_end = ptr++;
+
+    /* Check for SRIP key, and skip over it */
+    if (ptr[0] != ProtocolKey.c[0] ||
+        ptr[1] != ProtocolKey.c[1] ||
+        ptr[2] != ProtocolKey.c[2] ||
+        ptr[3] != ProtocolKey.c[3]) {
+        if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_') { *name_end = 0; RecvErr_Message(strip_info, name, ptr); }
+        else RecvErr("Unrecognized protocol key", strip_info);
+        return;
+    }
+    ptr += 4;
+
+    /* Decode start of the IP packet header */
+    ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4);
+    if (!ptr) {
+        RecvErr("Runt packet", strip_info);
+        return;
+    }
+
+    packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3];
+/*     printk("Packet %02X.%02X.%02X.%02X\n",
+        strip_info->rx_buff[0], strip_info->rx_buff[1],
+        strip_info->rx_buff[2], strip_info->rx_buff[3]);
+    printk("Got %d byte packet\n", packetlen);*/
+
+    /* Decode remainder of the IP packer */
+    ptr = UnStuffData(ptr, end, strip_info->rx_buff+4, packetlen-4);
+    if (!ptr) {
+        RecvErr("Runt packet", strip_info);
+        return;
+    }
+    strip_bump(strip_info, packetlen);
+
+    /* This turns out to be a mistake. Taking receipt of a valid packet as
+     * evidence that the radio is correctly in Starmode (and resetting the
+     * watchdog_doreset timer) is wrong.  It turns out that if the radio is
+     * in command mode, with character echo on, then the echo of the packet
+     * you sent coming back looks like a valid packet and fools this test.
+     * We should only accept the "ERR_004 Name too small or missing" message
+     * as evidence that the radio is correctly in Starmode.
+    strip_info->watchdog_doprobe = jiffies + 10 * HZ;
+    strip_info->watchdog_doreset = jiffies + LONG_TIME;
+     */
+}
+
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of STRIP data has been received, which can now be decapsulated
+ * and sent on to some IP layer for further processing.
+ */
+static void
+strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+/*     struct timeval tv;*/
+    struct strip *strip_info = (struct strip *) tty->disc_data;
+    const unsigned char *end = cp + count;
+
+    if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start)
+        return;
+
+    /* Argh! mtu change time! - costs us the packet part received at the change */
+    if (strip_info->mtu != STRIP_ENCAP_SIZE(strip_info->dev.mtu))
+        strip_changedmtu(strip_info);
+
+/*     do_gettimeofday(&tv);
+    printk("**** strip_receive_buf: %3d bytes at %d.%06d\n",
+        count, tv.tv_sec % 100, tv.tv_usec);*/
+    /* Read the characters out of the buffer */
+    while (cp < end) {
+        if (fp && *fp++) {
+            if (!set_bit(STR_ERROR, &strip_info->flags)) strip_info->rx_errors++;
+        }
+        else if (*cp == 0x0D) {
+            /*printk("Cut a %d byte packet (%d bytes remaining)\n",
+                strip_info->sx_count, end-cp-1);*/
+            if (!clear_bit(STR_ERROR, &strip_info->flags))
+                process_packet(strip_info);
+            strip_info->sx_count = 0;
+        }
+        else if (!test_bit(STR_ERROR, &strip_info->flags) &&
+            (strip_info->sx_count > 0 || *cp != 0x0A))
+        {
+            /* (leading newline characters are ignored) */
+            if (strip_info->sx_count < strip_info->buffsize)
+                strip_info->sx_buff[strip_info->sx_count++] = *cp;
+            else
+            {
+                set_bit(STR_ERROR, &strip_info->flags);
+                strip_info->rx_over_errors++;
+            }
+        }
+        cp++;
+    }
+}
+
+/************************************************************************/
+/* General control routines                                            */
+
+/*
+ *      Create the Ethernet MAC header for an arbitrary protocol layer 
+ *
+ *     saddr=NULL      means use device source address
+ *     daddr=NULL      means leave destination address (eg unresolved arp)
+ */
+
+static int strip_header(struct sk_buff *skb, struct device *dev, 
+       unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+       return(-dev->hard_header_len);
+}
+
+/*
+ *     Rebuild the Ethernet MAC header. This is called after an ARP
+ *     (or in future other address resolution) has completed on this
+ *     sk_buff. We now let ARP fill in the other fields.
+ */
+
+/* I think this should return zero if packet is ready to send, */
+/* or non-zero if it needs more time to do an address lookup   */
+
+static int strip_rebuild_header(void *buff, struct device *dev, 
+       unsigned long dst, struct sk_buff *skb)
+{
+/*     STRIP_Header *h = (STRIP_Header *)buff;*/
+
+#ifdef CONFIG_INET
+       /* I'll use arp_find when I understand it */
+       /* Arp find returns zero if if knows the address, or if it doesn't */
+       /* know the address it sends an ARP packet and returns non-zero */
+       /*return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;*/
+       return(0);
+#else
+       return(0);
+#endif 
+}
+
+static int strip_set_dev_mac_address(struct device *dev, void *addr)
+{
+       memcpy(dev->dev_addr, addr, 7);
+       return 0;
+}
+
+static struct enet_statistics *strip_get_stats(struct device *dev)
+{
+       static struct enet_statistics stats;
+       struct strip *strip_info = (struct strip *)(dev->priv);
+
+       memset(&stats, 0, sizeof(struct enet_statistics));
+
+       stats.rx_packets     = strip_info->rx_packets;
+       stats.tx_packets     = strip_info->tx_packets;
+       stats.rx_dropped     = strip_info->rx_dropped;
+       stats.tx_dropped     = strip_info->tx_dropped;
+       stats.tx_errors      = strip_info->tx_errors;
+       stats.rx_errors      = strip_info->rx_errors;
+       stats.rx_over_errors = strip_info->rx_over_errors;
+       return(&stats);
+}
+
+/************************************************************************/
+/* Opening and closing                                                 */
+
+/*
+ * Here's the order things happen:
+ * When the user runs "slattach -p strip ..."
+ *  1. The TTY module calls strip_open
+ *  2. strip_open calls strip_alloc
+ *  3.                  strip_alloc calls register_netdev
+ *  4.                  register_netdev calls strip_dev_init
+ *  5. then strip_open finishes setting up the strip_info
+ *
+ * When the user runs "ifconfig st<x> up address netmask ..."
+ *  6. strip_open_low gets called
+ *
+ * When the user runs "ifconfig st<x> down"
+ *  7. strip_close_low gets called
+ *
+ * When the user kills the slattach process
+ *  8. strip_close gets called
+ *  9. strip_close calls dev_close
+ * 10. if the device is still up, then dev_close calls strip_close_low
+ * 11. strip_close calls strip_free
+ */
+
+/* Open the low-level part of the STRIP channel. Easy! */
+
+static int strip_open_low(struct device *dev)
+{
+       struct strip *strip_info = (struct strip *)(dev->priv);
+       unsigned long len;
+
+       if (strip_info->tty == NULL) 
+               return(-ENODEV);
+
+       /*
+        * Allocate the STRIP frame buffers:
+        *
+        * rbuff        Receive buffer.
+        * tbuff        Transmit buffer.
+        * cbuff        Temporary compression buffer.
+        */
+
+       len = STRIP_ENCAP_SIZE(dev->mtu);
+       if (len < STRIP_ENCAP_SIZE(576)) 
+               len = STRIP_ENCAP_SIZE(576);
+       strip_info->rx_buff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+       if (strip_info->rx_buff == NULL) 
+               goto norbuff;
+       strip_info->sx_buff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+       if (strip_info->sx_buff == NULL) 
+               goto nosbuff;
+       strip_info->tx_buff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+       if (strip_info->tx_buff == NULL) 
+               goto notbuff;
+
+       strip_info->flags   &= (1 << STR_INUSE); /* Clear ESCAPE & ERROR flags */
+       strip_info->mtu  = STRIP_ENCAP_SIZE(dev->mtu);
+       strip_info->buffsize = len;
+       strip_info->sx_count = 0;
+       strip_info->tx_left  = 0;
+
+       /*
+        *      Needed because address '0' is special 
+        */
+        
+       if (dev->pa_addr == 0) 
+               dev->pa_addr=ntohl(0xC0A80001);
+       dev->tbusy  = 0;
+       dev->start  = 1;
+
+       printk("%s: Initializing Radio.\n", strip_info->dev.name);
+       ResetRadio(strip_info);
+       strip_info->idle_timer.expires  = jiffies + 2 * HZ;
+       add_timer(&strip_info->idle_timer);
+       return(0);
+
+notbuff:
+       kfree(strip_info->sx_buff);
+nosbuff:
+       kfree(strip_info->rx_buff);
+norbuff:
+       return(-ENOMEM);
+}
+
+
+/*
+ *     Close the low-level part of the STRIP channel. Easy! 
+ */
+static int strip_close_low(struct device *dev)
+{
+       struct strip *strip_info = (struct strip *)(dev->priv);
+
+       if (strip_info->tty == NULL) 
+               return -EBUSY;
+       strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+       dev->tbusy = 1;
+       dev->start = 0;
+    
+       /*
+        *      Free all STRIP frame buffers.
+        */
+       if (strip_info->rx_buff) 
+       {
+               kfree(strip_info->rx_buff);
+               strip_info->rx_buff = NULL;
+       }
+       if (strip_info->sx_buff) 
+       {
+               kfree(strip_info->sx_buff); 
+               strip_info->sx_buff = NULL;
+       }
+       if (strip_info->tx_buff) 
+       {
+               kfree(strip_info->tx_buff); 
+               strip_info->tx_buff = NULL; 
+       }
+       del_timer(&strip_info->idle_timer);
+       return 0;
+}
+
+/* 
+ *     This routine is called by DDI when the
+ *     (dyamically assigned) device is registered
+ */
+static int strip_dev_init(struct device *dev)
+{
+       int i;
+       
+       /*
+        *      Finish setting up the DEVICE info. 
+        */
+
+       dev->trans_start        = 0;
+       dev->last_rx            = 0;
+       dev->tx_queue_len       = 30;   /* Drop after 30 frames queued */
+
+       dev->flags              = 0;
+       dev->family             = AF_INET;
+       dev->metric             = 0;
+       dev->mtu                = STRIP_MTU;
+       dev->type               = ARPHRD_METRICOM;        /* dtang */
+       dev->hard_header_len    = 8; /*sizeof(STRIP_Header);*/
+       /*
+        *  dev->priv                 Already holds a pointer to our struct strip 
+        */
+
+       dev->broadcast[0]       = 0;
+       dev->dev_addr[0]        = 0;
+       dev->addr_len           = sizeof(MetricomAddress);
+       dev->pa_addr            = 0;
+       dev->pa_brdaddr         = 0;
+       dev->pa_mask            = 0;
+       dev->pa_alen            = sizeof(unsigned long);
+
+       /*
+        *      Pointer to the interface buffers. 
+        */
+        
+       for (i = 0; i < DEV_NUMBUFFS; i++) 
+               skb_queue_head_init(&dev->buffs[i]);
+
+       /*
+        *      Pointers to interface service routines. 
+        */
+
+       dev->open               = strip_open_low;
+       dev->stop               = strip_close_low;
+       dev->hard_start_xmit    = strip_xmit;
+       dev->hard_header        = strip_header;
+       dev->rebuild_header     = strip_rebuild_header;
+       /*  dev->type_trans            unused */
+       /*  dev->set_multicast_list   unused */
+       dev->set_mac_address    = strip_set_dev_mac_address;
+       /*  dev->do_ioctl             unused */
+       /*  dev->set_config           unused */
+       dev->get_stats          = strip_get_stats;
+       return 0;
+}
+
+/*
+ *     Free a STRIP channel. 
+ */
+static void strip_free(struct strip *strip_info)
+{
+       *(strip_info->referrer) = strip_info->next;
+       if (strip_info->next) 
+               strip_info->next->referrer = strip_info->referrer;
+       strip_info->magic = 0;
+       kfree(strip_info);
+}
+
+/* 
+ *     Allocate a new free STRIP channel 
+ */
+static struct strip *strip_alloc(void)
+{
+       int channel_id = 0;
+       struct strip **s = &struct_strip_list;
+       struct strip *strip_info = (struct strip *)
+               kmalloc(sizeof(struct strip), GFP_KERNEL);
+
+       if (!strip_info) 
+               return(NULL);   /* If no more memory, return */
+
+       /*
+        *      Clear the allocated memory 
+        */
+        
+       memset(strip_info, 0, sizeof(struct strip));
+
+       /*
+        *      Search the list to find where to put our new entry
+        *      (and in the process decide what channel number it is
+        *      going to be) 
+        */
+        
+       while (*s && (*s)->dev.base_addr == channel_id) 
+       {
+               channel_id++;
+               s = &(*s)->next;
+       }
+
+       /*
+        *      Fill in the link pointers 
+        */
+        
+       strip_info->next = *s;
+       if (*s) 
+               (*s)->referrer = &strip_info->next;
+       strip_info->referrer = s;
+       *s = strip_info;
+
+       set_bit(STR_INUSE, &strip_info->flags);
+       strip_info->magic = STRIP_MAGIC;
+       strip_info->tty   = NULL;
+
+       init_timer(&strip_info->idle_timer);
+       strip_info->idle_timer.data     = (long)&strip_info->dev;
+       strip_info->idle_timer.function = strip_IdleTask;
+
+       sprintf(strip_info->if_name, "st%d", channel_id);
+       strip_info->dev.name         = strip_info->if_name;
+       strip_info->dev.base_addr    = channel_id;
+       strip_info->dev.priv         = (void*)strip_info;
+       strip_info->dev.next         = NULL;
+       strip_info->dev.init         = strip_dev_init;
+
+       return(strip_info);
+}
+
+/*
+ *     Open the high-level part of the STRIP channel.
+ *     This function is called by the TTY module when the
+ *     STRIP line discipline is called for.  Because we are
+ *     sure the tty line exists, we only have to link it to
+ *     a free STRIP channel...
+ */
+
+static int strip_open(struct tty_struct *tty)
+{
+       struct strip *strip_info = (struct strip *) tty->disc_data;
+
+       /*
+        *      First make sure we're not already connected.
+        */
+       
+       if (strip_info && strip_info->magic == STRIP_MAGIC) 
+               return -EEXIST;
+
+       /*
+        *      OK.  Find a free STRIP channel to use. 
+        */
+        
+       if ((strip_info = strip_alloc()) == NULL) 
+               return -ENFILE;
+
+       /*
+        *      Register our newly created device so it can be ifconfig'd
+        * strip_dev_init() will be called as a side-effect
+        */
+     
+       if (register_netdev(&strip_info->dev) != 0) 
+       {
+               printk("strip: register_netdev() failed.\n");
+               strip_free(strip_info);
+               return -ENFILE;
+       }
+
+       strip_info->tty = tty;
+       tty->disc_data = strip_info;
+       if (tty->driver.flush_buffer) 
+               tty->driver.flush_buffer(tty);
+       if (tty->ldisc.flush_buffer) 
+               tty->ldisc.flush_buffer(tty);
+
+       /*
+        *      Restore default settings 
+        */
+        
+       strip_info->dev.type = ARPHRD_METRICOM; /* dtang */
+
+       /*
+        *      Set tty options 
+        */
+
+       tty->termios->c_iflag |= IGNBRK |IGNPAR;/* Ignore breaks and parity errors. */
+       tty->termios->c_cflag |= CLOCAL;        /* Ignore modem control signals. */
+       tty->termios->c_cflag &= ~HUPCL;        /* Don't close on hup */
+
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+       /*
+        *      Done.  We have linked the TTY line to a channel. 
+        */
+       return(strip_info->dev.base_addr);
+}
+
+/*
+ * Close down a STRIP channel.
+ * This means flushing out any pending queues, and then restoring the
+ * TTY line discipline to what it was before it got hooked to STRIP
+ * (which usually is TTY again).
+ */
+static void strip_close(struct tty_struct *tty)
+{
+       struct strip *strip_info = (struct strip *) tty->disc_data;
+
+       /*
+        *      First make sure we're connected. 
+        */
+        
+       if (!strip_info || strip_info->magic != STRIP_MAGIC) 
+               return;
+
+       dev_close(&strip_info->dev);
+       unregister_netdev(&strip_info->dev);
+    
+       tty->disc_data = 0;
+       strip_info->tty = NULL;
+       strip_free(strip_info);
+       tty->disc_data = NULL;
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+}
+
+
+/************************************************************************/
+/* Perform I/O control calls on an active STRIP channel.                       */
+
+static int strip_ioctl(struct tty_struct *tty, struct file *file, 
+       unsigned int cmd, unsigned long arg)
+{
+       struct strip *strip_info = (struct strip *) tty->disc_data;
+       int err;
+
+       /*
+        *      First make sure we're connected. 
+        */
+        
+       if (!strip_info || strip_info->magic != STRIP_MAGIC) 
+               return -EINVAL;
+
+       switch(cmd) 
+       {
+               case SIOCGIFNAME:
+                       err = verify_area(VERIFY_WRITE, (void*)arg, 16);
+                       if (err)
+                               return -err;
+                       memcpy_tofs((void*)arg, strip_info->dev.name, 
+                               strlen(strip_info->dev.name) + 1);
+                       return 0;
+
+               case SIOCSIFHWADDR:
+                       return -EINVAL;
+
+               /*
+                *      Allow stty to read, but not set, the serial port 
+                */
+        
+               case TCGETS:
+               case TCGETA:
+                       return n_tty_ioctl(tty, (struct file *) file, cmd, 
+                               (unsigned long) arg);
+
+               default:
+                       return -ENOIOCTLCMD;
+       }
+}
+
+/************************************************************************/
+/* Initialization                                                      */
+
+/*
+ *     Initialize the STRIP driver.
+ *     This routine is called at boot time, to bootstrap the multi-channel
+ *     STRIP driver
+ */
+
+#ifdef MODULE
+static
+#endif
+int strip_init_ctrl_dev(struct device *dummy)
+{
+       static struct tty_ldisc strip_ldisc;
+       int status;
+       printk("STRIP: version %s (unlimited channels)\n", STRIP_VERSION);
+
+       /*
+        *      Fill in our line protocol discipline, and register it
+        */
+        
+       memset(&strip_ldisc, 0, sizeof(strip_ldisc));
+       strip_ldisc.magic       = TTY_LDISC_MAGIC;
+       strip_ldisc.flags       = 0;
+       strip_ldisc.open        = strip_open;
+       strip_ldisc.close       = strip_close;
+       strip_ldisc.read        = NULL;
+       strip_ldisc.write       = NULL;
+       strip_ldisc.ioctl       = strip_ioctl;
+       strip_ldisc.select       = NULL;
+       strip_ldisc.receive_buf  = strip_receive_buf;
+       strip_ldisc.receive_room = strip_receive_room;
+       strip_ldisc.write_wakeup = strip_write_some_more;
+       status = tty_register_ldisc(N_STRIP, &strip_ldisc);
+       if (status != 0) 
+       {
+               printk("STRIP: can't register line discipline (err = %d)\n", status);
+       }
+
+#ifdef MODULE
+        return status;
+#else
+       /* Return "not found", so that dev_init() will unlink
+        * the placeholder device entry for us.
+        */
+       return ENODEV;
+#endif
+}
+
+/************************************************************************/
+/* From here down is only used when compiled as an external module        */
+
+#ifdef MODULE
+
+int init_module(void)
+{
+    return strip_init_ctrl_dev(0);
+}
+
+void cleanup_module(void)
+{
+       int i;
+       while (struct_strip_list) 
+               strip_free(struct_strip_list);
+
+       if ((i = tty_register_ldisc(N_STRIP, NULL)))  
+               printk("STRIP: can't unregister line discipline (err = %d)\n", i);
+}
+#endif /* MODULE */
index 10783863340c690066512d7da6a3ca6ccb6edd10..f69da3b8595a57f91f14ee9b6d80ff804ef8fe28 100644 (file)
@@ -93,8 +93,8 @@ struct pci_dev_info dev_info[] = {
        DEVICE( FD,             FD_36C70,       "TMC-18C30"),
        DEVICE( SI,             SI_6201,        "6201"),
        DEVICE( SI,             SI_6202,        "6202"),
-       DEVICE( SI,             SI_6205,        "6205"),
        DEVICE( SI,             SI_503,         "85C503"),
+       DEVICE( SI,             SI_6205,        "6205"),
        DEVICE( SI,             SI_501,         "85C501"),
        DEVICE( SI,             SI_496,         "85C496"),
        DEVICE( SI,             SI_601,         "85C601"),
index caed509af0e29c4d3ce679e67e1f82b533abda43..148423bc8fa04820f8fc3d01c6b53f7dde1b939a 100644 (file)
  *  the fourth byte from 50 to 25.
  */
 
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_NCR53C7xx_sync
+#define PERM_OPTIONS (OPTION_IO_MAPPED|OPTION_DEBUG_TEST1|OPTION_DISCONNECT|\
+       OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS)
+#else
 #define PERM_OPTIONS (OPTION_IO_MAPPED|OPTION_DEBUG_TEST1|OPTION_DISCONNECT|\
        OPTION_SYNCHRONOUS)
+#endif
 
 /*
  * Sponsored by 
@@ -635,7 +642,11 @@ setup_wrapper(825)
 /* Template for "preferred" synchronous transfer parameters. */
 
 static const unsigned char sdtr_message[] = {
+#ifdef CONFIG_SCSI_NCR53C7xx_FAST
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */ 
+#else
     EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */ 
+#endif
 };
 
 /* Template to request asynchronous transfers */
index ca8ae6e13d0144bc46bd9d551585afa4cc4f76c9..40b9ecc13aa253eef64a5c9c6ab0ddc5de65495a 100644 (file)
@@ -36,6 +36,10 @@ fi
 if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI
 fi
+if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then
+  bool '   always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync
+  bool '   allow FAST-SCSI [10MHz]' CONFIG_SCSI_NCR53C7xx_FAST
+fi
 dep_tristate 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC $CONFIG_SCSI
index 2f39f19776e0b9cf1ec9e05bbd9ee05c64e02d59..b415545f57e6b2e37b1eeb86df2e0e4e3ad58c3d 100644 (file)
@@ -646,7 +646,7 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
       any2scsi(ccb[mbo].dataptr, buff);
     };
     ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/
-    ccb[mbo].rsalen = 12;
+    ccb[mbo].rsalen = 16;
     ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
     ccb[mbo].commlinkid = 0;
 
index ea1d67e77b2c793bc4e4c91745faea6d0a39d8cc..910031044c9725d7dfe503a7694d40645a82bf19 100644 (file)
  *
  *  Native multichannel and wide scsi support added 
  *  by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ *
+ *  Added request_module("scsi_hostadapter") for kerneld:
+ *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
+ *  Bjorn Ekwall  <bj0rn@blox.se>
  */
 
 /*
@@ -26,6 +30,8 @@
  * symbol tables.
  */
 #define _SCSI_SYMS_VER_
+
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/system.h>
@@ -44,7 +50,9 @@
 #include "hosts.h"
 #include "constants.h"
 
-#include <linux/config.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 #undef USE_STATIC_SCSI_MEMORY
 
@@ -607,6 +615,15 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   if (SCpnt->result)
     return 0;     /* assume no peripheral if any sort of error */
 
+  /*
+   * Check the peripheral qualifier field - this tells us whether LUNS
+   * are supported here or not.
+   */
+  if( (scsi_result[0] >> 5) == 3 )
+    {
+      return 0;     /* assume no peripheral if any sort of error */
+    }
+
   /*
    * It would seem some TOSHIBA CDROM gets things wrong
    */
@@ -3058,6 +3075,10 @@ int scsi_register_module(int module_type, void * ptr)
        
        /* Load upper level device handler of some kind */
     case MODULE_SCSI_DEV:
+#ifdef CONFIG_KERNELD
+       if (scsi_hosts == NULL)
+               request_module("scsi_hostadapter");
+#endif
        return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
        /* The rest of these are not yet implemented */
        
index b17f5d8a5c06877f8694cef33bae2703fff1a712..91d68fc1c13ed2194c978f23da9caccbe29ae065 100644 (file)
@@ -1718,7 +1718,7 @@ printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %
  * 256 heads * 64 sectors. 
  */
 
-      if ((cylinders > 1024) || (sectors > 64)) 
+      if ((cylinders > 1024) || (sectors > 64)) {
        /* The Seagate's seem to have some mapping
         * Multiple heads * sectors * cyl to get capacity
         * Then start rounding down. */
@@ -1730,7 +1730,7 @@ printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %
        {
                heads *= 2;     /* For some reason, they go in multiples */
                cylinders = capacity / heads;
-       };
+       }
       }
       ip[0] = heads;
       ip[1] = sectors;
index b3fbe982a2b5396fb7ef41999e6a43aea7921997..a8ad2224dbdfa3fb11aac774ca42a58b4ffba465 100644 (file)
@@ -58,7 +58,8 @@ static int * sr_sizes;
 static int * sr_blocksizes;
 
 static int sr_open(struct inode *, struct file *);
-static void get_sectorsize(int);
+void get_sectorsize(int);
+void sr_photocd(struct inode *);
 
 extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
@@ -291,9 +292,10 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
 }
 
 /*
- * Here I tried to implement better support for PhotoCD's.
+ * Here I tried to implement support for multisession-CD's
  * 
- * Much of this has do be done with vendor-specific SCSI-commands.
+ * Much of this has do be done with vendor-specific SCSI-commands, becauce
+ * multisession is newer than the SCSI-II standard.
  * So I have to complete it step by step. Useful information is welcome.
  *
  * Actually works:
@@ -304,17 +306,17 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
  *              work now without running the program "set_density"
  *              Multisession CD's are supported too.
  *
- *   kraxel@cs.tu-berlin.de (Gerd Knorr)
+ *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
  */
 /*
  * 19950704 operator@melchior.cuivre.fdn.fr (Thomas Quinot)
  *
  *   - SONY:   Same as Nec.
  *
- *   - PIONEER: works with SONY code
+ *   - PIONEER: works with SONY code (may be others too ?)
  */
 
-static void sr_photocd(struct inode *inode)
+void sr_photocd(struct inode *inode)
 {
     unsigned long   sector,min,sec,frame;
     unsigned char   buf[40];    /* the buffer for the ioctl */
@@ -325,17 +327,17 @@ static void sr_photocd(struct inode *inode)
     
     if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
 #ifdef DEBUG
-       printk("sr_photocd: CDROM and/or the driver does not support multisession CD's");
+       printk(KERN_DEBUG "sr_photocd: CDROM and/or driver do not support multisession CD's");
 #endif
        return;
     }
     
     if (!suser()) {
-       /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed for me.
-        * That's why mpcd_sector will be initialized with zero, because I'm not
-        * able to get the right value. Necessary only if access_count is 1, else
-        * no disk change happened since the last call of this function and we can
-        * keep the old value.
+       /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed
+         * for me. That's why mpcd_sector will be initialized with zero,
+         * because I'm not able to get the right value. Necessary only if
+         * access_count is 1, else no disk change happened since the last
+         * call of this function and we can keep the old value.
         */
        if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
            scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
@@ -353,7 +355,7 @@ static void sr_photocd(struct inode *inode)
        
     case SCSI_MAN_NEC:
 #ifdef DEBUG
-       printk("sr_photocd: use NEC code\n");
+       printk(KERN_DEBUG "sr_photocd: use NEC code\n");
 #endif
        memset(buf,0,40);
        *((unsigned long*)buf)   = 0x0;   /* we send nothing...     */
@@ -364,11 +366,12 @@ static void sr_photocd(struct inode *inode)
        rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
                           SCSI_IOCTL_SEND_COMMAND, buf);
        if (rc != 0) {
-           printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
+            if (rc != 0x28000002) /* drop "not ready" */
+                printk(KERN_WARNING"sr_photocd: ioctl error (NEC): 0x%x\n",rc);
            break;
        }
        if (rec[14] != 0 && rec[14] != 0xb0) {
-           printk("sr_photocd: (NEC) Hmm, seems the CDROM doesn't support multisession CD's\n");
+           printk(KERN_INFO"sr_photocd: (NEC) Hmm, seems the CDROM doesn't support multisession CD's\n");
            no_multi = 1;
            break;
        }
@@ -379,14 +382,14 @@ static void sr_photocd(struct inode *inode)
        is_xa  = (rec[14] == 0xb0);
 #ifdef DEBUG
        if (sector) {
-           printk("sr_photocd: multisession CD detected. start: %lu\n",sector);
+           printk(KERN_DEBUG "sr_photocd: multisession CD detected. start: %lu\n",sector);
        }
 #endif
        break;
        
     case SCSI_MAN_TOSHIBA:
 #ifdef DEBUG
-       printk("sr_photocd: use TOSHIBA code\n");
+       printk(KERN_DEBUG "sr_photocd: use TOSHIBA code\n");
 #endif
        
        /* we request some disc information (is it a XA-CD ?,
@@ -402,16 +405,15 @@ static void sr_photocd(struct inode *inode)
            if (rc == 0x28000002) {
                /* Got a "not ready" - error. No chance to find out if this is
                 * because there is no CD in the drive or because the drive
-                * don't knows multisession CD's. So I need to do an extra check... */
-               if (kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                                     SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
-                   printk("sr_photocd: drive not ready\n");
-               } else {
-                   printk("sr_photocd: (TOSHIBA) Hmm, seems the CDROM doesn't support multisession CD's\n");
+                * don't knows multisession CD's. So I need to do an extra
+                 * check... */
+               if (!kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+                                      SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
+                   printk(KERN_INFO "sr_photocd: (TOSHIBA) Hmm, seems the CDROM doesn't support multisession CD's\n");
                    no_multi = 1;
                }
            } else
-               printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
+               printk(KERN_WARNING"sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
            break; /* if the first ioctl fails, we don't call the second one */
        }
        is_xa  = (rec[0] == 0x20);
@@ -422,7 +424,7 @@ static void sr_photocd(struct inode *inode)
        if (sector) {
            sector -= CD_BLOCK_OFFSET;
 #ifdef DEBUG
-           printk("sr_photocd: multisession CD detected: start: %lu\n",sector);
+           printk(KERN_DEBUG "sr_photocd: multisession CD detected: start: %lu\n",sector);
 #endif
        }
        
@@ -436,17 +438,17 @@ static void sr_photocd(struct inode *inode)
        rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
                               SCSI_IOCTL_SEND_COMMAND, buf);
        if (rc != 0) {
-           printk("sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
+           printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
            break;
        }
 #ifdef DEBUG
-       printk("sr_photocd: get_density: 0x%x\n",rec[4]);
+       printk(KERN_DEBUG "sr_photocd: get_density: 0x%x\n",rec[4]);
 #endif
        
        /* ...and only if necessary a set_density */
        if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
 #ifdef DEBUG
-           printk("sr_photocd: doing set_density\n");
+           printk(KERN_DEBUG "sr_photocd: doing set_density\n");
 #endif
            memset(buf,0,40);
            *((unsigned long*)buf)   = 12;  /* sending 12 bytes... */
@@ -454,16 +456,17 @@ static void sr_photocd(struct inode *inode)
            cmd[0] = 0x15;
            cmd[1] = (1 << 4);
            cmd[4] = 12;
-           send = &cmd[6];                 /* this is a 6-Byte command          */
-           send[ 3] = 0x08;                /* the data for the command          */
-           send[ 4] = (is_xa) ? 0x81 : 0;  /* density 0x81 for XA-CD's, 0 else  */
+           send = &cmd[6];                 /* this is a 6-Byte command    */
+           send[ 3] = 0x08;                /* the data for the command    */
+           send[ 4] = (is_xa) ? 0x81 : 0;  /* density 0x81 for XA, 0 else */
            send[10] = 0x08;
            rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
                                   SCSI_IOCTL_SEND_COMMAND, buf);
            if (rc != 0) {
-               printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
+               printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
            }
-           /* The set_density command may have changed the sector size or capacity. */
+           /* The set_density command may have changed the
+             * sector size or capacity. */
            scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
        }
        break;
@@ -471,7 +474,7 @@ static void sr_photocd(struct inode *inode)
     case SCSI_MAN_SONY: /* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
     case SCSI_MAN_PIONEER:
 #ifdef DEBUG
-       printk("sr_photocd: use SONY/PIONEER code\n");
+       printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER code\n");
 #endif
        memset(buf,0,40);
        *((unsigned long*)buf)   = 0x0;   /* we send nothing...     */
@@ -483,11 +486,12 @@ static void sr_photocd(struct inode *inode)
                               SCSI_IOCTL_SEND_COMMAND, buf);
        
        if (rc != 0) {
-           printk("sr_photocd: ioctl error (SONY): 0x%x\n",rc);
+            if (rc != 0x28000002) /* drop "not ready" */
+                printk(KERN_WARNING "sr_photocd: ioctl error (SONY): 0x%x\n",rc);
            break;
        }
        if ((rec[0] << 8) + rec[1] != 0x0a) {
-           printk("sr_photocd: (SONY) Hmm, seems the CDROM doesn't support multisession CD's\n");
+           printk(KERN_INFO "sr_photocd: (SONY) Hmm, seems the CDROM doesn't support multisession CD's\n");
            no_multi = 1;
            break;
        }
@@ -495,7 +499,7 @@ static void sr_photocd(struct inode *inode)
        is_xa = !!sector;
 #ifdef DEBUG
        if (sector)
-           printk ("sr_photocd: multisession CD detected. start: %lu\n",sector);
+           printk (KERN_DEBUG "sr_photocd: multisession CD detected. start: %lu\n",sector);
 #endif
        break;
                
@@ -972,7 +976,7 @@ static void sr_init_done (Scsi_Cmnd * SCpnt)
     }
 }
 
-static void get_sectorsize(int i){
+void get_sectorsize(int i){
     unsigned char cmd[10];
     unsigned char *buffer;
     int the_result, retries;
index 44b31ced64453c750acf938a38e94b2bad486b23..6106fc9343a14e7df1d7a8d500ebbdc7f2cdf66a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/fs.h>
 #include <asm/segment.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 
 #include <linux/blk.h>
 #include "scsi.h"
@@ -13,6 +14,9 @@
 
 #include <linux/cdrom.h>
 
+extern void get_sectorsize(int);
+extern void sr_photocd(struct inode *);
+
 #define IOCTL_RETRIES 3
 /* The CDROM is fairly slow, so we need a little extra time */
 /* In fact, it is very slow if it has to spin up first */
@@ -203,7 +207,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
        char * buffer;
        
        sr_cmd[0] = SCMD_READ_TOC;
-       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
        sr_cmd[6] = 0;
        sr_cmd[7] = 0;              /* MSB of length (12) */
@@ -231,7 +235,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
     case CDROMREADTOCENTRY:
     {
        struct cdrom_tocentry tocentry;
-       char * buffer;
+       unsigned char * buffer;
        
         err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
         if (err) return err;
@@ -239,7 +243,8 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
        memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
        
        sr_cmd[0] = SCMD_READ_TOC;
-       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
+          (tocentry.cdte_format == CDROM_MSF ? 0x02 : 0);
        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
        sr_cmd[6] = tocentry.cdte_track;
        sr_cmd[7] = 0;             /* MSB of length (12)  */
@@ -251,14 +256,17 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
        
        result = do_ioctl (target, sr_cmd, buffer, 12);
        
+        tocentry.cdte_ctrl = buffer[5] & 0xf;  
+        tocentry.cdte_adr = buffer[5] >> 4;
+        tocentry.cdte_datamode = (tocentry.cdte_ctrl & 0x04) ? 1 : 0;
        if (tocentry.cdte_format == CDROM_MSF) {
            tocentry.cdte_addr.msf.minute = buffer[9];
            tocentry.cdte_addr.msf.second = buffer[10];
            tocentry.cdte_addr.msf.frame = buffer[11];
-           tocentry.cdte_ctrl = buffer[5] & 0xf;
        }
        else
-           tocentry.cdte_addr.lba = (int) buffer[0];
+           tocentry.cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+                                       + buffer[10]) << 8) + buffer[11];
        
        scsi_free(buffer, 512);
        
@@ -288,6 +296,25 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
        result = do_ioctl(target, sr_cmd, NULL, 255);
        return result;
        
+    case CDROMCLOSETRAY:
+       sr_cmd[0] = START_STOP;
+       sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5);
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+       sr_cmd[4] = 0x03;
+       
+        if ((result = do_ioctl(target, sr_cmd, NULL, 255)))
+          return result;
+
+        /* Gather information about newly inserted disc */
+        check_disk_change (inode->i_rdev);
+        sr_ioctl (inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+        sr_photocd (inode);
+
+        if (scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
+          get_sectorsize (MINOR(inode->i_rdev));
+
+        return 0;
+
     case CDROMEJECT:
         /*
          * Allow 0 for access count for auto-eject feature.
@@ -458,6 +485,38 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
        return result;
     }
        
+    case CDROM_GET_UPC:
+    {
+       struct cdrom_mcn mcn;
+       char * buffer;
+       
+       sr_cmd[0] = SCMD_READ_SUBCHANNEL;
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
+       sr_cmd[2] = 0x40;    /* I do want the subchannel info */
+       sr_cmd[3] = 0x02;    /* Give me medium catalog number info */
+       sr_cmd[4] = sr_cmd[5] = 0;
+       sr_cmd[6] = 0;
+       sr_cmd[7] = 0;
+       sr_cmd[8] = 24;
+       sr_cmd[9] = 0;
+       
+       buffer = (unsigned char*) scsi_malloc(512);
+       if(!buffer) return -ENOMEM;
+       
+       result = do_ioctl(target, sr_cmd, buffer, 24);
+       
+       memcpy (mcn.medium_catalog_number, buffer + 9, 13);
+        mcn.medium_catalog_number[13] = 0;
+
+       scsi_free(buffer, 512);
+       
+       err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_mcn));
+       if (err)
+           return err;
+       memcpy_tofs ((void *) arg, &mcn, sizeof (struct cdrom_mcn));
+       return result;
+    }
+       
     case CDROMREADMODE2:
        return -EINVAL;
     case CDROMREADMODE1:
diff --git a/drivers/sound/.version.orig b/drivers/sound/.version.orig
deleted file mode 100644 (file)
index 5caf251..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-3.5.1
-0x030500
index cba918d850ab08740b1e3bb9a990e29631c68215..29dd1efece243b16ed21e5c8c376016b95beb183 100644 (file)
@@ -16,8 +16,9 @@ http://personal.eunet.fi/pp/voxware for latest news. Please don't
 mail me and ask about these cards. The unsupported cards are:
 
        - All PnP soundcards (SB PnP, GUS PnP, Soundscape PnP etc.)
-               (SB PnP in first 3.6-alpha version (Apr?), GUS PnP bit later,
-               Soundscape PnP propably much later, others ???).
+               (SB PnP in first 3.6-alpha version (Apr 96?), GUS PnP bit later,
+               Soundscape PnP propably much later, others ???). See
+               "Configuring PnP soundcards" below for some hints.
        - Mwave soundcards and motherboards
                (Version 3.6 or 3.7. Depends on how fast I get a Mwave
                card and suitable documents for it).
@@ -37,6 +38,59 @@ mail me and ask about these cards. The unsupported cards are:
        - Yamaha OPL4 (on cards having _RAM_ for samples)
                (Late 96?. Works as OPL3 with current driver versions)
 
+How to use sound without recompiling kernel and/or sound driver
+---------------------------------------------------------------
+
+There is commercial sound driver which should be released during Apr 96.
+It comes in precompiled form and doesn't require recompiling of kernel. See
+http://www.4Front-tech.com/uss.html for more info.
+
+Configuring PnP cards
+---------------------
+
+New versions of most soundcards use so called ISA PnP protocol for
+soft configuring their I/O, IRQ, DMA and shared memory resources.
+Currently at least cards made by Creative Technology (SB32 and SB32AWE
+PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and
+Aztech (some Sound Galazy models) use PnP technology. The CS4232 audio
+chip by Crystal Semiconductor (Intel Atlantis, HP Pavillon and many other
+motherboards) is also based on PnP technology but there is a "native" driver
+available for it (see information about CS4232 later in this document).
+
+PnP soundcards (as well as most other PnP ISA cards) are not supported
+by version 3.5 of this driver (Linux 1.3.xx and Linux 2.0.x). Proper
+support for them should be released during spring 96 
+(see http://personal.eunet.fi/pp/voxware for latest info).
+
+There is a method to get most of the PnP cards to work. The basic method
+is the following:
+
+1) Boot DOS so that card's DOS drivers have chance to initialize the
+card.
+2) _Cold_ boot to Linux by using "loadlin.exe". Hitting ctrl-alt-del
+works with older machines but causes hard reset of all cards on latest
+(Pentium) machines.
+3) If you have sound driver in Linux configured properly, the card should work
+now. "Proper" means here that I/O, IRQ and DMA settings are the same than in
+DOS. The hard part is to find which settings were used. See documentation of
+your card for more info.
+
+Windows 95 could work as well as DOS but running loadlin may be somehow 
+difficult. Propably you should "shut down" your machine to MS-DOS mode
+before running it.
+
+Some machines have BIOS utility for setting PnP resources. This is a good
+way to configure some cards. In this case you don't need to boot DOS/Win95
+prior starting Linux.
+Another way to initialize PnP cards without DOS/Win95 is a Linux based
+PnP isolation tool. When writing this there is a pre alpha test version
+of such tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The
+file is called isapnptools-*. Please note that this tool is just a temporary
+solution which may be incompatible with future kernel versions having proper
+support for PnP cards.
+These two methods don't work with GUS PnP which requires some additional
+initialization (cards DOS/Win95 driver does it). 
+
 Read this before trying to configure the driver
 -----------------------------------------------
 
@@ -805,8 +859,8 @@ models are based on the MAD16 chip which is supported by the driver.
 Audio Excel DSP16
 -----------------
 
-See comments in aedsp16.c.
-
+Support for this card is currently not functional. A new driver for it
+should be available later this year.
 
 PCMCIA cards
 ------------
@@ -836,8 +890,10 @@ Cards not supported yet
 
 First of all. There is an easy way to make most soundcards to work
 with Linux. Just use the DOS based driver to initialize the card
-to a _known_ state. Then ctrl-alt-del to Linux. If Linux is configured
+to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured
 to use the sama I/O, IRQ and DMA numbers than DOS, the card could work.
+(ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with
+new motherboards). This method works also with all/most PnP soundcards.
 
 Don't get fooled with SB compatibility. Most cards are compatible with
 SB but that may require a TSR which is not possible with Linux. If
@@ -852,9 +908,9 @@ required in maintaining the driver (some changes need to be done
 to all low level drivers and be tested too, maybe with multiple
 operating systems). For this reason I have made a desicion to not support
 obsolete cards. It's possible that someone else makes a separately 
-distributed driver (diffs) for the card. Version v4.0 will be much more
+distributed driver (diffs) for the card. Version v3.6 will be much more
 modular so making separately distributed drivers will be easier with it.
-(The bad news is that v4.0 will not be available before late -96).
+(The bad news is that v3.6 will not be available before summer -96).
 
 Writing a driver for a new card is not possible if there are no 
 programming information available about the card. If you don't
@@ -864,42 +920,24 @@ manufacturer of the card and ask if they have (or are willing to)
 released technical details of the card. Do this before contacting me. I
 can only answer 'no' if there are no programming information available.
 
-Some companies don't give low level technical information about their
-products to public or at least their require signing a NDA.
-
-I have also made decicion to not accept code based on reverse engineering
+I have made decicion to not accept code based on reverse engineering
 to the driver. There are three main reasons: First I don't want to break
 relationships to sound card manufacturers. The second reason is that
-maintaining and supporting a driver withoun any specs will be a pain. The
-third reason is that why shoud we help such companies in selling their
-products to Linux users when they don't want to sell to Linux users
-at all?
-
-Unfortunately many of the leading soundcard manufacturers are not willing
-to co-operate with Linux/Unix community. For example: Creative Technology 
-doesn't give information about the ASP chip and the Emu synth chip of AWE32
-and SB32. Turtle Beach don't give information about any of their
-products. MediaVision requires NDA before they are willing to
-give information about the Jazz16 chip (fortunately Logitech gave
-the info about SM Wave).
-
-So at least the above three companies are out until they are willing to 
-release documentation about their products (the situation is the
-same with many DOS based freeware/shareware games and utilities). If
-you want to use Linux/Unix with their cards, please don't try to push
-me. It's a better idea to contact the manufacturer and explain that
-you want to use your card with Linux/Unix. You could also try to sell
-your card to somebody else and then buy a card that is supported by the driver.
-
-However it's possible that things change and a driver gets written
-for some of the banned cards. Please, don't send me messages asking if
-there is any plans to write a driver for the cards mentioned above. I 
-will put any news to sound driver's www home page (see below).
+maintaining and supporting a driver withoun any specs will be a pain.
+The third reason is that companies have freedom to refuse selling their
+products to other than Windows useres.
+
+Some companies don't give low level technical information about their
+products to public or at least their require signing a NDA. It's not
+possible to implement a freeware driver for them. However it's possible
+that support for such cards become available in the commercial version
+of this driver (see http://www.4Front-tech.com/uss.html for more info).
 
 There are some common audio chipsets that are not supported yet. For example
 Sierra Aria and IBM Mwave. It's possible that these architectures
 get some support in future but I can't make any promises. Just look
-at the home page for latest info.
+at the home page (http://personal.eunet.fi/pp/voxware/new_cards.html)
+for latest info.
 
 Information about unsupported soundcards and chipsets is welcome as well
 as free copies of soundcards, SDKs and operating systems.
@@ -909,4 +947,5 @@ If you have any corrections and/or comments, please contact me.
 Hannu Savolainen
 hannu@voxware.pp.fi
 Sound driver's www home page: http://personal.eunet.fi/pp/voxware
+                   US mirror: http://www.4Front-Tech.com/usslite
 
index 56dafb9a09506930d5b7bed53a4a34c445b20783..3746059a55e31468b153b3a85990bea1c02b8345 100644 (file)
@@ -502,7 +502,7 @@ int fat_notify_change(struct inode * inode,struct iattr * attr)
 
        error = inode_change_ok(inode, attr);
        if (error)
-               return error;
+               return MSDOS_SB(inode->i_sb)->options.quiet ? 0 : error;
 
        if (((attr->ia_valid & ATTR_UID) && 
             (attr->ia_uid != MSDOS_SB(inode->i_sb)->options.fs_uid)) ||
index e72b6f889aa2b2e10e92aecf0ff2d8977703c1b9..a7612d20c0d5ff8f10248020bdb71a646366dd82 100644 (file)
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := nfs.o
-O_OBJS   := proc.o sock.o rpcsock.o inode.o file.o dir.o symlink.o
+O_OBJS   := proc.o sock.o rpcsock.o inode.o file.o bio.o \
+           nfsiod.o dir.o symlink.o
 
 ifdef CONFIG_ROOT_NFS
 O_OBJS += nfsroot.o
diff --git a/fs/nfs/README b/fs/nfs/README
new file mode 100644 (file)
index 0000000..f2c1053
--- /dev/null
@@ -0,0 +1,114 @@
+
+
+    This is an NFS client for Linux that supports async RPC calls for
+    read-ahead (and hopefully soon, write-back) on regular files. 
+
+    The implementation uses a straightforward nfsiod scheme.  After
+    trying out a number of different concepts, I finally got back to
+    this concept, because everything else either didn't work or gave me
+    headaches. It's not flashy, but it works without hacking into any
+    other regions of the kernel.
+
+
+    HOW TO USE
+
+    This stuff compiles as a loadable module (I developed it on 1.3.77).
+    Simply type mkmodule, and insmod nfs.o. This will start for nfsiod's
+    at the same time (which will show up under the pesudonym of insmod in
+    ps-style listings).
+
+    Alternatively, you can put it right into the kernel: remove everything
+    from fs/nfs, move the Makefile and all *.c to this directory, and
+    copy all *.h files to include/linux.
+
+    After mounting, you should be able to watch (with tcpdump) several
+    RPC READ calls being placed simultaneously.
+
+
+    HOW IT WORKS
+
+    When a process reads from a file on an NFS volume, the following
+    happens:
+
+     * nfs_file_read sets file->f_reada if more than 1K is
+       read at once. It then calls generic_file_read.
+
+     * generic_file_read requests one ore more pages via
+       nfs_readpage.
+
+     * nfs_readpage allocates a request slot with an nfsiod
+       daemon, fills in the READ request, sends out the
+       RPC call, kicks the daemon, and returns.
+       If there's no free biod, nfs_readpage places the
+       call directly, waiting for the reply (sync readpage).
+
+     * nfsiod calls nfs_rpc_doio to collect the reply. If the
+       call was successful, it sets page->uptodate and
+       wakes up all processes waiting on page->wait;
+
+    This is the rough outline only. There are a few things to note:
+
+     * Async RPC will not be tried when server->rsize < PAGE_SIZE.
+
+     * When an error occurs, nfsiod has no way of returning
+       the error code to the user process. Theerefore, it flags
+       page->error and wakes up all processes waiting on that
+       page (they usually do so from withing generic_readpage).
+
+       generic_readpage finds that the page is still not
+       uptodate, and calls nfs_readpage again. This time around,
+       nfs_readpage notices that page->error is set and
+       unconditionally does a synchronous RPC call.
+
+       This area needs a lot of improvement, since read errors
+       are not that uncommon (e.g. we have to retransmit calls
+       if the fsuid is different from the ruid in order to
+       cope with root squashing and stuff like this).
+
+       Retransmits with fsuid/ruid change should be handled by
+       nfsiod, but this doesn't come easily (a more general nfs_call
+       routine that does all this may be useful...)
+
+     * To save some time on readaheads, we save one data copy
+       by frobbing the page into the iovec passed to the
+       RPC code so that the networking layer copies the
+       data into the page directly.
+
+       This needs to be adjustable (different authentication
+       flavors; AUTH_NULL versus AUTH_SHORT verifiers).
+
+     * Currently, a fixed number of nfsiod's is spawned from
+       within init_nfs_fs. This is problematic when running
+       as a loadable module, because this will keep insmod's
+       memory allocated. As a side-effect, you will see the
+       nfsiod processes listed as several insmod's when doing
+       a `ps.'
+
+     *         This NFS client implements server congestion control via
+       Van Jacobson slow start as implemented in 44BSD. I haven't
+       checked how well this behaves, but since Rick Macklem did
+       it this way, it should be okay :-)
+
+
+    WISH LIST
+
+    After giving this thing some testing, I'd like to add some more
+    features:
+
+     * Some sort of async write handling. True write-back doesn't
+       work with the current kernel (I think), because invalidate_pages
+       kills all pages, regardless of whether they're dirty or not.
+       Besides, this may require special bdflush treatment because
+       write caching on clients is really hairy.
+
+       Alternatively, a write-through scheme might be useful where
+       the client enqueues the request, but leaves collecting the
+       results to nfsiod. Again, we need a way to pass RPC errors
+       back to the application.
+
+     * Support for different authentication flavors.
+
+     * /proc/net/nfsclnt (for nfsstat, etc.).
+
+March 29, 1996
+Olaf Kirch <okir@monad.swb.de>
diff --git a/fs/nfs/bio.c b/fs/nfs/bio.c
new file mode 100644 (file)
index 0000000..d46b034
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * linux/fs/nfs/bio.c
+ *
+ * Block I/O for NFS
+ *
+ * Partial copy of Linus' read cache modifications to fs/nfs/file.c
+ * modified for async RPC by okir@monad.swb.de
+ *
+ * We do an ugly hack here in order to return proper error codes to the
+ * user program when a read request failed. This is a huge problem because
+ * generic_file_read only checks the return value of inode->i_op->readpage()
+ * which is usually 0 for async RPC. To overcome this obstacle, we set
+ * the error bit of the page to 1 when an error occurs, and make nfs_readpage
+ * transmit requests synchronously when encountering this.
+ *
+ * Another possible solution to this problem may be to have a cache of recent
+ * RPC call results indexed by page pointer, or even a result code field
+ * in struct page.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfsiod.h>
+#include <linux/malloc.h>
+#include <linux/pagemap.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#undef DEBUG_BIO
+#ifdef DEBUG_BIO
+#define dprintk(args...)       printk(## args)
+#else
+#define dprintk(args...)       /* nothing */
+#endif
+
+static inline int
+do_read_nfs_sync(struct inode * inode, struct page * page)
+{
+       struct nfs_fattr fattr;
+       int             result, refresh = 0;
+       int             count = PAGE_SIZE;
+       int             rsize = NFS_SERVER(inode)->rsize;
+       char            *buf = (char *) page_address(page);
+       unsigned long   pos = page->offset;
+
+       dprintk("NFS: do_read_nfs_sync(%p)\n", page);
+
+       page->locked = 1;
+       page->error = 0;
+
+       do {
+               if (count < rsize)
+                       rsize = count;
+               result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
+                       pos, rsize, buf, &fattr);
+               dprintk("nfs_proc_read(%s, (%x,%lx), %ld, %d, %p) = %d\n",
+                               NFS_SERVER(inode)->hostname,
+                               inode->i_dev, inode->i_ino,
+                               pos, rsize, buf, result);
+               if (result < 0)
+                       break;
+               refresh = 1;
+               count -= result;
+               pos += result;
+               buf += result;
+               if (result < rsize)
+                       break;
+       } while (count);
+
+       memset(buf, 0, count);
+       if (refresh) {
+               nfs_refresh_inode(inode, &fattr);
+               result = 0;
+               page->uptodate = 1;
+       }
+       page->locked = 0;
+       wake_up(&page->wait);
+       return result;
+}
+
+/*
+ * This is the callback from nfsiod telling us whether a reply was
+ * received or some error occurred (timeout or socket shutdown).
+ */
+static void
+nfs_read_cb(int result, struct nfsiod_req *req)
+{
+       struct page     *page = (struct page *) req->rq_cdata;
+       static int      succ = 0, fail = 0;
+
+       dprintk("BIO: received callback for page %p, result %d\n",
+                       page, result);
+
+       if (result >= 0
+        && (result = nfs_proc_read_reply(&req->rq_rpcreq)) >= 0) {
+               succ++;
+               page->uptodate = 1;
+       } else {
+               fail++;
+               printk("BIO: %d successful reads, %d failures\n", succ, fail);
+               page->error = 1;
+       }
+       page->locked = 0;
+       wake_up(&page->wait);
+       free_page(page_address(page));
+}
+
+static inline int
+do_read_nfs_async(struct inode *inode, struct page *page)
+{
+       struct nfsiod_req *req;
+       int             result = -1;    /* totally arbitrary */
+
+       dprintk("NFS: do_read_nfs_async(%p)\n", page);
+
+       page->locked = 1;
+       page->error = 0;
+
+       if (!(req = nfsiod_reserve(NFS_SERVER(inode), nfs_read_cb)))
+               goto done;
+       result = nfs_proc_read_request(&req->rq_rpcreq,
+                       NFS_SERVER(inode), NFS_FH(inode),
+                       page->offset, PAGE_SIZE, 
+                       (__u32 *) page_address(page));
+       if (result >= 0) {
+               req->rq_cdata = page;
+               page->count++;
+               result = nfsiod_enqueue(req);
+               if (result >= 0)
+                       dprintk("NFS: enqueued async READ request.\n");
+       }
+       if (result < 0) {
+               dprintk("NFS: deferring async READ request.\n");
+               nfsiod_release(req);
+               page->locked = 0;
+               wake_up(&page->wait);
+       }
+
+done:
+       return result < 0? result : 0;
+}
+
+int
+nfs_readpage(struct inode *inode, struct page *page)
+{
+       unsigned long   address;
+       int             error = -1;
+
+       dprintk("NFS: nfs_readpage %08lx\n", page_address(page));
+       address = page_address(page);
+       page->count++;
+       if (!page->error && NFS_SERVER(inode)->rsize >= PAGE_SIZE)
+               error = do_read_nfs_async(inode, page);
+       if (error < 0)          /* couldn't enqueue */
+               error = do_read_nfs_sync(inode, page);
+       free_page(address);
+       return error;
+}
diff --git a/fs/nfs/cache.c b/fs/nfs/cache.c
deleted file mode 100644 (file)
index 29a5899..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-
-void nfs_bl_cache_invalidate(nfs_cache *nh)
-{
-       unsigned long flags;
-       save_flags(flags);
-       cli();
-       if(nh->inuse)
-               nh->dead=1;
-       else
-       {
-               kfree_s(nh->data);
-               nh->data=NULL;
-               nh->free=1;
-       }
-       restore_flags(flags);
-}
-
-void nfs_bl_cache_revalidate(nfs_cache *nh, struct fattr fa)
-{
-       nh->fattr=fattr;
-       nh->time=jiffies;
-}
-
-/*
- *     Find a block in the cache. We know the cache is block sized in block
- *     aligned space.
- */
-nfs_cache *nfs_cache_find(struct inode *inode, off_t pos)
-{
-       nfs_cache *nh=&nfs_cache_slot[0];
-       nfs_cache *ffree=NULL;
-       struct nfs_fattr fattr;
-       int ct=0;
-       while(ct<NH_CACHE_SIZE)
-       {
-               if(nh->inode_num==inode->i_no && !nh->dead&&!nh->free&&nh->file_pos==pos)
-               {
-                       if(abs(jiffies-nh->time)<EXPIRE_CACHE)
-                               return nh;
-                       /*
-                        *      Revalidate
-                        */
-                       
-                       if(nfs_proc_getattr(NFS_SERVER(inode), NFS_FH(inode), &fattr))
-                       {
-                               nfs_bl_cache_invalidate(nh);
-                               continue;       /* get attr failed */
-                       }
-                       if(nh->fattr.modified!=fattr.modified)
-                       {
-                               nfs_bl_cache_invalidate(nh);
-                               continue;       /* cache is out of date */
-                       }
-                       nfs_refresh_inode(inode, fattr);
-                       nh->fattr=fattr;
-                       nfs_bl_cache_revalidate(nh);
-                       return nh;
-               }
-               if(nh->free)
-                       ffree=nh;
-       }
-       return ffree;
-}      
index 818c8125ff7b14317da6d6a7334818f274a8601d..75012de1837bcb03f919bd02769b60e8393fadb9 100644 (file)
@@ -33,7 +33,6 @@ static int nfs_file_mmap(struct inode *, struct file *, struct vm_area_struct *)
 static int nfs_file_read(struct inode *, struct file *, char *, int);
 static int nfs_file_write(struct inode *, struct file *, const char *, int);
 static int nfs_fsync(struct inode *, struct file *);
-static int nfs_readpage(struct inode * inode, struct page * page);
 
 static struct file_operations nfs_file_operations = {
        NULL,                   /* lseek - default */
@@ -103,53 +102,6 @@ static int nfs_fsync(struct inode *inode, struct file *file)
        return 0;
 }
 
-static inline int do_read_nfs(struct inode * inode, struct page * page,
-       char * buf, unsigned long pos)
-{
-       int result, refresh = 0;
-       int count = PAGE_SIZE;
-       int rsize = NFS_SERVER(inode)->rsize;
-       struct nfs_fattr fattr;
-
-       page->locked = 1;
-       do {
-               if (count < rsize)
-                       rsize = count;
-               result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
-                       pos, rsize, buf, &fattr);
-               if (result < 0)
-                       break;
-               refresh = 1;
-               count -= result;
-               pos += result;
-               buf += result;
-               if (result < rsize)
-                       break;
-       } while (count);
-
-       memset(buf, 0, count);
-       if (refresh) {
-               nfs_refresh_inode(inode, &fattr);
-               result = 0;
-               page->uptodate = 1;
-       }
-       page->locked = 0;
-       wake_up(&page->wait);
-       return result;
-}
-
-static int nfs_readpage(struct inode * inode, struct page * page)
-{
-       int error;
-       unsigned long address;
-
-       address = page_address(page);
-       page->count++;
-       error = do_read_nfs(inode, page, (char *) address, page->offset);
-       free_page(address);
-       return error;
-}
-
 static int nfs_file_write(struct inode *inode, struct file *file, const char *buf,
                          int count)
 {
index 9996f1a9af7492f4b15e4f231a8030aecc37d71b..f709ffd48819163aa6e272b4cf99a99ca69b15a3 100644 (file)
 
 #include <linux/sched.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfsiod.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
+#include <linux/smp.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
 
+/* This is for kernel_thread */
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
 extern int close_fp(struct file *filp);
 
 static int nfs_notify_change(struct inode *, struct iattr *);
@@ -307,8 +313,39 @@ static struct file_system_type nfs_fs_type = {
        nfs_read_super, "nfs", 0, NULL
 };
 
+/*
+ * Start up an nfsiod process. This is an awful hack, because when running
+ * as a module, we will keep insmod's memory. Besides, the current->comm
+ * hack won't work in this case
+ * The best would be to have a syscall for nfs client control that (among
+ * other things) forks biod's.
+ * Alternatively, we might want to have the idle task spawn biod's on demand.
+ */
+static int run_nfsiod(void *dummy)
+{
+       int     ret;
+
+#ifdef __SMP__
+       lock_kernel();
+       syscall_count++;
+#endif
+
+       MOD_INC_USE_COUNT;
+       current->session = 1;
+       current->pgrp = 1;
+       sprintf(current->comm, "nfsiod");
+       ret = nfsiod();
+       MOD_DEC_USE_COUNT;
+       return ret;
+}
+
 int init_nfs_fs(void)
 {
+       /* Fork four biod's */
+       kernel_thread(run_nfsiod, NULL, 0);
+       kernel_thread(run_nfsiod, NULL, 0);
+       kernel_thread(run_nfsiod, NULL, 0);
+       kernel_thread(run_nfsiod, NULL, 0);
         return register_filesystem(&nfs_fs_type);
 }
 
diff --git a/fs/nfs/nfsiod.c b/fs/nfs/nfsiod.c
new file mode 100644 (file)
index 0000000..4d8795f
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * linux/fs/nfs/nfsiod.c
+ *
+ * Async NFS RPC call support.
+ *
+ * When a process wants to place an asynchronous RPC call, it reserves
+ * an nfsiod slot, fills in all necessary fields including the callback
+ * handler field, and enqueues the request.
+ *
+ * This will wake up nfsiod, which calls nfs_rpc_doio to collect the
+ * reply. It then dispatches the result to the caller via the callback
+ * function, including result value and request pointer. It then re-inserts
+ * itself into the free list.
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/sched.h>
+#include <linux/nfs_fs.h>
+#include <linux/errno.h>
+#include <linux/rpcsock.h>
+#include <linux/nfsiod.h>
+
+static struct nfsiod_req *     free_list = NULL;
+static int                     active = 0;
+
+#undef DEBUG_NFSIOD
+#ifdef DEBUG_NFSIOD
+#define dprintk(args...)       printk(## args)
+#else
+#define dprintk(args...)       /* nothing */
+#endif
+
+
+/*
+ * Reserve an nfsiod slot and initialize the request struct
+ */
+struct nfsiod_req *
+nfsiod_reserve(struct nfs_server *server, nfsiod_done_fn_t callback)
+{
+       struct nfsiod_req       *req;
+
+       if (!(req = free_list)) {
+               dprintk("BIO: nfsiod_reserve: no free nfsiods\n");
+               return NULL;
+       }
+       free_list = req->rq_next;
+       memset(&req->rq_rpcreq, 0, sizeof(struct rpc_ioreq));
+
+       if (rpc_reserve(server->rsock, &req->rq_rpcreq, 1) < 0) {
+               dprintk("BIO: nfsiod_reserve failed to reserve RPC slot\n");
+               req->rq_next = free_list;
+               free_list = req;
+               return NULL;
+       }
+
+       req->rq_server = server;
+       req->rq_callback = callback;
+
+       return req;
+}
+
+void
+nfsiod_release(struct nfsiod_req *req)
+{
+       dprintk("BIO: nfsiod_release called\n");
+       rpc_release(req->rq_server->rsock, &req->rq_rpcreq);
+       memset(&req->rq_rpcreq, 0, sizeof(struct rpc_ioreq));
+       req->rq_next = free_list;
+       free_list = req;
+}
+
+/*
+ * Transmit a request and put it on nfsiod's list of pending requests.
+ */
+int
+nfsiod_enqueue(struct nfsiod_req *req)
+{
+       int     result;
+
+       dprintk("BIO: enqueuing request %p\n", &req->rq_rpcreq);
+       result = rpc_transmit(req->rq_server->rsock, &req->rq_rpcreq);
+       if (result < 0) {
+               dprintk("BIO: rpc_transmit returned %d\n", result);
+       } else {
+               dprintk("BIO: waking up nfsiod (%p)\n", req->rq_wait);
+               wake_up(&req->rq_wait);
+               schedule();
+       }
+       return result;
+}
+
+/*
+ * This is the main nfsiod loop.
+ */
+int
+nfsiod(void)
+{
+       struct nfsiod_req       request, *req = &request;
+       int                     result;
+
+       dprintk("BIO: nfsiod %d starting\n", current->pid);
+       while (1) {
+               /* Insert request into free list */
+               memset(req, 0, sizeof(*req));
+               req->rq_next = free_list;
+               free_list = req;
+
+               /* Wait until user enqueues request */
+               dprintk("BIO: before: now %d nfsiod's active\n", active);
+               dprintk("BIO: nfsiod %d waiting\n", current->pid);
+               interruptible_sleep_on(&req->rq_wait);
+
+               if (current->signal & ~current->blocked)
+                       break;
+               if (!req->rq_rpcreq.rq_slot)
+                       continue;
+               dprintk("BIO: nfsiod %d woken up; calling nfs_rpc_doio.\n",
+                               current->pid);
+               active++;
+               dprintk("BIO: before: now %d nfsiod's active\n", active);
+               result = nfs_rpc_doio(req->rq_server, &req->rq_rpcreq, 1);
+               req->rq_callback(result, req);
+               active--;
+       }
+
+       return 0;
+}
index 802028d5a88a800ea5624a2d65a6a3cb67308829..8790e48a4ccc7857f54346d52e15a9ed894ed40e 100644 (file)
  *                             Linus so that I don' always have to cleanup
  *                             _afterwards_ - thanks)
  *     Gero Kuhlmann   :       Last changes of Martin Mares undone.
+ *     Gero Kuhlmann   :       RARP replies are tested for specified server
+ *                             again. However, it's now possible to have
+ *                             different RARP and NFS servers.
+ *     Gero Kuhlmann   :       "0.0.0.0" addresses from command line are
+ *                             now mapped to INADDR_NONE.
  *
  */
 
@@ -116,6 +121,7 @@ static int bootp_flag;                      /* User said: Use BOOTP! */
 static int rarp_flag;                  /* User said: Use RARP! */
 static int bootp_dev_count = 0;                /* Number of devices allowing BOOTP */
 static int rarp_dev_count = 0;         /* Number of devices allowing RARP */
+static struct sockaddr_in rarp_serv;   /* IP address of RARP server */
 
 #if defined(CONFIG_RNFS_BOOTP) || defined(CONFIG_RNFS_RARP)
 #define CONFIG_RNFS_DYNAMIC            /* Enable dynamic IP config */
@@ -312,8 +318,8 @@ static int root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet
        }
        /* Discard packets which are not from specified server. */
        if (rarp_flag && !bootp_flag &&
-           server.sin_addr.s_addr != INADDR_NONE &&
-           server.sin_addr.s_addr != sip) {
+           rarp_serv.sin_addr.s_addr != INADDR_NONE &&
+           rarp_serv.sin_addr.s_addr != sip) {
                kfree_skb(skb, FREE_READ);
                return 0;
        }
@@ -1167,9 +1173,9 @@ static void root_nfs_addrs(char *addrs)
        int num = 0;
 
        /* Clear all addresses and strings */
-       myaddr.sin_family = server.sin_family =
+       myaddr.sin_family = server.sin_family = rarp_serv.sin_family =
            gateway.sin_family = netmask.sin_family = AF_INET;
-       myaddr.sin_addr.s_addr = server.sin_addr.s_addr =
+       myaddr.sin_addr.s_addr = server.sin_addr.s_addr = rarp_serv.sin_addr.s_addr =
            gateway.sin_addr.s_addr = netmask.sin_addr.s_addr = INADDR_NONE;
        system_utsname.nodename[0] = '\0';
        system_utsname.domainname[0] = '\0';
@@ -1199,16 +1205,20 @@ static void root_nfs_addrs(char *addrs)
 #endif
                        switch (num) {
                        case 0:
-                               myaddr.sin_addr.s_addr = in_aton(ip);
+                               if ((myaddr.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
+                                       myaddr.sin_addr.s_addr = INADDR_NONE;
                                break;
                        case 1:
-                               server.sin_addr.s_addr = in_aton(ip);
+                               if ((server.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
+                                       server.sin_addr.s_addr = INADDR_NONE;
                                break;
                        case 2:
-                               gateway.sin_addr.s_addr = in_aton(ip);
+                               if ((gateway.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
+                                       gateway.sin_addr.s_addr = INADDR_NONE;
                                break;
                        case 3:
-                               netmask.sin_addr.s_addr = in_aton(ip);
+                               if ((netmask.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
+                                       netmask.sin_addr.s_addr = INADDR_NONE;
                                break;
                        case 4:
                                if ((dp = strchr(ip, '.'))) {
@@ -1238,6 +1248,7 @@ static void root_nfs_addrs(char *addrs)
                ip = cp;
                num++;
        }
+       rarp_serv = server;
 }
 
 
index 339b3d6e52cfd0030ab7aef437d7ec8e5adc106c..411d1e668ebde597a100bb97ab6ad21651b9cf35 100644 (file)
@@ -29,7 +29,7 @@
  * filesystem and type 'ls xyzzy' to turn on debugging.
  */
 
-#if 0
+#if 1
 #define NFS_PROC_DEBUG
 #endif
 
@@ -416,6 +416,80 @@ retry:
        return status;
 }
 
+int
+nfs_proc_read_request(struct rpc_ioreq *req, struct nfs_server *server,
+                       struct nfs_fh *fh, unsigned long offset,
+                       unsigned long count, __u32 *buf)
+{
+       __u32   *p, *p0;
+       int     len;
+
+       PRINTK("NFS reqst read %ld @ %ld\n", count, offset);
+       if (!(p0 = nfs_rpc_alloc(NFS_SLACK_SPACE)))
+               return -EIO;
+
+       p = nfs_rpc_header(p0, NFSPROC_READ, 0);
+       p = xdr_encode_fhandle(p, fh);
+       *p++ = htonl(offset);
+       *p++ = htonl(count);
+       *p++ = htonl(count); /* traditional, could be any value */
+       req->rq_svec[0].iov_base = p0;
+       req->rq_svec[0].iov_len  = (p - p0) << 2;
+       req->rq_slen = (p - p0) << 2;
+       req->rq_snr = 1;
+
+       len = (6 + 1 + 17 + 1);         /* standard READ reply header */
+       req->rq_rvec[0].iov_base = p0;
+       req->rq_rvec[0].iov_len  = len << 2;
+       req->rq_rvec[1].iov_base = buf;
+       req->rq_rvec[1].iov_len  = count;
+       req->rq_rvec[2].iov_base = p0 + len;            /* spill buffer */
+       req->rq_rvec[2].iov_len  = (NFS_SLACK_SPACE - len) << 2;
+       req->rq_rlen = count + NFS_SLACK_SPACE;
+       req->rq_rnr = 3;
+
+       req->rq_addr = &server->toaddr;
+       req->rq_alen = sizeof(server->toaddr);
+
+       return 0;
+}
+
+int
+nfs_proc_read_reply(struct rpc_ioreq *req)
+{
+       struct nfs_fattr fattr;
+       int             status;
+       __u32           *p0, *p;
+       int             count;
+
+       p0 = (__u32 *) req->rq_rvec[0].iov_base;
+
+       if (!(p = nfs_rpc_verify(p0))) {
+               status = -errno_NFSERR_IO;
+       } else if ((status = ntohl(*p++)) == NFS_OK) {
+               p = xdr_decode_fattr(p, &fattr);
+               count = ntohl(*p++);
+               if (p != req->rq_rvec[2].iov_base) {
+                       /* unexpected RPC reply header size. punt.
+                        * fixme: move iovec contents to align data
+                        * on page boundary and adjust RPC header size
+                        * guess. */
+                       status = -errno_NFSERR_IO;
+                       PRINTK("NFS reply read odd header size %d\n",
+                                       (p - p0) << 2);
+               } else {
+                       status = count;
+                       PRINTK("NFS reply read %d\n", count);
+               }
+       }
+       else {
+               PRINTK("NFS reply read failed = %d\n", status);
+               status = -nfs_stat_to_errno(status);
+       }
+       nfs_rpc_free(p0);
+       return status;
+}
+
 int nfs_proc_write(struct inode * inode, int offset,
                   int count, const char *data, struct nfs_fattr *fattr)
 {
@@ -870,7 +944,7 @@ int *rpc_verify(int *p)
 
        p++;
        if ((n = ntohl(*p++)) != RPC_REPLY) {
-               printk("nfs_rpc_verify: not an RPC reply: %d\n", n);
+               printk("nfs_rpc_verify: not an RPC reply: %x\n", n);
                return NULL;
        }
        if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
index 809c6357611733f4d1c7aef930bb2a688dfa57f3..bb206f060b9fce9e3b56f8f1c394988bd4aae7d1 100644 (file)
@@ -6,17 +6,27 @@
  *  this:
  *
  *  -  When a process places a call, it allocates a request slot if
- *     one is available. Otherwise, it sleeps on the backlog queue.
- *  -  The first process on the receive queue waits for the next RPC reply,
+ *     one is available. Otherwise, it sleeps on the backlog queue
+ *     (rpc_reserve).
+ *  -  Then, the message is transmitted via rpc_send (exported by name of
+ *     rpc_transmit).
+ *  -  Finally, the process waits for the call to complete (rpc_doio):
+ *     The first process on the receive queue waits for the next RPC packet,
  *     and peeks at the XID. If it finds a matching request, it receives
  *     the datagram on behalf of that process and wakes it up. Otherwise,
  *     the datagram is discarded.
  *  -  If the process having received the datagram was the first one on
  *     the receive queue, it wakes up the next one to listen for replies.
- *  -  It then removes itself from the request queue. If there are more
- *     callers waiting on the backlog queue, they are woken up, too.
+ *  -  It then removes itself from the request queue (rpc_release).
+ *     If there are more callers waiting on the backlog queue, they are
+ *     woken up, too.
  *
- *  Copyright (C) 1995, Olaf Kirch <okir@monad.swb.de>
+ * Mar 1996:
+ *  -  Split up large functions into smaller chunks as per Linus' coding
+ *     style. Found an interesting bug this way, too.
+ *  -  Added entry points for nfsiod.
+ *
+ *  Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
  */
 
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/rpcsock.h>
 
+#include <linux/udp.h>
+#include <net/sock.h>
+
 #include <asm/segment.h>
 
 #define msleep(sec)    { current->timeout = sec * HZ / 1000; \
                          current->state = TASK_INTERRUPTIBLE; \
                          schedule(); \
                        }
-                       
-#ifdef DEBUG_NFS                       
-#define dprintk(x)             printk(x)
+
+#undef DEBUG_RPC
+#ifdef DEBUG_RPC                       
+#define dprintk(args...)       printk(## args)
 #else
-#define        dprintk(x)
+#define        dprintk(args...)
 #endif
 
+
+/*
+ * Insert new request into wait list. We make sure list is sorted by
+ * increasing timeout value.
+ */
 static inline void
 rpc_insque(struct rpc_sock *rsock, struct rpc_wait *slot)
 {
-       struct rpc_wait *tmp;
+       struct rpc_wait *next = rsock->pending;
 
-       if ((tmp = rsock->tail) != NULL) {
-               tmp->next = slot;
-       } else {
-               rsock->head = slot;
-       }
-       rsock->tail = slot;
-       slot->prev = tmp;
-       slot->next = NULL;
-       dprintk(("RPC: inserted %08lx into queue.\n", (long)slot));
-       dprintk(("RPC: head = %08lx, tail = %08lx.\n",
-                       (long) rsock->head, (long) rsock->tail));
+       slot->w_next = next;
+       slot->w_prev = NULL;
+       if (next)
+               next->w_prev = slot;
+       rsock->pending = slot;
+       slot->w_queued = 1;
+
+       dprintk("RPC: inserted %p into queue\n", slot);
 }
 
+/*
+ * Remove request from request queue
+ */
 static inline void
 rpc_remque(struct rpc_sock *rsock, struct rpc_wait *slot)
 {
-       struct rpc_wait *prev = slot->prev,
-                       *next = slot->next;
+       struct rpc_wait *prev = slot->w_prev,
+                       *next = slot->w_next;
 
        if (prev != NULL)
-               prev->next = next;
+               prev->w_next = next;
        else
-               rsock->head = next;
+               rsock->pending = next;
        if (next != NULL)
-               next->prev = prev;
-       else
-               rsock->tail = prev;
-       dprintk(("RPC: removed %08lx from queue.\n", (long)slot));
-       dprintk(("RPC: head = %08lx, tail = %08lx.\n",
-                       (long) rsock->head, (long) rsock->tail));
+               next->w_prev = prev;
+
+       slot->w_queued = 0;
+       dprintk("RPC: removed %p from queue, head now %p.\n",
+                       slot, rsock->pending);
 }
 
+/*
+ * Write data to socket.
+ */
 static inline int
-rpc_sendmsg(struct rpc_sock *rsock, struct msghdr *msg, int len)
+rpc_sendmsg(struct rpc_sock *rsock, struct iovec *iov, int nr, int len,
+                               struct sockaddr *sap, int salen)
 {
        struct socket   *sock = rsock->sock;
+       struct msghdr   msg;
        unsigned long   oldfs;
        int             result;
 
-       dprintk(("RPC: sending %d bytes (buf %p)\n", len, msg->msg_iov[0].iov_base));
+       msg.msg_iov     = iov;
+       msg.msg_iovlen  = nr;
+       msg.msg_name    = sap;
+       msg.msg_namelen = salen;
+       msg.msg_accrights = NULL;
+
        oldfs = get_fs();
        set_fs(get_ds());
-       result = sock->ops->sendmsg(sock, msg, len, 0, 0);
+       result = sock->ops->sendmsg(sock, &msg, len, 0, 0);
        set_fs(oldfs);
-       dprintk(("RPC: result = %d\n", result));
 
+       dprintk("RPC: rpc_sendmsg(iov %p, len %d) = %d\n", iov, len, result);
+       return result;
+}
+/*
+ * Read data from socket
+ */
+static inline int
+rpc_recvmsg(struct rpc_sock *rsock, struct iovec *iov,
+                       int nr, int len, int flags)
+{
+       struct socket   *sock = rsock->sock;
+       struct sockaddr sa;
+       struct msghdr   msg;
+       unsigned long   oldfs;
+       int             result, alen;
+
+       msg.msg_iov     = iov;
+       msg.msg_iovlen  = nr;
+       msg.msg_name    = &sa;
+       msg.msg_namelen = sizeof(sa);
+       msg.msg_accrights = NULL;
+
+       oldfs = get_fs();
+       set_fs(get_ds());
+       result = sock->ops->recvmsg(sock, &msg, len, 1, flags, &alen);
+       set_fs(oldfs);
+
+       dprintk("RPC: rpc_recvmsg(iov %p, len %d) = %d\n", iov, len, result);
        return result;
 }
 
@@ -109,7 +164,7 @@ rpc_select(struct rpc_sock *rsock)
        struct file     *file = rsock->file;
        select_table    wait_table;
 
-       dprintk(("RPC: selecting on socket...\n"));
+       dprintk("RPC: selecting on socket...\n");
        wait_table.nr = 0;
        wait_table.entry = &entry;
        current->state = TASK_INTERRUPTIBLE;
@@ -125,232 +180,347 @@ rpc_select(struct rpc_sock *rsock)
        } else if (wait_table.nr)
                remove_wait_queue(entry.wait_address, &entry.wait);
        current->state = TASK_RUNNING;
-       dprintk(("RPC: ...Okay, there appears to be some data.\n"));
+       dprintk("RPC: ...Okay, there appears to be some data.\n");
        return 0;
 }
 
-static inline int
-rpc_recvmsg(struct rpc_sock *rsock, struct msghdr *msg, int len,int flags)
+/*
+ * Reserve an RPC call slot. nocwait determines whether we wait in case
+ * of congestion or not.
+ */
+int
+rpc_reserve(struct rpc_sock *rsock, struct rpc_ioreq *req, int nocwait)
 {
-       struct socket   *sock = rsock->sock;
-       struct sockaddr sa;
-       int             alen = sizeof(sa);
-       unsigned long   oldfs;
-       int             result;
+       struct rpc_wait *slot;
 
-       dprintk(("RPC: receiving %d bytes max (buf %p)\n", len, msg->msg_iov[0].iov_base));
-       oldfs = get_fs();
-       set_fs(get_ds());
-       result = sock->ops->recvmsg(sock, msg, len, 1, flags, &alen);
-       set_fs(oldfs);
-       dprintk(("RPC: result = %d\n", result));
+       req->rq_slot = NULL;
 
-#if 0
-       if (alen != salen || memcmp(&sa, sap, alen)) {
-               dprintk(("RPC: reply address mismatch... rejected.\n"));
-               result = -EAGAIN;
+       while (!(slot = rsock->free) || rsock->cong >= rsock->cwnd) {
+               if (nocwait) {
+                       current->timeout = 0;
+                       return -ENOBUFS;
+               }
+               dprintk("RPC: rpc_reserve waiting on backlog\n");
+               interruptible_sleep_on(&rsock->backlog);
+               if (current->timeout == 0)
+                       return -ETIMEDOUT;
+               if (current->signal & ~current->blocked)
+                       return -ERESTARTSYS;
+               if (rsock->shutdown)
+                       return -EIO;
        }
-#endif
 
-       return result;
+       rsock->free = slot->w_next;
+       rsock->cong += RPC_CWNDSCALE;   /* bump congestion value */
+
+       slot->w_queued = 0;
+       slot->w_gotit = 0;
+       slot->w_req = req;
+
+       dprintk("RPC: reserved slot %p\n", slot);
+       req->rq_slot = slot;
+       return 0;
+}
+
+/*
+ * Release an RPC call slot
+ */
+void
+rpc_release(struct rpc_sock *rsock, struct rpc_ioreq *req)
+{
+       struct rpc_wait *slot = req->rq_slot;
+
+       if (slot != NULL) {
+               dprintk("RPC: release slot %p\n", slot);
+
+               /* Wake up the next receiver */
+               if (slot == rsock->pending && slot->w_next != NULL)
+                       wake_up(&slot->w_next->w_wait);
+
+               /* remove slot from queue of pending */
+               if (slot->w_queued)
+                       rpc_remque(rsock, slot);
+               slot->w_next = rsock->free;
+               rsock->free = slot;
+
+               /* decrease congestion value */
+               rsock->cong -= RPC_CWNDSCALE;
+               if (rsock->cong < rsock->cwnd && rsock->backlog)
+                       wake_up(&rsock->backlog);
+               if (rsock->shutdown)
+                       wake_up(&rsock->shutwait);
+
+               req->rq_slot = NULL;
+       }
+}
+
+/*
+ * Adjust RPC congestion window
+ */
+static void
+rpc_cwnd_adjust(struct rpc_sock *rsock, int timeout)
+{
+       unsigned long   cwnd = rsock->cwnd;
+
+       if (!timeout) {
+               if (rsock->cong >= cwnd) {
+                       /* The (cwnd >> 1) term makes sure
+                        * the result gets rounded properly. */
+                       cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE +
+                                       (cwnd >> 1)) / cwnd;
+                       if (cwnd > RPC_MAXCWND)
+                               cwnd = RPC_MAXCWND;
+               }
+       } else {
+               if ((cwnd >>= 1) < RPC_CWNDSCALE)
+                       cwnd = RPC_CWNDSCALE;
+               dprintk("RPC: cwnd decrease %08lx\n", cwnd);
+       }
+       dprintk("RPC: cong %08lx, cwnd was %08lx, now %08lx\n",
+                       rsock->cong, rsock->cwnd, cwnd);
+
+       rsock->cwnd = cwnd;
+}
+
+static inline void
+rpc_send_check(char *where, u32 *ptr)
+{
+       if (ptr[1] != 0 || ptr[2] != htonl(2) || ptr[3] != htonl(100003)) {
+               printk("RPC: %s sending evil packet:\n"
+                      "     %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                      where,
+                      ptr[0], ptr[1], ptr[2], ptr[3],
+                      ptr[4], ptr[5], ptr[6], ptr[7]);
+       }
 }
 
 /*
  * Place the actual RPC call.
+ * We have to copy the iovec because sendmsg fiddles with its contents.
  */
-static int
-rpc_call_one(struct rpc_sock *rsock, struct rpc_wait *slot,
-               struct sockaddr *sap, int salen,
-               const int *sndbuf, int slen, int *rcvbuf, int rlen)
+static inline int
+rpc_send(struct rpc_sock *rsock, struct rpc_wait *slot)
 {
-       struct rpc_wait *rovr = NULL;
-       int             result;
-       u32             xid;
-       int             safe;
-       struct msghdr   msg;
-       struct iovec    iov;
-       
-       msg.msg_iov     =       &iov;
-       msg.msg_iovlen  =       1;
-       msg.msg_name    =       (void *)sap;
-       msg.msg_namelen =       salen;
-       msg.msg_accrights =     NULL;
-       iov.iov_base    =       (void *)sndbuf;
-       iov.iov_len     =       slen;
-
-       dprintk(("RPC: placing one call, rsock = %08lx, slot = %08lx, "
-               "sap = %08lx, salen = %d, "
-               "sndbuf = %08lx, slen = %d, rcvbuf = %08lx, rlen = %d\n",
-               (long) rsock, (long) slot, (long) sap, 
-               salen, (long) sndbuf, slen, (long) rcvbuf, rlen));
-
-       result = rpc_sendmsg(rsock, &msg, slen);
-       if (result < 0)
-               return result;
+       struct rpc_ioreq *req = slot->w_req;
+       struct iovec    iov[MAX_IOVEC];
 
-       do {
-               /* We are not the receiver. Wait on the side lines. */
-               if (rsock->head != slot) {
-                       interruptible_sleep_on(&slot->wait);
-                       if (slot->gotit)
-                               break;
-                       if (current->timeout != 0)
-                               continue;
-                       if (rsock->shutdown) {
-                               printk("RPC: aborting call due to shutdown.\n");
-                               return -EIO;
-                       }
-                       return -ETIMEDOUT;
+       if (rsock->shutdown)
+               return -EIO;
+
+       memcpy(iov, req->rq_svec, req->rq_snr * sizeof(iov[0]));
+       slot->w_xid = *(u32 *)(iov[0].iov_base);
+       if (!slot->w_queued)
+               rpc_insque(rsock, slot);
+
+       dprintk("rpc_send(%p, %x)\n", slot, slot->w_xid);
+       rpc_send_check("rpc_send", (u32 *) req->rq_svec[0].iov_base);
+       return rpc_sendmsg(rsock, iov, req->rq_snr, req->rq_slen,
+                               req->rq_addr, req->rq_alen);
+}
+
+/*
+ * This is the same as rpc_send but for the functions exported to nfsiod
+ */
+int
+rpc_transmit(struct rpc_sock *rsock, struct rpc_ioreq *req)
+{
+       rpc_send_check("rpc_transmit", (u32 *) req->rq_svec[0].iov_base);
+       return rpc_send(rsock, req->rq_slot);
+}
+
+/*
+ * Receive and dispatch a single reply
+ */
+static inline int
+rpc_grok(struct rpc_sock *rsock)
+{
+       struct rpc_wait *rovr;
+       struct rpc_ioreq *req;
+       struct iovec    iov[MAX_IOVEC];
+       u32             xid;
+       int             safe, result;
+
+       iov[0].iov_base = (void *) &xid;
+       iov[0].iov_len  = sizeof(xid);
+       result = rpc_recvmsg(rsock, iov, 1, sizeof(xid), MSG_PEEK);
+
+       if (result < 0) {
+               switch (-result) {
+               case EAGAIN: case ECONNREFUSED:
+                       return 0;
+               case ERESTARTSYS:
+                       return result;
+               default:
+                       dprintk("rpc_grok: recv error = %d\n", result);
                }
-               
-               /* wait for data to arrive */
-               result = rpc_select(rsock);
-               if (result < 0) {
-                       dprintk(("RPC: select error = %d\n", result));
+       }
+       if (result < 4) {
+               printk(KERN_WARNING "RPC: impossible RPC reply size %d\n",
+                                               result);
+               return 0;
+       }
+
+       dprintk("RPC: rpc_grok: got xid %08lx\n", (unsigned long) xid);
+
+       /* Look for the caller */
+       safe = 0;
+       for (rovr = rsock->pending; rovr; rovr = rovr->w_next) {
+               if (rovr->w_xid == xid)
+                       break;
+               if (safe++ > RPC_MAXREQS) {
+                       printk(KERN_WARNING "RPC: loop in request Q!!\n");
+                       rovr = NULL;
                        break;
                }
+       }
+
+       if (!rovr || rovr->w_gotit) {
+               /* discard dgram */
+               dprintk("RPC: rpc_grok: %s.\n",
+                       rovr? "duplicate reply" : "bad XID");
+               iov[0].iov_base = (void *) &xid;
+               iov[0].iov_len  = sizeof(xid);
+               rpc_recvmsg(rsock, iov, 1, sizeof(xid), 0);
+               return 0;
+       }
+       req = rovr->w_req;
+
+       /* Now receive the reply... Copy the iovec first because of 
+        * memcpy_fromiovec fiddling. */
+       memcpy(iov, req->rq_rvec, req->rq_rnr * sizeof(iov[0]));
+       result = rpc_recvmsg(rsock, iov, req->rq_rnr, req->rq_rlen, 0);
+       rovr->w_result = result;
+       rovr->w_gotit = 1;
+
+       /* ... and wake up the process */
+       wake_up(&rovr->w_wait);
+
+       return result;
+}
+
+/*
+ * Wait for the reply to our call.
+ */
+static int
+rpc_recv(struct rpc_sock *rsock, struct rpc_wait *slot)
+{
+       int     result;
 
-               iov.iov_base=(void *)&xid;
-               iov.iov_len=sizeof(xid);
-               
-               result = rpc_recvmsg(rsock, &msg, sizeof(xid), MSG_PEEK);
-               if (result < 0) {
-                       switch (-result) {
-                       case EAGAIN: case ECONNREFUSED:
-                               continue;
-                       default:
-                               dprintk(("rpc_call: recv error = %d\n", result));
-                       case ERESTARTSYS:
+       do {
+               /* If we are not the receiver, wait on the sidelines */
+               dprintk("RPC: rpc_recv TP1\n");
+               while (rsock->pending != slot) {
+                       if (!slot->w_gotit)
+                               interruptible_sleep_on(&slot->w_wait);
+                       if (slot->w_gotit) {
+                               result = slot->w_result; /* quite important */
                                return result;
                        }
+                       if (current->signal & ~current->blocked)
+                               return -ERESTARTSYS;
+                       if (rsock->shutdown)
+                               return -EIO;
+                       if (current->timeout == 0)
+                               return -ETIMEDOUT;
                }
 
-               /* Look for the caller */
-               safe = 0;
-               for (rovr = rsock->head; rovr; rovr = rovr->next) {
-                       if (safe++ > NRREQS) {
-                               printk("RPC: loop in request Q!!\n");
-                               rovr = NULL;
-                               break;
-                       }
-                       if (rovr->xid == xid)
-                               break;
+               /* Wait for data to arrive */
+               if ((result = rpc_select(rsock)) < 0) {
+                       dprintk("RPC: select error = %d\n", result);
+                       break;
                }
 
-               if (!rovr || rovr->gotit) {
-                       /* bad XID or duplicate reply, discard dgram */
-                       dprintk(("RPC: bad XID or duplicate reply.\n"));
-                       iov.iov_base=(void *)&xid;
-                       iov.iov_len=sizeof(xid);
-                       rpc_recvmsg(rsock, &msg, sizeof(xid),0);
-                       continue;
-               }
-               rovr->gotit = 1;
-
-               /* Now receive the reply */
-               
-               iov.iov_base=rovr->buf;
-               iov.iov_len=rovr->len;
-               
-               result = rpc_recvmsg(rsock, &msg, rovr->len, 0);
-
-               /* If this is not for ourselves, wake up the caller */
-               if (rovr != slot)
-                       wake_up(&rovr->wait);
-       } while (rovr != slot);
-
-       /* This is somewhat tricky. We rely on the fact that we are able to
-        * remove ourselves from the queues before the next reader is scheduled,
-        * otherwise it would find that we're still at the head of the queue
-        * and go to sleep again.
-        */
-       if (rsock->head == slot && slot->next != NULL)
-               wake_up(&slot->next->wait);
+               /* Receive and dispatch */
+               if ((result = rpc_grok(rsock)) < 0)
+                       break;
+       } while (current->timeout && !slot->w_gotit);
 
-       return result;
+       return slot->w_gotit? result : -ETIMEDOUT;
 }
 
 /*
- * Generic RPC call routine. This handles retries and timeouts etc pp
+ * Generic RPC call routine. This handles retries and timeouts etc pp.
+ *
+ * If sent is non-null, it assumes the called has already sent out the
+ * message, so it won't need to do so unless a timeout occurs.
  */
 int
-rpc_call(struct rpc_sock *rsock, struct sockaddr *sap, int addrlen,
-               const int *sndbuf, int slen, int *rcvbuf, int rlen,
-               struct rpc_timeout *strategy, int flag)
+rpc_doio(struct rpc_sock *rsock, struct rpc_ioreq *req,
+                       struct rpc_timeout *strategy, int sent)
 {
-       struct rpc_wait         *slot;
-       int                     result, retries;
-       unsigned long           timeout;
+       struct rpc_wait *slot;
+       int             result, retries;
+       unsigned long   timeout;
 
-       timeout = strategy->init_timeout;
+       timeout = strategy->to_initval;
        retries = 0;
-       slot = NULL;
+       slot = req->rq_slot;
 
        do {
-               dprintk(("RPC call TP1\n"));
+               dprintk("RPC: rpc_doio: TP1 (req %p)\n", req);
                current->timeout = jiffies + timeout;
                if (slot == NULL) {
-                       while ((slot = rsock->free) == NULL) {
-                               if (!flag) {
-                                       current->timeout = 0;
-                                       return -ENOBUFS;
-                               }
-                               interruptible_sleep_on(&rsock->backlog);
-                               if (current->timeout == 0) {
-                                       result = -ETIMEDOUT;
-                                       goto timedout;
-                               }
-                               if (rsock->shutdown) {
-                                       dprintk(("RPC: aborting call due to shutdown.\n"));
-                                       current->timeout = 0;
-                                       return -EIO;
-                               }
-                       }
-                       dprintk(("RPC call TP2\n"));
-                       slot->gotit = 0;
-                       slot->xid = *(u32 *)sndbuf;
-                       slot->buf = rcvbuf;
-                       slot->len = rlen;
-                       rsock->free = slot->next;
+                       result = rpc_reserve(rsock, req, 0);
+                       if (result == -ETIMEDOUT)
+                               goto timedout;
+                       if (result < 0)
+                               break;
+                       slot = req->rq_slot;
+                       rpc_send_check("rpc_doio",
+                               (u32 *) req->rq_svec[0].iov_base);
                        rpc_insque(rsock, slot);
                }
 
-               dprintk(("RPC call TP3\n"));
-               result = rpc_call_one(rsock, slot, sap, addrlen,
-                                       sndbuf, slen, rcvbuf, rlen);
-               if (result != -ETIMEDOUT)
+               /* This check is for loopback NFS. Sometimes replies come
+                * in before biod has called rpc_doio... */
+               if (slot->w_gotit) {
+                       result = slot->w_result;
+                       break;
+               }
+
+               dprintk("RPC: rpc_doio: TP2\n");
+               if (sent || (result = rpc_send(rsock, slot)) >= 0) {
+                       result = rpc_recv(rsock, slot);
+                       sent = 0;
+               }
+
+               if (result != -ETIMEDOUT) {
+                       /* dprintk("RPC: rpc_recv returned %d\n", result); */
+                       rpc_cwnd_adjust(rsock, 0);
                        break;
+               }
+
+               rpc_cwnd_adjust(rsock, 1);
 
 timedout:
-               dprintk(("RPC call TP4\n"));
-               dprintk(("RPC: rpc_call_one returned timeout.\n"));
-               if (strategy->exponential)
+               dprintk("RPC: rpc_recv returned timeout.\n");
+               if (strategy->to_exponential)
                        timeout <<= 1;
                else
-                       timeout += strategy->increment;
-               if (strategy->max_timeout && timeout >= strategy->max_timeout)
-                       timeout = strategy->max_timeout;
-               if (strategy->retries && ++retries >= strategy->retries)
+                       timeout += strategy->to_increment;
+               if (strategy->to_maxval && timeout >= strategy->to_maxval)
+                       timeout = strategy->to_maxval;
+               if (strategy->to_retries && ++retries >= strategy->to_retries)
                        break;
        } while (1);
 
-       dprintk(("RPC call TP5\n"));
+       dprintk("RPC: rpc_doio: TP3\n");
        current->timeout = 0;
-       if (slot != NULL) {
-               dprintk(("RPC call TP6\n"));
-               rpc_remque(rsock, slot);
-               slot->next = rsock->free;
-               rsock->free = slot;
-
-               /* wake up tasks that haven't sent anything yet. (Waking
-                * up the first one on the wait queue would be enough) */
-               if (rsock->backlog)
-                       wake_up(&rsock->backlog);
-       }
+       return result;
+}
 
-       if (rsock->shutdown)
-               wake_up(&rsock->shutwait);
+/*
+ */
+int
+rpc_call(struct rpc_sock *rsock, struct rpc_ioreq *req,
+                       struct rpc_timeout *strategy)
+{
+       int     result;
 
+       result = rpc_doio(rsock, req, strategy, 0);
+       if (req->rq_slot == NULL)
+               printk(KERN_WARNING "RPC: bad: rq_slot == NULL\n");
+       rpc_release(rsock, req);
        return result;
 }
 
@@ -358,31 +528,35 @@ struct rpc_sock *
 rpc_makesock(struct file *file)
 {
        struct rpc_sock *rsock;
+       struct socket   *sock;
+       struct sock     *sk;
        struct rpc_wait *slot;
        int             i;
 
-       dprintk(("RPC: make RPC socket...\n"));
+       dprintk("RPC: make RPC socket...\n");
+       sock = &file->f_inode->u.socket_i;
+       if (sock->type != SOCK_DGRAM || sock->ops->family != AF_INET) {
+               printk(KERN_WARNING "RPC: only UDP sockets supported\n");
+               return NULL;
+       }
+       sk = (struct sock *) sock->data;
+
        if ((rsock = kmalloc(sizeof(struct rpc_sock), GFP_KERNEL)) == NULL)
                return NULL;
        memset(rsock, 0, sizeof(*rsock)); /* Nnnngh! */
 
-       rsock->sock = &file->f_inode->u.socket_i;
+       rsock->sock = sock;
+       rsock->inet = sk;
        rsock->file = file;
+       rsock->cwnd = RPC_INITCWND;
 
+       dprintk("RPC: slots %p, %p, ...\n", rsock->waiting, rsock->waiting + 1);
        rsock->free = rsock->waiting;
-       for (i = 0, slot = rsock->waiting; i < NRREQS-1; i++, slot++)
-               slot->next = slot + 1;
-       slot->next = NULL;
-
-       /* --- taken care of by memset above ---
-       rsock->backlog = NULL;
-       rsock->head = rsock->tail = NULL;
-
-       rsock->shutwait = NULL;
-       rsock->shutdown = 0;
-        */
+       for (i = 0, slot = rsock->waiting; i < RPC_MAXREQS-1; i++, slot++)
+               slot->w_next = slot + 1;
+       slot->w_next = NULL;
 
-       dprintk(("RPC: made socket %08lx", (long) rsock));
+       dprintk("RPC: made socket %p\n", rsock);
        return rsock;
 }
 
@@ -392,13 +566,13 @@ rpc_closesock(struct rpc_sock *rsock)
        unsigned long   t0 = jiffies;
 
        rsock->shutdown = 1;
-       while (rsock->head || rsock->backlog) {
+       while (rsock->pending || rsock->backlog) {
                interruptible_sleep_on(&rsock->shutwait);
                if (current->signal & ~current->blocked)
                        return -EINTR;
 #if 1
                if (t0 && t0 - jiffies > 60 * HZ) {
-                       printk("RPC: hanging in rpc_closesock.\n");
+                       printk(KERN_WARNING "RPC: hanging in rpc_closesock.\n");
                        t0 = 0;
                }
 #endif
index e22eafe207685b7025963bfaf2b8cd8e86d57901..702fb4b1e428b5859e6e240be1de786bd0866c35 100644 (file)
 
 #include <asm/segment.h>
 
-/* JEJB/JSP 2/7/94
- * this must match the value of NFS_SLACK_SPACE in linux/fs/nfs/proc.c 
- * ***FIXME*** should probably put this in nfs_fs.h */
-#define NFS_SLACK_SPACE 1024
-
 #define _S(nr) (1<<((nr)-1))
 
 /*
- * We violate some modularity principles here by poking around
- * in some socket internals.  Besides having to call socket
- * functions from kernel-space instead of user space, the socket
- * interface does not lend itself well to being cleanly called
- * without a file descriptor.  Since the nfs calls can run on
- * behalf of any process, the superblock maintains a file pointer
- * to the server socket.
+ * Place a synchronous call to the NFS server, meaning that the process
+ * sleeps in rpc_call until it either receives a reply or a major timeout
+ * occurs.
+ * This is now merely a front-end to nfs_rpc_doio.
  */
-
 int
 nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
+{
+       struct rpc_ioreq        req;
+
+       size += 1024;           /* account for NFS slack space. ugly */
+
+       req.rq_addr = &server->toaddr;
+       req.rq_alen = sizeof(server->toaddr);
+       req.rq_slot = NULL;
+
+       req.rq_svec[0].iov_base = start;
+       req.rq_svec[0].iov_len = (end - start) << 2;
+       req.rq_slen = (end - start) << 2;
+       req.rq_snr = 1;
+       req.rq_rvec[0].iov_base = start;
+       req.rq_rvec[0].iov_len = size;
+       req.rq_rlen = size;
+       req.rq_rnr = 1;
+
+       return nfs_rpc_doio(server, &req, 0);
+}
+
+int
+nfs_rpc_doio(struct nfs_server *server, struct rpc_ioreq *req, int async)
 {
        struct rpc_timeout      timeout;
        unsigned long           maxtimeo;
        unsigned long           oldmask;
        int                     major_timeout_seen, result;
 
-       timeout.init_timeout = server->timeo;
-       timeout.max_timeout = maxtimeo = NFS_MAX_RPC_TIMEOUT*HZ/10;
-       timeout.retries = server->retrans;
-       timeout.exponential = 1;
+       timeout.to_initval = server->timeo;
+       timeout.to_maxval = NFS_MAX_RPC_TIMEOUT*HZ/10;
+       timeout.to_retries = server->retrans;
+       timeout.to_exponential = 1;
 
        oldmask = current->blocked;
        current->blocked |= ~(_S(SIGKILL)
@@ -68,17 +82,19 @@ nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
                | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
                        ? _S(SIGQUIT) : 0))
                : 0));
+
        major_timeout_seen = 0;
+       maxtimeo = timeout.to_maxval;
 
        do {
-               result = rpc_call(server->rsock, 
-                               &server->toaddr, sizeof(server->toaddr),
-                               start, ((char *) end) - ((char *) start),
-                               start, size + 1024,
-                               &timeout, 1);
+               result = rpc_doio(server->rsock, req, &timeout, async);
+               rpc_release(server->rsock, req);        /* Release slot */
+
                if (current->signal & ~current->blocked)
                        result = -ERESTARTSYS;
                if (result == -ETIMEDOUT) {
+                       if (async)
+                               break;
                        if (server->flags & NFS_MOUNT_SOFT) {
                                printk("NFS server %s not responding, "
                                        "timed out.\n", server->hostname);
@@ -90,8 +106,9 @@ nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
                                        "still trying.\n", server->hostname);
                                major_timeout_seen = 1;
                        }
-                       if ((timeout.init_timeout <<= 1) >= maxtimeo)
-                               timeout.init_timeout = maxtimeo;
+                       if ((timeout.to_initval <<= 1) >= maxtimeo) {
+                               timeout.to_initval = maxtimeo;
+                       }
                } else if (result < 0 && result != -ERESTARTSYS) {
                        printk("NFS: notice message: result = %d.\n", result);
                }
index 4fffac6e5befa11c7336655db549a97dceee77ee..d6547aa33bb4ceab298eca2af1a41b4402e3e39e 100644 (file)
@@ -37,6 +37,7 @@
 #define ST_DEC_EB64P            20     /* EB64+ systype        */
 #define ST_DEC_EB66P           -19     /* EB66 systype         */
 #define ST_DEC_EBPC64          -20     /* Cabriolet (AlphaPC64) systype */
+#defien ST_DEC_EB164            26     /* EB164 systype        */
 
 struct pcb_struct {
        unsigned long ksp;
index 0059e121d2086b70fce877888de96416c2000abe..c62a402e73f7609a795a0ca8e8740ef43ec04db9 100644 (file)
@@ -192,9 +192,9 @@ __asm__ __volatile__ ( \
 #define tas(ptr) (xchg((ptr),1))
 
 struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+#define __xg(x) ((struct __xchg_dummy *)(x))
 
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
        switch (size) {
                case 1:
index 07f949172edd373ba11ad9ac069f32c289f1be41..a8fc1460d3f451bab76b5d97c8137d351019a819 100644 (file)
@@ -51,6 +51,7 @@ struct termio {
 #define N_SLIP         1
 #define N_MOUSE                2
 #define N_PPP          3
+#define N_STRIP                4
 
 #ifdef __KERNEL__
 
index 9f151ee5d72674c3d2d620f76579eb1f2cdc653c..45d1b9a166ab5d40ee31f01d36fcf0fdfbd696f6 100644 (file)
@@ -65,6 +65,7 @@ struct ax25_bpqaddr_struct
 #define        AX25_HDRINCL    8
 #define AX25_IDLE      9
 #define AX25_PACLEN    10
+#define AX25_IPMAXQUEUE 11
 
 #define AX25_KILL      99
 
@@ -109,6 +110,7 @@ struct ax25_bpqaddr_struct
 #define        AX25_VALUES_DIGI        12      /* Digipeat mode */
 #define AX25_VALUES_IDLE       13      /* mode vc idle timer */
 #define AX25_VALUES_PACLEN     14      /* AX.25 MTU */
+#define AX25_VALUES_IPMAXQUEUE  15     /* Maximum number of buffers enqueued */
 #define        AX25_MAX_VALUES         20
 
 struct ax25_parms_struct
index ccdf02371db8e7c8572fb793aaee7dd60ff75e04..48821c45429bc3eaf73bca544506e216592f33ae 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: aztcd.h,v 2.0 1995/11/10 19:38:49 root Exp root $
+/* $Id: aztcd.h,v 2.20 1996/03/12 18:31:30 root Exp root $
  *
  * Definitions for a AztechCD268 CD-ROM interface
  *     Copyright (C) 1994, 1995  Werner Zimmermann
@@ -23,6 +23,7 @@
  *             October 1994 Email: zimmerma@rz.fht-esslingen.de
  */
 
+
 /* *** change this to set the I/O port address of your CD-ROM drive*/
 #define AZT_BASE_ADDR          0x320
 
index 7a329a7124212c7579d4060039e04ffcc8eb764b..5bb4f0bdfbc31c5d9dd058a5f7548a0a724e1e6d 100644 (file)
@@ -149,6 +149,10 @@ struct cdrom_subchnl
        union cdrom_addr cdsc_reladdr;
 };
 
+struct cdrom_mcn {
+  u_char medium_catalog_number[14]; /* 13 ASCII digits, null-terminated */
+};
+
 /*
  * audio states (from SCSI-2, but seen with other drives, too)
  */
index 59ed69c08117ca7ffdd14a54a8ff17463c1364e1..f52aad01df006f2d843aada573dde4e90816fafb 100644 (file)
@@ -49,6 +49,7 @@
 #define ARPHRD_SKIP    771             /* SKIP vif                     */
 #define ARPHRD_LOOPBACK        772             /* Loopback device              */
 #define ARPHRD_LOCALTLK 773            /* Localtalk device             */
+#define ARPHRD_METRICOM        774             /* Metricom STRIP               */
 
 /* ARP protocol opcodes. */
 #define        ARPOP_REQUEST   1               /* ARP request                  */
diff --git a/include/linux/if_strip.h b/include/linux/if_strip.h
new file mode 100644 (file)
index 0000000..e8de0ab
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * if_strip.h --
+ *
+ *      Definitions for the STRIP interface
+ *
+ * Copyright 1996 The Board of Trustees of The Leland Stanford
+ * Junior University. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  Stanford University
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#ifndef __LINUX_STRIP_H
+#define __LINUX_STRIP_H
+
+typedef union {
+       __u32 l;
+       __u16 s[2];
+       __u8  c[4];
+} MetricomAddress;
+
+#endif
index b326e1cc99255e701e86e3a2cce7dad301263f5f..68fffca71acbb8b514df88092fece09603459643 100644 (file)
@@ -17,7 +17,7 @@ struct miscdevice
        struct miscdevice * next, * prev;
 };
 
-extern int mouse_register(struct miscdevice * misc);
-extern int mouse_deregister(struct miscdevice * misc);
+extern int misc_register(struct miscdevice * misc);
+extern int misc_deregister(struct miscdevice * misc);
 
 #endif
index 7055e9fbe8a279449dd47e49b665aa56151bd821..9cd0cb73d5cb9e246d480db8abb90a9ed2f4d1ff 100644 (file)
@@ -92,13 +92,20 @@ extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
                            int cookie, int count, struct nfs_entry *entry);
 extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
                            struct nfs_fsinfo *res);
+extern int nfs_proc_read_request(struct rpc_ioreq *, struct nfs_server *,
+                                struct nfs_fh *, unsigned long offset,
+                                unsigned long count, __u32 *buf);
+extern int nfs_proc_read_reply(struct rpc_ioreq *);
 extern int *rpc_header(int *p, int procedure, int program, int version,
                                int uid, int gid, int *groups);
 extern int *rpc_verify(int *p);
 
 /* linux/fs/nfs/sock.c */
 
-extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size);
+extern int nfs_rpc_call(struct nfs_server *server, int *start,
+                               int *end, int size);
+extern int nfs_rpc_doio(struct nfs_server *server, struct rpc_ioreq *,
+                               int async);
 
 /* linux/fs/nfs/inode.c */
 
@@ -126,6 +133,10 @@ extern struct inode_operations nfs_symlink_inode_operations;
 
 extern int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
 
+/* linux/fs/nfs/bio.c */
+
+extern int nfs_readpage(struct inode *, struct page *);
+
 /* NFS root */
 
 #define NFS_ROOT               "/tftpboot/%s"
diff --git a/include/linux/nfsiod.h b/include/linux/nfsiod.h
new file mode 100644 (file)
index 0000000..b2c6ba0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * linux/include/linux/nfsiod.h
+ *
+ * Declarations for asynchronous NFS RPC calls.
+ *
+ */
+
+#ifndef _LINUX_NFSIOD_H
+#define _LINUX_NFSIOD_H
+
+#include <linux/rpcsock.h>
+
+#ifdef __KERNEL__
+
+/*
+ * This is the callback handler for nfsiod requests.
+ * Note that the callback procedure must NOT sleep.
+ */
+struct nfsiod_req;
+typedef void   (*nfsiod_done_fn_t)(int result, struct nfsiod_req *);
+
+/*
+ * This is the nfsiod request struct.
+ */
+struct nfsiod_req {
+       struct nfsiod_req *     rq_next;
+       struct nfsiod_req *     rq_prev;
+       struct nfs_server *     rq_server;
+       struct wait_queue *     rq_wait;
+       struct rpc_ioreq        rq_rpcreq;
+       nfsiod_done_fn_t        rq_callback;
+       void *                  rq_cdata;
+};
+
+struct nfsiod_req *    nfsiod_reserve(struct nfs_server *, nfsiod_done_fn_t);
+void                   nfsiod_release(struct nfsiod_req *);
+int                    nfsiod_enqueue(struct nfsiod_req *);
+int                    nfsiod(void);
+
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_NFSIOD_H */
index 223dd25972c1ad299959be4a54fdef9f4420e059..36fbf1a01b1754e1eca6bf81eea2eeb9f03feef8 100644 (file)
 /*
  *  rpcsock.h  Declarations for the RPC call interface.
  *
- *  Coypright (C) 1995 Olaf Kirch <okir@monad.swb.de>
- *
+ *  Coypright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  */
 
 
 #ifndef _LINUX_RPCSOCK_H
 #define _LINUX_RPCSOCK_H
 
-/* Maximum number of outstanding RPCs per socket.
- * With 32 slots, IP fragment reassembly would frequently
- * fail due to low memory.
+/*
+ * The rpcsock code maintains an estimate on the maximum number of out-
+ * standing RPC requests, using the congestion avoidance implemented in
+ * 44BSD. This is basically the Van Jacobson slow start algorithm: If a
+ * retransmit occurs, the congestion window is halved; otherwise, it is
+ * incremented by 1/cwnd when a reply is received and a full number of
+ * requests are outstanding.
+ *
+ * Upper procedures may check whether a request would block waiting for
+ * a free RPC slot by using the RPC_CONGESTED() macro.
+ *
+ * Note: on machines with low memory we should probably use a smaller
+ * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
+ * reassembly will frequently run out of memory.
  */
-#define NRREQS         16
+#define RPC_MAXREQS            32
+#define RPC_CWNDSCALE          256
+#define RPC_MAXCWND            (RPC_MAXREQS * RPC_CWNDSCALE)
+/* #define RPC_INITCWND                (RPC_MAXCWND / 2) */
+#define RPC_INITCWND           RPC_CWNDSCALE
+#define RPC_CONGESTED(rsock)   ((rsock)->cong >= (rsock)->cwnd)
 
-/* This describes a timeout strategy */
+/* RPC reply header size: xid, direction, status, accept_status (verifier
+ * size computed separately)
+ */
+#define RPC_HDRSIZE            (4 * 4)
+
+/*
+ * This describes a timeout strategy
+ */
 struct rpc_timeout {
-       unsigned long           init_timeout,
-                               max_timeout,
-                               increment;
-       int                     retries;
-       char                    exponential;
+       unsigned long           to_initval,
+                               to_maxval,
+                               to_increment;
+       int                     to_retries;
+       char                    to_exponential;
+};
+
+/*
+ * This describes a complete RPC request
+ */
+struct rpc_ioreq {
+       struct rpc_wait *       rq_slot;
+       struct sockaddr *       rq_addr;
+       int                     rq_alen;
+       struct iovec            rq_svec[MAX_IOVEC];
+       unsigned int            rq_snr;
+       unsigned long           rq_slen;
+       struct iovec            rq_rvec[MAX_IOVEC];
+       unsigned int            rq_rnr;
+       unsigned long           rq_rlen;
 };
 
-/* Wait information */
+/*
+ * This is the callback handler for async RPC.
+ */
+struct rpc_wait;
+typedef void   (*rpc_callback_fn_t)(int, struct rpc_wait *, void *);
+
+/*
+ * Wait information. This struct defines all the state of an RPC
+ * request currently in flight.
+ */
 struct rpc_wait {
-       struct rpc_wait         *prev, *next;
-       struct wait_queue       *wait;
-       int                     *buf;
-       int                     len;
-       char                    gotit;
-       __u32                   xid;
+       struct rpc_sock *       w_sock;
+       struct rpc_wait *       w_prev;
+       struct rpc_wait *       w_next;
+       struct rpc_ioreq *      w_req;
+       int                     w_result;
+       struct wait_queue *     w_wait;
+       rpc_callback_fn_t       w_handler;
+       void *                  w_cdata;
+       char                    w_queued;
+       char                    w_gotit;
+       __u32                   w_xid;
 };
 
 struct rpc_sock {
-       struct file             *file;
-       struct socket           *sock;
-       struct rpc_wait         waiting[NRREQS];
-       struct rpc_wait         *head, *tail, *free;
-       struct wait_queue       *backlog;
-       struct wait_queue       *shutwait;
+       struct file *           file;
+       struct socket *         sock;
+       struct sock *           inet;
+       struct rpc_wait         waiting[RPC_MAXREQS];
+       unsigned long           cong;
+       unsigned long           cwnd;
+       struct rpc_wait *       pending;
+       struct rpc_wait *       free;
+       struct wait_queue *     backlog;
+       struct wait_queue *     shutwait;
        int                     shutdown;
 };
 
 #ifdef __KERNEL__
 
-int                    rpc_call(struct rpc_sock *, struct sockaddr *, int,
-                               const int *, int, int *, int,
-                               struct rpc_timeout *, int);
+/* rpc_call: Call synchronously */
+int                    rpc_call(struct rpc_sock *, struct rpc_ioreq *,
+                                        struct rpc_timeout *);
+/* These implement asynch calls for nfsiod: Process calls rpc_reserve and
+ * rpc_transmits, then passes the request to nfsiod, which collects the
+ * results via rpc_doio
+ */
+int                    rpc_reserve(struct rpc_sock *, struct rpc_ioreq *, int);
+void                   rpc_release(struct rpc_sock *, struct rpc_ioreq *);
+int                    rpc_transmit(struct rpc_sock *, struct rpc_ioreq *);
+int                    rpc_doio(struct rpc_sock *, struct rpc_ioreq *,
+                                        struct rpc_timeout *, int);
 struct rpc_sock        *       rpc_makesock(struct file *);
 int                    rpc_closesock(struct rpc_sock *);
 
index cc8ded7e7291f135a2884f7b93726ffb06641649..3fbaf10b0023c6c5bc91675a508369223269769f 100644 (file)
@@ -69,6 +69,33 @@ struct __sysctl_args {
 
 /* CTL_NET names: */
 
+/* /proc/sys/net/core */
+#define NET_CORE               0x01000000
+
+/* /proc/sys/net/ethernet */
+#define NET_ETHER              0x02000000
+
+/* /proc/sys/net/802 */
+#define NET_802                0x03000000
+
+/* /proc/sys/net/unix */
+#define NET_UNIX               0x04000000
+
+/* /proc/sys/net/ipv4 */
+#define NET_IPV4               0x05000000
+
+/* /proc/sys/net/ipx */
+#define NET_IPX                        0x06000000
+
+/* /proc/sys/net/appletalk */
+#define NET_ATALK              0x07000000
+
+/* /proc/sys/net/netrom */
+#define NET_NETROM             0x08000000
+
+/* /proc/sys/net/ax25 */
+#define NET_AX25               0x09000000
+
 /* CTL_PROC names: */
 
 /* CTL_FS names: */
index 8411c20993a33fc9d58959a83e1e57689b507e0d..9ca741dcecd01de627fe89f774ec6bc0c99fcca9 100644 (file)
 #include <asm/bitops.h>
 #include <asm/system.h>
 
-#ifdef INCLUDE_INLINE_FUNCS
-#define _INLINE_ extern
-#else
-#define _INLINE_ extern __inline__
-#endif
-
 /*
  * New proposed "bottom half" handlers:
  * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de
@@ -54,22 +48,15 @@ struct tq_struct {
 
 typedef struct tq_struct * task_queue;
 
-#define DECLARE_TASK_QUEUE(q)  task_queue q = &tq_last
+#define DECLARE_TASK_QUEUE(q)  task_queue q = NULL
 
-extern struct tq_struct tq_last;
 extern task_queue tq_timer, tq_immediate, tq_scheduler;
 
-#ifdef INCLUDE_INLINE_FUNCS
-struct tq_struct tq_last = {
-       &tq_last, 0, 0, 0
-};
-#endif
-
 /*
  * To implement your own list of active bottom halfs, use the following
  * two definitions:
  *
- * struct tq_struct *my_bh = &tq_last;
+ * struct tq_struct *my_bh = NULL;
  * struct tq_struct run_my_bh = {
  *     0, 0, (void *)(void *) run_task_queue, &my_bh
  * };
@@ -92,7 +79,7 @@ struct tq_struct tq_last = {
  * "bh_list".  You may call this function only from an interrupt
  * handler or a bottom half handler.
  */
-_INLINE_ void queue_task_irq(struct tq_struct *bh_pointer,
+extern __inline__ void queue_task_irq(struct tq_struct *bh_pointer,
                               task_queue *bh_list)
 {
        if (!set_bit(0,&bh_pointer->sync)) {
@@ -105,7 +92,7 @@ _INLINE_ void queue_task_irq(struct tq_struct *bh_pointer,
  * queue_task_irq_off: put the bottom half handler "bh_pointer" on the list
  * "bh_list".  You may call this function only when interrupts are off.
  */
-_INLINE_ void queue_task_irq_off(struct tq_struct *bh_pointer,
+extern __inline__ void queue_task_irq_off(struct tq_struct *bh_pointer,
                                 task_queue *bh_list)
 {
        if (!(bh_pointer->sync & 1)) {
@@ -119,7 +106,7 @@ _INLINE_ void queue_task_irq_off(struct tq_struct *bh_pointer,
 /*
  * queue_task: as queue_task_irq, but can be called from anywhere.
  */
-_INLINE_ void queue_task(struct tq_struct *bh_pointer,
+extern __inline__ void queue_task(struct tq_struct *bh_pointer,
                           task_queue *bh_list)
 {
        if (!set_bit(0,&bh_pointer->sync)) {
@@ -135,16 +122,15 @@ _INLINE_ void queue_task(struct tq_struct *bh_pointer,
 /*
  * Call all "bottom halfs" on a given list.
  */
-_INLINE_ void run_task_queue(task_queue *list)
+extern __inline__ void run_task_queue(task_queue *list)
 {
-       register struct tq_struct *p;
+       struct tq_struct *p;
 
-       p = xchg(list,&tq_last);
-
-       while (p != &tq_last) {
+       p = xchg(list,NULL);
+       while (p) {
                void *arg;
                void (*f) (void *);
-               register struct tq_struct *save_p;
+               struct tq_struct *save_p;
                arg    = p -> data;
                f      = p -> routine;
                save_p = p;
@@ -154,6 +140,4 @@ _INLINE_ void run_task_queue(task_queue *list)
        }
 }
 
-#undef _INLINE_
-
 #endif /* _LINUX_TQUEUE_H */
index 779c83c232f134d6dac1d05102a39fffb8c15249..630cbb81f2987b1ab8a793e4453d367e60ac7eec 100644 (file)
 #define        AX25_DEF_N2             10
 #define AX25_DEF_IDLE          20
 #define AX25_DEF_PACLEN                256
+#define AX25_DEF_IPMAXQUEUE    1               /* 1 * ax25->window */
 #define        AX25_DEF_DIGI           (AX25_DIGI_INBAND|AX25_DIGI_XBAND)
 
 typedef struct ax25_uid_assoc {
@@ -153,6 +154,7 @@ typedef struct ax25_cb {
        unsigned short          t1, t2, t3, idle, rtt;
        unsigned short          t1timer, t2timer, t3timer, idletimer;
        unsigned short          paclen;
+       unsigned short          maxqueue;
        unsigned short          fragno, fraglen;
        ax25_digi               *digipeat;
        struct sk_buff_head     write_queue;
@@ -235,6 +237,7 @@ extern int  build_ax25_addr(unsigned char *, ax25_address *, ax25_address *,
 extern int  size_ax25_addr(ax25_digi *);
 extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
 extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *);
+extern int  ax25_queue_length(ax25_cb *, struct sk_buff *); /* dl1bke 960327 */
 extern void ax25_dama_on(ax25_cb *);   /* dl1bke 951121 */
 extern void ax25_dama_off(ax25_cb *);  /* dl1bke 951121 */
 
index 3cb02ae91bde60ad8033f40e3e07e5082d296709..6da15d1334ce61cd7cbf4c0dae6a8070fb6d0d7c 100644 (file)
@@ -237,7 +237,7 @@ struct sock
  */
  
        volatile unsigned short backoff;
-       volatile int            err, err_soft;  /* Soft holds errors that don't
+       int                     err, err_soft;  /* Soft holds errors that don't
                                                   cause failure but are the cause
                                                   of a persistent failure not just
                                                   'timed out' */
@@ -441,6 +441,8 @@ here:
 }
 
 
+extern struct sock *           sk_alloc(int priority);
+extern void                    sk_free(struct sock *sk);
 extern void                    destroy_sock(struct sock *sk);
 extern unsigned short          get_new_socknum(struct proto *,
                                                unsigned short);
index e73d1f8e2ff1d0d165cfd9735abd82051be82af0..209befed6d3ca88a53feb40a242c73a100a7ae82 100644 (file)
@@ -434,6 +434,54 @@ void calibrate_delay(void)
                ((loops_per_sec+2500)/5000) % 100);
 }
 
+static void parse_root_dev(char * line)
+{
+       int base = 0;
+       static struct dev_name_struct {
+               const char *name;
+               const int num;
+       } devices[] = {
+               { "nfs",     0x00ff },
+               { "hda",     0x0300 },
+               { "hdb",     0x0340 },
+               { "hdc",     0x1600 },
+               { "hdd",     0x1640 },
+               { "sda",     0x0800 },
+               { "sdb",     0x0810 },
+               { "sdc",     0x0820 },
+               { "sdd",     0x0830 },
+               { "sde",     0x0840 },
+               { "fd",      0x0200 },
+               { "xda",     0x0d00 },
+               { "xdb",     0x0d40 },
+               { "ram",     0x0100 },
+               { "scd",     0x0b00 },
+               { "mcd",     0x1700 },
+               { "cdu535",  0x1800 },
+               { "aztcd",   0x1d00 },
+               { "cm206cd", 0x2000 },
+               { "gscd",    0x1000 },
+               { "sbpcd",   0x1900 },
+               { "sonycd",  0x1800 },
+               { NULL, 0 }
+       };
+
+       if (strncmp(line,"/dev/",5) == 0) {
+               struct dev_name_struct *dev = devices;
+               line += 5;
+               do {
+                       int len = strlen(dev->name);
+                       if (strncmp(line,dev->name,len) == 0) {
+                               line += len;
+                               base = dev->num;
+                               break;
+                       }
+                       dev++;
+               } while (dev->name);
+       }
+       ROOT_DEV = to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
+}
+
 /*
  * This is a simple kernel command line parsing function: it parses
  * the command line, and fills in the arguments/environment to init
@@ -447,11 +495,8 @@ void calibrate_delay(void)
 static void parse_options(char *line)
 {
        char *next;
-       char *devnames[] = { "nfs", "hda", "hdb", "hdc", "hdd", "sda", "sdb",
-               "sdc", "sdd", "sde", "fd", "xda", "xdb", "ram", NULL };
-       int devnums[]    = { 0x0FF, 0x300, 0x340, 0x1600, 0x1640, 0x800,
-               0x810, 0x820, 0x830, 0x840, 0x200, 0xD00, 0xD40, 0x100, 0};
        int args, envs;
+
        if (!*line)
                return;
        args = 0;
@@ -464,22 +509,7 @@ static void parse_options(char *line)
                 * check for kernel options first..
                 */
                if (!strncmp(line,"root=",5)) {
-                       int n;
-                       line += 5;
-                       if (strncmp(line,"/dev/",5)) {
-                               ROOT_DEV = to_kdev_t(
-                                            simple_strtoul(line,NULL,16));
-                               continue;
-                       }
-                       line += 5;
-                       for (n = 0 ; devnames[n] ; n++) {
-                               int len = strlen(devnames[n]);
-                               if (!strncmp(line,devnames[n],len)) {
-                                       ROOT_DEV = to_kdev_t(devnums[n]+
-                                            simple_strtoul(line+len,NULL,0));
-                                       break;
-                               }
-                       }
+                       parse_root_dev(line+5);
                        continue;
                }
 #ifdef CONFIG_ROOT_NFS
index 2b8e6d13ba1fa3aff1d983e196364f150b1d8429..329d0b36bb08f623f9d4b6196fd6ab6703656ba0 100644 (file)
@@ -23,25 +23,28 @@ extern void kerneld_exit(void);
 
 int getrusage(struct task_struct *, int, struct rusage *);
 
-static int generate(unsigned long sig, struct task_struct * p)
+static inline void generate(unsigned long sig, struct task_struct * p)
 {
        unsigned long mask = 1 << (sig-1);
        struct sigaction * sa = sig + p->sig->action - 1;
 
-       /* always generate signals for traced processes ??? */
-       if (!(p->flags & PF_PTRACED)) {
+       /*
+        * Optimize away the signal, if it's a signal that can
+        * be handled immediately (ie non-blocked and untraced)
+        * and that is ignored (either explicitly or by default)
+        */
+       if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
                /* don't bother with ignored signals (but SIGCHLD is special) */
                if (sa->sa_handler == SIG_IGN && sig != SIGCHLD)
-                       return 0;
+                       return;
                /* some signals are ignored by default.. (but SIGCONT already did its deed) */
                if ((sa->sa_handler == SIG_DFL) &&
                    (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG))
-                       return 0;
+                       return;
        }
        p->signal |= mask;
        if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
                wake_up_process(p);
-       return 1;
 }
 
 int send_sig(unsigned long sig,struct task_struct * p,int priv)
index 8349734ee8af2a0303a8350a2391091aa7d6bbb2..04a8abcfb8391df03db6b28e02901c66c111694d 100644 (file)
@@ -244,7 +244,6 @@ struct symbol_table symbol_table = {
        X(tq_timer),
        X(tq_immediate),
        X(tq_scheduler),
-       X(tq_last),
        X(timer_active),
        X(timer_table),
        X(intr_count),
index a1d2d4683bdaf68947a337c27d367cbbcd2f81da..50e416026e072189e08930a5b9e5ce0a0707581f 100644 (file)
@@ -290,15 +290,15 @@ asmlinkage void schedule(void)
 
 /* check alarm, wake up any interruptible tasks that have got a signal */
 
-       if (intr_count) {
-               printk("Aiee: scheduling in interrupt\n");
-               return;
-       }
+       if (intr_count)
+               goto scheduling_in_interrupt;
+
        if (bh_active & bh_mask) {
                intr_count = 1;
                do_bottom_half();
                intr_count = 0;
        }
+
        run_task_queue(&tq_scheduler);
 
        need_resched = 0;
@@ -393,6 +393,10 @@ asmlinkage void schedule(void)
                if (timeout)
                        del_timer(&timer);
        }
+       return;
+
+scheduling_in_interrupt:
+       printk("Aiee: scheduling in interrupt\n");
 }
 
 #ifndef __alpha__
@@ -1028,7 +1032,7 @@ void do_timer(struct pt_regs * regs)
                                prof_buffer[ip]++;
                }
        }
-       if (tq_timer != &tq_last)
+       if (tq_timer)
                mark_bh(TQUEUE_BH);
 }
 
index 43e26854a1d981b4711c53d27cfcb1bfb79ee95a..022b55355a6348cc83cd7124455cb8e63501dbbb 100644 (file)
@@ -8,9 +8,6 @@
  * bottom_half handler need not be re-entrant.
  */
 
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -24,7 +21,6 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
-
 unsigned long intr_count = 0;
 
 int bh_mask_count[32];
index 148f298dee034175814ea86871ea2591b8ce8cba..8362374d1af838421a474f2d290fbf8af8228048 100644 (file)
@@ -4,6 +4,7 @@
  * Begun 24 March 1995, Stephen Tweedie
  * Added /proc support, Dec 1995
  * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
+ * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
  */
 
 #include <linux/config.h>
@@ -38,6 +39,7 @@ static int parse_table(int *, int, void *, size_t *, void *, size_t,
 
 static ctl_table kern_table[];
 static ctl_table vm_table[];
+extern ctl_table net_table[];
 
 /* /proc declarations: */
 
@@ -100,6 +102,7 @@ static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
 static ctl_table root_table[] = {
        {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
        {CTL_VM, "vm", NULL, 0, 0555, vm_table},
+       {CTL_NET, "net", NULL, 0, 0555, net_table},
        {0}
 };
 
index 92a6c2c0a4ea724e04e5a6e7b3d4d0fbeeec0f13..35836111a27832ad3c8d050c33b80f30765a728d 100644 (file)
@@ -367,9 +367,12 @@ found_page:
                        while (ahead < max_ahead) {
                                ahead += PAGE_SIZE;
                                page_cache = try_to_read_ahead(inode, pos + ahead, page_cache);
+                               if (!page->locked)
+                                       goto unlocked_page;
                        }
                        __wait_on_page(page);
                }
+unlocked_page:
                if (!page->uptodate)
                        goto read_page;
                if (nr > inode->i_size - pos)
@@ -439,14 +442,11 @@ static inline unsigned long fill_page(struct inode * inode, unsigned long offset
 
        page = find_page(inode, offset);
        if (page)
-               goto found_page;
+               goto found_page_dont_free;
        new_page = __get_free_page(GFP_KERNEL);
        page = find_page(inode, offset);
-       if (page) {
-               if (new_page)
-                       free_page(new_page);
+       if (page)
                goto found_page;
-       }
        if (!new_page)
                return 0;
        page = mem_map + MAP_NR(new_page);
@@ -458,7 +458,12 @@ static inline unsigned long fill_page(struct inode * inode, unsigned long offset
        add_page_to_inode_queue(inode, page);
        add_page_to_hash_queue(inode, page);
        inode->i_op->readpage(inode, page);
+       if (page->locked)
+               new_page = try_to_read_ahead(inode, offset + PAGE_SIZE, 0);
 found_page:
+       if (new_page)
+               free_page(new_page);
+found_page_dont_free:
        wait_on_page(page);
        return page_address(page);
 }
index e87f6637f36dc3be173a7581f5a640199a3c1b86..2f061f580d94ffba37171222722edce4a13d4b42 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := 802.o
-O_OBJS   = p8023.o
+O_OBJS   = p8023.o sysctl_net_802.o
 
 ifdef CONFIG_TR
 O_OBJS += tr.o
diff --git a/net/802/sysctl_net_802.c b/net/802/sysctl_net_802.c
new file mode 100644 (file)
index 0000000..96f5158
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_802.c: sysctl interface to net 802 subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/802 directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table e802_table[] = {
+       {0}
+};
index 5cca88018813715814a02e65ca529d9a56c15b61..111c18958744942d89f6bf6d6597b09e4c8e04b2 100644 (file)
@@ -41,7 +41,7 @@ SUB_DIRS += ax25
 endif
 
 L_TARGET     := network.a
-L_OBJS      := socket.o protocols.o $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+L_OBJS      := socket.o protocols.o sysctl_net.o $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
 ifeq ($(CONFIG_MODULES),y)
 LX_OBJS = netsyms.o
 endif
index 3980cd9e4cb505f296f04d95f138a8b5fae09fd9..bfe56726491b1f10354db19e8c9f925d6ca284b0 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := appletalk.o
-O_OBJS  := aarp.o ddp.o
+O_OBJS  := aarp.o ddp.o sysctl_net_atalk.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
index 03ed4fc176b73120963ab6f7faa56328f02fe2ac..e8ce364b1b8afd211b2e0755f05ff1a930890d57 100644 (file)
@@ -219,7 +219,7 @@ static void atalk_destroy_socket(atalk_socket *sk)
        
        if(sk->wmem_alloc == 0 && sk->rmem_alloc == 0 && sk->dead)
        {
-               kfree_s(sk,sizeof(*sk));
+               sk_free(sk);
                MOD_DEC_USE_COUNT;
        }
        else
@@ -1125,7 +1125,7 @@ static void def_callback2(struct sock *sk, int len)
 static int atalk_create(struct socket *sock, int protocol)
 {
        atalk_socket *sk;
-       sk=(atalk_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
+       sk=(atalk_socket *)sk_alloc(GFP_KERNEL);
        if(sk==NULL)
                return(-ENOMEM);
        switch(sock->type)
@@ -1137,7 +1137,7 @@ static int atalk_create(struct socket *sock, int protocol)
                case SOCK_DGRAM:
                        break;
                default:
-                       kfree_s((void *)sk,sizeof(*sk));
+                       sk_free((void *)sk);
                        return(-ESOCKTNOSUPPORT);
        }
 
@@ -1364,7 +1364,7 @@ static int atalk_socketpair(struct socket *sock1, struct socket *sock2)
 static int atalk_accept(struct socket *sock, struct socket *newsock, int flags)
 {
        if(newsock->data)
-               kfree_s(newsock->data,sizeof(atalk_socket));
+               sk_free(newsock->data);
        return -EOPNOTSUPP;
 }
 
@@ -2064,7 +2064,7 @@ void atalk_proto_init(struct net_proto *pro)
                atalk_if_get_info
        });
 
-       printk("Appletalk 0.17 for Linux NET3.034\n");
+       printk(KERN_INFO "Appletalk 0.17 for Linux NET3.034\n");
 }
 
 #ifdef MODULE
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
new file mode 100644 (file)
index 0000000..3072789
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_atalk.c: sysctl interface to net Appletalk subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/atalk directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table atalk_table[] = {
+       {0}
+};
index d4bd4b9158e9d4ba34bfd748c26cb47888251a3c..d13b8de3566fbb5dd47a8621fac0f0b013ce772b 100644 (file)
@@ -9,7 +9,7 @@
 
 
 O_TARGET := ax25.o
-O_OBJS  := af_ax25.o
+O_OBJS  := af_ax25.o sysctl_net_ax25.o
 
 ifdef CONFIG_AX25
 O_OBJS += ax25_in.o ax25_out.o ax25_route.o ax25_subr.o ax25_timer.o
index e000000f5ff44b434225d90f5c8935fdd0098cf5..71a3c1a49ff8e475b7d13b7b12a78fe517747e2e 100644 (file)
  *                     Joerg(DL1BKE)           Added DAMA support, fixed (?) digipeating, fixed buffer locking
  *                                             for "virtual connect" mode... Result: Probably the
  *                                             "Most Buggiest Code You've Ever Seen" (TM)
- *                     HaJo(DD8NE)             implementation of a T5 (idle) timer
- *                     Joerg(DL1BKE)           renamed T5 to IDLE and changed behaviour:
+ *                     HaJo(DD8NE)             Implementation of a T5 (idle) timer
+ *                     Joerg(DL1BKE)           Renamed T5 to IDLE and changed behaviour:
  *                                             the timer gets reloaded on every received or transmited
  *                                             I frame for IP or NETROM. The idle timer is not active
  *                                             on "vanilla AX.25" connections. Furthermore added PACLEN
  *                                             to provide AX.25-layer based fragmentation (like WAMPES)
+ *      AX.25 032      Joerg(DL1BKE)           Fixed DAMA timeout error.
+ *                                             ax25_send_frame() limits the number of enqueued
+ *                                             datagrams per socket.
  *
  *     To do:
  *             Restructure the ax25_rcv code to be cleaner/faster and
@@ -634,6 +637,12 @@ static int ax25_ctl_ioctl(const unsigned int cmd, const unsigned long arg)
                                printk("ax25_ctl_ioctl(): Warning --- huge paclen %d", (int) ax25_ctl.arg);
                        ax25->paclen = ax25_ctl.arg;
                        break;
+               case AX25_IPMAXQUEUE:
+                       if (ax25_ctl.arg < 1)
+                               return -EINVAL;
+                               
+                       ax25->maxqueue = ax25_ctl.arg;
+                       break;
                default:
                        return -EINVAL;
          }
@@ -667,6 +676,7 @@ static ax25_cb *ax25_create_cb(void)
        ax25->t3      = AX25_DEF_T3 * PR_SLOWHZ;
        ax25->n2      = AX25_DEF_N2;
        ax25->paclen  = AX25_DEF_PACLEN;
+       ax25->maxqueue= AX25_DEF_IPMAXQUEUE;
        ax25->idle    = 0;
 
        ax25->modulus   = AX25_DEF_AXDEFMODE;
@@ -729,14 +739,15 @@ int ax25_dev_is_dama_slave(struct device *dev)
  */
 static void ax25_fillin_cb(ax25_cb *ax25, struct device *dev)
 {
-       ax25->device = dev;
+       ax25->device  = dev;
 
-       ax25->rtt    = ax25_dev_get_value(dev, AX25_VALUES_T1);
-       ax25->t1     = ax25_dev_get_value(dev, AX25_VALUES_T1);
-       ax25->t2     = ax25_dev_get_value(dev, AX25_VALUES_T2);
-       ax25->t3     = ax25_dev_get_value(dev, AX25_VALUES_T3);
-       ax25->n2     = ax25_dev_get_value(dev, AX25_VALUES_N2);
-       ax25->paclen = ax25_dev_get_value(dev, AX25_VALUES_PACLEN);
+       ax25->rtt      = ax25_dev_get_value(dev, AX25_VALUES_T1);
+       ax25->t1       = ax25_dev_get_value(dev, AX25_VALUES_T1);
+       ax25->t2       = ax25_dev_get_value(dev, AX25_VALUES_T2);
+       ax25->t3       = ax25_dev_get_value(dev, AX25_VALUES_T3);
+       ax25->n2       = ax25_dev_get_value(dev, AX25_VALUES_N2);
+       ax25->paclen   = ax25_dev_get_value(dev, AX25_VALUES_PACLEN);
+       ax25->maxqueue = ax25_dev_get_value(dev, AX25_VALUES_IPMAXQUEUE);
 
        ax25->dama_slave = 0;
        ax25->idle = 0;
@@ -768,7 +779,11 @@ int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest,
                        continue;
 
                if (ax25cmp(&ax25->source_addr, src) == 0 && ax25cmp(&ax25->dest_addr, dest) == 0 && ax25->device == dev) {
-                       ax25_output(ax25, skb);
+                       if (ax25_queue_length(ax25, skb) > ax25->maxqueue * ax25->window) {
+                               kfree_skb(skb, FREE_WRITE);
+                       } else {
+                               ax25_output(ax25, skb);
+                       }
                        ax25->idletimer = ax25->idle;   /* dl1bke 960228 */
                        return 1;               /* It already existed */
                }
@@ -1075,11 +1090,11 @@ static int ax25_create(struct socket *sock, int protocol)
                        return -ESOCKTNOSUPPORT;
        }
 
-       if ((sk = (struct sock *)kmalloc(sizeof(*sk), GFP_ATOMIC)) == NULL)
+       if ((sk = sk_alloc(GFP_ATOMIC)) == NULL)
                return -ENOMEM;
 
        if ((ax25 = ax25_create_cb()) == NULL) {
-               kfree_s(sk, sizeof(*sk));
+               sk_free(sk);
                return -ENOMEM;
        }
 
@@ -1133,11 +1148,11 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
        struct sock *sk;
        ax25_cb *ax25;
 
-       if ((sk = (struct sock *)kmalloc(sizeof(*sk), GFP_ATOMIC)) == NULL)
+       if ((sk = sk_alloc(GFP_ATOMIC)) == NULL)
                return NULL;
 
        if ((ax25 = ax25_create_cb()) == NULL) {
-               kfree_s(sk, sizeof(*sk));
+               sk_free(sk);
                return NULL;
        }
 
@@ -1152,7 +1167,7 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
                case SOCK_SEQPACKET:
                        break;
                default:
-                       kfree_s((void *)sk, sizeof(*sk));
+                       sk_free(sk);
                        kfree_s((void *)ax25, sizeof(*ax25));
                        return NULL;
        }
@@ -1206,7 +1221,7 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
        
        if (osk->ax25->digipeat != NULL) {
                if ((ax25->digipeat = (ax25_digi *)kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
-                       kfree_s(sk, sizeof(*sk));
+                       sk_free(sk);
                        kfree_s(ax25, sizeof(*ax25));
                        return NULL;
                }
@@ -1268,9 +1283,12 @@ static int ax25_release(struct socket *sock, struct socket *peer)
                        case AX25_STATE_4:
                                ax25_clear_queues(sk->ax25);
                                sk->ax25->n2count = 0;
-                               if (!sk->ax25->dama_slave)
+                               if (!sk->ax25->dama_slave) {
                                        ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND);
-                               sk->ax25->t3timer = 0;
+                                       sk->ax25->t3timer = 0;
+                               } else {
+                                       sk->ax25->t3timer = sk->ax25->t3;       /* DAMA slave timeout */
+                               }
                                sk->ax25->t1timer = sk->ax25->t1 = ax25_calculate_t1(sk->ax25);
                                sk->ax25->state   = AX25_STATE_2;
                                sk->state         = TCP_CLOSE;
@@ -1501,7 +1519,7 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
        struct sk_buff *skb;
 
        if (newsock->data)
-               kfree_s(newsock->data, sizeof(struct sock));
+               sk_free(newsock->data);
 
        newsock->data = NULL;
        
@@ -2441,11 +2459,10 @@ void ax25_proto_init(struct net_proto *pro)
 void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
 {
        unsigned char *ptr;
-       int was_locked;
        
 #ifdef CONFIG_FIREWALL
        if (call_out_firewall(PF_AX25, skb, skb->data) != FW_ACCEPT) {
-               kfree_skb(skb, FREE_WRITE);
+               dev_kfree_skb(skb, FREE_WRITE);
                return;
        }
 #endif 
@@ -2459,8 +2476,7 @@ void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
 
                if(skb_headroom(skb) < AX25_BPQ_HEADER_LEN) {
                        printk("ax25_queue_xmit: not enough space to add BPQ Ether header\n");
-                       skb->free = 1;
-                       kfree_skb(skb, FREE_WRITE);
+                       dev_kfree_skb(skb, FREE_WRITE);
                        return;
                }
 
@@ -2472,32 +2488,14 @@ void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
                *ptr++ = (size + 5) / 256;
 
                dev->hard_header(skb, dev, ETH_P_BPQ, bcast_addr, NULL, 0);
-
-               /* dl1bke 960201: see below. Note that the device driver should 
-                *                copy the data into its own buffers, or strange
-                *                things will happen again.
-                */
-
-               was_locked = skb_device_locked(skb);
                dev_queue_xmit(skb, dev, pri);
-               if (was_locked) skb_device_unlock(skb);
-
                return;
        } 
 #endif
 
        ptr = skb_push(skb, 1);
        *ptr++ = 0;                     /* KISS */
-
-/* dl1bke 960201: dev_queue_xmit() will free the skb if it's not locked, so
- *                we need an additional variable to store its status.
- *               sl_xmit() copies the data before returning, we can
- *               remove the lock savely.
- */
-
-       was_locked = skb_device_locked(skb);
        dev_queue_xmit(skb, dev, pri);
-       if (was_locked) skb_device_unlock(skb);
 }
 
 /*
@@ -2584,9 +2582,17 @@ int ax25_rebuild_header(unsigned char *bp, struct device *dev, unsigned long des
                         *      freeing it).
                         */
                        struct sk_buff *ourskb=skb_clone(skb, GFP_ATOMIC);
+
+                       if(ourskb==NULL) {
+                               dev_kfree_skb(skb, FREE_WRITE);
+                               return 1;
+                       }
+
+                       ourskb->sk = skb->sk;
+                       if (ourskb->sk != NULL)
+                               atomic_add(ourskb->truesize, &ourskb->sk->wmem_alloc);
+
                        dev_kfree_skb(skb, FREE_WRITE);
-                       if(ourskb==NULL)
-                               return 1;                       
                        skb_pull(ourskb, AX25_HEADER_LEN - 1);  /* Keep PID */
                        ax25_send_frame(ourskb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
                        return 1;
@@ -2600,10 +2606,16 @@ int ax25_rebuild_header(unsigned char *bp, struct device *dev, unsigned long des
        bp[14] &= ~LAPB_C;
        bp[14] |= LAPB_E;
        bp[14] |= SSSID_SPARE;
+       
+       /*
+        * dl1bke 960317: we use ax25_queue_xmit here to allow mode datagram
+        *                over ethernet. I don't know if this is valid, though.
+        */
 
        ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev);
+       ax25_queue_xmit(skb, dev, SOPRI_NORMAL);
 
-       return 0;
+       return 1;
 }      
 
 #endif
index 27e43bb6e6619f9271b5eb2bb7ce720d8ab3e553..90491ba0302009e96a5bf696d162293905ae54c7 100644 (file)
@@ -29,7 +29,7 @@
  *                                     Added arbitrary protocol id support.
  *     AX.25 031       Joerg(DL1BKE)   Added DAMA support
  *                     HaJo(DD8NE)     Added Idle Disc Timer T5
- *                     Joerg(DL1BKE)   renamed it to "IDLE" with a slightly
+ *                     Joerg(DL1BKE)   Renamed it to "IDLE" with a slightly
  *                                     different behaviour. Fixed defrag
  *                                     routine (I hope)
  */
index 0b4105db3a9b4d8d39dd6f8b96a0b8e1dd2846ab..6c2119c917b86f85e6977875149be9758c091b80 100644 (file)
  *                                     Added support for extended AX.25.
  *     AX.25 031       Joerg(DL1BKE)   Added DAMA support
  *
- *                     Joerg(DL1BKE)   modified fragmenter to fragment vanilla 
+ *                     Joerg(DL1BKE)   Modified fragmenter to fragment vanilla 
  *                                     AX.25 I-Frames. Added PACLEN parameter.
+ *                     Joerg(DL1BKE)   Fixed a problem with buffer allocation
+ *                                     for fragments.
  */
 
 #include <linux/config.h>
@@ -61,7 +63,8 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
 {
        struct sk_buff *skbn;
        unsigned char *p;
-       int err, frontlen, mtu, len, fragno, ka9qfrag, first = 1;
+       int frontlen, mtu, len, fragno, ka9qfrag, first = 1;
+       long flags;
        
        /*
         * dl1bke 960301: We use the new PACLEN parameter as MTU of the AX.25 layer.
@@ -97,15 +100,28 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
                frontlen = skb_headroom(skb);   /* Address space + CTRL */
 
                while (skb->len > 0) {
-                       if (skb->sk != NULL) {
-                               if ((skbn = sock_alloc_send_skb(skb->sk, mtu + 2 + frontlen, 0, 0, &err)) == NULL)
-                                       return;
-                       } else {
-                               if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL)
-                                       return;
+                       save_flags(flags); 
+                       cli();
+                       /* 
+                        * do _not_ use sock_alloc_send_skb, our socket may have
+                        * sk->shutdown set...
+                        *
+                        */
+                       if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) {
+                               restore_flags(flags);
+                               printk("ax25_output(): alloc_skb returned NULL\n");
+                               if (skb_device_locked(skb))
+                                       skb_device_unlock(skb);
+                               return;
                        }
 
                        skbn->sk   = skb->sk;
+                       
+                       if (skbn->sk)
+                               atomic_add(skbn->truesize, &skbn->sk->wmem_alloc);
+                       
+                       restore_flags(flags);
+                       
                        skbn->free = 1;
                        skbn->arp  = 1;
 
@@ -437,7 +453,7 @@ void dama_establish_data_link(ax25_cb *ax25)
        ax25->condition = 0x00;
        ax25->n2count   = 0;
 
-       ax25->t3timer = 0;
+       ax25->t3timer = ax25->t3;
        ax25->t2timer = 0;
        ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 }
index ac7cee597006c21ae6e520b8a1b2cf2f43cca631..3c9de22a6b2527c34ab1d79783f82ce7e544a1f1 100644 (file)
  *                     Joerg(DL1BKE)   ax25_rt_build_path() find digipeater list and device by 
  *                                     destination call. Needed for IP routing via digipeater
  *                     Jonathan(G4KLX) Added routing for IP datagram packets.
- *                     Joerg(DL1BKE)   changed routing for IP datagram and VC to use a default
+ *                     Joerg(DL1BKE)   Changed routing for IP datagram and VC to use a default
  *                                     route if available. Does not overwrite default routes
  *                                     on route-table overflow anymore.
- *                     Joerg(DL1BKE)   fixed AX.25 routing of IP datagram and VC, new ioctl()
+ *                     Joerg(DL1BKE)   Fixed AX.25 routing of IP datagram and VC, new ioctl()
  *                                     "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
  *                                     on routes.
  */
@@ -584,7 +584,8 @@ void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *
        ax25_address src, dest;
        unsigned char *bp;
        int len;
-       
+
+       skb_pull(skb, 1);       /* skip KISS command */
 
        ax25_rt = ax25_find_route(addr);
        if (ax25_rt == NULL || ax25_rt->digipeat == NULL)
@@ -597,16 +598,14 @@ void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *
        len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
                
        if (skb_headroom(skb) < len) {
-               printk("ax25_dg_build_path: not enough headroom for in skb\n");
+               printk("ax25_dg_build_path: not enough headroom for digis in skb\n");
                return;
        }
-
-       memcpy(&dest, skb->data + 1, AX25_ADDR_LEN);
-       memcpy(&src,  skb->data + 8, AX25_ADDR_LEN);
        
+       memcpy(&dest, skb->data    , AX25_ADDR_LEN);
+       memcpy(&src,  skb->data + 7, AX25_ADDR_LEN);
 
        bp = skb_push(skb, len);
-       *bp++ = 0x00;           /* KISS Data */
 
        build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
 }
@@ -696,6 +695,7 @@ void ax25_dev_device_up(struct device *dev)
        ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
        ax25_dev->values[AX25_VALUES_DIGI]      = AX25_DEF_DIGI;
        ax25_dev->values[AX25_VALUES_PACLEN]    = AX25_DEF_PACLEN;
+       ax25_dev->values[AX25_VALUES_IPMAXQUEUE]= AX25_DEF_IPMAXQUEUE;
 
        save_flags(flags);
        cli();
@@ -784,11 +784,13 @@ int ax25_dev_ioctl(unsigned int cmd, void *arg)
                        if (ax25_parms.values[AX25_VALUES_N2] < 1 ||
                            ax25_parms.values[AX25_VALUES_N2] > 31)
                                return -EINVAL;
-                       if (ax25_parms.values[AX25_VALUES_PACLEN] < 16)
+                       if (ax25_parms.values[AX25_VALUES_PACLEN] < 22)
                                return -EINVAL;
                        if ((ax25_parms.values[AX25_VALUES_DIGI] &
                            ~(AX25_DIGI_INBAND | AX25_DIGI_XBAND)) != 0)
                                return -EINVAL;
+                       if (ax25_parms.values[AX25_VALUES_IPMAXQUEUE] < 1)
+                               return -EINVAL;
                        memcpy(ax25_dev->values, ax25_parms.values, AX25_MAX_VALUES * sizeof(short));
                        ax25_dev->values[AX25_VALUES_T1] *= PR_SLOWHZ;
                        ax25_dev->values[AX25_VALUES_T1] /= 2;
index bee13ee4fb82bd872341f193d9735d7be516ecf0..0e30c50d7606c0046394c9e701a7eae8e12ed1e5 100644 (file)
@@ -29,7 +29,9 @@
  *                                     Thus we have ax25_kiss_cmd() now... ;-)
  *                     Dave Brown(N2RJT)
  *                                     Killed a silly bug in the DAMA code.
- *                     Joerg(DL1BKE)   found the real bug in ax25.h --- sorry.
+ *                     Joerg(DL1BKE)   Found the real bug in ax25.h, sri.
+ *     AX.25 032       Joerg(DL1BKE)   Added ax25_queue_length to count the number of
+ *                                     enqeued buffers of a socket..
  */
 
 #include <linux/config.h>
@@ -473,6 +475,46 @@ void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
        out->lastrepeat = 0;
 }
 
+/*
+ *     count the number of buffers on a list belonging to the same
+ *     socket as skb
+ */
+
+static int ax25_list_length(struct sk_buff_head *list, struct sk_buff *skb)
+{
+       int count = 0;
+       long flags;
+       struct sk_buff *skbq;
+
+       save_flags(flags);
+       cli();
+
+       if (list == NULL) {
+               restore_flags(flags);
+                return 0;
+        }
+
+       skbq = (struct sk_buff *) list->next;
+
+       while (skbq != list) {
+               if (skb->sk == skbq->sk)
+                       count++;
+               skbq = skbq->next;
+       }
+
+        restore_flags(flags);
+        return count;
+}
+
+/*
+ *     count the number of buffers of one socket on the write/ack-queue
+ */
+
+int ax25_queue_length(ax25_cb *ax25, struct sk_buff *skb)
+{
+       return ax25_list_length(&ax25->write_queue, skb)+ax25_list_length(&ax25->ack_queue, skb);
+}
+
 /*
  *     :::FIXME:::
  *     This is ****NOT**** the right approach. Not all drivers do kiss. We
index 7f83618bf9daafec6fabe6d4d0f06b62ad8d14af..8f5afbfdee004d6a5b61d2f4f5966c6b786da35e 100644 (file)
@@ -18,6 +18,7 @@
  *                                     sock structure.
  *     AX.25 029       Alan(GW4PTS)    Switched to KA9Q constant names.
  *     AX.25 031       Joerg(DL1BKE)   Added DAMA support
+ *     AX.25 032       Joerg(DL1BKE)   Fixed DAMA timeout bug
  */
 
 #include <linux/config.h>
@@ -180,8 +181,12 @@ static void ax25_timer(unsigned long param)
                ax25_clear_queues(ax25);
 
                ax25->n2count = 0;
-               if (!ax25->dama_slave)
+               if (!ax25->dama_slave) {
+                       ax25->t3timer = 0;
                        ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+               } else {
+                       ax25->t3timer = ax25->t3;
+               }
                
                /* state 1 or 2 should not happen, but... */
                
@@ -190,7 +195,6 @@ static void ax25_timer(unsigned long param)
                else
                        ax25->state = AX25_STATE_2;
 
-               ax25->t3timer = 0;
                ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 
                if (ax25->sk != NULL)
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
new file mode 100644 (file)
index 0000000..70626c6
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_ax25.c: sysctl interface to net AX.25 subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table ax25_table[] = {
+       {0}
+};
index 502d135a0a392490dc445bc284d626c6f201ade6..e2acb2484a70fc49c0a948faedcaa2a102366401 100644 (file)
@@ -9,7 +9,7 @@
 
 O_TARGET := core.o
 
-O_OBJS := sock.o skbuff.o iovec.o datagram.o 
+O_OBJS := sock.o skbuff.o iovec.o datagram.o sysctl_net_core.o
 
 ifdef CONFIG_NET
 
index 766b685b6871ac5cd71b1ff835ad857410749875..057d1f1e47c765999273f5e098ead7b1db0b6ec0 100644 (file)
@@ -628,9 +628,9 @@ void kfree_skb(struct sk_buff *skb, int rw)
                        if (rw)
                                atomic_sub(skb->truesize, &sk->rmem_alloc);
                        else {
-                               atomic_sub(skb->truesize, &sk->wmem_alloc);
                                if(!sk->dead)
                                        sk->write_space(sk);
+                               atomic_sub(skb->truesize, &sk->wmem_alloc);
                        }
                        kfree_skbmem(skb);
                }
index 696e169975f7992e361a735ba8270bd38fcf7787..cc70133b9c546476f104a913317b4a50d4db8ed1 100644 (file)
@@ -68,6 +68,8 @@
  *             Alan Cox        :       Allocator for a socket is settable.
  *             Alan Cox        :       SO_ERROR includes soft errors.
  *             Alan Cox        :       Allow NULL arguments on some SO_ opts
+ *             Alan Cox        :       Generic socket allocation to make hooks
+ *                                     easier (suggested by Craig Metz).
  *
  * To Fix:
  *
@@ -324,6 +326,21 @@ int sock_getsockopt(struct sock *sk, int level, int optname,
        return(0);
 }
 
+struct sock *sk_alloc(int priority)
+{
+       struct sock *sk=(struct sock *)kmalloc(sizeof(*sk), priority);
+       if(!sk)
+               return NULL;
+       memset(sk, 0, sizeof(*sk));
+       return sk;
+}
+
+void sk_free(struct sock *sk)
+{
+       kfree_s(sk,sizeof(*sk));
+}
+
+
 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
        if (sk) {
@@ -393,9 +410,9 @@ void sock_wfree(struct sock *sk, struct sk_buff *skb)
        kfree_skbmem(skb);
        if (sk) 
        {
-               atomic_sub(s, &sk->wmem_alloc);
                /* In case it might be waiting for more memory. */
                sk->write_space(sk);
+               atomic_sub(s, &sk->wmem_alloc);
        }
 }
 
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
new file mode 100644 (file)
index 0000000..8b5848e
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_core.c: sysctl interface to net core subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/core directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table core_table[] = {
+       {0}
+};
index 1929cd2164f780531676a502dad9ad6f2f243bce..a1e61cdda6ec8881c2ca8434f7a2da864aa14e2c 100644 (file)
@@ -9,7 +9,7 @@
 
 O_TARGET := ethernet.o
 
-OBJS   := eth.o 
+OBJS   := eth.o sysctl_net_ether.o
 
 ifdef CONFIG_IPX
 OBJ2   := pe2.o
diff --git a/net/ethernet/sysctl_net_ether.c b/net/ethernet/sysctl_net_ether.c
new file mode 100644 (file)
index 0000000..b81a6d5
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_ether.c: sysctl interface to net Ethernet subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/ether directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table ether_table[] = {
+       {0}
+};
index 6f436bf38180f0bf2b2093884265a2dfd0ad4b11..ea2d94e1d15126518ce2df91f8ec496afcd16257 100644 (file)
@@ -12,7 +12,8 @@ IPV4_OBJS := utils.o route.o proc.o timer.o protocol.o packet.o \
             ip_input.o ip_fragment.o ip_forward.o ip_options.o \
             ip_output.o ip_sockglue.o \
             tcp.o tcp_input.o tcp_output.o tcp_timer.o \
-            raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o ip_fw.o
+            raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o ip_fw.o \
+            sysctl_net_ipv4.o
 
 MOD_LIST_NAME := IPV4_MODULES
 M_OBJS :=
index 5962b522e9c630fb70bde5d031d38a9a236950e6..6eaa4ca8c0d06c3d78ca4c2034a2947660fa10ff 100644 (file)
@@ -407,7 +407,7 @@ void destroy_sock(struct sock *sk)
                 *      later once I know the bug is buried.
                 */
                tcp_cache_zap();
-               kfree_s((void *)sk,sizeof(*sk));
+               sk_free(sk);
        } 
        else 
        {
@@ -578,7 +578,7 @@ static int inet_create(struct socket *sock, int protocol)
        struct proto *prot;
        int err;
 
-       sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
+       sk = sk_alloc(GFP_KERNEL);
        if (sk == NULL) 
                return(-ENOBUFS);
        memset(sk,0,sizeof(*sk));       /* Efficient way to set most fields to zero */
@@ -591,7 +591,7 @@ static int inet_create(struct socket *sock, int protocol)
                case SOCK_SEQPACKET:
                        if (protocol && protocol != IPPROTO_TCP) 
                        {
-                               kfree_s((void *)sk, sizeof(*sk));
+                               sk_free(sk);
                                return(-EPROTONOSUPPORT);
                        }
                        protocol = IPPROTO_TCP;
@@ -602,7 +602,7 @@ static int inet_create(struct socket *sock, int protocol)
                case SOCK_DGRAM:
                        if (protocol && protocol != IPPROTO_UDP) 
                        {
-                               kfree_s((void *)sk, sizeof(*sk));
+                               sk_free(sk);
                                return(-EPROTONOSUPPORT);
                        }
                        protocol = IPPROTO_UDP;
@@ -613,12 +613,12 @@ static int inet_create(struct socket *sock, int protocol)
                case SOCK_RAW:
                        if (!suser()) 
                        {
-                               kfree_s((void *)sk, sizeof(*sk));
+                               sk_free(sk);
                                return(-EPERM);
                        }
                        if (!protocol) 
                        {
-                               kfree_s((void *)sk, sizeof(*sk));
+                               sk_free(sk);
                                return(-EPROTONOSUPPORT);
                        }
                        prot = &raw_prot;
@@ -629,12 +629,12 @@ static int inet_create(struct socket *sock, int protocol)
                case SOCK_PACKET:
                        if (!suser()) 
                        {
-                               kfree_s((void *)sk, sizeof(*sk));
+                               sk_free(sk);
                                return(-EPERM);
                        }
                        if (!protocol) 
                        {
-                               kfree_s((void *)sk, sizeof(*sk));
+                               sk_free(sk);
                                return(-EPROTONOSUPPORT);
                        }
                        prot = &packet_prot;
@@ -643,7 +643,7 @@ static int inet_create(struct socket *sock, int protocol)
                        break;
 
                default:
-                       kfree_s((void *)sk, sizeof(*sk));
+                       sk_free(sk);
                        return(-ESOCKTNOSUPPORT);
        }
        sk->socket = sock;
@@ -655,7 +655,6 @@ static int inet_create(struct socket *sock, int protocol)
        sk->allocation = GFP_KERNEL;
        sk->sndbuf = SK_WMEM_MAX;
        sk->rcvbuf = SK_RMEM_MAX;
-       sk->ato = HZ/3;
        sk->rto = TCP_TIMEOUT_INIT;             /*TCP_WRITE_TIME*/
        sk->cong_window = 1; /* start with only sending one packet at a time. */
        sk->priority = 1;
index 3a1d77b2fe2e60e4d854e2533b61635c7f3a8459..4846e0fdc2894b0d46425bd3a430f238dd0e2f72 100644 (file)
@@ -1023,6 +1023,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 #endif
                case ARPHRD_ETHER:
                case ARPHRD_ARCNET:
+               case ARPHRD_METRICOM:
                        if(arp->ar_pro != htons(ETH_P_IP))
                        {
                                kfree_skb(skb, FREE_READ);
index ce6fb4bb6306ae570591d91a51f6911580d15c06..60f32848857384814be4def68e642d7a176fb0ac 100644 (file)
@@ -346,7 +346,7 @@ struct ip_masq * ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 s
                         save_flags(flags);
                         cli();
                 
-                        if (ip_masq_free_ports == 0) {
+                        if (*free_ports_p == 0) {
                                 restore_flags(flags);
                                 break;
                         }
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
new file mode 100644 (file)
index 0000000..463c4de
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table ipv4_table[] = {
+       {0}
+};
index a27d434dd28a1c080e52f089c2d8df1e9e3e5ffa..023149e1f4a49d4ebd6ef8d11c925390cc3256ff 100644 (file)
@@ -1438,6 +1438,17 @@ static int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                if (copied && sk->urg_data && sk->urg_seq == *seq)
                        break;
 
+               /*
+                * We need to check signals first, to get correct SIGURG
+                * handling.
+                */
+               if (current->signal & ~current->blocked) {
+                       if (copied)
+                               break;
+                       copied = -ERESTARTSYS;
+                       break;
+               }
+
                /*
                 *      Next get a buffer.
                 */
@@ -1502,12 +1513,6 @@ static int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                schedule();
                sk->socket->flags &= ~SO_WAITDATA;
                lock_sock(sk);
-
-               if (current->signal & ~current->blocked) 
-               {
-                       copied = -ERESTARTSYS;
-                       break;
-               }
                continue;
 
        found_ok_skb:
index 53b59e85ba9a3fa72aea0a1ee0cb0b739bfdb10d..a3b74bb8e81c24885a4e0f738f34a8015791c43a 100644 (file)
@@ -398,7 +398,6 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        newsk->send_tail = NULL;
        skb_queue_head_init(&newsk->back_log);
        newsk->rtt = 0;         /*TCP_CONNECT_TIME<<3*/
-       newsk->ato = HZ/3;
        newsk->rto = TCP_TIMEOUT_INIT;
        newsk->mdev = 0;
        newsk->max_window = 0;
index a63f7d01a3ddec5f326386ce92575f4f2c784701..c54f9436f8fe7da1827d7d51f43155f5a4663714 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := ipx.o
-O_OBJS   := af_ipx.o
+O_OBJS   := af_ipx.o sysctl_net_ipx.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
index 972fa7f6e56891425a29517e7cd890810dff81f0..06c3e3cfa3a6ad6ed9544999a2f456dd3ef6ab6d 100644 (file)
@@ -42,6 +42,7 @@
  *     Revision 0.33:  Internal network support, routing changes, uses a
  *                     protocol private area for ipx data.
  *     Revision 0.34:  Module support. <Jim Freeman>
+ *     Revision 0.35:  Checksum support. <Neil Turton>, hooked in by <Alan Cox>
  *
  *     Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com>
  *     Neither Greg Page nor Caldera, Inc. admit liability nor provide 
@@ -193,7 +194,7 @@ ipx_destroy_socket(ipx_socket *sk)
                kfree_skb(skb,FREE_READ);
        }
        
-       kfree_s(sk,sizeof(*sk));
+       sk_free(sk);
        MOD_DEC_USE_COUNT;
 }
        
@@ -907,8 +908,8 @@ ipxitf_create(ipx_interface_definition *idef)
        if(dev->addr_len>IPX_NODE_LEN)
                return -EINVAL;
 
-       if ((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL) {
-
+       if ((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL) 
+       {
                /* Ok now create */
                intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
                if (intrfc==NULL)
@@ -924,9 +925,14 @@ ipxitf_create(ipx_interface_definition *idef)
                        ipx_primary_net = intrfc;
                intrfc->if_internal = 0;
                intrfc->if_ipx_offset = dev->hard_header_len + datalink->header_length;
-               memset(intrfc->if_node, 0, IPX_NODE_LEN);
-               memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), dev->dev_addr, dev->addr_len);
-
+               if(memcmp(idef->ipx_node, "\000\000\000\000\000\000", IPX_NODE_LEN)==0)
+               {
+                       memset(intrfc->if_node, 0, IPX_NODE_LEN);
+                       memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), 
+                               dev->dev_addr, dev->addr_len);
+               }
+               else
+                       memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);
                ipxitf_insert(intrfc);
        }
 
@@ -1171,6 +1177,65 @@ ipxrtr_delete(long net)
        return -ENOENT;
 }
 
+/*
+ *     Checksum routine for IPX
+ */
+/* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
+
+static __u16 ipx_set_checksum(ipx_packet *packet,int length) 
+{
+       /* 
+        *      NOTE: sum is a net byte order quantity, which optimizes the 
+        *      loop. This only works on big and little endian machines. (I
+        *      don't know of a machine that isn't.)
+        */
+
+       __u32 sum=0;
+
+       /*
+        *      Pointer to second word - We skip the checksum field
+        */
+
+       __u16 *p=(__u16 *)&packet->ipx_pktsize;
+
+       /*
+        *      Number of complete words 
+        */
+
+       __u32 i=length>>1;
+
+       /*
+        *      Loop through all complete words except the checksum field 
+        */
+
+       while(--i)
+               sum+=*p++;
+
+       /*
+        *      Add on the last part word if it exists 
+        */
+
+       if(packet->ipx_pktsize&htons(1))
+               sum+=ntohs(0xff00)&*p;
+
+       /*
+        *      Do final fixup 
+        */
+        
+       sum=(sum&0xffff)+(sum>>16);
+
+       /*
+        *      It's a pitty there's no concept of carry in C 
+        */
+
+       if(sum>=0x10000)
+               sum++;
+               
+       return ~sum;
+};
+
 /*
  *     Route an outgoing frame from a socket.
  */
@@ -1215,7 +1280,6 @@ static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struc
 
        /* Fill in IPX header */
        ipx=(ipx_packet *)skb_put(skb,sizeof(ipx_packet));
-       ipx->ipx_checksum=0xFFFF;
        ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
        ipx->ipx_tctrl=0;
        ipx->ipx_type=usipx->sipx_type;
@@ -1244,6 +1308,15 @@ static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struc
 
        memcpy_fromiovec(skb_put(skb,len),iov,len);
 
+       /*
+        *      Apply checksum. Not allowed on 802.3 links.
+        */
+        
+       if(sk->no_check || intrfc->if_dlink_type!=IPX_FRAME_8023)
+               ipx->ipx_checksum=0xFFFF;
+       else
+               ipx->ipx_checksum=ipx_set_checksum(ipx, len+sizeof(ipx_packet));
+
 #ifdef CONFIG_FIREWALL 
        if(call_out_firewall(PF_IPX, skb, ipx)!=FW_ACCEPT)
        {
@@ -1608,11 +1681,10 @@ static void def_callback2(struct sock *sk, int len)
        }
 }
 
-static int 
-ipx_create(struct socket *sock, int protocol)
+static int ipx_create(struct socket *sock, int protocol)
 {
        ipx_socket *sk;
-       sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
+       sk=(ipx_socket *)sk_alloc(GFP_KERNEL);
        if(sk==NULL)
                return(-ENOMEM);
        switch(sock->type)
@@ -1623,17 +1695,9 @@ ipx_create(struct socket *sock, int protocol)
                        kfree_s((void *)sk,sizeof(*sk));
                        return(-ESOCKTNOSUPPORT);
        }
-       sk->dead=0;
-       sk->next=NULL;
-       sk->broadcast=0;
        sk->rcvbuf=SK_RMEM_MAX;
        sk->sndbuf=SK_WMEM_MAX;
-       sk->wmem_alloc=0;
-       sk->rmem_alloc=0;
-       sk->users=0;
-       sk->shutdown=0;
        sk->prot=NULL;  /* So we use default free mechanisms */
-       sk->err=0;
        skb_queue_head_init(&sk->receive_queue);
        skb_queue_head_init(&sk->write_queue);
        sk->send_head=NULL;
@@ -1641,15 +1705,8 @@ ipx_create(struct socket *sock, int protocol)
        sk->state=TCP_CLOSE;
        sk->socket=sock;
        sk->type=sock->type;
-       sk->protinfo.af_ipx.type=0;             /* General user level IPX */
-       sk->debug=0;
-       sk->protinfo.af_ipx.intrfc = NULL;
-       memset(&sk->protinfo.af_ipx.dest_addr,'\0',
-               sizeof(sk->protinfo.af_ipx.dest_addr));
-       sk->protinfo.af_ipx.port = 0;
-       sk->protinfo.af_ipx.ncp_server = 0;
        sk->mtu=IPX_MTU;
-       
+       sk->no_check = 1;               /* Checksum off by default */   
        if(sock!=NULL)
        {
                sock->data=(void *)sk;
@@ -1965,23 +2022,26 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        
        ipx=(ipx_packet *)skb->h.raw;
        
-       if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) {
-               /* We don't do checksum options. We can't really. Novell don't seem to have documented them.
-                  If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be
-                  the same... */
+       /* Too small */
+       
+       if(ntohs(ipx->ipx_pktsize)<sizeof(ipx_packet)) {
                kfree_skb(skb,FREE_READ);
                return 0;
        }
        
-       /* Too small */
-       if(htons(ipx->ipx_pktsize)<sizeof(ipx_packet)) {
-               kfree_skb(skb,FREE_READ);
-               return 0;
+       if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) 
+       {
+               if(ipx_set_checksum(ipx, ntohs(ipx->ipx_pktsize))!=ipx->ipx_checksum)
+               {
+                       kfree_skb(skb,FREE_READ);
+                       return 0;
+               }
        }
        
        /* Determine what local ipx endpoint this is */
        intrfc = ipxitf_find_using_phys(dev, pt->type);
-       if (intrfc == NULL) {
+       if (intrfc == NULL) 
+       {
                if (ipxcfg_auto_create_interfaces) {
                        intrfc = ipxitf_auto_create(dev, pt->type);
                }
@@ -2004,8 +2064,10 @@ static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nob
        struct sockaddr_ipx local_sipx;
        int retval;
 
-       if (sk->zapped) return -EIO; /* Socket not bound */
-       if(flags) return -EINVAL;
+       if (sk->zapped) 
+               return -EIO; /* Socket not bound */
+       if(flags) 
+               return -EINVAL;
                
        if(usipx) 
        {
@@ -2043,7 +2105,8 @@ static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nob
        }
        
        retval = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len);
-       if (retval < 0) return retval;
+       if (retval < 0) 
+               return retval;
 
        return len;
 }
@@ -2278,8 +2341,8 @@ ipx_proto_init(struct net_proto *pro)
        proc_net_register(&ipx_if_procinfo);
        proc_net_register(&ipx_rt_procinfo);
                
-       printk("Swansea University Computer Society IPX 0.34 for NET3.034\n");
-       printk("IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
+       printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.034\n");
+       printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
 }
 
 #ifdef MODULE
diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c
new file mode 100644 (file)
index 0000000..c699d6f
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_ipx.c: sysctl interface to net IPX subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/ipx directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table ipx_table[] = {
+       {0}
+};
index 42e44c8fe012cccf15253be8ec8614bcb6ea98fd..a98e7646ef67e4155ea1f1138af27235bb6ad640 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := netrom.o
-O_OBJS  := af_netrom.o
+O_OBJS  := af_netrom.o sysctl_net_netrom.o
 
 ifdef CONFIG_NETROM
 O_OBJS += nr_dev.o nr_in.o nr_out.o nr_route.o nr_subr.o nr_timer.o
index d527040f0344a7ee519727e18945edb4371a67ca..fa2e8f949d164f2692460f886ed2639ae19a834d 100644 (file)
@@ -266,7 +266,7 @@ void nr_destroy_socket(struct sock *sk)     /* Not static as its used by the timer *
                add_timer(&sk->timer);
        } else {
                kfree_s(sk->nr, sizeof(*sk->nr));
-               kfree_s(sk, sizeof(*sk));
+               sk_free(sk);
        }
 
        restore_flags(flags);
@@ -415,11 +415,11 @@ static int nr_create(struct socket *sock, int protocol)
        if (sock->type != SOCK_SEQPACKET || protocol != 0)
                return -ESOCKTNOSUPPORT;
 
-       if ((sk = (struct sock *)kmalloc(sizeof(*sk), GFP_ATOMIC)) == NULL)
+       if ((sk = sk_alloc(GFP_ATOMIC)) == NULL)
                return -ENOMEM;
 
        if ((nr = (nr_cb *)kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) {
-               kfree_s(sk, sizeof(*sk));
+               sk_free(sk);
                return -ENOMEM;
        }
 
@@ -516,11 +516,11 @@ static struct sock *nr_make_new(struct sock *osk)
        if (osk->type != SOCK_SEQPACKET)
                return NULL;
 
-       if ((sk = (struct sock *)kmalloc(sizeof(*sk), GFP_ATOMIC)) == NULL)
+       if ((sk = (struct sock *)sk_alloc(GFP_ATOMIC)) == NULL)
                return NULL;
 
        if ((nr = (nr_cb *)kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) {
-               kfree_s(sk, sizeof(*sk));
+               sk_free(sk);
                return NULL;
        }
 
@@ -814,7 +814,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
        struct sk_buff *skb;
 
        if (newsock->data)
-               kfree_s(newsock->data, sizeof(struct sock));
+               sk_free(newsock->data);
 
        newsock->data = NULL;
        
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
new file mode 100644 (file)
index 0000000..d4f0527
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_netrom.c: sysctl interface to net NETROM subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table netrom_table[] = {
+       {0}
+};
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
new file mode 100644 (file)
index 0000000..0b84d09
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- linux-c -*-
+ * sysctl_net.c: sysctl interface to net subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net directories for each protocol family. [MS]
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+#ifdef CONFIG_INET
+extern ctl_table ipv4_table[];
+#endif
+
+#ifdef CONFIG_IPX
+extern ctl_table ipx_table[];
+#endif
+
+#ifdef CONFIG_ATALK
+extern ctl_table atalk_table[];
+#endif
+
+#ifdef CONFIG_NETROM
+extern ctl_table netrom_table[];
+#endif
+
+#ifdef CONFIG_AX25
+extern ctl_table ax25_table[];
+#endif
+
+extern ctl_table core_table[], ether_table[], e802_table[], unix_table[];
+
+ctl_table net_table[] = {
+       {NET_CORE,   "core",      NULL, 0, 0555, core_table},
+       {NET_ETHER,  "ethernet",  NULL, 0, 0555, ether_table},
+        {NET_802,    "802",       NULL, 0, 0555, e802_table},
+        {NET_UNIX,   "unix",      NULL, 0, 0555, unix_table},
+#ifdef CONFIG_INET
+       {NET_IPV4,   "ipv4",      NULL, 0, 0555, ipv4_table},
+#endif
+#ifdef CONFIG_IPX
+        {NET_IPX,    "ipx",       NULL, 0, 0555, ipx_table},
+#endif
+#ifdef CONFIG_ATALK
+        {NET_ATALK,  "appletalk", NULL, 0, 0555, atalk_table},
+#endif
+#ifdef CONFIG_NETROM
+       {NET_NETROM, "netrom",    NULL, 0, 0555, netrom_table},
+#endif
+#ifdef CONFIG_AX25
+       {NET_AX25,   "ax25",      NULL, 0, 0555, ax25_table},
+#endif
+       {0}
+};
index 22aa00ce8205af7f0fe4bab8fcebbeb66dee1264..9116cc054773d04a17baa67455d8d40fb3a980c2 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := unix.o
-O_OBJS  := af_unix.o garbage.o
+O_OBJS  := af_unix.o garbage.o sysctl_net_unix.o
 
 include $(TOPDIR)/Rules.make
 
index 0ecfd096ce731c20a40ff0b39cb6b89e4cfa5888..bf519d02079ea7ce29803daef368fdff70f55bcd 100644 (file)
@@ -148,7 +148,7 @@ static void unix_destroy_timer(unsigned long data)
        {
                if(sk->protinfo.af_unix.name)
                        kfree(sk->protinfo.af_unix.name);
-               kfree_s(sk,sizeof(*sk));
+               sk_free(sk);
                return;
        }
        
@@ -202,7 +202,7 @@ static void unix_destroy_socket(unix_socket *sk)
        {
                if(sk->protinfo.af_unix.name)
                        kfree(sk->protinfo.af_unix.name);
-               kfree_s(sk,sizeof(*sk));
+               sk_free(sk);
        }
        else
        {
@@ -281,7 +281,7 @@ static int unix_create(struct socket *sock, int protocol)
        unix_socket *sk;
        if(protocol && protocol != PF_UNIX)
                return -EPROTONOSUPPORT;
-       sk=(unix_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
+       sk=(unix_socket *)sk_alloc(GFP_KERNEL);
        if(sk==NULL)
                return -ENOMEM;
        switch(sock->type)
@@ -297,7 +297,7 @@ static int unix_create(struct socket *sock, int protocol)
                case SOCK_DGRAM:
                        break;
                default:
-                       kfree_s(sk,sizeof(*sk));
+                       sk_free(sk);
                        return -ESOCKTNOSUPPORT;
        }
        sk->type=sock->type;
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
new file mode 100644 (file)
index 0000000..b436aab
--- /dev/null
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_unix.c: sysctl interface to net af_unix subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/unix directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table unix_table[] = {
+       {0}
+};