diff -u --recursive --new-file v1.3.81/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.81/linux/Documentation/Configure.help Sun Mar 31 00:13:16 1996 +++ linux/Documentation/Configure.help Tue Apr 2 08:43:04 1996 @@ -642,13 +642,13 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /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 @@ 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 diff -u --recursive --new-file v1.3.81/linux/Documentation/cdrom/aztcd linux/Documentation/cdrom/aztcd --- v1.3.81/linux/Documentation/cdrom/aztcd Mon Dec 11 11:18:47 1995 +++ linux/Documentation/cdrom/aztcd Tue Apr 2 08:24:06 1996 @@ -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 @@ 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 @@ 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 @@ 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 @@ '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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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); diff -u --recursive --new-file v1.3.81/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v1.3.81/linux/Documentation/devices.tex Sun Mar 24 20:07:00 1996 +++ linux/Documentation/devices.tex Mon Apr 1 10:48:04 1996 @@ -42,7 +42,7 @@ % \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 @@ \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 @@ \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 @@ \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} diff -u --recursive --new-file v1.3.81/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v1.3.81/linux/Documentation/devices.txt Sun Mar 24 20:07:00 1996 +++ linux/Documentation/devices.txt Mon Apr 1 10:48:04 1996 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - 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 @@ 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 @@ 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 -u --recursive --new-file v1.3.81/linux/Documentation/nfsroot.txt linux/Documentation/nfsroot.txt --- v1.3.81/linux/Documentation/nfsroot.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/nfsroot.txt Mon Apr 1 10:46:29 1996 @@ -0,0 +1,204 @@ +Mounting the root filesystem via NFS (nfsroot) +============================================== + +Written 1996 by Gero Kuhlmann + + + +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=[:][,] + + If the nfsroot parameter is NOT give on the command line, the default + "/tftpboot/%s" will be used. + + 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. + + 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. + + 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=:::::: + + 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). + + 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 parameter. If this parameter is not + empty, neither RARP nor BOOTP will be used. + + 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. + + 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 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. + + Name of the client. If empty, the client IP address is + used in ASCII-notation, or the value received by BOOTP. + + 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. + + 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 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// 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 + , with the BOOTP code and a couple of bug fixes + contributed by Martin Mares . In order to write + the initial version of nfsroot I would like to thank Jens-Uwe Mager + for his help. + diff -u --recursive --new-file v1.3.81/linux/Makefile linux/Makefile --- v1.3.81/linux/Makefile Sun Mar 31 00:13:16 1996 +++ linux/Makefile Sun Mar 31 20:27:33 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 81 +SUBLEVEL = 82 ARCH = i386 diff -u --recursive --new-file v1.3.81/linux/Rules.make linux/Rules.make --- v1.3.81/linux/Rules.make Wed Feb 28 08:44:10 1996 +++ linux/Rules.make Tue Apr 2 08:43:04 1996 @@ -150,7 +150,7 @@ @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 diff -u --recursive --new-file v1.3.81/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v1.3.81/linux/arch/alpha/config.in Sun Mar 31 00:13:16 1996 +++ linux/arch/alpha/config.in Mon Apr 1 10:48:04 1996 @@ -15,6 +15,7 @@ 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 diff -u --recursive --new-file v1.3.81/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v1.3.81/linux/arch/alpha/defconfig Mon Mar 25 11:56:11 1996 +++ linux/arch/alpha/defconfig Mon Apr 1 13:40:33 1996 @@ -7,6 +7,7 @@ # CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set +# CONFIG_KERNELD is not set # # General setup @@ -130,10 +131,11 @@ 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_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 diff -u --recursive --new-file v1.3.81/linux/arch/alpha/kernel/ksyms.c linux/arch/alpha/kernel/ksyms.c --- v1.3.81/linux/arch/alpha/kernel/ksyms.c Mon Mar 4 11:46:31 1996 +++ linux/arch/alpha/kernel/ksyms.c Tue Apr 2 08:43:04 1996 @@ -33,6 +33,12 @@ X(_outb), X(_outw), X(_outl), + X(_readb), + X(_readw), + X(_readl), + X(_writeb), + X(_writew), + X(_writel), X(__divl), X(__reml), X(__divq), diff -u --recursive --new-file v1.3.81/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v1.3.81/linux/arch/alpha/kernel/setup.c Sat Mar 16 13:52:12 1996 +++ linux/arch/alpha/kernel/setup.c Mon Apr 1 17:00:03 1996 @@ -174,7 +174,8 @@ "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; diff -u --recursive --new-file v1.3.81/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v1.3.81/linux/arch/i386/boot/setup.S Thu Mar 28 17:34:33 1996 +++ linux/arch/i386/boot/setup.S Sat Mar 30 20:58:57 1996 @@ -114,10 +114,12 @@ 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 diff -u --recursive --new-file v1.3.81/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v1.3.81/linux/arch/i386/defconfig Sun Mar 31 00:13:16 1996 +++ linux/arch/i386/defconfig Mon Apr 1 11:02:35 1996 @@ -88,10 +88,11 @@ 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 diff -u --recursive --new-file v1.3.81/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v1.3.81/linux/arch/i386/kernel/irq.c Sun Mar 17 09:01:02 1996 +++ linux/arch/i386/kernel/irq.c Mon Apr 1 10:46:29 1996 @@ -263,27 +263,28 @@ 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;ihandler) + if (!action || !action->handler) continue; len += sprintf(buf+len, "%3d: %10d ", i, kstat.interrupts[i]); for (j=0;jflags & SA_INTERRUPT) ? '+' : ' ', action->name); @@ -297,7 +298,7 @@ sum_spins); for (i=0;irq_status == RQ_INACTIVE){ - DPRINT("current not active!\n"); + CLEAR_INTR; + unlock_fdc(); return; } @@ -3335,7 +3336,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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); diff -u --recursive --new-file v1.3.81/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v1.3.81/linux/drivers/block/ide-cd.c Sat Mar 16 13:52:13 1996 +++ linux/drivers/block/ide-cd.c Mon Apr 1 10:46:32 1996 @@ -2105,6 +2105,14 @@ return 0; } + case CDROMCLOSETRAY: + { + if (drive->usage > 1) + return -EBUSY; + + return cdrom_eject (drive, 1, NULL); + } + case CDROMPAUSE: return cdrom_pause (drive, 1, NULL); diff -u --recursive --new-file v1.3.81/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.3.81/linux/drivers/block/ide.c Thu Mar 28 17:34:33 1996 +++ linux/drivers/block/ide.c Sun Mar 31 00:14:26 1996 @@ -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) */ @@ -223,6 +223,7 @@ * 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 @@ 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 @@ 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<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 @@ 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); diff -u --recursive --new-file v1.3.81/linux/drivers/block/md.c linux/drivers/block/md.c --- v1.3.81/linux/drivers/block/md.c Sun Mar 24 20:07:00 1996 +++ linux/drivers/block/md.c Mon Apr 1 12:58:34 1996 @@ -389,6 +389,7 @@ static void do_md_request (void) { int minor; + long flags; struct request *req; while (1) @@ -396,12 +397,13 @@ #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 @@ #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 @@ 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 && diff -u --recursive --new-file v1.3.81/linux/drivers/block/triton.c linux/drivers/block/triton.c --- v1.3.81/linux/drivers/block/triton.c Sat Mar 16 13:52:15 1996 +++ linux/drivers/block/triton.c Mon Apr 1 10:46:31 1996 @@ -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 @@ -121,7 +121,7 @@ * 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"}; /* diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v1.3.81/linux/drivers/cdrom/aztcd.c Mon Dec 11 11:18:47 1995 +++ linux/drivers/cdrom/aztcd.c Tue Apr 2 08:43:05 1996 @@ -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 @@ -134,7 +134,7 @@ 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 as the directory structure was changed. README.aztcd is now /usr/src/docu- @@ -1545,7 +1545,7 @@ 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 @@ 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 @@ } 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> "); @@ -2098,6 +2098,6 @@ return; } release_region(azt_port,4); - printk("aztcd module released.\n"); + printk(KERN_INFO "aztcd module released.\n"); } #endif MODULE diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v1.3.81/linux/drivers/cdrom/cdu31a.c Wed Mar 27 08:19:28 1996 +++ linux/drivers/cdrom/cdu31a.c Tue Apr 2 08:43:05 1996 @@ -3092,11 +3092,11 @@ } } - 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 @@ free_irq(cdu31a_irq, NULL); release_region(cdu31a_port,4); - printk("cdu31a module released.\n"); + printk(KERN_INFO "cdu31a module released.\n"); } #endif MODULE diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v1.3.81/linux/drivers/cdrom/cm206.c Sun Mar 3 15:23:54 1996 +++ linux/drivers/cdrom/cm206.c Tue Apr 2 08:43:05 1996 @@ -1119,7 +1119,7 @@ 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 @@ 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 @@ 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 @@ void cleanup_module(void) { cleanup(4); - printk("cm206 removed\n"); + printk(KERN_INFO "cm206 removed\n"); } #else /* !MODULE */ diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c --- v1.3.81/linux/drivers/cdrom/gscd.c Wed Nov 8 12:07:27 1995 +++ linux/drivers/cdrom/gscd.c Tue Apr 2 08:43:05 1996 @@ -967,7 +967,7 @@ } else { - printk ( "Happy GoldStar !\n" ); + printk (KERN_INFO "Happy GoldStar !\n" ); return 0; } } @@ -982,7 +982,7 @@ } release_region (gscd_port,4); - printk( "GoldStar-module released.\n" ); + printk(KERN_INFO "GoldStar-module released.\n" ); } #endif @@ -1001,8 +1001,8 @@ 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 @@ 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 @@ 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; } diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c --- v1.3.81/linux/drivers/cdrom/isp16.c Tue Feb 13 10:30:25 1996 +++ linux/drivers/cdrom/isp16.c Tue Apr 2 08:43:05 1996 @@ -93,7 +93,7 @@ { 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 @@ 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 @@ 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 @@ 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v1.3.81/linux/drivers/cdrom/mcd.c Thu Mar 21 08:55:44 1996 +++ linux/drivers/cdrom/mcd.c Tue Apr 2 08:43:05 1996 @@ -1172,7 +1172,7 @@ 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 @@ } release_region(mcd_port,4); free_irq(mcd_irq, NULL); - printk("mcd module released.\n"); + printk(KERN_INFO "mcd module released.\n"); } #endif MODULE diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c --- v1.3.81/linux/drivers/cdrom/optcd.c Fri Feb 23 09:39:34 1996 +++ linux/drivers/cdrom/optcd.c Tue Apr 2 08:43:06 1996 @@ -2059,7 +2059,7 @@ 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 @@ return; } release_region(optcd_port, 4); - printk("optcd: module released.\n"); + printk(KERN_INFO "optcd: module released.\n"); } #endif MODULE diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c --- v1.3.81/linux/drivers/cdrom/sjcd.c Tue Feb 13 10:30:25 1996 +++ linux/drivers/cdrom/sjcd.c Tue Apr 2 08:43:06 1996 @@ -1447,7 +1447,7 @@ 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 @@ * 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 @@ /* * 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 @@ * 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 @@ } 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 @@ if ( sjcd_cleanup() ) printk( "SJCD: module: cannot be removed.\n" ); else - printk( "SJCD: module: removed.\n"); + printk(KERN_INFO "SJCD: module: removed.\n"); } #endif diff -u --recursive --new-file v1.3.81/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v1.3.81/linux/drivers/cdrom/sonycd535.c Wed Mar 27 08:19:28 1996 +++ linux/drivers/cdrom/sonycd535.c Tue Apr 2 08:43:06 1996 @@ -1512,7 +1512,7 @@ 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 @@ 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 @@ 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c --- v1.3.81/linux/drivers/char/atixlmouse.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/char/atixlmouse.c Tue Apr 2 08:43:06 1996 @@ -207,7 +207,7 @@ 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; diff -u --recursive --new-file v1.3.81/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v1.3.81/linux/drivers/char/busmouse.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/char/busmouse.c Tue Apr 2 08:43:06 1996 @@ -270,7 +270,7 @@ 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; diff -u --recursive --new-file v1.3.81/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v1.3.81/linux/drivers/char/istallion.c Wed Mar 27 08:19:28 1996 +++ linux/drivers/char/istallion.c Tue Apr 2 08:43:06 1996 @@ -792,7 +792,7 @@ 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 @@ 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(); diff -u --recursive --new-file v1.3.81/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v1.3.81/linux/drivers/char/lp.c Sun Mar 24 20:07:00 1996 +++ linux/drivers/char/lp.c Tue Apr 2 08:43:06 1996 @@ -553,7 +553,7 @@ 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)); diff -u --recursive --new-file v1.3.81/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v1.3.81/linux/drivers/char/misc.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/char/misc.c Mon Apr 1 10:46:29 1996 @@ -20,15 +20,20 @@ * * 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 , + * adapted by Bjorn Ekwall + * corrected by Alan Cox */ +#include #include #include #include #include -#include #include #include #include @@ -37,6 +42,9 @@ #include /* needed by selection.h */ #include "selection.h" /* export its symbols */ +#ifdef CONFIG_KERNELD +#include +#endif /* * Head entry for the doubly linked miscdevice list @@ -76,17 +84,25 @@ 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 @@ void cleanup_module(void) { - unregister_chrdev(MOUSE_MAJOR, "misc"); + unregister_chrdev(MISC_MAJOR, "misc"); } #endif diff -u --recursive --new-file v1.3.81/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c --- v1.3.81/linux/drivers/char/msbusmouse.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/char/msbusmouse.c Tue Apr 2 08:43:06 1996 @@ -204,7 +204,7 @@ 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; } diff -u --recursive --new-file v1.3.81/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v1.3.81/linux/drivers/char/psaux.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/char/psaux.c Tue Apr 2 08:43:06 1996 @@ -491,7 +491,7 @@ #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 @@ } 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 { diff -u --recursive --new-file v1.3.81/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v1.3.81/linux/drivers/char/stallion.c Wed Mar 27 08:19:28 1996 +++ linux/drivers/char/stallion.c Tue Apr 2 08:43:07 1996 @@ -580,7 +580,7 @@ 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 @@ 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(); diff -u --recursive --new-file v1.3.81/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.3.81/linux/drivers/net/3c501.c Fri Mar 1 07:50:41 1996 +++ linux/drivers/net/3c501.c Mon Apr 1 10:46:29 1996 @@ -559,8 +559,9 @@ * 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); diff -u --recursive --new-file v1.3.81/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.3.81/linux/drivers/net/3c509.c Thu Mar 21 14:31:22 1996 +++ linux/drivers/net/3c509.c Mon Apr 1 10:46:29 1996 @@ -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, @@ -22,13 +22,14 @@ 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 @@ -64,7 +65,6 @@ #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 @@ 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 @@ 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 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 @@ -178,31 +186,46 @@ } #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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v1.3.81/linux/drivers/net/Config.in Mon Mar 25 08:58:20 1996 +++ linux/drivers/net/Config.in Mon Apr 1 10:46:29 1996 @@ -11,15 +11,16 @@ 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 @@ 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 @@ bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 fi + diff -u --recursive --new-file v1.3.81/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.81/linux/drivers/net/Makefile Sun Mar 31 00:13:17 1996 +++ linux/drivers/net/Makefile Tue Apr 2 07:22:04 1996 @@ -178,6 +178,14 @@ 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 @@ 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 @@ 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 @@ -480,6 +491,9 @@ $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $< slip.o: slip.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< + +strip.o: strip.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) -c $< dummy.o: dummy.c CONFIG diff -u --recursive --new-file v1.3.81/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.3.81/linux/drivers/net/Space.c Mon Mar 25 08:58:20 1996 +++ linux/drivers/net/Space.c Mon Apr 1 10:46:29 1996 @@ -198,7 +198,7 @@ /* 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 @@ #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 = { diff -u --recursive --new-file v1.3.81/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.3.81/linux/drivers/net/lance.c Sun Mar 10 09:28:56 1996 +++ linux/drivers/net/lance.c Mon Apr 1 10:46:30 1996 @@ -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 #include @@ -159,6 +159,14 @@ #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 @@ /* 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) */ + u8 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 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 @@ 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 @@ } #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 @@ lance_probe1(ioaddr); } } +#endif return 0; } @@ -363,6 +376,7 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 -u --recursive --new-file v1.3.81/linux/drivers/net/lance32.c linux/drivers/net/lance32.c --- v1.3.81/linux/drivers/net/lance32.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/lance32.c Mon Apr 1 10:46:30 1996 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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); + + + +/* 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; +} + + +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, + 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 */ + +} + + +/* + * 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: + */ diff -u --recursive --new-file v1.3.81/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v1.3.81/linux/drivers/net/plip.c Fri Mar 1 07:50:45 1996 +++ linux/drivers/net/plip.c Mon Apr 1 07:34:58 1996 @@ -290,12 +290,12 @@ 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; diff -u --recursive --new-file v1.3.81/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.3.81/linux/drivers/net/ppp.c Tue Mar 5 10:05:49 1996 +++ linux/drivers/net/ppp.c Mon Apr 1 10:50:01 1996 @@ -620,10 +620,10 @@ 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v1.3.81/linux/drivers/net/sdla.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/net/sdla.c Mon Apr 1 10:46:30 1996 @@ -393,6 +393,12 @@ 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 diff -u --recursive --new-file v1.3.81/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.3.81/linux/drivers/net/slhc.c Wed Feb 7 08:55:37 1996 +++ linux/drivers/net/slhc.c Tue Apr 2 08:43:07 1996 @@ -750,7 +750,7 @@ 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; } diff -u --recursive --new-file v1.3.81/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.3.81/linux/drivers/net/slip.c Sun Mar 10 10:00:03 1996 +++ linux/drivers/net/slip.c Tue Apr 2 08:43:07 1996 @@ -1201,7 +1201,7 @@ 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 @@ 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 -u --recursive --new-file v1.3.81/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v1.3.81/linux/drivers/net/strip.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/strip.c Mon Apr 1 10:46:30 1996 @@ -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 + * + * 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 +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_INET +#include +#include +#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: *
* + * eg. *0000-1164*SIP0 + */ + +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= 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 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 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 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 up address netmask ..." + * 6. strip_open_low gets called + * + * When the user runs "ifconfig st 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v1.3.81/linux/drivers/pci/pci.c Thu Mar 28 17:34:34 1996 +++ linux/drivers/pci/pci.c Mon Apr 1 11:04:10 1996 @@ -93,8 +93,8 @@ 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"), diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v1.3.81/linux/drivers/scsi/53c7,8xx.c Fri Mar 1 07:50:50 1996 +++ linux/drivers/scsi/53c7,8xx.c Tue Apr 2 09:01:55 1996 @@ -62,8 +62,15 @@ * the fourth byte from 50 to 25. */ +#include + +#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 @@ /* 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v1.3.81/linux/drivers/scsi/Config.in Thu Mar 14 12:57:45 1996 +++ linux/drivers/scsi/Config.in Tue Apr 2 08:43:04 1996 @@ -36,6 +36,10 @@ 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 diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v1.3.81/linux/drivers/scsi/aha1542.c Fri Mar 1 07:50:51 1996 +++ linux/drivers/scsi/aha1542.c Mon Apr 1 10:46:31 1996 @@ -646,7 +646,7 @@ 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; diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.3.81/linux/drivers/scsi/scsi.c Sat Mar 23 13:15:00 1996 +++ linux/drivers/scsi/scsi.c Mon Apr 1 10:46:31 1996 @@ -19,6 +19,10 @@ * * 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 */ /* @@ -26,6 +30,8 @@ * symbol tables. */ #define _SCSI_SYMS_VER_ + +#include #include #include @@ -44,7 +50,9 @@ #include "hosts.h" #include "constants.h" -#include +#ifdef CONFIG_KERNELD +#include +#endif #undef USE_STATIC_SCSI_MEMORY @@ -608,6 +616,15 @@ 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 */ if (!strncmp (scsi_result + 8, "TOSHIBA", 7) && @@ -3058,6 +3075,10 @@ /* 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 */ diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v1.3.81/linux/drivers/scsi/seagate.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/scsi/seagate.c Sat Mar 30 22:13:21 1996 @@ -1718,7 +1718,7 @@ * 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 @@ { heads *= 2; /* For some reason, they go in multiples */ cylinders = capacity / heads; - }; + } } ip[0] = heads; ip[1] = sectors; diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.3.81/linux/drivers/scsi/sr.c Sun Mar 31 00:13:17 1996 +++ linux/drivers/scsi/sr.c Tue Apr 2 08:43:04 1996 @@ -58,7 +58,8 @@ 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 @@ } /* - * 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 @@ * work now without running the program "set_density" * Multisession CD's are supported too. * - * kraxel@cs.tu-berlin.de (Gerd Knorr) + * Gerd Knorr */ /* * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ case SCSI_MAN_SONY: /* Thomas QUINOT */ 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 @@ 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 @@ 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 get_sectorsize(int i){ +void get_sectorsize(int i){ unsigned char cmd[10]; unsigned char *buffer; int the_result, retries; diff -u --recursive --new-file v1.3.81/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v1.3.81/linux/drivers/scsi/sr_ioctl.c Tue Mar 19 08:58:59 1996 +++ linux/drivers/scsi/sr_ioctl.c Mon Apr 1 10:46:31 1996 @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "scsi.h" @@ -13,6 +14,9 @@ #include +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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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. @@ -455,6 +482,38 @@ if (err) return err; memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl)); + 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; } diff -u --recursive --new-file v1.3.81/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards --- v1.3.81/linux/drivers/sound/Readme.cards Sun Mar 31 00:13:17 1996 +++ linux/drivers/sound/Readme.cards Mon Apr 1 12:56:43 1996 @@ -16,8 +16,9 @@ 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 @@ - 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v1.3.81/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v1.3.81/linux/fs/fat/inode.c Mon Mar 11 11:25:57 1996 +++ linux/fs/fat/inode.c Tue Apr 2 08:45:13 1996 @@ -502,7 +502,7 @@ 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)) || diff -u --recursive --new-file v1.3.81/linux/fs/nfs/Makefile linux/fs/nfs/Makefile --- v1.3.81/linux/fs/nfs/Makefile Tue Feb 20 09:51:05 1996 +++ linux/fs/nfs/Makefile Sun Mar 31 00:05:22 1996 @@ -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 -u --recursive --new-file v1.3.81/linux/fs/nfs/README linux/fs/nfs/README --- v1.3.81/linux/fs/nfs/README Thu Jan 1 02:00:00 1970 +++ linux/fs/nfs/README Sun Mar 31 20:27:59 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/fs/nfs/bio.c linux/fs/nfs/bio.c --- v1.3.81/linux/fs/nfs/bio.c Thu Jan 1 02:00:00 1970 +++ linux/fs/nfs/bio.c Sat Mar 30 23:54:01 1996 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 -u --recursive --new-file v1.3.81/linux/fs/nfs/cache.c linux/fs/nfs/cache.c --- v1.3.81/linux/fs/nfs/cache.c Thu Aug 31 08:09:06 1995 +++ linux/fs/nfs/cache.c Thu Jan 1 02:00:00 1970 @@ -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(ctinode_num==inode->i_no && !nh->dead&&!nh->free&&nh->file_pos==pos) - { - if(abs(jiffies-nh->time)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; -} diff -u --recursive --new-file v1.3.81/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v1.3.81/linux/fs/nfs/file.c Fri Mar 8 16:28:42 1996 +++ linux/fs/nfs/file.c Sat Mar 30 23:57:56 1996 @@ -33,7 +33,6 @@ 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 */ @@ -101,53 +100,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, diff -u --recursive --new-file v1.3.81/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v1.3.81/linux/fs/nfs/inode.c Sun Mar 24 20:07:00 1996 +++ linux/fs/nfs/inode.c Tue Apr 2 07:26:11 1996 @@ -17,16 +17,22 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include +/* This is for kernel_thread */ +#define __KERNEL_SYSCALLS__ +#include + extern int close_fp(struct file *filp); static int nfs_notify_change(struct inode *, struct iattr *); @@ -307,8 +313,39 @@ 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 -u --recursive --new-file v1.3.81/linux/fs/nfs/nfsiod.c linux/fs/nfs/nfsiod.c --- v1.3.81/linux/fs/nfs/nfsiod.c Thu Jan 1 02:00:00 1970 +++ linux/fs/nfs/nfsiod.c Sat Mar 30 23:54:23 1996 @@ -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 + */ + +#include +#include +#include +#include +#include + +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; +} diff -u --recursive --new-file v1.3.81/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v1.3.81/linux/fs/nfs/nfsroot.c Thu Mar 28 17:34:34 1996 +++ linux/fs/nfs/nfsroot.c Mon Apr 1 10:46:29 1996 @@ -38,6 +38,11 @@ * 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 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 @@ } /* 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 @@ 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 @@ #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 @@ ip = cp; num++; } + rarp_serv = server; } diff -u --recursive --new-file v1.3.81/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v1.3.81/linux/fs/nfs/proc.c Tue Feb 20 09:49:41 1996 +++ linux/fs/nfs/proc.c Sun Mar 31 00:09:49 1996 @@ -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 @@ 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 @@ 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) { diff -u --recursive --new-file v1.3.81/linux/fs/nfs/rpcsock.c linux/fs/nfs/rpcsock.c --- v1.3.81/linux/fs/nfs/rpcsock.c Tue Dec 26 06:03:00 1995 +++ linux/fs/nfs/rpcsock.c Sun Mar 31 00:34:56 1996 @@ -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 + * 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 */ #include @@ -31,70 +41,115 @@ #include #include +#include +#include + #include #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); + set_fs(oldfs); + + 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->sendmsg(sock, msg, len, 0, 0); + result = sock->ops->recvmsg(sock, &msg, len, 1, flags, &alen); set_fs(oldfs); - dprintk(("RPC: result = %d\n", result)); + dprintk("RPC: rpc_recvmsg(iov %p, len %d) = %d\n", iov, len, result); return result; } @@ -109,7 +164,7 @@ 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 @@ } 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; + struct rpc_ioreq *req = slot->w_req; + struct iovec iov[MAX_IOVEC]; + + 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; - 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; + int safe, result; - 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; + 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; } + } - 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: - return result; - } - } + 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; - /* 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; + /* 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; + + 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 (rovr->xid == xid) - break; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + if (rsock->shutdown) + return -EIO; + if (current->timeout == 0) + return -ETIMEDOUT; } - 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; + /* Wait for data to arrive */ + if ((result = rpc_select(rsock)) < 0) { + dprintk("RPC: select error = %d\n", result); + break; } - 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) -{ - struct rpc_wait *slot; - int result, retries; - unsigned long timeout; +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; - 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 @@ 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 @@ 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 diff -u --recursive --new-file v1.3.81/linux/fs/nfs/sock.c linux/fs/nfs/sock.c --- v1.3.81/linux/fs/nfs/sock.c Wed Feb 7 08:55:39 1996 +++ linux/fs/nfs/sock.c Sun Mar 31 00:05:22 1996 @@ -30,35 +30,49 @@ #include -/* 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 @@ | (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 @@ "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); } diff -u --recursive --new-file v1.3.81/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h --- v1.3.81/linux/include/asm-alpha/hwrpb.h Tue Aug 29 10:15:52 1995 +++ linux/include/asm-alpha/hwrpb.h Mon Apr 1 17:00:03 1996 @@ -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; diff -u --recursive --new-file v1.3.81/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v1.3.81/linux/include/asm-i386/system.h Sun Mar 3 13:14:50 1996 +++ linux/include/asm-i386/system.h Mon Apr 1 10:31:01 1996 @@ -192,9 +192,9 @@ #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: diff -u --recursive --new-file v1.3.81/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h --- v1.3.81/linux/include/asm-i386/termios.h Sun Mar 24 13:12:47 1996 +++ linux/include/asm-i386/termios.h Mon Apr 1 10:46:30 1996 @@ -51,6 +51,7 @@ #define N_SLIP 1 #define N_MOUSE 2 #define N_PPP 3 +#define N_STRIP 4 #ifdef __KERNEL__ diff -u --recursive --new-file v1.3.81/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v1.3.81/linux/include/linux/ax25.h Sat Mar 16 13:52:10 1996 +++ linux/include/linux/ax25.h Mon Apr 1 10:46:30 1996 @@ -65,6 +65,7 @@ #define AX25_HDRINCL 8 #define AX25_IDLE 9 #define AX25_PACLEN 10 +#define AX25_IPMAXQUEUE 11 #define AX25_KILL 99 @@ -109,6 +110,7 @@ #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 diff -u --recursive --new-file v1.3.81/linux/include/linux/aztcd.h linux/include/linux/aztcd.h --- v1.3.81/linux/include/linux/aztcd.h Sat Nov 25 17:28:41 1995 +++ linux/include/linux/aztcd.h Tue Apr 2 08:24:06 1996 @@ -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 @@ -22,6 +22,7 @@ * History: W.Zimmermann adaption to Aztech CD268-01A Version 1.3 * 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 diff -u --recursive --new-file v1.3.81/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v1.3.81/linux/include/linux/cdrom.h Fri Feb 23 09:39:34 1996 +++ linux/include/linux/cdrom.h Mon Apr 1 10:46:31 1996 @@ -149,6 +149,10 @@ 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) */ diff -u --recursive --new-file v1.3.81/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v1.3.81/linux/include/linux/if_arp.h Mon Mar 25 08:58:22 1996 +++ linux/include/linux/if_arp.h Mon Apr 1 10:46:30 1996 @@ -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 -u --recursive --new-file v1.3.81/linux/include/linux/if_strip.h linux/include/linux/if_strip.h --- v1.3.81/linux/include/linux/if_strip.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/if_strip.h Tue Apr 2 12:12:35 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h --- v1.3.81/linux/include/linux/miscdevice.h Sun Mar 31 00:13:18 1996 +++ linux/include/linux/miscdevice.h Sun Mar 31 16:36:42 1996 @@ -17,7 +17,7 @@ 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 diff -u --recursive --new-file v1.3.81/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v1.3.81/linux/include/linux/nfs_fs.h Thu Mar 28 17:34:34 1996 +++ linux/include/linux/nfs_fs.h Sun Mar 31 00:05:22 1996 @@ -92,13 +92,20 @@ 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 */ @@ -125,6 +132,10 @@ /* linux/fs/nfs/mmap.c */ 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 */ diff -u --recursive --new-file v1.3.81/linux/include/linux/nfsiod.h linux/include/linux/nfsiod.h --- v1.3.81/linux/include/linux/nfsiod.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/nfsiod.h Sun Mar 31 00:22:58 1996 @@ -0,0 +1,42 @@ +/* + * linux/include/linux/nfsiod.h + * + * Declarations for asynchronous NFS RPC calls. + * + */ + +#ifndef _LINUX_NFSIOD_H +#define _LINUX_NFSIOD_H + +#include + +#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 */ diff -u --recursive --new-file v1.3.81/linux/include/linux/rpcsock.h linux/include/linux/rpcsock.h --- v1.3.81/linux/include/linux/rpcsock.h Mon Oct 23 10:49:11 1995 +++ linux/include/linux/rpcsock.h Sun Mar 31 00:05:22 1996 @@ -1,54 +1,118 @@ /* * rpcsock.h Declarations for the RPC call interface. * - * Coypright (C) 1995 Olaf Kirch - * + * Coypright (C) 1995, 1996 Olaf Kirch */ #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; }; -/* Wait information */ +/* + * 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; +}; + +/* + * 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 *); diff -u --recursive --new-file v1.3.81/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v1.3.81/linux/include/linux/sysctl.h Sun Mar 10 10:06:09 1996 +++ linux/include/linux/sysctl.h Tue Apr 2 08:43:07 1996 @@ -69,6 +69,33 @@ /* 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: */ diff -u --recursive --new-file v1.3.81/linux/include/linux/tqueue.h linux/include/linux/tqueue.h --- v1.3.81/linux/include/linux/tqueue.h Sat Mar 16 14:29:21 1996 +++ linux/include/linux/tqueue.h Mon Apr 1 11:03:53 1996 @@ -16,12 +16,6 @@ #include #include -#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 @@ 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 @@ * "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 @@ * 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 @@ /* * 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 @@ /* * 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; @@ -153,7 +139,5 @@ (*f)(arg); } } - -#undef _INLINE_ #endif /* _LINUX_TQUEUE_H */ diff -u --recursive --new-file v1.3.81/linux/include/net/ax25.h linux/include/net/ax25.h --- v1.3.81/linux/include/net/ax25.h Mon Mar 25 10:24:40 1996 +++ linux/include/net/ax25.h Tue Apr 2 12:28:47 1996 @@ -126,6 +126,7 @@ #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 @@ 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 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 */ diff -u --recursive --new-file v1.3.81/linux/include/net/sock.h linux/include/net/sock.h --- v1.3.81/linux/include/net/sock.h Mon Mar 25 10:24:40 1996 +++ linux/include/net/sock.h Tue Apr 2 12:28:47 1996 @@ -237,7 +237,7 @@ */ 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 @@ } +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); diff -u --recursive --new-file v1.3.81/linux/init/main.c linux/init/main.c --- v1.3.81/linux/init/main.c Thu Mar 28 17:34:34 1996 +++ linux/init/main.c Mon Apr 1 13:56:12 1996 @@ -434,6 +434,54 @@ ((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 @@ 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 @@ * 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 diff -u --recursive --new-file v1.3.81/linux/kernel/exit.c linux/kernel/exit.c --- v1.3.81/linux/kernel/exit.c Sat Mar 23 14:31:02 1996 +++ linux/kernel/exit.c Sun Mar 31 20:39:57 1996 @@ -23,25 +23,28 @@ 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) diff -u --recursive --new-file v1.3.81/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.3.81/linux/kernel/ksyms.c Wed Mar 27 08:19:29 1996 +++ linux/kernel/ksyms.c Mon Apr 1 07:34:13 1996 @@ -244,7 +244,6 @@ X(tq_timer), X(tq_immediate), X(tq_scheduler), - X(tq_last), X(timer_active), X(timer_table), X(intr_count), diff -u --recursive --new-file v1.3.81/linux/kernel/sched.c linux/kernel/sched.c --- v1.3.81/linux/kernel/sched.c Sun Mar 31 00:13:19 1996 +++ linux/kernel/sched.c Mon Apr 1 10:32:07 1996 @@ -290,15 +290,15 @@ /* 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 @@ if (timeout) del_timer(&timer); } + return; + +scheduling_in_interrupt: + printk("Aiee: scheduling in interrupt\n"); } #ifndef __alpha__ @@ -1028,7 +1032,7 @@ prof_buffer[ip]++; } } - if (tq_timer != &tq_last) + if (tq_timer) mark_bh(TQUEUE_BH); } diff -u --recursive --new-file v1.3.81/linux/kernel/softirq.c linux/kernel/softirq.c --- v1.3.81/linux/kernel/softirq.c Thu Mar 28 17:34:35 1996 +++ linux/kernel/softirq.c Mon Apr 1 08:36:26 1996 @@ -8,9 +8,6 @@ * bottom_half handler need not be re-entrant. */ -#define INCLUDE_INLINE_FUNCS -#include - #include #include #include @@ -23,7 +20,6 @@ #include #include #include - unsigned long intr_count = 0; diff -u --recursive --new-file v1.3.81/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v1.3.81/linux/kernel/sysctl.c Fri Mar 15 10:21:12 1996 +++ linux/kernel/sysctl.c Tue Apr 2 08:43:07 1996 @@ -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 @@ -38,6 +39,7 @@ static ctl_table kern_table[]; static ctl_table vm_table[]; +extern ctl_table net_table[]; /* /proc declarations: */ @@ -100,6 +102,7 @@ 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} }; diff -u --recursive --new-file v1.3.81/linux/mm/filemap.c linux/mm/filemap.c --- v1.3.81/linux/mm/filemap.c Thu Mar 28 17:34:35 1996 +++ linux/mm/filemap.c Mon Apr 1 14:15:01 1996 @@ -367,9 +367,12 @@ 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 @@ 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 @@ 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); } diff -u --recursive --new-file v1.3.81/linux/net/802/Makefile linux/net/802/Makefile --- v1.3.81/linux/net/802/Makefile Sun Mar 31 00:13:19 1996 +++ linux/net/802/Makefile Tue Apr 2 08:43:08 1996 @@ -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 -u --recursive --new-file v1.3.81/linux/net/802/sysctl_net_802.c linux/net/802/sysctl_net_802.c --- v1.3.81/linux/net/802/sysctl_net_802.c Thu Jan 1 02:00:00 1970 +++ linux/net/802/sysctl_net_802.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table e802_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/Makefile linux/net/Makefile --- v1.3.81/linux/net/Makefile Mon Mar 25 08:58:23 1996 +++ linux/net/Makefile Tue Apr 2 08:43:08 1996 @@ -41,7 +41,7 @@ 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 diff -u --recursive --new-file v1.3.81/linux/net/appletalk/Makefile linux/net/appletalk/Makefile --- v1.3.81/linux/net/appletalk/Makefile Mon Mar 25 08:58:23 1996 +++ linux/net/appletalk/Makefile Tue Apr 2 08:43:08 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v1.3.81/linux/net/appletalk/ddp.c Sun Mar 31 00:13:19 1996 +++ linux/net/appletalk/ddp.c Tue Apr 2 08:43:07 1996 @@ -219,7 +219,7 @@ 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 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 @@ case SOCK_DGRAM: break; default: - kfree_s((void *)sk,sizeof(*sk)); + sk_free((void *)sk); return(-ESOCKTNOSUPPORT); } @@ -1364,7 +1364,7 @@ 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 @@ 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 -u --recursive --new-file v1.3.81/linux/net/appletalk/sysctl_net_atalk.c linux/net/appletalk/sysctl_net_atalk.c --- v1.3.81/linux/net/appletalk/sysctl_net_atalk.c Thu Jan 1 02:00:00 1970 +++ linux/net/appletalk/sysctl_net_atalk.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table atalk_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/ax25/Makefile linux/net/ax25/Makefile --- v1.3.81/linux/net/ax25/Makefile Wed Aug 16 13:03:17 1995 +++ linux/net/ax25/Makefile Tue Apr 2 08:43:08 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v1.3.81/linux/net/ax25/af_ax25.c Mon Mar 25 08:58:24 1996 +++ linux/net/ax25/af_ax25.c Mon Apr 1 10:46:30 1996 @@ -72,12 +72,15 @@ * 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 @@ 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 @@ 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 @@ */ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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_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 @@ 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 @@ *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 @@ * 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 @@ 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 diff -u --recursive --new-file v1.3.81/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v1.3.81/linux/net/ax25/ax25_in.c Wed Mar 20 14:15:53 1996 +++ linux/net/ax25/ax25_in.c Mon Apr 1 10:46:30 1996 @@ -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) */ diff -u --recursive --new-file v1.3.81/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v1.3.81/linux/net/ax25/ax25_out.c Sun Mar 10 09:28:57 1996 +++ linux/net/ax25/ax25_out.c Mon Apr 1 10:46:30 1996 @@ -26,8 +26,10 @@ * 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 @@ -61,7 +63,8 @@ { 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 @@ 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 @@ ax25->condition = 0x00; ax25->n2count = 0; - ax25->t3timer = 0; + ax25->t3timer = ax25->t3; ax25->t2timer = 0; ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); } diff -u --recursive --new-file v1.3.81/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v1.3.81/linux/net/ax25/ax25_route.c Sat Mar 16 13:52:11 1996 +++ linux/net/ax25/ax25_route.c Mon Apr 1 10:46:30 1996 @@ -31,10 +31,10 @@ * 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 @@ 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 @@ 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 @@ 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,10 +784,12 @@ 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; diff -u --recursive --new-file v1.3.81/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v1.3.81/linux/net/ax25/ax25_subr.c Wed Mar 20 14:15:19 1996 +++ linux/net/ax25/ax25_subr.c Mon Apr 1 10:46:31 1996 @@ -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 @@ -471,6 +473,46 @@ /* Finish off */ 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); } /* diff -u --recursive --new-file v1.3.81/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c --- v1.3.81/linux/net/ax25/ax25_timer.c Sat Mar 16 13:52:11 1996 +++ linux/net/ax25/ax25_timer.c Mon Apr 1 10:46:31 1996 @@ -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 @@ -180,8 +181,12 @@ 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 @@ else ax25->state = AX25_STATE_2; - ax25->t3timer = 0; ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); if (ax25->sk != NULL) diff -u --recursive --new-file v1.3.81/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v1.3.81/linux/net/ax25/sysctl_net_ax25.c Thu Jan 1 02:00:00 1970 +++ linux/net/ax25/sysctl_net_ax25.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table ax25_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/core/Makefile linux/net/core/Makefile --- v1.3.81/linux/net/core/Makefile Tue Dec 12 07:05:07 1995 +++ linux/net/core/Makefile Tue Apr 2 08:43:08 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v1.3.81/linux/net/core/skbuff.c Mon Mar 25 08:10:56 1996 +++ linux/net/core/skbuff.c Sun Mar 31 18:02:42 1996 @@ -628,9 +628,9 @@ 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); } diff -u --recursive --new-file v1.3.81/linux/net/core/sock.c linux/net/core/sock.c --- v1.3.81/linux/net/core/sock.c Wed Mar 20 15:57:00 1996 +++ linux/net/core/sock.c Mon Apr 1 10:46:31 1996 @@ -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 @@ 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 @@ 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 -u --recursive --new-file v1.3.81/linux/net/core/sysctl_net_core.c linux/net/core/sysctl_net_core.c --- v1.3.81/linux/net/core/sysctl_net_core.c Thu Jan 1 02:00:00 1970 +++ linux/net/core/sysctl_net_core.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table core_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/ethernet/Makefile linux/net/ethernet/Makefile --- v1.3.81/linux/net/ethernet/Makefile Tue Aug 15 15:07:03 1995 +++ linux/net/ethernet/Makefile Tue Apr 2 08:43:08 1996 @@ -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 -u --recursive --new-file v1.3.81/linux/net/ethernet/sysctl_net_ether.c linux/net/ethernet/sysctl_net_ether.c --- v1.3.81/linux/net/ethernet/sysctl_net_ether.c Thu Jan 1 02:00:00 1970 +++ linux/net/ethernet/sysctl_net_ether.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table ether_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- v1.3.81/linux/net/ipv4/Makefile Sun Mar 31 00:13:19 1996 +++ linux/net/ipv4/Makefile Tue Apr 2 08:43:08 1996 @@ -12,7 +12,8 @@ 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 := diff -u --recursive --new-file v1.3.81/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v1.3.81/linux/net/ipv4/af_inet.c Sun Mar 31 00:13:19 1996 +++ linux/net/ipv4/af_inet.c Mon Apr 1 10:46:31 1996 @@ -407,7 +407,7 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ break; default: - kfree_s((void *)sk, sizeof(*sk)); + sk_free(sk); return(-ESOCKTNOSUPPORT); } sk->socket = sock; @@ -655,7 +655,6 @@ 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; diff -u --recursive --new-file v1.3.81/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.81/linux/net/ipv4/arp.c Sun Mar 31 00:13:19 1996 +++ linux/net/ipv4/arp.c Mon Apr 1 10:46:31 1996 @@ -1023,6 +1023,7 @@ #endif case ARPHRD_ETHER: case ARPHRD_ARCNET: + case ARPHRD_METRICOM: if(arp->ar_pro != htons(ETH_P_IP)) { kfree_skb(skb, FREE_READ); diff -u --recursive --new-file v1.3.81/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v1.3.81/linux/net/ipv4/ip_masq.c Sun Mar 31 00:13:19 1996 +++ linux/net/ipv4/ip_masq.c Mon Apr 1 10:46:31 1996 @@ -346,7 +346,7 @@ save_flags(flags); cli(); - if (ip_masq_free_ports == 0) { + if (*free_ports_p == 0) { restore_flags(flags); break; } diff -u --recursive --new-file v1.3.81/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v1.3.81/linux/net/ipv4/sysctl_net_ipv4.c Thu Jan 1 02:00:00 1970 +++ linux/net/ipv4/sysctl_net_ipv4.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table ipv4_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v1.3.81/linux/net/ipv4/tcp.c Fri Mar 15 09:32:32 1996 +++ linux/net/ipv4/tcp.c Sun Mar 31 20:07:11 1996 @@ -1439,6 +1439,17 @@ 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 @@ schedule(); sk->socket->flags &= ~SO_WAITDATA; lock_sock(sk); - - if (current->signal & ~current->blocked) - { - copied = -ERESTARTSYS; - break; - } continue; found_ok_skb: diff -u --recursive --new-file v1.3.81/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v1.3.81/linux/net/ipv4/tcp_input.c Thu Mar 21 17:08:06 1996 +++ linux/net/ipv4/tcp_input.c Sun Mar 31 20:21:24 1996 @@ -398,7 +398,6 @@ 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; diff -u --recursive --new-file v1.3.81/linux/net/ipx/Makefile linux/net/ipx/Makefile --- v1.3.81/linux/net/ipx/Makefile Mon Mar 25 08:58:25 1996 +++ linux/net/ipx/Makefile Tue Apr 2 08:43:08 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v1.3.81/linux/net/ipx/af_ipx.c Sun Mar 31 00:13:19 1996 +++ linux/net/ipx/af_ipx.c Tue Apr 2 08:43:07 1996 @@ -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. + * Revision 0.35: Checksum support. , hooked in by * * Portions Copyright (c) 1995 Caldera, Inc. * Neither Greg Page nor Caldera, Inc. admit liability nor provide @@ -193,7 +194,7 @@ kfree_skb(skb,FREE_READ); } - kfree_s(sk,sizeof(*sk)); + sk_free(sk); MOD_DEC_USE_COUNT; } @@ -907,8 +908,8 @@ 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 @@ 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); } @@ -1172,6 +1178,65 @@ } /* + * 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 @@ /* 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 @@ 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 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 @@ 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 @@ 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 @@ 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)ipx_pktsize)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 @@ 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 @@ } 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 @@ 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 -u --recursive --new-file v1.3.81/linux/net/ipx/sysctl_net_ipx.c linux/net/ipx/sysctl_net_ipx.c --- v1.3.81/linux/net/ipx/sysctl_net_ipx.c Thu Jan 1 02:00:00 1970 +++ linux/net/ipx/sysctl_net_ipx.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table ipx_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/netrom/Makefile linux/net/netrom/Makefile --- v1.3.81/linux/net/netrom/Makefile Wed Sep 27 13:07:34 1995 +++ linux/net/netrom/Makefile Tue Apr 2 08:43:08 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v1.3.81/linux/net/netrom/af_netrom.c Mon Mar 25 08:58:26 1996 +++ linux/net/netrom/af_netrom.c Mon Apr 1 10:46:31 1996 @@ -266,7 +266,7 @@ 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 @@ 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 @@ 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 @@ struct sk_buff *skb; if (newsock->data) - kfree_s(newsock->data, sizeof(struct sock)); + sk_free(newsock->data); newsock->data = NULL; diff -u --recursive --new-file v1.3.81/linux/net/netrom/sysctl_net_netrom.c linux/net/netrom/sysctl_net_netrom.c --- v1.3.81/linux/net/netrom/sysctl_net_netrom.c Thu Jan 1 02:00:00 1970 +++ linux/net/netrom/sysctl_net_netrom.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table netrom_table[] = { + {0} +}; diff -u --recursive --new-file v1.3.81/linux/net/sysctl_net.c linux/net/sysctl_net.c --- v1.3.81/linux/net/sysctl_net.c Thu Jan 1 02:00:00 1970 +++ linux/net/sysctl_net.c Tue Apr 2 08:43:08 1996 @@ -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 +#include +#include + +#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} +}; diff -u --recursive --new-file v1.3.81/linux/net/unix/Makefile linux/net/unix/Makefile --- v1.3.81/linux/net/unix/Makefile Mon Mar 4 09:16:41 1996 +++ linux/net/unix/Makefile Tue Apr 2 08:43:08 1996 @@ -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 diff -u --recursive --new-file v1.3.81/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v1.3.81/linux/net/unix/af_unix.c Mon Mar 25 08:58:28 1996 +++ linux/net/unix/af_unix.c Mon Apr 1 10:46:31 1996 @@ -148,7 +148,7 @@ { 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 @@ { 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 @@ 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 @@ case SOCK_DGRAM: break; default: - kfree_s(sk,sizeof(*sk)); + sk_free(sk); return -ESOCKTNOSUPPORT; } sk->type=sock->type; diff -u --recursive --new-file v1.3.81/linux/net/unix/sysctl_net_unix.c linux/net/unix/sysctl_net_unix.c --- v1.3.81/linux/net/unix/sysctl_net_unix.c Thu Jan 1 02:00:00 1970 +++ linux/net/unix/sysctl_net_unix.c Tue Apr 2 09:03:35 1996 @@ -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 +#include + +ctl_table unix_table[] = { + {0} +};