diff -u --recursive --new-file v1.3.98/linux/CREDITS linux/CREDITS --- v1.3.98/linux/CREDITS Mon Apr 29 18:05:14 1996 +++ linux/CREDITS Tue May 7 12:06:49 1996 @@ -122,6 +122,14 @@ D: Author and maintainer of the QIC-02 tape driver S: The Netherlands +N: Thomas Bogendoerfer +E: tsbogend@bigbug.franken.de +D: Lance32 driver +D: strace for Linux/Alpha +S: Baumgartenweg 5 +S: 91452 Wilhermsdorf +S: Germany + N: Ross Biro E: bir7@leland.Stanford.Edu D: Original author of the Linux networking code @@ -424,14 +432,6 @@ S: Toronto, Ontario, M5S 3A6 S: Canada -N: Miquel van Smoorenburg -E: miquels@cistron.nl -D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff. -S: Cistron Internet Services -S: PO-Box 297 -S: 2400 AG, Alphen aan den Rijn -S: The Netherlands - N: Danny ter Haar E: dth@cistron.nl D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;) @@ -1085,6 +1085,14 @@ D: HPFS filesystem S: Richardson, Texas S: USA + +N: Miquel van Smoorenburg +E: miquels@cistron.nl +D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff. +S: Cistron Internet Services +S: PO-Box 297 +S: 2400 AG, Alphen aan den Rijn +S: The Netherlands N: Scott Snyder E: snyder@fnald0.fnal.gov diff -u --recursive --new-file v1.3.98/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.98/linux/Documentation/Configure.help Sun May 5 08:51:57 1996 +++ linux/Documentation/Configure.help Mon May 6 12:26:01 1996 @@ -45,7 +45,7 @@ internals are usually welcomed by the developers. Unless you intend to help test and develop a feature or driver that falls into this category, you should probably say N here, which will cause this - configure script to present you with less choices. If you say Y here, + configure script to present you with fewer choices. If you say Y here, you will be offered the choice of using features or drivers that are currently considered to be in the alpha-test phase. @@ -1261,7 +1261,7 @@ kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. -EATA-DMA (DPT, NEC, ATT, Olivetti for ISA, EISA, PCI) support +EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support CONFIG_SCSI_EATA_DMA This is support for the EATA-DMA protocol compliant SCSI Host Adaptors like the SmartCache III/IV, SmartRAID controller families and the DPT diff -u --recursive --new-file v1.3.98/linux/Documentation/SMP.txt linux/Documentation/SMP.txt --- v1.3.98/linux/Documentation/SMP.txt Fri Apr 12 15:51:43 1996 +++ linux/Documentation/SMP.txt Mon May 6 12:26:01 1996 @@ -14,7 +14,7 @@ o Clean up processor specific/independent split. o Document it all. [PARTLY DONE] o Halt other CPU's on reset/panic doesn't always work. -o Dont waste page at 4K - dont need it now.(watch the GDT code). +o Don't waste page at 4K - don't need it now.(watch the GDT code). o Dump bootup pages once booted somehow. o Clean up warnings/volatiles. o Fix load_TR() for non contiguous processor ids diff -u --recursive --new-file v1.3.98/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v1.3.98/linux/Documentation/devices.tex Sun Apr 21 19:21:58 1996 +++ linux/Documentation/devices.tex Mon May 6 08:35:53 1996 @@ -42,7 +42,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: April 20, 1996} +\date{Last revised: May 5, 1996} \maketitle % \noindent @@ -156,6 +156,7 @@ \major{39}{}{char }{ML-16P experimental I/O board} \major{ }{}{block}{Reserved for Linux/AP+} \major{40}{}{char }{Matrox Meteor frame grabber} +\major{ }{}{block}{Syquest EZ135 removable drive} \major{41}{}{char }{Yet Another Micro Monitor} \major{42}{}{}{Demo/sample use} \major{43}{}{char }{isdn4linux virtual modem} @@ -165,7 +166,8 @@ \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices} \major{48}{}{char }{SDL RISCom serial card} \major{49}{}{char }{SDL RISCom serial card -- alternate devices} -\major{50}{--59}{}{Unallocated} +\major{50}{}{char }{Reserved for GLINT} +\major{51}{--59}{}{Unallocated} \major{60}{--63}{}{Local/experimental use} \major{64}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} @@ -942,7 +944,14 @@ \begin{devicelist} \major{40}{}{char }{Matrox Meteor frame grabber} \minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber} +\\ +\major{ }{}{block}{Syquest EZ135 removable drive} + \minor{0}{/dev/eza}{First EZ135 drive whole disk} \end{devicelist} + +\noindent +Partitions are handled the same way as for IDE disks (see major number +3). \begin{devicelist} \major{41}{}{char }{Yet Another Micro Monitor} diff -u --recursive --new-file v1.3.98/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v1.3.98/linux/Documentation/devices.txt Wed Apr 24 17:00:33 1996 +++ linux/Documentation/devices.txt Mon May 6 08:35:53 1996 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - Last revised: April 20, 1996 + Last revised: May 5, 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 @@ -621,6 +621,8 @@ and "user level packet I/O." This board is also accessible as a standard networking "eth" device. + block Reserved for Linux/AP+ + 39 char ML-16P experimental I/O board 0 = /dev/ml16pa-a0 First card, first analog channel 1 = /dev/ml16pa-a1 First card, second analog channel @@ -643,7 +645,11 @@ 40 char Matrox Meteor frame grabber 0 = /dev/mmetfgrab Matrox Meteor frame grabber - block Reserved for Linux/AP+ + block Syquest EZ135 removable drive + 0 = /dev/eza First EZ135 drive, whole disk + + Partitions are handled in the same way as IDE disks + (see major number 3). 41 char Yet Another Micro Monitor 0 = /dev/yamm Yet Another Micro Monitor diff -u --recursive --new-file v1.3.98/linux/Documentation/filesystems/affs.txt linux/Documentation/filesystems/affs.txt --- v1.3.98/linux/Documentation/filesystems/affs.txt Sat Apr 27 15:19:44 1996 +++ linux/Documentation/filesystems/affs.txt Mon May 6 12:44:30 1996 @@ -1,3 +1,109 @@ +Amiga filesystems Overview +========================== + +Not all varieties of the Amiga filesystems are supported. The Amiga +currently knows 6 different filesystems: + +DOS\0 The old or original filesystem, not really suited for + hard disks and normally not used on them, either. + Not supported. + +DOS\1 The original Fast File System. Supported. + +DOS\2 The old "international" filesystem. International means that + a bug has been fixed so that accented ("international") letters + in file names are case-insensitive, as they ought to be. + Not supported. + +DOS\3 The "international" Fast File System. Supported. + +DOS\4 The original filesystem with directory cache. The directory + cache speeds up directory accesses on floppies considerably, + but slowes down file creation/deletion. Doesn't make much + sense on hard disks. Not supported. + +DOS\5 The Fast File System with directory cache. Not supported. + +All of the above filesystems allow block sizes from 512 to 32K bytes. +Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks +speed up almost everything with the expense of wasted disk space. The speed +gain above 4K seems not really worth the price, so you don't lose too +much here, either. + +Mount options for the AFFS +========================== + +protect If this option is set, the protection bits cannot be altered. + +uid[=uid] This sets the uid of the root directory (i. e. the mount point + to uid or to the uid of the current user, if the =uid is + ommitted. + +gid[=gid] Same as above, but for gid. + +setuid[=uid] This sets the owner of all files and directories in the file + system to uid or the uid of the current user, respectively. + +setgid[=gid] Same as above, but for gid. + +use_mp The uid and gid are taken from the now covered mount point + instead of the current user or value defined. + +mode=mode Sets the mode flags to the given (octal) value, regardles + of the original permissions. Directories will get an x + permission, if the corresponding r bit is set. + This is useful since most of the plain AmigaOS files + will map to 600. + +reserved=num Sets the number of reserved blocks at the start of the + partition to num. Default is 2. + +root=block Sets the block number of the root block. This schould never + be neccessary. + +bs=blksize Sets the blocksize to blksize. Valid block sizes are 512, + 1024, 2048 and 4096. Like the root option, this should + never be neccessary, as the affs can figure it out itself. + +quiet The file system will not return an error for disallowed + mode changes. + +Handling of the Users/Groups and protection flags +================================================= + +Amiga -> Linux: + +The Amiga protection flags RWEDRWEDHSPARWED are handled as follows: + + - R maps to r for user, group and others. On directories, R implies x. + + - If both W and D are allowed, w will be set. + + - If both R and S are set, x will be set. + + - H, P and E are always retained and ignored under Linux. + + - A is always reset when written. + +User id and group id will be used unless set[gu]id are given as mount +options. Since most of the Amiga file systems are single user systems +they will be owned by root. + +Linux -> Amiga: + +The Linux rwxrwxrwx file mode is handled as follows: + + - r permission will set R for user, group and others. + + - w permission will set W and D for user, group and others. + + - x permission of the user will set S for plain files. + + - All other flags (suid, sgid, ...) are ignored and will + not be retained. + +Newly created files and directories will get the user and group id +of the current user and a mode according to the umask. Linux can read, but not write, Amiga FFS partitions. Mount options are diff -u --recursive --new-file v1.3.98/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v1.3.98/linux/Documentation/ioctl-number.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/ioctl-number.txt Tue May 7 07:50:53 1996 @@ -0,0 +1,98 @@ +Ioctl Numbers +6 May 1996 +Michael Chastain + + +If you are adding new ioctl's to the kernel, you should use the _IO +macros defined in : + + _IO an ioctl with no parameters + _IOW an ioctl with write parameters (from user's point of view) + _IOR an ioctl with read parameters (from user's point of view) + _IOWR an ioctl with both write and read parameters. + +'Write' and 'read' are from the user's point of view. This is like the +system calls 'write' and 'read'. For example, a SET_FOO ioctl would be +_IOW, although the kernel would actually read data from user space; a +GET_FOO ioctl would be _IOR, although the kernel would actually write +data to user space. + +The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter +or number from the table below. If you are writing a driver for a new +device and need a letter, pick an unused letter. You can register the +letter by patching this file and submitting the patch to Linus Torvalds. +Or you can e-mail me at and I'll register one +for you. + +The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number +to distinguish ioctls from each other. The third argument is a size +of the structure going into the kernel or coming out of the kernel. + +Some devices use their major number as the identifier; this is not +recommended. Some devices are even more irregular and don't follow +the convention at all. + +Following the convention is good because: + +(1) Keeping the ioctl's globally unique helps error checking: + if a program calls an ioctl on the wrong device, it will get an + error rather than some unexpected behaviour. + +(2) The 'strace' build procedure automatically finds ioctl numbers + defined with _IO, _IOW, _IOR, or _IOWR. + +(3) 'strace' can decode numbers back into useful names when the + numbers are unique. + +(4) People looking for ioctls can grep for them more easily when + the convention is used to define the ioctl numbers. + +(5) When following the convention, the driver code can use generic + code to call verify_area to validate parameters. + +This table is current to Linux 1.3.98. + +Ioctl Include File Comments +======================================================== +0x00 linux/fs.h only FIBMAP, FIGETBSZ +0x00 linux/random.h codes in 0x010800NN +0x00 linux/mc146818rtc.h conflict! +0x02 linux/fd.h +0x03 linux/hdreg.h +0x04 linux/umsdos_fs.h +0x06 linux/lp.h +0x09 linux/md.h +0x12 linux/fs.h +0x20 linux/cm206.h +0x22 linux/scc.h conflict! +0x22 scsi/sg.h conflict! +'A' linux/apm_bios.h +'C' linux/soundcard.h +'F' linux/fb.h +'I' linux/isdn.h +'K' linux/kd.h +'L' linux/loop.h +'M' linux/soundcard.h +'P' linux/soundcard.h +'Q' linux/soundcard.h +'S' linux/cdrom.h conflict! +'S' scsi/scsi.h conflict! +'S' scsi/scsi_ioctl.h conflict! +'T' linux/soundcard.h conflict! +'T' asm/ioctls.h conflict! +'V' linux/vt.h +'Y' linux/cyclades.h codes in 0x004359NN +'a' various, see http://lrcwww.epfl.ch/linux-atm/magic.html +'c' linux/comstats.h +'f' linux/ext2_fs.h +'m' linux/mtio.h conflict! +'m' linux/soundcard.h conflict! +'n' linux/ncp_fs.h +'r' linux/msdos_fs.h +'s' linux/cdk.h +'t' linux/if_ppp.h no conflict +'t' linux/isdn_ppp.h no conflict +'u' linux/smb_fs.h +'v' linux/ext2_fs.h +0x89 asm/sockios.h no conflict +0x89 linux/sockios.h no conflict diff -u --recursive --new-file v1.3.98/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v1.3.98/linux/Documentation/isdn/INTERFACE Fri Apr 12 15:51:44 1996 +++ linux/Documentation/isdn/INTERFACE Mon May 6 12:26:01 1996 @@ -48,7 +48,7 @@ To be preset by the HL-driver, if it supports sk_buff's. The driver should put here the amount of additional space needed in sk-buff's for - it's internal purposes. Drivers not supporting sk_buff's should put + its internal purposes. Drivers not supporting sk_buff's should put initialize this field to 0. void (*rcvcallb)(int, int, u_char*, int); @@ -68,7 +68,7 @@ This field will be set by LL. The HL-driver delivers received data- packets by calling this function. Upon calling, the HL-driver must - already have it's private data pulled off the head of the sk_buff. + already have its private data pulled off the head of the sk_buff. Parameter: int driver-Id @@ -83,8 +83,8 @@ Parameter: isdn_ctrl* - The struct isdn_ctrl also defined in isdn_if. The exact meaning of it's - fields is described together with the descriptions of the possible + The struct isdn_ctrl also defined in isdn_if. The exact meanings of its + fields are described together with the descriptions of the possible events. Here is only a short description of the fields: driver = driver Id. @@ -196,7 +196,7 @@ char id[20]; ***CHANGE0.7: New since this version. - This string has to be preset by the HL-driver. It's purpose is for + This string has to be preset by the HL-driver. Its purpose is for identification of the driver by the user. Eg.: it is shown in the status-info of /dev/isdninfo. Furthermore it is used as Id for binding net-interfaces to a specific channel. If a string of length zero is diff -u --recursive --new-file v1.3.98/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v1.3.98/linux/Documentation/isdn/README Sun Apr 21 19:21:59 1996 +++ linux/Documentation/isdn/README Mon May 6 12:26:01 1996 @@ -308,7 +308,7 @@ 3.2.1 Teles driver. The module teles.o can be configured during "insmod'ing" it by - appending it's parameters to the insmod-commandline. The following + appending its parameters to the insmod-commandline. The following syntax is accepted: io=m0,i0,p0,d0[,m1,i1,p1,d1 ... ,mn,in,pn,dn] teles_id=idstring @@ -323,7 +323,7 @@ 3.2.2 ICN driver. The module icn.o can be configured during "insmod'ing" it by - appending it's parameters to the insmod-commandline. The following + appending its parameters to the insmod-commandline. The following syntax is accepted: portbase=p membase=m icn_id=idstring icn_id2=idstring2 @@ -347,7 +347,7 @@ 4. Device-inodes - The major and minor-numbers and it's names are described in + The major and minor-numbers and its names are described in Documentation/devices.txt. The major-numbers are: 43 for the ISDN-tty's. @@ -494,7 +494,7 @@ cisco-h A special-mode for communicating with a Cisco, which is configured to do "hdlc" ethernet No stripping. Packets are sent with full MAC-header. - The Ethernet-address of the interface is faked, from it's + The Ethernet-address of the interface is faked, from its IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values. syncppp Synchronous PPP @@ -553,7 +553,7 @@ "isdnctrl sdelay secs." This sets the minimum time an Interface has to be fully loaded, until - it sends an dial-request to it's slave. + it sends a dial-request to its slave. "isdnctrl dial " Forces an interface to start dialing even if no packets are to be diff -u --recursive --new-file v1.3.98/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt --- v1.3.98/linux/Documentation/magic-number.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/magic-number.txt Tue May 7 07:50:53 1996 @@ -0,0 +1,61 @@ +This file is a registry of magic numbers which are in use. When you +add a magic number to a structure, you should also add it to this +file, since it is best if the magic numbers used by various structures +are unique. + +It is a *very* good idea to protect kernel data structures with magic +numbers. This allows you to check at run time whether (a) a structure +has been clobbered, or (b) you've passed the wrong structure to a +routine. This last is especially useful --- particularly when you are +passing pointers to structures via a void * pointer. The tty code, +for example, does this frequently to pass driver-specific and line +discipline-specific structures back and forth. + +The way to use magic numbers is to declare then at the beginning of +the structure, like so: + +struct tty_ldisc { + int magic; + ... +}; + +Please follow this discipline when you are adding future enhancements +to the kernel! It has saved me countless hours of debugging, +especially in the screw cases where an array has been overrun and +structures following the array have been overwritten. Using this +discipline, these cases get detected quickly and safely. + + Theodore Ts'o + 31-Mar-94 + +The magic table is current to Linux 1.3.98. + + Michael Chastain + + 6 May 1996 + + + +Magic Name Number Structure File +=========================================================================== +RISCOM8_MAGIC 0x0907 struct riscom_port drivers/char/riscom8.h +APM_BIOS_MAGIC 0x4101 struct apm_struct include/linux/apm_bios.h +CYCLADES_MAGIC 0x4359 struct cyclades_port include/linux/cyclades.h +FASYNC_MAGIC 0x4601 struct fasync_struct include/linux/fs.h +PTY_MAGIC 0x5001 struct pty_struct drivers/char/pty.c +PPP_MAGIC 0x5002 struct ppp_struct include/linux/if_ppp.h +SERIAL_MAGIC 0x5301 struct async_struct include/linux/serial.h +SLIP_MAGIC 0x5302 struct slip drivers/net/slip.h +STRIP_MAGIC 0x5303 struct strip drivers/net/strip.c +TTY_MAGIC 0x5401 struct tty_struct include/linux/tty.h +TTY_DRIVER_MAGIC 0x5402 struct tty_driver include/linux/tty_driver.h +TTY_LDISC_MAGIC 0x5403 struct tty_ldisc include/linux/tty_ldisc.h +SCC_MAGIC 0x8530 struct scc_channel include/linux/scc.h +ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h +ISDN_NET_MAGIC 0x49344C02 isdn_net_ndev include/linux/isdn.h +STLI_BOARDMAGIC 0x4bc6c825 stlibrd_t include/linux/istallion.h +STLI_PORTMAGIC 0xe671c7a1 stliport_t include/linux/istallion.h +STL_PANELMAGIC 0x7ef621a1 stlpanel_t include/linux/stallion.h +STL_BOARDMAGIC 0xa2267f52 stlbrd_t include/linux/stallion.h +STL_PORTMAGIC 0x5a7182c9 stlport_t include/linux/stallion.h +PCXX_MAGIC 0x5c6df104 struct channel drivers/char/pcxx.h diff -u --recursive --new-file v1.3.98/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt --- v1.3.98/linux/Documentation/networking/arcnet-hardware.txt Fri Apr 12 15:51:44 1996 +++ linux/Documentation/networking/arcnet-hardware.txt Mon May 6 12:26:01 1996 @@ -140,7 +140,7 @@ 5. An active hub to passive hub. Remember, that you can not connect two passive hubs together. The power loss -implied by such connection is too high for the net to operate reliably. +implied by such a connection is too high for the net to operate reliably. An example of a typical ARCnet network: @@ -2256,9 +2256,9 @@ function, and the 8th switch is used to select "compatible" or "enhanced". When I got my two cards, one of them had this switch set to "enhanced". That card didn't work at all, it wasn't even recognized by the driver. The other -card had this switch set to "compatible" and it behaved absolutely normal. I +card had this switch set to "compatible" and it behaved absolutely normally. I guess that the switch on one of the cards, must have been changed accidently -when the card was taken out of it's former host. The question remains +when the card was taken out of its former host. The question remains unanswered, what is the purpose of the "enhanced" position? [Avery's note: "enhanced" probably either disables shared memory (use IO diff -u --recursive --new-file v1.3.98/linux/Documentation/networking/framerelay.txt linux/Documentation/networking/framerelay.txt --- v1.3.98/linux/Documentation/networking/framerelay.txt Fri Apr 12 15:51:44 1996 +++ linux/Documentation/networking/framerelay.txt Mon May 6 12:26:01 1996 @@ -1,6 +1,6 @@ Frame Relay (FR) support for linux is built into a two tiered system of device drivers. The upper layer implements RFC1490 FR specification, and uses the -Data Link Connection Identifier (DLCI) as it's hardware address. Usually these +Data Link Connection Identifier (DLCI) as its hardware address. Usually these are assigned by your network supplier, they give you the number/numbers of the Virtual Connections (VC) assigned to you. diff -u --recursive --new-file v1.3.98/linux/Documentation/nfsroot.txt linux/Documentation/nfsroot.txt --- v1.3.98/linux/Documentation/nfsroot.txt Fri Apr 12 15:51:44 1996 +++ linux/Documentation/nfsroot.txt Mon May 6 12:26:01 1996 @@ -160,7 +160,7 @@ 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 + RARP will mount the directory /tftpboot// as its root. If it got a BOOTP answer the directory name in that answer is used. @@ -169,8 +169,8 @@ 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 + set up a dummy device as described in 3.1 above. For how to use + LILO and its 'append=' command please refer to the LILO documentation. 3.3) Using loadlin @@ -187,7 +187,7 @@ 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'. + and its mirrors. They are called 'netboot-nfs' and 'etherboot'. Both contain everything you need to boot a diskless Linux client. diff -u --recursive --new-file v1.3.98/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt --- v1.3.98/linux/Documentation/oops-tracing.txt Sun May 5 08:51:57 1996 +++ linux/Documentation/oops-tracing.txt Sun May 5 08:51:13 1996 @@ -19,7 +19,7 @@ Oh, it helps if the report happens on a kernel that is compiled with the same compiler and similar setups. -The other thing to do is disassemble the "Code:" part of the bugreprot: +The other thing to do is disassemble the "Code:" part of the bug report: ksymoops will do this too with the correct tools (and new version of ksymoops), but if you don't have the tools you can just do a silly program: @@ -30,7 +30,7 @@ and compile it with gcc -g and then do "disassemble str" (where the "XX" stuff are the values reported by the Oops - you can just cut-and-paste and do a replace of spaces to "\x" - that's what I do, as I'm too lazy -to write a prigram to automate this all). +to write a program to automate this all). Finally, if you want to see where the code comes from, you can do diff -u --recursive --new-file v1.3.98/linux/Documentation/ramdisk.txt linux/Documentation/ramdisk.txt --- v1.3.98/linux/Documentation/ramdisk.txt Sun May 5 08:51:57 1996 +++ linux/Documentation/ramdisk.txt Mon May 6 12:26:01 1996 @@ -79,7 +79,7 @@ load_ramdisk=N ============== -This parameter tells the kernel whether it is to try and load a +This parameter tells the kernel whether it is to try to load a ramdisk image or not. Specifying "load_ramdisk=1" will tell the kernel to load a floppy into the ramdisk. The default value is zero, meaning that the kernel should not try to load a ramdisk. @@ -194,7 +194,7 @@ dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400 g) Use "rdev" to set the boot device, ramdisk offset, prompt flag, etc. - For ramdisk_start=400, load_ramdisk=1, ramdisk_start=400, one would + For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would have 2^15 + 2^14 + 400 = 49552. rdev /dev/fd0 /dev/fd0 diff -u --recursive --new-file v1.3.98/linux/Documentation/rtc.txt linux/Documentation/rtc.txt --- v1.3.98/linux/Documentation/rtc.txt Sun May 5 08:51:57 1996 +++ linux/Documentation/rtc.txt Tue May 7 08:18:50 1996 @@ -9,7 +9,7 @@ However it can also be used to generate signals from a slow 2Hz to a relatively fast 8192Hz, in increments of powers of two. These signals -are reported by interrupt number 8. (Oh! So *thats* what IRQ 8 is +are reported by interrupt number 8. (Oh! So *that* is what IRQ 8 is for...) It can also function as a 24hr alarm, raising IRQ 8 when the alarm goes off. The alarm can also be programmed to only check any subset of the three programmable values, meaning that it could be set to @@ -88,13 +88,12 @@ #include #include #include -#include void main(void) { int i, fd, retval, irqcount = 0; unsigned long tmp, data; -struct tm rtc_tm; +struct rtc_time rtc_tm; fd = open ("/dev/rtc", O_RDONLY); diff -u --recursive --new-file v1.3.98/linux/MAGIC linux/MAGIC --- v1.3.98/linux/MAGIC Tue Apr 23 13:57:01 1996 +++ linux/MAGIC Thu Jan 1 02:00:00 1970 @@ -1,105 +0,0 @@ -This file is a registry of magic numbers which are in use. When you -add a magic number to a structure, you should also add it to this -file, since it is best if the magic numbers used by various structures -are unique. - -It is a *very* good idea to protect kernel data structures with magic -numbers. This allows you to check at run time whether (a) a structure -has been clobbered, or (b) you've passed the wrong structure to a -routine. This last is especially useful --- particularly when you are -passing pointers to structures via a void * pointer. The tty code, -for example, does this frequently to pass driver-specific and line -discipline-specific structures back and forth. - -The way to use magic numbers is to declare then at the beginning of -the structure, like so: - -struct tty_ldisc { - int magic; - ... -}; - -Please follow this discipline when you are adding future enhancements -to the kernel! It has saved me countless hours of debugging, -especially in the screw cases where an array has been overrun and -structures following the array have been overwritten. Using this -discipline, these cases get detected quickly and safely. - -You should also register the magic number used by ioctls in the table -below. This allows ioctls on inappropriate devices to fail, rather than -doing something completely unexpected. The magic number is the first -argument to the _IO family of macros (see include/linux/ioctl.h) or -in general bits 8..15 of the ioctl number. Where ioctls are done on -devices with a major device number, it is recommended that you use the -major device number as the ioctl magic value (e.g. hd, lp). - - Theodore Ts'o - 31-Mar-94 - -The magic table is current to Linux 1.3.35. -The ioctl table is current to Linux 1.3.35. -For a complete list of kernel ioctl's, look for 'ioctl-list.X.Y.ZZ' on -an ftp site, where 'X.Y.ZZ' is the kernel version for the ioctl list. - - Michael Chastain - - 17-Oct-95 - - - - -Magic Name Number Structure File -=========================================================================== -APM_BIOS_MAGIC 0x4101 struct apm_struct include/linux/apm_bios.h -CYCLADES_MAGIC 0x4359 struct cyclades_port include/linux/cyclades.h -FASYNC_MAGIC 0x4601 struct fasync_struct include/linux/fs.h -PTY_MAGIC 0x5001 struct pty_struct drivers/char/pty.c -PPP_MAGIC 0x5002 struct ppp_struct include/linux/if_ppp.h -TTY_MAGIC 0x5401 struct tty_struct include/linux/tty.h -TTY_DRIVER_MAGIC 0x5402 struct tty_driver include/linux/tty_driver.h -TTY_LDISC_MAGIC 0x5403 struct tty_ldisc include/linux/tty_ldisc.h -SERIAL_MAGIC 0x5301 struct async_struct include/linux/serial.h -SLIP_MAGIC 0x5302 struct slip drivers/net/slip.h -SCC_MAGIC 0x8530 struct scc_channel include/linux/scc.h -RISCOM8_MAGIC 0x0907 struct riscom_port drivers/char/riscom8.h - - - -Ioctl Include File Comments -======================================================== -0x00 linux/fs.h only FIBMAP, FIGETBSZ -0x00 linux/random.h codes in 0x010800NN -0x02 linux/fd.h -0x03 linux/hdreg.h -0x04 linux/umsdos_fs.h -0x06 linux/lp.h -0x09 linux/md.h -0x12 linux/fs.h -0x20 linux/cm206.h -0x22 linux/scc.h -'A' linux/apm_bios.h -'C' linux/soundcard.h -'I' linux/isdn.h -'K' linux/kd.h -'L' linux/loop.h -'M' linux/soundcard.h -'P' linux/soundcard.h -'Q' linux/soundcard.h -'S' linux/cdrom.h conflict! -'S' linux/scsi.h conflict! -'T' linux/soundcard.h conflict! -'T' asm/termios.h conflict! -'V' linux/vt.h -'Y' linux/cyclades.h codes in 0x004359NN -'a' various, see http://lrcwww.epfl.ch/linux-atm/magic.html -'f' linux/ext2_fs.h -'m' linux/mtio.h conflict! -'m' linux/soundcard.h conflict! -'n' linux/ncp_fs.h -'s' linux/cdk.h -'t' linux/if_ppp.h -'u' linux/smb_fs.h -'u' linux/smb_fs.h -'v' linux/ext2_fs.h -0x89 asm/socket.h no conflict -0x89 linux/sockios.h no conflict diff -u --recursive --new-file v1.3.98/linux/MAINTAINERS linux/MAINTAINERS --- v1.3.98/linux/MAINTAINERS Sun May 5 08:51:57 1996 +++ linux/MAINTAINERS Tue May 7 12:06:49 1996 @@ -7,13 +7,13 @@ 1. Always _test_ your changes, however small, on at least 4 or 5 people, preferably many more. -2. Try and release a few ALPHA test versions to the net. Announce +2. Try to release a few ALPHA test versions to the net. Announce them onto the kernel channel and await results. This is especially - important for device drivers, because often thats the only way + important for device drivers, because often that's the only way you will find things like the fact version 3 firmware needs a magic fix you didn't know about, or some clown changed the chips on a board and not its name. (Don't laugh! Look at the - SMC etherpower for that). + SMC etherpower for that.) 3. Make sure your changes compile correctly in multiple configurations. @@ -30,7 +30,7 @@ your driver to get around a problem actual needs to become a generalised kernel feature ready for next time. - PLEASE try and include any credit lines you want added with the + PLEASE try to include any credit lines you want added with the patch. It avoids people being missed off by mistake and makes it easier to know who wants adding and who doesn't. @@ -74,6 +74,12 @@ L: linux-net@vger.rutgers.edu S: Maintained +8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] +P: Paul Gortmaker +M gpg109@rsphy1.anu.edu.au +L: linux-net@vger.rutgers.edu +S: Maintained + ETHEREXPRESS NETWORK DRIVER P: Philip Blundell M: pjb27@cam.ac.uk @@ -226,6 +232,12 @@ L: linux-ppp@vger.rutgers.edu S: Maintained +REAL TIME CLOCK DRIVER +P: Paul Gortmaker +M gpg109@rsphy1.anu.edu.au +L: linux-kernel@vger.rutgers.edu +S: Maintained + STARMODE RADIO IP (STRIP) PROTOCOL DRIVER P: Stuart Cheshire M: cheshire@cs.stanford.edu @@ -286,6 +298,12 @@ P: William Roadcap M: roadcapw@cfw.com L: linux-kernel@vger.rutgers.edu +S: Maintained + +LANCE AND LANCE32 NETWORK DRIVER +P: Thomas Bogendoerfer +M: tsbogend@bigbug.franken.de +L: linux-net@vger.rutgers.edu S: Maintained REST: diff -u --recursive --new-file v1.3.98/linux/Makefile linux/Makefile --- v1.3.98/linux/Makefile Sun May 5 08:51:57 1996 +++ linux/Makefile Sun May 5 08:51:39 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 98 +SUBLEVEL = 99 ARCH = i386 diff -u --recursive --new-file v1.3.98/linux/README linux/README --- v1.3.98/linux/README Wed Apr 24 17:00:33 1996 +++ linux/README Mon May 6 07:28:51 1996 @@ -24,9 +24,9 @@ WHAT IS LINUX? - Linux is a Unix clone for 386/486-based PCs written from scratch by - Linus Torvalds with assistance from a loosely-knit team of hackers - across the Net. It aims towards POSIX compliance. + Linux is a Unix clone written from scratch by Linus Torvalds with + assistance from a loosely-knit team of hackers across the Net. + It aims towards POSIX compliance. It has all the features you would expect in a modern fully-fledged Unix, including true multitasking, virtual memory, shared libraries, @@ -35,6 +35,12 @@ It is distributed under the GNU General Public License - see the accompanying COPYING file for more details. + +ON WHAT HARDWARE DOES IT RUN? + + Linux was first developed for 386/486-based PCs. These days it also + runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga), + MIPS and PowerPC. DOCUMENTATION: diff -u --recursive --new-file v1.3.98/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v1.3.98/linux/arch/alpha/config.in Sun May 5 08:51:58 1996 +++ linux/arch/alpha/config.in Sun May 5 09:05:58 1996 @@ -82,7 +82,9 @@ bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO if [ "$CONFIG_PCI" = "y" ]; then bool 'TGA Console Support' CONFIG_TGA_CONSOLE - bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE + fi fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC diff -u --recursive --new-file v1.3.98/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v1.3.98/linux/arch/alpha/kernel/bios32.c Sun Apr 21 12:39:00 1996 +++ linux/arch/alpha/kernel/bios32.c Mon May 6 12:26:02 1996 @@ -442,7 +442,7 @@ } /* - * The SRM console *disables* the IDE interface, this code ensures its + * The SRM console *disables* the IDE interface, this code ensures it's * enabled. * * This code bangs on a control register of the 87312 Super I/O chip @@ -565,7 +565,7 @@ PCI_INTERRUPT_LINE, dev->irq); #endif /* - * if its a VGA, enable its BIOS ROM at C0000 + * if it's a VGA, enable its BIOS ROM at C0000 */ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { pcibios_write_config_dword(dev->bus->number, dev->devfn, @@ -799,7 +799,7 @@ dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, slot, pin, pirq)); /* - * if its a VGA, enable its BIOS ROM at C0000 + * if it's a VGA, enable its BIOS ROM at C0000 */ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { pcibios_write_config_dword(dev->bus->number, dev->devfn, diff -u --recursive --new-file v1.3.98/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v1.3.98/linux/arch/i386/boot/Makefile Sat Mar 16 13:52:09 1996 +++ linux/arch/i386/boot/Makefile Sun May 5 09:05:58 1996 @@ -90,6 +90,7 @@ clean: rm -f bootsect setup + rm -f bbootsect rm -f zImage tools/build compressed/vmlinux.out rm -f bzImage tools/bbuild compressed/bvmlinux.out @$(MAKE) -C compressed clean diff -u --recursive --new-file v1.3.98/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.3.98/linux/arch/i386/config.in Sun May 5 08:51:58 1996 +++ linux/arch/i386/config.in Tue May 7 12:06:50 1996 @@ -26,14 +26,15 @@ bool 'Limit memory to low 16MB' CONFIG_MAX_16M bool 'PCI bios support' CONFIG_PCI if [ "$CONFIG_PCI" = "y" ]; then - bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE + fi fi bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -if [ "$CONFIG_BINFMT_ELF" = "y" ]; then - bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF -fi +bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF + choice 'Processor type' \ "386 CONFIG_M386 \ 486 CONFIG_M486 \ diff -u --recursive --new-file v1.3.98/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v1.3.98/linux/arch/i386/kernel/irq.c Fri Apr 12 15:51:46 1996 +++ linux/arch/i386/kernel/irq.c Mon May 6 12:26:02 1996 @@ -370,7 +370,7 @@ { struct irqaction * action = *(irq + irq_action); #ifdef __SMP__ - /* IRQ 13 is allowed - thats a flush tlb */ + /* IRQ 13 is allowed - that's a flush tlb */ if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13) panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id()); #endif diff -u --recursive --new-file v1.3.98/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v1.3.98/linux/arch/i386/kernel/setup.c Mon Apr 15 12:20:17 1996 +++ linux/arch/i386/kernel/setup.c Mon May 6 07:05:57 1996 @@ -207,7 +207,8 @@ static const char * i486model(unsigned int nr) { static const char *model[] = { - "0", "DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB" + "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB", + "10","11","12","13","Am5x85-WT","Am5x86-WB" }; if (nr < sizeof(model)/sizeof(char *)) return model[nr]; @@ -325,7 +326,7 @@ } } len += sprintf(buffer+len, - "\nbogomips:\t: %lu.%02lu\n", + "\nbogomips\t: %lu.%02lu\n", CD(loops_per_sec)/500000, (CD(loops_per_sec)/5000) % 100); #ifdef __SMP__ diff -u --recursive --new-file v1.3.98/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v1.3.98/linux/arch/i386/kernel/signal.c Mon Apr 29 18:05:15 1996 +++ linux/arch/i386/kernel/signal.c Mon May 6 16:31:18 1996 @@ -43,11 +43,6 @@ } } -/* - * FIXME. We don't currently restore emulator state - */ -#define restore_i387_soft(x) do { } while (0) - static inline void restore_i387_hard(struct _fpstate *buf) { #ifdef __SMP__ @@ -121,11 +116,6 @@ badframe: do_exit(SIGSEGV); } - -/* - * FIXME. We currently don't save 387 state if we use emulation - */ -#define save_i387_soft(x) NULL static inline struct _fpstate * save_i387_hard(struct _fpstate * buf) { diff -u --recursive --new-file v1.3.98/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v1.3.98/linux/arch/i386/kernel/smp.c Fri Apr 12 15:51:46 1996 +++ linux/arch/i386/kernel/smp.c Mon May 6 12:26:02 1996 @@ -56,7 +56,7 @@ volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */ volatile int cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */ -volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map thats also checked in the spinlock */ +volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters */ static unsigned int num_processors = 1; /* Internal processor count */ static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */ @@ -448,7 +448,7 @@ /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller - * has made sure its suitably aligned. + * has made sure it's suitably aligned. */ static void install_trampoline(unsigned char *mp) @@ -1094,7 +1094,7 @@ /* printk("SMI-");*/ /* - * The assignment is safe because its volatile so the compiler cannot reorder it, + * The assignment is safe because it's volatile so the compiler cannot reorder it, * because the i586 has strict memory ordering and because only the kernel lock holder * may issue a tlb flush. If you break any one of those three change this to an atomic * bus locked or. @@ -1104,7 +1104,7 @@ /* * Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will - * ensure they dont do a spurious flush tlb or miss one. + * ensure they don't do a spurious flush tlb or miss one. */ save_flags(flags); diff -u --recursive --new-file v1.3.98/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v1.3.98/linux/arch/i386/kernel/time.c Sun May 5 08:51:58 1996 +++ linux/arch/i386/kernel/time.c Mon May 6 12:26:02 1996 @@ -267,7 +267,7 @@ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ /* As we return to user mode fire off the other CPU schedulers.. this is basically because we don't yet share IRQ's around. This message is - rigged to be safe on the 386 - basically its a hack, so don't look + rigged to be safe on the 386 - basically it's a hack, so don't look closely for now.. */ /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */ diff -u --recursive --new-file v1.3.98/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v1.3.98/linux/arch/i386/kernel/traps.c Sat Apr 27 15:19:44 1996 +++ linux/arch/i386/kernel/traps.c Mon May 6 16:41:22 1996 @@ -255,18 +255,11 @@ */ __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard)); task->flags&=~PF_USEDFPU; + stts(); force_sig(SIGFPE, task); task->tss.trap_no = 16; task->tss.error_code = 0; - - /* - * Give the process a clean slate next time they use - * the FPU (and if they haven't accepted the SIGFPE before - * that, it's their problem..) - */ - stts(); - task->used_math = 0; } asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) diff -u --recursive --new-file v1.3.98/linux/arch/i386/math-emu/errors.c linux/arch/i386/math-emu/errors.c --- v1.3.98/linux/arch/i386/math-emu/errors.c Tue Aug 1 10:02:31 1995 +++ linux/arch/i386/math-emu/errors.c Mon May 6 16:31:17 1996 @@ -3,9 +3,9 @@ | | | The error handling functions for wm-FPU-emu | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1996 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ @@ -82,7 +82,7 @@ -void emu_printall() +void emu_printall(void) { int i; static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR", @@ -166,7 +166,8 @@ for ( i = 0; i < 8; i++ ) { FPU_REG *r = &st(i); - switch (r->tag) + char tagi = r->tag; + switch (tagi) { case TW_Empty: continue; @@ -190,22 +191,13 @@ r->exp - EXP_BIAS + 1); break; default: - printk("Whoops! Error in errors.c "); + printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi); + continue; break; } - printk("%s\n", tag_desc[(int) (unsigned) r->tag]); + printk("%s\n", tag_desc[(int) (unsigned) tagi]); } -#ifdef OBSOLETE - printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ", - FPU_loaded_data.sign ? '-' : '+', - (long)(FPU_loaded_data.sigh >> 16), - (long)(FPU_loaded_data.sigh & 0xFFFF), - (long)(FPU_loaded_data.sigl >> 16), - (long)(FPU_loaded_data.sigl & 0xFFFF), - FPU_loaded_data.exp - EXP_BIAS + 1); - printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]); -#endif OBSOLETE RE_ENTRANT_CHECK_ON; } @@ -365,12 +357,8 @@ /* * The 80486 generates an interrupt on the next non-control FPU * instruction. So we need some means of flagging it. - * We use the ES (Error Summary) bit for this, assuming that - * this is the way a real FPU does it (until I can check it out), - * if not, then some method such as the following kludge might - * be needed. + * We use the ES (Error Summary) bit for this. */ -/* regs[0].tag |= TW_FPU_Interrupt; */ } RE_ENTRANT_CHECK_ON; @@ -568,7 +556,7 @@ return !(control_word & CW_Precision); } - return !(control_word & CW_Overflow); + return 0; } @@ -599,7 +587,7 @@ return !(control_word & CW_Precision); } - return !(control_word & CW_Underflow); + return 0; } diff -u --recursive --new-file v1.3.98/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h --- v1.3.98/linux/arch/i386/math-emu/fpu_emu.h Tue Aug 1 10:02:31 1995 +++ linux/arch/i386/math-emu/fpu_emu.h Tue May 7 10:02:31 1996 @@ -57,6 +57,7 @@ #ifndef __ASSEMBLY__ +#include /* for struct _fpstate */ #include #include diff -u --recursive --new-file v1.3.98/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c --- v1.3.98/linux/arch/i386/math-emu/fpu_entry.c Sun Nov 27 20:19:52 1994 +++ linux/arch/i386/math-emu/fpu_entry.c Mon May 6 16:31:17 1996 @@ -1,11 +1,11 @@ /*---------------------------------------------------------------------------+ | fpu_entry.c | | | - | The entry function for wm-FPU-emu | + | The entry functions for wm-FPU-emu | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1996 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@jacobi.maths.monash.edu.au | | | | See the files "README" and "COPYING" for further copyright and warranty | | information. | @@ -20,7 +20,8 @@ +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ - | math_emulate() is the sole entry point for wm-FPU-emu | + | math_emulate(), restore_i387_soft() and save_i387_soft() are the only | + | entry points for wm-FPU-emu. | +---------------------------------------------------------------------------*/ #include @@ -159,8 +160,9 @@ { /* Make sure that the registers are compatible with the assumptions of the emulator. */ - regs[i].exp = 0; - regs[i].sigh = 0x80000000; + if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0) + && (regs[i].sigl == 0)) ) + regs[i].sigh |= 0x80000000; } finit(); current->used_math = 1; @@ -283,24 +285,8 @@ /* * We need to simulate the action of the kernel to FPU * interrupts here. - * Currently, the "real FPU" part of the kernel (0.99.10) - * clears the exception flags, sets the registers to empty, - * and passes information back to the interrupted process - * via the cs selector and operand selector, so we do the same. */ do_the_FPU_interrupt: - instruction_address.selector = status_word(); - operand_address.selector = tag_word(); - partial_status = 0; - top = 0; - { - int r; - for (r = 0; r < 8; r++) - { - regs[r].tag = TW_Empty; - } - } - FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */ RE_ENTRANT_CHECK_OFF; @@ -687,4 +673,23 @@ #ifdef PARANOID printk("ERROR: wm-FPU-emu math_abort failed!\n"); #endif PARANOID +} + + + +void restore_i387_soft(struct _fpstate *buf) +{ + fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0}; + + frstor(addr_modes, (char *)buf); +} + + +struct _fpstate * save_i387_soft(struct _fpstate * buf) +{ + fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0}; + + fsave(addr_modes, (char *)buf); + + return buf; } diff -u --recursive --new-file v1.3.98/linux/arch/i386/math-emu/reg_ld_str.c linux/arch/i386/math-emu/reg_ld_str.c --- v1.3.98/linux/arch/i386/math-emu/reg_ld_str.c Fri Aug 19 08:54:01 1994 +++ linux/arch/i386/math-emu/reg_ld_str.c Mon May 6 16:31:17 1996 @@ -3,9 +3,9 @@ | | | All of the functions which transfer data between user memory and FPU_REGs.| | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1996 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ @@ -466,6 +466,7 @@ if (st0_tag == TW_Valid) { + int precision_loss; int exp; FPU_REG tmp; @@ -474,8 +475,6 @@ if ( exp < DOUBLE_Emin ) /* It may be a denormal */ { - int precision_loss; - /* A denormal will always underflow. */ #ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate @@ -518,6 +517,7 @@ { if ( tmp.sigl & 0x000007ff ) { + precision_loss = 1; switch (control_word & CW_RC) { case RC_RND: @@ -541,8 +541,6 @@ if ( increment ) { - set_precision_flag_up(); - if ( tmp.sigl >= 0xfffff800 ) { /* the sigl part overflows */ @@ -566,9 +564,9 @@ tmp.sigl += 0x00000800; } } - else - set_precision_flag_down(); } + else + precision_loss = 0; l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21); l[1] = ((tmp.sigh >> 11) & 0xfffff); @@ -590,6 +588,13 @@ } else { + if ( precision_loss ) + { + if ( increment ) + set_precision_flag_up(); + else + set_precision_flag_down(); + } /* Add the exponent */ l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); } @@ -661,6 +666,7 @@ if (st0_tag == TW_Valid) { + int precision_loss; int exp; FPU_REG tmp; @@ -669,8 +675,6 @@ if ( exp < SINGLE_Emin ) { - int precision_loss; - /* A denormal will always underflow. */ #ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate @@ -715,6 +719,7 @@ unsigned long sigh = tmp.sigh; unsigned long sigl = tmp.sigl; + precision_loss = 1; switch (control_word & CW_RC) { case RC_RND: @@ -740,8 +745,6 @@ if (increment) { - set_precision_flag_up(); - if ( sigh >= 0xffffff00 ) { /* The sigh part overflows */ @@ -758,10 +761,11 @@ } else { - set_precision_flag_down(); tmp.sigh &= 0xffffff00; /* Finish the truncation */ } } + else + precision_loss = 0; templ = (tmp.sigh >> 8) & 0x007fffff; @@ -780,7 +784,17 @@ templ = 0x7f800000; } else - templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; + { + if ( precision_loss ) + { + if ( increment ) + set_precision_flag_up(); + else + set_precision_flag_down(); + } + /* Add the exponent */ + templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; + } } } else if (st0_tag == TW_Zero) diff -u --recursive --new-file v1.3.98/linux/arch/i386/math-emu/version.h linux/arch/i386/math-emu/version.h --- v1.3.98/linux/arch/i386/math-emu/version.h Tue Mar 19 13:45:02 1996 +++ linux/arch/i386/math-emu/version.h Mon May 6 16:31:17 1996 @@ -3,10 +3,10 @@ | | | | | Copyright (C) 1992,1993,1994,1996 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ -#define FPU_VERSION "wm-FPU-emu version 1.21" +#define FPU_VERSION "wm-FPU-emu version 1.22" diff -u --recursive --new-file v1.3.98/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile --- v1.3.98/linux/arch/m68k/amiga/Makefile Tue Apr 23 13:57:02 1996 +++ linux/arch/m68k/amiga/Makefile Mon May 6 12:44:30 1996 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := amiga.o -O_OBJS := config.o amikeyb.o amiints.o amipart.o \ +O_OBJS := config.o amikeyb.o amiints.o \ chipram.o amisound.o amifb.o zorro.o OX_OBJS = ksyms.o diff -u --recursive --new-file v1.3.98/linux/arch/m68k/amiga/amipart.c linux/arch/m68k/amiga/amipart.c --- v1.3.98/linux/arch/m68k/amiga/amipart.c Tue Apr 23 13:57:02 1996 +++ linux/arch/m68k/amiga/amipart.c Thu Jan 1 02:00:00 1970 @@ -1,119 +0,0 @@ -/* - * linux/amiga/amipart.c - * - * Amiga partition checking driver for 680x0 Linux - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive - * for more details. - */ - -#include -#include -#include - -#include -#include - -extern int current_minor; - -static ulong checksum (ulong *ptr, int len) -{ - ulong sum; - int cnt; - - for (sum = 0, cnt = 0; cnt < len; cnt++) - sum += ptr[cnt]; - - return sum; -} - -/* XXX */ -/* int current_minor = 0; */ - -void amiga_check_partition(struct gendisk *hd, kdev_t dev) -{ - int i, minor = current_minor, m_lim = current_minor + hd->max_p; - struct buffer_head *bh; - struct RigidDiskBlock *rdb; - struct PartitionBlock *pb; - ulong bnum, partsect; - - for (bnum = 0; bnum < RDB_LOCATION_LIMIT/2; bnum++) { - if (!(bh = bread(dev,bnum,1024))) { - printk (" unable to read block %ld\n", bnum); - return; - } -#ifdef DEBUG - printk ("block read, press mousebutton to continue\n"); - waitbut(); -#endif - rdb = (struct RigidDiskBlock *)bh->b_data; - if (rdb->rdb_ID == IDNAME_RIGIDDISK) - break; - rdb = (struct RigidDiskBlock *)&bh->b_data[512]; - if (rdb->rdb_ID == IDNAME_RIGIDDISK) - break; - brelse (bh); - } - if (bnum == RDB_LOCATION_LIMIT/2) { - /* no RDB on the disk! */ - printk (" unable to find RigidDiskBlock\n"); - return; - } - - /* checksum the RigidDiskBlock */ - if (checksum ((ulong *)rdb, rdb->rdb_SummedLongs) != 0) { - printk (" RDB checksum bad\n"); - return; - } - - printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift)); - - partsect = rdb->rdb_PartitionList; - brelse (bh); - - for (i = 1; minor < m_lim && partsect != 0xffffffff; minor++, i++) - { - ulong *env; - - if (!(bh = bread(dev,partsect/2,1024))) { - printk (" block %ld read failed\n", partsect); - return; - } -#ifdef DEBUG - printk ("block read, press mousebutton to continue\n"); - waitbut(); -#endif - pb = (struct PartitionBlock *)bh->b_data; - if (partsect & 1) - pb = (struct PartitionBlock *)&bh->b_data[512]; - if (pb->pb_ID != IDNAME_PARTITION) { - printk (" block %ld Not a partition block (%#lx)\n", - partsect, pb->pb_ID); - brelse (bh); - return; - } - if (checksum ((ulong *)pb, pb->pb_SummedLongs) != 0) { - printk (" block %ld checksum bad\n", partsect); - brelse (bh); - return; - } - - env = pb->pb_Environment; - - hd->part[minor].start_sect = env[DE_LOWCYL] - * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK]; - hd->part[minor].nr_sects = (env[DE_UPPERCYL] - - env[DE_LOWCYL] + 1) - * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK]; - - printk(" %s%c%d", hd->major_name, - 'a'+(minor >> hd->minor_shift), i); - - partsect = pb->pb_Next; - brelse (bh); - } - - printk ("\n"); -} diff -u --recursive --new-file v1.3.98/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v1.3.98/linux/arch/m68k/amiga/config.c Sat Apr 27 15:19:45 1996 +++ linux/arch/m68k/amiga/config.c Mon May 6 12:44:30 1996 @@ -49,7 +49,6 @@ extern void a2000_gettod (int *, int *, int *, int *, int *, int *); extern int amiga_hwclk (int, struct hwclk_time *); extern int amiga_set_clock_mmss (unsigned long); -extern void amiga_check_partition (struct gendisk *hd, unsigned int dev); extern void amiga_mksound( unsigned int count, unsigned int ticks ); #ifdef CONFIG_BLK_DEV_FD extern int amiga_floppy_init (void); @@ -288,7 +287,6 @@ } mach_hwclk = amiga_hwclk; mach_set_clock_mmss = amiga_set_clock_mmss; - mach_check_partition = amiga_check_partition; mach_mksound = amiga_mksound; #ifdef CONFIG_BLK_DEV_FD mach_floppy_init = amiga_floppy_init; diff -u --recursive --new-file v1.3.98/linux/arch/m68k/atari/Makefile linux/arch/m68k/atari/Makefile --- v1.3.98/linux/arch/m68k/atari/Makefile Tue Apr 23 13:57:02 1996 +++ linux/arch/m68k/atari/Makefile Mon May 6 12:44:30 1996 @@ -11,7 +11,7 @@ O_TARGET := atari.o O_OBJS := config.o atakeyb.o ataints.o \ - atapart.o stdma.o atasound.o joystick.o stram.o atafb.o + stdma.o atasound.o joystick.o stram.o atafb.o OX_OBJS = ksyms.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.98/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c --- v1.3.98/linux/arch/m68k/atari/atafb.c Sat Apr 27 15:19:45 1996 +++ linux/arch/m68k/atari/atafb.c Mon May 6 12:26:02 1996 @@ -1399,7 +1399,7 @@ if (hw->ste_mode || mon_type!=F_MON_VGA) var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; else - /* cant use this in ste_mode, because hbb is +1 off */ + /* can't use this in ste_mode, because hbb is +1 off */ var->right_margin = prescale * (hw->hht + 2 - hw->hbb); var->hsync_len = prescale * (hw->hht + 2 - hw->hss); diff -u --recursive --new-file v1.3.98/linux/arch/m68k/atari/atapart.c linux/arch/m68k/atari/atapart.c --- v1.3.98/linux/arch/m68k/atari/atapart.c Sat Apr 27 15:19:45 1996 +++ linux/arch/m68k/atari/atapart.c Thu Jan 1 02:00:00 1970 @@ -1,158 +0,0 @@ -/* - * linux/atari/atapart.c - * - * Atari partition checking driver for 680x0 Linux - * Written by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) - * - * 5/3/94 Roman Hodek: - * Added some sanity checks - * Linux device names start from 1 not 0, so I changed the initial value - * for i to 1. - * - * 10/09/94 Guenther Kelleter: - * Added support for ICD/Supra partition info. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive - * for more details. - */ - -#include -#include -#include - -#include - -/* ++guenther: this should be settable by the user ("make config")?. - */ -#define ICD_PARTS - -extern int current_minor; - -void -atari_check_partition (struct gendisk *hd, unsigned int dev) -{ - int i, minor = current_minor, m_lim = current_minor + hd->max_p; - struct buffer_head *bh; - struct rootsector *rs; - struct partition_info *pi; - ulong extensect; -#ifdef ICD_PARTS - int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ -#endif - - bh = bread (dev, 0, 1024); - if (!bh) - { - printk (" unable to read block 0\n"); - return; - } - - rs = (struct rootsector *) bh->b_data; - printk (" %s%c:", hd->major_name, 'a' + (minor >> hd->minor_shift)); - - pi = &rs->part[0]; - for (i = 1; pi < &rs->part[4] && minor < m_lim; i++, minor++, pi++) - { - if (pi->flg & 1) - /* active partition */ - { - if (memcmp (pi->id, "XGM", 3) == 0) - /* extension partition */ - { - struct rootsector *xrs; - struct buffer_head *xbh; - ulong partsect; - -#ifdef ICD_PARTS - part_fmt = 1; -#endif - partsect = extensect = pi->st; - while (1) - { - xbh = bread (dev, partsect / 2, 1024); - if (!xbh) - { - printk (" block %ld read failed\n", partsect); - return; - } - if (partsect & 1) - xrs = (struct rootsector *) &xbh->b_data[512]; - else - xrs = (struct rootsector *) &xbh->b_data[0]; - - /* ++roman: sanity check: bit 0 of flg field must be set */ - if (!(xrs->part[0].flg & 1)) { - printk( "\nFirst sub-partition in extended partition is not valid!\n" ); - break; - } - - hd->part[minor].start_sect = partsect + xrs->part[0].st; - hd->part[minor].nr_sects = xrs->part[0].siz; - printk (" %s%c%d", hd->major_name, - 'a' + (minor >> hd->minor_shift), i); - - if (!(xrs->part[1].flg & 1)) { - /* end of linked partition list */ - brelse( xbh ); - break; - } - if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { - printk( "\nID of extended partition is not XGM!\n" ); - brelse( xbh ); - break; - } - - partsect = xrs->part[1].st + extensect; - brelse (xbh); - i++; - minor++; - if (minor >= m_lim) { - printk( "\nMaximum number of partitions reached!\n" ); - break; - } - } - } - else - { - /* we don't care about other id's */ - hd->part[minor].start_sect = pi->st; - hd->part[minor].nr_sects = pi->siz; - printk (" %s%c%d", hd->major_name, - 'a' + (minor >> hd->minor_shift), i); - - } - } - } -#ifdef ICD_PARTS - if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */ - { - pi = &rs->icdpart[0]; - /* sanity check: no ICD format if first partition invalid */ - if (memcmp (pi->id, "GEM", 3) == 0 || - memcmp (pi->id, "BGM", 3) == 0 || - memcmp (pi->id, "RAW", 3) == 0 ) - { - for (i = 1; pi < &rs->icdpart[8] && minor < m_lim; i++, minor++, pi++) - { - /* accept only GEM,BGM,RAW partitions */ - if (pi->flg & 1 && - (memcmp (pi->id, "GEM", 3) == 0 || - memcmp (pi->id, "BGM", 3) == 0 || - memcmp (pi->id, "RAW", 3) == 0) ) - { - part_fmt = 2; - hd->part[minor].start_sect = pi->st; - hd->part[minor].nr_sects = pi->siz; - printk (" %s%c%d", hd->major_name, - 'a' + (minor >> hd->minor_shift), i); - } - } - } - } -#endif - brelse (bh); - - printk ("\n"); -} - diff -u --recursive --new-file v1.3.98/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c --- v1.3.98/linux/arch/m68k/atari/config.c Sat Apr 27 15:19:45 1996 +++ linux/arch/m68k/atari/config.c Mon May 6 12:44:30 1996 @@ -60,7 +60,6 @@ extern int atari_hwclk (int, struct hwclk_time *); extern int atari_mste_set_clock_mmss (unsigned long); extern int atari_set_clock_mmss (unsigned long); -extern void atari_check_partition (struct gendisk *hd, unsigned int dev); extern void atari_mksound( unsigned int count, unsigned int ticks ); extern void atari_reset( void ); #ifdef CONFIG_BLK_DEV_FD @@ -214,7 +213,6 @@ mach_disable_irq = atari_disable_irq; mach_get_irq_list = atari_get_irq_list; mach_gettimeoffset = atari_gettimeoffset; - mach_check_partition = atari_check_partition; mach_mksound = atari_mksound; mach_reset = atari_reset; #ifdef CONFIG_BLK_DEV_FD diff -u --recursive --new-file v1.3.98/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v1.3.98/linux/arch/m68k/config.in Tue Apr 23 13:57:03 1996 +++ linux/arch/m68k/config.in Mon May 6 12:44:30 1996 @@ -143,6 +143,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari mouse support' CONFIG_ATARIMOUSE fi +if [ "$CONFIG_ATARI" = y ]; then + tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER + tristate 'Atari SCC serial support' CONFIG_ATARI_SCC + tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI +fi +if [ "$CONFIG_AMIGA" = y ]; then + tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL + bool 'GVP IO-Extender support' CONFIG_GVPIOEXT + tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY +fi +bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT diff -u --recursive --new-file v1.3.98/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c --- v1.3.98/linux/arch/m68k/console/fbcon.c Sat Apr 27 15:19:46 1996 +++ linux/arch/m68k/console/fbcon.c Mon May 6 12:26:02 1996 @@ -721,7 +721,7 @@ * * Not a great fan of assembler for the sake of it, but I think * that these routines are at least 10 times faster than their C - * equivalents for large blits, and thats important to the lowest level of + * equivalents for large blits, and that's important to the lowest level of * a graphics driver. Question is whether some scheme with the blitter * would be faster. I suspect not for simple text system - not much * asynchrony. diff -u --recursive --new-file v1.3.98/linux/arch/m68k/defconfig linux/arch/m68k/defconfig --- v1.3.98/linux/arch/m68k/defconfig Sat Apr 27 15:19:46 1996 +++ linux/arch/m68k/defconfig Mon May 6 12:44:30 1996 @@ -17,7 +17,7 @@ # CONFIG_MAC is not set CONFIG_FPSP_040=y # CONFIG_IFPSP_060 is not set -# CONFIG_NET is not set +CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y diff -u --recursive --new-file v1.3.98/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S --- v1.3.98/linux/arch/m68k/fpsp040/skeleton.S Sat Apr 27 15:19:46 1996 +++ linux/arch/m68k/fpsp040/skeleton.S Mon May 6 12:44:30 1996 @@ -452,7 +452,7 @@ moveq #-1,%d0 movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc.. - + | | mem_write --- write to user or supervisor address space diff -u --recursive --new-file v1.3.98/linux/arch/m68k/ifpsp060/ilsp.doc linux/arch/m68k/ifpsp060/ilsp.doc --- v1.3.98/linux/arch/m68k/ifpsp060/ilsp.doc Tue Apr 23 13:57:07 1996 +++ linux/arch/m68k/ifpsp060/ilsp.doc Mon May 6 12:26:02 1996 @@ -126,7 +126,7 @@ Exception reporting: -------------------- If the instruction being emulated is a divide and the source -operand is a zero, then the library routine, as it's last +operand is a zero, then the library routine, as its last instruction, executes an implemented divide using a zero source operand so that an "Integer Divide-by-Zero" exception will be taken. Although the exception stack frame will not diff -u --recursive --new-file v1.3.98/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c --- v1.3.98/linux/arch/m68k/kernel/console.c Sat Apr 27 15:19:47 1996 +++ linux/arch/m68k/kernel/console.c Mon May 6 12:26:02 1996 @@ -2049,7 +2049,7 @@ /* undraw cursor first */ hide_cursor(currcons); - /* Contrived structure to try and emulate original need_wrap behaviour + /* Contrived structure to try to emulate original need_wrap behaviour * Problems caused when we have need_wrap set on '\n' character */ while ((c = *(b++)) != 0) { diff -u --recursive --new-file v1.3.98/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S --- v1.3.98/linux/arch/m68k/kernel/head.S Sat Apr 27 15:19:47 1996 +++ linux/arch/m68k/kernel/head.S Mon May 6 12:44:30 1996 @@ -14,6 +14,8 @@ ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa +** 96/04/26 G|nther Kelleter: fixed identity mapping for Falcon with +** Magnum- and FX-alternate ram ** ** This file is subject to the terms and conditions of the GNU General Public ** License. See the file README.legal in the main directory of this archive @@ -146,6 +148,16 @@ movew #0x2700,%sr /* + * Setup initial stack pointer + */ + lea %pc@(SYMBOL_NAME(_start)),%sp + +/* clear the fpu */ + lea %pc@(mmu),%a0 + clrl %a0@ + frestore %a0@ + +/* * Copy bootinfo from position after BSS to final resting place */ lea %pc@(SYMBOL_NAME(_end)),%a0 @@ -651,8 +663,8 @@ .word 0xf4d8 /* CINVA I/D */ .word 0xf518 /* pflusha */ - .long 0x4e7bc807 /* movec a5,srp */ - .long 0x4e7bc806 /* movec a5,urp */ + .long 0x4e7bc807 /* movec a4,srp */ + .long 0x4e7bc806 /* movec a4,urp */ movel #(TC_ENABLE+TC_PAGE4K),%d0 /* setup registers for jumping MMU enabling code */ @@ -723,12 +735,36 @@ /* cleanup is needed; note it */ moveq #1,%d5 + /* tt0 doesn't work if physical and virtual address of kernel is in + * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram) + */ movel %a0,%d2 andl #0xff000000,%d2 /* logical address base */ + jeq 1f orw #0x8143,%d2 /* add in magic bits */ lea %pc@(mmu),%a0 movel %d2,%a0@ pmove %a0@,%tt0 + jra Lnophys2 +1: + /* Transparent translation through kernel pointer table + * Requires that this code until after MMU enabling lies in + * the 256K page around %a0 + */ + movel %a0,%d2 + moveq #ROOT_INDEX_SHIFT,%d1 + lsrl %d1,%d2 + movel %a4@(%d2:l:4),%d0 + andw #0xfff0,%d0 + movel %d0,%a1 + movel %a0,%d2 + andl #0x01ffffff,%d2 + moveq #(ROOT_INDEX_SHIFT-7),%d1 + lsrl %d1,%d2 + movel %a0,%d0 + addql #PAGEDESC,%d0 + movel %a1@(%d2:l:4),%a2 /* save old_entry */ + movel %d0,%a1@(%d2:l:4) Lnophys2: /* @@ -832,11 +868,28 @@ cmpl #MACH_ATARI,%d4 jne Lnoclean + movel %a3,%d2 + andl #0xff000000,%d2 + jeq 1f /* clear transparent translation register */ lea %pc@(mmu),%a0 clrl %a0@ pmove %a0@,%tt0 jra Lnoclean +1: + movel %a3,%d2 + moveq #ROOT_INDEX_SHIFT,%d1 + lsrl %d1,%d2 + movel %a4@(%d2:l:4),%d0 + andw #0xfff0,%d0 + subl %a3,%d0 /* to virtual address */ + movel %d0,%a0 + movel %a3,%d2 + andl #0x01ffffff,%d2 + moveq #(ROOT_INDEX_SHIFT-7),%d1 + lsrl %d1,%d2 + movel %a2,%a0@(%d2:l:4) /* restore old entry */ + jra Lnoclean Lclean030: movel %a0,%d2 /* a0 contains physical start address */ @@ -1177,7 +1230,11 @@ rts #endif - .align 512 /* +#ifdef __ELF__ + .align 512 +#else + .align 9 +#endif /* * MMU root-pointers need to be 512-byte * aligned on the 680[46]0 - Jes */ diff -u --recursive --new-file v1.3.98/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v1.3.98/linux/arch/m68k/kernel/setup.c Tue Apr 23 13:57:08 1996 +++ linux/arch/m68k/kernel/setup.c Mon May 6 12:44:30 1996 @@ -62,7 +62,6 @@ void (*mach_gettod) (int*, int*, int*, int*, int*, int*); int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; -void (*mach_check_partition) (struct gendisk *, unsigned int); void (*mach_mksound)( unsigned int count, unsigned int ticks ); void (*mach_reset)( void ); void (*waitbut)(void) = dummy_waitbut; @@ -296,10 +295,6 @@ #endif } /* boot_info.machtype */ -#if 0 /* ++1.3++ */ - len += get_serial_list (buffer + len); -#endif /* ++1.3++ */ - return(len); } @@ -322,21 +317,6 @@ unsigned long arch_kbd_init(void) { return mach_keyb_init(); -} - -int rs_init(void) -{ - return 0; -} - -struct serial_struct; -int register_serial(struct serial_struct *req) -{ - return -1; -} - -void unregister_serial(int line) -{ } void arch_gettod(int *year, int *mon, int *day, int *hour, diff -u --recursive --new-file v1.3.98/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v1.3.98/linux/arch/m68k/kernel/traps.c Sat Apr 27 15:19:47 1996 +++ linux/arch/m68k/kernel/traps.c Mon May 6 12:44:30 1996 @@ -392,7 +392,7 @@ } printk ("BAD KERNEL BUSERR\n"); die_if_kernel("Oops",&fp->ptregs,0); - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); user_space_fault = 0; } } else { @@ -447,7 +447,7 @@ !(ssw & RW) ? "write" : "read", addr, fp->ptregs.pc); die_if_kernel("Oops",&fp->ptregs,mmusr); - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } else { #ifdef DEBUG @@ -478,7 +478,7 @@ printk("Unknown SIGSEGV - 1\n"); #endif die_if_kernel("Oops",&fp->ptregs,mmusr); - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } @@ -576,7 +576,7 @@ printk("Unknown SIGSEGV - 2\n"); #endif die_if_kernel("Oops",&fp->ptregs,mmusr); - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } else { #ifdef DEBUG @@ -609,7 +609,7 @@ printk("Unknown SIGSEGV - 3\n"); #endif die_if_kernel("Oops",&fp->ptregs,mmusr); - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } @@ -644,7 +644,7 @@ #if DEBUG printk("Unknown SIGSEGV - 4\n"); #endif - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); } } @@ -871,7 +871,7 @@ break; } - send_sig (sig, current, 1); + force_sig (sig, current); } asmlinkage void set_esp0 (unsigned long ssp) diff -u --recursive --new-file v1.3.98/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c --- v1.3.98/linux/arch/m68k/mm/fault.c Tue Apr 23 13:57:08 1996 +++ linux/arch/m68k/mm/fault.c Mon May 6 12:44:30 1996 @@ -93,7 +93,7 @@ bad_area: if (user_mode(regs)) { /* User memory access */ - send_sig (SIGSEGV, current, 1); + force_sig (SIGSEGV, current); return 1; } diff -u --recursive --new-file v1.3.98/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v1.3.98/linux/arch/m68k/mm/memory.c Sat Apr 27 15:19:48 1996 +++ linux/arch/m68k/mm/memory.c Mon May 6 12:44:30 1996 @@ -506,7 +506,7 @@ : : "i" (FLUSH_I) : "d0"); } - +#if 1 void flush_cache_all(void) { if (m68k_is040or060 >= 4) @@ -515,26 +515,53 @@ asm volatile ("movec %/cacr,%/d0\n\t" "oriw %0,%/d0\n\t" "movec %/d0,%/cacr" - : : "i" (FLUSH_I) + : : "i" (FLUSH_I_AND_D) : "d0"); } -void flush_page_to_ram (unsigned long addr) +void flush_cache_mm(struct mm_struct *mm){ + + if (mm == current->mm) + flush_cache_all(); +} + +void flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end){ + if (mm == current->mm) + cache_push_v(start, end-start); +} + +void flush_cache_page (struct vm_area_struct *vma, unsigned long vaddr) { - if (m68k_is040or060 == 4) - pushv040(addr); + if (m68k_is040or060 >= 4) + pushv040(vaddr); /* + * the 040 always invalidates the I-cache when + * pushing its contents to ram. + */ + + /* 68030/68020 have no writeback cache; still need to clear icache. */ + else /* 68030 or 68020 */ + asm volatile ("movec %/cacr,%/d0\n\t" + "oriw %0,%/d0\n\t" + "movec %/d0,%/cacr" + : : "i" (FLUSH_I_AND_D) + : "d0"); +} - else if (m68k_is040or060 == 6) - push040(VTOP(addr)); /* someone mentioned that pushv060 doesn't work */ +void flush_page_to_ram (unsigned long vaddr) +{ + if (m68k_is040or060 >= 4) + pushcl040(VTOP(vaddr)); /* 68030/68020 have no writeback cache; still need to clear icache. */ else /* 68030 or 68020 */ asm volatile ("movec %/cacr,%/d0\n\t" "oriw %0,%/d0\n\t" "movec %/d0,%/cacr" - : : "i" (FLUSH_I) + : : "i" (FLUSH_I_AND_D) : "d0"); } +#endif #undef clear040 #undef push040 diff -u --recursive --new-file v1.3.98/linux/arch/mips/config.in linux/arch/mips/config.in --- v1.3.98/linux/arch/mips/config.in Fri Apr 12 15:51:46 1996 +++ linux/arch/mips/config.in Sun May 5 09:05:58 1996 @@ -45,7 +45,9 @@ bool 'Networking support' CONFIG_NET #bool 'PCI bios support' CONFIG_PCI #if [ "$CONFIG_PCI" = "y" ]; then -# bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE +# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE +# fi #fi bool 'System V IPC' CONFIG_SYSVIPC endmenu diff -u --recursive --new-file v1.3.98/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S --- v1.3.98/linux/arch/mips/kernel/head.S Fri Apr 12 15:51:46 1996 +++ linux/arch/mips/kernel/head.S Mon May 6 12:26:03 1996 @@ -49,8 +49,8 @@ eret /* * Workaround for R4000 bug. For explanation see MIPS - * docs. Note that this that obscure that it wont almost - * never happen. Well, but Mips writes about it's bugs. + * docs. Note that this is so obscure that it will almost + * never happen. Well, but Mips writes about its bugs. */ nop eret diff -u --recursive --new-file v1.3.98/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c --- v1.3.98/linux/arch/mips/kernel/time.c Wed Dec 13 12:39:44 1995 +++ linux/arch/mips/kernel/time.c Mon May 6 12:26:03 1996 @@ -202,7 +202,7 @@ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ /* As we return to user mode fire off the other CPU schedulers.. this is basically because we don't yet share IRQ's around. This message is - rigged to be safe on the 386 - basically its a hack, so don't look + rigged to be safe on the 386 - basically it's a hack, so don't look closely for now.. */ smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); } diff -u --recursive --new-file v1.3.98/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v1.3.98/linux/arch/mips/mm/init.c Fri Apr 12 15:51:47 1996 +++ linux/arch/mips/mm/init.c Mon May 6 12:26:03 1996 @@ -168,7 +168,7 @@ { /* * The page copied most is the COW empty_zero_page. Since we - * know it's contents we can avoid the writeback reading of + * know its contents we can avoid the writeback reading of * the page. Speeds up the standard case a lot. */ __zeropage(to); diff -u --recursive --new-file v1.3.98/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v1.3.98/linux/arch/ppc/config.in Tue Feb 13 10:30:24 1996 +++ linux/arch/ppc/config.in Sun May 5 09:05:58 1996 @@ -29,7 +29,9 @@ #bool 'Limit memory to low 16MB' CONFIG_MAX_16M n bool 'PCI bios support' CONFIG_PCI y if [ "$CONFIG_PCI" = "y" ]; then - bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n + fi if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then bool ' PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y fi diff -u --recursive --new-file v1.3.98/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v1.3.98/linux/arch/ppc/kernel/head.S Fri Apr 12 15:51:47 1996 +++ linux/arch/ppc/kernel/head.S Mon May 6 12:26:03 1996 @@ -1287,8 +1287,8 @@ /* * This routine switches between two different tasks. The process - * state of one is saved on it's kernel stack. Then the state - * of the other is restored from it's kernel stack. The memory + * state of one is saved on its kernel stack. Then the state + * of the other is restored from its kernel stack. The memory * management hardware is updated to the second process's state. * Finally, we can return to the second process, via the 'return'. * diff -u --recursive --new-file v1.3.98/linux/arch/sparc/boot/README linux/arch/sparc/boot/README --- v1.3.98/linux/arch/sparc/boot/README Wed Apr 24 17:00:34 1996 +++ linux/arch/sparc/boot/README Mon May 6 12:26:03 1996 @@ -4,7 +4,7 @@ off of the root partition but also be able to netboot. This means that it knows about RPC and NFS (bleech, yuck, eeewwwww!!) so that it can remote mount the root directory to fetch the kernel. Also it must -be able to ARP for it's IP address and who it's boot server is. I +be able to ARP for its IP address and who its boot server is. I think I'm getting sick. Regardless for now I will concentrate on the low-level stuff necessary diff -u --recursive --new-file v1.3.98/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v1.3.98/linux/arch/sparc/kernel/head.S Sat Apr 27 15:19:48 1996 +++ linux/arch/sparc/kernel/head.S Mon May 6 12:26:03 1996 @@ -497,7 +497,7 @@ std %g4, [%g3 + 0x8] ! Copy proms handler /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT - * MMU so we can remap ourselves properly. DONT TOUCH %l0 thru %l5 in these + * MMU so we can remap ourselves properly. DON'T TOUCH %l0 thru %l5 in these * remapping routines, we need their values afterwards! */ /* Now check whether we are already mapped, if we @@ -571,7 +571,7 @@ /* Grrr, why does it seem like every other load/store * on the sun4m is in some ASI space... * Fine with me, let's get the pointer to the level 1 - * page table directory and fetch it's entry. + * page table directory and fetch its entry. */ lda [%g4] ASI_M_BYPASS, %o1 ! This is a level 1 ptr srl %o1, 0x4, %o1 ! Clear low 4 bits diff -u --recursive --new-file v1.3.98/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v1.3.98/linux/arch/sparc/kernel/irq.c Sat Apr 27 15:19:48 1996 +++ linux/arch/sparc/kernel/irq.c Mon May 6 12:26:03 1996 @@ -81,7 +81,7 @@ * equally sucky but at least we'll never try to free statically allocated * space or call kmalloc before kmalloc_init :(. * - * In fact its the timer10 that attaches first.. then timer14 + * In fact it's the timer10 that attaches first.. then timer14 * then kmalloc_init is called.. then the tty interrupts attach. * hmmm.... * diff -u --recursive --new-file v1.3.98/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v1.3.98/linux/arch/sparc/kernel/sparc-stub.c Sat Apr 27 15:19:48 1996 +++ linux/arch/sparc/kernel/sparc-stub.c Mon May 6 12:26:03 1996 @@ -13,7 +13,7 @@ THIS SOFTWARE IS NOT COPYRIGHTED HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or it's performance and the + warranty with regard to the software or its performance and the user accepts the software "AS IS" with all faults. HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD diff -u --recursive --new-file v1.3.98/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c --- v1.3.98/linux/arch/sparc/kernel/sun4m_irq.c Wed Apr 24 17:00:35 1996 +++ linux/arch/sparc/kernel/sun4m_irq.c Mon May 6 12:26:03 1996 @@ -41,10 +41,10 @@ /* These tables only apply for interrupts greater than 15.. * * any intr value below 0x10 is considered to be a soft-int - * this may be useful or it may not.. but thats how I've done it. + * this may be useful or it may not.. but that's how I've done it. * and it won't clash with what OBP is telling us about devices. * - * take an encoded intr value and lookup if its valid + * take an encoded intr value and lookup if it's valid * then get the mask bits that match from irq_mask */ static unsigned char irq_xlate[32] = { diff -u --recursive --new-file v1.3.98/linux/arch/sparc/kernel/switch.S linux/arch/sparc/kernel/switch.S --- v1.3.98/linux/arch/sparc/kernel/switch.S Sun Apr 21 19:22:00 1996 +++ linux/arch/sparc/kernel/switch.S Mon May 6 12:26:03 1996 @@ -66,7 +66,7 @@ #ifdef __SMP__ /* Because of nasty register windows this is the only way - * to start a processor into it's cpu_idle() thread. + * to start a processor into its cpu_idle() thread. */ .globl C_LABEL(sparc_cpusched) diff -u --recursive --new-file v1.3.98/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S --- v1.3.98/linux/arch/sparc/kernel/wof.S Sun Apr 21 19:22:01 1996 +++ linux/arch/sparc/kernel/wof.S Mon May 6 12:26:03 1996 @@ -130,7 +130,7 @@ /* Wow, user windows have to be dealt with, this is dirty * and messy as all hell. And difficult to follow if you * are approaching the infamous register window trap handling - * problem for the first time. DONT LOOK! + * problem for the first time. DON'T LOOK! * * Note that how the execution path works out, the new %wim * will be left for us in the global temporary register, diff -u --recursive --new-file v1.3.98/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v1.3.98/linux/arch/sparc/mm/srmmu.c Sat Apr 27 15:19:49 1996 +++ linux/arch/sparc/mm/srmmu.c Mon May 6 12:26:03 1996 @@ -1834,7 +1834,7 @@ } #endif if(!num_contexts) { - prom_printf("Something wrong, cant find cpu node in paging_init.\n"); + prom_printf("Something wrong, can't find cpu node in paging_init.\n"); prom_halt(); } diff -u --recursive --new-file v1.3.98/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v1.3.98/linux/arch/sparc/prom/tree.c Sun Apr 21 19:22:02 1996 +++ linux/arch/sparc/prom/tree.c Mon May 6 12:26:04 1996 @@ -83,7 +83,7 @@ return prom_nodeops->no_getprop(node, prop, buffer); } -/* Acquire an integer property and return it's value. Returns -1 +/* Acquire an integer property and return its value. Returns -1 * on failure. */ int diff -u --recursive --new-file v1.3.98/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v1.3.98/linux/drivers/block/Config.in Fri Apr 12 15:51:49 1996 +++ linux/drivers/block/Config.in Sun May 5 09:09:59 1996 @@ -42,7 +42,7 @@ define_bool CONFIG_BLK_DEV_HD y fi -bool 'XT harddisk support' CONFIG_BLK_DEV_XD +tristate 'XT harddisk support' CONFIG_BLK_DEV_XD bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR diff -u --recursive --new-file v1.3.98/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v1.3.98/linux/drivers/block/Makefile Sat Mar 16 13:52:13 1996 +++ linux/drivers/block/Makefile Sun May 5 09:09:40 1996 @@ -99,6 +99,10 @@ ifeq ($(CONFIG_BLK_DEV_XD),y) L_OBJS += xd.o +else + ifeq ($(CONFIG_BLK_DEV_XD),m) + M_OBJS += xd.o + endif endif ifeq ($(CONFIG_BLK_DEV_MD),y) diff -u --recursive --new-file v1.3.98/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.3.98/linux/drivers/block/README.ide Sun May 5 08:51:58 1996 +++ linux/drivers/block/README.ide Mon May 6 12:26:04 1996 @@ -485,7 +485,7 @@ I agreed that you might be able to concoct a benchmark that was affected, but it has had no real world effect for me or a lot of other people. Disabling IDE prefetch has the effect of a small increase in PCI bus busy at a time -when the CPU is giving all it's CPU cycles to the IDE driver (because the +when the CPU is giving all its CPU cycles to the IDE driver (because the RZ1000 can't run DMA and the driver has to be in a PIO loop) and therefore the CPU can't do much of anything else anyway. diff -u --recursive --new-file v1.3.98/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v1.3.98/linux/drivers/block/amiflop.c Sat Apr 27 15:19:50 1996 +++ linux/drivers/block/amiflop.c Mon May 6 12:44:30 1996 @@ -21,7 +21,7 @@ * - added command line and machine based default for "silent" df0 * * december 1995 adapted for 1.2.13pl4 by Joerg Dorchain - * - works but I think its inefficient. (look in redo_fd_request) + * - works but I think it's inefficient. (look in redo_fd_request) * But the changes were very efficient. (only three and a half lines) * * january 1995 added special ioctl for tracking down read/write problems @@ -675,7 +675,7 @@ len_desc;/* 2 */ unsigned short crc; /* on 68000 we got an alignment problem, but this compiler solves it by adding silently - adding a pad byte so data wont fit + adding a pad byte so data won't fit and this cost about 3h to discover.... */ unsigned char gap1[22]; /* for longword-alignedness (0x4e) */ }; @@ -1780,3 +1780,12 @@ return 0; } + +#ifndef MODULE +/* + * This is just a dummy function to keep fs/super.c happy. + */ +void floppy_eject(void) +{ +} +#endif diff -u --recursive --new-file v1.3.98/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c --- v1.3.98/linux/drivers/block/ataflop.c Sat Apr 27 15:19:50 1996 +++ linux/drivers/block/ataflop.c Mon May 6 12:44:30 1996 @@ -1945,4 +1945,12 @@ timer_table[FLOPPY_TIMER].fn = 0; kfree (DMABuffer); } +#else +/* + * This is just a dummy function to keep fs/super.c happy. + */ +void floppy_eject(void) +{ +} #endif + diff -u --recursive --new-file v1.3.98/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.3.98/linux/drivers/block/ll_rw_blk.c Wed Apr 24 17:00:36 1996 +++ linux/drivers/block/ll_rw_blk.c Mon May 6 07:28:51 1996 @@ -206,18 +206,18 @@ else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31)); } -static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk_index) +static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, + short disk_index) { kstat.dk_drive[disk_index]++; if (cmd == READ) { kstat.dk_drive_rio[disk_index]++; kstat.dk_drive_rblk[disk_index] += nr_sectors; - } - else if (cmd == WRITE) { + } else if (cmd == WRITE) { kstat.dk_drive_wio[disk_index]++; kstat.dk_drive_wblk[disk_index] += nr_sectors; } else - printk("drive_stat_acct: cmd not R/W?\n"); + printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n"); } /* @@ -289,9 +289,15 @@ if (blk_size[major]) if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) { bh->b_state = 0; - printk("attempt to access beyond end of device\n"); - printk("%s: rw=%d, want=%d, limit=%d\n", kdevname(bh->b_rdev), - rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]); + /* This may well happen - the kernel calls bread() + without checking the size of the device, e.g., + when mounting a device. */ + printk(KERN_INFO + "attempt to access beyond end of device\n"); + printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", + kdevname(bh->b_rdev), rw, + (sector + count)>>1, + blk_size[major][MINOR(bh->b_rdev)]); return; } /* Uhhuh.. Nasty dead-lock possible here.. */ @@ -330,7 +336,8 @@ max_req = (NR_REQUEST * 2) / 3; break; default: - printk("make_request: bad block dev cmd, must be R/W/RA/WA\n"); + printk(KERN_ERR "make_request: bad block dev cmd," + " must be R/W/RA/WA\n"); unlock_buffer(bh); return; } @@ -442,13 +449,13 @@ bh++; if (--nr <= 0) return; - }; + } dev = NULL; if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV) dev = blk_dev + major; if (!dev || !dev->request_fn) { - printk( + printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", kdevname(bh[0]->b_dev), bh[0]->b_blocknr); goto sorry; @@ -465,7 +472,7 @@ /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { if (bh[i] && bh[i]->b_size != correct_size) { - printk("ll_rw_block: device %s: " + printk(KERN_NOTICE "ll_rw_block: device %s: " "only %d-char blocks implemented (%lu)\n", kdevname(bh[0]->b_dev), correct_size, bh[i]->b_size); @@ -484,7 +491,7 @@ } if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) { - printk("Can't write to read-only device %s\n", + printk(KERN_NOTICE "Can't write to read-only device %s\n", kdevname(bh[0]->b_dev)); goto sorry; } @@ -519,7 +526,8 @@ struct semaphore sem = MUTEX_LOCKED; if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) { - printk("ll_rw_swap_file: trying to swap nonexistent block-device\n"); + printk(KERN_NOTICE "ll_rw_swap_file: trying to swap to" + " nonexistent block-device\n"); return; } switch (rw) { @@ -527,7 +535,8 @@ break; case WRITE: if (is_read_only(dev)) { - printk("Can't swap to read-only device %s\n", + printk(KERN_NOTICE + "Can't swap to read-only device %s\n", kdevname(dev)); return; } @@ -547,7 +556,8 @@ if (major==MD_MAJOR && md_map (MINOR(dev), &rdev, &rsector, buffersize >> 9)) { - printk ("Bad md_map in ll_rw_page_size\n"); + printk (KERN_ERR + "Bad md_map in ll_rw_page_size\n"); return; } #endif diff -u --recursive --new-file v1.3.98/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v1.3.98/linux/drivers/block/loop.c Wed Apr 24 17:00:37 1996 +++ linux/drivers/block/loop.c Mon May 6 07:28:51 1996 @@ -133,12 +133,12 @@ int size; if (S_ISREG(lo->lo_inode->i_mode)) - size = (lo->lo_inode->i_size - lo->lo_offset) / 1024; + size = (lo->lo_inode->i_size - lo->lo_offset) / BLOCK_SIZE; else { - if (blk_size[MAJOR(lo->lo_device)]) - size = ((blk_size[MAJOR(lo->lo_device)] - [MINOR(lo->lo_device)]) - - (lo->lo_offset/1024)); + kdev_t lodev = lo->lo_device; + if (blk_size[MAJOR(lodev)]) + size = blk_size[MAJOR(lodev)][MINOR(lodev)] - + lo->lo_offset / BLOCK_SIZE; else size = MAX_DISK_SIZE; } @@ -307,11 +307,15 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg) { struct loop_info info; + int err; if (!lo->lo_inode) return -ENXIO; if (!arg) return -EINVAL; + err = verify_area(VERIFY_READ, arg, sizeof(info)); + if (err) + return err; memcpy_fromfs(&info, arg, sizeof(info)); if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; @@ -349,11 +353,15 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg) { struct loop_info info; + int err; if (!lo->lo_inode) return -ENXIO; if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, arg, sizeof(info)); + if (err) + return err; memset(&info, 0, sizeof(info)); info.lo_number = lo->lo_number; info.lo_device = kdev_t_to_nr(lo->lo_inode->i_dev); diff -u --recursive --new-file v1.3.98/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v1.3.98/linux/drivers/block/xd.c Sun Mar 31 00:13:16 1996 +++ linux/drivers/block/xd.c Sun May 5 09:08:29 1996 @@ -17,6 +17,9 @@ * interrupts enabled and Linus didn't want to enable them in that first * phase. xd_geninit() is the place to do these kinds of things anyway, * he says. + * + * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu + * */ @@ -64,6 +67,7 @@ static XD_SIGNATURE xd_sigs[] = { { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */ + { 0x000B,"CRD18A Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */ { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, pat@it.com.au */ { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */ { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */ @@ -89,7 +93,11 @@ 6, /* Bits to shift to get real from partition */ 1 << 6, /* Number of partitions per real */ XD_MAXDRIVES, /* maximum number of real */ - xd_geninit, /* init function */ +#ifdef MODULE + NULL, /* called from init_module */ +#else + xd_geninit, /* init function */ +#endif xd, /* hd struct */ xd_sizes, /* block sizes */ 0, /* number */ @@ -726,4 +734,24 @@ if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) printk("xd_setparam: error setting characteristics for drive %d\n",drive); } + + +#ifdef MODULE +int init_module(void) +{ + int error = xd_init(); + if (!error) + { + printk(KERN_INFO "XD: Loaded as a module.\n"); + xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 }); + } + + return error; +} + +void cleanup_module(void) +{ + unregister_blkdev(MAJOR_NR, "xd"); +} +#endif /* MODULE */ diff -u --recursive --new-file v1.3.98/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v1.3.98/linux/drivers/cdrom/aztcd.c Sun May 5 08:51:59 1996 +++ linux/drivers/cdrom/aztcd.c Sun May 5 08:51:13 1996 @@ -150,7 +150,7 @@ Werner Zimmermann, April 29, 96 V2.40 Reorganized the placement of functions in the source code file to reflect the layered approach; did not actually change code - Werner Zimmermann, Mai 1, 96 + Werner Zimmermann, May 1, 96 */ #include #include diff -u --recursive --new-file v1.3.98/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog --- v1.3.98/linux/drivers/char/ChangeLog Sun May 5 08:51:59 1996 +++ linux/drivers/char/ChangeLog Sun May 5 08:51:13 1996 @@ -1,6 +1,6 @@ Wed Apr 24 14:02:04 1996 Theodore Ts'o - * random.c (add_timer_randomness): Use 2nd derivitive as well to + * random.c (add_timer_randomness): Use 2nd derivative as well to better estimate entropy. (rand_initialize): Explicitly initialize all the pointers diff -u --recursive --new-file v1.3.98/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.3.98/linux/drivers/char/console.c Wed Mar 20 11:39:51 1996 +++ linux/drivers/char/console.c Mon May 6 07:28:51 1996 @@ -864,7 +864,7 @@ toggle_meta = 0; break; case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, let's + * Select first alternate font, lets * chars < 32 be displayed as ROM chars. */ translate = set_translate(IBMPC_MAP); diff -u --recursive --new-file v1.3.98/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c --- v1.3.98/linux/drivers/char/fbmem.c Tue Apr 23 13:57:09 1996 +++ linux/drivers/char/fbmem.c Mon May 6 12:44:31 1996 @@ -45,6 +45,10 @@ if (!current->tty) return fg_console; + if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + /* XXX Should report error here? */ + return fg_console; + if (MINOR(current->tty->device) < 1) return fg_console; @@ -180,6 +184,18 @@ if (i) return i; } return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE())); + case FBIOPAN_DISPLAY: + i = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct fb_var_screeninfo)); + if (i) return i; + memcpy_fromfs(&var, (void *) arg, sizeof(var)); + i=fb->fb_pan_display(&var, PROC_CONSOLE()); + memcpy_tofs((void *) arg, &var, sizeof(var)); + fbidx=GET_FB_IDX(inode->i_rdev); + vidx=GET_FB_VAR_IDX(inode->i_rdev); + if (! i && vidx) + registered_fb_var[fbidx][vidx-1]=var; + return i; default: return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE())); } @@ -199,8 +215,11 @@ vma->vm_offset += fix.smem_start; if (vma->vm_offset & ~PAGE_MASK) return -ENXIO; - if (boot_info.cputype & CPU_68040) + if (m68k_is040or060) { pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; + /* Use write-through cache mode */ + pgprot_val(vma->vm_page_prot) |= _PAGE_CACHE040W; + } if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; diff -u --recursive --new-file v1.3.98/linux/drivers/char/ftape/ftape-read.c linux/drivers/char/ftape/ftape-read.c --- v1.3.98/linux/drivers/char/ftape/ftape-read.c Thu Mar 14 11:53:45 1996 +++ linux/drivers/char/ftape/ftape-read.c Mon May 6 12:26:05 1996 @@ -606,8 +606,8 @@ * get more than 29 Kb from it (As it only contains this much). * This works only for sequential access, so random access should * stay away from this `last' segment. - * Note: ftape_seg_pos points to the next segment what will be - * read, so it's one too hight here! + * Note: ftape_seg_pos points to the next segment that will be + * read, so it's one too high here! */ if (!eof_mark && ftape_seg_pos - 1 >= ftape_last_segment.id) { TRACEi(5, "remaining of last segment:", remaining); diff -u --recursive --new-file v1.3.98/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c --- v1.3.98/linux/drivers/char/ftape/kernel-interface.c Sat Mar 16 23:13:55 1996 +++ linux/drivers/char/ftape/kernel-interface.c Mon May 6 12:26:05 1996 @@ -45,7 +45,7 @@ /* Global vars. */ -/* Allocating a 96Kb DMAable buffer in one chunk wont work due to +/* Allocating a 96Kb DMAable buffer in one chunk won't work due to * memory fragmentation. To avoid this, it is broken up into * NR_BUFFERS chunks of 32Kbyte. --khp */ diff -u --recursive --new-file v1.3.98/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v1.3.98/linux/drivers/char/istallion.c Wed Apr 24 17:00:38 1996 +++ linux/drivers/char/istallion.c Mon May 6 12:26:05 1996 @@ -3386,7 +3386,7 @@ } /* - * The per-board operations structure is all setup, so now lets go + * The per-board operations structure is all set up, so now let's go * and get the board operational. Firstly initialize board configuration * registers. Then if we are using the higher 1Mb support then set up * the memory mapping info so we can get at the boards shared memory. @@ -3542,7 +3542,7 @@ } /* - * The per-board operations structure is all setup, so now lets go + * The per-board operations structure is all set up, so now let's go * and get the board operational. Firstly initialize board configuration * registers. Then if we are using the higher 1Mb support then set up * the memory mapping info so we can get at the boards shared memory. diff -u --recursive --new-file v1.3.98/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v1.3.98/linux/drivers/char/lp.c Sun May 5 08:51:59 1996 +++ linux/drivers/char/lp.c Mon May 6 13:20:19 1996 @@ -183,14 +183,14 @@ if (lp_table[minor].runchars > LP_STAT(minor).maxrun) LP_STAT(minor).maxrun = lp_table[minor].runchars; status = LP_S(minor); - if ((status & LP_OFFL) || !(status & LP_PSELECD)) { - printk(KERN_INFO "lp%d off-line\n", minor); - if (LP_F(minor) & LP_ABORT) - return rc?rc:-EIO; - } else if ((status & LP_POUTPA)) { + if ((status & LP_POUTPA)) { printk(KERN_INFO "lp%d out of paper\n", minor); if (LP_F(minor) & LP_ABORT) return rc?rc:-ENOSPC; + } else if (!(status & LP_PSELECD)) { + printk(KERN_INFO "lp%d off-line\n", minor); + if (LP_F(minor) & LP_ABORT) + return rc?rc:-EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d printer error\n", minor); if (LP_F(minor) & LP_ABORT) @@ -248,18 +248,18 @@ LP_STAT(minor).maxrun = lp_table[minor].runchars; status = LP_S(minor); - if ((status & LP_OFFL) || !(status & LP_PSELECD)) { - printk(KERN_INFO "lp%d off-line\n", minor); + if (status & LP_POUTPA) { + printk(KERN_INFO "lp%d out of paper\n", minor); if(LP_F(minor) & LP_ABORT) - return temp-buf?temp-buf:-EIO; + return temp-buf?temp-buf:-ENOSPC; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIMEOUT_POLLED; schedule(); } else - if (status & LP_POUTPA) { - printk(KERN_INFO "lp%d out of paper\n", minor); + if (!(status & LP_PSELECD)) { + printk(KERN_INFO "lp%d off-line\n", minor); if(LP_F(minor) & LP_ABORT) - return temp-buf?temp-buf:-ENOSPC; + return temp-buf?temp-buf:-EIO; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIMEOUT_POLLED; schedule(); diff -u --recursive --new-file v1.3.98/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c --- v1.3.98/linux/drivers/char/lp_m68k.c Sat Apr 27 15:19:51 1996 +++ linux/drivers/char/lp_m68k.c Mon May 6 12:49:43 1996 @@ -236,13 +236,13 @@ been printed at all. */ if (lp_table[dev].lp_has_pout(dev)) { - printk("lp%d: paper-out\n",dev); + printk(KERN_NOTICE "lp%d: paper-out\n",dev); if (!rc) rc = -ENOSPC; } else if (!lp_table[dev].lp_is_online(dev)) { - printk("lp%d: off-line\n",dev); + printk(KERN_NOTICE "lp%d: off-line\n",dev); if (!rc) rc = -EIO; } else if (lp_table[dev].lp_is_busy(dev)) { - printk("lp%d: on fire\n",dev); + printk(KERN_NOTICE "lp%d: on fire\n",dev); if (!rc) rc = -EIO; } if (lp_table[dev].flags & LP_ABORT) @@ -294,14 +294,14 @@ #endif } else { /* if printer timed out */ if (lp_table[dev].lp_has_pout(dev)) { - printk("lp%d: out of paper\n",dev); + printk(KERN_NOTICE "lp%d: out of paper\n",dev); if (lp_table[dev].flags & LP_ABORT) return temp - buf ? temp-buf : -ENOSPC; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIMEOUT_POLLED; schedule(); } else if (!lp_table[dev].lp_is_online(dev)) { - printk("lp%d: off-line\n",dev); + printk(KERN_NOTICE "lp%d: off-line\n",dev); if (lp_table[dev].flags & LP_ABORT) return temp - buf ? temp-buf : -EIO; current->state = TASK_INTERRUPTIBLE; @@ -310,7 +310,7 @@ } else /* not offline or out of paper. on fire? */ if (lp_table[dev].lp_is_busy(dev)) { - printk("lp%d: on fire\n",dev); + printk(KERN_NOTICE "lp%d: on fire\n",dev); if (lp_table[dev].flags & LP_ABORT) return temp - buf ? temp-buf : -EFAULT; current->state = TASK_INTERRUPTIBLE; @@ -447,7 +447,7 @@ #if WHICH_DRIVER == FORCE_POLLING lp_irq = 0; - printk("lp_init: lp using polling driver\n"); + printk(KERN_INFO "lp_init: lp using polling driver\n"); #else #ifdef CONFIG_AMIGA @@ -462,13 +462,13 @@ #endif if (lp_irq) - printk("lp_init: lp using interrupt\n"); + printk(KERN_INFO "lp_init: lp using interrupt\n"); else #if WHICH_DRIVER == PREFER_INTERRUPT - printk("lp_init: lp using polling driver\n"); + printk(KERN_INFO "lp_init: lp using polling driver\n"); #else - printk("lp_init: cant get interrupt, and polling driver not configured\n"); + printk(KERN_WARNING "lp_init: can't get interrupt, and polling driver not configured\n"); #endif #endif diff -u --recursive --new-file v1.3.98/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v1.3.98/linux/drivers/char/pcxx.c Fri Apr 19 10:07:58 1996 +++ linux/drivers/char/pcxx.c Mon May 6 12:26:06 1996 @@ -38,7 +38,7 @@ 19200 = 57600 38400 = 115K The driver supports the native 57.6K and 115K Baudrates under Linux, but - some distributions like Slackware 3.0 dont like these high baudrates. + some distributions like Slackware 3.0 don't like these high baudrates. */ #include @@ -1602,7 +1602,7 @@ { ch->digiext.digi_flags |= DIGI_FAST; res |= FEP_HUPCL; - /* This gets strange but if we dont do this we will get 78600 + /* This gets strange but if we don't do this we will get 78600 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in * FAST mode. 115200 is mapped to 75. We need to map it to 110 to * do 115K diff -u --recursive --new-file v1.3.98/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v1.3.98/linux/drivers/char/psaux.c Tue Apr 2 13:32:20 1996 +++ linux/drivers/char/psaux.c Tue May 7 12:30:49 1996 @@ -315,13 +315,13 @@ aux_count--; return -EBUSY; } + MOD_INC_USE_COUNT; poll_aux_status(); outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */ aux_write_dev(AUX_ENABLE_DEV); /* enable aux device */ aux_write_cmd(AUX_INTS_ON); /* enable controller ints */ poll_aux_status(); aux_ready = 0; - MOD_INC_USE_COUNT; return 0; } diff -u --recursive --new-file v1.3.98/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v1.3.98/linux/drivers/char/pty.c Sat Apr 27 15:19:51 1996 +++ linux/drivers/char/pty.c Mon May 6 14:56:04 1996 @@ -181,7 +181,9 @@ int pty_open(struct tty_struct *tty, struct file * filp) { +#if PTY_SLAVE_WAITS_ON_OPEN struct wait_queue wait = { current, NULL }; +#endif int retval; int line; struct pty_struct *pty; diff -u --recursive --new-file v1.3.98/linux/drivers/char/random.c linux/drivers/char/random.c --- v1.3.98/linux/drivers/char/random.c Sun May 5 08:51:59 1996 +++ linux/drivers/char/random.c Sun May 5 08:51:13 1996 @@ -169,7 +169,7 @@ * fi * dd if=/dev/urandom of=/etc/random-seed count=1 * - * and the following lines in an approproate script which is run as + * and the following lines in an appropriate script which is run as * the system is shutdown: * * # Carry a random seed from shut-down to start-up @@ -574,7 +574,7 @@ #define HASH_TRANSFORM SHATransform /* - * SHA transform algorith, taken from code written by Peter Gutman, + * SHA transform algorithm, taken from code written by Peter Gutman, * and apparently in the public domain. */ @@ -615,7 +615,7 @@ E = digest[ 4 ]; memcpy( eData, data, 16*sizeof(__u32)); - /* Heavy mangling, in 4 sub-rounds of 20 interations each. */ + /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */ subRound( A, B, C, D, E, f1, K1, eData[ 0 ] ); subRound( E, A, B, C, D, f1, K1, eData[ 1 ] ); subRound( D, E, A, B, C, f1, K1, eData[ 2 ] ); diff -u --recursive --new-file v1.3.98/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v1.3.98/linux/drivers/char/rtc.c Sun May 5 08:51:59 1996 +++ linux/drivers/char/rtc.c Tue May 7 08:18:50 1996 @@ -30,7 +30,7 @@ * */ -#define RTC_VERSION "1.05" +#define RTC_VERSION "1.06" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_BASE 0x70 /* Or this... */ @@ -56,8 +56,6 @@ #include #include -#include - /* * We sponge a minor off of the misc major. No need slurping * up another valuable major dev number for this. @@ -81,14 +79,14 @@ static int rtc_select(struct inode *inode, struct file *file, int sel_type, select_table *wait); -void get_rtc_time (struct tm *rtc_tm); -void get_rtc_alm_time (struct tm *alm_tm); +void get_rtc_time (struct rtc_time *rtc_tm); +void get_rtc_alm_time (struct rtc_time *alm_tm); void rtc_dropped_irq(unsigned long data); -inline void set_rtc_irq_bit(unsigned char bit); -inline void mask_rtc_irq_bit(unsigned char bit); +void set_rtc_irq_bit(unsigned char bit); +void mask_rtc_irq_bit(unsigned char bit); -unsigned char rtc_is_updating(void); +static inline unsigned char rtc_is_updating(void); /* * Bits in rtc_status. (7 bits of room for future expansion) @@ -221,10 +219,7 @@ * than 64Hz of interrupts on a multi-user machine. */ if ((rtc_freq > 64) && (!suser())) - return -EPERM; - - if (rtc_freq == 0) - return -EINVAL; + return -EACCES; if (!(rtc_status & RTC_TIMER_ON)) { rtc_status |= RTC_TIMER_ON; @@ -247,39 +242,39 @@ case RTC_ALM_READ: /* Read the present alarm time */ { /* - * This returns a struct tm. Reading >= 0xc0 means - * "don't care" or "match all". Only the tm_hour, + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, * tm_min, and tm_sec values are filled in. */ int retval; - struct tm alm_tm; + struct rtc_time alm_tm; - retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm)); + retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time)); if (retval != 0 ) return retval; get_rtc_alm_time(&alm_tm); - memcpy_tofs((struct tm*)arg, &alm_tm, sizeof(struct tm)); + memcpy_tofs((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time)); return 0; } case RTC_ALM_SET: /* Store a time into the alarm */ { /* - * This expects a struct tm. Writing 0xff means + * This expects a struct rtc_time. Writing 0xff means * "don't care" or "match all". Only the tm_hour, * tm_min and tm_sec are used. */ int retval; unsigned char hrs, min, sec; - struct tm alm_tm; + struct rtc_time alm_tm; - retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm)); + retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time)); if (retval != 0 ) return retval; - memcpy_fromfs(&alm_tm, (struct tm*)arg, sizeof(struct tm)); + memcpy_fromfs(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)); hrs = alm_tm.tm_hour; min = alm_tm.tm_min; @@ -313,33 +308,33 @@ case RTC_RD_TIME: /* Read the time/date from RTC */ { int retval; - struct tm rtc_tm; + struct rtc_time rtc_tm; - retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm)); + retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time)); if (retval !=0 ) return retval; get_rtc_time(&rtc_tm); - memcpy_tofs((struct tm*)arg, &rtc_tm, sizeof(struct tm)); + memcpy_tofs((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)); return 0; } case RTC_SET_TIME: /* Set the RTC */ { int retval; - struct tm rtc_tm; + struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; unsigned char save_control, save_freq_select; unsigned int yrs; unsigned long flags; if (!suser()) - return -EPERM; + return -EACCES; - retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm)); + retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time)); if (retval !=0 ) return retval; - memcpy_fromfs(&rtc_tm, (struct tm*)arg, sizeof(struct tm)); + memcpy_fromfs(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)); yrs = rtc_tm.tm_year + 1900; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ @@ -424,7 +419,7 @@ * than 64Hz of interrupts on a multi-user machine. */ if ((arg > 64) && (!suser())) - return -EPERM; + return -EACCES; while (arg > (1<tm_year <= 69) rtc_tm->tm_year += 100; @@ -741,7 +730,7 @@ rtc_tm->tm_mon--; } -void get_rtc_alm_time(struct tm *alm_tm) +void get_rtc_alm_time(struct rtc_time *alm_tm) { unsigned long flags; unsigned char ctrl; @@ -775,7 +764,7 @@ * We also clear out any old irq data after an ioctl() that * meddles the interrupt enable/disable bits. */ -inline void mask_rtc_irq_bit(unsigned char bit) +void mask_rtc_irq_bit(unsigned char bit) { unsigned char val; unsigned long flags; @@ -790,7 +779,7 @@ rtc_irq_data = 0; } -inline void set_rtc_irq_bit(unsigned char bit) +void set_rtc_irq_bit(unsigned char bit) { unsigned char val; unsigned long flags; diff -u --recursive --new-file v1.3.98/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v1.3.98/linux/drivers/char/stallion.c Wed Apr 24 17:00:38 1996 +++ linux/drivers/char/stallion.c Mon May 6 12:26:06 1996 @@ -495,7 +495,7 @@ /* * Free up all allocated resources used by the ports. This includes * memory and interrupts. As part of this process we will also do - * a hangup on every open port - to try and flush out any processes + * a hangup on every open port - to try to flush out any processes * hanging onto ports. */ i = tty_unregister_driver(&stl_serial); @@ -2383,7 +2383,7 @@ /*****************************************************************************/ /* - * Try and find and initialize all the ports on a panel. We don't care + * Try to find and initialize all the ports on a panel. We don't care * what sort of board these ports are on - since the port io registers * are almost identical when dealing with ports. */ @@ -2861,7 +2861,7 @@ #ifdef CONFIG_PCI /* - * If the PCI BIOS support is compiled in then lets go looking for + * If the PCI BIOS support is compiled in then let's go looking for * ECH-PCI boards. */ stl_findpcibrds(); diff -u --recursive --new-file v1.3.98/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v1.3.98/linux/drivers/char/vc_screen.c Tue Oct 10 10:31:02 1995 +++ linux/drivers/char/vc_screen.c Tue May 7 07:50:53 1996 @@ -149,7 +149,7 @@ org = screen_pos(cons, p, viewed); while (count-- > 0) { scr_writew((scr_readw(org) & 0xff00) | - get_user(buf++), org); + get_user((const unsigned char*)buf++), org); org++; } } else { @@ -175,7 +175,7 @@ } if (count > 0) scr_writew((scr_readw(org) & 0xff00) | - get_user(buf++), org); + get_user((const unsigned char*)buf++), org); } written = buf - buf0; file->f_pos += written; diff -u --recursive --new-file v1.3.98/linux/drivers/char/vga.c linux/drivers/char/vga.c --- v1.3.98/linux/drivers/char/vga.c Fri Mar 15 11:01:46 1996 +++ linux/drivers/char/vga.c Tue May 7 07:50:53 1996 @@ -29,6 +29,10 @@ * Colour palette handling, by Simon Tatham * 17-Jun-95 * + * if 512 char mode is already enabled don't re-enable it, + * because it causes screen to flicker, by Mitja Horvat + * 5-May-96 + * */ #include @@ -308,6 +312,7 @@ set_get_font(char * arg, int set, int ch512) { #ifdef CAN_LOAD_EGA_FONTS + static int ch512enabled = 0; int i; char *charmap; int beg; @@ -432,8 +437,11 @@ outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */ outb_p( 0x06, gr_port_reg ); outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */ - if (set) /* attribute controller */ + + /* if 512 char mode is already enabled don't re-enable it. */ + if ((set)&&(ch512!=ch512enabled)) /* attribute controller */ { + ch512enabled=ch512; /* 256-char: enable intensity bit 512-char: disable intensity bit */ inb_p( video_port_status ); /* clear address flip-flop */ diff -u --recursive --new-file v1.3.98/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v1.3.98/linux/drivers/isdn/isdn_common.c Sun Apr 21 19:22:06 1996 +++ linux/drivers/isdn/isdn_common.c Mon May 6 12:26:06 1996 @@ -489,7 +489,7 @@ break; if ((mi = dev->m_idx[i]) >= 0) { /* Schedule CONNECT-Message to any tty, waiting for it and - * set DCD-bit of it's modem-status. + * set DCD-bit of its modem-status. */ if (dev->mdm.info[mi].flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { diff -u --recursive --new-file v1.3.98/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v1.3.98/linux/drivers/isdn/isdn_net.c Sun Apr 21 19:22:06 1996 +++ linux/drivers/isdn/isdn_net.c Mon May 6 12:26:06 1996 @@ -46,7 +46,7 @@ * Correct ARP-handling for ETHERNET-encapsulation. * * Revision 1.2 1996/01/22 05:05:12 fritz - * Changed returncode-logic for isdn_net_start_xmit() and it's + * Changed returncode-logic for isdn_net_start_xmit() and its * helper-functions. * Changed handling of buildheader for RAWIP and ETHERNET-encapsulation. * @@ -195,7 +195,7 @@ /* * Handle status-messages from ISDN-interfacecard. * This function is called from within the main-status-dispatcher - * isdn_status_callback, which itself is called from the lowlevel-driver. + * isdn_status_callback, which itself is called from the low-level driver. * Return: 1 = Event handled, 0 = not for us or unknown Event. */ int @@ -1200,7 +1200,7 @@ return 0; } /* - * Try and get ARP to resolve the header. + * Try to get ARP to resolve the header. */ #ifdef CONFIG_INET ret = arp_find((unsigned char *)&(eth->h_dest), dst, dev, dev->pa_addr,skb)? 1 : 0; @@ -1775,7 +1775,7 @@ } /* - * Allocate a new network-interface and initialize it's data structures. + * Allocate a new network-interface and initialize its data structures. */ char * isdn_net_new(char *name, struct device *master) diff -u --recursive --new-file v1.3.98/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v1.3.98/linux/drivers/isdn/isdn_ppp.c Sun Apr 21 19:22:06 1996 +++ linux/drivers/isdn/isdn_ppp.c Mon May 6 12:26:07 1996 @@ -802,10 +802,12 @@ isdn_net_local *lp = nd->queue; int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt = ippp_table[lp->ppp_minor]; +#if defined(CONFIG_ISDN_PPP_VJ) || defined(CONFIG_ISDN_MPP) struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor]; +#endif /* If packet is to be resent, it has already been processed and - * therefore it's first bytes are already initialized. In this case + * therefore its first bytes are already initialized. In this case * send it immediately ... */ if (*((unsigned long *)skb->data) != 0) diff -u --recursive --new-file v1.3.98/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.3.98/linux/drivers/net/3c501.c Tue Apr 2 13:32:20 1996 +++ linux/drivers/net/3c501.c Mon May 6 12:26:07 1996 @@ -68,7 +68,7 @@ The combination of slow receive restart and no real multicast filter makes the board unusable with a kernel compiled for IP - multicasting in a real multicast environment. Thats down to the board, + multicasting in a real multicast environment. That's down to the board, but even with no multicast programs running a multicast IP kernel is in group 224.0.0.1 and you will therefore be listening to all multicasts. One nv conference running over that ethernet and you can give up. diff -u --recursive --new-file v1.3.98/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v1.3.98/linux/drivers/net/8390.c Fri Mar 1 07:50:42 1996 +++ linux/drivers/net/8390.c Mon May 6 11:41:57 1996 @@ -16,28 +16,30 @@ This is not a complete driver, it must be combined with board-specific code such as ne.c, wd.c, 3c503.c, etc. + Seeing how at least eight drivers use this code, (not counting the + PCMCIA ones either) it is easy to break some card by what seems like + a simple innocent change. Please contact me or Donald if you think + you have found something that needs changing. -- PG + + Changelog: Paul Gortmaker : remove set_bit lock, other cleanups. Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to ei_block_input() for eth_io_copy_and_sum(). + Paul Gortmaker : exchange static int ei_pingpong for a #define, + also add better Tx error handling. - */ -static const char *version = - "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - -/* - Braindamage remaining: - Much of this code should have been cleaned up, but every attempt - has broken some clone part. - Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. + */ -#include +static const char *version = + "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +#include #include #include #include @@ -87,18 +89,10 @@ #else int ei_debug = 1; #endif -#ifdef EI_PINGPONG -static int ei_pingpong = 1; -#else -static int ei_pingpong = 0; -#endif - -/* Max number of packets received at one Intr. - Currently this may only be examined by a kernel debugger. */ -static int high_water_mark = 0; /* Index to functions. */ static void ei_tx_intr(struct device *dev); +static void ei_tx_err(struct device *dev); static void ei_receive(struct device *dev); static void ei_rx_overrun(struct device *dev); @@ -141,8 +135,8 @@ { int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; - int length, send_length; - + int length, send_length, output_page; + /* * We normally shouldn't be called if dev->tbusy is set, but the * existing code does anyway. If it has been too long since the @@ -161,6 +155,12 @@ return 1; } + /* + * Note that if the Tx posted a TX_ERR interrupt, then the + * error will have been handled from the interrupt handler. + * and not here. + */ + printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); @@ -199,53 +199,77 @@ send_length = ETH_ZLEN < length ? length : ETH_ZLEN; - if (ei_local->pingpong) { - int output_page; - if (ei_local->tx1 == 0) { - output_page = ei_local->tx_start_page; - ei_local->tx1 = send_length; - if (ei_debug && ei_local->tx2 > 0) - printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n", - dev->name, ei_local->tx2, ei_local->lasttx, - ei_local->txing); - } else if (ei_local->tx2 == 0) { - output_page = ei_local->tx_start_page + 6; - ei_local->tx2 = send_length; - if (ei_debug && ei_local->tx1 > 0) - printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", - dev->name, ei_local->tx1, ei_local->lasttx, - ei_local->txing); - } else { /* We should never get here. */ - if (ei_debug) - printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n", - dev->name, dev->interrupt, ei_local->tx1, - ei_local->tx2, ei_local->lasttx); - ei_local->irqlock = 0; - dev->tbusy = 1; - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - return 1; - } - ei_block_output(dev, length, skb->data, output_page); - if (! ei_local->txing) { - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, output_page); - dev->trans_start = jiffies; - if (output_page == ei_local->tx_start_page) - ei_local->tx1 = -1, ei_local->lasttx = -1; - else - ei_local->tx2 = -1, ei_local->lasttx = -2; - } else - ei_local->txqueue++; - - dev->tbusy = (ei_local->tx1 && ei_local->tx2); - } else { /* No pingpong, just a single Tx buffer. */ - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - dev->trans_start = jiffies; - dev->tbusy = 1; +#ifdef EI_PINGPONG + + /* + * We have two Tx slots available for use. Find the first free + * slot, and then perform some sanity checks. With two Tx bufs, + * you get very close to transmitting back-to-back packets. With + * only one Tx buf, the transmitter sits idle while you reload the + * card, leaving a substantial gap between each transmitted packet. + */ + + if (ei_local->tx1 == 0) { + output_page = ei_local->tx_start_page; + ei_local->tx1 = send_length; + if (ei_debug && ei_local->tx2 > 0) + printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n", + dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing); + } else if (ei_local->tx2 == 0) { + output_page = ei_local->tx_start_page + TX_1X_PAGES; + ei_local->tx2 = send_length; + if (ei_debug && ei_local->tx1 > 0) + printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", + dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing); + } else { /* We should never get here. */ + if (ei_debug) + printk("%s: No Tx buffers free! irq=%d tx1=%d tx2=%d last=%d\n", + dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx); + ei_local->irqlock = 0; + dev->tbusy = 1; + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + return 1; } - + + /* + * Okay, now upload the packet and trigger a send if the transmitter + * isn't already sending. If it is busy, the interrupt handler will + * trigger the send later, upon receiving a Tx done interrupt. + */ + + ei_block_output(dev, length, skb->data, output_page); + if (! ei_local->txing) { + ei_local->txing = 1; + NS8390_trigger_send(dev, send_length, output_page); + dev->trans_start = jiffies; + if (output_page == ei_local->tx_start_page) { + ei_local->tx1 = -1; + ei_local->lasttx = -1; + } else { + ei_local->tx2 = -1; + ei_local->lasttx = -2; + } + } else + ei_local->txqueue++; + + dev->tbusy = (ei_local->tx1 && ei_local->tx2); + +#else /* EI_PINGPONG */ + + /* + * Only one Tx buffer in use. You need two Tx bufs to come close to + * back-to-back transmits. Expect a 20 -> 25% performance hit on + * reasonable hardware if you only use one Tx buffer. + */ + + ei_block_output(dev, length, skb->data, ei_local->tx_start_page); + ei_local->txing = 1; + NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); + dev->trans_start = jiffies; + dev->tbusy = 1; + +#endif /* EI_PINGPONG */ + /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -305,18 +329,17 @@ /* Push the next to-transmit packet through. */ if (interrupts & ENISR_TX) { ei_tx_intr(dev); - } else if (interrupts & ENISR_COUNTERS) { + } else if (interrupts & ENISR_TX_ERR) { + ei_tx_err(dev); + } + + if (interrupts & ENISR_COUNTERS) { ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */ } - /* Ignore the transmit errs and reset intr for now. */ - if (interrupts & ENISR_TX_ERR) { - outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */ - } - /* Ignore any RDC interrupts that make it back to here. */ if (interrupts & ENISR_RDC) { outb_p(ENISR_RDC, e8390_base + EN0_ISR); @@ -340,6 +363,43 @@ return; } +/* + * A transmitter error has happened. Most likely excess collisions (which + * is a fairly normal condition). If the error is one where the Tx will + * have been aborted, we try and send another one right away, instead of + * letting the failed packet sit and collect dust in the Tx buffer. This + * is a much better solution as it avoids kernel based Tx timeouts, and + * an unnecessary card reset. + */ + +static void ei_tx_err(struct device *dev) +{ + int e8390_base = dev->base_addr; + unsigned char txsr = inb_p(e8390_base+EN0_TSR); + unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); + +#ifdef VERBOSE_ERROR_DUMP + printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr); + if (txsr & ENTSR_ABT) + printk("excess-collisions "); + if (txsr & ENTSR_ND) + printk("non-deferral "); + if (txsr & ENTSR_CRS) + printk("lost-carrier "); + if (txsr & ENTSR_FU) + printk("FIFO-underrun "); + if (txsr & ENTSR_CDH) + printk("lost-heartbeat "); + printk("\n"); +#endif + + outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */ + + if (tx_was_aborted) + ei_tx_intr(dev); + +} + /* We have finished a transmit: check for errors and then trigger the next packet to be sent. */ static void ei_tx_intr(struct device *dev) @@ -349,58 +409,68 @@ struct ei_device *ei_local = (struct ei_device *) dev->priv; outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */ - - if (ei_local->pingpong) { - ei_local->txqueue--; - if (ei_local->tx1 < 0) { - if (ei_local->lasttx != 1 && ei_local->lasttx != -1) - printk("%s: bogus last_tx_buffer %d, tx1=%d.\n", - ei_local->name, ei_local->lasttx, ei_local->tx1); - ei_local->tx1 = 0; - dev->tbusy = 0; - if (ei_local->tx2 > 0) { - ei_local->txing = 1; - NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6); - dev->trans_start = jiffies; - ei_local->tx2 = -1, - ei_local->lasttx = 2; - } else - ei_local->lasttx = 20, ei_local->txing = 0; - } else if (ei_local->tx2 < 0) { - if (ei_local->lasttx != 2 && ei_local->lasttx != -2) - printk("%s: bogus last_tx_buffer %d, tx2=%d.\n", - ei_local->name, ei_local->lasttx, ei_local->tx2); - ei_local->tx2 = 0; - dev->tbusy = 0; - if (ei_local->tx1 > 0) { - ei_local->txing = 1; - NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page); - dev->trans_start = jiffies; - ei_local->tx1 = -1; - ei_local->lasttx = 1; - } else - ei_local->lasttx = 10, ei_local->txing = 0; - } else - printk("%s: unexpected TX-done interrupt, lasttx=%d.\n", - dev->name, ei_local->lasttx); - } else { - ei_local->txing = 0; - dev->tbusy = 0; - } + +#ifdef EI_PINGPONG + + /* + * There are two Tx buffers, see which one finished, and trigger + * the send of another one if it exists. + */ + ei_local->txqueue--; + if (ei_local->tx1 < 0) { + if (ei_local->lasttx != 1 && ei_local->lasttx != -1) + printk("%s: bogus last_tx_buffer %d, tx1=%d.\n", + ei_local->name, ei_local->lasttx, ei_local->tx1); + ei_local->tx1 = 0; + dev->tbusy = 0; + if (ei_local->tx2 > 0) { + ei_local->txing = 1; + NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6); + dev->trans_start = jiffies; + ei_local->tx2 = -1, + ei_local->lasttx = 2; + } else + ei_local->lasttx = 20, ei_local->txing = 0; + } else if (ei_local->tx2 < 0) { + if (ei_local->lasttx != 2 && ei_local->lasttx != -2) + printk("%s: bogus last_tx_buffer %d, tx2=%d.\n", + ei_local->name, ei_local->lasttx, ei_local->tx2); + ei_local->tx2 = 0; + dev->tbusy = 0; + if (ei_local->tx1 > 0) { + ei_local->txing = 1; + NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page); + dev->trans_start = jiffies; + ei_local->tx1 = -1; + ei_local->lasttx = 1; + } else + ei_local->lasttx = 10, ei_local->txing = 0; + } else + printk("%s: unexpected TX-done interrupt, lasttx=%d.\n", + dev->name, ei_local->lasttx); + +#else /* EI_PINGPONG */ + /* + * Single Tx buffer: mark it free so another packet can be loaded. + */ + ei_local->txing = 0; + dev->tbusy = 0; +#endif /* Minimize Tx latency: update the statistics after we restart TXing. */ - if (status & ENTSR_COL) ei_local->stat.collisions++; + if (status & ENTSR_COL) + ei_local->stat.collisions++; if (status & ENTSR_PTX) - ei_local->stat.tx_packets++; + ei_local->stat.tx_packets++; else { - ei_local->stat.tx_errors++; - if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++; - if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; - if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++; - if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; - if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++; - } - + ei_local->stat.tx_errors++; + if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++; + if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; + if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++; + if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; + if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++; + } + mark_bh (NET_BH); } @@ -410,7 +480,8 @@ { int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; - int rxing_page, this_frame, next_frame, current_offset; + unsigned char rxing_page, this_frame, next_frame; + unsigned short current_offset; int rx_pkt_count = 0; struct e8390_pkt_hdr rx_frame; int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page; @@ -502,13 +573,6 @@ ei_local->current_page = next_frame; outb_p(next_frame-1, e8390_base+EN0_BOUNDARY); } - /* If any worth-while packets have been received, netif_rx() - has done a mark_bh(NET_BH) for us and will work on them - when we get to the bottom-half routine. */ - - /* Record the maximum Rx packet queue. */ - if (rx_pkt_count > high_water_mark) - high_water_mark = rx_pkt_count; /* We used to also ack ENISR_OVER here, but that would sometimes mask a real overrun, leaving the 8390 in a stopped state with rec'vr off. */ @@ -607,7 +671,6 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(struct ei_device)); ei_local = (struct ei_device *)dev->priv; - ei_local->pingpong = ei_pingpong; } dev->hard_start_xmit = &ei_start_xmit; diff -u --recursive --new-file v1.3.98/linux/drivers/net/8390.h linux/drivers/net/8390.h --- v1.3.98/linux/drivers/net/8390.h Mon Mar 25 10:27:57 1996 +++ linux/drivers/net/8390.h Tue May 7 14:19:33 1996 @@ -13,7 +13,15 @@ #define TX_2X_PAGES 12 #define TX_1X_PAGES 6 -#define TX_PAGES (ei_status.pingpong ? TX_2X_PAGES : TX_1X_PAGES) + +/* Should always use two Tx slots to get back-to-back transmits. */ +#define EI_PINGPONG + +#ifdef EI_PINGPONG +#define TX_PAGES TX_2X_PAGES +#else +#define TX_PAGES TX_1X_PAGES +#endif #define ETHER_ADDR_LEN 6 @@ -56,7 +64,6 @@ unsigned txing:1; /* Transmit Active */ unsigned irqlock:1; /* 8390's intrs disabled when '1'. */ unsigned dmaing:1; /* Remote DMA Active */ - unsigned pingpong:1; /* Using the ping-pong driver */ unsigned char tx_start_page, rx_start_page, stop_page; unsigned char current_page; /* Read pointer in buffer */ unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.98/linux/drivers/net/Makefile Sat Apr 27 15:19:53 1996 +++ linux/drivers/net/Makefile Mon May 6 12:44:31 1996 @@ -466,6 +466,14 @@ endif endif +ifeq ($(CONFIG_HYDRA),y) +L_OBJS += hydra.o +else + ifeq ($(CONFIG_HYDRA),m) + M_OBJS += hydra.o + endif +endif + ifeq ($(CONFIG_SDLA),y) L_OBJS += sdla.o else diff -u --recursive --new-file v1.3.98/linux/drivers/net/README.eql linux/drivers/net/README.eql --- v1.3.98/linux/drivers/net/README.eql Fri Apr 12 15:51:54 1996 +++ linux/drivers/net/README.eql Mon May 6 12:26:07 1996 @@ -29,7 +29,7 @@ my testing so far, the Livingston PortMaster 2e's load-balancing is a good 1 to 2 KB/s slower than the test machine working with a 28.8 Kbps and 14.4 Kbps connection. However, I am not sure that it really is - the PortMaster, or if its Linux's TCP drivers. I'm told that Linux's + the PortMaster, or if it's Linux's TCP drivers. I'm told that Linux's TCP implementation is pretty fast though.--) diff -u --recursive --new-file v1.3.98/linux/drivers/net/README.tunnel linux/drivers/net/README.tunnel --- v1.3.98/linux/drivers/net/README.tunnel Sun Jan 14 16:22:17 1996 +++ linux/drivers/net/README.tunnel Mon May 6 12:26:07 1996 @@ -6,7 +6,7 @@ A network tunneling driver encapsulates packets of one protocol type within packets of another protocol type. It sends them out over the network to a relay (or destination) where the -packet is unwrapped and is forwarded to it's ultimate destination. +packet is unwrapped and is forwarded to its ultimate destination. Packet tunneling is useful in situations where you want to route packets of a non-standard protocol type over the common network. A good example of this is 'IPX encapsulation', in which IPX packets @@ -41,7 +41,7 @@ based on the Linux loopback driver written (in part) by Ross Biro, Fred N. van Kempen, and Donald Becker. After the driver is loaded, it can be set up as any other network interface, using -ifconfig. The tunnel device is given it's own IP address, which +ifconfig. The tunnel device is given its own IP address, which can match that of the machine, and also is given a pointopoint address. This pointopoint address is the address of the machine providing the decapsulating endpoint for the IP tunnel. After @@ -54,7 +54,7 @@ The decapsulating endpoint must have loaded the ipip.o decapsulator module for it to understand IP-in-IP encapsulation. This module takes any IP-in-IP packet that is destined for the local -machine, unwraps it, and sends it on it's way, using standard +machine, unwraps it, and sends it on its way, using standard routing rules. The current implementation of IP decapsulation does no checking on the packet, other than making sure wrapper is bound for the local machine. @@ -106,11 +106,11 @@ and every incoming IP-in-IP packet bound for the local machine is unwrapped and re-routed normally. The only difference in the two machines setup shown above is that -machine A set it's tunnel address to one existing on machine B's +machine A set its tunnel address to one existing on machine B's network, while B set a route to machine A's tunnel device address through the tunnel. This is because machine A wants to have a new address on network B, and machine B is simply acting as a proxy -for machine A. Machine A needs it's tunnel address to be on network +for machine A. Machine A needs its tunnel address to be on network B so that when packets from machine B are unwrapped, the Linux routing system knows that the address is a local one. Due to a feature of Linux, any packets received locally, bound for another diff -u --recursive --new-file v1.3.98/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.3.98/linux/drivers/net/Space.c Sat Apr 27 15:19:53 1996 +++ linux/drivers/net/Space.c Mon May 6 12:44:31 1996 @@ -77,6 +77,7 @@ extern int atarilance_probe(struct device *); extern int a2065_probe(struct device *); extern int ariadne_probe(struct device *); +extern int hydra_probe(struct device *); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); @@ -202,6 +203,9 @@ #endif #ifdef CONFIG_ARIADNE /* Village Tronic Ariadne Ethernet Board */ && ariadne_probe(dev) +#endif +#ifdef CONFIG_HYDRA /* Hydra Systems Amiganet Ethernet board */ + && hydra_probe(dev) #endif #ifdef CONFIG_SUNLANCE && sparc_lance_probe(dev) diff -u --recursive --new-file v1.3.98/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v1.3.98/linux/drivers/net/arcnet.c Sun Apr 21 19:22:09 1996 +++ linux/drivers/net/arcnet.c Mon May 6 12:26:07 1996 @@ -2678,7 +2678,7 @@ } /* - * Try and get ARP to resolve the header. + * Try to get ARP to resolve the header. */ #ifdef CONFIG_INET BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n", @@ -3132,7 +3132,7 @@ } /* - * Try and get ARP to resolve the header. + * Try to get ARP to resolve the header. */ #ifdef CONFIG_INET return arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0; diff -u --recursive --new-file v1.3.98/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v1.3.98/linux/drivers/net/dgrs.c Sun Apr 21 19:22:09 1996 +++ linux/drivers/net/dgrs.c Mon May 6 12:26:07 1996 @@ -193,7 +193,7 @@ ulong x; /* - * If Space.c says not to use DMA, or if its not a PLX based + * If Space.c says not to use DMA, or if it's not a PLX based * PCI board, or if the expansion ROM space is not PCI * configured, then return false. */ @@ -250,10 +250,10 @@ * Initiate DMA using PLX part on PCI board. Spin the * processor until completed. All addresses are physical! * - * If pciaddr is NULL, then its a chaining DMA, and lcladdr is + * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is * the address of the first DMA descriptor in the chain. * - * If pciaddr is not NULL, then its a single DMA. + * If pciaddr is not NULL, then it's a single DMA. * * In either case, "lcladdr" must have been fixed up to make * sure the MSB isn't set using the S2DMA macro before passing @@ -373,13 +373,13 @@ /* * There are three modes here for doing the packet copy. * If we have DMA, and the packet is "long", we use the - * chaining mode of DMA. If its shorter, we use single + * chaining mode of DMA. If it's shorter, we use single * DMA's. Otherwise, we use memcpy(). */ if (priv->use_dma && priv->dmadesc_h && len > 64) { /* - * If we can use DMA and its a long frame, copy it using + * If we can use DMA and it's a long frame, copy it using * DMA chaining. */ DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */ @@ -451,7 +451,7 @@ else if (priv->use_dma) { /* - * If we can use DMA and its a shorter frame, copy it + * If we can use DMA and it's a shorter frame, copy it * using single DMA transfers. */ uchar *phys_p; diff -u --recursive --new-file v1.3.98/linux/drivers/net/dgrs_driver.c linux/drivers/net/dgrs_driver.c --- v1.3.98/linux/drivers/net/dgrs_driver.c Sun Apr 21 19:22:09 1996 +++ linux/drivers/net/dgrs_driver.c Mon May 6 12:26:08 1996 @@ -193,7 +193,7 @@ ulong x; /* - * If Space.c says not to use DMA, or if its not a PLX based + * If Space.c says not to use DMA, or if it's not a PLX based * PCI board, or if the expansion ROM space is not PCI * configured, then return false. */ @@ -250,10 +250,10 @@ * Initiate DMA using PLX part on PCI board. Spin the * processor until completed. All addresses are physical! * - * If pciaddr is NULL, then its a chaining DMA, and lcladdr is + * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is * the address of the first DMA descriptor in the chain. * - * If pciaddr is not NULL, then its a single DMA. + * If pciaddr is not NULL, then it's a single DMA. * * In either case, "lcladdr" must have been fixed up to make * sure the MSB isn't set using the S2DMA macro before passing @@ -373,13 +373,13 @@ /* * There are three modes here for doing the packet copy. * If we have DMA, and the packet is "long", we use the - * chaining mode of DMA. If its shorter, we use single + * chaining mode of DMA. If it's shorter, we use single * DMA's. Otherwise, we use memcpy(). */ if (priv->use_dma && priv->dmadesc_h && len > 64) { /* - * If we can use DMA and its a long frame, copy it using + * If we can use DMA and it's a long frame, copy it using * DMA chaining. */ DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */ @@ -451,7 +451,7 @@ else if (priv->use_dma) { /* - * If we can use DMA and its a shorter frame, copy it + * If we can use DMA and it's a shorter frame, copy it * using single DMA transfers. */ uchar *phys_p; diff -u --recursive --new-file v1.3.98/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v1.3.98/linux/drivers/net/dlci.c Wed Apr 17 09:06:31 1996 +++ linux/drivers/net/dlci.c Tue May 7 12:06:50 1996 @@ -286,10 +286,6 @@ int err, i; char buf[10]; - err = verify_area(VERIFY_READ, new, sizeof(*new)); - if (err) - return(err); - err = verify_area(VERIFY_WRITE, new, sizeof(*new)); if (err) return(err); diff -u --recursive --new-file v1.3.98/linux/drivers/net/dummy.c linux/drivers/net/dummy.c --- v1.3.98/linux/drivers/net/dummy.c Thu Nov 9 08:24:06 1995 +++ linux/drivers/net/dummy.c Mon May 6 12:26:08 1996 @@ -24,7 +24,7 @@ misguided packets. Nick Holloway, 27th May 1994 - [I tweaked this explanation a little but thats all] + [I tweaked this explanation a little but that's all] Alan Cox, 30th May 1994 */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v1.3.98/linux/drivers/net/eexpress.c Wed Apr 17 09:06:31 1996 +++ linux/drivers/net/eexpress.c Mon May 6 12:26:08 1996 @@ -903,7 +903,7 @@ /* * This should never happen. It is called when some higher - * routine detects the CU has stopped, to try and restart + * routine detects the CU has stopped, to try to restart * it from the last packet we knew we were working on, * or the idle loop if we had finished for the time. */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v1.3.98/linux/drivers/net/eql.c Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/eql.c Mon May 6 12:26:08 1996 @@ -66,7 +66,7 @@ * printk's trimmed out. * * Revision 3.6 1995/01/19 21:49:56 guru - * This is working pretty well. I gained 1 K/s in speed.. now its just + * This is working pretty well. I gained 1 K/s in speed.. now it's just * robustness and printk's to be diked out. * * Revision 3.5 1995/01/18 22:29:59 guru diff -u --recursive --new-file v1.3.98/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v1.3.98/linux/drivers/net/eth16i.c Fri Apr 12 15:51:55 1996 +++ linux/drivers/net/eth16i.c Mon May 6 12:26:08 1996 @@ -400,7 +400,7 @@ /* Now it seems that we have found a ethernet chip in this particular ioaddr. The MB86985 chip has this feature, that when you read a - certain register it will increase it's io base address to next + certain register it will increase its io base address to next configurable slot. Now when we have found the chip, first thing is to make sure that the chip's ioaddr will hold still here. */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/hp100.h linux/drivers/net/hp100.h --- v1.3.98/linux/drivers/net/hp100.h Fri Apr 12 15:51:56 1996 +++ linux/drivers/net/hp100.h Mon May 6 12:26:08 1996 @@ -128,7 +128,7 @@ #define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */ #define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */ #define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */ -#define HP100_TRI_INT 0x0200 /* 0:Dont, 1:Do tri-state the int */ +#define HP100_TRI_INT 0x0200 /* 0:Don't, 1:Do tri-state the int */ #define HP100_MEM_EN 0x0040 /* Config program set this to */ /* 0:Disable, 1:Enable mem map. */ /* See MMAP_DIS. */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v1.3.98/linux/drivers/net/hydra.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/hydra.c Mon May 6 12:44:31 1996 @@ -0,0 +1,655 @@ +/* Linux/68k Hydra Amiganet board driver v2.1 BETA */ +/* copyleft by Topi Kanerva (topi@susanna.oulu.fi) */ +/* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi) */ + +/* The code is mostly based on the linux/68k Ariadne driver */ +/* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) */ +/* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) */ + +/* This file is subject to the terms and conditions of the GNU General */ +/* Public License. See the file README.legal in the main directory of the */ +/* Linux/68k distribution for more details. */ + +/* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a */ +/* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM */ +/* and 10BASE-2 (thin coax) and AUI connectors. */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "hydra.h" + + +#define HYDRA_DEBUG +#undef HAVE_MULTICAST + +#define HYDRA_VERSION "v2.1 BETA" + +struct device *init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp); + +#undef HYDRA_DEBUG /* define this for (lots of) debugging information */ + +#if 0 /* currently hardwired to one transmit buffer */ + #define TX_RING_SIZE 5 + #define RX_RING_SIZE 16 +#else + #define TX_RING_SIZE 1 + #define RX_RING_SIZE 8 +#endif + +#define ETHER_MIN_LEN 64 +#define ETHER_MAX_LEN 1518 +#define ETHER_ADDR_LEN 6 + + +/* + * let's define here nice macros for writing and reading NIC registers + * + * the CIA accesses here are uses to make sure the minimum time + * requirement between NIC chip selects is met. + */ +#define WRITE_REG(reg, val) (ciaa.pra, ((u_char)(*(nicbase+(reg))=val))) +#define READ_REG(reg) (ciaa.pra, ((u_char)(*(nicbase+(reg))))) + +/* mask value for the interrupts we use */ +#define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT) + +/* only broadcasts, no promiscuous mode for now */ +#define NIC_RCRBITS (0) + +/* + * Private Device Data + */ +struct hydra_private + { + u_char *hydra_base; + u_char *hydra_nic_base; + u_short tx_page_start; + u_short rx_page_start; + u_short rx_page_stop; + u_short next_pkt; + struct enet_statistics stats; + }; + +static int hydra_open(struct device *dev); +static int hydra_start_xmit(struct sk_buff *skb, struct device *dev); +static void hydra_interrupt(int irq, struct pt_regs *fp, void *data); +static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, u_char *nicbase); +static int hydra_close(struct device *dev); +static struct enet_statistics *hydra_get_stats(struct device *dev); +#ifdef HAVE_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif + + +/* this is now coherent to the C version below, */ +/* compile the source with -D__USE_ASM__ if you */ +/* want it - it'll only be some 10% faster thou */ + +#if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM) + +static __inline__ void *memcpyw(u_short *dest, u_short *src, int len) + { + __asm__(" move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t" + " cmpi.l #2,%/d0 \n\t" + "1: bcs.s 2f \n\t" + " move.w %/a0@+,%/a1@+ \n\t" + " subq.l #2,%/d0 \n\t" + " bra.s 1b \n\t" + "2: cmpi.l #1,%/d0 \n\t" + " bne.s 3f \n\t" + " move.w %/a0@,%/d0 \n\t" + " swap.w %/d0 \n\t" + " move.b %/d0,%/a1@ \n\t" + "3: moveq #0,%/d0 \n\t" + : + : "g" (dest), "g" (src), "g" (len) + : "a1", "a0", "d0"); + return; +} + +#else + +/* hydra memory can only be read or written as words or longwords. */ +/* that will mean that we'll have to write a special memcpy for it. */ +/* this one here relies on the fact that _writes_ to hydra memory */ +/* are guaranteed to be of even length. (reads can be arbitrary) */ + +static void memcpyw(u_short *dest, u_short *src, int len) +{ + if(len & 1) + len++; + + while (len >= 2) { + *(dest++) = *(src++); + len -= 2; + } + +} + +#endif + +unsigned long hydra_probe(struct device *dev) + { + struct hydra_private *priv; + u_long board; + int key; + struct ConfigDev *cd; + int j; + +#ifdef HYDRA_DEBUG + printk("hydra_probe(%x)\n", dev); +#endif + + if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) { + cd = zorro_get_board(key); + if((board = (u_long) cd->cd_BoardAddr)) + { + for(j = 0; j < ETHER_ADDR_LEN; j++) + dev->dev_addr[j] = *((u_char *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j)); + + printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", + dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + init_etherdev(dev, 0, NULL); + + dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL); + priv = (struct hydra_private *)dev->priv; + memset(priv, 0, sizeof(struct hydra_private)); + + priv->hydra_base = (u_char *) ZTWO_VADDR(board); + priv->hydra_nic_base = (u_char *) ZTWO_VADDR(board) + HYDRA_NIC_BASE; + + dev->open = &hydra_open; + dev->stop = &hydra_close; + dev->hard_start_xmit = &hydra_start_xmit; + dev->get_stats = &hydra_get_stats; +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &hydra_set_multicast_list; +#endif + zorro_config_board(key, 0); + return(0); + } + } + return(ENODEV); + } + + +static int hydra_open(struct device *dev) + { + struct hydra_private *priv = (struct hydra_private *)dev->priv; + static int interruptinstalled = 0; + u_char volatile *nicbase = priv->hydra_nic_base; +#ifdef HAVE_MULTICAST + int i; +#endif + +#ifdef HYDRA_DEBUG + printk("hydra_open(0x%x)\n", dev); +#endif + + /* first, initialize the private structure */ + priv->tx_page_start = 0; /* these are 256 byte buffers for NS8390 */ + priv->rx_page_start = 6; + priv->rx_page_stop = 62; /* these values are hard coded for now */ + + /* Reset the NS8390 NIC */ + WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP); + + /* be sure that the NIC is in stopped state */ + while(!(READ_REG(NIC_ISR) & ISR_RST)); + + /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */ + WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0); + + /* clear remote byte count registers */ + WRITE_REG(NIC_RBCR0, 0); + WRITE_REG(NIC_RBCR1, 0); + + /* accept packets addressed to this card and also broadcast packets */ + WRITE_REG(NIC_RCR, NIC_RCRBITS); + + /* enable loopback mode 1 */ + WRITE_REG(NIC_TCR, TCR_LB1); + + /* initialize receive buffer ring */ + WRITE_REG(NIC_PSTART, priv->rx_page_start); + WRITE_REG(NIC_PSTOP, priv->rx_page_stop); + WRITE_REG(NIC_BNDRY, priv->rx_page_start); + + /* clear interrupts */ + WRITE_REG(NIC_ISR, 0xff); + + /* enable interrupts */ + WRITE_REG(NIC_IMR, NIC_INTS); + + /* set the ethernet hardware address */ + WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */ + + WRITE_REG(NIC_PAR0, dev->dev_addr[0]); + WRITE_REG(NIC_PAR1, dev->dev_addr[1]); + WRITE_REG(NIC_PAR2, dev->dev_addr[2]); + WRITE_REG(NIC_PAR3, dev->dev_addr[3]); + WRITE_REG(NIC_PAR4, dev->dev_addr[4]); + WRITE_REG(NIC_PAR5, dev->dev_addr[5]); + +#ifdef HAVE_MULTICAST + /* clear multicast hash table */ + for(i = 0; i < 8; i++) + WRITE_REG(NIC_MAR0 + 2*i, 0); +#endif + + priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */ + WRITE_REG(NIC_CURR, priv->next_pkt); /* set the next buf for current */ + + /* goto page 0, start NIC */ + WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START); + + /* take interface out of loopback */ + WRITE_REG(NIC_TCR, 0); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + if(!interruptinstalled) { + if(!add_isr(IRQ_AMIGA_PORTS, hydra_interrupt, 0, dev, + "Hydra Ethernet")) + return(-EAGAIN); + interruptinstalled = 1; + } + + return(0); + } + + +static int hydra_close(struct device *dev) +{ + struct hydra_private *priv = (struct hydra_private *)dev->priv; + u_char volatile *nicbase = priv->hydra_nic_base; + int n = 5000; + + dev->start = 0; + dev->tbusy = 1; + +#ifdef HYDRA_DEBUG + printk("%s: Shutting down ethercard\n", dev->name); + printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors); +#endif + + WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP); + + /* wait for NIC to stop (what a nice timeout..) */ + while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n); + + return(0); +} + + +static void hydra_interrupt(int irq, struct pt_regs *fp, void *data) + { + u_char volatile *nicbase; + + struct device *dev = (struct device *) data; + struct hydra_private *priv; + u_short intbits; + + if(dev == NULL) + { + printk("hydra_interrupt(): irq for unknown device\n"); + return; + } + +/* this is not likely a problem - i think */ + if(dev->interrupt) + printk("%s: re-entering the interrupt handler\n", dev->name); + + dev->interrupt = 1; + + priv = (struct hydra_private *) dev->priv; + nicbase = (u_char *) priv->hydra_nic_base; + + /* select page 0 */ + WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA); + + intbits = READ_REG(NIC_ISR) & NIC_INTS; + if(intbits == 0) + { + dev->interrupt = 0; + return; + } + + /* acknowledge all interrupts, by clearing the interrupt flag */ + WRITE_REG(NIC_ISR, intbits); + + if((intbits & ISR_PTX) && !(intbits & ISR_TXE)) + { + dev->tbusy = 0; + mark_bh(NET_BH); + } + + if((intbits & ISR_PRX) && !(intbits & ISR_RXE))/* packet received OK */ + hydra_rx(dev, priv, nicbase); + + if(intbits & ISR_TXE) + priv->stats.tx_errors++; + + if(intbits & ISR_RXE) + priv->stats.rx_errors++; + + if(intbits & ISR_CNT) { + /* + * read the tally counters and (currently) ignore the values + * might be useful because of bugs of some versions of the 8390 NIC + */ +#ifdef HYDRA_DEBUG + printk("hydra_interrupt(): ISR_CNT\n"); +#endif + (void)READ_REG(NIC_CNTR0); + (void)READ_REG(NIC_CNTR1); + (void)READ_REG(NIC_CNTR2); + } + + if(intbits & ISR_OVW) + { + #ifdef HYDRA_DEBUG + WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA); +/* another one just too much for me to comprehend - basically this could */ +/* only occur because of invalid access to hydra ram, thus invalidating */ +/* the interrupt bits read - in average usage these do not occur at all */ + printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n", + intbits, READ_REG(NIC_CURR)); + WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA); + #endif + + + /* overwrite warning occured, stop NIC & check the BOUNDARY pointer */ + /* FIXME - real overwrite handling needed !! */ + + printk("hydra_interrupt(): overwrite warning, resetting NIC\n"); + WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP); + while(!(READ_REG(NIC_ISR) & ISR_RST)); + /* wait for NIC to reset */ + WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0); + WRITE_REG(NIC_RBCR0, 0); + WRITE_REG(NIC_RBCR1, 0); + WRITE_REG(NIC_RCR, NIC_RCRBITS); + WRITE_REG(NIC_TCR, TCR_LB1); + WRITE_REG(NIC_PSTART, priv->rx_page_start); + WRITE_REG(NIC_PSTOP, priv->rx_page_stop); + WRITE_REG(NIC_BNDRY, priv->rx_page_start); + WRITE_REG(NIC_ISR, 0xff); + WRITE_REG(NIC_IMR, NIC_INTS); +/* currently this _won't_ reset my hydra, even though it is */ +/* basically the same code as in the board init - any ideas? */ + + priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */ + WRITE_REG(NIC_CURR, priv->next_pkt); /* set the next buf for current */ + + WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START); + + WRITE_REG(NIC_TCR, 0); + } + + dev->interrupt = 0; + return; + } + + +/* + * packet transmit routine + */ +static int hydra_start_xmit(struct sk_buff *skb, struct device *dev) + { + struct hydra_private *priv = (struct hydra_private *)dev->priv; + u_char volatile *nicbase = priv->hydra_nic_base; + int len, len1; + + /* Transmitter timeout, serious problems. */ + + if(dev->tbusy) + { + int tickssofar = jiffies - dev->trans_start; + if(tickssofar < 20) + return(1); + WRITE_REG(NIC_CR, CR_STOP); + printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0); + priv->stats.tx_errors++; + + + dev->tbusy = 0; + dev->trans_start = jiffies; + + return(0); + } + + + if(skb == NULL) + { + dev_tint(dev); + return(0); + } + + if((len = skb->len) <= 0) + return(0); + + /* fill in a tx ring entry */ + +#ifdef HYDRA_DEBUG + printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); + { + int i; + u_char *ptr = &((u_char *)skb->data)[6]; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" to "); + { + int i; + u_char *ptr = (u_char *)skb->data; + for (i = 0; i < 6; i++) + printk("%02x", ptr[i]); + } + printk(" data 0x%08x len %d\n", (int)skb->data, len); +#endif + + /* + * make sure that the packet size is at least the minimum + * allowed ethernet packet length. + * (possibly should also clear the unused space...) + * note: minimum packet length is 64, including CRC + */ + len1 = len; + if(len < (ETHER_MIN_LEN-4)) + len = (ETHER_MIN_LEN-1); + + /* make sure we've got an even number of bytes to copy to hydra's mem */ + if(len & 1) len++; + + if((u_long)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000) + printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = %0x\n", (priv->hydra_base+(priv->tx_page_start<<8))); + + /* copy the packet data to the transmit buffer + in the ethernet card RAM */ + memcpyw((u_short *)(priv->hydra_base + (priv->tx_page_start << 8)), + (u_short *)skb->data, len); + /* clear the unused space */ +/* for(; len1hydra_base + (priv->tx_page_start<<8) + len1) = 0; +*/ + dev_kfree_skb(skb, FREE_WRITE); + + priv->stats.tx_packets++; + + cli(); + /* make sure we are on the correct page */ + WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START); + + /* here we configure the transmit page start register etc */ + /* notice that this code is hardwired to one transmit buffer */ + WRITE_REG(NIC_TPSR, priv->tx_page_start); + WRITE_REG(NIC_TBCR0, len & 0xff); + WRITE_REG(NIC_TBCR1, len >> 8); + + /* commit the packet to the wire */ + WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP); + sti(); + + dev->trans_start = jiffies; + + return(0); + } + + +static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, u_char *nicbase) + { + u_short volatile *board_ram_ptr; + struct sk_buff *skb; + int hdr_next_pkt, pkt_len, len1, boundary; + + + /* remove packet(s) from the ring and commit them to TCP layer */ + WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */ + while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */ + { + board_ram_ptr = (u_short *)(priv->hydra_base + (priv->next_pkt << 8)); + +#ifdef HYDRA_DEBUG + printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr); +#endif + + /* the following must be done with two steps, or + GCC optimizes it to a byte access to Hydra memory, + which doesn't work... */ + hdr_next_pkt = board_ram_ptr[0]; + hdr_next_pkt >>= 8; + + pkt_len = board_ram_ptr[1]; + pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8)); + +#ifdef HYDRA_DEBUG + printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len); +#endif + + if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN) + { + /* note that board_ram_ptr is u_short */ + /* CRC is not included in the packet length */ + + pkt_len -= 4; + skb = dev_alloc_skb(pkt_len+2); + if(skb == NULL) + { + printk("%s: memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped++; + } + else + { + skb->dev = dev; + skb_reserve(skb, 2); + + if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start) + { + /* here, the packet is wrapped */ + len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4; + + memcpyw((u_short *)skb_put(skb, len1), (u_short *)(board_ram_ptr+2), len1); + memcpyw((u_short *)skb_put(skb, pkt_len-len1), (u_short *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1); + +#ifdef HYDRA_DEBUG + printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1); +#endif + } /* ... here, packet is not wrapped */ + else memcpyw((u_short *) skb_put(skb, pkt_len), (u_short *)(board_ram_ptr+2), pkt_len); + } + /* if(skb == NULL) ... */ + } + else + { + WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA); + printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR)); +/* +this is the error i kept getting until i switched to 0.9.10. it still doesn't +mean that the bug would have gone away - so be alarmed. the packet is likely +being fetched from a wrong memory location - but why - dunno + +note-for-v2.1: not really problem anymore. hasn't been for a long time. +*/ + + WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA); + /* should probably reset the NIC here ?? */ + + hydra_open(dev); /* FIXME - i shouldn't really be doing this. */ + return; + } + + /* now, update the next_pkt pointer */ + if(hdr_next_pkt < priv->rx_page_stop) priv->next_pkt = hdr_next_pkt; + else printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt); + + /* update the boundary pointer */ + boundary = priv->next_pkt - 1; + if(boundary < priv->rx_page_start) + boundary = priv->rx_page_stop - 1; + + /* set NIC to page 0 to update the NIC_BNDRY register */ + WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA); + WRITE_REG(NIC_BNDRY, boundary); + + /* select page1 to access the NIC_CURR register */ + WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA); + + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + priv->stats.rx_packets++; + + } + return; + } + + +static struct enet_statistics *hydra_get_stats(struct device *dev) +{ + struct hydra_private *priv = (struct hydra_private *)dev->priv; +#if 0 + u_char *board = priv->hydra_base; + + short saved_addr; +#endif +/* currently does nothing :) i'll finish this later */ + + return(&priv->stats); +} + +#ifdef HAVE_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) + { + struct hydra_private *priv = (struct hydra_private *)dev->priv; + u_char *board = priv->hydra_base; + + /* yes, this code is also waiting for someone to complete.. :) */ + /* (personally i don't care about multicasts at all :) */ + return; + } +#endif + diff -u --recursive --new-file v1.3.98/linux/drivers/net/hydra.h linux/drivers/net/hydra.h --- v1.3.98/linux/drivers/net/hydra.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/hydra.h Mon May 6 12:44:31 1996 @@ -0,0 +1,177 @@ +/* $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $ */ + +/* + * Copyright (c) 1994 Timo Rossi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Timo Rossi + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The Hydra Systems card uses the National Semiconductor + * 8390 NIC (Network Interface Controller) chip, located + * at card base address + 0xffe1. NIC registers are accessible + * only at odd byte addresses, so the register offsets must + * be multiplied by two. + * + * Card address PROM is located at card base + 0xffc0 (even byte addresses) + * + * RAM starts at the card base address, and is 16K or 64K. + * The current Amiga NetBSD hydra driver is hardwired for 16K. + * It seems that the RAM should be accessed as words or longwords only. + * + */ + +/* adapted for Linux by Topi Kanerva 03/29/95 + with original author's permission */ + +#define HYDRA_NIC_BASE 0xffe1 + +/* Page0 registers */ + +#define NIC_CR 0 /* Command register */ +#define NIC_PSTART (1*2) /* Page start (write) */ +#define NIC_PSTOP (2*2) /* Page stop (write) */ +#define NIC_BNDRY (3*2) /* Boundary pointer */ +#define NIC_TSR (4*2) /* Transmit status (read) */ +#define NIC_TPSR (4*2) /* Transmit page start (write) */ +#define NIC_NCR (5*2) /* Number of collisions, read */ +#define NIC_TBCR0 (5*2) /* Transmit byte count low (write) */ +#define NIC_FIFO (6*2) /* FIFO reg. (read) */ +#define NIC_TBCR1 (6*2) /* Transmit byte count high (write) */ +#define NIC_ISR (7*2) /* Interrupt status register */ +#define NIC_RBCR0 (0xa*2) /* Remote byte count low (write) */ +#define NIC_RBCR1 (0xb*2) /* Remote byte count high (write) */ +#define NIC_RSR (0xc*2) /* Receive status (read) */ +#define NIC_RCR (0xc*2) /* Receive config (write) */ +#define NIC_CNTR0 (0xd*2) /* Frame alignment error count (read) */ +#define NIC_TCR (0xd*2) /* Transmit config (write) */ +#define NIC_CNTR1 (0xe*2) /* CRC error counter (read) */ +#define NIC_DCR (0xe*2) /* Data config (write) */ +#define NIC_CNTR2 (0xf*2) /* missed packet counter (read) */ +#define NIC_IMR (0xf*2) /* Interrupt mask reg. (write) */ + +/* Page1 registers */ + +#define NIC_PAR0 (1*2) /* Physical address */ +#define NIC_PAR1 (2*2) +#define NIC_PAR2 (3*2) +#define NIC_PAR3 (4*2) +#define NIC_PAR4 (5*2) +#define NIC_PAR5 (6*2) +#define NIC_CURR (7*2) /* Current RX ring-buffer page */ +#define NIC_MAR0 (8*2) /* Multicast address */ +#define NIC_MAR1 (9*2) +#define NIC_MAR2 (0xa*2) +#define NIC_MAR3 (0xb*2) +#define NIC_MAR4 (0xc*2) +#define NIC_MAR5 (0xd*2) +#define NIC_MAR6 (0xe*2) +#define NIC_MAR7 (0xf*2) + +/* Command register definitions */ + +#define CR_STOP 0x01 /* Stop -- software reset command */ +#define CR_START 0x02 /* Start */ +#define CR_TXP 0x04 /* Transmit packet */ + +#define CR_RD0 0x08 /* Remote DMA cmd */ +#define CR_RD1 0x10 +#define CR_RD2 0x20 + +#define CR_NODMA CR_RD2 + +#define CR_PS0 0x40 /* Page select */ +#define CR_PS1 0x80 + +#define CR_PAGE0 0 +#define CR_PAGE1 CR_PS0 +#define CR_PAGE2 CR_PS1 + +/* Interrupt status reg. definitions */ + +#define ISR_PRX 0x01 /* Packet received without errors */ +#define ISR_PTX 0x02 /* Packet transmitted without errors */ +#define ISR_RXE 0x04 /* Receive error */ +#define ISR_TXE 0x08 /* Transmit error */ +#define ISR_OVW 0x10 /* Ring buffer overrrun */ +#define ISR_CNT 0x20 /* Counter overflow */ +#define ISR_RDC 0x40 /* Remote DMA compile */ +#define ISR_RST 0x80 /* Reset status */ + +/* Data config reg. definitions */ + +#define DCR_WTS 0x01 /* Word transfer select */ +#define DCR_BOS 0x02 /* Byte order select */ +#define DCR_LAS 0x04 /* Long address select */ +#define DCR_LS 0x08 /* Loopback select */ +#define DCR_AR 0x10 /* Auto-init remote */ +#define DCR_FT0 0x20 /* FIFO threshold select */ +#define DCR_FT1 0x40 + +/* Transmit config reg. definitions */ + +#define TCR_CRC 0x01 /* Inhibit CRC */ +#define TCR_LB0 0x02 /* Loopback control */ +#define TCR_LB1 0x04 +#define TCR_ATD 0x08 /* Auto transmit disable */ +#define TCR_OFST 0x10 /* Collision offset enable */ + +/* Transmit status reg. definitions */ + +#define TSR_PTX 0x01 /* Packet transmitted */ +#define TSR_COL 0x04 /* Transmit collided */ +#define TSR_ABT 0x08 /* Transmit aborted */ +#define TSR_CRS 0x10 /* Carrier sense lost */ +#define TSR_FU 0x20 /* FIFO underrun */ +#define TSR_CDH 0x40 /* CD Heartbeat */ +#define TSR_OWC 0x80 /* Out of Window Collision */ + +/* Receiver config register definitions */ + +#define RCR_SEP 0x01 /* Save errored packets */ +#define RCR_AR 0x02 /* Accept runt packets */ +#define RCR_AB 0x04 /* Accept broadcast */ +#define RCR_AM 0x08 /* Accept multicast */ +#define RCR_PRO 0x10 /* Promiscuous mode */ +#define RCR_MON 0x20 /* Monitor mode */ + +/* Receiver status register definitions */ + +#define RSR_PRX 0x01 /* Packet received without error */ +#define RSR_CRC 0x02 /* CRC error */ +#define RSR_FAE 0x04 /* Frame alignment error */ +#define RSR_FO 0x08 /* FIFO overrun */ +#define RSR_MPA 0x10 /* Missed packet */ +#define RSR_PHY 0x20 /* Physical address */ +#define RSR_DIS 0x40 /* Received disabled */ +#define RSR_DFR 0x80 /* Deferring (jabber) */ + +/* Hydra System card address PROM offset */ + +#define HYDRA_ADDRPROM 0xffc0 + + diff -u --recursive --new-file v1.3.98/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v1.3.98/linux/drivers/net/ibmtr.c Fri Apr 12 15:51:56 1996 +++ linux/drivers/net/ibmtr.c Mon May 6 12:26:08 1996 @@ -333,7 +333,7 @@ ti->mmio= t_mmio; dev->priv = ti; /* this seems like the logical use of the - field ... lets try some empirical tests + field ... let's try some empirical tests using the token-info structure -- that should fit with out future hope of multiple adapter support as well /dwm */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/lance32.c linux/drivers/net/lance32.c --- v1.3.98/linux/drivers/net/lance32.c Tue Apr 2 13:32:21 1996 +++ linux/drivers/net/lance32.c Tue May 7 12:06:50 1996 @@ -13,7 +13,7 @@ * 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"; +static const char *version = "lance32.c:v0.10 28.4.96 tsbogend@bigbug.franken.de\n"; #include #include @@ -55,6 +55,11 @@ * only tested on Alpha Noname Board * v0.02: changed IRQ handling for new interrupt scheme (dev_id) * tested on a ASUS SP3G + * v0.10: fixed a odd problem with the 79C794 in a Compaq Deskpro XL + * looks like the 974 doesn't like stopping and restarting in a + * short period of time; now we do a reinit of the lance; the + * bug was triggered by doing ifconfig eth0 broadcast + * and hangs the machine (thanks to Klaus Liedl for debugging) */ @@ -320,7 +325,11 @@ (u32) virt_to_bus(lp->rx_ring), (u32) virt_to_bus(&lp->init_block)); + lp->init_block.mode = 0x0000; + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; 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); @@ -404,12 +413,9 @@ 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); } @@ -417,11 +423,21 @@ static void lance32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit) { + int i; + int ioaddr = dev->base_addr; + lance32_purge_tx_ring(dev); lance32_init_ring(dev); - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(csr0_bits, dev->base_addr + LANCE_DATA); + outw(0x0000, ioaddr + LANCE_ADDR); + /* ReInit Ring */ + outw(0x0001, ioaddr + LANCE_DATA); + i = 0; + while (i++ < 100) + if (inw(ioaddr+LANCE_DATA) & 0x0100) + break; + + outw(csr0_bits, ioaddr + LANCE_DATA); } static int @@ -459,7 +475,7 @@ printk("\n"); } #endif - lance32_restart(dev, 0x0043, 1); + lance32_restart(dev, 0x0042, 1); dev->tbusy=0; dev->trans_start = jiffies; @@ -794,32 +810,25 @@ 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. */ + struct lance32_private *lp = (struct lance32_private *)dev->priv; 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 */ + lp->init_block.mode = 0x8000; } 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 */ + memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter)); + lp->init_block.mode = 0x0000; } + + outw(0, ioaddr+LANCE_ADDR); + outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */ - lance32_restart(dev, 0x0142, 0); /* Resume normal operation */ + lance32_restart(dev, 0x0042, 0); /* Resume normal operation */ } diff -u --recursive --new-file v1.3.98/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v1.3.98/linux/drivers/net/loopback.c Mon Mar 25 08:58:21 1996 +++ linux/drivers/net/loopback.c Mon May 6 12:26:08 1996 @@ -15,8 +15,8 @@ * Alan Cox : Rejig for NET3.029 snap #3 * Alan Cox : Fixed NET3.029 bugs and sped up * Larry McVoy : Tiny tweak to double performance - * Alan Cox : Backed out LMV's tweak - the linux mm cant - * take it... + * Alan Cox : Backed out LMV's tweak - the linux mm + * can't take it... * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --recursive --new-file v1.3.98/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v1.3.98/linux/drivers/net/ne.c Fri Mar 1 07:50:44 1996 +++ linux/drivers/net/ne.c Mon May 6 11:41:58 1996 @@ -23,6 +23,7 @@ Paul Gortmaker : new reset code, reset card after probe at boot. Paul Gortmaker : multiple card support for module users. Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c + Paul Gortmaker : Allow users with bad cards to avoid full probe. */ @@ -78,6 +79,7 @@ {"NN1000", "NN2000", {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */ {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}}, /* Outlaw 4-Dimension cards. */ {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */ + {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */ {0,} }; #endif @@ -206,7 +208,7 @@ int wordlength = 2; const char *name = NULL; int start_page, stop_page; - int neX000, ctron; + int neX000, ctron, bad_card; int reg0 = inb_p(ioaddr); static unsigned version_printed = 0; @@ -232,6 +234,14 @@ printk("NE*000 ethercard probe at %#3x:", ioaddr); + /* A user with a poor card that fails to ack the reset, or that + does not have a valid 0x57,0x57 signature can still use this + without having to recompile. Specifying an i/o address along + with an otherwise unused dev->mem_end value of "0xBAD" will + cause the driver to skip these parts of the probe. */ + + bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); + /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -240,8 +250,13 @@ while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { - printk(" not found (no reset ack).\n"); - return ENODEV; + if (bad_card) { + printk(" (warning: no reset ack)"); + break; + } else { + printk(" not found (no reset ack).\n"); + return ENODEV; + } } outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ @@ -297,7 +312,7 @@ ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); /* Set up the rest of the parameters. */ - if (neX000) { + if (neX000 || bad_card) { name = (wordlength == 2) ? "NE2000" : "NE1000"; } else if (ctron) { name = (wordlength == 2) ? "Ctron-8" : "Ctron-16"; diff -u --recursive --new-file v1.3.98/linux/drivers/net/new_tunnel.c linux/drivers/net/new_tunnel.c --- v1.3.98/linux/drivers/net/new_tunnel.c Sun May 5 08:52:00 1996 +++ linux/drivers/net/new_tunnel.c Tue May 7 15:21:39 1996 @@ -62,6 +62,7 @@ */ #include +#include /* for CONFIG_IP_FORWARD */ /* Only two headers!! :-) */ #include @@ -172,7 +173,8 @@ printk ( KERN_INFO "%s: Packet with no route!\n", dev->name); dev->tbusy=0; stats->tx_errors++; - return(1); + dev_kfree_skb(skb, FREE_WRITE); + return 0; } /* @@ -191,7 +193,8 @@ ip_rt_put(rt); dev->tbusy=0; stats->tx_errors++; - return(1); + dev_kfree_skb(skb, FREE_WRITE); + return 0; } ip_rt_put(rt); @@ -203,7 +206,8 @@ printk ( KERN_INFO "%s: Can't reach target gateway!\n", dev->name); dev->tbusy=0; stats->tx_errors++; - return(1); + dev_kfree_skb(skb, FREE_WRITE); + return 0; } tdev = rt->rt_dev; @@ -214,7 +218,8 @@ ip_rt_put(rt); dev->tbusy=0; stats->tx_errors++; - return(1); + dev_kfree_skb(skb, FREE_WRITE); + return 0; } #ifdef TUNNEL_DEBUG @@ -243,7 +248,8 @@ ip_rt_put(rt); dev->tbusy = 0; stats->tx_dropped++; - return(1); + dev_kfree_skb(skb, FREE_WRITE); + return 0; } new_skb->free = 1; @@ -259,8 +265,7 @@ */ new_skb->ip_hdr = (struct iphdr *) skb_put(new_skb, skb->len); memcpy(new_skb->ip_hdr, skb->data, skb->len); - /* Is this necessary? */ - memcpy(new_skb->proto_priv, skb->proto_priv, sizeof(skb->proto_priv)); + memset(new_skb->proto_priv, 0, sizeof(skb->proto_priv)); /* Tack on our header */ new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen); @@ -299,7 +304,9 @@ * If ip_forward() made a copy, it will return 1 so we can free. */ - if (ip_forward(skb, dev, 0, target) == 1) +#ifdef CONFIG_IP_FORWARD + if (ip_forward(skb, dev, 0, target)) +#endif kfree_skb(skb, FREE_WRITE); /* diff -u --recursive --new-file v1.3.98/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.3.98/linux/drivers/net/ppp.c Wed Apr 24 17:00:40 1996 +++ linux/drivers/net/ppp.c Mon May 6 07:28:51 1996 @@ -91,7 +91,7 @@ #include #include #include -#include "slhc.h" +#include #define fcstab ppp_crc16_table /* Name of the table in the kernel */ #include diff -u --recursive --new-file v1.3.98/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v1.3.98/linux/drivers/net/sdla.c Wed Apr 17 09:06:32 1996 +++ linux/drivers/net/sdla.c Mon May 6 12:26:08 1996 @@ -955,7 +955,7 @@ } memset(&intr, 0, sizeof(intr)); - /* lets start up the reception */ + /* let's start up the reception */ switch(flp->type) { case SDLA_S502A: @@ -1028,7 +1028,7 @@ sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); - /* lets start up the reception */ + /* let's start up the reception */ memset(&intr, 0, sizeof(intr)); switch(flp->type) { diff -u --recursive --new-file v1.3.98/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v1.3.98/linux/drivers/net/seeq8005.c Fri Apr 12 15:51:56 1996 +++ linux/drivers/net/seeq8005.c Mon May 6 12:26:08 1996 @@ -611,7 +611,7 @@ set_multicast_list(struct device *dev) { /* - * I _could_ do upto 6 addresses here, but wont (yet?) + * I _could_ do up to 6 addresses here, but won't (yet?) */ #if 0 diff -u --recursive --new-file v1.3.98/linux/drivers/net/seeq8005.h linux/drivers/net/seeq8005.h --- v1.3.98/linux/drivers/net/seeq8005.h Fri Apr 12 15:51:57 1996 +++ linux/drivers/net/seeq8005.h Mon May 6 12:26:09 1996 @@ -119,7 +119,7 @@ #define SEEQCFG2_NO_PREAM (0x0080) /* 1= user supplies Xmit preamble bytes */ #define SEEQCFG2_ADDR_LEN (0x0100) /* 1= 2byte addresses */ #define SEEQCFG2_REC_CRC (0x0200) /* 0= received packets will have CRC stripped from them */ -#define SEEQCFG2_XMIT_NO_CRC (0x0400) /* dont xmit CRC with each packet (user supplies it) */ +#define SEEQCFG2_XMIT_NO_CRC (0x0400) /* don't xmit CRC with each packet (user supplies it) */ #define SEEQCFG2_LOOPBACK (0x0800) #define SEEQCFG2_CTRLO (0x1000) #define SEEQCFG2_RESET (0x8000) /* software Hard-reset bit */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v1.3.98/linux/drivers/net/sk_g16.c Wed Apr 17 09:06:32 1996 +++ linux/drivers/net/sk_g16.c Mon May 6 12:26:09 1996 @@ -112,7 +112,7 @@ /* * In POS3 are bits A14-A19 of the address bus. These bits can be set - * to choose the RAM address. Thats why we only can choose the RAM address + * to choose the RAM address. That's why we only can choose the RAM address * in 16KB steps. */ @@ -1441,7 +1441,7 @@ /* * Here I have a problem. * I only know that there must be one or up to 15 collisions. - * Thats why TX_MORE is set, because after 16 attempts TX_RTRY + * That's why TX_MORE is set, because after 16 attempts TX_RTRY * will be set which means couldn't send packet aborted transfer. * * First I did not have this in but then I thought at minimum diff -u --recursive --new-file v1.3.98/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.3.98/linux/drivers/net/slhc.c Tue Apr 2 13:32:21 1996 +++ linux/drivers/net/slhc.c Mon May 6 07:28:51 1996 @@ -78,7 +78,7 @@ #include #include #include -#include "slhc.h" +#include #ifdef __alpha__ # include diff -u --recursive --new-file v1.3.98/linux/drivers/net/slhc.h linux/drivers/net/slhc.h --- v1.3.98/linux/drivers/net/slhc.h Wed Aug 10 19:26:18 1994 +++ linux/drivers/net/slhc.h Thu Jan 1 02:00:00 1970 @@ -1,187 +0,0 @@ -#ifndef _SLHC_H -#define _SLHC_H -/* - * Definitions for tcp compression routines. - * - * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ - * - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: - * - Initial distribution. - * - * - * modified for KA9Q Internet Software Package by - * Katie Stevens (dkstevens@ucdavis.edu) - * University of California, Davis - * Computing Services - * - 01-31-90 initial adaptation - * - * - Feb 1991 Bill_Simpson@um.cc.umich.edu - * variable number of conversation slots - * allow zero or one slots - * separate routines - * status display - */ - -/* - * Compressed packet format: - * - * The first octet contains the packet type (top 3 bits), TCP - * 'push' bit, and flags that indicate which of the 4 TCP sequence - * numbers have changed (bottom 5 bits). The next octet is a - * conversation number that associates a saved IP/TCP header with - * the compressed packet. The next two octets are the TCP checksum - * from the original datagram. The next 0 to 15 octets are - * sequence number changes, one change per bit set in the header - * (there may be no changes and there are two special cases where - * the receiver implicitly knows what changed -- see below). - * - * There are 5 numbers which can change (they are always inserted - * in the following order): TCP urgent pointer, window, - * acknowledgment, sequence number and IP ID. (The urgent pointer - * is different from the others in that its value is sent, not the - * change in value.) Since typical use of SLIP links is biased - * toward small packets (see comments on MTU/MSS below), changes - * use a variable length coding with one octet for numbers in the - * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the - * range 256 - 65535 or 0. (If the change in sequence number or - * ack is more than 65535, an uncompressed packet is sent.) - */ - -/* - * Packet types (must not conflict with IP protocol version) - * - * The top nibble of the first octet is the packet type. There are - * three possible types: IP (not proto TCP or tcp with one of the - * control flags set); uncompressed TCP (a normal IP/TCP packet but - * with the 8-bit protocol field replaced by an 8-bit connection id -- - * this type of packet syncs the sender & receiver); and compressed - * TCP (described above). - * - * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and - * is logically part of the 4-bit "changes" field that follows. Top - * three bits are actual packet type. For backward compatibility - * and in the interest of conserving bits, numbers are chosen so the - * IP protocol version number (4) which normally appears in this nibble - * means "IP packet". - */ - -/* SLIP compression masks for len/vers byte */ -#define SL_TYPE_IP 0x40 -#define SL_TYPE_UNCOMPRESSED_TCP 0x70 -#define SL_TYPE_COMPRESSED_TCP 0x80 -#define SL_TYPE_ERROR 0x00 - -/* Bits in first octet of compressed packet */ -#define NEW_C 0x40 /* flag bits for what changed in a packet */ -#define NEW_I 0x20 -#define NEW_S 0x08 -#define NEW_A 0x04 -#define NEW_W 0x02 -#define NEW_U 0x01 - -/* reserved, special-case values of above */ -#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ -#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ -#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) - -#define TCP_PUSH_BIT 0x10 - -/* - * data type and sizes conversion assumptions: - * - * VJ code KA9Q style generic - * u_char byte_t unsigned char 8 bits - * u_short int16 unsigned short 16 bits - * u_int int16 unsigned short 16 bits - * u_long unsigned long unsigned long 32 bits - * int int32 long 32 bits - */ - -typedef unsigned char byte_t; -typedef unsigned long int32; - -/* - * "state" data for each active tcp conversation on the wire. This is - * basically a copy of the entire IP/TCP header from the last packet - * we saw from the conversation together with a small identifier - * the transmit & receive ends of the line use to locate saved header. - */ -struct cstate { - byte_t cs_this; /* connection id number (xmit) */ - struct cstate *next; /* next in ring (xmit) */ - struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ - struct tcphdr cs_tcp; - unsigned char cs_ipopt[64]; - unsigned char cs_tcpopt[64]; - int cs_hsize; -}; -#define NULLSLSTATE (struct cstate *)0 - -/* - * all the state data for one serial line (we need one of these per line). - */ -struct slcompress { - struct cstate *tstate; /* transmit connection states (array)*/ - struct cstate *rstate; /* receive connection states (array)*/ - - byte_t tslot_limit; /* highest transmit slot id (0-l)*/ - byte_t rslot_limit; /* highest receive slot id (0-l)*/ - - byte_t xmit_oldest; /* oldest xmit in ring */ - byte_t xmit_current; /* most recent xmit id */ - byte_t recv_current; /* most recent rcvd id */ - - byte_t flags; -#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ - - int32 sls_o_nontcp; /* outbound non-TCP packets */ - int32 sls_o_tcp; /* outbound TCP packets */ - int32 sls_o_uncompressed; /* outbound uncompressed packets */ - int32 sls_o_compressed; /* outbound compressed packets */ - int32 sls_o_searches; /* searches for connection state */ - int32 sls_o_misses; /* times couldn't find conn. state */ - - int32 sls_i_uncompressed; /* inbound uncompressed packets */ - int32 sls_i_compressed; /* inbound compressed packets */ - int32 sls_i_error; /* inbound error packets */ - int32 sls_i_tossed; /* inbound packets tossed because of error */ - - int32 sls_i_runt; - int32 sls_i_badcheck; -}; -#define NULLSLCOMPR (struct slcompress *)0 - -#define __ARGS(x) x - -/* In slhc.c: */ -struct slcompress *slhc_init __ARGS((int rslots, int tslots)); -void slhc_free __ARGS((struct slcompress *comp)); - -int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize, unsigned char *ocp, unsigned char **cpp, - int compress_cid)); -int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, - int isize)); -int slhc_toss __ARGS((struct slcompress *comp)); - -void slhc_i_status __ARGS((struct slcompress *comp)); -void slhc_o_status __ARGS((struct slcompress *comp)); - -#endif /* _SLHC_H */ diff -u --recursive --new-file v1.3.98/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.3.98/linux/drivers/net/slip.c Fri Apr 12 15:51:57 1996 +++ linux/drivers/net/slip.c Mon May 6 07:28:51 1996 @@ -81,7 +81,7 @@ #ifdef CONFIG_INET #include #include -#include "slhc.h" +#include #endif #ifdef MODULE diff -u --recursive --new-file v1.3.98/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v1.3.98/linux/drivers/net/smc-ultra.c Fri Mar 1 07:50:46 1996 +++ linux/drivers/net/smc-ultra.c Tue May 7 10:40:09 1996 @@ -1,6 +1,8 @@ /* smc-ultra.c: A SMC Ultra ethernet driver for linux. */ /* - Written 1993,1994,1995 by Donald Becker. + This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards. + + Written 1993-1996 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. @@ -12,8 +14,6 @@ Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - This is a driver for the SMC Ultra and SMC EtherEZ ethercards. - This driver uses the cards in the 8390-compatible, shared memory mode. Most of the run-time complexity is handled by the generic code in 8390.c. The code in this file is responsible for @@ -32,17 +32,18 @@ transfers to avoid a bug in early version of the card that corrupted data transferred by a AHA1542. - This driver does not support the programmed-I/O data transfer mode of - the EtherEZ. That support (if available) is smc-ez.c. Nor does it - use the non-8390-compatible "Altego" mode. (No support currently planned.) + This driver now supports the programmed-I/O (PIO) data transfer mode of + the EtherEZ. It does not use the non-8390-compatible "Altego" mode. + That support (if available) is smc-ez.c. Changelog: Paul Gortmaker : multiple card support for module users. + Donald Becker : 4/17/96 PIO support, minor potential problems avoided. */ static const char *version = - "smc-ultra.c:v1.12 1/18/95 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + "smc-ultra.c:v1.99 4/17/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; #include @@ -73,6 +74,12 @@ struct sk_buff *skb, int ring_offset); static void ultra_block_output(struct device *dev, int count, const unsigned char *buf, const start_page); +static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void ultra_pio_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void ultra_pio_output(struct device *dev, int count, + const unsigned char *buf, const start_page); static int ultra_close_card(struct device *dev); @@ -81,8 +88,11 @@ #define ULTRA_CMDREG 0 /* Offset to ASIC command register. */ #define ULTRA_RESET 0x80 /* Board reset, in ULTRA_CMDREG. */ #define ULTRA_MEMENB 0x40 /* Enable the shared memory. */ +#define IOPD 0x02 /* I/O Pipe Data (16 bits), PIO operation. */ +#define IOPA 0x07 /* I/O Pipe Address for PIO operation. */ #define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */ #define ULTRA_IO_EXTENT 32 +#define EN0_ERWCNT 0x08 /* Early receive warning count. */ /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum @@ -123,7 +133,7 @@ unsigned char eeprom_irq = 0; static unsigned version_printed = 0; /* Values from various config regs. */ - unsigned char num_pages, irqreg, addr; + unsigned char num_pages, irqreg, addr, piomode; unsigned char idreg = inb(ioaddr + 7); unsigned char reg4 = inb(ioaddr + 4) & 0x7f; @@ -162,8 +172,9 @@ /* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */ outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c); - irqreg = inb(ioaddr + 0xd); + piomode = inb(ioaddr + 0x8); addr = inb(ioaddr + 0xb); + irqreg = inb(ioaddr + 0xd); /* Switch back to the station address register set so that the MS-DOS driver can find the card after a warm boot. */ @@ -214,13 +225,20 @@ dev->mem_end = dev->rmem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256; - printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ", - dev->irq, dev->mem_start, dev->mem_end-1); - + if (piomode) { + printk(",%s IRQ %d programmed-I/O mode.\n", + eeprom_irq ? "EEPROM" : "assigned ", dev->irq); + ei_status.block_input = &ultra_pio_input; + ei_status.block_output = &ultra_pio_output; + ei_status.get_8390_hdr = &ultra_pio_get_hdr; + } else { + printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ", + dev->irq, dev->mem_start, dev->mem_end-1); + ei_status.block_input = &ultra_block_input; + ei_status.block_output = &ultra_block_output; + ei_status.get_8390_hdr = &ultra_get_8390_hdr; + } ei_status.reset_8390 = &ultra_reset_8390; - ei_status.block_input = &ultra_block_input; - ei_status.block_output = &ultra_block_output; - ei_status.get_8390_hdr = &ultra_get_8390_hdr; dev->open = &ultra_open; dev->stop = &ultra_close_card; NS8390_init(dev, 0); @@ -236,9 +254,16 @@ if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, NULL)) return -EAGAIN; - outb(ULTRA_MEMENB, ioaddr); /* Enable memory, 16 bit mode. */ + outb(0x00, ioaddr); /* Disable shared memory for safety. */ outb(0x80, ioaddr + 5); - outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */ + if (ei_status.block_input == &ultra_pio_input) + outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */ + else + outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */ + /* Set the early receive warning level in window 0 high enough not + to receive ERW interrupts. */ + outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr); + outb(0xff, dev->base_addr + EN0_ERWCNT); ei_open(dev); MOD_INC_USE_COUNT; return 0; @@ -253,7 +278,12 @@ if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies); ei_status.txing = 0; - outb(ULTRA_MEMENB, cmd_port); + outb(0x00, cmd_port); /* Disable shared memory for safety. */ + outb(0x80, cmd_port + 5); + if (ei_status.block_input == &ultra_pio_input) + outb(0x11, cmd_port + 6); /* Enable interrupts and PIO. */ + else + outb(0x01, cmd_port + 6); /* Enable interrupts and memory. */ if (ei_debug > 1) printk("reset done\n"); return; @@ -266,7 +296,6 @@ static void ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { - unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8); outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */ @@ -316,6 +345,49 @@ memcpy_toio(shmem, buf, count); outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ +} + +/* The identical operations for programmed I/O cards. + The PIO model is trivial to use: the 16 bit start address is written + byte-sequentially to IOPA, with no intervening I/O operations, and the + data is read or written to the IOPD data port. + The only potential complication is that the address register is shared + must be always be rewritten between each read/write direction change. + This is no problem for us, as the 8390 code ensures that we are single + threaded. */ +static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, + int ring_page) +{ + int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ + outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ + outb(ring_page, ioaddr + IOPA); + insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1); +} + +static void ultra_pio_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ + char *buf = skb->data; + + /* For now set the address again, although it should already be correct. */ + outb(ring_offset, ioaddr + IOPA); /* Set the address, LSB first. */ + outb(ring_offset >> 8, ioaddr + IOPA); + insw(ioaddr + IOPD, buf, (count+1)>>1); +#ifdef notdef + /* We don't need this -- skbuffs are padded to at least word alignment. */ + if (count & 0x01) { + buf[count-1] = inb(ioaddr + IOPD); +#endif +} + +static void ultra_pio_output(struct device *dev, int count, + const unsigned char *buf, const start_page) +{ + int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ + outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ + outb(start_page, ioaddr + IOPA); + outsw(ioaddr + IOPD, buf, (count+1)>>1); } static int diff -u --recursive --new-file v1.3.98/linux/drivers/sbus/char/sunkeymap.map linux/drivers/sbus/char/sunkeymap.map --- v1.3.98/linux/drivers/sbus/char/sunkeymap.map Sat Apr 27 15:19:56 1996 +++ linux/drivers/sbus/char/sunkeymap.map Mon May 6 12:26:09 1996 @@ -273,7 +273,7 @@ # keycode 0x7f is special and it means 'all keys released' and is # taken care of within the sun keyboard driver itself keycode 0x7f = -# Thats all folks... +# That's all folks... string F1 = "\033[[A" string F2 = "\033[[B" string F3 = "\033[[C" diff -u --recursive --new-file v1.3.98/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v1.3.98/linux/drivers/sbus/char/sunserial.c Sun May 5 08:52:00 1996 +++ linux/drivers/sbus/char/sunserial.c Mon May 6 12:26:09 1996 @@ -467,7 +467,7 @@ } if((info->xmit_cnt <= 0) || info->tty->stopped) { - /* Thats peculiar... */ + /* That's peculiar... */ info->zs_channel->control = RES_Tx_P; udelay(5); goto clear_and_return; diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v1.3.98/linux/drivers/scsi/53c7,8xx.c Wed Apr 17 09:06:32 1996 +++ linux/drivers/scsi/53c7,8xx.c Mon May 6 12:26:10 1996 @@ -345,7 +345,7 @@ * 001c46d4 : 0x001c5ea0 0x000011f8 * * Changed the print code in the phase_mismatch handler so - * that we call print_lots to try and diagnose this. + * that we call print_lots to try to diagnose this. * */ diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog --- v1.3.98/linux/drivers/scsi/ChangeLog Fri Apr 19 10:07:59 1996 +++ linux/drivers/scsi/ChangeLog Mon May 6 12:26:10 1996 @@ -1233,7 +1233,7 @@ * scsi.c (scan_scsis): Add new devices to end of linked list, not to the beginning. - * scsi.h (SCSI_SLEEP): Remove brain dead hack to try and save + * scsi.h (SCSI_SLEEP): Remove brain dead hack to try to save the task state before sleeping. Sat Jul 9 15:01:03 1994 Eric Youngdale (eric@esp22) @@ -1724,7 +1724,7 @@ * constants.c, constants.h: New files with ascii descriptions of various conditions. - * Makefile: Do not try and count the number of low-level drivers, + * Makefile: Do not try to count the number of low-level drivers, just generate the list of .o files. * aha1542.c: Replace 16 with sizeof(SCpnt->sense_buffer). Add tests @@ -1819,7 +1819,7 @@ * sr.c: Increase timeout to 500 from 250. Add entry for sync in dispatch table (supply NULL). If we do not have a sectorsize, - try and get it in the sd_open function. Add new function just to + try to get it in the sd_open function. Add new function just to obtain sectorsize. * sr.h: Add needs_sector_size semaphore. diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v1.3.98/linux/drivers/scsi/Config.in Sun Apr 21 12:39:01 1996 +++ linux/drivers/scsi/Config.in Mon May 6 07:34:20 1996 @@ -21,7 +21,7 @@ dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI -dep_tristate 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI +dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v1.3.98/linux/drivers/scsi/README.st Sun May 5 08:52:00 1996 +++ linux/drivers/scsi/README.st Sun May 5 08:51:13 1996 @@ -274,7 +274,7 @@ The following ioctls use the structure mtlocation that contains both the block number and the partition number. These ioctls are available only for SCSI-2 tape drives and the block number is the -device-indepent logical block number defined by the standard. +device-independent logical block number defined by the standard. MTGETLOC Returns the current block and partition number. MTSETLOC Sets the tape to the block and partition specified by the diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v1.3.98/linux/drivers/scsi/aha1542.c Mon Apr 15 12:20:19 1996 +++ linux/drivers/scsi/aha1542.c Mon May 6 12:26:10 1996 @@ -1214,7 +1214,7 @@ setup_mailboxes(SCpnt->host->io_port, SCpnt->host); /* - * Now try and pick up the pieces. Restart all commands + * Now try to pick up the pieces. Restart all commands * that are currently active on the bus, and reset all of * the datastructures. We have some time to kill while * things settle down, so print a nice message. diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v1.3.98/linux/drivers/scsi/aic7xxx.c Sun May 5 08:52:00 1996 +++ linux/drivers/scsi/aic7xxx.c Mon May 6 12:26:10 1996 @@ -4483,12 +4483,12 @@ * The target we select to send the message to may be entirely * different than the target pointed to by the scb that timed * out. If the command is in the QINFIFO or the waiting for - * selection list, its not tying up the bus and isn't responsible + * selection list, it's not tying up the bus and isn't responsible * for the delay so we pick off the active command which should - * be the SCB selected by SCBPTR. If its disconnected or active, + * be the SCB selected by SCBPTR. If it's disconnected or active, * we device reset the target scbp points to. Although it may * be that this target is not responsible for the delay, it may - * may also be that we're timing out on a command that just takes + * also be that we're timing out on a command that just takes * too much time, so we try the bus device reset there first. */ active_scb = inb(SCBPTR + base); diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v1.3.98/linux/drivers/scsi/eata_dma.c Sun May 5 08:52:00 1996 +++ linux/drivers/scsi/eata_dma.c Mon May 6 07:34:20 1996 @@ -8,8 +8,15 @@ * * * The driver currently: * * -supports all ISA based EATA-DMA boards * + * like PM2011, PM2021, PM2041, PM3021 * * -supports all EISA based EATA-DMA boards * + * like PM2012B, PM2022, PM2122, PM2322, PM2042, * + * PM3122, PM3222, PM3332 * * -supports all PCI based EATA-DMA boards * + * like PM2024, PM2124, PM2044, PM2144, PM3224, * + * PM3334 * + * -supports the Wide, Ultra Wide and Differential * + * versions of the boards * * -supports multiple HBAs with & without IRQ sharing * * -supports all SCSI channels on multi channel boards * * -needs identical IDs on all channels of a HBA * @@ -19,8 +26,9 @@ * -provides rudimentary latency measurement * * possibilities via /proc/scsi/eata_dma/ * * * - * (c)1993,94,95 Michael Neuffer * - * neuffer@goofy.zdv.uni-mainz.de * + * (c)1993-96 Michael Neuffer * + * mike@i-Connect.Net * + * neuffer@mail.uni-mainz.de * * * * This program is free software; you can redistribute it * * and/or modify it under the terms of the GNU General * @@ -45,10 +53,11 @@ * very helpful and tried to give me all the infos and * * support I need. * * * - * Thanks also to Greg Hosler who did a lot of testing and * - * found quite a number of bugs during the development. * + * Thanks also to Simon Shapiro, Greg Hosler and Mike * + * Jagdis who did a lot of testing and found quite a number * + * of bugs during the development. * ************************************************************ - * last change: 95/04/27 OS: Linux 1.3.95 * + * last change: 95/05/05 OS: Linux 1.3.98 * ************************************************************/ /* Look in eata_dma.h for configuration and revision information */ @@ -63,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -132,7 +142,7 @@ else reg_IRQ[sh->irq]--; scsi_init_free((void *)status, 512); - scsi_init_free((void *)dma_scratch, 512); + scsi_init_free((void *)dma_scratch - 4, 1024); for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */ if(SD(sh)->ccb[i].sg_list != NULL) scsi_init_free((void *) SD(sh)->ccb[i].sg_list, @@ -149,12 +159,89 @@ #endif +inline void eata_latency_in(struct eata_ccb *cp, hostdata *hd) +{ + uint time; + time = jiffies - cp->timestamp; + if(hd->all_lat[1] > time) + hd->all_lat[1] = time; + if(hd->all_lat[2] < time) + hd->all_lat[2] = time; + hd->all_lat[3] += time; + hd->all_lat[0]++; + if((cp->rw_latency) == WRITE) { /* was WRITE */ + if(hd->writes_lat[cp->sizeindex][1] > time) + hd->writes_lat[cp->sizeindex][1] = time; + if(hd->writes_lat[cp->sizeindex][2] < time) + hd->writes_lat[cp->sizeindex][2] = time; + hd->writes_lat[cp->sizeindex][3] += time; + hd->writes_lat[cp->sizeindex][0]++; + } else if((cp->rw_latency) == READ) { + if(hd->reads_lat[cp->sizeindex][1] > time) + hd->reads_lat[cp->sizeindex][1] = time; + if(hd->reads_lat[cp->sizeindex][2] < time) + hd->reads_lat[cp->sizeindex][2] = time; + hd->reads_lat[cp->sizeindex][3] += time; + hd->reads_lat[cp->sizeindex][0]++; + } +} + +inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd) +{ + int x, z; + short *sho; + long *lon; + x = 0; /* just to keep GCC quiet */ + cp->timestamp = jiffies; /* For latency measurements */ + switch(cmd->cmnd[0]) { + case WRITE_6: + x = cmd->cmnd[4]/2; + cp->rw_latency = WRITE; + break; + case READ_6: + x = cmd->cmnd[4]/2; + cp->rw_latency = READ; + break; + case WRITE_10: + sho = (short *) &cmd->cmnd[7]; + x = ntohs(*sho)/2; + cp->rw_latency = WRITE; + break; + case READ_10: + sho = (short *) &cmd->cmnd[7]; + x = ntohs(*sho)/2; + cp->rw_latency = READ; + break; + case WRITE_12: + lon = (long *) &cmd->cmnd[6]; + x = ntohl(*lon)/2; + cp->rw_latency = WRITE; + break; + case READ_12: + lon = (long *) &cmd->cmnd[6]; + x = ntohl(*lon)/2; + cp->rw_latency = READ; + break; + default: + cp->rw_latency = OTHER; + break; + } + if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || + cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 || + cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) { + for(z = 0; (x > (1 << z)) && (z <= 11); z++) + /* nothing */; + cp->sizeindex = z; + } +} + + void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs) { uint i, result = 0; uint hba_stat, scsi_stat, eata_stat; Scsi_Cmnd *cmd; - struct eata_ccb *cp; + struct eata_ccb *ccb; struct eata_sp *sp; uint base; ulong flags; @@ -173,16 +260,16 @@ int_counter++; sp = &SD(sh)->sp; - cp = sp->ccb; + ccb = sp->ccb; - if(cp == NULL) { + if(ccb == NULL) { eata_stat = inb((uint)sh->base + HA_RSTATUS); printk("eata_dma: int_handler, Spurious IRQ %d " "received. CCB pointer not set.\n", irq); break; } - cmd = cp->cmd; + cmd = ccb->cmd; base = (uint) cmd->host->base; hba_stat = sp->hba_stat; @@ -190,23 +277,27 @@ if (sp->EOC == FALSE) { eata_stat = inb(base + HA_RSTATUS); - printk("eata_dma: int_handler, board: %x cmd %lx returned " - "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx " - "spadrirq %lx, irq%d\n", base, (long)cp, eata_stat, - hba_stat, scsi_stat,(long)&status, (long)&status[irq], - irq); - DBG(DBG_DELAY, DEL2(800)); + printk(KERN_WARNING "eata_dma: int_handler, board: %x cmd %lx " + "returned unfinished.\n" + "EATA: %x HBA: %x SCSI: %x spadr %lx spadrirq %lx, " + "irq%d\n", base, (long)ccb, eata_stat, hba_stat, + scsi_stat,(long)&status, (long)&status[irq], irq); + cmd->result = DID_ERROR << 16; + ccb->status = FREE; + cmd->scsi_done(cmd); break; } - if (cp->status == LOCKED) { - cp->status = FREE; + if (ccb->status == LOCKED) { + ccb->status = FREE; eata_stat = inb(base + HA_RSTATUS); printk("eata_dma: int_handler, freeing locked queueslot\n"); - DBG(DBG_INTR && DBG_DELAY, DEL2(800)); + DBG(DBG_INTR && DBG_DELAY, DELAY(1)); break; } + sp->EOC = FALSE; /* Clean out this flag */ + eata_stat = inb(base + HA_RSTATUS); DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, " "target: %x, lun: %x, ea_s: %#.2x, hba_s: " @@ -215,52 +306,22 @@ switch (hba_stat) { case HA_NO_ERROR: /* NO Error */ - if (scsi_stat == CONDITION_GOOD - && cmd->device->type == TYPE_DISK - && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET)) - result = DID_BUS_BUSY << 16; - else if (scsi_stat == GOOD) { - HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK; - if(HD(cmd)->do_latency == TRUE && cp->timestamp) { - uint time; - time = jiffies - cp->timestamp; - if((cp->rw_latency) == TRUE) { /* was WRITE */ - if(HD(cmd)->writes_lat[cp->sizeindex][1] > time) - HD(cmd)->writes_lat[cp->sizeindex][1] = time; - if(HD(cmd)->writes_lat[cp->sizeindex][2] < time) - HD(cmd)->writes_lat[cp->sizeindex][2] = time; - HD(cmd)->writes_lat[cp->sizeindex][3] += time; - HD(cmd)->writes_lat[cp->sizeindex][0]++; - } else { - if(HD(cmd)->reads_lat[cp->sizeindex][1] > time) - HD(cmd)->reads_lat[cp->sizeindex][1] = time; - if(HD(cmd)->reads_lat[cp->sizeindex][2] < time) - HD(cmd)->reads_lat[cp->sizeindex][2] = time; - HD(cmd)->reads_lat[cp->sizeindex][3] += time; - HD(cmd)->reads_lat[cp->sizeindex][0]++; - } - } - } - else if (scsi_stat == CHECK_CONDITION - && cmd->device->type == TYPE_DISK - && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR) - result = DID_BUS_BUSY << 16; - else - result = DID_OK << 16; - HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK; + HD(cmd)->t_state[ccb->cp_channel][ccb->cp_id] = OK; + if(HD(cmd)->do_latency == TRUE && ccb->timestamp) + eata_latency_in(ccb, HD(cmd)); + result = DID_OK << 16; + HD(cmd)->t_timeout[ccb->cp_channel][ccb->cp_id] = OK; break; case HA_ERR_SEL_TO: /* Selection Timeout */ - result = DID_BAD_TARGET << 16; - break; case HA_ERR_CMD_TO: /* Command Timeout */ - if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1) - result = DID_ERROR << 16; - else { - result = DID_TIME_OUT << 16; - HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++; - } + result = DID_TIME_OUT << 16; + break; + case HA_BUS_RESET: /* SCSI Bus Reset Received */ + result = DID_RESET << 16; + DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: BUS RESET " + "received on cmd %ld\n", + HD(cmd)->HBA_number, cmd->pid)); break; - case HA_ERR_RESET: /* SCSI Bus Reset Received */ case HA_INIT_POWERUP: /* Initial Controller Power-up */ if (cmd->device->type != TYPE_TAPE) result = DID_BUS_BUSY << 16; @@ -268,15 +329,39 @@ result = DID_ERROR << 16; for (i = 0; i < MAXTARGET; i++) - HD(cmd)->t_state[cp->cp_channel][i] = RESET; + HD(cmd)->t_state[ccb->cp_channel][i] = RESET; + DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld " + "returned with INIT_POWERUP\n", + HD(cmd)->HBA_number, cmd->pid)); + break; + case HA_CP_ABORT_NA: + case HA_CP_ABORTED: + result = DID_ABORT << 16; + DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: aborted cmd " + "returned\n", HD(cmd)->HBA_number)); + break; + case HA_CP_RESET_NA: + case HA_CP_RESET: + HD(cmd)->t_state[cmd->channel][cmd->target] = OK; + HD(cmd)->resetlevel[cmd->channel] = 0; + result = DID_RESET << 16; + DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd " + "pid %ldreturned\n", + HD(cmd)->HBA_number, cmd->pid)); + case HA_SCSI_HUNG: /* SCSI Hung */ + printk(KERN_ERR "scsi%d: SCSI hung\n", HD(cmd)->HBA_number); + result = DID_ERROR << 16; + break; + case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */ + DBG(DBG_STATUS, printk(KERN_ERR "scsi%d: Auto Request Sense " + "Failed\n", HD(cmd)->HBA_number)); + result = DID_ERROR << 16; break; case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */ case HA_UNX_BUS_FREE: /* Unexpected Bus Free */ case HA_BUS_PARITY: /* Bus Parity Error */ - case HA_SCSI_HUNG: /* SCSI Hung */ case HA_UNX_MSGRJCT: /* Unexpected Message Reject */ case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */ - case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */ case HA_PARITY_ERR: /* Controller Ram Parity */ default: result = DID_ERROR << 16; @@ -293,10 +378,10 @@ cmd->device->channel, cmd->device->id, cmd->device->lun, cmd->pid, eata_stat, hba_stat, scsi_stat, cmd->sense_buffer[2] & 0xf, cmd->result); - DBG(DBG_INTR&&DBG_DELAY,DEL2(800)); + DBG(DBG_INTR&&DBG_DELAY,DELAY(1)); #endif - cp->status = FREE; /* now we can release the slot */ + ccb->status = FREE; /* now we can release the slot */ cmd->scsi_done(cmd); } } @@ -314,41 +399,55 @@ return(FALSE); /* And now the address in nice little byte chunks */ +#ifdef __LITTLE_ENDIAN outb( addr & 0x000000ff, base + HA_WDMAADDR); outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); +#else + outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR); + outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1); + outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2); + outb((addr & 0x000000ff), base + HA_WDMAADDR + 3); +#endif outb(command, base + HA_WCOMMAND); return(TRUE); } -#if 0 -inline int eata_send_immediate(u32 addr, u32 base, u8 cmnd, u8 cmnd2, u8 id, - u8 lun) +inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2) { + outb(0x0, base + HA_WDMAADDR - 1); if(addr){ - outb( addr & 0x000000ff, base + HA_WDMAADDR); - outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); +#ifdef __LITTLE_ENDIAN + outb( addr & 0x000000ff, base + HA_WDMAADDR); + outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); +#else + outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR); + outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1); + outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2); + outb((addr & 0x000000ff), base + HA_WDMAADDR + 3); +#endif } else { - outb(id, base + HA_WSUBCODE); - outb(lun, base + HA_WSUBLUN); + outb(0x0, base + HA_WDMAADDR); + outb(0x0, base + HA_WDMAADDR + 1); + outb(code2, base + HA_WCODE2); + outb(code, base + HA_WCODE); } - outb(cmnd2, base + HA_WCOMMAND2); - outb(cmnd, base + HA_WCOMMAND); + outb(ifc, base + HA_WIFC); + outb(EATA_CMD_IMMEDIATE, base + HA_WCOMMAND); return(TRUE); } -#endif int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *)) { unsigned int i, x, y; - u32 flags; + ulong flags; hostdata *hd; struct Scsi_Host *sh; - struct eata_ccb *cp; + struct eata_ccb *ccb; struct scatterlist *sl; save_flags(flags); @@ -359,6 +458,15 @@ hd = HD(cmd); sh = cmd->host; +#if 1 + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) { + DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n")); + cmd->result = DID_OK << 16; + done(cmd); + return(0); + } +#endif + /* check for free slot */ for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { if (y >= sh->can_queue) @@ -378,52 +486,19 @@ restore_flags(flags); return(0); } - cp = &hd->ccb[y]; + ccb = &hd->ccb[y]; - memset(cp, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *)); + memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *)); - cp->status = USED; /* claim free slot */ + ccb->status = USED; /* claim free slot */ DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y)); - DBG(DBG_QUEUE && DBG_DELAY, DEL2(250)); + DBG(DBG_QUEUE && DBG_DELAY, DELAY(1)); - if(hd->do_latency == TRUE) { - int x, z; - short *sho; - long *lon; - x = 0; /* just to keep GCC quiet */ - if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || - cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 || - cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) { - - cp->timestamp = jiffies; /* For latency measurements */ - switch(cmd->cmnd[0]) { - case WRITE_6: - case READ_6: - x = cmd->cmnd[4]/2; - break; - case WRITE_10: - case READ_10: - sho = (short *) &cmd->cmnd[7]; - x = ntohs(*sho)/2; - break; - case WRITE_12: - case READ_12: - lon = (long *) &cmd->cmnd[6]; - x = ntohl(*lon)/2; - break; - } + if(hd->do_latency == TRUE) + eata_latency_out(ccb, cmd); - for(z = 0; (x > (1 << z)) && (z <= 11); z++) - /* nothing */; - cp->sizeindex = z; - if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || - cmd->cmnd[0] == WRITE_12){ - cp->rw_latency = TRUE; - } - } - } cmd->scsi_done = (void *)done; switch (cmd->cmnd[0]) { @@ -438,73 +513,73 @@ case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: case 0xea: /* alternate number for WRITE LONG */ - cp->DataOut = TRUE; /* Output mode */ + ccb->DataOut = TRUE; /* Output mode */ break; case TEST_UNIT_READY: default: - cp->DataIn = TRUE; /* Input mode */ + ccb->DataIn = TRUE; /* Input mode */ } /* FIXME: This will will have to be changed once the midlevel driver * allows different HBA IDs on every channel. */ if (cmd->target == sh->this_id) - cp->Interpret = TRUE; /* Interpret command */ + ccb->Interpret = TRUE; /* Interpret command */ if (cmd->use_sg) { - cp->scatter = TRUE; /* SG mode */ - if (cp->sg_list == NULL) { - cp->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list), + ccb->scatter = TRUE; /* SG mode */ + if (ccb->sg_list == NULL) { + ccb->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list), GFP_ATOMIC | GFP_DMA); } - if (cp->sg_list == NULL) + if (ccb->sg_list == NULL) panic("eata_dma: Run out of DMA memory for SG lists !\n"); - cp->cp_dataDMA = htonl(virt_to_bus(cp->sg_list)); + ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list)); - cp->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list)); + ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list)); sl=(struct scatterlist *)cmd->request_buffer; for(i = 0; i < cmd->use_sg; i++, sl++){ - cp->sg_list[i].data = htonl(virt_to_bus(sl->address)); - cp->sg_list[i].len = htonl((u32) sl->length); + ccb->sg_list[i].data = htonl(virt_to_bus(sl->address)); + ccb->sg_list[i].len = htonl((u32) sl->length); } } else { - cp->scatter = FALSE; - cp->cp_datalen = htonl(cmd->request_bufflen); - cp->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer)); + ccb->scatter = FALSE; + ccb->cp_datalen = htonl(cmd->request_bufflen); + ccb->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer)); } - cp->Auto_Req_Sen = TRUE; - cp->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer)); - cp->reqlen = sizeof(cmd->sense_buffer); - - cp->cp_id = cmd->target; - cp->cp_channel = cmd->channel; - cp->cp_lun = cmd->lun; - cp->cp_dispri = TRUE; - cp->cp_identify = TRUE; - memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len); + ccb->Auto_Req_Sen = TRUE; + ccb->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer)); + ccb->reqlen = sizeof(cmd->sense_buffer); + + ccb->cp_id = cmd->target; + ccb->cp_channel = cmd->channel; + ccb->cp_lun = cmd->lun; + ccb->cp_dispri = TRUE; + ccb->cp_identify = TRUE; + memcpy(ccb->cp_cdb, cmd->cmnd, cmd->cmd_len); - cp->cp_statDMA = htonl(virt_to_bus(&(hd->sp))); + ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp))); - cp->cp_viraddr = cp; /* This will be passed thru, so we don't need to + ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to * convert it */ - cp->cmd = cmd; + ccb->cmd = cmd; cmd->host_scribble = (char *)&hd->ccb[y]; - if(eata_send_command((u32) cp, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) { + if(eata_send_command((u32) ccb, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) { cmd->result = DID_BUS_BUSY << 16; DBG(DBG_QUEUE && DBG_ABNORM, printk("eata_queue target %d, pid %ld, HBA busy, " "returning DID_BUS_BUSY\n",cmd->target, cmd->pid)); done(cmd); - cp->status = FREE; + ccb->status = FREE; restore_flags(flags); return(0); } DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x " "slot %d irq %d\n", (s32)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq)); - DBG(DBG_QUEUE && DBG_DELAY, DEL2(200)); + DBG(DBG_QUEUE && DBG_DELAY, DELAY(1)); restore_flags(flags); return(0); } @@ -521,26 +596,26 @@ DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x" " reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason)); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) { if (--loop == 0) { printk("eata_dma: abort, timeout error.\n"); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); restore_flags(flags); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); return (SCSI_ABORT_ERROR); } } if (CD(cmd)->status == RESET) { - restore_flags(flags); printk("eata_dma: abort, command reset error.\n"); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); + restore_flags(flags); return (SCSI_ABORT_ERROR); } if (CD(cmd)->status == LOCKED) { - restore_flags(flags); DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n")); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); + restore_flags(flags); return (SCSI_ABORT_NOT_RUNNING); } if (CD(cmd)->status == USED) { @@ -557,11 +632,11 @@ panic("eata_dma: abort: invalid slot status\n"); } -int eata_reset(Scsi_Cmnd * cmd, int resetflags) +int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags) { ushort x, z; - ulong time, limit = 0; - ulong loop = R_LIMIT; + ulong limit = 0; + ulong loop = loops_per_sec / 3; ulong flags; unchar success = FALSE; Scsi_Cmnd *sp; @@ -576,7 +651,7 @@ if (HD(cmd)->state == RESET) { printk("eata_reset: exit, already in reset.\n"); restore_flags(flags); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_ERROR); } @@ -584,7 +659,7 @@ if (--loop == 0) { printk("eata_reset: exit, timeout error.\n"); restore_flags(flags); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_ERROR); } @@ -602,17 +677,17 @@ if (HD(cmd)->ccb[x].status == LOCKED) { HD(cmd)->ccb[x].status = FREE; printk("eata_reset: locked slot %d forced free.\n", x); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); continue; } sp = HD(cmd)->ccb[x].cmd; HD(cmd)->ccb[x].status = RESET; printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); if (sp == NULL) panic("eata_reset: slot %d, sp==NULL.\n", x); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); if (sp == cmd) success = TRUE; @@ -624,19 +699,12 @@ DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n")); HD(cmd)->state = RESET; - - restore_flags(flags); - - time = jiffies; - while (jiffies < (time + (3 * HZ)) || limit++ < 10000000) - /* As time goes by... */; - - save_flags(flags); - cli(); + + DELAY(1); DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n", limit)); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); for (x = 0; x < cmd->host->can_queue; x++) { @@ -652,10 +720,9 @@ printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n", x, sp->pid); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); - restore_flags(flags); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); + sp->scsi_done(sp); - cli(); } HD(cmd)->state = FALSE; @@ -663,11 +730,11 @@ if (success) { DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n")); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_SUCCESS); } else { DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n")); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_PUNT); } } @@ -677,7 +744,8 @@ * * At the moment the algorithm is rather simple */ -static void eata_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devicelist) +static void eata_select_queue_depths(struct Scsi_Host *host, + Scsi_Device *devicelist) { Scsi_Device *device; int devcount = 0; @@ -745,13 +813,34 @@ } else /* ISA forces us to limit the QS because of bounce buffers*/ device->queue_depth = 2; /* I know this is cruel */ - printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d set " - "to %d\n", host->host_no, device->id, device->channel, + printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d " + "set to %d\n", host->host_no, device->id, device->channel, device->queue_depth); } } } +int check_blink_state(long base) +{ + ushort loops = 10; + u32 blinkindicator; + u32 state = 0x12345678; + u32 oldstate = 0; + + blinkindicator = htonl(0x54504442); + while ((loops--) && (state != oldstate)) { + oldstate = state; + state = inl((uint) base + 1); + } + + DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n", + (state == oldstate) && (state == blinkindicator))); + + if ((state == oldstate) && (state == blinkindicator)) + return(TRUE); + else + return (FALSE); +} char * get_board_data(u32 base, u32 irq, u32 id) { @@ -802,8 +891,8 @@ while (fake_int_happened == FALSE && jiffies <= i) barrier(); - DBG(DBG_INTR3, printk("fake_int_result: %#x hbastat %#x scsistat %#x," - " buff %p sp %p\n", + DBG(DBG_INTR3, printk(KERN_DEBUG "fake_int_result: %#x hbastat %#x " + "scsistat %#x, buff %p sp %p\n", fake_int_result, (u32) (sp->hba_stat /*& 0x7f*/), (u32) sp->scsi_stat, buff, sp)); @@ -811,38 +900,17 @@ scsi_init_free((void *)sp, sizeof(struct eata_sp)); if ((fake_int_result & HA_SERROR) || jiffies > i){ + printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear " + "possible blink state\n", base); /* hard reset the HBA */ inb((u32) (base) + HA_RSTATUS); eata_send_command(0, base, EATA_CMD_RESET); - i = jiffies; - while (jiffies < (i + (3 * HZ)) && limit++ < 10000000) - barrier(); + DELAY(1); return (NULL); } else return (buff); } - -int check_blink_state(long base) -{ - ushort loops = 10; - u32 blinkindicator; - u32 state = 0x12345678; - u32 oldstate = 0; - - blinkindicator = htonl(0x54504442); - while ((loops--) && (state != oldstate)) { - oldstate = state; - state = inl((uint) base + 1); - } - - DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n", - (state == oldstate) && (state == blinkindicator))); - if ((state == oldstate) && (state == blinkindicator)) - return(TRUE); - else - return (FALSE); -} int get_conf_PIO(u32 base, struct get_conf *buf) { @@ -857,6 +925,10 @@ while (inb(base + HA_RSTATUS) & HA_SBUSY) if (--loop == 0) return (FALSE); + + fake_int_base = (struct eata_register *) base; + fake_int_result = FALSE; + fake_int_happened = FALSE; DBG(DBG_PIO && DBG_PROBE, printk("Issuing PIO READ CONFIG to HBA at %#x\n", base)); @@ -890,6 +962,7 @@ return (FALSE); } + void print_config(struct get_conf *gc) { printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n", @@ -929,7 +1002,7 @@ } if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22) gc->MAX_CHAN = 0; - + if (reg_IRQ[gc->IRQ] == FALSE) { /* Interrupt already registered ? */ if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT, "eata_dma", NULL)){ @@ -948,13 +1021,27 @@ } else reg_IRQ[gc->IRQ]++; } - + + + /* If DMA is supported but DMA_valid isn't set to indicate that + * the channel number is given we must have pre 2.0 firmware (1.7?) + * which leaves us to guess since the "newer ones" also don't set the + * DMA_valid bit. + */ + if (gc->DMA_support && !gc->DMA_valid && gc->DMA_channel) { + printk(KERN_WARNING "eata_dma: If you are using a pre 2.0 firmware " + "please update it !\n" + " You can get new firmware releases from ftp.dpt.com\n"); + gc->DMA_channel = (base == 0x1f0 ? 3 /* DMA=5 */ : 2 /* DMA=6 */); + gc->DMA_valid = TRUE; + } + /* if gc->DMA_valid it must be an ISA HBA and we have to register it */ dma_channel = BUSMASTER; if (gc->DMA_valid) { if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) { - printk("Unable to allocate DMA channel %d for ISA HBA at %#.4x.\n", - dma_channel, base); + printk(KERN_WARNING "Unable to allocate DMA channel %d for ISA HBA" + " at %#.4x.\n", dma_channel, base); reg_IRQ[gc->IRQ]--; if (reg_IRQ[gc->IRQ] == 0) free_irq(gc->IRQ, NULL); @@ -963,23 +1050,27 @@ return (FALSE); } } - -#if !(NEWSTUFF) + + if (dma_channel != BUSMASTER) { + disable_dma(dma_channel); + clear_dma_ff(dma_channel); + set_dma_mode(dma_channel, DMA_MODE_CASCADE); + enable_dma(dma_channel); + } + if (bustype != IS_EISA && bustype != IS_ISA) -#endif buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]); if (buff == NULL) { -#if !(NEWSTUFF) if (bustype == IS_EISA || bustype == IS_ISA) { bugs = bugs || BROKEN_INQUIRY; } else { -#endif if (gc->DMA_support == FALSE) - printk("HBA at %#.4x doesn't support DMA. Sorry\n", base); + printk(KERN_WARNING "HBA at %#.4x doesn't support DMA. " + "Sorry\n", base); else - printk("HBA at %#.4x does not react on INQUIRY. Sorry.\n", - base); + printk(KERN_WARNING "HBA at %#.4x does not react on INQUIRY. " + "Sorry.\n", base); if (gc->DMA_valid) free_dma(dma_channel); reg_IRQ[gc->IRQ]--; @@ -988,14 +1079,12 @@ if (gc->IRQ_TR == FALSE) reg_IRQL[gc->IRQ] = FALSE; return (FALSE); -#if !(NEWSTUFF) } -#endif } - + if (gc->DMA_support == FALSE && buff != NULL) - printk("HBA %.12sat %#.4x doesn't set the DMA_support flag correctly.\n", - &buff[16], base); + printk(KERN_WARNING "HBA %.12sat %#.4x doesn't set the DMA_support " + "flag correctly.\n", &buff[16], base); request_region(base, 9, "eata_dma"); /* We already checked the * availability, so this @@ -1004,8 +1093,10 @@ if(ntohs(gc->queuesiz) == 0) { gc->queuesiz = ntohs(64); - printk("Warning: Queue size has to be corrected. Assuming 64 queueslots\n" - " This might be a PM2012B with a defective Firmware\n"); + printk(KERN_WARNING "Warning: Queue size has to be corrected. Assuming" + " 64 queueslots\n" + " This might be a PM2012B with a defective Firmware\n" + " Contact DPT support@dpt.com for an upgrade\n"); } size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long)) @@ -1015,7 +1106,45 @@ sh = scsi_register(tpnt, size); - if(sh == NULL) { + if(sh != NULL) { + + hd = SD(sh); + + memset(hd->reads, 0, sizeof(u32) * 26); + + sh->select_queue_depths = eata_select_queue_depths; + + hd->bustype = bustype; + + /* + * If we are using a ISA board, we can't use extended SG, + * because we would need exessive amounts of memory for + * bounce buffers. + */ + if (gc->SG_64K==TRUE && ntohs(gc->SGsiz)==64 && hd->bustype!=IS_ISA){ + sh->sg_tablesize = SG_SIZE_BIG; + } else { + sh->sg_tablesize = ntohs(gc->SGsiz); + if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) { + if (sh->sg_tablesize == 0) + printk(KERN_WARNING "Warning: SG size had to be fixed.\n" + "This might be a PM2012 with a defective Firmware" + "\nContact DPT support@dpt.com for an upgrade\n"); + sh->sg_tablesize = SG_SIZE; + } + } + hd->sgsize = sh->sg_tablesize; + } + + if(sh != NULL) { + sh->can_queue = hd->queuesize = ntohs(gc->queuesiz); + sh->cmd_per_lun = 0; + } + + if(sh == NULL) { + DBG(DBG_REGISTER, printk(KERN_NOTICE "eata_dma: couldn't register HBA" + " at%x \n", base)); + scsi_unregister(sh); if (gc->DMA_valid) free_dma(dma_channel); @@ -1026,64 +1155,52 @@ reg_IRQL[gc->IRQ] = FALSE; return (FALSE); } - - hd = SD(sh); - - memset(hd->ccb, 0, sizeof(struct eata_ccb) * ntohs(gc->queuesiz)); - memset(hd->reads, 0, sizeof(u32) * 26); + hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY); if(hd->broken_INQUIRY == TRUE) { - strcpy(SD(sh)->vendor, "DPT"); - strcpy(SD(sh)->name, "??????????"); - strcpy(SD(sh)->revision, "???.?"); + strcpy(hd->vendor, "DPT"); + strcpy(hd->name, "??????????"); + strcpy(hd->revision, "???.?"); + hd->firmware_revision = 0; } else { - strncpy(SD(sh)->vendor, &buff[8], 8); - SD(sh)->vendor[8] = 0; - strncpy(SD(sh)->name, &buff[16], 17); - SD(sh)->name[17] = 0; - SD(sh)->revision[0] = buff[32]; - SD(sh)->revision[1] = buff[33]; - SD(sh)->revision[2] = buff[34]; - SD(sh)->revision[3] = '.'; - SD(sh)->revision[4] = buff[35]; - SD(sh)->revision[5] = 0; - } + strncpy(hd->vendor, &buff[8], 8); + hd->vendor[8] = 0; + strncpy(hd->name, &buff[16], 17); + hd->name[17] = 0; + hd->revision[0] = buff[32]; + hd->revision[1] = buff[33]; + hd->revision[2] = buff[34]; + hd->revision[3] = '.'; + hd->revision[4] = buff[35]; + hd->revision[5] = 0; + hd->firmware_revision = (buff[32] << 24) + (buff[33] << 16) + + (buff[34] << 8) + buff[35]; + } + + if (hd->firmware_revision >= (('0'<<24) + ('7'<<16) + ('G'<< 8) + '0')) + hd->immediate_support = 1; + else + hd->immediate_support = 0; switch (ntohl(gc->len)) { case 0x1c: - SD(sh)->EATA_revision = 'a'; + hd->EATA_revision = 'a'; break; case 0x1e: - SD(sh)->EATA_revision = 'b'; + hd->EATA_revision = 'b'; break; case 0x22: - SD(sh)->EATA_revision = 'c'; + hd->EATA_revision = 'c'; break; case 0x24: - SD(sh)->EATA_revision = 'z'; + hd->EATA_revision = 'z'; default: - SD(sh)->EATA_revision = '?'; + hd->EATA_revision = '?'; } - if(ntohl(gc->len) >= 0x22) { - if (gc->is_PCI == TRUE) - hd->bustype = IS_PCI; - else if (gc->is_EISA == TRUE) - hd->bustype = IS_EISA; - else - hd->bustype = IS_ISA; - } else if(hd->broken_INQUIRY == FALSE) { - if (buff[21] == '4') - hd->bustype = IS_PCI; - else if (buff[21] == '2') - hd->bustype = IS_EISA; - else - hd->bustype = IS_ISA; - } else - hd->bustype = bustype; - + if(ntohl(gc->len) >= 0x22) { sh->max_id = gc->MAX_ID + 1; sh->max_lun = gc->MAX_LUN + 1; @@ -1092,6 +1209,7 @@ sh->max_lun = 8; } + hd->HBA_number = sh->host_no; hd->channel = gc->MAX_CHAN; sh->max_channel = gc->MAX_CHAN; sh->unique_id = base; @@ -1105,34 +1223,7 @@ * SCSI midlevel code should support different HBA ids on every channel */ sh->this_id = gc->scsi_id[3]; - - hd->queuesize = ntohs(gc->queuesiz); - sh->can_queue = ntohs(gc->queuesiz); - sh->cmd_per_lun = 0; - sh->select_queue_depths = eata_select_queue_depths; - /* FIXME: - * SG should be allocated more dynamically - */ - /* - * If we are using a ISA board, we can't use extended SG, - * because we would need excessive amounts of memory for - * bounce buffers. - */ - if (gc->SG_64K == TRUE && ntohs(gc->SGsiz) == 64 && hd->bustype != IS_ISA){ - sh->sg_tablesize = SG_SIZE_BIG; - sh->use_clustering = TRUE; - } else { - sh->sg_tablesize = ntohs(gc->SGsiz); - sh->use_clustering = TRUE; - if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) { - sh->sg_tablesize = SG_SIZE; - if (ntohs(gc->SGsiz) == 0) - printk("Warning: SG size had to be corrected.\n" - "This might be a PM2012 with a defective Firmware\n"); - } - } - if (gc->SECOND) hd->primary = FALSE; else @@ -1150,6 +1241,7 @@ hd->writes_lat[x][1] = 0xffffffff; hd->reads_lat[x][1] = 0xffffffff; } + hd->all_lat[1] = 0xffffffff; hd->next = NULL; /* build a linked list of all HBAs */ hd->prev = last_HBA; @@ -1164,6 +1256,7 @@ } + void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt) { u32 base; @@ -1320,7 +1413,7 @@ continue; /* break; */ } else if (check_blink_state(base) == TRUE) { printk("eata_dma: HBA is in BLINK state.\n" - "Consult your HBAs Manual to correct this.\n"); + "Consult your HBAs manual to correct this.\n"); } } } @@ -1350,13 +1443,15 @@ tpnt->proc_dir = &proc_scsi_eata_dma; status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); - dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + dma_scratch = scsi_init_malloc(1024, GFP_ATOMIC | GFP_DMA); if(status == NULL || dma_scratch == NULL) { printk("eata_dma: can't allocate enough memory to probe for hosts !\n"); return(0); } + dma_scratch += 4; + find_PCI(&gc, tpnt); find_EISA(&gc, tpnt); @@ -1364,41 +1459,45 @@ find_ISA(&gc, tpnt); for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we */ - if (reg_IRQ[i]){ /* exchange the interrupt handler which */ + if (reg_IRQ[i] >= 1){ /* exchange the interrupt handler which */ free_irq(i, NULL); /* we used for probing with the real one */ - request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, "eata_dma", NULL); + request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, + "eata_dma", NULL); } } + HBA_ptr = first_HBA; - + if (registered_HBAs != 0) { - printk("EATA (Extended Attachment) driver version: %d.%d%s\n" - "developed in co-operation with DPT\n" - "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n", - VER_MAJOR, VER_MINOR, VER_SUB); - printk("Registered HBAs:"); - printk("\nHBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: " - "ID: Pr: QS: SG: CPL:\n"); - for (i = 1; i <= registered_HBAs; i++) { - printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d", + printk("EATA (Extended Attachment) driver version: %d.%d%s" + "\ndeveloped in co-operation with DPT\n" + "(c) 1993-96 Michael Neuffer, mike@i-Connect.Net\n", + VER_MAJOR, VER_MINOR, VER_SUB); + printk("Registered HBAs:"); + printk("\nHBA no. Boardtype Revis EATA Bus BaseIO IRQ" + " DMA Ch ID Pr QS S/G IS\n"); + for (i = 1; i <= registered_HBAs; i++) { + printk("scsi%-2d: %.12s v%s 2.0%c %s %#.4x %2d", HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision, SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ", (u32) HBA_ptr->base, HBA_ptr->irq); if(HBA_ptr->dma_channel != BUSMASTER) - printk(" %2x ", HBA_ptr->dma_channel); + printk(" %2x ", HBA_ptr->dma_channel); else - printk(" %s", "BMST"); - printk(" %d %d %c %2d %2d %2d\n", SD(HBA_ptr)->channel, - HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', - HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun); + printk(" %s", "BMST"); + printk(" %d %d %c %3d %3d %c\n", + SD(HBA_ptr)->channel+1, HBA_ptr->this_id, + (SD(HBA_ptr)->primary == TRUE)?'Y':'N', + HBA_ptr->can_queue, HBA_ptr->sg_tablesize, + (SD(HBA_ptr)->immediate_support == TRUE)?'Y':'N'); HBA_ptr = SD(HBA_ptr)->next; } } else { scsi_init_free((void *)status, 512); } - scsi_init_free((void *)dma_scratch, 512); + scsi_init_free((void *)dma_scratch - 4, 1024); DBG(DPT_DEBUG, DELAY(12)); diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v1.3.98/linux/drivers/scsi/eata_dma.h Sun May 5 08:52:00 1996 +++ linux/drivers/scsi/eata_dma.h Mon May 6 07:34:20 1996 @@ -1,11 +1,12 @@ /******************************************************** * Header file for eata_dma.c Linux EATA-DMA SCSI driver * -* (c) 1993,94,95 Michael Neuffer * +* (c) 1993-96 Michael Neuffer * +* mike@i-Connect.Net * +* neuffer@mail.uni-mainz.de * ********************************************************* -* last change: 95/07/18 * +* last change: 96/05/05 * ********************************************************/ - #ifndef _EATA_DMA_H #define _EATA_DMA_H @@ -16,7 +17,7 @@ #define VER_MAJOR 2 #define VER_MINOR 5 -#define VER_SUB "8a" +#define VER_SUB "8d" /************************************************************************ @@ -47,6 +48,9 @@ #define DBG_INTR 0 /* Trace interrupt service routine. */ #define DBG_INTR2 0 /* Trace interrupt service routine. */ #define DBG_INTR3 0 /* Trace get_board_data interrupts. */ +#define DBG_REQSENSE 0 /* Trace request sense commands */ +#define DBG_RESET 0 /* Trace reset calls */ +#define DBG_STATUS 0 /* Trace status generation */ #define DBG_PROC 0 /* Debug proc-fs related statistics */ #define DBG_PROC_WRITE 0 #define DBG_REGISTER 0 /* */ @@ -65,7 +69,7 @@ int eata_command(Scsi_Cmnd *); int eata_queue(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int eata_abort(Scsi_Cmnd *); -int eata_reset(Scsi_Cmnd *); +int eata_reset(Scsi_Cmnd *, unsigned int); int eata_proc_info(char *, char **, off_t, int, int, int); #ifdef MODULE int eata_release(struct Scsi_Host *); diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h --- v1.3.98/linux/drivers/scsi/eata_generic.h Sun May 5 08:52:00 1996 +++ linux/drivers/scsi/eata_generic.h Mon May 6 07:34:20 1996 @@ -1,9 +1,11 @@ /******************************************************** * Header file for eata_dma.c and eata_pio.c * * Linux EATA SCSI drivers * -* (c) 1993,94,95 Michael Neuffer * +* (c) 1993-96 Michael Neuffer * +* mike@i-Connect.Net * +* neuffer@mail.uni-mainz.de * ********************************************************* -* last change: 95/11/07 * +* last change: 95/05/05 * ********************************************************/ @@ -56,35 +58,43 @@ #define NEC_ID2 0xa3 #define NEC_ID3 0x82 + +#define EATA_CP_SIZE 44 -#define EATA_CP_SIZE 44 - -#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */ -#define MAX_METHOD_2 16 /* Max Devices For Method 2 */ -#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */ +#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */ +#define MAX_METHOD_2 16 /* Max Devices For Method 2 */ +#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */ -#define SG_SIZE 64 -#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ +#define SG_SIZE 64 +#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ #define TYPE_DISK_QUEUE 16 #define TYPE_TAPE_QUEUE 4 #define TYPE_ROM_QUEUE 4 #define TYPE_OTHER_QUEUE 2 -#define FREE 0 -#define OK 0 -#define NO_TIMEOUT 0 -#define USED 1 -#define TIMEOUT 2 -#define RESET 4 -#define LOCKED 8 +#define FREE 0 +#define OK 0 +#define NO_TIMEOUT 0 +#define USED 1 +#define TIMEOUT 2 +#define RESET 4 +#define LOCKED 8 +#define ABORTED 16 + +#define READ 0 +#define WRITE 1 +#define OTHER 2 #define HD(cmd) ((hostdata *)&(cmd->host->hostdata)) #define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble)) #define SD(host) ((hostdata *)&(host->hostdata)) -#define DELAY(x) { __u32 i; i = jiffies + (x * HZ); while (jiffies < i) barrier(); } -#define DEL2(x) { __u32 i; for (i = 0; i < 0xffff * x; i++); } +#define DELAY(x) { __u32 i; ulong flags; \ + save_flags(flags); sti(); \ + i = jiffies + (x * HZ); \ + while (jiffies < i) barrier(); \ + restore_flags(flags); } /*********************************************** * EATA Command & Register definitions * @@ -122,13 +132,14 @@ #define HA_WCOMMAND 0x07 /* command register offset */ -#define HA_WCOMMAND2 0x06 /* immediate command offset */ -#define HA_WSUBCODE 0x05 -#define HA_WSUBLUN 0x04 +#define HA_WIFC 0x06 /* immediate command offset */ +#define HA_WCODE 0x05 +#define HA_WCODE2 0x04 #define HA_WDMAADDR 0x02 /* DMA address LSB offset */ #define HA_RAUXSTAT 0x08 /* aux status register offset*/ #define HA_RSTATUS 0x07 /* status register offset */ #define HA_RDATA 0x00 /* data register (16bit) */ +#define HA_WDATA 0x00 /* data register (16bit) */ #define HA_ABUSY 0x01 /* aux busy bit */ #define HA_AIRQ 0x02 /* aux IRQ pending bit */ @@ -149,7 +160,7 @@ #define HA_NO_ERROR 0x00 /* No Error */ #define HA_ERR_SEL_TO 0x01 /* Selection Timeout */ #define HA_ERR_CMD_TO 0x02 /* Command Timeout */ -#define HA_ERR_RESET 0x03 /* SCSI Bus Reset Received */ +#define HA_BUS_RESET 0x03 /* SCSI Bus Reset Received */ #define HA_INIT_POWERUP 0x04 /* Initial Controller Power-up */ #define HA_UNX_BUSPHASE 0x05 /* Unexpected Bus Phase */ #define HA_UNX_BUS_FREE 0x06 /* Unexpected Bus Free */ @@ -247,7 +258,8 @@ ID_qest:1, /* Raidnum ID is questionable */ is_PCI:1, /* HBA is PCI */ is_EISA:1; /* HBA is EISA */ - __u8 unused[478]; + __u8 RAIDNUM; /* unique HBA identifier */ + __u8 unused[474]; }; struct eata_sg_list @@ -322,27 +334,34 @@ __u8 name[18]; __u8 revision[6]; __u8 EATA_revision; + __u32 firmware_revision; + __u8 HBA_number; __u8 bustype; /* bustype of HBA */ __u8 channel; /* # of avail. scsi channels */ __u8 state; /* state of HBA */ __u8 primary; /* true if primary */ - __u8 broken_INQUIRY:1; /* This is an EISA HBA with * + __u8 more_support:1, /* HBA supports MORE flag */ + immediate_support:1, /* HBA supports IMMEDIATE CMDs*/ + broken_INQUIRY:1; /* This is an EISA HBA with * * broken INQUIRY */ __u8 do_latency; /* Latency measurement flag */ __u32 reads[13]; __u32 writes[13]; __u32 reads_lat[12][4]; __u32 writes_lat[12][4]; + __u32 all_lat[4]; /* state of Target (RESET,..) */ __u8 t_state[MAXCHANNEL][MAXTARGET]; /* timeouts on target */ __u32 t_timeout[MAXCHANNEL][MAXTARGET]; + __u8 resetlevel[MAXCHANNEL]; __u32 last_ccb; /* Last used ccb */ __u32 cplen; /* size of CP in words */ __u16 cppadlen; /* pad length of cp in words */ - int queuesize; + __u16 queuesize; + __u16 sgsize; /* # of entries in the SG list*/ + __u16 devflags; /* bits set for detected devices */ __u8 hostid; /* SCSI ID of HBA */ - __u8 devflags; /* bits set for detected devices */ __u8 moresupport; /* HBA supports MORE flag */ struct Scsi_Host *next; struct Scsi_Host *prev; diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c --- v1.3.98/linux/drivers/scsi/eata_pio.c Sun May 5 08:52:00 1996 +++ linux/drivers/scsi/eata_pio.c Mon May 6 07:34:20 1996 @@ -242,7 +242,7 @@ eata_stat = inb(base + HA_RSTATUS); printk(KERN_NOTICE "eata_pio: int_handler, freeing locked " "queueslot\n"); - DBG(DBG_INTR&&DBG_DELAY,DEL2(800)); + DBG(DBG_INTR&&DBG_DELAY,DELAY(1)); restore_flags(flags); return; } @@ -251,7 +251,7 @@ if (stat != 0x50) printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, cmd->result); - DBG(DBG_INTR&&DBG_DELAY,DEL2(800)); + DBG(DBG_INTR&&DBG_DELAY,DELAY(1)); #endif cp->status = FREE; /* now we can release the slot */ @@ -322,7 +322,7 @@ DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:" " %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y)); - DBG(DBG_QUEUE && DBG_DELAY, DEL2(250)); + DBG(DBG_QUEUE && DBG_DELAY, DELAY(1)); cmd->scsi_done = (void *)done; @@ -396,7 +396,7 @@ DBG(DBG_QUEUE,printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x " "lun: %x slot %d irq %d\n", (long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq)); - DBG(DBG_QUEUE && DBG_DELAY, DEL2(200)); + DBG(DBG_QUEUE && DBG_DELAY, DELAY(1)); restore_flags(flags); return (0); @@ -413,14 +413,14 @@ DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld " "target: %x lun: %x reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason)); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) if (--loop == 0) { printk(KERN_WARNING "eata_pio: abort, timeout error.\n"); restore_flags(flags); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_ABORT_ERROR); } if (CD(cmd)->status == FREE) { @@ -436,21 +436,21 @@ if (CD(cmd)->status == RESET) { restore_flags(flags); printk(KERN_WARNING "eata_pio: abort, command reset error.\n"); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_ABORT_ERROR); } if (CD(cmd)->status == LOCKED) { restore_flags(flags); DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot " "locked.\n")); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_ABORT_NOT_RUNNING); } restore_flags(flags); panic("eata_pio: abort: invalid slot status\n"); } -int eata_pio_reset(Scsi_Cmnd * cmd, int dummy) +int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy) { uint x, z, time, limit = 0; ulong flags; @@ -467,7 +467,7 @@ if (HD(cmd)->state == RESET) { printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n"); restore_flags(flags); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_ERROR); } @@ -487,11 +487,11 @@ HD(cmd)->ccb[x].status = RESET; printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); if (sp == NULL) panic("eata_pio_reset: slot %d, sp==NULL.\n", x); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); } /* hard reset the HBA */ @@ -505,7 +505,7 @@ DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit)); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); for (x = 0; x < cmd->host->can_queue; x++) { @@ -517,7 +517,7 @@ sp->result = DID_RESET << 16; /* This mailbox is terminated */ - printk(KERN_WARNING "eata_pio_reset: resetted ccb %d.\n",x); + printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n",x); HD(cmd)->ccb[x].status = FREE; restore_flags(flags); @@ -530,11 +530,11 @@ if (success) { /* hmmm... */ DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n")); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_SUCCESS); } else { DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n")); - DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); return (SCSI_RESET_PUNT); } } @@ -718,7 +718,7 @@ if (!gc->IRQ_TR) reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */ } else { - printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ); + printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ); return (FALSE); } } else { /* More than one HBA on this IRQ */ diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/eata_pio.h linux/drivers/scsi/eata_pio.h --- v1.3.98/linux/drivers/scsi/eata_pio.h Sun May 5 08:52:01 1996 +++ linux/drivers/scsi/eata_pio.h Mon May 6 07:34:20 1996 @@ -65,7 +65,7 @@ int eata_pio_command(Scsi_Cmnd *); int eata_pio_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int eata_pio_abort(Scsi_Cmnd *); -int eata_pio_reset(Scsi_Cmnd *); +int eata_pio_reset(Scsi_Cmnd *, unsigned int); int eata_pio_proc_info(char *, char **, off_t, int, int, int); #ifdef MODULE int eata_pio_release(struct Scsi_Host *); diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v1.3.98/linux/drivers/scsi/fdomain.c Sun May 5 08:52:01 1996 +++ linux/drivers/scsi/fdomain.c Mon May 6 12:26:11 1996 @@ -594,7 +594,7 @@ #else /* That should have worked, but appears to - have problems. Lets assume it is an + have problems. Let's assume it is an 18c30 if the RAM is disabled. */ if (inb( port + Configuration2 ) & 0x02) { diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v1.3.98/linux/drivers/scsi/hosts.c Sat Apr 27 15:19:57 1996 +++ linux/drivers/scsi/hosts.c Mon May 6 12:26:11 1996 @@ -332,7 +332,7 @@ /* We call this when we come across a new host adapter. We only do this * once we are 100% sure that we want to use this host adapter - it is a - * pain to reverse this, so we try and avoid it + * pain to reverse this, so we try to avoid it */ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c --- v1.3.98/linux/drivers/scsi/pas16.c Sat Apr 13 18:22:07 1996 +++ linux/drivers/scsi/pas16.c Mon May 6 12:26:11 1996 @@ -311,7 +311,7 @@ /* Mediavision has some new model boards that return ID bits * that indicate a SCSI interface, but they're not (LMS). We'll - * put in an additional test to try and weed them out. + * put in an additional test to try to weed them out. */ outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v1.3.98/linux/drivers/scsi/scsi_debug.c Sun Jan 14 16:48:28 1996 +++ linux/drivers/scsi/scsi_debug.c Mon May 6 12:26:11 1996 @@ -422,7 +422,7 @@ do_done[i] = done; } else - printk("scsi_debug_queuecommand: done cant be NULL\n"); + printk("scsi_debug_queuecommand: done can't be NULL\n"); #ifdef IMMEDIATE if( !scsi_debug_lockup ) diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.3.98/linux/drivers/scsi/sd.c Sun May 5 08:52:02 1996 +++ linux/drivers/scsi/sd.c Mon May 6 12:26:11 1996 @@ -128,7 +128,7 @@ if(!rscsi_disks[target].device->access_count) sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); - }; + } /* * See if we are requesting a non-existent partition. Do this @@ -250,8 +250,8 @@ memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); scsi_free(sgpnt[i].address, sgpnt[i].length); - }; - }; + } + } /* Free list of scatter-gather pointers */ scsi_free(SCpnt->buffer, SCpnt->sglist_len); @@ -265,8 +265,8 @@ memcpy(SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen); scsi_free(SCpnt->buffer, SCpnt->bufflen); - }; - }; + } + } /* * If multiple sectors are requested in one buffer, then * they will have been finished off by the first command. @@ -307,8 +307,8 @@ #endif if (sgpnt[i].alt_address) { scsi_free(sgpnt[i].address, sgpnt[i].length); - }; - }; + } + } scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ } else { #ifdef DEBUG @@ -317,7 +317,7 @@ #endif if (SCpnt->buffer != SCpnt->request.buffer) scsi_free(SCpnt->buffer, SCpnt->bufflen); - }; + } /* * Now, if we were good little boys and girls, Santa left us a request @@ -417,7 +417,7 @@ if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { restore_flags(flags); return; - }; + } INIT_SCSI_REQUEST; SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device; @@ -468,11 +468,11 @@ restore_flags(flags); /* This is a performance enhancement. We dig down into the request - * list and try and find a queueable request (i.e. device not busy, + * list and try to find a queueable request (i.e. device not busy, * and host able to accept another command. If we find one, then we * queue it. This can make a big difference on systems with more than * one disk drive. We want to have the interrupts off when monkeying - * with the request list, because otherwise the kernel might try and + * with the request list, because otherwise the kernel might try to * slip in a request in between somewhere. */ @@ -486,21 +486,21 @@ if(SCpnt) break; req1 = req; req = req->next; - }; + } if (SCpnt && req->rq_status == RQ_INACTIVE) { if (req == CURRENT) CURRENT = CURRENT->next; else req1->next = req->next; - }; + } restore_flags(flags); - }; + } if (!SCpnt) return; /* Could not find anything to do */ /* Queue command */ requeue_sd_request(SCpnt); - }; /* While */ + } /* While */ } static void requeue_sd_request (Scsi_Cmnd * SCpnt) @@ -610,7 +610,7 @@ if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD) bounce_buffer = (char *) scsi_malloc(bounce_size); if(!bounce_buffer) contiguous = 0; - }; + } if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext) for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, @@ -620,7 +620,7 @@ contiguous = 0; break; } - }; + } if (!SCpnt->request.bh || contiguous) { /* case of page request (i.e. raw device), or unlinked buffer */ @@ -667,11 +667,11 @@ ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) { if (count < SCpnt->host->sg_tablesize) count++; else break; - }; + } this_count += (bh->b_size >> 9); bhp = bh; bh = bh->b_reqnext; - }; + } #if 0 if(SCpnt->host->unchecked_isa_dma && ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--; @@ -710,7 +710,7 @@ ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && !sgpnt[count].alt_address) { sgpnt[count].alt_address = sgpnt[count].address; - /* We try and avoid exhausting the DMA pool, since it is + /* We try to avoid exhausting the DMA pool, since it is * easier to control usage here. In other places we might * have a more pressing need, and we would be screwed if * we ran out */ @@ -719,7 +719,7 @@ } else { sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); - }; + } /* If we start running low on DMA buffers, we abort the * scatter-gather operation, and free all of the memory * we have allocated. We want to ensure that all scsi @@ -733,7 +733,7 @@ if(sgpnt[count].alt_address) scsi_free(sgpnt[count].address, sgpnt[count].length); - }; + } this_count = SCpnt->request.current_nr_sectors; buff = SCpnt->request.buffer; SCpnt->use_sg = 0; @@ -742,9 +742,8 @@ SCpnt->use_sg = count; this_count = counted -= bh->b_size >> 9; break; - }; - - }; + } + } /* Only cluster buffers if we know that we can supply DMA * buffers large enough to satisfy the request. Do not cluster @@ -766,21 +765,21 @@ else { tmp = NULL; max_sg = SCpnt->use_sg; - }; + } if(tmp){ scsi_free(sgpnt[count].address, sgpnt[count].length); sgpnt[count].address = tmp; count--; continue; - }; + } /* If we are allowed another sg chain, then increment * counter so we can insert it. Otherwise we will end up truncating */ if (SCpnt->use_sg < max_sg) SCpnt->use_sg++; - }; /* contiguous buffers */ - }; /* for loop */ + } /* contiguous buffers */ + } /* for loop */ /* This is actually how many we are going to transfer */ this_count = counted; @@ -795,7 +794,7 @@ while(bh){ printk("[%p %lx] ", bh->b_data, bh->b_size); bh = bh->b_reqnext; - }; + } if(SCpnt->use_sg < 16) for(count=0; countuse_sg; count++) printk("{%d:%p %p %d} ", count, @@ -803,15 +802,15 @@ sgpnt[count].alt_address, sgpnt[count].length); panic("Ooops"); - }; + } if (SCpnt->request.cmd == WRITE) for(count=0; countuse_sg; count++) if(sgpnt[count].alt_address) memcpy(sgpnt[count].address, sgpnt[count].alt_address, sgpnt[count].length); - }; /* Able to malloc sgpnt */ - }; /* Host adapter capable of scatter-gather */ + } /* Able to malloc sgpnt */ + } /* Host adapter capable of scatter-gather */ /* Now handle the possibility of DMA to addresses > 16Mb */ @@ -826,11 +825,11 @@ this_count = SCpnt->request.current_nr_sectors; buff = (char *) scsi_malloc(this_count << 9); if(!buff) panic("Ran out of DMA buffers."); - }; + } if (SCpnt->request.cmd == WRITE) memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9); - }; - }; + } + } #ifdef DEBUG printk("sd%c : %s %d/%d 512 byte blocks.\n", 'a' + devm, @@ -845,12 +844,12 @@ if(this_count & 1) panic("sd.c:Bad block number requested"); block = block >> 1; this_count = this_count >> 1; - }; + } if (rscsi_disks[dev].sector_size == 256){ block = block << 1; this_count = this_count << 1; - }; + } if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) { @@ -906,7 +905,7 @@ !rscsi_disks[target].device) { printk("SCSI disk request error: invalid device.\n"); return 0; - }; + } if(!rscsi_disks[target].device->removable) return 0; @@ -922,7 +921,7 @@ rscsi_disks[target].device->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ - }; + } /* * for removable scsi disk ( FLOPTICAL ) we have to recognise the @@ -1033,7 +1032,7 @@ time1 = jiffies; while(jiffies < time1 + HZ); /* Wait 1 second for next try */ printk( "." ); - }; + } } while(the_result && spintime && spintime+100*HZ > jiffies); if (spintime) { if (the_result) @@ -1041,8 +1040,7 @@ else printk( "ready\n" ); } - }; /* !MODULE_FLAG */ - + } /* !MODULE_FLAG */ retries = 3; do { @@ -1153,7 +1151,7 @@ rscsi_disks[i].device = NULL; sd_template.nr_dev--; return i; - }; + } } { /* @@ -1399,7 +1397,7 @@ restore_flags(flags); printk("Device busy for revalidation (usage=%d)\n", USAGE); return -EBUSY; - }; + } DEVICE_BUSY = 1; restore_flags(flags); @@ -1419,7 +1417,7 @@ * the partition table. */ blksize_size[MAJOR_NR][minor] = 1024; - }; + } #ifdef MAYBE_REINIT MAYBE_REINIT; @@ -1461,7 +1459,7 @@ sd_gendisk.part[minor].start_sect = 0; sd_gendisk.part[minor].nr_sects = 0; sd_sizes[minor] = 0; - }; + } dpnt->has_part_table = 0; dpnt->device = NULL; diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v1.3.98/linux/drivers/scsi/seagate.c Sun May 5 08:52:02 1996 +++ linux/drivers/scsi/seagate.c Mon May 6 12:26:11 1996 @@ -303,7 +303,7 @@ } /* If the user specified the controller type from the command line, - controller_type will be non-zero, so don't try and detect one */ + controller_type will be non-zero, so don't try to detect one */ if (!controller_type) { #ifdef OVERRIDE diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.3.98/linux/drivers/scsi/sr.c Sun May 5 08:52:02 1996 +++ linux/drivers/scsi/sr.c Mon May 6 12:26:11 1996 @@ -603,11 +603,11 @@ restore_flags(flags); /* This is a performance enhancement. We dig down into the request list and - * try and find a queueable request (i.e. device not busy, and host able to + * try to find a queueable request (i.e. device not busy, and host able to * accept another command. If we find one, then we queue it. This can * make a big difference on systems with more than one disk drive. We want * to have the interrupts off when monkeying with the request list, because - * otherwise the kernel might try and slip in a request in between somewhere. */ + * otherwise the kernel might try to slip in a request in between somewhere. */ if (!SCpnt && sr_template.nr_dev > 1){ struct request *req1; @@ -789,7 +789,7 @@ if (((long) sgpnt[count].address) + sgpnt[count].length > ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { sgpnt[count].alt_address = sgpnt[count].address; - /* We try and avoid exhausting the DMA pool, since it is easier + /* We try to avoid exhausting the DMA pool, since it is easier * to control usage here. In other places we might have a more * pressing need, and we would be screwed if we ran out */ if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) { diff -u --recursive --new-file v1.3.98/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h --- v1.3.98/linux/drivers/scsi/wd33c93.h Sat Apr 27 15:19:57 1996 +++ linux/drivers/scsi/wd33c93.h Mon May 6 12:44:31 1996 @@ -259,7 +259,7 @@ /* defines for hostdata->level2 */ /* NOTE: only the first 3 are implemented so far */ -/* (The first 8 bits are reserved for compatibility. They function +#define L2_NONE 1 /* no combination commands - we get lots of ints */ #define L2_SELECT 2 /* start with SEL_ATN_XFER, but never resume it */ #define L2_BASIC 3 /* resume after STATUS ints & RDP messages */ #define L2_DATA 4 /* resume after DATA_IN/OUT ints */ diff -u --recursive --new-file v1.3.98/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v1.3.98/linux/drivers/sound/CHANGELOG Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/CHANGELOG Mon May 6 12:26:11 1996 @@ -255,7 +255,7 @@ Since 2.1 - Preliminary support for SB16. - - The SB16 mixer is supported in it's native mode. + - The SB16 mixer is supported in its native mode. - Digitized voice capability up to 44.1 kHz/8 bit/mono (16 bit and stereo support coming in the next release). - Fixed some bugs in the digitized voice driver for PAS16. diff -u --recursive --new-file v1.3.98/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards --- v1.3.98/linux/drivers/sound/Readme.cards Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/Readme.cards Mon May 6 12:26:11 1996 @@ -893,10 +893,10 @@ Please check which version of sound driver you are using before complaining that your card is not supported. It's possible that you are using a driver version which was released months before your card was -introduced. Driver's release date is listed after it's version number +introduced. Driver's release date is listed after its version number in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h. -First of all. There is an easy way to make most soundcards to work +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 use loadlin.exe to boot Linux. If Linux is configured to use the same I/O, IRQ and DMA numbers than DOS, the card could work. diff -u --recursive --new-file v1.3.98/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v1.3.98/linux/drivers/sound/ad1848.c Wed Apr 24 17:00:41 1996 +++ linux/drivers/sound/ad1848.c Mon May 6 12:26:12 1996 @@ -1187,7 +1187,7 @@ * Check that the I/O address is in use. * * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed it's power on initialization. Just assume + * chip has performed its power-on initialization. Just assume * this has happened before the OS is starting. * * If the I/O address is unused, it typically returns 0xff. @@ -1233,7 +1233,7 @@ } /* - * The indirect register I12 has some read only bits. Lets + * The indirect register I12 has some read only bits. Let's * try to change them. */ diff -u --recursive --new-file v1.3.98/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v1.3.98/linux/drivers/sound/gus_wave.c Sat Apr 13 18:22:07 1996 +++ linux/drivers/sound/gus_wave.c Mon May 6 12:26:12 1996 @@ -359,7 +359,7 @@ gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); - /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ + /* Could writing twice fix problems with GUS_VOICE_POS() ? Let's try... */ gus_delay (); gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); @@ -3128,7 +3128,7 @@ sound_num_blocks++;; if (samples == NULL) { - printk ("GUS Error: Cant allocate memory for instrument tables\n"); + printk ("GUS Error: Can't allocate memory for instrument tables\n"); return mem_start; } diff -u --recursive --new-file v1.3.98/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v1.3.98/linux/drivers/sound/mpu401.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/mpu401.c Mon May 6 12:26:12 1996 @@ -1348,7 +1348,7 @@ /* * The MPU-401 supports just a limited set of possible timebase values. * Since the applications require more choices, the driver has to - * program the HW to do it's best and to convert between the HW and + * program the HW to do its best and to convert between the HW and * actual timebases. */ diff -u --recursive --new-file v1.3.98/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c --- v1.3.98/linux/drivers/sound/sound_switch.c Mon Mar 25 09:25:27 1996 +++ linux/drivers/sound/sound_switch.c Mon May 6 07:28:52 1996 @@ -407,8 +407,6 @@ int sound_open_sw (int dev, struct fileinfo *file) { - int retval; - DEB (printk ("sound_open_sw(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) @@ -438,25 +436,37 @@ #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: + { + int retval; + if ((retval = sequencer_open (dev, file)) < 0) return retval; break; + } #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: + { + int retval; + if ((retval = MIDIbuf_open (dev, file)) < 0) return retval; break; + } #endif #ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: + { + int retval; + if ((retval = audio_open (dev, file)) < 0) return retval; break; + } #endif default: diff -u --recursive --new-file v1.3.98/linux/fs/Config.in linux/fs/Config.in --- v1.3.98/linux/fs/Config.in Sun May 5 08:52:02 1996 +++ linux/fs/Config.in Mon May 6 12:44:31 1996 @@ -34,7 +34,10 @@ tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS -tristate 'AFFS filesystem support (read only)' CONFIG_AFFS_FS +tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS +if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then + define_bool CONFIG_AMIGA_PARTITION y +fi tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS if [ "$CONFIG_UFS_FS" != "n" ]; then bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL diff -u --recursive --new-file v1.3.98/linux/fs/affs/Makefile linux/fs/affs/Makefile --- v1.3.98/linux/fs/affs/Makefile Tue Apr 23 13:57:11 1996 +++ linux/fs/affs/Makefile Mon May 6 12:44:31 1996 @@ -1,5 +1,5 @@ # -# Makefile for the linux amiga fast filesystem routines. +# Makefile for the linux affs-filesystem routines. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := affs.o -O_OBJS := namei.o inode.o file.o dir.o amigaffs.o symlink.o +O_OBJS := namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.98/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c --- v1.3.98/linux/fs/affs/amigaffs.c Sat Apr 27 15:19:57 1996 +++ linux/fs/affs/amigaffs.c Mon May 6 14:36:05 1996 @@ -1,89 +1,57 @@ /* * linux/fs/affs/amigaffs.c * - * (C) 1996 Stefan Reinauer - Modified to compile as Module + * (c) 1996 Hans-Joachim Widmaier - Modified for larger blocks. * * (C) 1993 Ray Burr - Amiga FFS filesystem. * */ - -#include - -#include +#include +#include #include +#include +#include #include +#include -#include "amigaffs.h" +extern struct timezone sys_tz; /* * Functions for accessing Amiga-FFS structures. * */ -/* Get key entry number ENTRY_POS from the header block pointed to - by DATA. If ENTRY_POS is invalid, -1 is returned. This is - used to get entries from file and directory headers as well - as extension and root blocks. In the current FFS specs, these - tables are defined to be the same size in all of these. */ - -int affs_get_key_entry (int bsize, void *data, int entry_pos) -{ - struct dir_front *dir_front = (struct dir_front *)data; - int key, hash_table_size; - - hash_table_size = MIDBLOCK_LONGS (bsize); - key = 0; - if (entry_pos >= 0 && entry_pos < hash_table_size) - key = swap_long (dir_front->hash_table[entry_pos]); - - return key; -} - /* Find the next used hash entry at or after *HASH_POS in a directory's hash table. *HASH_POS is assigned that entry's number. DIR_DATA points to the directory header block in memory. If there are no more entries, 0 is returned. Otherwise, the key number in the next used hash slot is returned. */ -int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos) +int +affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *hash_pos) { - struct dir_front *dir_front = (struct dir_front *)dir_data; - int i, hash_table_size; + struct dir_front *dir_front = dir_data; + ULONG i; - hash_table_size = MIDBLOCK_LONGS (bsize); - if (*hash_pos < 0 || *hash_pos >= hash_table_size) - return -1; - for (i = *hash_pos; i < hash_table_size; i++) - if (dir_front->hash_table[i] != 0) + for (i = *hash_pos; i < hsize; i++) + if (dir_front->hashtable[i] != 0) break; - if (i == hash_table_size) + if (i >= hsize) return 0; *hash_pos = i; - return swap_long (dir_front->hash_table[i]); -} - -/* Get the hash_chain (next file header key in hash chain) entry from a - file header block in memory pointed to by FH_DATA. */ - -int affs_get_fh_hash_link (int bsize, void *fh_data) -{ - struct file_end *file_end; - int key; - - file_end = GET_END_PTR (struct file_end, fh_data, bsize); - key = swap_long (file_end->hash_chain); - return key; + return htonl(dir_front->hashtable[i]); } /* Set *NAME to point to the file name in a file header block in memory pointed to by FH_DATA. The length of the name is returned. */ -int affs_get_file_name (int bsize, void *fh_data, char **name) +int +affs_get_file_name(int bsize, void *fh_data, char **name) { struct file_end *file_end; - file_end = GET_END_PTR (struct file_end, fh_data, bsize); + file_end = GET_END_PTR(struct file_end, fh_data, bsize); if (file_end->file_name[0] == 0 || file_end->file_name[0] > 30) { printk ("affs_get_file_name: OOPS! bad filename\n"); @@ -96,57 +64,210 @@ return file_end->file_name[0]; } -/* Get the key number of the first extension block for the file - header pointed to by FH_DATA. */ +/* Find the predecessor in the hash chain */ -int affs_get_extension (int bsize, void *fh_data) +int +affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey) { - struct file_end *file_end; - int key; + struct buffer_head *bh = NULL; + ULONG nextkey; + LONG ptype, stype; + int retval; + + nextkey = startino->i_ino; + retval = -ENOENT; + lock_super(startino->i_sb); + while (1) { + pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n", nextkey, startoffset); + if (nextkey == 0) + break; + if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino)))) + break; + if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype) + || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR && + stype != ST_LINKFILE && stype != ST_LINKDIR && + stype != ST_ROOT && stype != ST_SOFTLINK)) { + printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n", + ptype,stype); + affs_brelse(bh); + break; + } + nextkey = htonl(((ULONG *)bh->b_data)[startoffset]); + if (nextkey == key) { + ((ULONG *)bh->b_data)[startoffset] = newkey; + affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + retval = 0; + break; + } + affs_brelse(bh); + startoffset = AFFS_I2BSIZE(startino) / 4 - 4; + } + unlock_super(startino->i_sb); - file_end = GET_END_PTR (struct file_end, fh_data, bsize); - key = swap_long (file_end->extension); - return key; + return retval; +} + +/* Remove inode from link chain */ + +int +affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey) +{ + struct buffer_head *bh = NULL; + ULONG nextkey; + ULONG offset; + LONG etype = 0; + LONG ptype, stype; + int retval; + + offset = AFFS_I2BSIZE(startino) / 4 - 10; + nextkey = startino->i_ino; + retval = -ENOENT; + lock_super(startino->i_sb); + while (1) { + if (nextkey == 0) + break; + pr_debug("AFFS: find_link_pred(): next key=%d\n", nextkey)); + if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino)))) + break; + if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype) + || ptype != T_SHORT) { + affs_brelse(bh); + break; + } + if (!etype) { + if (stype != ST_FILE && stype != ST_USERDIR) { + affs_brelse(bh); + break; + } + if (stype == ST_FILE) + etype = ST_LINKFILE; + else + etype = ST_LINKDIR; + } else if (stype != etype) { + affs_brelse(bh); + retval = -EPERM; + break; + } + nextkey = htonl(((ULONG *)bh->b_data)[offset]); + if (nextkey == key) { + FILE_END(bh->b_data,startino)->link_chain = newkey; + affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + retval = 0; + break; + } + affs_brelse(bh); + } + unlock_super(startino->i_sb); + return retval; } /* Checksum a block, do various consistency checks and optionally return the blocks type number. DATA points to the block. If their pointers are non-null, *PTYPE and *STYPE are set to the primary and secondary - block types respectively. Returns non-zero if the block is not - consistent. */ + block types respectively, *HASHSIZE is set to the size of the hashtable + (which lets us calculate the block size). + Returns non-zero if the block is not consistent. */ -int affs_checksum_block (int bsize, void *data, int *ptype, int *stype) +ULONG +affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype) { + ULONG sum; + ULONG *p; + + bsize /= 4; if (ptype) - *ptype = swap_long (((long *) data)[0]); + *ptype = htonl(((LONG *)data)[0]); if (stype) - *stype = swap_long (((long *) data)[bsize / 4 - 1]); - return 0; -} + *stype = htonl(((LONG *)data)[bsize - 1]); -static struct file_system_type affs_fs_type = { - affs_read_super, "affs", 1, NULL -}; + sum = 0; + p = data; + while (bsize--) + sum += htonl(*p++); + return sum; +} -int init_affs_fs(void) +void +affs_fix_checksum(int bsize, void *data, int cspos) { - return register_filesystem(&affs_fs_type); + ULONG ocs; + ULONG cs; + + cs = affs_checksum_block(bsize,data,NULL,NULL); + ocs = htonl (((ULONG *)data)[cspos]); + ocs -= cs; + ((ULONG *)data)[cspos] = htonl(ocs); } -#ifdef MODULE -int init_module(void) +void +secs_to_datestamp(int secs, struct DateStamp *ds) { - int status; + ULONG days; + ULONG minute; - if ((status = init_affs_fs()) == 0) - register_symtab(0); - return status; + secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60); + if (secs < 0) + secs = 0; + days = secs / 86400; + secs -= days * 86400; + minute = secs / 60; + secs -= minute * 60; + + ds->ds_Days = htonl(days); + ds->ds_Minute = htonl(minute); + ds->ds_Tick = htonl(secs * 50); } -void cleanup_module(void) +int +prot_to_mode(ULONG prot) { - unregister_filesystem(&affs_fs_type); + int mode = 0; + + if (AFFS_UMAYWRITE(prot)) + mode |= S_IWUSR; + if (AFFS_UMAYREAD(prot)) + mode |= S_IRUSR; + if (AFFS_UMAYEXECUTE(prot)) + mode |= S_IXUSR; + if (AFFS_GMAYWRITE(prot)) + mode |= S_IWGRP; + if (AFFS_GMAYREAD(prot)) + mode |= S_IRGRP; + if (AFFS_GMAYEXECUTE(prot)) + mode |= S_IXGRP; + if (AFFS_OMAYWRITE(prot)) + mode |= S_IWOTH; + if (AFFS_OMAYREAD(prot)) + mode |= S_IROTH; + if (AFFS_OMAYEXECUTE(prot)) + mode |= S_IXOTH; + + return mode; } -#endif +ULONG +mode_to_prot(int mode) +{ + ULONG prot = 0; + if (mode & S_IXUSR) + prot |= FIBF_SCRIPT; + if (mode & S_IRUSR) + prot |= FIBF_READ; + if (mode & S_IWUSR) + prot |= FIBF_WRITE | FIBF_DELETE; + if (mode & S_IRGRP) + prot |= FIBF_GRP_READ; + if (mode & S_IWGRP) + prot |= FIBF_GRP_WRITE; + if (mode & S_IROTH) + prot |= FIBF_OTR_READ; + if (mode & S_IWOTH) + prot |= FIBF_OTR_WRITE; + + return prot; +} diff -u --recursive --new-file v1.3.98/linux/fs/affs/amigaffs.h linux/fs/affs/amigaffs.h --- v1.3.98/linux/fs/affs/amigaffs.h Sat Apr 27 15:19:57 1996 +++ linux/fs/affs/amigaffs.h Thu Jan 1 02:00:00 1970 @@ -1,206 +0,0 @@ -#ifndef AMIGAFFS_H -#define AMIGAFFS_H - -/* Ugly macros to make the code pretty. */ - -#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st)))) - -#define MIDBLOCK_LONGS(sz) ((sz - sizeof (struct dir_front) \ - - sizeof (struct dir_end)) / 4) - -static __inline__ unsigned long -swap_long (unsigned long x) -{ -#ifdef __i386__ /* bad check... should be endian check */ - unsigned char *px; - - px = (unsigned char *) &x; - return ( (px[3] << 0) - | (px[2] << 8) - | (px[1] << 16) - | (px[0] << 24)); -#else - return x; -#endif -} - -typedef unsigned long ULONG; -typedef unsigned short UWORD; -typedef unsigned char UBYTE; - -typedef long LONG; -typedef short WORD; -typedef char BYTE; - -struct DateStamp -{ - ULONG ds_Days; - ULONG ds_Minute; - ULONG ds_Tick; -}; - -#define T_SHORT 2 -#define T_LIST 16 -#define T_DATA 8 - -#define ST_FILE -3 -#define ST_USERDIR 2 -#define ST_ROOT 1 -#define ST_SOFTLINK 3 -#define ST_LINKFILE -4 -#define ST_LINKDIR 4 - -#define PROT_ARCHIVE (1<<4) -#define PROT_READ (1<<3) -#define PROT_WRITE (1<<2) -#define PROT_EXECUTE (1<<1) -#define PROT_DELETE (1<<0) - -#define PROT_OTR_READ (1<<15) -#define PROT_OTR_WRITE (1<<14) -#define PROT_OTR_EXECUTE (1<<13) -#define PROT_OTR_DELETE (1<<12) - -#define PROT_GRP_READ (1<<11) -#define PROT_GRP_WRITE (1<<10) -#define PROT_GRP_EXECUTE (1<<9) -#define PROT_GRP_DELETE (1<<8) - -struct ffs_root_front -{ - LONG primary_type; - ULONG spare1[2]; - ULONG hash_size; - ULONG spare2; - ULONG checksum; -}; - -struct ffs_root_end -{ - LONG bm_flag; - ULONG bm_keys[25]; - ULONG bm_extend; - struct DateStamp dir_altered; - UBYTE disk_name[40]; - struct DateStamp disk_altered; - struct DateStamp disk_made; - ULONG spare1[3]; - LONG secondary_type; -}; - -struct dir_front -{ - LONG primary_type; - ULONG own_key; - ULONG spare1[3]; - ULONG checksum; - ULONG hash_table[0]; -}; - -struct dir_end -{ - ULONG spare1; - UWORD uid; - UWORD gid; - ULONG protect; - ULONG spare2; - UBYTE comment[92]; - struct DateStamp created; - UBYTE dir_name[64]; - ULONG hash_chain; - ULONG parent; - ULONG spare3; - LONG secondary_type; -}; - -struct file_front -{ - LONG primary_type; - ULONG own_key; - ULONG block_count; - ULONG unknown1; - ULONG first_data; - ULONG checksum; - ULONG blocks[0]; -}; - -struct file_end -{ - ULONG spare1; - UWORD uid; - UWORD gid; - ULONG protect; - ULONG byte_size; - UBYTE comment[92]; - struct DateStamp created; - UBYTE file_name[64]; - ULONG hash_chain; - ULONG parent; - ULONG extension; - LONG secondary_type; -}; - -struct data_front -{ - LONG primary_type; - ULONG header; - ULONG seq_num; - ULONG data_size; - ULONG next_data; - ULONG checksum; -}; - -struct symlink_front -{ - LONG primary_type; - ULONG own_key; - LONG unused[3]; - ULONG checksum; - UBYTE symname[0]; -}; - -struct symlink_end -{ - ULONG spare1; - UWORD uid; - UWORD gid; - ULONG protect; - ULONG spare2; - UBYTE comment[92]; - struct DateStamp created; - UBYTE link_name[64]; - ULONG hash_chain; - ULONG parent; - ULONG spare3; - LONG secondary_type; -}; - -struct hardlink_front -{ - LONG primary_type; - ULONG own_key; - LONG unused[3]; - ULONG checksum; -}; - -struct hardlink_end -{ - ULONG spare1; - UWORD uid; - UWORD gid; - ULONG protect; - ULONG spare2; - UBYTE comment[92]; - struct DateStamp created; - UBYTE link_name[32]; - ULONG spare3; - ULONG original; - ULONG link_chain; - ULONG spare4[5]; - ULONG hash_chain; - ULONG parent; - ULONG spare5; - LONG secondary_type; -}; - -#endif diff -u --recursive --new-file v1.3.98/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c --- v1.3.98/linux/fs/affs/bitmap.c Thu Jan 1 02:00:00 1970 +++ linux/fs/affs/bitmap.c Mon May 6 14:36:05 1996 @@ -0,0 +1,332 @@ +/* + * linux/fs/affs/bitmap.c + * + * (c) 1996 Hans-Joachim Widmaier + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; + +int +affs_count_free_bits(int blocksize, const UBYTE *data) +{ + int free; + int i; + + free = 0; + for (i = 0; i < blocksize; i++) { + free += nibblemap[data[i] & 0xF] + nibblemap[(data[i]>>4) & 0xF]; + } + + return free; +} + +int +affs_count_free_blocks(struct super_block *s) +{ + int free; + int i; + + pr_debug("AFFS: count_free_blocks()\n"); + + free = 0; + if (s->u.affs_sb.s_flags & SF_BM_VALID) { + for (i = 0; i < s->u.affs_sb.s_bm_count; i++) { + free += s->u.affs_sb.s_bitmap[i].bm_free; + } + } + return free; +} + +void +affs_free_block(struct super_block *sb, LONG block) +{ + int bmap; + int bit; + ULONG blk; + struct affs_bm_info *bm; + + pr_debug("AFFS: free_block(%d)\n",block); + + blk = block - sb->u.affs_sb.s_reserved; + bmap = blk / (sb->s_blocksize * 8 - 32); + bit = blk % (sb->s_blocksize * 8 - 32); + bm = &sb->u.affs_sb.s_bitmap[bmap]; + if (bmap >= sb->u.affs_sb.s_bm_count || bit >= bm->bm_size) { + printk("AFFS: free_block(): block %d outside partition.\n",block); + return; + } + blk = 0; + set_bit(bit & 31,&blk); + + lock_super(sb); + if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4)) + printk("AFFS: free_block(): block %d is already free.\n",block); + else { + bm->bm_free++; + ((ULONG *)bm->bm_bh->b_data)[0] = ntohl(htonl(((ULONG *)bm->bm_bh->b_data)[0]) - blk); + mark_buffer_dirty(bm->bm_bh,1); + sb->s_dirt = 1; + } + unlock_super(sb); +} + +static ULONG +affs_balloc(struct inode *inode, int zone_no) +{ + ULONG w; + ULONG *bm; + int fb; + int i; + int fwb; + ULONG block; + struct affs_zone *zone; + struct super_block *sb; + + sb = inode->i_sb; + zone = &sb->u.affs_sb.s_zones[zone_no]; + + if (!zone || !zone->z_bm || !zone->z_bm->bm_bh) + return 0; + + pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no); + + bm = (ULONG *)zone->z_bm->bm_bh->b_data; +repeat: + fb = (zone->z_bm->bm_size + 31) >> 5; + for (i = zone->z_start; i <= fb; i++) { + if (bm[i]) + goto found; + } + return 0; + +found: + fwb = zone->z_bm->bm_firstblk + (i - 1) * 32; + lock_super(sb); + zone->z_start = i; + w = htonl(bm[i]); + fb = find_first_one_bit(&w,32); + if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) { + unlock_super(sb); + printk("AFFS: balloc(): empty block disappeared somehow\n"); + goto repeat; + } + block = fwb + fb; + zone->z_bm->bm_free--; + + /* prealloc as much as possible within this word, but not for headers */ + + if (zone_no) { + while (inode->u.affs_i.i_pa_cnt < MAX_PREALLOC && ++fb < 32) { + fb = find_next_one_bit(&w,32,fb); + if (fb > 31) + break; + if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) { + printk("AFFS: balloc(): empty block disappeared\n"); + break; + } + inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb; + inode->u.affs_i.i_pa_last &= MAX_PREALLOC - 1; + inode->u.affs_i.i_pa_cnt++; + zone->z_bm->bm_free--; + } + } + w -= htonl(bm[i]); + bm[0] = ntohl(htonl(bm[0]) + w); + unlock_super(sb); + mark_buffer_dirty(zone->z_bm->bm_bh,1); + + return block; +} + +static void +affs_find_new_zone(struct super_block *sb,struct affs_zone *z, int minfree, int start) +{ + struct affs_bm_info *bm; + int offs; + int zone; + int free; + int len; + + pr_debug("AFFS: find_new_zone()\n"); + + lock_super(sb); + + zone = start; + z->z_bm = NULL; + while (1) { + if (zone >= sb->u.affs_sb.s_num_zones) { + zone = 0; + continue; + } + + if (!set_bit(zone,sb->u.affs_sb.s_zonemap)) { + bm = &sb->u.affs_sb.s_bitmap[zone >> (sb->s_blocksize_bits - 8)]; + offs = zone * 256 & (sb->s_blocksize - 1); + len = bm->bm_size / 8 - offs; + if (len > 256) + len = 256; + offs += 4; + free = affs_count_free_bits(len,(char *)bm->bm_bh->b_data + offs); + if (free && (100 * free) / (len * 8) > minfree) { + z->z_bm = bm; + z->z_start = offs / 4; + z->z_ino = 0; + z->z_zone_no = zone; + pr_debug(" ++ found zone (%d) in bh %d at offset %d with %d free blocks\n", + zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free); + break; + } + clear_bit(zone,sb->u.affs_sb.s_zonemap); + } + + /* Skip to next possible zone */ + + pr_debug(" ++ Skipping to next zone\n"); + if (++zone == start) + break; + } + unlock_super(sb); + return; +} + +LONG +affs_new_header(struct inode *inode) +{ + struct affs_zone *zone; + LONG block; + struct super_block *sb; + struct buffer_head *bh; + + sb = inode->i_sb; + zone = &sb->u.affs_sb.s_zones[0]; + + /* We try up to 3 times to find a free block: + * If there is no more room in the current header zone, + * we try to get a new one and allocate the block there. + * If there is no zone with at least AFFS_HDR_MIN_FREE + * percent of free blocks, we try to find a zone with + * at least one free block. + */ + + if (!(block = affs_balloc(inode,0))) { + clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap); + affs_find_new_zone(sb,zone,AFFS_HDR_MIN_FREE,(sb->u.affs_sb.s_num_zones + 1) / 2); + if (!(block = affs_balloc(inode,0))) { + clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap); + affs_find_new_zone(sb,zone,0,(sb->u.affs_sb.s_num_zones + 1) / 2); + if (!(block = affs_balloc(inode,0))) + return 0; + } + } + if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { + printk("AFFS: balloc(): cannot read block %d\n",block); + return 0; + } + memset(bh->b_data,0,sb->s_blocksize); + mark_buffer_uptodate(bh,1); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + + return block; +} + +LONG +affs_new_data(struct inode *inode) +{ + int empty, old; + unsigned long oldest; + struct affs_zone *zone; + struct super_block *sb; + struct buffer_head *bh; + int i = 0; + LONG block; + + pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino); + + sb = inode->i_sb; + lock_super(sb); + if (inode->u.affs_i.i_pa_cnt) { + inode->u.affs_i.i_pa_cnt--; + unlock_super(sb); + block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]; + inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1; + goto init_block; + } + unlock_super(sb); +repeat: + oldest = jiffies; + old = 0; + empty = 0; + zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone]; + if (zone->z_ino == inode->i_ino) { + i = inode->u.affs_i.i_zone; + goto found; + } + for (i = 1; i < MAX_ZONES; i++) { + zone = &sb->u.affs_sb.s_zones[i]; + if (!empty && zone->z_bm && !zone->z_ino) + empty = i; + if (zone->z_bm && zone->z_lru_time < oldest) { + old = i; + oldest = zone->z_lru_time; + } + } + if (empty) + i = empty; + else if (old) + i = old; + else + return affs_new_header(inode); + + inode->u.affs_i.i_zone = i; + zone->z_ino = inode->i_ino; + +found: + zone = &sb->u.affs_sb.s_zones[i]; + if (!(block = affs_balloc(inode,i))) { /* Zone is full */ + clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap); + affs_find_new_zone(sb,zone,AFFS_DATA_MIN_FREE,sb->u.affs_sb.s_nextzone); + sb->u.affs_sb.s_nextzone = zone->z_zone_no + 1; + goto repeat; + } + +init_block: + if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { + printk("AFFS: balloc(): cannot read block %u\n",block); + return 0; + } + memset(bh->b_data,0,sb->s_blocksize); + mark_buffer_uptodate(bh,1); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + + return block; +} + +void +affs_make_zones(struct super_block *sb) +{ + int i, j; + + pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_zones); + + j = (sb->u.affs_sb.s_num_zones + 1) / 2; + + affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[0],AFFS_HDR_MIN_FREE,j); + for (i = 1; i < MAX_ZONES; i++) { + affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[i],AFFS_DATA_MIN_FREE,j); + j = sb->u.affs_sb.s_zones[i].z_zone_no + 1; + } +} diff -u --recursive --new-file v1.3.98/linux/fs/affs/dir.c linux/fs/affs/dir.c --- v1.3.98/linux/fs/affs/dir.c Tue Apr 23 13:57:11 1996 +++ linux/fs/affs/dir.c Mon May 6 14:36:24 1996 @@ -1,6 +1,8 @@ /* * linux/fs/affs/dir.c * + * (c) 1996 Hans-Joachim Widmaier - Modifications for larger blocks + * and hard links. * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. @@ -8,25 +10,25 @@ * (C) 1991 Linus Torvalds - minix filesystem * * affs directory handling functions + * */ -#include - #include - +#include #include -#include #include #include #include #include -#include +#include +#include static int affs_readdir(struct inode *, struct file *, void *, filldir_t); +static int affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count); -struct file_operations affs_dir_operations = { +static struct file_operations affs_dir_operations = { NULL, /* lseek - default */ - NULL, /* read */ + affs_dir_read, /* read */ NULL, /* write - bad */ affs_readdir, /* readdir */ NULL, /* select - default */ @@ -34,7 +36,7 @@ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ - NULL /* fsync */ + file_fsync /* default fsync */ }; /* @@ -42,109 +44,153 @@ */ struct inode_operations affs_dir_inode_operations = { &affs_dir_operations, /* default directory file-ops */ - NULL, /* create */ + affs_create, /* create */ affs_lookup, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ + affs_link, /* link */ + affs_unlink, /* unlink */ + affs_symlink, /* symlink */ + affs_mkdir, /* mkdir */ + affs_rmdir, /* rmdir */ NULL, /* mknod */ - NULL, /* rename */ + affs_rename, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ + affs_dir_truncate, /* truncate */ + NULL /* permissions */ }; -/* This is used to speed up lookup. Without this we would need to -make a linear search of the directory to find the file that the -directory read just returned. This is a single element cache. */ - -/* struct lookup_cache cache = {0,}; */ +static int +affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + return -EISDIR; +} -static int affs_readdir(struct inode * inode, struct file * filp, - void * dirent, filldir_t filldir) +static int +affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir) { - int i, j, chain_pos, hash_pos, reclen, ino; + int j, namelen; + LONG i; + ULONG hash_pos; + ULONG chain_pos; + unsigned long ino; + unsigned long old; + int stored; char *name; struct buffer_head *dir_bh; struct buffer_head *fh_bh; - void *dir_data; - void *fh_data; + struct inode *dir; -#ifdef DEBUG - printk ("AFFS: readdir: inode=%d f_pos=%d\n", - inode->i_ino, filp->f_pos); -#endif + pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos); + if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; - while ((unsigned long)filp->f_pos < 2) { - if (filp->f_pos == 0) { - if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) - return 0; - } else { - i = affs_parent_ino (inode); - if (filldir (dirent, "..", 2, filp->f_pos, i) < 0) - return 0; + stored = 0; + dir_bh = NULL; + fh_bh = NULL; + dir = NULL; + old = filp->f_pos & 0x80000000; + filp->f_pos &= 0x7FFFFFFF; + + if (filp->f_pos == 0) { + filp->private_data = (void *)0; + if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) { + return 0; } - filp->f_pos++; + ++filp->f_pos; + stored++; } - /* No caching here. I've got 16 megs why should I care? :-) */ - chain_pos = (filp->f_pos - 2) & 0xffff; - if (chain_pos == 0xffff) - return 0; - hash_pos = (filp->f_pos - 2) >> 16; -#ifdef DEBUG - printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos); -#endif - if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data))) - return 0; - /* HASH_POS should already be on a used entry unless it is - the first read of the directory. Will this break the - dirtell thing somehow? */ - i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data, - &hash_pos); - j = chain_pos; - for (;;) { - if (i <= 0) { -#ifdef DEBUG - printk ("AFFS: bad f_pos in readdir\n"); -#endif - brelse (dir_bh); - return 0; + if (filp->f_pos == 1) { + if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) { + filp->f_pos |= 0x80000000; + return stored; } - ino = i; - if (!(fh_bh = affs_pread (inode, i, &fh_data))) { - brelse (dir_bh); - return 0; + filp->f_pos = 2; + stored++; + } + + /* Read original if this is a link */ + ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; + if (!(dir = iget(inode->i_sb,ino))) + return stored; + + chain_pos = (filp->f_pos - 2) & 0xffff; + hash_pos = (filp->f_pos - 2) >> 16; + if (chain_pos == 0xffff) { + printk("AFFS: more than 65535 entries in chain\n"); + chain_pos = 0; + hash_pos++; + filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; + } + if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode)))) + goto readdir_done; + + while (!stored || !old) { + while (hash_pos < AFFS_I2HSIZE(inode) && + !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]) + hash_pos++; + if (hash_pos >= AFFS_I2HSIZE(inode)) + goto readdir_done; + + i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]); + j = chain_pos; + /* If the directory hasn't changed since the last call to readdir(), + * we can jump directly to where we left off. + */ + if (filp->private_data && filp->f_version == dir->i_version) { + i = (ULONG)filp->private_data; + j = 0; + pd_debug("AFFS: readdir() left off=%lu\n",i); } - i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data); - if (j == 0) { - j = 1; - if (i <= 0) { - hash_pos++; - i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), - dir_data, &hash_pos); - if (i <= 0) - chain_pos = 0xffff; - else - chain_pos = 0; - } else - chain_pos++; - reclen = affs_get_file_name (AFFS_I2BSIZE (inode), - fh_data, &name); - if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) { - brelse (fh_bh); - brelse (dir_bh); - return 0; + filp->f_version = dir->i_version; + pd_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos); + while (i) { + if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) { + printk("AFFS: readdir: Can't get block %d\n",i); + goto readdir_done; } - filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; + ino = i; + i = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain); + if (j == 0) + break; + affs_brelse(fh_bh); + fh_bh = NULL; + j--; + } + if (fh_bh) { + namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name); + pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i); + filp->private_data = (void *)ino; + if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0) + goto readdir_done; + filp->private_data = (void *)i; + affs_brelse(fh_bh); + fh_bh = NULL; + stored++; } - brelse (fh_bh); - j--; + if (i == 0) { + hash_pos++; + chain_pos = 0; + } else + chain_pos++; + filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; } + +readdir_done: + filp->f_pos |= old; + affs_brelse(dir_bh); + affs_brelse(fh_bh); + iput(dir); + pr_debug("AFFS: readdir()=%d\n",stored); + return stored; +} + +void +affs_dir_truncate(struct inode *inode) +{ + printk("AFFS: dir_truncate()\n"); } diff -u --recursive --new-file v1.3.98/linux/fs/affs/file.c linux/fs/affs/file.c --- v1.3.98/linux/fs/affs/file.c Sat Apr 27 15:19:57 1996 +++ linux/fs/affs/file.c Mon May 6 14:36:24 1996 @@ -1,6 +1,8 @@ /* * linux/fs/affs/file.c * + * (c) 1996 Hans-Joachim Widmaier - Rewritten + * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. @@ -12,7 +14,6 @@ #include #include - #include #include #include @@ -20,36 +21,31 @@ #include #include #include - #include - -#define NBUF 16 +#include +#include +#include +#include #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -#include -#include - -#include "amigaffs.h" - -int affs_file_read(struct inode *, struct file *, char *, int); +static int affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count); +static int affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count); +static int affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count); +static void affs_release_file(struct inode *inode, struct file *filp); -/* - * We have mostly NULL's here: the current defaults are ok for - * the affs filesystem. - */ -struct file_operations affs_file_operations = { +static struct file_operations affs_file_operations = { NULL, /* lseek - default */ - affs_file_read, /* read */ - NULL, /* write */ + generic_file_read, /* read */ + affs_file_write, /* write */ NULL, /* readdir - bad */ NULL, /* select - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ - NULL, /* release */ - NULL /* can't fsync */ + affs_release_file, /* release */ + file_fsync /* brute force, but works */ }; struct inode_operations affs_file_inode_operations = { @@ -65,75 +61,229 @@ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ - NULL /* affs_bmap */, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ + generic_readpage, /* readpage */ + NULL, /* writepage */ + affs_bmap, /* bmap */ + affs_truncate, /* truncate */ + NULL, /* permission */ + NULL /* smap */ }; -static int affs_smap(struct inode *inode, int block) -{ - struct buffer_head *bh; - int key; - void *fh_data; +static struct file_operations affs_file_operations_ofs = { + NULL, /* lseek - default */ + affs_file_read_ofs, /* read */ + affs_file_write_ofs, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* brute force, but works */ +}; -/* FIXME */ -#define KEY_SLOTS_PER_BLOCK 72 +struct inode_operations affs_file_inode_operations_ofs = { + &affs_file_operations_ofs, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + affs_truncate_ofs, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + +int +affs_bmap(struct inode *inode, LONG block) +{ + struct buffer_head *bh; + LONG ext, key; + LONG ptype, stype; -#ifdef DEBUG - printk ("affs_smap: ino=%d block=%d\n", inode->i_ino, block); -#endif + pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block); if (block < 0) { - printk("affs_smap: block < 0"); + printk("affs_bmap: block < 0\n"); return 0; } - key = inode->i_ino; + /* If this is a hard link, quietly exchange the inode with the original */ + + key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; + + ext = block / AFFS_I2HSIZE(inode); + if (ext) { + if (ext > inode->u.affs_i.i_max_ext) + ext = inode->u.affs_i.i_max_ext; + if (ext) + key = inode->u.affs_i.i_ext[ext - 1]; + block -= ext * AFFS_I2HSIZE(inode); + } + for (;;) { - bh = affs_pread (inode, key, &fh_data); + bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); if (!bh) return 0; - if (block < KEY_SLOTS_PER_BLOCK) + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || + (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE) { + affs_brelse(bh); + return 0; + } + if (block < AFFS_I2HSIZE(inode)) break; - block -= KEY_SLOTS_PER_BLOCK; - key = affs_get_extension (AFFS_I2BSIZE (inode), fh_data); -#ifdef DEBUG - printk ("affs_smap: reading extension block %d\n", key); -#endif - brelse (bh); - } - key = affs_get_key_entry (AFFS_I2BSIZE (inode), fh_data, - (KEY_SLOTS_PER_BLOCK - 1) - block); - brelse (bh); - -#ifdef DEBUG - printk ("affs_smap: key=%d\n", key); -#endif + block -= AFFS_I2HSIZE(inode); + key = htonl(FILE_END(bh->b_data,inode)->extension); + affs_brelse(bh); + if (ext < EXT_CACHE_SIZE - 1) { + inode->u.affs_i.i_ext[ext] = key; + inode->u.affs_i.i_max_ext = ++ext; + } + } + key = AFFS_GET_HASHENTRY(bh->b_data,(AFFS_I2HSIZE(inode) - 1) - block); + affs_brelse(bh); return key; } -/* - * affs_file_read() is also needed by the directory read-routine, - * so it's not static. NOTE! reading directories directly is a bad idea, - * but has to be supported for now for compatibility reasons with older - * versions. +struct buffer_head * +affs_getblock(struct inode *inode, LONG block) +{ + struct buffer_head *bh; + struct buffer_head *ebh; + LONG key; + LONG ext; + LONG cnt, j, pt; + + pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block); + + if (block < 0) + return NULL; + key = inode->i_ino; + pt = T_SHORT; + + ext = block / AFFS_I2HSIZE(inode); + if (ext) { + if (ext > inode->u.affs_i.i_max_ext) + ext = inode->u.affs_i.i_max_ext; + if (ext) { + key = inode->u.affs_i.i_ext[ext - 1]; + block -= ext * AFFS_I2HSIZE(inode); + pt = T_LIST; + } + } + + for (;;) { + bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); + if (!bh) + return NULL; + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) || + cnt != pt || j != ST_FILE) { + printk("AFFS: getblock(): inode %d is not a valid %s\n",key, + pt == T_SHORT ? "file header" : "extension block"); + affs_brelse(bh); + return NULL; + } + j = htonl(((struct file_front *)bh->b_data)->block_count); + while (j < AFFS_I2HSIZE(inode) && j <= block) { + key = affs_new_data(inode); + if (!key) + break; + lock_super(inode->i_sb); + if (AFFS_BLOCK(bh->b_data,inode,j)) { + unlock_super(inode->i_sb); + printk("AFFS: getblock(): block already allocated\n"); + affs_free_block(inode->i_sb,key); + j++; + continue; + } + unlock_super(inode->i_sb); + AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key); + j++; + } + if (pt == T_SHORT) + ((struct file_front *)bh->b_data)->first_data = + AFFS_BLOCK(bh->b_data,inode,0); + ((struct file_front *)bh->b_data)->block_count = ntohl(j); + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + + if (block < j) + break; + if (j < AFFS_I2HSIZE(inode)) { + affs_brelse(bh); + return NULL; + } + + block -= AFFS_I2HSIZE(inode); + key = htonl(FILE_END(bh->b_data,inode)->extension); + if (!key) { + key = affs_new_header(inode); + if (!key) { + affs_brelse(bh); + return NULL; + } + ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); + if (!ebh) { + affs_free_block(inode->i_sb,key); + return NULL; + } + ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST); + ((struct file_front *)ebh->b_data)->own_key = ntohl(key); + FILE_END(ebh->b_data,inode)->secondary_type = ntohl(ST_FILE); + FILE_END(ebh->b_data,inode)->parent = ntohl(inode->i_ino); + affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); + FILE_END(bh->b_data,inode)->extension = ntohl(key); + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + bh = ebh; + } + affs_brelse(bh); + pt = T_LIST; + if (ext < EXT_CACHE_SIZE - 1) { + inode->u.affs_i.i_ext[ext] = key; + inode->u.affs_i.i_max_ext = ++ext; + } + } + key = htonl(AFFS_BLOCK(bh->b_data,inode,block)); + affs_brelse(bh); + if (!key) + return NULL; + + return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); +} + +/* This could be made static, regardless of what the former comment said. + * You cannot directly read affs directories. */ -int affs_file_read(struct inode * inode, struct file * filp, - char * buf, int count) + +static int +affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count) { char *start; int left, offset, size, sector; + int blocksize; struct buffer_head *bh; void *data; + pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count); + if (!inode) { printk("affs_file_read: inode = NULL\n"); return -EINVAL; } + blocksize = AFFS_I2BSIZE(inode) - 24; if (!(S_ISREG(inode->i_mode))) { -#ifdef DEBUG - printk("affs_file_read: mode = %07o\n",inode->i_mode); -#endif + pr_debug("affs_file_read: mode = %07o\n",inode->i_mode); return -EINVAL; } if (filp->f_pos >= inode->i_size || count <= 0) @@ -141,34 +291,296 @@ start = buf; for (;;) { - left = MIN (inode->i_size - filp->f_pos, - count - (buf - start)); + left = MIN (inode->i_size - filp->f_pos,count - (buf - start)); if (!left) break; - sector = affs_smap (inode, filp->f_pos >> AFFS_BLOCK_BITS); + sector = affs_bmap(inode,(ULONG)filp->f_pos / blocksize); if (!sector) break; - offset = filp->f_pos & (AFFS_BLOCK_SIZE - 1); - bh = affs_pread (inode, sector, &data); + offset = (ULONG)filp->f_pos % blocksize; + bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode)); if (!bh) break; - size = MIN (AFFS_BLOCK_SIZE - offset, left); + data = bh->b_data + 24; + size = MIN(blocksize - offset,left); filp->f_pos += size; - memcpy_tofs (buf, data + offset, size); + memcpy_tofs(buf,data + offset,size); buf += size; - brelse (bh); + affs_brelse(bh); } if (start == buf) return -EIO; return buf - start; +} -#if 0 - if (filp->f_pos == 0 && count > 0) { - put_fs_byte ('X', buf++); - filp->f_pos++; - return 1; +static int +affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count) +{ + off_t pos; + int written; + int c; + int blocksize; + struct buffer_head *bh; + struct inode *ino; + char *p; + + pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, + (unsigned long)filp->f_pos,count); + + ino = NULL; + if (!inode) { + printk("AFFS: file_write(): inode=NULL\n"); + return -EINVAL; + } + if (inode->u.affs_i.i_original) { + ino = iget(inode->i_sb,inode->u.affs_i.i_original); + if (!ino) { + printk("AFFS: could not follow link from inode %lu to %d\n", + inode->i_ino,inode->u.affs_i.i_original); + return -EINVAL; + } + inode = ino; + } + if (!S_ISREG(inode->i_mode)) { + printk("AFFS: file_write(): mode=%07o\n",inode->i_mode); + iput(inode); + return -EINVAL; + } + if (filp->f_flags & O_APPEND) { + pos = inode->i_size; + } else + pos = filp->f_pos; + written = 0; + blocksize = AFFS_I2BSIZE(inode); + + while (written < count) { + bh = affs_getblock(inode,pos / blocksize); + if (!bh) { + if (!written) + written = -ENOSPC; + break; + } + c = blocksize - (pos % blocksize); + if (c > count - written) + c = count - written; + if (c != blocksize && !buffer_uptodate(bh)) { + ll_rw_block(READ,1,&bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + affs_brelse(bh); + if (!written) + written = -EIO; + break; + } + } + p = (pos % blocksize) + bh->b_data; + memcpy_fromfs(p,buf,c); + update_vm_cache(inode,pos,p,c); + mark_buffer_uptodate(bh,1); + mark_buffer_dirty(bh,0); + affs_brelse(bh); + pos += c; + written += c; + buf += c; + } + if (pos > inode->i_size) + inode->i_size = pos; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + iput(ino); + return written; +} + +static int +affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count) +{ + pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, + (unsigned long)filp->f_pos,count); + + return -ENOSPC; +} + +void +affs_truncate(struct inode *inode) +{ + struct buffer_head *bh; + struct inode *ino; + LONG first; + LONG block; + LONG key; + LONG *keyp; + LONG ekey; + LONG ptype, stype; + int freethis; + int ext; + + pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); + + ino = NULL; + if (inode->u.affs_i.i_original) { + ino = iget(inode->i_sb,inode->u.affs_i.i_original); + if (!ino) { + printk("AFFS: truncate(): cannot follow link from %lu to %u\n", + inode->i_ino,inode->u.affs_i.i_original); + return; + } + inode = ino; + } + first = (inode->i_size + AFFS_I2BSIZE(inode) - 1) / AFFS_I2BSIZE(inode); + ekey = inode->i_ino; + ext = 0; + + while (ekey) { + if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) { + printk("AFFS: truncate(): Can't read block %d\n",ekey); + break; + } + ptype = htonl(((struct file_front *)bh->b_data)->primary_type); + stype = htonl(FILE_END(bh->b_data,inode)->secondary_type); + if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE && + LINK_END(bh->b_data,inode)->original == 0) { + pr_debug("AFFS: truncate(): dumping link\n"); + affs_brelse(bh); + break; + } + if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) { + printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n", + ptype,stype); + affs_brelse(bh); + break; + } + /* Do not throw away file header */ + freethis = first == 0 && ekey != inode->i_ino; + for ( block = first; block < AFFS_I2HSIZE(inode); block++) { + keyp = &AFFS_BLOCK(bh->b_data,inode,block); + key = htonl(*keyp); + if (key) { + *keyp = 0; + affs_free_block(inode->i_sb,key); + } else { + block = AFFS_I2HSIZE(inode); + break; + } + } + keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension; + key = htonl(*keyp); + if (first <= AFFS_I2HSIZE(inode)) { + ((struct file_front *)bh->b_data)->block_count = htonl(first); + first = 0; + *keyp = 0; + } else { + first -= AFFS_I2HSIZE(inode); + } + if (freethis) { /* Don't bother fixing checksum */ + affs_brelse(bh); + affs_free_block(inode->i_sb,ekey); + } else { + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + } + ekey = key; + } + inode->u.affs_i.i_max_ext = 0; /* invalidate cache */ + iput(ino); +} + +void +affs_truncate_ofs(struct inode *inode) +{ + struct buffer_head *bh; + struct inode *ino; + LONG first; + LONG block; + LONG key; + LONG *keyp; + LONG ekey; + LONG ptype, stype; + int freethis; + int blocksize; + + pr_debug("AFFS: file_truncate_ofs(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); + + ino = NULL; + if (inode->u.affs_i.i_original) { + ino = iget(inode->i_sb,inode->u.affs_i.i_original); + if (!ino) { + printk("AFFS: truncate(): cannot follow link from %lu to %u\n", + inode->i_ino,inode->u.affs_i.i_original); + return; + } + inode = ino; + } + blocksize = AFFS_I2BSIZE(inode) - 24; + first = (inode->i_size + blocksize - 1) / blocksize; + ekey = inode->i_ino; + + while (ekey) { + if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) { + printk("AFFS: truncate(): Can't read block %d\n",ekey); + break; + } + ptype = htonl(((struct file_front *)bh->b_data)->primary_type); + stype = htonl(FILE_END(bh->b_data,inode)->secondary_type); + if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE && + LINK_END(bh->b_data,inode)->original == 0) { + pr_debug("AFFS: truncate(): dumping link\n"); + affs_brelse(bh); + break; + } + if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) { + printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n", + ptype,stype); + affs_brelse(bh); + break; + } + /* Do not throw away file header */ + freethis = first == 0 && ekey != inode->i_ino; + for ( block = first; block < AFFS_I2HSIZE(inode); block++) { + keyp = &((struct file_front *)bh->b_data)-> + blocks[AFFS_I2HSIZE(inode) - 1 - block]; + key = htonl(*keyp); + if (key) { + *keyp = 0; + affs_free_block(inode->i_sb,key); + } else { + block = AFFS_I2HSIZE(inode); + break; + } + } + keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension; + key = htonl(*keyp); + if (first <= AFFS_I2HSIZE(inode)) { + ((struct file_front *)bh->b_data)->block_count = htonl(first); + first = 0; + *keyp = 0; + } else { + first -= AFFS_I2HSIZE(inode); + } + if (freethis) { /* Don't bother fixing checksum */ + affs_brelse(bh); + affs_free_block(inode->i_sb,ekey); + } else { + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + } + ekey = key; + } + inode->u.affs_i.i_max_ext = 0; /* invalidate cache */ + iput(ino); +} + +static void +affs_release_file(struct inode *inode, struct file *filp) +{ + if (filp->f_mode & 2) { /* Free preallocated blocks */ + while (inode->u.affs_i.i_pa_cnt) { + affs_free_block(inode->i_sb, + inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]); + inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1; + inode->u.affs_i.i_pa_cnt--; + } } - else - return 0; -#endif } diff -u --recursive --new-file v1.3.98/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v1.3.98/linux/fs/affs/inode.c Sat Apr 27 15:19:57 1996 +++ linux/fs/affs/inode.c Mon May 6 14:36:24 1996 @@ -1,15 +1,19 @@ /* * linux/fs/affs/inode.c * - * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem + * (c) 1996 Hans-Joachim Widmaier - Modified for larger blocks. * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. - * + * * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. * * (C) 1991 Linus Torvalds - minix filesystem */ +#include +#include +#include +#include #include #include #include @@ -17,50 +21,80 @@ #include #include #include - -#include -#include #include - #include +#include +#include +#include +#include -#include "amigaffs.h" - -extern int check_cdrom_media_change(int, int); - -#ifdef LEAK_CHECK -static int check_malloc = 0; -static int check_bread = 0; -#endif +extern int *blk_size[]; +extern struct timezone sys_tz; void affs_put_super(struct super_block *sb) { - lock_super(sb); + int i; + + pr_debug("affs_put_super()\n"); -#ifdef LEAK_CHECK - printk("Outstanding mallocs:%d, outstanding buffers: %d\n", - check_malloc, check_bread); -#endif + lock_super(sb); + if (!(sb->s_flags & MS_RDONLY)) { + for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) + affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); + ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); + secs_to_datestamp(CURRENT_TIME, + &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); + affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + } + if (sb->u.affs_sb.s_flags & SF_PREFIX) + kfree(sb->u.affs_sb.s_prefix); + kfree(sb->u.affs_sb.s_bitmap); + affs_brelse(sb->u.affs_sb.s_root_bh); + set_blocksize(sb->s_dev,BLOCK_SIZE); sb->s_dev = 0; unlock_super(sb); + MOD_DEC_USE_COUNT; return; } -static struct super_operations affs_sops = { +static void affs_write_super(struct super_block *sb) +{ + int i, clean = 2; + + if (!(sb->s_flags & MS_RDONLY)) { + for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) { + if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) { + clean = 0; + break; + } + } + ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean); + secs_to_datestamp(CURRENT_TIME, + &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); + affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + sb->s_dirt = !clean; /* redo until bitmap synced */ + } else + sb->s_dirt = 0; + + pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean); +} + +static struct super_operations affs_sops = { affs_read_inode, - NULL, /* notify_change */ - NULL, /* write_inode */ - NULL, /* put_inode */ + affs_notify_change, + affs_write_inode, + affs_put_inode, affs_put_super, - NULL, /* write_super */ + affs_write_super, affs_statfs, NULL /* remount */ }; int affs_parent_ino(struct inode *dir) { - int root_ino = (dir->i_sb->u.affs_sb.s_root_block - - dir->i_sb->u.affs_sb.s_partition_offset); + int root_ino = (dir->i_sb->u.affs_sb.s_root_block); if (!S_ISDIR (dir->i_mode)) { printk ("affs_parent_ino: argument is not a directory\n"); @@ -71,361 +105,854 @@ return dir->u.affs_i.i_parent; } -static int parse_options(char *options, struct affs_options *optp) + +static int +parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, + int *reserved, int *root, int *blocksize, char **prefix, + char *volume, unsigned long *mount_opts) { - char *this_opt,*value,*end; - int n; + char *this_char, *value; + int f; - optp->offset = 0; - optp->size = 0; - optp->root = 0; - optp->conv_links = 0; + /* Fill in defaults */ + *uid = 0; + *gid = 0; + *reserved = 2; + *root = -1; + *blocksize = -1; + *prefix = "/"; + volume[0] = ':'; + volume[1] = 0; + *mount_opts = 0; if (!options) return 1; - for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) { - if ((value = strchr(this_opt,'='))) *value++ = 0; - - if (!strcmp(this_opt,"offset") && value) { - n = simple_strtoul (value, &end, 10); - if (end == value || *end != 0) + for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { + f = 0; + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"protect")) { + if (value) { + printk("AFFS: option protect does not take an argument\n"); + return 0; + } + *mount_opts |= SF_IMMUTABLE; + } + else if (!strcmp(this_char,"verbose")) { + if (value) { + printk("AFFS: option verbose does not take an argument\n"); + return 0; + } + *mount_opts |= SF_VERBOSE; + } + else if ((f = !strcmp(this_char,"uid")) || !strcmp(this_char,"setuid")) { + if (!value) + *uid = current->uid; + else if (!*value) { + printk("AFFS: argument for uid option missing\n"); + return 0; + } else { + *uid = simple_strtoul(value,&value,0); + if (*value) + return 0; + if (!f) + *mount_opts |= SF_SETUID; + } + } + else if ((f = !strcmp(this_char,"gid")) || !strcmp(this_char,"setgid")) { + if (!value) + *gid = current->gid; + else if (!*value) { + printk("AFFS: argument for gid option missing\n"); + return 0; + } else { + *gid = simple_strtoul(value,&value,0); + if (*value) + return 0; + if (!f) + *mount_opts |= SF_SETGID; + } + } + else if (!strcmp(this_char,"prefix")) { + if (!value) { + printk("AFFS: The prefix option requires an argument\n"); + return 0; + } + *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); + if (!*prefix) + return 0; + strcpy(*prefix,value); + *mount_opts |= SF_PREFIX; + } + else if (!strcmp(this_char,"volume")) { + if (!value) { + printk("AFFS: The volume option requires an argument\n"); + return 0; + } + if (strlen(value) > 30) + value[30] = 0; + strcpy(volume,value); + } + else if (!strcmp(this_char,"mode")) { + if (!value || !*value) { + printk("AFFS: The mode option requires an argument\n"); + return 0; + } + *mode = simple_strtoul(value,&value,8) & 0777; + if (*value) + return 0; + *mount_opts |= SF_SETMODE; + } + else if (!strcmp(this_char,"reserved")) { + if (!value || !*value) { + printk("AFFS: The reserved option requires an argument\n"); + return 0; + } + *reserved = simple_strtoul(value,&value,0); + if (*value) return 0; - optp->offset = n; } - else if (!strcmp(this_opt,"size") && value) { - n = simple_strtoul (value, &end, 10); - if (end == value || *end != 0 || n <= 0) + else if (!strcmp(this_char,"root")) { + if (!value || !*value) { + printk("AFFS: The root option requires an argument\n"); + return 0; + } + *root = simple_strtoul(value,&value,0); + if (*value) return 0; - optp->size = n; } - else if (!strcmp(this_opt,"root") && value) { - n = simple_strtoul (value, &end, 10); - if (end == value || *end != 0 || n <= 0) + else if (!strcmp(this_char,"bs")) { + if (!value || !*value) { + printk("AFFS: The bs option requires an argument\n"); + return 0; + } + *blocksize = simple_strtoul(value,&value,0); + if (*value) + return 0; + if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048 + && *blocksize != 4096) { + printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n"); return 0; - optp->root = n; + } } - else if (!strcmp(this_opt,"conv_symlinks")) { - optp->conv_links = 1; + /* Silently ignore the quota options */ + else if (!strcmp (this_char, "grpquota") + || !strcmp (this_char, "noquota") + || !strcmp (this_char, "quota") + || !strcmp (this_char, "usrquota")) + ; + else { + printk("AFFS: Unrecognized mount option %s\n", + this_char); + return 0; } - else return 0; } return 1; } -/* Is this The Right Way? Should I be locking something? */ - -static int get_device_size (dev_t dev) +struct super_block * +affs_read_super(struct super_block *s,void *data, int silent) { - struct gendisk *gd_p; - int dev_size = 0; + struct buffer_head *bh = NULL; + struct buffer_head *bb; + kdev_t dev = s->s_dev; + int root_block; + int size; + ULONG chksum; + ULONG *bm; + LONG ptype, stype; + int mapidx = 0; + int num_bm; + int i; + int key; + int blocksize; + uid_t uid; + gid_t gid; + int mode, reserved; + int zm_size; + unsigned long mount_flags; + ULONG offset; - for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) { - if (gd_p->major != MAJOR(dev)) - continue; - dev_size = gd_p->part[MINOR(dev)].nr_sects; - break; - } - return dev_size; -} + pr_debug("affs_read_super(%s)\n",(const char *)data); -struct super_block *affs_read_super(struct super_block *s,void *data, - int silent) -{ - struct buffer_head *bh; - int dev = s->s_dev; - int root_block; - int ptype, stype; - void *root_data; - struct affs_options *optp; + MOD_INC_USE_COUNT; - optp = &s->u.affs_sb.s_options; - - if (!parse_options((char *) data, optp)) { + if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block, + &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { s->s_dev = 0; - printk ("AFFS: bad mount options\n"); + printk("AFFS: error parsing options.\n"); + MOD_DEC_USE_COUNT; return NULL; } - lock_super(s); - root_block = 0; - if (optp->size) { - s->u.affs_sb.s_partition_size = optp->size; - } - else { - int size = get_device_size (dev); - if (size == 0) { - s->s_dev = 0; - unlock_super(s); - printk ("affs_read_super: could not" - "determine device size\n"); - } - s->u.affs_sb.s_partition_size = size; - } - - s->u.affs_sb.s_partition_offset = optp->offset; - root_block = optp->root; - - if (!root_block) - root_block = (s->u.affs_sb.s_partition_offset - + s->u.affs_sb.s_partition_size / 2 - + (s->u.affs_sb.s_partition_size & 1)); - s->u.affs_sb.s_root_block = root_block; - - s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE; - -#if 0 - printk ("affs_read_super: dev=0x%04x offset=%d " - "size=%d root=%d blocksize=%d\n", - dev, - s->u.affs_sb.s_partition_offset, - s->u.affs_sb.s_partition_size, - s->u.affs_sb.s_root_block, - s->u.affs_sb.s_block_size); -#endif + /* Get the size of the device in 512-byte blocks. + * If we later see that the partition uses bigger + * blocks, we will have to change it. + */ + + size = 2 * blk_size[MAJOR(dev)][MINOR(dev)]; + s->u.affs_sb.s_bitmap = NULL; + s->u.affs_sb.s_root_bh = NULL; + s->u.affs_sb.s_flags = mount_flags; + s->u.affs_sb.s_mode = mode; + s->u.affs_sb.s_uid = uid; + s->u.affs_sb.s_gid = gid; - bh = affs_sread (dev, root_block, &root_data); - if (!bh) { + if (size == 0) { s->s_dev = 0; unlock_super(s); - printk ("AFFS: unable to read superblock\n"); - return NULL; + printk("affs_read_super: could not determine device size\n"); + goto out; } + s->u.affs_sb.s_partition_size = size; + s->u.affs_sb.s_reserved = reserved; + + /* Try to find root block. It's location may depend on the block size. */ - if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype) - || ptype != T_SHORT || stype != ST_ROOT) { - printk ("AFFS: invalid root block %d on device 0x%04x\n", - root_block, dev); + s->u.affs_sb.s_hashsize = 0; + if (blocksize > 0) { + chksum = blocksize; + num_bm = blocksize; + } else { + chksum = 512; + num_bm = 4096; + } + for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) { + if (root_block < 0) + if (MAJOR(dev) == FLOPPY_MAJOR) + s->u.affs_sb.s_root_block = size/4; + else + s->u.affs_sb.s_root_block = (reserved + size - 1) / 2; + else + s->u.affs_sb.s_root_block = root_block; + pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n", + blocksize,s->u.affs_sb.s_root_block,size,reserved); + set_blocksize(dev,blocksize); + bh = affs_bread(dev,s->u.affs_sb.s_root_block,blocksize); + if (!bh) { + printk("AFFS: unable to read root block\n"); + goto out; + } + if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) && + ptype == T_SHORT && stype == ST_ROOT) { + s->s_blocksize = blocksize; + s->u.affs_sb.s_hashsize = blocksize / 4 - 56; + break; + } + affs_brelse(bh); + bh = NULL; + } + if (!s->u.affs_sb.s_hashsize) { + affs_brelse(bh); + if (!silent) + printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev)); goto out; } + root_block = s->u.affs_sb.s_root_block; -#if 1 -{ - char *name; - int len; - char buf[33]; - len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name); - memcpy (buf,name,len); - buf[len] = 0; -#if 0 - printk ("affs_read_super: volume name \"%s\"\n", buf); -#endif -} -#endif + s->u.affs_sb.s_partition_size = size; + s->s_blocksize_bits = blocksize == 512 ? 9 : + blocksize == 1024 ? 10 : + blocksize == 2048 ? 11 : 12; + + /* Find out which kind of FS we have */ + bb = affs_bread(dev,0,s->s_blocksize); + if (bb) { + chksum = htonl(*(ULONG *)bb->b_data); + switch (chksum) { + case MUFS_FS: + case MUFS_INTLFFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_INTLFFS: + s->u.affs_sb.s_flags |= SF_INTL; + break; + case MUFS_FFS: + s->u.affs_sb.s_flags |= SF_MUFS; + break; + case FS_FFS: + break; + case MUFS_OFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_OFS: + s->u.affs_sb.s_flags |= SF_OFS; + break; + case MUFS_INTLOFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_INTLOFS: + s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; + break; + case FS_DCOFS: + case FS_DCFFS: + case MUFS_DCOFS: + case MUFS_DCFFS: + if (!silent) + printk("AFFS: Unsupported filesystem on device %s: %08X\n", + kdevname(dev),chksum); + if (0) + default: + printk("AFFS: Unknown filesystem on device %s: %08X\n", + kdevname(dev),chksum); + affs_brelse(bb); + goto out; + } + affs_brelse(bb); + } else { + printk("AFFS: Can't get boot block.\n"); + goto out; + } + if (mount_flags & SF_VERBOSE) { + chksum = ntohl(chksum); + printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", + GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0], + &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1], + (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); + } s->s_magic = AFFS_SUPER_MAGIC; + s->s_flags = MS_NODEV | MS_NOSUID; - s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID; + /* Keep super block in cache */ + if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { + printk("AFFS: Can't read root block a second time\n"); + goto out; + } - brelse(bh); + /* Allocate space for bitmap pointers and read the bitmap */ + + size = s->u.affs_sb.s_partition_size - reserved; + num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32); + zm_size = (num_bm * (1 << (s->s_blocksize_bits - 8)) + 7) / 8; + ptype = num_bm * sizeof(struct affs_bm_info) + zm_size + + MAX_ZONES * sizeof(struct affs_zone); + if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { + printk("AFFS: Can't get memory for bitmap info.\n"); + goto out; + } + memset(s->u.affs_sb.s_bitmap,0,ptype); + + if( (ULONG)((UBYTE *)bh->b_data + s->s_blocksize - 200) == 0 ) { + if (!(s->s_flags & MS_RDONLY)) { + printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev)); + s->s_flags |= MS_RDONLY; + } + affs_brelse(bh); + bh = NULL; + goto nobitmap; + } + + pr_debug("AFFS: %d bitmap blocks\n",num_bm); + + key = root_block; + ptype = s->s_blocksize / 4 - 49; + stype = ptype + 25; + offset = s->u.affs_sb.s_reserved; + while (bh) { + bm = (ULONG *)bh->b_data; + for (i = ptype; i < stype && bm[i]; i++, mapidx++) { + if (mapidx >= num_bm) { + printk("AFFS: Not enough bitmap space!?\n"); + goto out; + } + bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize); + if (bb) { + if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) /*&& + !(s->s_flags & MS_RDONLY)*/) { + printk("AFFS: Bitmap (%d,key=%lu) invalid - mounting %s read only.\n", + mapidx, htonl(bm[i]), + kdevname(dev)); + s->s_flags |= MS_RDONLY; + } + if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ + ptype = size / 32 + 1; /* word number */ + key = size & 0x1F; /* used bits */ + if (key) { + chksum = ntohl(0x7FFFFFFF >> (31 - key)); + ((ULONG *)bb->b_data)[ptype] &= chksum; + affs_fix_checksum(s->s_blocksize,bb->b_data,0); + /* no need to mark buffer as dirty */ + } + ptype = (size + 31) & ~0x1F; + size = 0; + if (!(s->s_flags & MS_RDONLY)) + s->u.affs_sb.s_flags |= SF_BM_VALID; + } else { + ptype = s->s_blocksize * 8 - 32; + size -= ptype; + } + s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; + s->u.affs_sb.s_bitmap[mapidx].bm_size = ptype; + s->u.affs_sb.s_bitmap[mapidx].bm_bh = bb; + s->u.affs_sb.s_bitmap[mapidx].bm_free = + affs_count_free_bits(ptype/8,bb->b_data + 4); + offset += ptype; + } else { + printk("AFFS: Can't read bitmap.\n"); + goto out; + } + } + key = htonl(bm[stype]); /* Next block of bitmap pointers */ + ptype = 0; + stype = s->s_blocksize / 4 - 1; + affs_brelse(bh); + if (key) { + if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) { + printk("AFFS: Can't read bitmap extension.\n"); + goto out; + } + } else + bh = NULL; + } + if (mapidx != num_bm) { + printk("AFFS: Got only %d bitmap blocks, expected %d\n", + mapidx, num_bm); + goto out; + } + s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8))+ + (s->u.affs_sb.s_bitmap[num_bm - 1].bm_size + 2047) / 2048; +nobitmap: + s->u.affs_sb.s_bm_count = mapidx; + s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; + s->u.affs_sb.s_zonemap = (char *)&s->u.affs_sb.s_zones[MAX_ZONES]; /* set up enough so that it can read an inode */ - s->s_dev = dev; - s->s_op = &affs_sops; - s->s_blocksize = AFFS_BUFFER_SIZE; - s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset); + s->s_dev = dev; + s->s_op = &affs_sops; + s->s_mounted = iget(s,root_block); unlock_super(s); if (!(s->s_mounted)) { s->s_dev = 0; printk("AFFS: get root inode failed\n"); + MOD_DEC_USE_COUNT; return NULL; } + /* If the fs is mounted r/w, create data zones, else free bitmaps. */ + + if (!(s->s_flags & MS_RDONLY)) { + ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0; + secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data, + s->s_mounted)->disk_altered); + affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(s->u.affs_sb.s_root_bh,1); + affs_make_zones(s); + } else { + for (i = 0; i < s->u.affs_sb.s_bm_count; i++) { + affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh); + s->u.affs_sb.s_bitmap[i].bm_bh = NULL; + } + } + + + pr_debug("AFFS: s_flags=%lX\n", s->s_flags); return s; out: /* Kick out for various error conditions */ - brelse (bh); + affs_brelse (bh); + affs_brelse(s->u.affs_sb.s_root_bh); + if (s->u.affs_sb.s_bitmap) { + for (i = 0; i < mapidx; i++) + affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh); + kfree(s->u.affs_sb.s_bitmap); + } s->s_dev = 0; unlock_super(s); + MOD_DEC_USE_COUNT; return NULL; } -void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz) +void +affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { -#ifdef DEBUG - printk ("AFFS: affs_statfs called\n"); -#endif - put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type); - put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize); - put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks); - put_fs_long(0, &buf->f_bfree); - put_fs_long(0, &buf->f_bavail); - put_fs_long(0, &buf->f_files); - put_fs_long(0, &buf->f_ffree); - /* Don't know what value to put in buf->f_fsid */ -} - -static int prot_table[9][2] = { - {PROT_OTR_EXECUTE, PROT_OTR_EXECUTE}, /* other: 1 = allowed */ - {PROT_OTR_WRITE, PROT_OTR_WRITE}, - {PROT_OTR_READ, PROT_OTR_READ}, - {PROT_GRP_EXECUTE, PROT_GRP_EXECUTE}, /* group: 1 = allowed */ - {PROT_GRP_WRITE, PROT_GRP_WRITE}, - {PROT_GRP_READ, PROT_GRP_READ}, - {PROT_EXECUTE, 0}, /* owner: 0 = allowed */ - {PROT_WRITE, 0}, - {PROT_READ, 0} -}; + ULONG free; + struct statfs tmp; + + pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n", + sb->u.affs_sb.s_partition_size, sb->u.affs_sb.s_reserved); -void affs_read_inode(struct inode * inode) + free = affs_count_free_blocks(sb); + tmp.f_type = AFFS_SUPER_MAGIC; + tmp.f_bsize = sb->s_blocksize; + tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved; + tmp.f_bfree = free; + tmp.f_bavail = free; + tmp.f_files = 0; + tmp.f_ffree = 0; + memcpy_tofs(buf,&tmp,bufsiz); +} + +void +affs_read_inode(struct inode *inode) { - struct buffer_head *bh; - int block; - void *fh_data; - struct file_front *file_front; - struct file_end *file_end; - int i; - struct hardlink_end *link_end; - int link; - -#ifdef DEBUG - printk ("AFFS: entering affs_read_inode\n"); -#endif - - inode->i_nlink = 1; /* at least */ - do { - link = 0; - block = inode->i_ino; - if (!(bh=affs_pread (inode, block, &fh_data))) { - printk("AFFS: unable to read i-node block %d\n", block); - return; - } - - file_front = (struct file_front *) fh_data; - file_end = GET_END_PTR (struct file_end, fh_data, /* coincidently the same as dir_end */ - AFFS_I2BSIZE (inode)); - - /* don't use bitmap data for mode, uid & gid of the rootblock */ - if (block == inode->i_sb->u.affs_sb.s_root_block) { - inode->u.affs_i.i_protect = 0; - inode->u.affs_i.i_parent = block; - - inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ; /* drwxrwxrwt */ - inode->i_nlink = 2; /* at least ..... */ - - inode->i_size = 0; /* some different idea ? */ - - inode->i_uid = 0; - inode->i_gid = 0; - } - else { - - inode->u.affs_i.i_protect = file_end->protect; - inode->u.affs_i.i_parent = swap_long (file_end->parent); - - inode->i_mode = 0; - for (i = 0; i < 9; i++) - if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1]) - inode->i_mode |= 1<secondary_type)) { - case ST_USERDIR: - inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR; - - inode->i_nlink++; /* There are always at least 2. It is - hard to figure out what is correct*/ - inode->i_size = 0; - break; - case ST_SOFTLINK: - inode->i_mode |= S_IFLNK; - inode->i_size = 0; - break; - case ST_LINKFILE: /* doing things very easy (not really correct) */ - case ST_LINKDIR: /* code is _very_ inefficient (see below) */ + struct buffer_head *bh, *lbh; + struct file_front *file_front; + struct file_end *file_end; + LONG block; + ULONG prot; + LONG ptype, stype; + unsigned short id; + + pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino); + lbh = NULL; + block = inode->i_ino; + if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { + printk("AFFS: unable to read i-node block %d\n",block); + return; + } + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) { + printk("AFFS: read_inode(): checksum or type (ptype=%d) error on inode %d\n", + ptype, block); + affs_brelse(bh); + return; + } - /* Where is struct link_end defined? - ... I don't know what is going on - here, someone else should - probably spend some time on this */ - link_end = (struct hardlink_end *)file_end; - inode->i_ino = link_end->original; - inode->i_nlink += 2; /* It's hard to say what's correct */ - brelse(bh); - link = 1; - break; - default: - printk("affs: unknown secondary type %ld; assuming file\n", - file_end->secondary_type); - case ST_FILE: - inode->i_mode |= S_IFREG; - inode->i_size = swap_long (file_end->byte_size); - break; - } - if (file_end->uid == 0xffff) - inode->i_uid = 0; /* root uid */ - else if (file_end->uid == 0x0000) { - umode_t mode; - inode->i_uid = -1; /* unknown uid */ - - /* - * change the mode of the inode to duplicate the - * perms of the user in the group and other fields; - * the assumption is that this isn't a MultiUser - * filesystem/file, so the permissions should be - * the same for all users - */ - mode = (inode->i_mode >> 6) & 7; - inode->i_mode |= (mode << 3) | (mode); - } else - inode->i_uid = file_end->uid; - if (file_end->gid == 0xffff) - inode->i_gid = 0; /* root gid */ - else if (file_end->gid == 0x0000) - inode->i_gid = -1; /* unknown gid */ - else - inode->i_gid = file_end->gid; + file_front = (struct file_front *)bh->b_data; + file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); + prot = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER; + + inode->u.affs_i.i_protect = prot; + inode->u.affs_i.i_parent = htonl(file_end->parent); + inode->u.affs_i.i_original = 0; + inode->u.affs_i.i_zone = 0; + inode->u.affs_i.i_hlink = 0; + inode->u.affs_i.i_pa_cnt = 0; + inode->u.affs_i.i_pa_next = 0; + inode->u.affs_i.i_pa_last = 0; + inode->u.affs_i.i_ext[0] = 0; + inode->u.affs_i.i_max_ext = 0; + inode->i_nlink = 1; + inode->i_mode = 0; + + if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) + inode->i_mode = inode->i_sb->u.affs_sb.s_mode; + else + inode->i_mode = prot_to_mode(prot); + + if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID) + inode->i_uid = inode->i_sb->u.affs_sb.s_uid; + else { + id = htons(file_end->owner_uid); + if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { + if (id == 0 || id == 0xFFFF) + id ^= ~0; } + inode->i_uid = id; + } + if (inode->i_sb->u.affs_sb.s_flags & SF_SETGID) + inode->i_gid = inode->i_sb->u.affs_sb.s_gid; + else { + id = htons(file_end->owner_gid); + if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { + if (id == 0 || id == 0xFFFF) + id ^= ~0; + } + inode->i_gid = id; } - while (link); - -#ifdef DEBUG - printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size); -#endif - inode->i_mtime = inode->i_atime = inode->i_ctime - = (swap_long (file_end->created.ds_Days) * (24 * 60 * 60) - + swap_long (file_end->created.ds_Minute) * 60 - + swap_long (file_end->created.ds_Tick) / 50 - + ((8 * 365 + 2) * 24 * 60 * 60)); - brelse(bh); + switch (htonl(file_end->secondary_type)) { + case ST_ROOT: + inode->i_uid = inode->i_sb->u.affs_sb.s_uid; + inode->i_gid = inode->i_sb->u.affs_sb.s_gid; + case ST_USERDIR: + if (htonl(file_end->secondary_type) == ST_USERDIR || + inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) { + if (inode->i_mode & S_IRUSR) + inode->i_mode |= S_IXUSR; + if (inode->i_mode & S_IRGRP) + inode->i_mode |= S_IXGRP; + if (inode->i_mode & S_IROTH) + inode->i_mode |= S_IXOTH; + inode->i_mode |= S_IFDIR; + } else + inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; + inode->i_size = 0; + break; + case ST_LINKDIR: + inode->u.affs_i.i_original = htonl(file_end->original); + inode->u.affs_i.i_hlink = 1; + inode->i_mode |= S_IFDIR; + inode->i_size = 0; + break; + case ST_LINKFILE: + inode->u.affs_i.i_original = htonl(file_end->original); + inode->u.affs_i.i_hlink = 1; + if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original, + AFFS_I2BSIZE(inode)))) { + affs_brelse(bh); + printk("AFFS: unable to read i-node block %ld\n",inode->i_ino); + return; + } + file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode)); + case ST_FILE: + inode->i_mode |= S_IFREG; + inode->i_size = htonl(file_end->byte_size); + break; + case ST_SOFTLINK: + inode->i_mode |= S_IFLNK; + inode->i_size = 0; + break; + } + inode->i_mtime = inode->i_atime = inode->i_ctime + = (htonl(file_end->created.ds_Days) * (24 * 60 * 60) + + htonl(file_end->created.ds_Minute) * 60 + + htonl(file_end->created.ds_Tick) / 50 + + ((8 * 365 + 2) * 24 * 60 * 60)) + + sys_tz.tz_minuteswest * 60; + affs_brelse(bh); + affs_brelse(lbh); + inode->i_op = NULL; - if (S_ISREG(inode->i_mode)) - inode->i_op = &affs_file_inode_operations; - else if (S_ISDIR(inode->i_mode)) + if (S_ISREG(inode->i_mode)) { + if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) + inode->i_op = &affs_file_inode_operations_ofs; + else + inode->i_op = &affs_file_inode_operations; + } else if (S_ISDIR(inode->i_mode)) inode->i_op = &affs_dir_inode_operations; else if (S_ISLNK(inode->i_mode)) inode->i_op = &affs_symlink_inode_operations; } +void +affs_write_inode(struct inode *inode) +{ + struct buffer_head *bh; + struct file_end *file_end; + short uid, gid; -#ifdef LEAK_CHECK -#undef malloc -#undef free_s -#undef bread -#undef brelse + pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino); -void * leak_check_malloc(unsigned int size){ - void * tmp; - check_malloc++; - tmp = kmalloc(size, GFP_ATOMIC); - return tmp; + inode->i_dirt = 0; + if (!inode->i_nlink) + return; + if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) { + printk("AFFS: Unable to read block of inode %ld on %s\n", + inode->i_ino,kdevname(inode->i_dev)); + return; + } + file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); + if (file_end->secondary_type == htonl(ST_ROOT)) { + secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered); + } else { + file_end->protect = ntohl(inode->u.affs_i.i_protect ^ FIBF_OWNER); + file_end->byte_size = ntohl(inode->i_size); + secs_to_datestamp(inode->i_mtime,&file_end->created); + if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) { + uid = inode->i_uid; + gid = inode->i_gid; + if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { + if (inode->i_uid == 0 || inode->i_uid == 0xFFFF) + uid = inode->i_uid ^ ~0; + if (inode->i_gid == 0 || inode->i_gid == 0xFFFF) + gid = inode->i_gid ^ ~0; + } + if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) + file_end->owner_gid = ntohs(uid); + if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) + file_end->owner_gid = ntohs(gid); + } + } + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + brelse(bh); } -void leak_check_free_s(void * obj, int size){ - check_malloc--; - return kfree_s(obj, size); +int +affs_notify_change(struct inode *inode, struct iattr *attr) +{ + int error; + + pr_debug("AFFS: notify_change(%lu,0x%x)\n", + inode->i_ino,attr->ia_valid); + + error = inode_change_ok(inode,attr); + if (error) + return error; + + if (((attr->ia_valid & ATTR_UID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) || + ((attr->ia_valid & ATTR_GID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) || + ((attr->ia_valid & ATTR_MODE) && + (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE)))) + error = -EPERM; + + if (error) + return (inode->i_sb->u.affs_sb.s_flags & SF_QUIET) ? 0 : error; + + if (attr->ia_valid & ATTR_MODE) + inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode); + + inode_setattr(inode,attr); + + return 0; } -struct buffer_head * leak_check_bread(int dev, int block, int size){ - check_bread++; - return bread(dev, block, size); +void +affs_put_inode(struct inode *inode) +{ + pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", + inode->i_ino,inode->i_nlink); + if (inode->i_nlink) { + return; + } + inode->i_size = 0; + if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink) + affs_truncate(inode); + affs_free_block(inode->i_sb,inode->i_ino); + clear_inode(inode); } -void leak_check_brelse(struct buffer_head * bh){ - check_bread--; - return brelse(bh); +struct inode * +affs_new_inode(const struct inode *dir) +{ + struct inode *inode; + struct super_block *sb; + ULONG block; + + if (!dir || !(inode = get_empty_inode())) + return NULL; + + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + + if (!(block = affs_new_header((struct inode *)dir))) { + iput(inode); + return NULL; + } + + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_dirt = 1; + inode->i_ino = block; + inode->i_op = NULL; + inode->i_blocks = 0; + inode->i_size = 0; + inode->i_mode = 0; + inode->i_blksize = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + + inode->u.affs_i.i_original = 0; + inode->u.affs_i.i_parent = dir->i_ino; + inode->u.affs_i.i_zone = 0; + inode->u.affs_i.i_hlink = 0; + inode->u.affs_i.i_pa_cnt = 0; + inode->u.affs_i.i_pa_next = 0; + inode->u.affs_i.i_pa_last = 0; + inode->u.affs_i.i_ext[0] = 0; + inode->u.affs_i.i_max_ext = 0; + + insert_inode_hash(inode); + + return inode; +} + +int +affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, + const char *name, int len, LONG type) +{ + struct buffer_head *dir_bh; + struct buffer_head *inode_bh; + struct buffer_head *link_bh; + ULONG hash; + + pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n", + dir->i_ino,inode->i_ino, len,name,type); + + dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); + inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + link_bh = NULL; + if (!dir_bh || !inode_bh) { + affs_brelse(dir_bh); + affs_brelse(inode_bh); + return -ENOSPC; + } + if (link) { + link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link)); + if (!link_bh) { + affs_brelse(dir_bh); + affs_brelse(inode_bh); + return -EINVAL; + } + } + ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT); + ((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino); + + if (len > 30) /* truncate name quietly */ + len = 30; + DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; + strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len); + DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type); + DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino); + hash = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)); + + lock_super(inode->i_sb); + DIR_END(inode_bh->b_data,inode)->hash_chain = + ((struct dir_front *)dir_bh->b_data)->hashtable[hash]; + ((struct dir_front *)dir_bh->b_data)->hashtable[hash] = ntohl(inode->i_ino); + if (link_bh) { + LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino); + LINK_END(inode_bh->b_data,inode)->link_chain = + FILE_END(link_bh->b_data,link)->link_chain; + FILE_END(link_bh->b_data,link)->link_chain = ntohl(inode->i_ino); + affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5); + link->i_version = ++event; + link->i_dirt = 1; + mark_buffer_dirty(link_bh,1); + } + affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5); + affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5); + dir->i_version = ++event; + dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME; + unlock_super(inode->i_sb); + + dir->i_dirt = 1; + inode->i_dirt = 1; + mark_buffer_dirty(dir_bh,1); + mark_buffer_dirty(inode_bh,1); + affs_brelse(dir_bh); + affs_brelse(inode_bh); + affs_brelse(link_bh); + + return 0; +} + +static struct file_system_type affs_fs_type = { + affs_read_super, + "affs", + 1, + NULL +}; + +int +init_affs_fs(void) +{ + return register_filesystem(&affs_fs_type); +} + +#ifdef MODULE + +int +init_module(void) +{ + int status; + if ((status = init_affs_fs()) == 0) + register_symtab(0); + return status; +} + +void +cleanup_module(void) +{ + unregister_filesystem(&affs_fs_type); } #endif diff -u --recursive --new-file v1.3.98/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v1.3.98/linux/fs/affs/namei.c Tue Apr 23 13:57:11 1996 +++ linux/fs/affs/namei.c Mon May 6 14:36:05 1996 @@ -1,187 +1,736 @@ /* * linux/fs/affs/namei.c * - * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * (c) 1996 Hans-Joachim Widmaier - Heavily hacked up. * - * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1991 Linus Torvalds - minix filesystem */ #include #include +#include #include #include #include #include +#include #include #include +/* Simple toupper() for DOS\1 */ -static inline int namecompare(int len, int maxlen, - const char * name, const char * buffer) +static inline unsigned int +affs_toupper(unsigned int ch) { - if (len >= maxlen || !buffer[len]) { - return strncmp (name, buffer, len) == 0; - } - return 0; + return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; +} + +/* International toupper() for DOS\3 */ + +static inline unsigned int +affs_intl_toupper(unsigned int ch) +{ + return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0 + && ch <= 0xFE && ch != 0xF7) ? + ch - ('a' - 'A') : ch; } /* - * ok, we cannot use strncmp, as the name is not in our data space. - * Thus we'll have to use affs_match. No big problem. Match also makes - * some sanity tests. - * * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. */ -static int affs_match(int len,const char * name, char * compare, int dlen) + +static int +affs_match(const char *name, int len, const char *compare, int dlen, int intl) { - if (!compare) return 0; + if (!compare) + return 0; + + if (len > 30) + len = 30; + if (dlen > 30) + dlen = 30; /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ if (!len && dlen == 1 && compare[0] == '.') return 1; - -#if 0 - if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen); -#endif - - return namecompare(len,dlen,name,compare); + if (dlen != len) + return 0; + if (intl) { + while (dlen--) { + if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF)) + return 0; + name++; + compare++; + } + } else { + while (dlen--) { + if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF)) + return 0; + name++; + compare++; + } + } + return 1; } -/* Avoid pulling in ctype stuff. */ - -static int affs_toupper (int ch) +int +affs_hash_name(const char *name, int len, int intl, int hashsize) { - if (ch >= 'a' && ch <= 'z') - ch -= ('a' - 'A'); - return ch; -} + unsigned int i, x; -static int affs_hash_name (const char *name, int len) -{ - int i, x; + if (len > 30) + len = 30; x = len; for (i = 0; i < len; i++) - x = (x * 13 + affs_toupper (name[i])) & 0x7ff; - return x % 72; /* FIXME: Assumes 512 byte blocks. */ + if (intl) + x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff; + else + x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff; + + return x % hashsize; } -static struct buffer_head *affs_find_entry(struct inode *dir, - const char *name, int namelen, int *ino) +static struct buffer_head * +affs_find_entry(struct inode *dir, const char *name, int namelen, + unsigned long *ino) { struct buffer_head *bh; - void *dir_data; - int key; + int intl; + ULONG key; - *ino = 0; + pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); - bh = affs_pread (dir, dir->i_ino, &dir_data); + intl = AFFS_I2FSTYPE(dir); + bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); if (!bh) return NULL; - if (affs_match (namelen, name, ".", 1)) { + if (affs_match(name,namelen,".",1,intl)) { *ino = dir->i_ino; return bh; } - if (affs_match (namelen, name, "..", 2)) { - *ino = affs_parent_ino (dir); + if (affs_match(name,namelen,"..",2,intl)) { + *ino = affs_parent_ino(dir); return bh; } - key = affs_get_key_entry (AFFS_I2BSIZE (dir), dir_data, - affs_hash_name (name, namelen)); + + key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir))); for (;;) { char *cname; int cnamelen; - brelse (bh); - if (key <= 0) - return NULL; - bh = affs_pread (dir, key, &dir_data); + affs_brelse(bh); + if (key == 0) { + bh = NULL; + break; + } + bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir)); if (!bh) - return NULL; - cnamelen = affs_get_file_name (AFFS_I2BSIZE (dir), - dir_data, &cname); - if (affs_match (namelen, name, cname, cnamelen)) break; - key = affs_get_fh_hash_link (AFFS_I2BSIZE (dir), dir_data); + cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname); + if (affs_match(name,namelen,cname,cnamelen,intl)) + break; + key = htonl(FILE_END(bh->b_data,dir)->hash_chain); } - + pr_debug("%lu\n",key); *ino = key; - return bh; } -int affs_lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +int +affs_lookup(struct inode *dir, const char *name, int len, struct inode **result) { - int ino; + int res; + unsigned long ino; struct buffer_head *bh; + pr_debug("AFFS: lookup(%.*s)\n",len,name); + *result = NULL; if (!dir) return -ENOENT; -#ifdef DEBUG - printk ("lookup: %d %d\n", dir->i_ino, len); -#endif + res = -ENOENT; + if (S_ISDIR(dir->i_mode)) { + if ((bh = affs_find_entry(dir,name,len,&ino))) { + if (FILE_END(bh->b_data,dir)->original) + ino = htonl(FILE_END(bh->b_data,dir)->original); + affs_brelse(bh); + if ((*result = iget(dir->i_sb,ino))) + res = 0; + else + res = -EACCES; + } + } + iput(dir); + return res; +} + +int +affs_unlink(struct inode *dir, const char *name, int len) +{ + int retval; + struct buffer_head *bh; + unsigned long ino; + struct inode *inode; + + pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name); + + bh = NULL; + inode = NULL; + retval = -ENOENT; + if (!(bh = affs_find_entry(dir,name,len,&ino))) { + goto unlink_done; + } + if (!(inode = iget(dir->i_sb,ino))) { + goto unlink_done; + } + if (S_ISDIR(inode->i_mode)) { + retval = -EPERM; + goto unlink_done; + } + + if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), + AFFS_I2HSIZE(dir)) + 6,ino, + FILE_END(bh->b_data,dir)->hash_chain))) + goto unlink_done; + + if ((retval = affs_fixup(bh,inode))) + goto unlink_done; + + inode->i_nlink=0; + inode->i_dirt=1; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version = ++event; + dir->i_dirt=1; +unlink_done: + affs_brelse(bh); + iput(inode); + iput(dir); + return retval; +} + +int +affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result) +{ + struct inode *inode; + int error; + + pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); + - if (!S_ISDIR(dir->i_mode)) { + *result = NULL; + + if (!dir || !dir->i_sb) { iput(dir); - return -ENOENT; + return -EINVAL; } - if (!(bh = affs_find_entry(dir, name, len, &ino))) { - iput(dir); - return -ENOENT; + inode = affs_new_inode(dir); + if (!inode) { + iput (dir); + return -ENOSPC; } - brelse(bh); - if (!(*result = iget(dir->i_sb, ino))) { + inode->i_op = &affs_file_inode_operations; + inode->i_mode = mode; + error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE); + if (error) { iput(dir); - return -EACCES; + inode->i_nlink = 0; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; } - iput (dir); + inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + + iput(dir); + *result = inode; + return 0; +} -#if 0 - ino = 0; - while(cache.lock); - cache.lock = 1; - if (dir->i_dev == cache.dev && - dir->i_ino == cache.dir && - len == cache.dlen && - affs_match(len, name, cache.filename, cache.dlen)) - { - ino = cache.ino; - ino_back = dir->i_ino; - /* These two cases are special, but since they are at the start - of the directory, we can just as easily search there */ - if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0; - if (cache.dlen == 2 && cache.filename[0] == '.' && - cache.filename[1] == '.') ino = 0; - }; - cache.lock = 0; - - if (!ino) { - if (!(bh = affs_find_entry(dir,name,len, &ino, &ino_back))) { - iput(dir); - return -ENOENT; - } - brelse(bh); - }; +int +affs_mkdir(struct inode *dir, const char *name, int len, int mode) +{ + struct inode *inode; + struct buffer_head *bh; + unsigned long i; + int error; + + pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); - if (!(*result = iget(dir->i_sb,ino))) { + if (!dir || !dir->i_sb) { + iput(dir); + return -EINVAL; + } + bh = affs_find_entry(dir,name,len,&i); + if (bh) { + affs_brelse(bh); iput(dir); - return -EACCES; + return -EEXIST; } + inode = affs_new_inode(dir); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_op = &affs_dir_inode_operations; + error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR); + if (error) { + iput(dir); + inode->i_nlink = 0; + inode->i_dirt = 1; + iput(inode); + return error; + } + inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); + inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); - /* We need this backlink for the .. entry */ - - if (ino_back) (*result)->u.affs_i.i_backlink = ino_back; + iput(dir); + iput(inode); + + return 0; +} + +static int +empty_dir(struct buffer_head *bh, int hashsize) +{ + while (--hashsize >= 0) { + if (((struct dir_front *)bh->b_data)->hashtable[hashsize]) + return 0; + } + return 1; +} + +int +affs_rmdir(struct inode *dir, const char *name, int len) +{ + int retval; + unsigned long ino; + struct inode *inode; + struct buffer_head *bh; + + pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name); + + inode = NULL; + retval = -ENOENT; + if (!(bh = affs_find_entry(dir,name,len,&ino))) { + goto rmdir_done; + } + if (!(inode = iget(dir->i_sb,ino))) { + goto rmdir_done; + } + retval = -EPERM; + if (!fsuser() && current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid) + goto rmdir_done; + if (inode->i_dev != dir->i_dev) + goto rmdir_done; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto rmdir_done; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto rmdir_done; + } + if (!empty_dir(bh,AFFS_I2HSIZE(inode))) { + retval = -ENOTEMPTY; + goto rmdir_done; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto rmdir_done; + } + if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), + AFFS_I2HSIZE(dir)) + 6,ino, + FILE_END(bh->b_data,dir)->hash_chain))) + goto rmdir_done; + + if ((retval = affs_fixup(bh,inode))) + goto rmdir_done; + + inode->i_nlink=0; + inode->i_dirt=1; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version = ++event; + dir->i_dirt=1; +rmdir_done: + iput(dir); + iput(inode); + affs_brelse(bh); + return retval; +} + +int +affs_symlink(struct inode *dir, const char *name, int len, const char *symname) +{ + struct buffer_head *bh; + struct inode *inode; + char *p; + unsigned long tmp; + int i, maxlen; + char c, lc; + + pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname); + printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname); + maxlen = 4 * AFFS_I2HSIZE(dir) - 1; + inode = affs_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &affs_symlink_inode_operations; + inode->i_mode = S_IFLNK | 0777; + inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + if (!bh) { + iput(dir); + inode->i_nlink = 0; + inode->i_dirt = 1; + iput(inode); + return -EIO; + } + i = 0; + p = ((struct slink_front *)bh->b_data)->symname; + lc = '/'; + if (*symname == '/') { + while (*symname == '/') + symname++; + while (inode->i_sb->u.affs_sb.s_volume[i]) /* Cannot overflow */ + *p++ = inode->i_sb->u.affs_sb.s_volume[i++]; + } + while (i < maxlen && (c = *symname++)) { + if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { + *p++ = '/'; + i++; + symname += 2; + lc = '/'; + } else if (c == '.' && lc == '/' && *symname == '/') { + symname++; + lc = '/'; + } else { + *p++ = c; + lc = c; + i++; + } + if (lc == '/') + while (*symname == '/') + symname++; + } + *p = 0; + mark_buffer_dirty(bh,1); + affs_brelse(bh); + inode->i_dirt = 1; + bh = affs_find_entry(dir,name,len,&tmp); + if (bh) { + inode->i_nlink = 0; + iput(inode); + affs_brelse(bh); + iput(dir); + return -EEXIST; + } + i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK); + if (i) { + inode->i_nlink = 0; + inode->i_dirt = 1; + iput(inode); + affs_brelse(bh); + iput(dir); + return i; + } iput(dir); + iput(inode); + return 0; -#endif +} + +int +affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len) +{ + struct inode *inode; + struct buffer_head *bh; + unsigned long i; + int error; + + pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name); + + bh = affs_find_entry(dir,name,len,&i); + if (bh) { + affs_brelse(bh); + iput(oldinode); + iput(dir); + return -EEXIST; + } + if (oldinode->u.affs_i.i_hlink) { + i = oldinode->u.affs_i.i_original; + iput(oldinode); + oldinode = iget(dir->i_sb,i); + if (!oldinode) { + printk("AFFS: link(): original does not exist.\n"); + iput(dir); + return -ENOENT; + } + } + inode = affs_new_inode(dir); + if (!inode) { + iput(oldinode); + iput(dir); + return -ENOSPC; + } + inode->i_op = oldinode->i_op; + inode->i_mode = oldinode->i_mode; + inode->i_uid = oldinode->i_uid; + inode->i_gid = oldinode->i_gid; + inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + inode->u.affs_i.i_original = oldinode->i_ino; + inode->u.affs_i.i_hlink = 1; + + if (S_ISDIR(oldinode->i_mode)) + error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR); + else + error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE); + if (error) { + inode->i_nlink = 0; + inode->i_dirt = 1; + } + iput(dir); + iput(inode); + iput(oldinode); + + return error; +} + +static int +subdir(struct inode * new_inode, struct inode * old_inode) +{ + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (affs_lookup(new_inode,"..",2,&new_inode)) + break; + if (new_inode->i_ino == ino) + break; + } + iput(new_inode); + return result; +} + +/* I'm afraid this might not be race proof. Maybe next time. */ + +int +affs_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len) +{ + struct inode *old_inode; + struct inode *new_inode; + struct buffer_head *old_bh; + struct buffer_head *new_bh; + unsigned long old_ino; + unsigned long new_ino; + int retval; + + pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name, + new_dir->i_ino,new_len,new_name); + + if (new_len > 30) + new_len = 30; + goto start_up; +retry: + affs_brelse(old_bh); + affs_brelse(new_bh); + iput(new_inode); + iput(old_inode); + current->counter = 0; + schedule(); +start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = NULL; + retval = -ENOENT; + + old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino); + if (!old_bh) + goto end_rename; + old_inode = __iget(old_dir->i_sb,old_ino,0); + if (!old_inode) + goto end_rename; + new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); + if (new_bh) { + new_inode = __iget(new_dir->i_sb,new_ino,0); + if (!new_inode) { /* What does this mean? */ + affs_brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { /* Won't happen */ + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir,old_inode)) + goto end_rename; + retval = -ENOTEMPTY; + if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) + goto end_rename; + retval = -EBUSY; + if (new_inode->i_count > 1) + goto end_rename; + } + if (S_ISDIR(old_inode->i_mode)) { + retval = -ENOTDIR; + if (new_inode && !S_ISDIR(new_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir,old_inode)) + goto end_rename; + if (affs_parent_ino(old_inode) != old_dir->i_ino) + goto end_rename; + } + /* Unlink destination if existant */ + if (new_inode) { + if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len, + AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6, + new_ino, + FILE_END(new_bh->b_data,new_dir)->hash_chain))) + goto retry; + if ((retval = affs_fixup(new_bh,new_inode))) + goto retry; + mark_buffer_dirty(new_bh,1); + new_dir->i_version = ++event; + new_dir->i_dirt = 1; + new_inode->i_nlink = 0; + new_inode->i_dirt = 1; + } + retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir), + AFFS_I2HSIZE(old_dir)) + 6,old_ino, + FILE_END(old_bh->b_data,old_dir)->hash_chain); + if (retval) + goto retry; + + retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len, + htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type)); + + new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + new_dir->i_version = ++event; + old_dir->i_version = ++event; + new_dir->i_dirt = 1; + old_dir->i_dirt = 1; + mark_buffer_dirty(old_bh,1); + +end_rename: + affs_brelse(old_bh); + affs_brelse(new_bh); + iput(new_inode); + iput(old_inode); + iput(old_dir); + iput(new_dir); + + return retval; +} + +int +affs_fixup(struct buffer_head *bh, struct inode *inode) +{ + ULONG key, link_key; + LONG type; + struct buffer_head *nbh; + struct inode *ofinode; + + type = htonl(FILE_END(bh->b_data,inode)->secondary_type); + if (type == ST_LINKFILE || type == ST_LINKDIR) { + key = htonl(LINK_END(bh->b_data,inode)->original); + LINK_END(bh->b_data,inode)->original = 0; + if (!key) { + printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino); + return -ENOENT; + } + if (!(ofinode = iget(inode->i_sb,key))) + return -ENOENT; + type = affs_fix_link_pred(ofinode,inode->i_ino, + FILE_END(bh->b_data,inode)->link_chain); + iput(ofinode); + return type; + } else if (type == ST_FILE || type == ST_USERDIR) { + if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) { + /* Get first link, turn it to a file */ + if (!(ofinode = iget(inode->i_sb,key))) { + printk("AFFS: fixup(): cannot read inode %u\n",key); + return -ENOENT; + } + if (!ofinode->u.affs_i.i_hlink) { + printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n", + inode->i_ino,key); + iput(ofinode); + return -ENOENT; + } + if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { + printk("AFFS: fixup(): cannot read block %u\n",key); + iput(ofinode); + return -ENOENT; + } + lock_super(inode->i_sb); + memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208); + FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)-> + byte_size; + FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)-> + extension; + FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)-> + secondary_type; + FILE_END(nbh->b_data,inode)->original = 0; + + ofinode->u.affs_i.i_original = 0; + ofinode->u.affs_i.i_hlink = 0; + ofinode->i_size = inode->i_size; + ofinode->i_uid = inode->i_uid; + ofinode->i_gid = inode->i_gid; + ofinode->i_dirt = 1; + link_key = ofinode->i_ino; + + /* Let all remaining links point to the new file */ + while (1) { + affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5); + mark_buffer_dirty(nbh,1); + key = htonl(FILE_END(nbh->b_data,inode)->link_chain); + affs_brelse(nbh); + iput(ofinode); + if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) + break; + if ((ofinode = iget(inode->i_sb,key))) { + if (!ofinode->u.affs_i.i_hlink) + printk("AFFS: fixup() inode %u in link chain is " + "not a link\n",key); + ofinode->u.affs_i.i_original = link_key; + ofinode->i_dirt = 1; + FILE_END(nbh->b_data,inode)->original = htonl(link_key); + } else + printk("AFFS: fixup(): cannot get inode %u\n",key); + } + /* Turn old inode to a link */ + inode->u.affs_i.i_hlink = 1; + unlock_super(inode->i_sb); + } + return 0; + } else if (type == ST_SOFTLINK) { + return 0; + } else { + printk("AFFS: fixup(): secondary type=%d\n",type); + return -EBADF; + } } diff -u --recursive --new-file v1.3.98/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v1.3.98/linux/fs/affs/symlink.c Tue Apr 23 13:57:11 1996 +++ linux/fs/affs/symlink.c Mon May 6 14:36:05 1996 @@ -1,34 +1,28 @@ /* * linux/fs/affs/symlink.c * - * (C) 1995 Joerg Dorchain Modified for Amiga FFS filesystem - * based on: - * - * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * 1995 Hans-Joachim Widmaier - modified for AFFS. * * Copyright (C) 1991, 1992 Linus Torvalds * - * isofs symlink handling code. This is only used with the Rock Ridge - * extensions to iso9660 + * affs symlink handling code */ -#include - #include #include +#include #include #include -#include #include +#include + +#include -#include "amigaffs.h" +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) static int affs_readlink(struct inode *, char *, int); static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **); -/* - * symlinks can't do much... - */ struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ NULL, /* create */ @@ -47,21 +41,27 @@ NULL /* permission */ }; -static int affs_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) +static int +affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode, + struct inode **res_inode) { - int error; - char * pnt; - struct buffer_head *bh; - struct symlink_front *sy_data; + struct buffer_head *bh; + struct slink_front *lf; + char *buffer; + int error; + int i, j; + char c; + char lc; + pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); + + *res_inode = NULL; if (!dir) { dir = current->fs->root; dir->i_count++; } if (!inode) { iput(dir); - *res_inode = NULL; return -ENOENT; } if (!S_ISLNK(inode->i_mode)) { @@ -70,110 +70,108 @@ return 0; } if (current->link_count > 5) { - iput(dir); iput(inode); - *res_inode = NULL; + iput(dir); return -ELOOP; } - if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) { - printk("affs: unable to read block %ld",inode->i_ino); - return 0; + if (!(buffer = kmalloc(1024,GFP_KERNEL))) { + iput(inode); + iput(dir); + return -ENOSPC; } - - pnt = sy_data->symname; + bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + i = 0; + j = 0; + if (!bh) { + printk("AFFS: unable to read i-node block %lu\n",inode->i_ino); + kfree(buffer); + iput(inode); + iput(dir); + return -EIO; + } + lf = (struct slink_front *)bh->b_data; + lc = 0; + if (strchr(lf->symname,':')) { /* Handle assign or volume name */ + while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i])) + buffer[i++] = c; + while (i < 1023 && lf->symname[j] != ':') + buffer[i++] = lf->symname[j++]; + if (i < 1023) + buffer[i++] = '/'; + j++; + lc = '/'; + } + while (i < 1023 && (c = lf->symname[j])) { + if (c == '/' && lc == '/' && i < 1020) { /* parent dir */ + buffer[i++] = '.'; + buffer[i++] = '.'; + } + buffer[i++] = c; + lc = c; + j++; + } + buffer[i] = '\0'; + affs_brelse(bh); iput(inode); current->link_count++; - error = open_namei(pnt,flag,mode,res_inode,dir); + error = open_namei(buffer,flag,mode,res_inode,dir); current->link_count--; - brelse(bh); + kfree(buffer); return error; } -static char *affs_conv_path(char *affs_path) +static int +affs_readlink(struct inode *inode, char *buffer, int buflen) { -static char unix_path[1024]="/"; -int up,ap; -char dp,slash; - - -dp=1; -slash=1; -ap=0; -up=1; -if (affs_path[0] == 0) - unix_path[up++]='.'; -while ((up < 1020) && (affs_path[ap]!=0)) - { - switch (affs_path[ap]) { - case ':': - if (dp == 0) { - slash=0; - unix_path[up++]=':'; - } - else { - dp=0; - slash=1; - unix_path[up++]='/'; - } - break; - case '/': - if (slash==0) { - slash=1; - unix_path[up++]='/'; - } - else { - unix_path[up++]='.'; - unix_path[up++]='.'; - unix_path[up++]='/'; - } - break; - default: - slash=0; - unix_path[up++]=affs_path[ap]; - break; - } - ap++; - } -unix_path[up]=0; -return unix_path+dp; -} - + struct buffer_head *bh; + struct slink_front *lf; + int i, j; + char c; + char lc; -static int affs_readlink(struct inode * inode, char * buffer, int buflen) -{ - char * pnt; - int i; - char c; - struct buffer_head *bh; - struct symlink_front *sy_data; + pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen); if (!S_ISLNK(inode->i_mode)) { iput(inode); return -EINVAL; } - - if (buflen > 1023) - buflen = 1023; - - if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) { - printk("affs: unable to read block %ld\n",inode->i_ino); - return -ENOENT; + bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + i = 0; + j = 0; + if (!bh) { + printk("AFFS: unable to read i-node block %lu\n",inode->i_ino); + goto symlink_end; } + lf = (struct slink_front *)bh->b_data; + lc = 0; - iput(inode); - - pnt = sy_data->symname; - if (inode->i_sb->u.affs_sb.s_options.conv_links != 0) - pnt = affs_conv_path(pnt); - - i = 0; - - while (isymname,':')) { /* Handle assign or volume name */ + while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) { + put_user(c,buffer++); + i++; + } + while (i < buflen && (c = lf->symname[j]) != ':') { + put_user(c,buffer++); + i++, j++; + } + if (i < buflen) { + put_user('/',buffer++); + i++, j++; + } + lc = '/'; + } + while (i < buflen && (c = lf->symname[j])) { + if (c == '/' && lc == '/' && (i + 3 < buflen)) { /* parent dir */ + put_user('.',buffer++); + put_user('.',buffer++); + i += 2; + } + put_user(c,buffer++); + lc = c; + i++, j++; } - - brelse(bh); - +symlink_end: + iput(inode); + affs_brelse(bh); return i; } diff -u --recursive --new-file v1.3.98/linux/fs/block_dev.c linux/fs/block_dev.c --- v1.3.98/linux/fs/block_dev.c Mon Mar 4 11:25:48 1996 +++ linux/fs/block_dev.c Mon May 6 12:26:13 1996 @@ -225,9 +225,9 @@ if (block + blocks > size) blocks = size - block; - /* We do this in a two stage process. We first try and request + /* We do this in a two stage process. We first try to request as many blocks as we can, then we wait for the first one to - complete, and then we try and wrap up as many as are actually + complete, and then we try to wrap up as many as are actually done. This routine is rather generic, in that it can be used in a filesystem by substituting the appropriate function in for getblk. diff -u --recursive --new-file v1.3.98/linux/fs/buffer.c linux/fs/buffer.c --- v1.3.98/linux/fs/buffer.c Sun May 5 08:52:02 1996 +++ linux/fs/buffer.c Mon May 6 12:26:13 1996 @@ -86,7 +86,7 @@ activate bdflush */ int ndirty; /* Maximum number of dirty blocks to write out per wake-cycle */ - int nrefill; /* Number of clean buffers to try and obtain + int nrefill; /* Number of clean buffers to try to obtain each time we call refill */ int nref_dirt; /* Dirty buffer threshold for activating bdflush when trying to refill buffers. */ @@ -572,7 +572,7 @@ now so as to ensure that there are still clean buffers available for user processes to use (and dirty) */ - /* We are going to try and locate this much memory */ + /* We are going to try to locate this much memory */ needed =bdf_prm.b_un.nrefill * size; while (nr_free_pages > min_free_pages*2 && needed > 0 && @@ -592,7 +592,7 @@ if(needed <= 0) return; }; - /* OK, we cannot grow the buffer cache, now try and get some + /* OK, we cannot grow the buffer cache, now try to get some from the lru list */ /* First set the candidate pointers to usable buffers. This @@ -885,8 +885,7 @@ struct buffer_head * bh; if (!(bh = getblk(dev, block, size))) { - printk("VFS: bread: READ error on device %s\n", - kdevname(dev)); + printk("VFS: bread: impossible error\n"); return NULL; } if (buffer_uptodate(bh)) @@ -1867,7 +1866,7 @@ /* - * Here we attempt to write back old buffers. We also try and flush inodes + * Here we attempt to write back old buffers. We also try to flush inodes * and supers as well, since this function is essentially "update", and * otherwise there would be no way of ensuring that these quantities ever * get written back. Ideally, we would have a timestamp on the inodes diff -u --recursive --new-file v1.3.98/linux/fs/ext/file.c linux/fs/ext/file.c --- v1.3.98/linux/fs/ext/file.c Sun Feb 25 11:17:58 1996 +++ linux/fs/ext/file.c Mon May 6 12:26:13 1996 @@ -113,9 +113,9 @@ blocks = size - block; } - /* We do this in a two stage process. We first try and request + /* We do this in a two stage process. We first try to request as many blocks as we can, then we wait for the first one to - complete, and then we try and wrap up as many as are actually + complete, and then we try to wrap up as many as are actually done. This routine is rather generic, in that it can be used in a filesystem by substituting the appropriate function in for getblk. diff -u --recursive --new-file v1.3.98/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v1.3.98/linux/fs/fat/dir.c Mon Mar 11 11:25:57 1996 +++ linux/fs/fat/dir.c Mon May 6 11:43:19 1996 @@ -380,6 +380,7 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { + int err; /* * We want to provide an interface for Samba to be able * to get the short filename for a given long filename. @@ -389,6 +390,9 @@ switch (cmd) { case VFAT_IOCTL_READDIR_BOTH: { struct dirent *d1 = (struct dirent *)arg; + err = verify_area(VERIFY_WRITE, d1, sizeof (*d1)); + if (err) + return err; put_user(0, &d1->d_reclen); return fat_readdirx(inode,filp,(void *)arg, vfat_ioctl_fill, NULL, 0, 1, 1); @@ -396,6 +400,9 @@ case VFAT_IOCTL_READDIR_SHORT: { struct dirent *d1 = (struct dirent *)arg; put_user(0, &d1->d_reclen); + err = verify_area(VERIFY_WRITE, d1, sizeof (*d1)); + if (err) + return err; return fat_readdirx(inode,filp,(void *)arg, vfat_ioctl_fill, NULL, 1, 0, 1); } diff -u --recursive --new-file v1.3.98/linux/fs/fat/msbuffer.h linux/fs/fat/msbuffer.h --- v1.3.98/linux/fs/fat/msbuffer.h Sat Apr 27 15:19:58 1996 +++ linux/fs/fat/msbuffer.h Mon May 6 07:28:52 1996 @@ -17,8 +17,8 @@ /* These macros exist to avoid modifying all the code */ /* They should be removed one day I guess */ -/* The versioning mechanism of the modules system define those macros */ -/* This remove some warnings */ +/* The versioning mechanism of the modules system defines those macros */ +/* This removes some warnings */ #ifdef brelse #undef brelse #endif diff -u --recursive --new-file v1.3.98/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.3.98/linux/fs/isofs/inode.c Sat Apr 27 15:19:58 1996 +++ linux/fs/isofs/inode.c Mon May 6 07:28:52 1996 @@ -88,15 +88,15 @@ if (strncmp(this_char,"norock",6) == 0) { popt->rock = 'n'; continue; - }; + } if (strncmp(this_char,"unhide",6) == 0) { popt->unhide = 'y'; continue; - }; + } if (strncmp(this_char,"cruft",5) == 0) { popt->cruft = 'y'; continue; - }; + } if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; if (!strcmp(this_char,"map") && value) { @@ -134,7 +134,7 @@ if(*vpnt < '0' || *vpnt > '9') break; ivalue = ivalue * 10 + (*vpnt - '0'); vpnt++; - }; + } if (*vpnt) return 0; switch(*this_char) { case 'b': @@ -241,8 +241,8 @@ while (i != 1){ blocksize_bits++; i >>=1; - }; - }; + } + } set_blocksize(dev, opt.blocksize); lock_super(s); @@ -251,15 +251,15 @@ vol_desc_start = isofs_get_last_session(dev); - for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) { -#if 0 - printk("isofs.inode: iso_blknum=%d\n", iso_blknum); -#endif 0 - if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) { + for (iso_blknum = vol_desc_start+16; + iso_blknum < vol_desc_start+100; iso_blknum++) { + int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); + + if (!(bh = bread(dev,b,opt.blocksize))) { s->s_dev = 0; printk("isofs_read_super: bread failed, dev " - "%s iso_blknum %d\n", - kdevname(dev), iso_blknum); + "%s iso_blknum %d block %d\n", + kdevname(dev), iso_blknum, b); unlock_super(s); MOD_DEC_USE_COUNT; return NULL; @@ -280,7 +280,7 @@ opt.rock = 'n'; h_pri = (struct hs_primary_descriptor *)vdp; break; - }; + } if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) @@ -290,7 +290,7 @@ pri = (struct iso_primary_descriptor *)vdp; break; - }; + } brelse(bh); } @@ -301,8 +301,7 @@ unlock_super(s); MOD_DEC_USE_COUNT; return NULL; - }; - + } if(high_sierra){ rootp = (struct iso_directory_record *) h_pri->root_directory_record; @@ -311,7 +310,7 @@ printk("Multi-volume disks not (yet) supported.\n"); goto out; #endif - }; + } s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); @@ -322,7 +321,7 @@ printk("Multi-volume disks not (yet) supported.\n"); goto out; #endif - }; + } s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); @@ -793,7 +792,7 @@ if(!(bh = bread(parent->i_dev,block,bufsize))) { kfree(cpnt); return -1; - }; + } memcpy((char *)cpnt+frag1, bh->b_data, offset); } diff -u --recursive --new-file v1.3.98/linux/fs/isofs/rock.c linux/fs/isofs/rock.c --- v1.3.98/linux/fs/isofs/rock.c Fri Apr 19 10:08:01 1996 +++ linux/fs/isofs/rock.c Mon May 6 12:26:14 1996 @@ -319,7 +319,7 @@ break; case SIG('T','F'): /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. - Try and handle this correctly for either case. */ + Try to handle this correctly for either case. */ cnt = 0; /* Rock ridge never appears on a High Sierra disk */ if(rr->u.TF.flags & TF_CREATE) inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0); diff -u --recursive --new-file v1.3.98/linux/fs/locks.c linux/fs/locks.c --- v1.3.98/linux/fs/locks.c Sun May 5 08:52:03 1996 +++ linux/fs/locks.c Sun May 5 08:51:12 1996 @@ -639,7 +639,7 @@ locks_free_lock(new_fl); return (-ERESTARTSYS); } - /* Try to avoid deadlocks due to pathalogical programs that + /* Try to avoid deadlocks due to pathological programs that * mix calls to flock() and fcntl(). Return EAGAIN, because * EDEADLOCK isn't a documented return value for flock(). */ diff -u --recursive --new-file v1.3.98/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v1.3.98/linux/fs/nfs/nfsroot.c Sun May 5 08:52:03 1996 +++ linux/fs/nfs/nfsroot.c Mon May 6 12:26:14 1996 @@ -292,7 +292,7 @@ unsigned long sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ - /* If this test doesn't pass, its not IP, or we should ignore it anyway */ + /* If this test doesn't pass, it's not IP, or we should ignore it anyway */ if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) { kfree_skb(skb, FREE_READ); return 0; @@ -763,9 +763,9 @@ */ static void root_do_bootp_ext(u8 *ext) { +#ifdef NFSROOT_BOOTP_DEBUG u8 *c; -#ifdef NFSROOT_BOOTP_DEBUG printk("BOOTP: Got extension %02x",*ext); for(c=ext+2; cmnt_dev = dev; diff -u --recursive --new-file v1.3.98/linux/fs/sysv/file.c linux/fs/sysv/file.c --- v1.3.98/linux/fs/sysv/file.c Sun Feb 25 11:17:58 1996 +++ linux/fs/sysv/file.c Mon May 6 12:26:15 1996 @@ -114,9 +114,9 @@ blocks = size - block; } - /* We do this in a two stage process. We first try and request + /* We do this in a two stage process. We first try to request as many blocks as we can, then we wait for the first one to - complete, and then we try and wrap up as many as are actually + complete, and then we try to wrap up as many as are actually done. This routine is rather generic, in that it can be used in a filesystem by substituting the appropriate function in for getblk. diff -u --recursive --new-file v1.3.98/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v1.3.98/linux/fs/ufs/ufs_super.c Mon Apr 29 18:05:19 1996 +++ linux/fs/ufs/ufs_super.c Sun May 5 12:05:48 1996 @@ -13,6 +13,9 @@ /* * Kernel module support added on 96/04/26 by * Stefan Reinauer + * + * Module usage counts added on 96/04/29 by + * Gertjan van Wingerde */ #include diff -u --recursive --new-file v1.3.98/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v1.3.98/linux/fs/umsdos/namei.c Wed Nov 8 12:33:39 1995 +++ linux/fs/umsdos/namei.c Mon May 6 12:26:15 1996 @@ -433,7 +433,7 @@ in unused entry of the EMD file. The other is to have a separate file dedicated to hold all symbolic links data. - Lets go for simplicity... + Let's go for simplicity... */ struct inode *inode; int ret; diff -u --recursive --new-file v1.3.98/linux/fs/vfat/Makefile linux/fs/vfat/Makefile --- v1.3.98/linux/fs/vfat/Makefile Wed Feb 7 09:39:29 1996 +++ linux/fs/vfat/Makefile Mon May 6 11:43:19 1996 @@ -8,8 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := vfat.o -O_OBJS := namei.o -OX_OBJS := +O_OBJS := +OX_OBJS := namei.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.98/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v1.3.98/linux/fs/vfat/namei.c Sun Apr 21 19:22:11 1996 +++ linux/fs/vfat/namei.c Mon May 6 11:43:19 1996 @@ -1569,12 +1569,26 @@ vfat_read_super, "vfat", 1, NULL }; +static struct symbol_table vfat_syms = { +#include + X(vfat_create), + X(vfat_unlink), + X(vfat_mkdir), + X(vfat_rmdir), + X(vfat_rename), + X(vfat_put_super), + X(vfat_read_super), + X(vfat_read_inode), + X(vfat_lookup), +#include +}; + int init_vfat_fs(void) { int status; if ((status = register_filesystem(&vfat_fs_type)) == 0) - status = register_symtab(0); + status = register_symtab(&vfat_syms); return status; } diff -u --recursive --new-file v1.3.98/linux/fs/xiafs/file.c linux/fs/xiafs/file.c --- v1.3.98/linux/fs/xiafs/file.c Sun Feb 25 11:17:58 1996 +++ linux/fs/xiafs/file.c Mon May 6 12:26:15 1996 @@ -106,9 +106,9 @@ zones = f_zones - zone_nr; } - /* We do this in a two stage process. We first try and request + /* We do this in a two stage process. We first try to request as many blocks as we can, then we wait for the first one to - complete, and then we try and wrap up as many as are actually + complete, and then we try to wrap up as many as are actually done. This routine is rather generic, in that it can be used in a filesystem by substituting the appropriate function in for getblk. diff -u --recursive --new-file v1.3.98/linux/include/asm-i386/locks.h linux/include/asm-i386/locks.h --- v1.3.98/linux/include/asm-i386/locks.h Fri Apr 12 15:52:05 1996 +++ linux/include/asm-i386/locks.h Mon May 6 12:26:15 1996 @@ -21,7 +21,7 @@ while(lock_set_bit(0,&sp->lock)) { /* - * Failed, but thats cos we own it! + * Failed, but that's cos we own it! */ if(sp->cpu==processor) @@ -45,7 +45,7 @@ } /* * Someone wrote the line, we go 'I' and get - * the cache entry. Now try and regrab + * the cache entry. Now try to regrab */ } sp->users++;sp->cpu=processor; @@ -117,7 +117,7 @@ extern __inline__ void spintestlock(struct spinlock *sp) { /* - * We do no sanity checks, its legal to optimistically + * We do no sanity checks, it's legal to optimistically * get a lower lock. */ prim_spin_lock_nb(sp); diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h --- v1.3.98/linux/include/asm-m68k/atomic.h Sat Apr 27 15:19:59 1996 +++ linux/include/asm-m68k/atomic.h Mon May 6 12:44:32 1996 @@ -10,54 +10,32 @@ * We do not have SMP m68k systems, so we don't have to deal with that. */ -/* - * Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. - */ -#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x) - typedef int atomic_t; static __inline__ void atomic_add(atomic_t i, atomic_t *v) { - __asm__ __volatile__( - "addl %1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"ir" (i), "0" (__atomic_fool_gcc(v))); + __asm__ __volatile__("addl %1,%0" : : "m" (*v), "id" (i)); } static __inline__ void atomic_sub(atomic_t i, atomic_t *v) { - __asm__ __volatile__( - "subl %1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"ir" (i), "0" (__atomic_fool_gcc(v))); + __asm__ __volatile__("subl %1,%0" : : "m" (*v), "id" (i)); } static __inline__ void atomic_inc(atomic_t *v) { - __asm__ __volatile__( - "addql #1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"0" (__atomic_fool_gcc(v))); + __asm__ __volatile__("addql #1,%0" : : "m" (*v)); } static __inline__ void atomic_dec(atomic_t *v) { - __asm__ __volatile__( - "subql #1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"0" (__atomic_fool_gcc(v))); + __asm__ __volatile__("subql #1,%0" : : "m" (*v)); } static __inline__ int atomic_dec_and_test(atomic_t *v) { char c; - __asm__ __volatile__( - "subql #1,%0; seq %1" - :"=m" (__atomic_fool_gcc(v)), "=d" (c) - :"0" (__atomic_fool_gcc(v))); + __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c) : "m" (*v)); return c != 0; } diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h --- v1.3.98/linux/include/asm-m68k/bitops.h Sat Apr 27 15:19:59 1996 +++ linux/include/asm-m68k/bitops.h Mon May 6 12:44:32 1996 @@ -111,6 +111,54 @@ return res ^ 31; } +extern __inline__ int find_first_one_bit(void * vaddr, unsigned size) +{ + unsigned long *p = vaddr, *addr = vaddr; + int res; + unsigned long num; + + if (!size) + return 0; + + while (!*p++) + { + if (size <= 32) + return (p - addr) << 5; + size -= 32; + } + + num = *--p; + __asm__ __volatile__ ("bfffo %1{#0,#0},%0" + : "=d" (res) : "d" (num & -num)); + return ((p - addr) << 5) + (res ^ 31); +} + +extern __inline__ int find_next_one_bit (void *vaddr, int size, + int offset) +{ + unsigned long *addr = vaddr; + unsigned long *p = addr + (offset >> 5); + int set = 0, bit = offset & 31UL, res; + + if (offset >= size) + return size; + + if (bit) { + unsigned long num = *p & (~0UL << bit); + + /* Look for one in first longword */ + __asm__ __volatile__ ("bfffo %1{#0,#0},%0" + : "=d" (res) : "d" (num & -num)); + if (res < 32) + return (offset & ~31UL) + (res ^ 31); + set = 32 - bit; + p++; + } + /* No one yet, search remaining full bytes for a one */ + res = find_first_one_bit (p, size - 32 * (p - addr)); + return (offset + set + res); +} + /* Bitmap functions for the minix filesystem */ extern __inline__ int diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/checksum.h linux/include/asm-m68k/checksum.h --- v1.3.98/linux/include/asm-m68k/checksum.h Tue Apr 23 13:57:12 1996 +++ linux/include/asm-m68k/checksum.h Mon May 6 12:44:32 1996 @@ -108,7 +108,6 @@ * in icmp.c */ -#if 1 static inline unsigned short ip_compute_csum(unsigned char * buff, int len) { @@ -124,52 +123,5 @@ : "0" (csum_partial(buff, len, 0))); return ~sum; } -#else -static inline unsigned short -ip_compute_csum(unsigned char * buff, int len) -{ - unsigned long sum = 0; - - /* Do the first multiple of 4 bytes and convert to 16 bits. */ - if (len > 3) - { - int dummy; - __asm__ ("subql #1,%2\n\t" - "1:\t" - "movel %1@+,%/d0\n\t" - "addxl %/d0,%0\n\t" - "dbra %2,1b\n\t" - "movel %0,%/d0\n\t" - "swap %/d0\n\t" - "addxw %/d0,%0\n\t" - "clrw %/d0\n\t" - "addxw %/d0,%0" - : "=d" (sum), "=a" (buff), "=d" (dummy) - : "0" (sum), "1" (buff), "2" (len >> 2) - : "d0"); - } - if (len & 2) - { - __asm__ ("addw %1@+,%0\n\t" - "addxw %2,%0" - : "=d" (sum), "=a" (buff) - : "d" (0), "0" (sum), "1" (buff)); - } - if (len & 1) - { - __asm__ ("movew %1@,%/d0\n\t" - "clrb %/d0\n\t" - "addw %/d0,%0\n\t" - "clrw %/d0\n\t" - "addxw %/d0,%0" - : "=d" (sum) - : "a" (buff), "0" (sum) - : "d0"); - } - - sum =~sum; - return(sum & 0xffff); -} -#endif #endif /* _M68K_CHECKSUM_H */ diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h --- v1.3.98/linux/include/asm-m68k/elf.h Tue Apr 23 13:57:12 1996 +++ linux/include/asm-m68k/elf.h Mon May 6 12:44:32 1996 @@ -12,11 +12,6 @@ #define ELF_NGREG 20 /* d1-d7/a0-a6/d0/usp/orig_d0/sr/pc/fmtvec */ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -/* XXX temporary */ -/* -typedef unsigned long elf_fpregset_t; -*/ - typedef struct user_m68kfp_struct elf_fpregset_t; #endif diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h --- v1.3.98/linux/include/asm-m68k/pgtable.h Sat Apr 27 15:19:59 1996 +++ linux/include/asm-m68k/pgtable.h Mon May 6 12:44:32 1996 @@ -14,7 +14,6 @@ __asm__ __volatile__("pflusha\n"::); \ } while (0) -#if 1 static inline void __flush_tlb_one(unsigned long addr) { if (m68k_is040or060) { @@ -24,9 +23,6 @@ } else __asm__ __volatile__("pflush #0,#0,(%0)" : : "a" (addr)); } -#else -#define __flush_tlb_one(addr) __flush_tlb() -#endif #define flush_tlb() __flush_tlb() #define flush_tlb_all() flush_tlb() @@ -573,15 +569,14 @@ /* * I don't know what is going on here, but since these were changed, - * swapping haven't been working on the 68040. + * swapping hasn't been working on the 68040. */ -#if 0 #define SWP_TYPE(entry) (((entry) >> 2) & 0x7f) +#if 0 #define SWP_OFFSET(entry) ((entry) >> 9) #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9)) #else -#define SWP_TYPE(entry) (((entry) & 0x1fc) >> 2) #define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT) #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT)) #endif diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h --- v1.3.98/linux/include/asm-m68k/serial.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-m68k/serial.h Mon May 6 12:44:32 1996 @@ -0,0 +1,380 @@ +/* + * include/linux/serial.h + * + * Copyright (C) 1992 by Theodore Ts'o. + * + * Redistribution of this file is permitted under the terms of the GNU + * Public License (GPL) + */ + +#ifndef _M68K_SERIAL_H +#define _M68K_SERIAL_H + + +/* m68k serial port types are numbered from 100 to avoid interference + * with the PC types (1..4) + */ +#define PORT_UNKNOWN 0 +#define PORT_8250 1 +#define PORT_16450 2 +#define PORT_16550 3 +#define PORT_16550A 4 +#define PORT_CIRRUS 5 +#define SER_SCC_NORM 100 /* standard SCC channel */ +#define SER_SCC_DMA 101 /* SCC channel with DMA support */ +#define SER_MFP_CTRL 102 /* standard MFP port with modem control signals */ +#define SER_MFP_BARE 103 /* MFP port without modem controls */ +#define SER_MIDI 104 /* Atari MIDI */ +#define SER_AMIGA 105 /* Amiga built-in serial port */ +#define SER_IOEXT 106 /* Amiga GVP IO-Extender (16c552) */ +#define SER_MFC_III 107 /* Amiga BSC Multiface Card III (MC68681) */ + + +struct serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + int reserved[4]; +}; + +/* + * For the close wait times, 0 means wait forever for serial port to + * flush its output. 65535 means don't wait at all. + */ +#define ASYNC_CLOSING_WAIT_INF 0 +#define ASYNC_CLOSING_WAIT_NONE 65535 + +/* This function tables does the abstraction from the underlying + * hardware: + * + * init(): Initialize the port as necessary, set RTS and DTR and + * enable interrupts. It does not need to set the speed and other + * parameters, because change_speed() is called, too. + * deinit(): Stop and shutdown the port (e.g. disable interrupts, ...) + * enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt + * independently from other interrupt sources. If the int is + * enabled, the transmitter should also be restarted, i.e. if there + * are any chars to be sent, they should be put into the Tx + * register. The real en/disabling of the interrupt may be a no-op + * if there is no way to do this or it is too complex. This Tx ints + * are just disabled to save some interrupts if the transmitter is + * stopped anyway. But the restarting must be implemented! + * check_custom_divisor(): Check the given custom divisor for legality + * and return 0 if OK, non-zero otherwise. + * change_speed(): Set port speed, character size, number of stop + * bits and parity from the termios structure. If the user wants + * to set the speed with a custom divisor, he is required to + * check the baud_base first! + * throttle(): Set or clear the RTS line according to 'status'. + * set_break(): Set or clear the 'Send a Break' flag. + * get_serial_info(): Fill in the baud_base and custom_divisor + * fields of a serial_struct. It may also modify other fields, if + * needed. + * get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS. + * set_modem_info(): Set the status of RTS and DTR according to + * 'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change + * ioctl(): Process any port-specific ioctl's. This pointer may be + * NULL, if the port has no own ioctl's. + * stop_receive(): Turn off the Rx part of the port, so no more characters + * will be received. This is called before shutting the port down. + * trans_empty(): Return !=0 if there are no more characters still to be + * sent out (Tx buffer register and FIFOs empty) + * check_open(): Is called before the port is opened. The driver can check + * if that's ok and return an error code, or keep track of the opening + * even before init() is called. Use deinit() for matching closing of the + * port. + * + */ + +struct async_struct; + +typedef struct { + void (*init)( struct async_struct *info ); + void (*deinit)( struct async_struct *info, int leave_dtr ); + void (*enab_tx_int)( struct async_struct *info, int enab_flag ); + int (*check_custom_divisor)( struct async_struct *info, int baud_base, + int divisor ); + void (*change_speed)( struct async_struct *info ); + void (*throttle)( struct async_struct *info, int status ); + void (*set_break)( struct async_struct *info, int break_flag ); + void (*get_serial_info)( struct async_struct *info, + struct serial_struct *retinfo ); + unsigned int (*get_modem_info)( struct async_struct *info ); + int (*set_modem_info)( struct async_struct *info, int new_dtr, + int new_rts ); + int (*ioctl)( struct tty_struct *tty, struct file *file, + struct async_struct *info, unsigned int cmd, + unsigned long arg ); + void (*stop_receive)( struct async_struct *info ); + int (*trans_empty)( struct async_struct *info ); + int (*check_open)( struct async_struct *info, struct tty_struct *tty, + struct file *file ); +} SERIALSWITCH; + +/* + * Definitions for async_struct (and serial_struct) flags field + */ +#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define ASYNC_SPD_MASK 0x0030 +#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ + +#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define ASYNC_FLAGS 0x0FFF /* Possible legal async flags */ +#define ASYNC_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by drivers/char/m68kserial.c */ +#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */ +#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +/* + * Serial input interrupt line counters -- external structure + * Four lines can interrupt: CTS, DSR, RI, DCD + */ +struct serial_icounter_struct { + int cts, dsr, rng, dcd; + int reserved[16]; +}; + + +#ifdef __KERNEL__ +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * For definitions of the flags field, see tty.h + */ + +#include +#include + +/* + * Counters of the input lines (CTS, DSR, RI, CD) interrupts + */ +struct async_icount { + __u32 cts, dsr, rng, dcd; +}; + +struct async_struct { + int magic; + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int hub6; /* HUB6 plus one */ + int type; + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + int IER; /* Interrupt Enable Register */ + int MCR; /* Modem control register */ + int MCR_noint; /* MCR with interrupts off */ + unsigned long event; + unsigned long last_active; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; + struct wait_queue *delta_msr_wait; + struct async_icount icount; /* kernel counters for the 4 input interrupts */ + struct async_struct *next_port; /* For the linked list */ + struct async_struct *prev_port; + void *board_base; /* board-base address for use with + boards carrying several UART's, + like some Amiga boards. */ + unsigned short nr_uarts; /* UART-counter, that indicates + how manu UART's there are on + the board. If the board has a + IRQ-register, this can be used + to check if any of the uarts, + on the board has requested an + interrupt, instead of checking + IRQ-registers on all UART's */ + SERIALSWITCH *sw; /* functions to manage this port */ +}; + +#define SERIAL_MAGIC 0x5301 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ +#define SERIAL_XMIT_SIZE 4096 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Export to allow PCMCIA to use this - Dave Hinds */ +extern int register_serial(struct serial_struct *req); +extern void unregister_serial(int line); +extern struct async_struct rs_table[]; +extern task_queue tq_serial; + + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static __inline__ void rs_sched_event(struct async_struct *info, int event) +{ + info->event |= 1 << event; + queue_task_irq(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static __inline__ void rs_receive_char( struct async_struct *info, + int ch, int err ) +{ + struct tty_struct *tty = info->tty; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + return; + tty->flip.count++; + if (err == TTY_BREAK) { + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } + *tty->flip.flag_buf_ptr++ = err; + *tty->flip.char_buf_ptr++ = ch; + queue_task_irq(&tty->flip.tqueue, &tq_timer); +} + +static __inline__ int rs_get_tx_char( struct async_struct *info ) +{ + unsigned char ch; + + if (info->x_char) { + ch = info->x_char; + info->x_char = 0; + return( ch ); + } + + if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped) + return( -1 ); + + ch = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail &= SERIAL_XMIT_SIZE - 1; + if (--info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return( ch ); +} + +static __inline__ int rs_no_more_tx( struct async_struct *info ) +{ + return( info->xmit_cnt <= 0 || + info->tty->stopped || + info->tty->hw_stopped ); +} + +static __inline__ void rs_dcd_changed( struct async_struct *info, int dcd ) + +{ + /* update input line counter */ + info->icount.dcd++; + wake_up_interruptible(&info->delta_msr_wait); + + if (info->flags & ASYNC_CHECK_CD) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttyS%d CD now %s...", info->line, + dcd ? "on" : "off"); +#endif + if (dcd) { + wake_up_interruptible(&info->open_wait); + } else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("scheduling hangup..."); +#endif + queue_task_irq(&info->tqueue_hangup, + &tq_scheduler); + } + } +} + + +void rs_stop( struct tty_struct *tty ); +void rs_start( struct tty_struct *tty ); + +static __inline__ void rs_check_cts( struct async_struct *info, int cts ) +{ + /* update input line counter */ + info->icount.cts++; + wake_up_interruptible(&info->delta_msr_wait); + + if ((info->flags & ASYNC_CTS_FLOW) && info->tty) + if (info->tty->hw_stopped) { + if (cts) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + rs_start( info->tty ); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!cts) { + info->tty->hw_stopped = 1; + rs_stop( info->tty ); + } + } + +} + + +#endif /* __KERNEL__ */ + +#endif /* _M68K_SERIAL_H */ diff -u --recursive --new-file v1.3.98/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h --- v1.3.98/linux/include/asm-m68k/system.h Sat Apr 27 15:19:59 1996 +++ linux/include/asm-m68k/system.h Mon May 6 12:44:32 1996 @@ -64,6 +64,7 @@ #endif /* machine compilation types */ #define cli() __asm__ __volatile__ ("oriw #0x0700,%/sr": : : "memory") #define nop() __asm__ __volatile__ ("nop"::) +#define mb() __asm__ __volatile__ ("" : : :"memory") #define save_flags(x) \ __asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory") diff -u --recursive --new-file v1.3.98/linux/include/asm-mips/shmparam.h linux/include/asm-mips/shmparam.h --- v1.3.98/linux/include/asm-mips/shmparam.h Wed Dec 13 12:39:46 1995 +++ linux/include/asm-mips/shmparam.h Mon May 6 12:26:15 1996 @@ -39,7 +39,7 @@ #define SHMALL /* max shm system wide (pages) */ \ (1<<(_SHM_IDX_BITS+_SHM_ID_BITS)) /* - * This constant is very large but the ABI in it's wisdom says ... + * This constant is very large but the ABI in its wisdom says ... */ #define SHMLBA 0x40000 /* attach addr a multiple of this */ #define SHMSEG SHMMNI /* max shared segs per process */ diff -u --recursive --new-file v1.3.98/linux/include/asm-sparc/floppy.h linux/include/asm-sparc/floppy.h --- v1.3.98/linux/include/asm-sparc/floppy.h Mon Apr 29 18:05:19 1996 +++ linux/include/asm-sparc/floppy.h Mon May 6 12:26:16 1996 @@ -290,7 +290,7 @@ /* We certainly don't have a floppy controller. */ goto no_sun_fdc; } - /* Well, try and find one. */ + /* Well, try to find one. */ tnode = prom_getchild(prom_root_node); fd_node = prom_searchsiblings(tnode, "obio"); if(fd_node != 0) { diff -u --recursive --new-file v1.3.98/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h --- v1.3.98/linux/include/asm-sparc/head.h Sat Apr 27 15:20:04 1996 +++ linux/include/asm-sparc/head.h Mon May 6 12:26:16 1996 @@ -90,7 +90,7 @@ #define NMI_TRAP \ rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop; -/* Window overflows/underflows are special and we need to try and be as +/* Window overflows/underflows are special and we need to try to be as * efficient as possible here.... */ #define WINDOW_SPILL \ diff -u --recursive --new-file v1.3.98/linux/include/asm-sparc/kdebug.h linux/include/asm-sparc/kdebug.h --- v1.3.98/linux/include/asm-sparc/kdebug.h Mon Mar 4 08:50:00 1996 +++ linux/include/asm-sparc/kdebug.h Mon May 6 12:26:16 1996 @@ -26,7 +26,7 @@ #ifndef __ASSEMBLY__ /* The debug vector is passed in %o1 at boot time. It is a pointer to - * a structure in the debuggers address space. Here is it's format. + * a structure in the debuggers address space. Here is its format. */ typedef unsigned int (*debugger_funct)(void); diff -u --recursive --new-file v1.3.98/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h --- v1.3.98/linux/include/asm-sparc/smp.h Wed Apr 24 17:00:42 1996 +++ linux/include/asm-sparc/smp.h Mon May 6 12:26:16 1996 @@ -26,7 +26,7 @@ /* Per processor Sparc parameters we need. */ struct cpuinfo_sparc { - unsigned long udelay_val; /* thats it */ + unsigned long udelay_val; /* that's it */ }; extern struct cpuinfo_sparc cpu_data[NR_CPUS]; diff -u --recursive --new-file v1.3.98/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h --- v1.3.98/linux/include/asm-sparc/system.h Sun Apr 21 19:22:13 1996 +++ linux/include/asm-sparc/system.h Mon May 6 12:26:16 1996 @@ -40,7 +40,7 @@ #define halt() romvec->pv_halt() /* When a context switch happens we must flush all user windows so that - * the windows of the current process are flushed onto it's stack. This + * the windows of the current process are flushed onto its stack. This * way the windows are all clean for the next process and the stack * frames are up to date. */ diff -u --recursive --new-file v1.3.98/linux/include/linux/a.out.h linux/include/linux/a.out.h --- v1.3.98/linux/include/linux/a.out.h Sun Apr 21 19:22:15 1996 +++ linux/include/linux/a.out.h Mon May 6 12:44:32 1996 @@ -129,7 +129,7 @@ #ifdef linux #include -#ifdef __i386__ +#if defined(__i386__) || defined(__mc68000__) #define SEGMENT_SIZE 1024 #else #ifndef SEGMENT_SIZE diff -u --recursive --new-file v1.3.98/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h --- v1.3.98/linux/include/linux/affs_fs.h Tue Apr 23 13:57:13 1996 +++ linux/include/linux/affs_fs.h Mon May 6 14:58:39 1996 @@ -1,101 +1,104 @@ - #ifndef _AFFS_FS_H #define _AFFS_FS_H - -#include /* * The affs filesystem constants/structures */ -#define AFFS_BLOCK_BITS 9 -#define AFFS_BLOCK_SIZE 512 - -#define AFFS_BUFFER_BITS 9 -#define AFFS_BUFFER_SIZE 512 - -#define AFFS_BLOCK_NUMBER(X) (X<<1) +#include +#include #define AFFS_SUPER_MAGIC 0xadff /* Get the filesystem block size given an inode. */ -#define AFFS_I2BSIZE(inode) ((inode)->i_sb->u.affs_sb.s_block_size) +#define AFFS_I2BSIZE(inode) ((inode)->i_sb->s_blocksize) -/* Read the device block that contains filesystem block ("sector"). */ +/* Get the filesystem hash table size given an inode. */ +#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize) -static inline struct buffer_head *affs_sread(int dev,int sector,void **start) -{ - struct buffer_head *bh; - int mask; - - bh = bread (dev, sector >> (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS), 1024); - if (!bh) - return NULL; - mask = (1 << (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS)) - 1; - *start = bh->b_data + ((sector & mask) << AFFS_BLOCK_BITS); - return bh; -} - -/* Use affs_sread() to read a "sector", but take the filesystems partition - offset into account. */ - -static inline struct buffer_head *affs_pread(struct inode *inode, - int sector, void **start) -{ - int offset = inode->i_sb->u.affs_sb.s_partition_offset; - return affs_sread (inode->i_dev, sector + offset, start); -} - -/* amigaffs.c prototypes */ - -extern int affs_get_key_entry (int bsize, void *data, int entry_pos); -extern int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos); -extern int affs_get_fh_hash_link (int bsize, void *fh_data); -extern int affs_get_file_name (int bsize, void *fh_data, char **name); -extern int affs_get_extension (int bsize, void *fh_data); -extern int affs_checksum_block (int bsize, void *data, int *ptype, int *stype); - -/* The stuff that follows may be totally unneeded. I have not checked to see - which prototypes we are still using. */ - -extern int affs_open(struct inode * inode, struct file * filp); -extern void affs_release(struct inode * inode, struct file * filp); -extern int affs_lookup(struct inode * dir,const char * name, int len, - struct inode ** result); -extern unsigned long affs_count_free_inodes(struct super_block *sb); -extern int affs_new_block(int dev); -extern int affs_free_block(int dev, int block); -extern int affs_bmap(struct inode *,int); - -extern void affs_put_super(struct super_block *); -extern struct super_block *affs_read_super(struct super_block *,void *,int); -extern void affs_read_inode(struct inode *); -extern void affs_put_inode(struct inode *); -extern void affs_statfs(struct super_block *, struct statfs *, int); -extern int affs_parent_ino(struct inode *dir); -extern int affs_lseek(struct inode *, struct file *, off_t, int); -extern int affs_read(struct inode *, struct file *, char *, int); -extern int affs_file_read(struct inode *, struct file *, char *, int); -extern int init_affs_fs(void); +/* Get the block number bits given an inode */ +#define AFFS_I2BITS(inode) ((inode)->i_sb->s_blocksize_bits) -extern struct inode_operations affs_file_inode_operations; -extern struct inode_operations affs_dir_inode_operations; -extern struct inode_operations affs_symlink_inode_operations; -extern struct inode_operations affs_chrdev_inode_operations; -extern struct inode_operations affs_blkdev_inode_operations; - -extern struct file_operations affs_file_operations; -extern struct file_operations affs_dir_operations; - -/* The following macros are used to check for memory leaks. */ -#ifdef LEAK_CHECK -#define free_s leak_check_free_s -#define malloc leak_check_malloc -#define bread leak_check_bread -#define brelse leak_check_brelse -extern void * leak_check_malloc(unsigned int size); -extern void leak_check_free_s(void * obj, int size); -extern struct buffer_head * leak_check_bread(int dev, int block, int size); -extern void leak_check_brelse(struct buffer_head * bh); -#endif /* LEAK_CHECK */ +/* Get the fs type given an inode */ +#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL) + +/* --- Prototypes ----------------------------------------------------------------------------- */ + +/* amigaffs.c */ + +extern int affs_get_key_entry(int bsize, void *data, int entry_pos); +extern int affs_find_next_hash_entry(int bsize, void *dir_data, ULONG *hash_pos); +extern int affs_get_file_name(int bsize, void *fh_data, char **name); +extern ULONG affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype); +extern void affs_fix_checksum(int bsize, void *data, int cspos); +extern void secs_to_datestamp(int secs, struct DateStamp *ds); +extern int prot_to_mode(ULONG prot); +extern ULONG mode_to_prot(int mode); +extern int affs_fix_hash_pred(struct inode *startino, int startoffset, + LONG key, LONG newkey); +extern int affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey); + +/* bitmap. c */ + +extern int affs_count_free_blocks(struct super_block *s); +extern int affs_count_free_bits(int blocksize, const UBYTE *data); +extern void affs_free_block(struct super_block *sb, LONG block); +extern LONG affs_new_header(struct inode *inode); +extern LONG affs_new_data(struct inode *inode); +extern void affs_make_zones(struct super_block *sb); + +/* namei.c */ + +extern int affs_hash_name(const char *name, int len, int intl, int hashsize); +extern int affs_lookup(struct inode *dir,const char *name, int len, + struct inode **result); +extern int affs_unlink(struct inode *dir, const char *name, int len); +extern int affs_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result); +extern int affs_mkdir(struct inode *dir, const char *name, int len, int mode); +extern int affs_rmdir(struct inode *dir, const char *name, int len); +extern int affs_link(struct inode *oldinode, struct inode *dir, + const char *name, int len); +extern int affs_symlink(struct inode *dir, const char *name, int len, + const char *symname); +extern int affs_fixup(struct buffer_head *bh, struct inode *inode); +extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len); + +/* inode.c */ + +extern struct buffer_head *affs_bread(kdev_t dev, int block, int size); +extern void affs_brelse(struct buffer_head *buf); +extern void affs_put_super(struct super_block *); +extern int affs_parent_ino(struct inode *dir); +extern struct super_block *affs_read_super(struct super_block *,void *, int); +extern void affs_statfs(struct super_block *, struct statfs *, int bufsiz); +extern void affs_read_inode(struct inode *); +extern void affs_write_inode(struct inode *); +extern int affs_notify_change(struct inode *inode, struct iattr *attr); +extern void affs_put_inode(struct inode *); +extern struct inode *affs_new_inode(const struct inode *dir); +extern int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, + const char *name, int len, LONG type); + +/* file.c */ + +extern int affs_bmap(struct inode *inode, int block); +extern struct buffer_head *affs_getblock(struct inode *inode, int block); +extern void affs_truncate(struct inode *); +extern void affs_truncate_ofs(struct inode *); + +/* dir.c */ + +extern void affs_dir_truncate(struct inode *); + +/* jump tables */ + +extern struct inode_operations affs_file_inode_operations; +extern struct inode_operations affs_file_inode_operations_ofs; +extern struct inode_operations affs_dir_inode_operations; +extern struct inode_operations affs_symlink_inode_operations; +extern struct inode_operations affs_chrdev_inode_operations; +extern struct inode_operations affs_blkdev_inode_operations; +extern int init_affs_fs(void); #endif diff -u --recursive --new-file v1.3.98/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h --- v1.3.98/linux/include/linux/affs_fs_i.h Tue Apr 23 13:57:13 1996 +++ linux/include/linux/affs_fs_i.h Mon May 6 12:44:32 1996 @@ -1,12 +1,25 @@ #ifndef _AFFS_FS_I #define _AFFS_FS_I +#define EXT_CACHE_SIZE 16 +#define MAX_PREALLOC 8 /* MUST be a power of 2 */ + /* * affs fs inode data in memory */ struct affs_inode_info { int i_protect; /* unused attribute bits */ int i_parent; /* parent ino */ + int i_original; /* if != 0, this is the key of the original */ + __u32 i_ext[EXT_CACHE_SIZE]; /* extension block numbers */ + __u32 i_data[MAX_PREALLOC]; /* preallocated blocks */ + short i_max_ext; /* last known extension block */ + short i_pa_cnt; /* number of preallocated blocks */ + short i_pa_next; /* Index of next block in i_data[] */ + short i_pa_last; /* Index of next free slot in i_data[] */ + short i_zone; /* write zone */ + unsigned char i_hlink; /* This is a fake */ + unsigned char i_pad; }; #endif diff -u --recursive --new-file v1.3.98/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h --- v1.3.98/linux/include/linux/affs_fs_sb.h Tue Apr 23 13:57:13 1996 +++ linux/include/linux/affs_fs_sb.h Mon May 6 14:03:07 1996 @@ -4,34 +4,63 @@ /* * super-block data in memory * - * Block numbers are for FFS-sized (normally 512 bytes) blocks. + * Block numbers are adjusted for their actual size * */ -/* Mount options */ +#include -struct affs_options { - int offset; - int size; - int root; - int nocase:1; /* Ignore case in filenames. */ - int conv_links:1; /* convert pathnames symlinks point to */ +#define MAX_ZONES 8 +#define AFFS_DATA_MIN_FREE 30 /* Percentage of free blocks needed for a data zone */ +#define AFFS_HDR_MIN_FREE 10 /* Same for header blocks */ + +struct affs_bm_info { + struct buffer_head *bm_bh; /* Buffer for bitmap. */ + int bm_free; /* Free blocks. */ + int bm_size; /* Size in bits, rounded to multiple of 32. */ + int bm_firstblk; /* Block number of first bit in this map */ +}; + +struct affs_zone { + unsigned long z_ino; /* Associated inode number */ + struct affs_bm_info *z_bm; /* Zone lies in this bitmap */ + int z_start; /* Index of first word in bitmap */ + int z_zone_no; /* Zone number */ + unsigned long z_lru_time; /* Time of last usage */ }; struct affs_sb_info { - int s_partition_offset; /* Offset to start in blocks. */ int s_partition_size; /* Partition size in blocks. */ - int s_root_block; /* Absolute FFS root block number. */ - int s_block_size; /* Block size in bytes. */ - char s_volume_name[42]; - struct affs_options s_options; + int s_root_block; /* FFS root block number. */ + int s_hashsize; /* Size of hash table. */ + unsigned long s_flags; /* See below. */ + short s_uid; /* uid to override */ + short s_gid; /* gid to override */ + umode_t s_mode; /* mode to override */ + int s_reserved; /* Number of reserved blocks. */ + struct buffer_head *s_root_bh; /* Cached root block. */ + struct affs_bm_info *s_bitmap; /* Bitmap infos. */ + int s_bm_count; /* Number of bitmap blocks. */ + int s_nextzone; /* Next zone to look for free blocks. */ + int s_num_zones; /* Total number of zones. */ + struct affs_zone *s_zones; /* The zones themselfes. */ + char *s_zonemap; /* Bitmap for zones. */ + char *s_prefix; /* Prefix for volumes and assignes. */ + int s_prefix_len; /* Length of prefix. */ + char s_volume[32]; /* Volume prefix for absolute symlinks. */ }; -#endif - - - - - - +#define SF_INTL 0x0001 /* International filesystem. */ +#define SF_BM_VALID 0x0002 /* Bitmap is valid. */ +#define SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */ +#define SF_QUIET 0x0008 /* chmod errors will be not reported */ +#define SF_SETUID 0x0010 /* Ignore Amiga uid */ +#define SF_SETGID 0x0020 /* Ignore Amiga gid */ +#define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */ +#define SF_USE_MP 0x0080 /* Use uid and gid from mount point */ +#define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */ +#define SF_OFS 0x0200 /* Old filesystem */ +#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ +#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */ +#endif diff -u --recursive --new-file v1.3.98/linux/include/linux/affs_hardblocks.h linux/include/linux/affs_hardblocks.h --- v1.3.98/linux/include/linux/affs_hardblocks.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/affs_hardblocks.h Mon May 6 12:44:32 1996 @@ -0,0 +1,70 @@ +#ifndef AFFS_HARDBLOCKS_H +#define AFFS_HARDBLOCKS_H + +/* Just the needed definitions for the RDB of an Amiga HD. */ + +#ifndef AMIGAFFS_H +#include +#endif + +struct RigidDiskBlock { + ULONG rdb_ID; + ULONG rdb_SummedLongs; + LONG rdb_ChkSum; + ULONG rdb_HostID; + ULONG rdb_BlockBytes; + ULONG rdb_Flags; + ULONG rdb_BadBlockList; + ULONG rdb_PartitionList; + ULONG rdb_FileSysHeaderList; + ULONG rdb_DriveInit; + ULONG rdb_Reserved1[6]; + ULONG rdb_Cylinders; + ULONG rdb_Sectors; + ULONG rdb_Heads; + ULONG rdb_Interleave; + ULONG rdb_Park; + ULONG rdb_Reserved2[3]; + ULONG rdb_WritePreComp; + ULONG rdb_ReducedWrite; + ULONG rdb_StepRate; + ULONG rdb_Reserved3[5]; + ULONG rdb_RDBBlocksLo; + ULONG rdb_RDBBlocksHi; + ULONG rdb_LoCylinder; + ULONG rdb_HiCylinder; + ULONG rdb_CylBlocks; + ULONG rdb_AutoParkSeconds; + ULONG rdb_HighRDSKBlock; + ULONG rdb_Reserved4; + char rdb_DiskVendor[8]; + char rdb_DiskProduct[16]; + char rdb_DiskRevision[4]; + char rdb_ControllerVendor[8]; + char rdb_ControllerProduct[16]; + char rdb_ControllerRevision[4]; + ULONG rdb_Reserved5[10]; +}; + +#define IDNAME_RIGIDDISK 0x5244534B /* "RDSK" */ + +struct PartitionBlock { + ULONG pb_ID; + ULONG pb_SummedLongs; + LONG pb_ChkSum; + ULONG pb_HostID; + ULONG pb_Next; + ULONG pb_Flags; + ULONG pb_Reserved1[2]; + ULONG pb_DevFlags; + UBYTE pb_DriveName[32]; + ULONG pb_Reserved2[15]; + ULONG pb_Environment[17]; + ULONG pb_EReserved[15]; +}; + +#define IDNAME_PARTITION 0x50415254 /* "PART" */ + +#define RDB_ALLOCATION_LIMIT 16 + +#endif /* AFFS_HARDBLOCKS_H */ diff -u --recursive --new-file v1.3.98/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h --- v1.3.98/linux/include/linux/amigaffs.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/amigaffs.h Mon May 6 14:02:33 1996 @@ -0,0 +1,224 @@ +#ifndef AMIGAFFS_H +#define AMIGAFFS_H + +#include +#include + +/* Ugly macros make the code more pretty. */ + +#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st)))) +#define AFFS_GET_HASHENTRY(data,hashkey) htonl(((struct dir_front *)data)->hashtable[hashkey]) +#define AFFS_BLOCK(data,ino,blk) ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-blk] + +#define FILE_END(p,i) GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i)) +#define ROOT_END(p,i) GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i)) +#define DIR_END(p,i) GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i)) +#define LINK_END(p,i) GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i)) +#define ROOT_END_S(p,s) GET_END_PTR(struct root_end,p,(s)->s_blocksize) + +/* Only for easier debugging if need be */ +#define affs_bread bread +#define affs_brelse brelse + +#ifdef __LITTLE_ENDIAN +#define BO_EXBITS 0x18UL +#elif defined(__BIG_ENDIAN) +#define BO_EXBITS 0x00UL +#else +#error Endianess must be known for affs to work. +#endif + +/* The following constants will be checked against the values read native */ + +#define FS_OFS 0x444F5300 +#define FS_FFS 0x444F5301 +#define FS_INTLOFS 0x444F5302 +#define FS_INTLFFS 0x444F5303 +#define FS_DCOFS 0x444F5304 +#define FS_DCFFS 0x444F5305 +#define MUFS_FS 0x6d754653 /* 'muFS' */ +#define MUFS_OFS 0x6d754600 /* 'muF\0' */ +#define MUFS_FFS 0x6d754601 /* 'muF\1' */ +#define MUFS_INTLOFS 0x6d754602 /* 'muF\2' */ +#define MUFS_INTLFFS 0x6d754603 /* 'muF\3' */ +#define MUFS_DCOFS 0x6d754604 /* 'muF\4' */ +#define MUFS_DCFFS 0x6d754605 /* 'muF\5' */ + +typedef __u32 ULONG; +typedef __u16 UWORD; +typedef __u8 UBYTE; + +typedef __s32 LONG; +typedef __s16 WORD; +typedef __s8 BYTE; + +struct DateStamp +{ + ULONG ds_Days; + ULONG ds_Minute; + ULONG ds_Tick; +}; + +#define T_SHORT 2 +#define T_LIST 16 +#define T_DATA 8 + +#define ST_LINKFILE -4 +#define ST_FILE -3 +#define ST_ROOT 1 +#define ST_USERDIR 2 +#define ST_SOFTLINK 3 +#define ST_LINKDIR 4 + +struct root_front +{ + LONG primary_type; + ULONG spare1[2]; + ULONG hash_size; + ULONG spare2; + ULONG checksum; + ULONG hashtable[0]; +}; + +struct root_end +{ + LONG bm_flag; + ULONG bm_keys[25]; + ULONG bm_extend; + struct DateStamp dir_altered; + UBYTE disk_name[40]; + struct DateStamp disk_altered; + struct DateStamp disk_made; + ULONG spare1[3]; + LONG secondary_type; +}; + +struct dir_front +{ + LONG primary_type; + ULONG own_key; + ULONG spare1[3]; + ULONG checksum; + ULONG hashtable[0]; +}; + +struct dir_end +{ + ULONG spare1; + UWORD owner_uid; + UWORD owner_gid; + ULONG protect; + ULONG spare2; + UBYTE comment[92]; + struct DateStamp created; + UBYTE dir_name[32]; + ULONG spare3[2]; + ULONG link_chain; + ULONG spare4[5]; + ULONG hash_chain; + ULONG parent; + ULONG spare5; + LONG secondary_type; +}; + +struct file_front +{ + LONG primary_type; + ULONG own_key; + ULONG block_count; + ULONG unknown1; + ULONG first_data; + ULONG checksum; + ULONG blocks[0]; +}; + +struct file_end +{ + ULONG spare1; + UWORD owner_uid; + UWORD owner_gid; + ULONG protect; + ULONG byte_size; + UBYTE comment[92]; + struct DateStamp created; + UBYTE file_name[32]; + ULONG spare2; + ULONG original; /* not really in file_end */ + ULONG link_chain; + ULONG spare3[5]; + ULONG hash_chain; + ULONG parent; + ULONG extension; + LONG secondary_type; +}; + +struct hlink_front +{ + LONG primary_type; + ULONG own_key; + ULONG spare1[3]; + ULONG checksum; +}; + +struct hlink_end +{ + ULONG spare1; + UWORD owner_uid; + UWORD owner_gid; + ULONG protect; + UBYTE comment[92]; + struct DateStamp created; + UBYTE link_name[32]; + ULONG spare2; + ULONG original; + ULONG link_chain; + ULONG spare3[5]; + ULONG hash_chain; + ULONG parent; + ULONG spare4; + LONG secondary_type; +}; + +struct slink_front +{ + LONG primary_type; + ULONG own_key; + ULONG spare1[3]; + ULONG checksum; + UBYTE symname[288]; /* depends on block size */ +}; + +/* Permission bits */ + +#define FIBF_OTR_READ 0x8000 +#define FIBF_OTR_WRITE 0x4000 +#define FIBF_OTR_EXECUTE 0x2000 +#define FIBF_OTR_DELETE 0x1000 +#define FIBF_GRP_READ 0x0800 +#define FIBF_GRP_WRITE 0x0400 +#define FIBF_GRP_EXECUTE 0x0200 +#define FIBF_GRP_DELETE 0x0100 + +#define FIBF_SCRIPT 0x0040 +#define FIBF_PURE 0x0020 /* no use under linux */ +#define FIBF_ARCHIVE 0x0010 /* never set, always cleared on write */ +#define FIBF_READ 0x0008 /* 0 means allowed */ +#define FIBF_WRITE 0x0004 /* 0 means allowed */ +#define FIBF_EXECUTE 0x0002 /* 0 means allowed, ignored under linux */ +#define FIBF_DELETE 0x0001 /* 0 means allowed */ + +#define FIBF_OWNER 0x000F /* Bits pertaining to owner */ + +#define AFFS_UMAYWRITE(prot) (((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE)) +#define AFFS_UMAYREAD(prot) ((prot) & FIBF_READ) +#define AFFS_UMAYEXECUTE(prot) (((prot) & (FIBF_SCRIPT|FIBF_READ)) == (FIBF_SCRIPT|FIBF_READ)) +#define AFFS_GMAYWRITE(prot) (((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\ + (FIBF_GRP_WRITE|FIBF_GRP_DELETE)) +#define AFFS_GMAYREAD(prot) ((prot) & FIBF_GRP_READ) +#define AFFS_GMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_GRP_READ))==(FIBF_SCRIPT|FIBF_GRP_READ)) +#define AFFS_OMAYWRITE(prot) (((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\ + (FIBF_OTR_WRITE|FIBF_OTR_DELETE)) +#define AFFS_OMAYREAD(prot) ((prot) & FIBF_OTR_READ) +#define AFFS_OMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_OTR_READ))==(FIBF_SCRIPT|FIBF_OTR_READ)) + +#endif diff -u --recursive --new-file v1.3.98/linux/include/linux/genhd.h linux/include/linux/genhd.h --- v1.3.98/linux/include/linux/genhd.h Sat Apr 27 15:20:06 1996 +++ linux/include/linux/genhd.h Tue May 7 14:12:47 1996 @@ -22,7 +22,7 @@ #endif /* These two have identical behaviour; use the second one if DOS fdisk gets - confused about extended/logical partitions starting past cylinder 1023. */ + confused about extended/logical partitions starting past cylinder 1023. */ #define DOS_EXTENDED_PARTITION 5 #define LINUX_EXTENDED_PARTITION 0x85 diff -u --recursive --new-file v1.3.98/linux/include/linux/hdreg.h linux/include/linux/hdreg.h --- v1.3.98/linux/include/linux/hdreg.h Fri Apr 12 15:52:07 1996 +++ linux/include/linux/hdreg.h Tue May 7 14:12:47 1996 @@ -8,7 +8,7 @@ #define HD_IRQ 14 /* the standard disk interrupt */ -/* ide.c has it's own port definitions in "ide.h" */ +/* ide.c has its own port definitions in "ide.h" */ /* Hd controller regs. Ref: IBM AT Bios-listing */ #define HD_DATA 0x1f0 /* _CTL when writing */ diff -u --recursive --new-file v1.3.98/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v1.3.98/linux/include/linux/if_arp.h Sat Apr 27 15:20:06 1996 +++ linux/include/linux/if_arp.h Tue May 7 12:06:50 1996 @@ -111,18 +111,16 @@ #define ARPD_UPDATE 0x01 #define ARPD_LOOKUP 0x02 +#define ARPD_FLUSH 0x03 struct arpd_request { unsigned short req; /* request type */ __u32 ip; /* ip address of entry */ - __u32 mask; /* netmask - used for proxy */ + unsigned long dev; /* Device entry is tied to */ + unsigned long stamp; + unsigned long updated; unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ - unsigned long last_used; /* For expiry */ - unsigned long last_updated; /* For expiry */ - unsigned int flags; /* Control status */ - struct device *dev; /* Device entry is tied to */ - int loc; /* Debugging call location */ }; #endif /* _LINUX_IF_ARP_H */ diff -u --recursive --new-file v1.3.98/linux/include/linux/if_frad.h linux/include/linux/if_frad.h --- v1.3.98/linux/include/linux/if_frad.h Mon Apr 15 12:20:21 1996 +++ linux/include/linux/if_frad.h Mon May 6 12:26:16 1996 @@ -3,7 +3,7 @@ * created for each DLCI associated with a FRAD. The FRAD driver * is not truly a network device, but the lower level device * handler. This allows other FRAD manufacturers to use the DLCI - * code, including it's RFC1490 encapsulation along side the current + * code, including its RFC1490 encapsulation alongside the current * implementation for the Sangoma cards. * * Version: @(#)if_ifrad.h 0.15 31 Mar 96 diff -u --recursive --new-file v1.3.98/linux/include/linux/in.h linux/include/linux/in.h --- v1.3.98/linux/include/linux/in.h Mon Mar 25 10:22:43 1996 +++ linux/include/linux/in.h Mon May 6 12:26:16 1996 @@ -129,7 +129,7 @@ /* * IPv6 definitions as we start to include them. This is just - * a beginning dont get excited 8) + * a beginning -- don't get excited 8) */ struct in_addr6 diff -u --recursive --new-file v1.3.98/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v1.3.98/linux/include/linux/isdn.h Sun Apr 21 19:22:16 1996 +++ linux/include/linux/isdn.h Mon May 6 07:28:53 1996 @@ -184,7 +184,7 @@ #ifdef CONFIG_ISDN_PPP #ifdef CONFIG_ISDN_PPP_VJ -# include "/usr/src/linux/drivers/net/slhc.h" +# include #endif #include diff -u --recursive --new-file v1.3.98/linux/include/linux/isdnif.h linux/include/linux/isdnif.h --- v1.3.98/linux/include/linux/isdnif.h Sun Apr 21 19:22:16 1996 +++ linux/include/linux/isdnif.h Mon May 6 12:26:16 1996 @@ -2,7 +2,7 @@ * * Linux ISDN subsystem * - * Definition of the interface between the subsystem and it's lowlevel-drivers. + * Definition of the interface between the subsystem and its low-level drivers. * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg @@ -136,7 +136,7 @@ * The interface-struct itself (initialized at load-time of lowlevel-driver) * * See Documentation/isdn/INTERFACE for a description, how the communication - * between the ISDN subsystem and it's drivers is done. + * between the ISDN subsystem and its drivers is done. * */ typedef struct { diff -u --recursive --new-file v1.3.98/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v1.3.98/linux/include/linux/kernel.h Sun May 5 08:52:04 1996 +++ linux/include/linux/kernel.h Mon May 6 14:50:10 1996 @@ -57,8 +57,13 @@ asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); -#define pr_debug(show,fmt,arg...) \ - do { if (show) printk(KERN_DEBUG fmt,##arg); } while (0) +#if DEBUG +#define pr_debug(fmt,arg...) \ + printk(KERN_DEBUG fmt,##arg) +#else +#define pr_debug(fmt,arg...) \ + do { } while (0) +#endif #define pr_info(fmt,arg...) \ printk(KERN_INFO fmt,##arg) diff -u --recursive --new-file v1.3.98/linux/include/linux/math_emu.h linux/include/linux/math_emu.h --- v1.3.98/linux/include/linux/math_emu.h Wed Feb 16 13:07:57 1994 +++ linux/include/linux/math_emu.h Mon May 6 16:31:18 1996 @@ -1,6 +1,10 @@ #ifndef _LINUX_MATH_EMU_H #define _LINUX_MATH_EMU_H + +void restore_i387_soft(struct _fpstate *buf); +struct _fpstate * save_i387_soft(struct _fpstate * buf); + struct fpu_reg { char sign; char tag; diff -u --recursive --new-file v1.3.98/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h --- v1.3.98/linux/include/linux/mc146818rtc.h Mon Apr 15 12:20:21 1996 +++ linux/include/linux/mc146818rtc.h Tue May 7 08:18:50 1996 @@ -124,4 +124,22 @@ #define RTC_IRQP_READ 0x0b /* Read periodic IRQ rate (Hz) */ #define RTC_IRQP_SET 0x0c /* Set periodic IRQ rate (Hz) */ +/* + * The struct used to pass data via the above ioctl. Similar to the + * struct tm in , but it needs to be here so that the kernel + * source is self contained, allowing cross-compiles, etc. etc. + */ + +struct rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + #endif /* _MC146818RTC_H */ diff -u --recursive --new-file v1.3.98/linux/include/linux/mroute.h linux/include/linux/mroute.h --- v1.3.98/linux/include/linux/mroute.h Mon Mar 25 10:27:41 1996 +++ linux/include/linux/mroute.h Mon May 6 12:26:16 1996 @@ -112,7 +112,7 @@ }; /* - * Thats all usermode folks + * That's all usermode folks */ #ifdef __KERNEL__ diff -u --recursive --new-file v1.3.98/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v1.3.98/linux/include/linux/msdos_fs.h Mon Mar 25 10:25:11 1996 +++ linux/include/linux/msdos_fs.h Tue May 7 14:16:16 1996 @@ -256,6 +256,21 @@ /* fatfs_syms.c */ extern int init_fat_fs(void); +/* vfat/namei.c - these are for dmsdos */ +extern int vfat_create(struct inode *dir,const char *name,int len,int mode, + struct inode **result); +extern int vfat_unlink(struct inode *dir,const char *name,int len); +extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode); +extern int vfat_rmdir(struct inode *dir,const char *name,int len); +extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, + struct inode *new_dir,const char *new_name,int new_len); +extern void vfat_put_super(struct super_block *sb); +extern struct super_block *vfat_read_super(struct super_block *sb,void *data, + int silent); +extern void vfat_read_inode(struct inode *inode); +extern int vfat_lookup(struct inode *dir,const char *name,int len, + struct inode **result); + #endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v1.3.98/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v1.3.98/linux/include/linux/netdevice.h Sun Apr 21 12:39:03 1996 +++ linux/include/linux/netdevice.h Tue May 7 14:14:53 1996 @@ -71,7 +71,7 @@ * any address resolution module, * not only ARP. */ - unsigned int hh_refcnt; /* number of users */ + int hh_refcnt; /* number of users */ unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP */ char hh_uptodate; /* hh_data is valid */ char hh_data[16]; /* cached hardware header */ @@ -218,7 +218,7 @@ extern int ip_addr_match(unsigned long addr1, unsigned long addr2); extern int ip_chk_addr(unsigned long addr); -extern struct device *ip_dev_check(unsigned long daddr); +extern struct device *ip_dev_bynet(unsigned long daddr, unsigned long mask); extern unsigned long ip_my_addr(void); extern unsigned long ip_get_mask(unsigned long addr); extern struct device *ip_dev_find(unsigned long addr); @@ -246,7 +246,7 @@ extern int dev_lockct; /* - * These two dont currently need to be interrupt safe + * These two don't currently need to be interrupt-safe * but they may do soon. Do it properly anyway. */ diff -u --recursive --new-file v1.3.98/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.3.98/linux/include/linux/skbuff.h Mon Apr 29 18:05:20 1996 +++ linux/include/linux/skbuff.h Tue May 7 14:12:57 1996 @@ -392,7 +392,11 @@ skb->tail+=len; skb->len+=len; if(skb->tail>skb->end) - panic("skput:over: %p:%d", __builtin_return_address(0),len); + { + __label__ here; + panic("skput:over: %p:%d", &&here,len); +here: + } return tmp; } @@ -401,7 +405,11 @@ skb->data-=len; skb->len+=len; if(skb->datahead) - panic("skpush:under: %p:%d", __builtin_return_address(0),len); + { + __label__ here; + panic("skpush:under: %p:%d", &&here,len); +here: + } return skb->data; } diff -u --recursive --new-file v1.3.98/linux/include/linux/string.h linux/include/linux/string.h --- v1.3.98/linux/include/linux/string.h Mon Mar 25 10:22:43 1996 +++ linux/include/linux/string.h Sun May 5 15:00:23 1996 @@ -17,6 +17,7 @@ extern char * strcat(char *, const char *); extern char * strncat(char *, const char *, size_t); extern char * strchr(const char *,int); +extern char * strrchr(const char *,int); extern char * strpbrk(const char *,const char *); extern char * strtok(char *,const char *); extern char * strstr(const char *,const char *); diff -u --recursive --new-file v1.3.98/linux/include/net/netlink.h linux/include/net/netlink.h --- v1.3.98/linux/include/net/netlink.h Mon Mar 25 10:12:54 1996 +++ linux/include/net/netlink.h Tue May 7 14:18:35 1996 @@ -2,7 +2,7 @@ #define __NET_NETLINK_H #define NET_MAJOR 36 /* Major 18 is reserved for networking */ -#define MAX_LINKS 8 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ +#define MAX_LINKS 9 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ /* 4-7 are psi0-psi3 */ #define MAX_QBYTES 32768 /* Maximum bytes in the queue */ @@ -19,6 +19,7 @@ #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ #define NETLINK_FIREWALL 3 /* Firewalling hook */ #define NETLINK_PSI 4 /* PSI devices - 4 to 7 */ +#define NETLINK_ARPD 8 #ifdef CONFIG_RTNETLINK extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *); diff -u --recursive --new-file v1.3.98/linux/include/net/route.h linux/include/net/route.h --- v1.3.98/linux/include/net/route.h Sun May 5 08:52:05 1996 +++ linux/include/net/route.h Tue May 7 15:24:06 1996 @@ -62,120 +62,16 @@ #define RTF_LOCAL 0x8000 #endif -/* - * Semaphores. - */ -#if defined(__alpha__) - -static __inline__ void ATOMIC_INCR(unsigned int * addr) -{ - unsigned tmp; - - __asm__ __volatile__( - "1:\n\ - ldl_l %1,%2\n\ - addl %1,1,%1\n\ - stl_c %1,%0\n\ - beq %1,1b\n" - : "m=" (*addr), "r=&" (tmp) - : "m"(*addr)); -} - -static __inline__ void ATOMIC_DECR(unsigned int * addr) -{ - unsigned tmp; - - __asm__ __volatile__( - "1:\n\ - ldl_l %1,%2\n\ - subl %1,1,%1\n\ - stl_c %1,%0\n\ - beq %1,1b\n" - : "m=" (*addr), "r=&" (tmp) - : "m"(*addr)); -} - -static __inline__ int ATOMIC_DECR_AND_CHECK (unsigned int * addr) -{ - unsigned tmp; - int result; - - __asm__ __volatile__( - "1:\n\ - ldl_l %1,%3\n\ - subl %1,1,%1\n\ - mov %1,%2\n\ - stl_c %1,%0\n\ - beq %1,1b\n" - : "m=" (*addr), "r=&" (tmp), "r=&"(result) - : "m"(*addr)); - return result; -} - -#elif defined(__i386__) -#include - -extern __inline__ void ATOMIC_INCR(void * addr) -{ - __asm__ __volatile__( - "incl %0" - :"=m" (ADDR)); -} - -extern __inline__ void ATOMIC_DECR(void * addr) -{ - __asm__ __volatile__( - "decl %0" - :"=m" (ADDR)); -} - -/* - * It is DECR that is ATOMIC, not CHECK! - * If you want to do atomic checks, use cli()/sti(). --ANK - */ - -extern __inline__ unsigned long ATOMIC_DECR_AND_CHECK(void * addr) -{ - unsigned long retval; - __asm__ __volatile__( - "decl %0\nmovl %0,%1" - : "=m" (ADDR), "=r"(retval)); - return retval; -} - - -#else - -static __inline__ void ATOMIC_INCR(unsigned int * addr) -{ - (*(__volatile__ unsigned int*)addr)++; -} - -static __inline__ void ATOMIC_DECR(unsigned int * addr) -{ - (*(__volatile__ unsigned int*)addr)--; -} - -static __inline__ int ATOMIC_DECR_AND_CHECK (unsigned int * addr) -{ - ATOMIC_DECR(addr); - return *(volatile unsigned int*)addr; -} - -#endif - - - struct rtable { struct rtable *rt_next; __u32 rt_dst; __u32 rt_src; __u32 rt_gateway; - unsigned rt_refcnt; - unsigned rt_use; + atomic_t rt_refcnt; + atomic_t rt_use; unsigned long rt_window; - unsigned long rt_lastuse; + atomic_t rt_lastuse; struct hh_cache *rt_hh; struct device *rt_dev; unsigned short rt_flags; @@ -185,6 +81,7 @@ }; extern void ip_rt_flush(struct device *dev); +extern void ip_rt_update(int event, struct device *dev); extern void ip_rt_redirect(__u32 src, __u32 dst, __u32 gw, struct device *dev); extern struct rtable *ip_rt_slow_route(__u32 daddr, int local); extern int rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy); @@ -196,23 +93,23 @@ extern void ip_rt_advice(struct rtable **rp, int advice); extern void ip_rt_run_bh(void); -extern int ip_rt_lock; +extern atomic_t ip_rt_lock; extern unsigned ip_rt_bh_mask; extern struct rtable *ip_rt_hash_table[RT_HASH_DIVISOR]; extern __inline__ void ip_rt_fast_lock(void) { - ATOMIC_INCR(&ip_rt_lock); + atomic_inc(&ip_rt_lock); } extern __inline__ void ip_rt_fast_unlock(void) { - ATOMIC_DECR(&ip_rt_lock); + atomic_dec(&ip_rt_lock); } extern __inline__ void ip_rt_unlock(void) { - if (!ATOMIC_DECR_AND_CHECK(&ip_rt_lock) && ip_rt_bh_mask) + if (atomic_dec_and_test(&ip_rt_lock) && ip_rt_bh_mask) ip_rt_run_bh(); } @@ -227,7 +124,7 @@ #ifndef MODULE { if (rt) - ATOMIC_DECR(&rt->rt_refcnt); + atomic_dec(&rt->rt_refcnt); } #else ; @@ -248,8 +145,8 @@ if (rth->rt_dst == daddr) { rth->rt_lastuse = jiffies; - ATOMIC_INCR(&rth->rt_use); - ATOMIC_INCR(&rth->rt_refcnt); + atomic_inc(&rth->rt_use); + atomic_inc(&rth->rt_refcnt); ip_rt_unlock(); return rth; } diff -u --recursive --new-file v1.3.98/linux/include/net/slhc_vj.h linux/include/net/slhc_vj.h --- v1.3.98/linux/include/net/slhc_vj.h Thu Jan 1 02:00:00 1970 +++ linux/include/net/slhc_vj.h Mon May 6 07:28:54 1996 @@ -0,0 +1,187 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef unsigned char byte_t; +typedef unsigned long int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +#define __ARGS(x) x + +/* In slhc.c: */ +struct slcompress *slhc_init __ARGS((int rslots, int tslots)); +void slhc_free __ARGS((struct slcompress *comp)); + +int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize, unsigned char *ocp, unsigned char **cpp, + int compress_cid)); +int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_toss __ARGS((struct slcompress *comp)); + +void slhc_i_status __ARGS((struct slcompress *comp)); +void slhc_o_status __ARGS((struct slcompress *comp)); + +#endif /* _SLHC_H */ diff -u --recursive --new-file v1.3.98/linux/include/net/sock.h linux/include/net/sock.h --- v1.3.98/linux/include/net/sock.h Fri Apr 19 10:08:02 1996 +++ linux/include/net/sock.h Tue May 7 14:14:58 1996 @@ -488,7 +488,7 @@ * protocols can't normally use this as they need to fit buffers in * and play with them. * - * Inlined as its very short and called for pretty much every + * Inlined as it's very short and called for pretty much every * packet ever received. */ diff -u --recursive --new-file v1.3.98/linux/include/net/tcp.h linux/include/net/tcp.h --- v1.3.98/linux/include/net/tcp.h Sat Apr 27 15:20:07 1996 +++ linux/include/net/tcp.h Tue May 7 15:24:31 1996 @@ -192,50 +192,7 @@ return sk->window - (sk->acked_seq - sk->lastwin_seq); } -static __inline__ int tcp_new_window(struct sock * sk) -{ - int window = sock_rspace(sk); - - if (window > 1024) - window &= ~0x3FF; /* make free space a multiple of 1024 */ - - if (sk->window_clamp && sk->window_clamp < window) - window = sk->window_clamp; - - /* - * RFC 1122 says: - * - * "the suggested [SWS] avoidance algorithm for the receiver is to keep - * RECV.NEXT + RCV.WIN fixed until: - * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" - * - * Experiments against BSD and Solaris machines show that following - * these rules results in the BSD and Solaris machines making very - * bad guesses about how much data they can have in flight. - * - * Instead we follow the BSD lead and offer a window that gives - * the size of the current free space, truncated to a multiple - * of 1024 bytes. If the window is smaller than - * min(sk->mss, MAX_WINDOW/2) - * then we advertise the window as having size 0, unless this - * would shrink the window we offered last time. - * This results in as much as double the throughput as the original - * implementation. - */ - - if (sk->mss == 0) - sk->mss = sk->mtu; - - /* BSD style SWS avoidance - * Note that RFC1122 only says we must do silly window avoidance, - * it does not require that we use the suggested algorithm. - */ - - if (window < min(sk->mss, MAX_WINDOW/2)) - window = 0; - - return window; -} +extern int tcp_new_window(struct sock *); /* * Return true if we should raise the window when we @@ -247,7 +204,8 @@ */ static __inline__ int tcp_raise_window(struct sock * sk) { - return tcp_new_window(sk) >= 2*tcp_old_window(sk); + int new = tcp_new_window(sk); + return new && (new >= 2*tcp_old_window(sk)); } static __inline__ unsigned short tcp_select_window(struct sock *sk) diff -u --recursive --new-file v1.3.98/linux/ipc/msg.c linux/ipc/msg.c --- v1.3.98/linux/ipc/msg.c Fri Apr 12 15:52:09 1996 +++ linux/ipc/msg.c Mon May 6 12:09:01 1996 @@ -159,7 +159,8 @@ * Take care of missing kerneld, especially in case of multiple daemons */ #define KERNELD_TIMEOUT 1 * (HZ) -#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer) +#define DROP_TIMER del_timer(&kd_timer) +/*#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)*/ static void kd_timeout(unsigned long msgid) { @@ -185,7 +186,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) { - struct timer_list kd_timer; + struct timer_list kd_timer = { NULL, NULL, 0, 0, 0}; struct msqid_ds *msq; struct ipc_perm *ipcp; struct msg *tmsg, *leastp = NULL; @@ -229,16 +230,20 @@ * msgtyp < 0 => get message with least type must be < abs(msgtype). */ while (!nmsg) { - if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) + if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) { + DROP_TIMER; return -EIDRM; + } if ((msgflg & IPC_KERNELD) == 0) { /* * Non-root processes may receive from kerneld! * i.e. no permission check if called from the kernel * otoh we don't want user level non-root snoopers... */ - if (ipcperms (ipcp, S_IRUGO)) + if (ipcperms (ipcp, S_IRUGO)) { + DROP_TIMER; return -EACCES; + } } if (msgtyp == 0) nmsg = msq->msg_first; @@ -267,8 +272,10 @@ if (nmsg) { /* done finding a message */ DROP_TIMER; - if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) + if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) { + DROP_TIMER; return -E2BIG; + } msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz; if (nmsg == msq->msg_first) msq->msg_first = nmsg->msg_next; @@ -315,6 +322,7 @@ memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz); } kfree(nmsg); + DROP_TIMER; return msgsz; } else { /* did not find a message */ if (msgflg & IPC_NOWAIT) { diff -u --recursive --new-file v1.3.98/linux/kernel/module.c linux/kernel/module.c --- v1.3.98/linux/kernel/module.c Sun Apr 21 19:22:16 1996 +++ linux/kernel/module.c Mon May 6 14:37:42 1996 @@ -46,12 +46,6 @@ #ifdef CONFIG_MODULES /* a *big* #ifdef block... */ -#ifdef DEBUG_MODULE -#define PRINTK(a) printk a -#else -#define PRINTK(a) /* */ -#endif - static struct module kernel_module; static struct module *module_list = &kernel_module; @@ -127,8 +121,8 @@ * (long *) addr = 0; /* set use count to zero */ module_list = mp; /* link it in */ - PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n", - mp->name, (unsigned long) mp->size, (unsigned long) mp->addr)); + pr_debug("module `%s' (%lu pages @ 0x%08lx) created\n", + mp->name, (unsigned long) mp->size, (unsigned long) mp->addr); return (unsigned long) addr; } @@ -167,8 +161,8 @@ if ((error = get_mod_name(module_name, name)) != 0) return error; - PRINTK(("initializing module `%s', %d (0x%x) bytes\n", - name, codesize, codesize)); + pr_debug("initializing module `%s', %d (0x%x) bytes\n", + name, codesize, codesize); memcpy_fromfs(&rt, routines, sizeof rt); if ((mp = find_module(name)) == NULL) return -ENOENT; @@ -185,8 +179,8 @@ memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize); memset((char *)mp->addr + sizeof (long) + codesize, 0, mp->size * PAGE_SIZE - (codesize + sizeof (long))); - PRINTK(( "module init entry = 0x%08lx, cleanup entry = 0x%08lx\n", - (unsigned long) rt.init, (unsigned long) rt.cleanup)); + pr_debug("module init entry = 0x%08lx, cleanup entry = 0x%08lx\n", + (unsigned long) rt.init, (unsigned long) rt.cleanup); mp->cleanup = rt.cleanup; /* update kernel symbol table */ diff -u --recursive --new-file v1.3.98/linux/kernel/sched.c linux/kernel/sched.c --- v1.3.98/linux/kernel/sched.c Sat Apr 27 15:20:09 1996 +++ linux/kernel/sched.c Tue May 7 12:06:51 1996 @@ -121,8 +121,7 @@ init_task.prev_run = p; #ifdef __SMP__ /* this is safe only if called with cli()*/ - while(set_bit(31,&smp_process_available)); -#if 0 + while(set_bit(31,&smp_process_available)) { while(test_bit(31,&smp_process_available)) { @@ -133,7 +132,6 @@ } } } -#endif smp_process_available++; clear_bit(31,&smp_process_available); if ((0!=p->pid) && smp_threads_ready) @@ -242,6 +240,11 @@ /* We are not permitted to run a task someone else is running */ if (p->processor != NO_PROC_ID) return -1000; +#ifdef PAST_2_0 + /* This process is locked to a processor group */ + if (p->processor_mask && !(p->processor_mask & (1<processor = NO_PROC_ID; -#define idle_task (task[this_cpu]) +#define idle_task (task[cpu_number_map[this_cpu]]) #else #define idle_task (&init_task) #endif diff -u --recursive --new-file v1.3.98/linux/mm/filemap.c linux/mm/filemap.c --- v1.3.98/linux/mm/filemap.c Sun May 5 08:52:05 1996 +++ linux/mm/filemap.c Mon May 6 12:44:32 1996 @@ -779,7 +779,8 @@ free_page(page); return new_page; } - flush_page_to_ram(page); + if (page) + flush_page_to_ram(page); return page; } diff -u --recursive --new-file v1.3.98/linux/mm/swapfile.c linux/mm/swapfile.c --- v1.3.98/linux/mm/swapfile.c Sat Mar 16 11:55:40 1996 +++ linux/mm/swapfile.c Mon May 6 12:42:08 1996 @@ -187,6 +187,7 @@ return 1; } set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); + flush_tlb_page(vma, address); ++vma->vm_mm->rss; swap_free(pte_val(pte)); return 1; diff -u --recursive --new-file v1.3.98/linux/net/Changes linux/net/Changes --- v1.3.98/linux/net/Changes Fri Apr 12 15:52:10 1996 +++ linux/net/Changes Mon May 6 12:26:16 1996 @@ -376,7 +376,7 @@ load. [TRYING THINGS] o AX.25/NetROM needs more locking. o NFS flow control is needed with the new multirequest NFS support. -o Need to be able to turn off the intelligent arp refreshing as its not so +o Need to be able to turn off the intelligent arp refreshing as it's not so hot over AX.25 and upsets some people with very dumb ISDN bridges. o Matti Arnio's TCP problem. o Should unix domain connect never block ? @@ -435,7 +435,7 @@ problem. [See the LiS project] 10. Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board -driver but thats for an internal project and its general release is still +driver but that's for an internal project and its general release is still a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is Mike McLagan][Friz Elfert is doing the isdn4linux kit]. diff -u --recursive --new-file v1.3.98/linux/net/TUNABLE linux/net/TUNABLE --- v1.3.98/linux/net/TUNABLE Fri Apr 12 15:52:10 1996 +++ linux/net/TUNABLE Mon May 6 12:26:16 1996 @@ -35,7 +35,7 @@ MAX_HEADER Largest physical header (tunable) MAX_ADDR_LEN Largest physical address (tunable) SOCK_ARRAY_SIZE IP socket array hash size (tunable) -ARP_RES_TIME Time we try and resolve (tunable) +ARP_RES_TIME Time we try to resolve (tunable) ARP_DEAD_RES_TIME Time the entry stays dead (tunable) ARP_MAX_TRIES Maximum tries (tunable) ARP_TIMEOUT Timeout on an ARP (tunable) diff -u --recursive --new-file v1.3.98/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v1.3.98/linux/net/ax25/af_ax25.c Sat Apr 27 15:20:10 1996 +++ linux/net/ax25/af_ax25.c Mon May 6 12:26:17 1996 @@ -13,7 +13,7 @@ * 2 of the License, or (at your option) any later version. * * History - * AX.25 006 Alan(GW4PTS) Nearly died of shock - its working 8-) + * AX.25 006 Alan(GW4PTS) Nearly died of shock - it's working 8-) * AX.25 007 Alan(GW4PTS) Removed the silliest bugs * AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks * AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption @@ -25,7 +25,7 @@ * Correct receive on SOCK_DGRAM. * AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed * Leave spare SSID bits set (DAMA etc) - thanks for bug report, - * removed device registration (its not used or needed). Clean up for + * removed device registration (it's not used or needed). Clean up for * gcc 2.5.8. PID to AX25_P_ * AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge * AX.25 015 Alan(GW4PTS) Internal test version. @@ -409,7 +409,7 @@ * Once it is removed from the queue no interrupt or bottom half will * touch it and we are (fairly 8-) ) safe. */ -void ax25_destroy_socket(ax25_cb *ax25) /* Not static as its used by the timer */ +void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer */ { struct sk_buff *skb; unsigned long flags; @@ -1893,7 +1893,7 @@ */ static int kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) { - skb->sk = NULL; /* Initially we don't know who its for */ + skb->sk = NULL; /* Initially we don't know who it's for */ if ((*skb->data & 0x0F) != 0) { kfree_skb(skb, FREE_READ); /* Not a KISS data frame */ @@ -1914,7 +1914,7 @@ ax25_address *port_call; int len; - skb->sk = NULL; /* Initially we don't know who its for */ + skb->sk = NULL; /* Initially we don't know who it's for */ if ((port_call = ax25_bpq_get_addr(dev)) == NULL) { kfree_skb(skb, FREE_READ); /* We have no port callsign */ @@ -2546,7 +2546,7 @@ if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) { /* - * This is a workaround to try and keep the device locking + * This is a workaround to try to keep the device locking * straight until skb->free=0 is abolished post 1.4. * * We clone the buffer and release the original thereby diff -u --recursive --new-file v1.3.98/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v1.3.98/linux/net/ax25/ax25_out.c Sun May 5 08:52:05 1996 +++ linux/net/ax25/ax25_out.c Mon May 6 12:26:17 1996 @@ -389,7 +389,7 @@ /* The FLEXNET DAMA master implementation refuses to send us ANY */ /* I frame for this connection if we send a REJ here, probably */ - /* due to it's frame collector scheme? A simple RR or RNR will */ + /* due to its frame collector scheme? A simple RR or RNR will */ /* invoke the retransmission, and in fact REJs are superfluous */ /* in DAMA mode anyway... */ diff -u --recursive --new-file v1.3.98/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v1.3.98/linux/net/ax25/ax25_subr.c Fri Apr 19 10:08:02 1996 +++ linux/net/ax25/ax25_subr.c Mon May 6 12:26:17 1996 @@ -248,7 +248,7 @@ /* * Send a 'DM' to an unknown connection attempt, or an invalid caller. * - * Note: src here is the sender, thus its the target of the DM + * Note: src here is the sender, thus it's the target of the DM */ void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi) { diff -u --recursive --new-file v1.3.98/linux/net/core/dev.c linux/net/core/dev.c --- v1.3.98/linux/net/core/dev.c Sun May 5 08:52:06 1996 +++ linux/net/core/dev.c Tue May 7 12:06:51 1996 @@ -291,13 +291,7 @@ * Flush the multicast chain */ dev_mc_discard(dev); - /* - * Blank the IP addresses - */ - dev->pa_addr = 0; - dev->pa_dstaddr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; + /* * Purge any queued packets when we down the link */ @@ -1082,6 +1076,17 @@ } else { + u32 new_pa_addr = (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_addr.s_addr; + u16 new_family = ifr.ifr_addr.sa_family; + + if (new_family == dev->family && + new_pa_addr == dev->pa_addr) { + ret =0; + break; + } + if (dev->flags & IFF_UP) + notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); /* * if dev is an alias, must rehash to update @@ -1092,16 +1097,19 @@ if (net_alias_is(dev)) net_alias_dev_rehash(dev ,&ifr.ifr_addr); #endif - dev->pa_addr = (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr; - dev->family = ifr.ifr_addr.sa_family; + dev->pa_addr = new_pa_addr; + dev->family = new_family; #ifdef CONFIG_INET /* This is naughty. When net-032e comes out It wants moving into the net032 code not the kernel. Till then it can sit here (SIGH) */ - dev->pa_mask = ip_get_mask(dev->pa_addr); + if (!dev->pa_mask) + dev->pa_mask = ip_get_mask(dev->pa_addr); #endif - dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; + if (!dev->pa_brdaddr) + dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; + if (dev->flags & IFF_UP) + notifier_call_chain(&netdev_chain, NETDEV_UP, dev); ret = 0; } break; diff -u --recursive --new-file v1.3.98/linux/net/core/net_alias.c linux/net/core/net_alias.c --- v1.3.98/linux/net/core/net_alias.c Fri Apr 12 15:52:11 1996 +++ linux/net/core/net_alias.c Mon May 6 12:26:17 1996 @@ -1122,7 +1122,7 @@ if (main_dev == NULL) return NULL; /* - * if not aliased, dont bother any more + * if not aliased, don't bother any more */ if ((alias_info = main_dev->alias_info) == NULL) @@ -1194,7 +1194,7 @@ if (main_dev == NULL) return NULL; /* - * if not aliased, dont bother any more + * if not aliased, don't bother any more */ if ((alias_info = main_dev->alias_info) == NULL) diff -u --recursive --new-file v1.3.98/linux/net/ethernet/eth.c linux/net/ethernet/eth.c --- v1.3.98/linux/net/ethernet/eth.c Fri Apr 12 15:52:11 1996 +++ linux/net/ethernet/eth.c Mon May 6 12:26:17 1996 @@ -154,7 +154,7 @@ } /* - * Try and get ARP to resolve the header. + * Try to get ARP to resolve the header. */ #ifdef CONFIG_INET return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; diff -u --recursive --new-file v1.3.98/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v1.3.98/linux/net/ipv4/Config.in Sun May 5 08:52:06 1996 +++ linux/net/ipv4/Config.in Tue May 7 12:06:52 1996 @@ -22,7 +22,7 @@ tristate 'IP: aliasing support' CONFIG_IP_ALIAS fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_KERNELD" = "y" ]; then + if [ "$CONFIG_NETLINK" = "y" ]; then bool 'IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD fi fi diff -u --recursive --new-file v1.3.98/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.98/linux/net/ipv4/arp.c Fri Apr 12 15:52:11 1996 +++ linux/net/ipv4/arp.c Tue May 7 12:06:52 1996 @@ -103,8 +103,8 @@ #include #endif #ifdef CONFIG_ARPD -#include -#endif /* CONFIG_ARPD */ +#include +#endif #include #include @@ -112,97 +112,157 @@ #include /* - * This structure defines the ARP mapping cache. As long as we make changes - * in this structure, we keep interrupts off. But normally we can copy the - * hardware address and the device pointer in a local variable and then - * make any "long calls" to send a packet out. + * Configurable Parameters */ -struct arp_table -{ - struct arp_table *next; /* Linked entry list */ - unsigned long last_used; /* For expiry */ - unsigned long last_updated; /* For expiry */ - unsigned int flags; /* Control status */ - u32 ip; /* ip address of entry */ - u32 mask; /* netmask - used for generalised proxy arps (tridge) */ - unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ - struct device *dev; /* Device the entry is tied to */ +/* + * After that time, an unused entry is deleted from the arp table. + * RFC1122 recommends set it to 60*HZ, if your site uses proxy arp + * and dynamic routing. + */ - /* - * The following entries are only used for unresolved hw addresses. - */ - - struct timer_list timer; /* expire timer */ - int retries; /* remaining retries */ - struct sk_buff_head skb; /* list of queued packets */ - struct hh_cache *hh; -}; +#ifndef CONFIG_ARPD +#define ARP_TIMEOUT (600*HZ) +#else +#define ARP_TIMEOUT (60*HZ) +#define ARPD_TIMEOUT (600*HZ) +#endif + +/* + * How often is ARP cache checked for expire. + * It is useless to set ARP_CHECK_INTERVAL > ARP_TIMEOUT + */ +#define ARP_CHECK_INTERVAL (60*HZ) /* - * Configurable Parameters (don't touch unless you know what you are doing + * Soft limit on ARP cache size. + * Note that this number should be greater, than + * number of simultaneously opened sockets, else + * hardware header cache will be not efficient. */ +#if RT_CACHE_DEBUG >= 2 +#define ARP_MAXSIZE 4 +#else +#ifdef CONFIG_ARPD +#define ARP_MAXSIZE 64 +#else +#define ARP_MAXSIZE 256 +#endif /* CONFIG_ARPD */ +#endif + /* * If an arp request is send, ARP_RES_TIME is the timeout value until the * next request is send. * RFC1122: OK. Throttles ARPing, as per 2.3.2.1. (MUST) * The recommended minimum timeout is 1 second per destination. - * This timeout is prolongated to ARP_DEAD_RES_TIME, if - * destination does not respond. + * */ #define ARP_RES_TIME (5*HZ) -#define ARP_DEAD_RES_TIME (60*HZ) /* - * The number of times an arp request is send, until the host is - * considered temporarily unreachable. + * The number of times an broadcast arp request is send, until + * the host is considered temporarily unreachable. */ #define ARP_MAX_TRIES 3 /* - * After that time, an unused entry is deleted from the arp table. + * The entry is reconfirmed by sending point-to-point ARP + * request after ARP_CONFIRM_INTERVAL. + * RFC1122 recommends 60*HZ. + * + * Warning: there exist nodes, that answer only broadcast + * ARP requests (Cisco-4000 in hot standby mode?) + * Now arp code should work with such nodes, but + * it still will generate redundant broadcast requests, so that + * this interval should be enough long. */ -#define ARP_TIMEOUT (600*HZ) +#define ARP_CONFIRM_INTERVAL (300*HZ) /* - * How often is the function 'arp_check_retries' called. - * An unused entry is invalidated in the time between ARP_TIMEOUT and - * (ARP_TIMEOUT+ARP_CHECK_INTERVAL). + * We wait for answer to unicast request for ARP_CONFIRM_TIMEOUT. */ -#define ARP_CHECK_INTERVAL (60*HZ) +#define ARP_CONFIRM_TIMEOUT ARP_RES_TIME /* - * The entry is reconfirmed by sending point-to-point ARP - * request after ARP_CONFIRM_INTERVAL. If destinations does not respond - * for ARP_CONFIRM_TIMEOUT, normal broadcast resolution scheme is started. + * The number of times an unicast arp request is retried, until + * the cache entry is considered suspicious. + * Value 0 means that no unicast pings will be sent. + * RFC1122 recommends 2. + */ + +#define ARP_MAX_PINGS 1 + +/* + * When a host is dead, but someone tries to connect it, + * we do not remove corresponding cache entry (it would + * be useless, it will be created again immediately) + * Instead we prolongate interval between broadcasts + * to ARP_DEAD_RES_TIME. + * This interval should be not very long. + * (When the host will be up again, we will notice it only + * when ARP_DEAD_RES_TIME expires, or when the host will arp us. */ -#define ARP_CONFIRM_INTERVAL (300*HZ) -#define ARP_CONFIRM_TIMEOUT ARP_RES_TIME +#define ARP_DEAD_RES_TIME (60*HZ) + +/* + * This structure defines the ARP mapping cache. + */ + +struct arp_table +{ + struct arp_table *next; /* Linked entry list */ + unsigned long last_used; /* For expiry */ + unsigned long last_updated; /* For expiry */ + unsigned int flags; /* Control status */ + u32 ip; /* ip address of entry */ + u32 mask; /* netmask - used for generalised proxy arps (tridge) */ + unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ + struct device *dev; /* Device the entry is tied to */ + struct hh_cache *hh; /* Hardware headers chain */ + + /* + * The following entries are only used for unresolved hw addresses. + */ + + struct timer_list timer; /* expire timer */ + int retries; /* remaining retries */ + struct sk_buff_head skb; /* list of queued packets */ +}; + + +static atomic_t arp_size = 0; + +#ifdef CONFIG_ARPD +static int arpd_not_running; +static int arpd_stamp; +#endif -static unsigned int arp_lock; static unsigned int arp_bh_mask; #define ARP_BH_BACKLOG 1 +/* + * Backlog for ARP updates. + */ static struct arp_table *arp_backlog; -/* If we have arpd configured, assume that we will be running arpd and keep - the internal cache small */ -#ifdef CONFIG_ARPD -#define ARP_MAXSIZE 256 -#endif /* CONFIG_ARPD */ +/* + * Backlog for incomplete entries. + */ +static struct arp_table *arp_req_backlog; -static unsigned int arp_size = 0; static void arp_run_bh(void); static void arp_check_expire (unsigned long); +static int arp_update (u32 sip, char *sha, struct device * dev, + struct arp_table *ientry, int grat); static struct timer_list arp_timer = { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire }; @@ -216,12 +276,10 @@ /* * The size of the hash table. Must be a power of two. - * Maybe we should remove hashing in the future for arp and concentrate - * on Patrick Schaaf's Host-Cache-Lookup... */ -#define ARP_TABLE_SIZE 16 -#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1) +#define ARP_TABLE_SIZE 16 +#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1) struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] = { @@ -238,22 +296,47 @@ #define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1)) /* - * Lock/unlock arp_table chains. + * ARP cache semaphore. + * + * Every time when someone wants to traverse arp table, + * he MUST call arp_fast_lock. + * It will guarantee that arp cache list will not change + * by interrupts and the entry that you found will not + * disappear unexpectedly. + * + * If you want to modify arp cache lists, you MUST + * call arp_fast_lock, and check that you are the only + * owner of semaphore (arp_lock == 1). If it is not the case + * you can defer your operation or forgot it, + * but DO NOT TOUCH lists. + * + * However, you are allowed to change arp entry contents. + * + * Assumptions: + * -- interrupt code MUST have lock/unlock balanced, + * you cannot lock cache on interrupt and defer unlocking + * to callback. + * In particular, it means that lock/unlock are allowed + * to be non-atomic. They are made atomic, but it was not + * necessary. + * -- nobody is allowed to sleep while + * it keeps arp locked. (route cache has similar locking + * scheme, but allows sleeping) + * */ -static __inline__ void arp_fast_lock(void) -{ - ATOMIC_INCR(&arp_lock); -} +static atomic_t arp_lock; + +#define ARP_LOCKED() (arp_lock != 1) -static __inline__ void arp_fast_unlock(void) +static __inline__ void arp_fast_lock(void) { - ATOMIC_DECR(&arp_lock); + atomic_inc(&arp_lock); } static __inline__ void arp_unlock(void) { - if (!ATOMIC_DECR_AND_CHECK(&arp_lock) && arp_bh_mask) + if (atomic_dec_and_test(&arp_lock) && arp_bh_mask) arp_run_bh(); } @@ -306,7 +389,7 @@ * Purge all linked skb's of the entry. */ -static void arp_release_entry(struct arp_table *entry) +static void arp_purge_send_q(struct arp_table *entry) { struct sk_buff *skb; unsigned long flags; @@ -328,6 +411,7 @@ /* * Release the entry and all resources linked to it: skb's, hh's, timer * and certainly memory. + * The entry should be already removed from lists. */ static void arp_free_entry(struct arp_table *entry) @@ -336,280 +420,416 @@ struct hh_cache *hh, *next; del_timer(&entry->timer); + arp_purge_send_q(entry); save_flags(flags); cli(); - arp_release_entry(entry); + hh = entry->hh; + entry->hh = NULL; + restore_flags(flags); - for (hh = entry->hh; hh; hh = next) + for ( ; hh; hh = next) { next = hh->hh_next; - hh->hh_arp = NULL; hh->hh_uptodate = 0; - if (!--hh->hh_refcnt) + hh->hh_next = NULL; + hh->hh_arp = NULL; + if (atomic_dec_and_test(&hh->hh_refcnt)) kfree_s(hh, sizeof(struct(struct hh_cache))); } - restore_flags(flags); kfree_s(entry, sizeof(struct arp_table)); - --arp_size; + atomic_dec(&arp_size); return; } /* - * How many users has this entry? + * Hardware header cache. + * + * BEWARE! Hardware header cache has no locking, so that + * it requires especially careful handling. + * It is the only part of arp+route, where a list + * should be traversed with masked interrupts. + * Luckily, this list contains one element 8), as rule. + */ + +/* + * How many users has this entry? + * The answer is reliable only when interrupts are masked. */ static __inline__ int arp_count_hhs(struct arp_table * entry) { - struct hh_cache *hh, **hhp; + struct hh_cache *hh; int count = 0; - hhp = &entry->hh; - while ((hh=*hhp) != NULL) - { - if (hh->hh_refcnt == 1) - { - *hhp = hh->hh_next; - kfree_s(hh, sizeof(struct hh_cache)); - continue; - } + for (hh = entry->hh; hh; hh = hh->hh_next) count += hh->hh_refcnt-1; - hhp = &hh->hh_next; - } return count; } - /* - * Force the expiry of an entry in the internal cache so the memory - * can be used for a new request or for loading a query from arpd. - * I'm not really sure what the best algorithm should be, so I just - * search for the oldest. NOTE: make sure the cache is locked before - * jumping into this function! If someone wants to do something - * other than searching the whole cache, by all means do so! + * Signal to device layer, that hardware address may be changed. */ -#ifdef CONFIG_ARPD -static int arp_force_expire(void) +static __inline__ void arp_update_hhs(struct arp_table * entry) { - int i; - struct arp_table *entry = NULL; - struct arp_table **pentry = NULL; - struct arp_table **oldest_entry = NULL, **last_resort = NULL; - unsigned long oldest_used = ~0; - -#if RT_CACHE_DEBUG >= 2 - printk("Looking for something to force expire.\n"); -#endif - for (i = 0; i < ARP_TABLE_SIZE; i++) - { - pentry = &arp_tables[i]; + struct hh_cache *hh; - while ((entry = *pentry) != NULL) - { - if (entry->last_used < oldest_used) - { - if (arp_count_hhs(entry) == 0) - { - oldest_entry = pentry; - } - last_resort = pentry; - oldest_used = entry->last_used; - } - pentry = &entry->next; /* go to next entry */ - } - } - if (oldest_entry == NULL) - { - if (last_resort == NULL) - return -1; - oldest_entry = last_resort; - } - - entry = *oldest_entry; - *oldest_entry = (*oldest_entry)->next; -#if RT_CACHE_DEBUG >= 2 - printk("Force expiring %08x\n", entry->ip); -#endif - arp_free_entry(entry); - return 0; + for (hh=entry->hh; hh; hh=hh->hh_next) + entry->dev->header_cache_update(hh, entry->dev, entry->ha); } -#endif /* CONFIG_ARPD */ +/* + * Invalidate all hh's, so that higher level will not try to use it. + */ -static void arpd_update(struct arp_table * entry, int loc) +static __inline__ void arp_invalidate_hhs(struct arp_table * entry) { -#ifdef CONFIG_ARPD - static struct arpd_request arpreq; - - arpreq.req = ARPD_UPDATE; - arpreq.ip = entry->ip; - arpreq.mask = entry->mask; - memcpy (arpreq.ha, entry->ha, MAX_ADDR_LEN); - arpreq.loc = loc; - arpreq.last_used = entry->last_used; - arpreq.last_updated = entry->last_updated; - arpreq.flags = entry->flags; - arpreq.dev = entry->dev; + struct hh_cache *hh; - kerneld_send(KERNELD_ARP, 0, sizeof(arpreq), - (char *) &arpreq, NULL); -#endif /* CONFIG_ARPD */ + for (hh=entry->hh; hh; hh=hh->hh_next) + hh->hh_uptodate = 0; } -/* - * Allocate memory for a new entry. If we are at the maximum limit - * of the internal ARP cache, arp_force_expire() an entry. NOTE: - * arp_force_expire() needs the cache to be locked, so therefore - * arp_add_entry() should only be called with the cache locked too! +/* + * Atomic attaching new hh entry. + * Return 1, if entry has been freed, rather than attached. */ -static struct arp_table * arp_add_entry(void) +static int arp_set_hh(struct hh_cache **hhp, struct hh_cache *hh) { - struct arp_table * entry; + unsigned long flags; + struct hh_cache *hh1; + struct arp_table *entry; -#ifdef CONFIG_ARPD - if (arp_size >= ARP_MAXSIZE) + atomic_inc(&hh->hh_refcnt); + + save_flags(flags); + cli(); + if ((hh1 = *hhp) == NULL) { - if (arp_force_expire() < 0) - return NULL; + *hhp = hh; + restore_flags(flags); + return 0; } -#endif /* CONFIG_ARPD */ - entry = (struct arp_table *) - kmalloc(sizeof(struct arp_table),GFP_ATOMIC); + entry = (struct arp_table*)hh->hh_arp; - if (entry != NULL) - ++arp_size; - return entry; + /* + * An hh1 entry is already attached to this point. + * Is it not linked to arp entry? Link it! + */ + if (!hh1->hh_arp && entry) + { + atomic_inc(&hh1->hh_refcnt); + hh1->hh_next = entry->hh; + entry->hh = hh1; + hh1->hh_arp = (void*)entry; + restore_flags(flags); + + if (entry->flags & ATF_COM) + entry->dev->header_cache_update(hh1, entry->dev, entry->ha); +#if RT_CACHE_DEBUG >= 1 + printk("arp_set_hh: %08x is reattached. Good!\n", entry->ip); +#endif + } +#if RT_CACHE_DEBUG >= 1 + else if (entry) + printk("arp_set_hh: %08x rr1 ok!\n", entry->ip); +#endif + restore_flags(flags); + if (atomic_dec_and_test(&hh->hh_refcnt)) + kfree_s(hh, sizeof(struct hh_cache)); + return 1; } +static __inline__ struct hh_cache * arp_alloc_hh(int htype) +{ + struct hh_cache *hh; + hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC); + if (hh) + { + memset(hh, 0, sizeof(struct hh_cache)); + hh->hh_type = htype; + } + return hh; +} /* - * Lookup ARP entry by (addr, dev) pair in the arpd. + * Test if a hardware address is all zero */ -static struct arp_table * arpd_lookup(u32 addr, unsigned short flags, - struct device * dev, - int loc) +static __inline__ int empty(unsigned char * addr, int len) { -#ifdef CONFIG_ARPD - static struct arpd_request arpreq, retreq; - struct arp_table * entry; - int rv, i; + while (len > 0) + { + if (*addr) + return 0; + len--; + addr++; + } + return 1; +} - arpreq.req = ARPD_LOOKUP; - arpreq.ip = addr; - arpreq.loc = loc; - - rv = kerneld_send(KERNELD_ARP, - sizeof(retreq) | KERNELD_WAIT, - sizeof(arpreq), - (char *) &arpreq, - (char *) &retreq); - /* don't worry about rv != 0 too much, it's probably - because arpd isn't running or an entry couldn't - be found */ - - if (rv != 0) - return NULL; - if (dev != retreq.dev) - return NULL; - if (! memcmp (retreq.ha, "\0\0\0\0\0\0", 6)) - return NULL; - arp_fast_lock(); - entry = arp_add_entry(); - arp_unlock(); +#ifdef CONFIG_ARPD - if (entry == NULL) - return NULL; +/* + * Send ARPD message. + */ +static void arpd_send(int req, u32 addr, struct device * dev, char *ha, + unsigned long updated) +{ + int retval; + struct sk_buff *skb; + struct arpd_request *arpreq; - entry->next = NULL; - entry->last_used = retreq.last_used; - entry->last_updated = retreq.last_updated; - entry->flags = retreq.flags; - entry->ip = retreq.ip; - entry->mask = retreq.mask; - memcpy (entry->ha, retreq.ha, MAX_ADDR_LEN); - arpreq.dev = entry->dev; + if (arpd_not_running) + return; - skb_queue_head_init(&entry->skb); - entry->hh = NULL; - entry->retries = 0; + skb = alloc_skb(sizeof(struct arpd_request), GFP_ATOMIC); + if (skb == NULL) + return; -#if RT_CACHE_DEBUG >= 2 - printk("Inserting arpd entry %08x\n in local cache.", entry->ip); -#endif - i = HASH(entry->ip); - arp_fast_lock(); - entry->next = arp_tables[i]->next; - arp_tables[i]->next = entry; - arp_unlock(); - return entry; -#endif /* CONFIG_ARPD */ - return NULL; -} + skb->free=1; + arpreq=(struct arpd_request *)skb_put(skb, sizeof(struct arpd_request)); + arpreq->req = req; + arpreq->ip = addr; + arpreq->dev = (unsigned long)dev; + arpreq->stamp = arpd_stamp; + arpreq->updated = updated; + if (ha) + memcpy(arpreq->ha, ha, sizeof(arpreq->ha)); + retval = netlink_post(NETLINK_ARPD, skb); + if (retval) + { + kfree_skb(skb, FREE_WRITE); + if (retval == -EUNATCH) + arpd_not_running = 1; + } +} /* - * Invalidate all hh's, so that higher level will not try to use it. + * Send ARPD update message. */ -static __inline__ void arp_invalidate_hhs(struct arp_table * entry) +static __inline__ void arpd_update(struct arp_table * entry) { - struct hh_cache *hh; - - for (hh=entry->hh; hh; hh=hh->hh_next) - hh->hh_uptodate = 0; + if (arpd_not_running) + return; + arpd_send(ARPD_UPDATE, entry->ip, entry->dev, entry->ha, + entry->last_updated); } /* - * Signal to device layer, that hardware address may be changed. + * Send ARPD lookup request. */ -static __inline__ void arp_update_hhs(struct arp_table * entry) +static __inline__ void arpd_lookup(u32 addr, struct device * dev) { - struct hh_cache *hh; - - for (hh=entry->hh; hh; hh=hh->hh_next) - entry->dev->header_cache_update(hh, entry->dev, entry->ha); + if (arpd_not_running) + return; + arpd_send(ARPD_LOOKUP, addr, dev, NULL, 0); } /* - * Check if there are too old entries and remove them. If the ATF_PERM - * flag is set, they are always left in the arp cache (permanent entry). - * If an entry was not be confirmed for ARP_CONFIRM_INTERVAL, - * declare it invalid and send point-to-point ARP request. - * If it will not be confirmed for ARP_CONFIRM_TIMEOUT, - * give it to shred by arp_expire_entry. + * Send ARPD flush message. */ -static void arp_check_expire(unsigned long dummy) +static __inline__ void arpd_flush(struct device * dev) { - int i; - unsigned long now = jiffies; + if (arpd_not_running) + return; + arpd_send(ARPD_FLUSH, 0, dev, NULL, 0); +} - del_timer(&arp_timer); - if (!arp_lock) - { - arp_fast_lock(); +static int arpd_callback(struct sk_buff *skb) +{ + struct device * dev; + struct arpd_request *retreq; - for (i = 0; i < ARP_TABLE_SIZE; i++) - { - struct arp_table *entry; - struct arp_table **pentry; - - pentry = &arp_tables[i]; + arpd_not_running = 0; + + if (skb->len != sizeof(struct arpd_request)) + { + kfree_skb(skb, FREE_READ); + return -EINVAL; + } + + retreq = (struct arpd_request *)skb->data; + dev = (struct device*)retreq->dev; + + if (retreq->stamp != arpd_stamp || !dev) + { + kfree_skb(skb, FREE_READ); + return -EINVAL; + } + + if (!retreq->updated || empty(retreq->ha, sizeof(retreq->ha))) + { +/* + * Invalid mapping: drop it and send ARP broadcast. + */ + arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL, + dev->dev_addr, NULL); + } + else + { + arp_fast_lock(); + arp_update(retreq->ip, retreq->ha, dev, NULL, 0); + arp_unlock(); + +/* + * Old mapping: we cannot trust it, send ARP broadcast to confirm it. + * If it will answer, the entry will be updated, + * if not ... we are lost. We will use it for ARP_CONFIRM_INTERVAL. + */ + if (jiffies - retreq->updated < ARPD_TIMEOUT) + arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL, + dev->dev_addr, NULL); + } + + kfree_skb(skb, FREE_READ); + return sizeof(struct arpd_request); +} + +#else + +static __inline__ void arpd_update(struct arp_table * entry) +{ + return; +} + +#endif /* CONFIG_ARPD */ + + + + +/* + * ARP expiration routines. + */ + +/* + * Force the expiry of an entry in the internal cache so the memory + * can be used for a new request. + */ + +static int arp_force_expire(void) +{ + int i; + struct arp_table *entry, **pentry; + struct arp_table **oldest_entry = NULL; + unsigned long oldest_used = ~0; + unsigned long flags; + unsigned long now = jiffies; + int result = 0; + + static last_index; + + if (ARP_LOCKED()) + return 0; + + save_flags(flags); + + if (last_index >= ARP_TABLE_SIZE) + last_index = 0; + + for (i = 0; i < ARP_TABLE_SIZE; i++, last_index++) + { + pentry = &arp_tables[last_index & (ARP_TABLE_SIZE-1)]; + + while ((entry = *pentry) != NULL) + { + if (!(entry->flags & ATF_PERM)) + { + int users; + cli(); + users = arp_count_hhs(entry); + + if (!users && now - entry->last_used > ARP_TIMEOUT) + { + *pentry = entry->next; + restore_flags(flags); +#if RT_CACHE_DEBUG >= 2 + printk("arp_force_expire: %08x expired\n", entry->ip); +#endif + arp_free_entry(entry); + result++; + if (arp_size < ARP_MAXSIZE) + goto done; + continue; + } + restore_flags(flags); + if (!users && entry->last_used < oldest_used) + { + oldest_entry = pentry; + oldest_used = entry->last_used; + } + } + pentry = &entry->next; + } + } + +done: + if (result || !oldest_entry) + return result; + + entry = *oldest_entry; + *oldest_entry = entry->next; +#if RT_CACHE_DEBUG >= 2 + printk("arp_force_expire: expiring %08x\n", entry->ip); +#endif + arp_free_entry(entry); + return 1; +} + +/* + * Check if there are too old entries and remove them. If the ATF_PERM + * flag is set, they are always left in the arp cache (permanent entry). + * If an entry was not be confirmed for ARP_CONFIRM_INTERVAL, + * send point-to-point ARP request. + * If it will not be confirmed for ARP_CONFIRM_TIMEOUT, + * give it to shred by arp_expire_entry. + */ + +static void arp_check_expire(unsigned long dummy) +{ + int i; + unsigned long now = jiffies; + + del_timer(&arp_timer); + +#ifdef CONFIG_ARPD + arpd_not_running = 0; +#endif + + ip_rt_check_expire(); + + arp_fast_lock(); + + if (!ARP_LOCKED()) + { + + for (i = 0; i < ARP_TABLE_SIZE; i++) + { + struct arp_table *entry, **pentry; + + pentry = &arp_tables[i]; + + while ((entry = *pentry) != NULL) + { + if (entry->flags & ATF_PERM) + { + pentry = &entry->next; + continue; + } - while ((entry = *pentry) != NULL) - { cli(); if (now - entry->last_used > ARP_TIMEOUT - && !(entry->flags & ATF_PERM) && !arp_count_hhs(entry)) { *pentry = entry->next; @@ -618,17 +838,15 @@ printk("arp_expire: %08x expired\n", entry->ip); #endif arp_free_entry(entry); + continue; } - else if (entry->last_updated - && now - entry->last_updated > ARP_CONFIRM_INTERVAL - && !(entry->flags & ATF_PERM)) + sti(); + if (entry->last_updated + && now - entry->last_updated > ARP_CONFIRM_INTERVAL + && !(entry->flags & ATF_PERM)) { struct device * dev = entry->dev; - pentry = &entry->next; - entry->flags &= ~ATF_COM; - arp_invalidate_hhs(entry); - sti(); - entry->retries = ARP_MAX_TRIES+1; + entry->retries = ARP_MAX_TRIES+ARP_MAX_PINGS; del_timer(&entry->timer); entry->timer.expires = jiffies + ARP_CONFIRM_TIMEOUT; add_timer(&entry->timer); @@ -639,14 +857,12 @@ printk("arp_expire: %08x requires confirmation\n", entry->ip); #endif } - else - pentry = &entry->next; /* go to next entry */ + pentry = &entry->next; /* go to next entry */ } } - arp_unlock(); } - ip_rt_check_expire(); + arp_unlock(); /* * Set the timer again. @@ -669,34 +885,46 @@ unsigned long hash; unsigned long flags; + arp_fast_lock(); + save_flags(flags); cli(); + del_timer(&entry->timer); /* - * Since all timeouts are handled with interrupts enabled, there is a - * small chance, that this entry has just been resolved by an incoming - * packet. This is the only race condition, but it is handled... + * If arp table is locked, defer expire processing. */ - - if (entry->flags & ATF_COM) + if (ARP_LOCKED()) { +#if RT_CACHE_DEBUG >= 1 + printk(KERN_DEBUG "arp_expire_request: %08x deferred\n", entry->ip); +#endif + entry->timer.expires = jiffies + HZ/10; + add_timer(&entry->timer); restore_flags(flags); + arp_unlock(); return; } - if (arp_lock) + /* + * Since all timeouts are handled with interrupts enabled, there is a + * small chance, that this entry has just been resolved by an incoming + * packet. This is the only race condition, but it is handled... + * + * One exception: if entry is COMPLETE but old, + * it means that point-to-point ARP ping has been failed + * (It really occurs with Cisco 4000 routers) + * We should reconfirm it. + */ + + if ((entry->flags & ATF_COM) && entry->last_updated + && jiffies - entry->last_updated <= ARP_CONFIRM_INTERVAL) { -#if RT_CACHE_DEBUG >= 1 - printk("arp_expire_request: %08x postponed\n", entry->ip); -#endif - del_timer(&entry->timer); - entry->timer.expires = jiffies + HZ/10; - add_timer(&entry->timer); restore_flags(flags); + arp_unlock(); return; } - arp_fast_lock(); restore_flags(flags); if (entry->last_updated && --entry->retries > 0) @@ -707,29 +935,47 @@ printk("arp_expire_request: %08x timed out\n", entry->ip); #endif /* Set new timer. */ - del_timer(&entry->timer); entry->timer.expires = jiffies + ARP_RES_TIME; add_timer(&entry->timer); - arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, - NULL, dev->dev_addr, NULL); + arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, + entry->retries > ARP_MAX_TRIES ? entry->ha : NULL, + dev->dev_addr, NULL); arp_unlock(); return; } - arp_release_entry(entry); + /* + * The host is really dead. + */ + + arp_purge_send_q(entry); cli(); if (arp_count_hhs(entry)) { + /* + * The host is dead, but someone refers to it. + * It is useless to drop this entry just now, + * it will be born again, so that + * we keep it, but slow down retransmitting + * to ARP_DEAD_RES_TIME. + */ + struct device *dev = entry->dev; #if RT_CACHE_DEBUG >= 2 printk("arp_expire_request: %08x is dead\n", entry->ip); #endif - arp_release_entry(entry); entry->retries = ARP_MAX_TRIES; + entry->flags &= ~ATF_COM; + arp_invalidate_hhs(entry); restore_flags(flags); + + /* + * Declare the entry dead. + */ entry->last_updated = 0; - del_timer(&entry->timer); + arpd_update(entry); + entry->timer.expires = jiffies + ARP_DEAD_RES_TIME; add_timer(&entry->timer); arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, @@ -739,30 +985,65 @@ } restore_flags(flags); + entry->last_updated = 0; + arpd_update(entry); + hash = HASH(entry->ip); pentry = &arp_tables[hash]; while (*pentry != NULL) { - if (*pentry == entry) + if (*pentry != entry) { - cli(); - *pentry = entry->next; - restore_flags(flags); + pentry = &(*pentry)->next; + continue; + } + *pentry = entry->next; #if RT_CACHE_DEBUG >= 2 - printk("arp_expire_request: %08x is killed\n", entry->ip); + printk("arp_expire_request: %08x is killed\n", entry->ip); #endif - arp_free_entry(entry); - arp_unlock(); - return; - } - pentry = &(*pentry)->next; + arp_free_entry(entry); } - printk("arp_expire_request: bug: ARP entry is lost!\n"); arp_unlock(); } + +/* + * Allocate memory for a new entry. If we are at the maximum limit + * of the internal ARP cache, arp_force_expire() an entry. NOTE: + * arp_force_expire() needs the cache to be locked, so therefore + * arp_alloc_entry() should only be called with the cache locked too! + */ + +static struct arp_table * arp_alloc_entry(void) +{ + struct arp_table * entry; + + + if (arp_size >= ARP_MAXSIZE) + arp_force_expire(); + + entry = (struct arp_table *) + kmalloc(sizeof(struct arp_table),GFP_ATOMIC); + + if (entry != NULL) + { + atomic_inc(&arp_size); + memset(entry, 0, sizeof(struct arp_table)); + + entry->mask = DEF_ARP_NETMASK; + init_timer(&entry->timer); + entry->timer.function = arp_expire_request; + entry->timer.data = (unsigned long)entry; + entry->last_updated = entry->last_used = jiffies; + skb_queue_head_init(&entry->skb); + } + return entry; +} + + + /* * Purge a device from the ARP queue */ @@ -774,15 +1055,17 @@ if (event != NETDEV_DOWN) return NOTIFY_DONE; - /* - * This is a bit OTT - maybe we need some arp semaphores instead. - */ -#if RT_CACHE_DEBUG >= 1 - if (arp_lock) - printk("arp_device_event: bug\n"); +#ifdef CONFIG_ARPD + arpd_flush(dev); + arpd_stamp++; #endif + arp_fast_lock(); +#if RT_CACHE_DEBUG >= 1 + if (ARP_LOCKED()) + printk("arp_device_event: impossible\n"); +#endif for (i = 0; i < FULL_ARP_TABLE_SIZE; i++) { @@ -805,104 +1088,29 @@ } + /* - * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast - * message. + * This will try to retransmit everything on the queue. */ -void arp_send(int type, int ptype, u32 dest_ip, - struct device *dev, u32 src_ip, - unsigned char *dest_hw, unsigned char *src_hw, - unsigned char *target_hw) +static void arp_send_q(struct arp_table *entry) { struct sk_buff *skb; - struct arphdr *arp; - unsigned char *arp_ptr; - /* - * No arp on this interface. - */ - - if (dev->flags&IFF_NOARP) - return; + unsigned long flags; /* - * Allocate a buffer + * Empty the entire queue, building its data up ready to send */ - skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) - + dev->hard_header_len, GFP_ATOMIC); - if (skb == NULL) + if(!(entry->flags&ATF_COM)) { - printk("ARP: no memory to send an arp packet\n"); - return; - } - skb_reserve(skb, dev->hard_header_len); - arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); - skb->arp = 1; - skb->dev = dev; - skb->free = 1; - skb->protocol = htons (ETH_P_IP); - - /* - * Fill the device header for the ARP frame - */ - - dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len); - - /* Fill out the arp protocol part. */ - arp->ar_hrd = htons(dev->type); -#ifdef CONFIG_AX25 -#ifdef CONFIG_NETROM - arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP); -#else - arp->ar_pro = (dev->type != ARPHRD_AX25) ? htons(ETH_P_IP) : htons(AX25_P_IP); -#endif -#else - arp->ar_pro = htons(ETH_P_IP); -#endif - arp->ar_hln = dev->addr_len; - arp->ar_pln = 4; - arp->ar_op = htons(type); - - arp_ptr=(unsigned char *)(arp+1); - - memcpy(arp_ptr, src_hw, dev->addr_len); - arp_ptr+=dev->addr_len; - memcpy(arp_ptr, &src_ip,4); - arp_ptr+=4; - if (target_hw != NULL) - memcpy(arp_ptr, target_hw, dev->addr_len); - else - memset(arp_ptr, 0, dev->addr_len); - arp_ptr+=dev->addr_len; - memcpy(arp_ptr, &dest_ip, 4); - - dev_queue_xmit(skb, dev, 0); -} - -/* - * This will try to retransmit everything on the queue. - */ - -static void arp_send_q(struct arp_table *entry) -{ - struct sk_buff *skb; - - unsigned long flags; - - /* - * Empty the entire queue, building its data up ready to send - */ - - if(!(entry->flags&ATF_COM)) - { - printk("arp_send_q: incomplete entry for %s\n", - in_ntoa(entry->ip)); - /* Can't flush the skb, because RFC1122 says to hang on to */ - /* at least one from any unresolved entry. --MS */ - /* What's happened is that someone has 'unresolved' the entry - as we got to use it - this 'can't happen' -- AC */ + printk("arp_send_q: incomplete entry for %s\n", + in_ntoa(entry->ip)); + /* Can't flush the skb, because RFC1122 says to hang on to */ + /* at least one from any unresolved entry. --MS */ + /* What's happened is that someone has 'unresolved' the entry + as we got to use it - this 'can't happen' -- AC */ return; } @@ -927,435 +1135,137 @@ } -/* - * Delete an ARP mapping entry in the cache. - */ - -static void arp_destroy(struct arp_table * entry) +static int +arp_update (u32 sip, char *sha, struct device * dev, + struct arp_table *ientry, int grat) { - struct arp_table *entry1; - struct arp_table **pentry; + struct arp_table * entry; + unsigned long hash; - if (entry->flags & ATF_PUBL) - pentry = &arp_proxy_list; - else - pentry = &arp_tables[HASH(entry->ip)]; + hash = HASH(sip); - while ((entry1 = *pentry) != NULL) + for (entry=arp_tables[hash]; entry; entry = entry->next) + if (entry->ip == sip && entry->dev == dev) + break; + + if (entry) { - if (entry1 == entry) +/* + * Entry found; update it only if it is not a permanent entry. + */ + if (!(entry->flags & ATF_PERM)) { - *pentry = entry1->next; del_timer(&entry->timer); - arp_free_entry(entry); - return; + entry->last_updated = jiffies; + if (memcmp(entry->ha, sha, dev->addr_len)!=0) + { + memcpy(entry->ha, sha, dev->addr_len); + if (entry->flags & ATF_COM) + arp_update_hhs(entry); + } + arpd_update(entry); } - pentry = &entry1->next; - } -} + if (!(entry->flags & ATF_COM)) + { /* - * Receive an arp request by the device layer. Maybe I rewrite it, to - * use the incoming packet for the reply. The time for the current - * "overhead" isn't that high... + * This entry was incomplete. Delete the retransmit timer + * and switch to complete status. */ - -int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ -/* - * We shouldn't use this type conversion. Check later. + entry->flags |= ATF_COM; + arp_update_hhs(entry); +/* + * Send out waiting packets. We might have problems, if someone is + * manually removing entries right now -- entry might become invalid + * underneath us. */ - - struct arphdr *arp = (struct arphdr *)skb->h.raw; - unsigned char *arp_ptr= (unsigned char *)(arp+1); - struct arp_table *entry; - struct arp_table *proxy_entry; - unsigned long hash, grat=0; - unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */ - unsigned char *sha,*tha; - u32 sip,tip; - -/* - * The hardware length of the packet should match the hardware length - * of the device. Similarly, the hardware types should match. The - * device should be ARP-able. Also, if pln is not 4, then the lookup - * is not from an IP number. We can't currently handle this, so toss - * it. - */ - if (arp->ar_hln != dev->addr_len || - dev->type != ntohs(arp->ar_hrd) || - dev->flags & IFF_NOARP || - arp->ar_pln != 4) - { - kfree_skb(skb, FREE_READ); - return 0; - /* Should this be an error/printk? Seems like something */ - /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */ + arp_send_q(entry); + } + return 1; } /* - * Another test. - * The logic here is that the protocol being looked up by arp should - * match the protocol the device speaks. If it doesn't, there is a - * problem, so toss the packet. + * No entry found. Need to add a new entry to the arp table. */ -/* Again, should this be an error/printk? -- MS */ - - switch (dev->type) - { -#ifdef CONFIG_AX25 - case ARPHRD_AX25: - if(arp->ar_pro != htons(AX25_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; -#endif -#ifdef CONFIG_NETROM - case ARPHRD_NETROM: - if(arp->ar_pro != htons(AX25_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; -#endif - case ARPHRD_ETHER: - case ARPHRD_ARCNET: - case ARPHRD_METRICOM: - if(arp->ar_pro != htons(ETH_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; + entry = ientry; - case ARPHRD_IEEE802: - if(arp->ar_pro != htons(ETH_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; + if (grat && !entry) + return 0; - default: - printk("ARP: dev->type mangled!\n"); - kfree_skb(skb, FREE_READ); + if (!entry) + { + entry = arp_alloc_entry(); + if (!entry) return 0; + + entry->ip = sip; + entry->flags = ATF_COM; + memcpy(entry->ha, sha, dev->addr_len); + entry->dev = dev; } -/* - * Extract fields - */ + entry->last_updated = entry->last_used = jiffies; + arpd_update(entry); - sha=arp_ptr; - arp_ptr += dev->addr_len; - memcpy(&sip, arp_ptr, 4); - arp_ptr += 4; - tha=arp_ptr; - arp_ptr += dev->addr_len; - memcpy(&tip, arp_ptr, 4); - -/* - * Check for bad requests for 127.x.x.x and requests for multicast - * addresses. If this is one such, delete it. - */ - if (LOOPBACK(tip) || MULTICAST(tip)) + if (!ARP_LOCKED()) { - kfree_skb(skb, FREE_READ); + entry->next = arp_tables[hash]; + arp_tables[hash] = entry; return 0; } +#if RT_CACHE_DEBUG >= 2 + printk("arp_update: %08x backlogged\n", entry->ip); +#endif + arp_enqueue(&arp_backlog, entry); + arp_bh_mask |= ARP_BH_BACKLOG; + return 0; +} -/* - * Process entry. The idea here is we want to send a reply if it is a - * request for us or if it is a request for someone else that we hold - * a proxy for. We want to add an entry to our cache if it is a reply - * to us or if it is a request for our address. - * (The assumption for this last is that if someone is requesting our - * address, they are probably intending to talk to us, so it saves time - * if we cache their address. Their address is also probably not in - * our cache, since ours is not in their cache.) - * - * Putting this another way, we only care about replies if they are to - * us, in which case we add them to the cache. For requests, we care - * about those for us and those for our proxies. We reply to both, - * and in the case of requests for us we add the requester to the arp - * cache. - */ + + +static __inline__ struct arp_table *arp_lookup(u32 paddr, struct device * dev) +{ + struct arp_table *entry; + + for (entry = arp_tables[HASH(paddr)]; entry != NULL; entry = entry->next) + if (entry->ip == paddr && (!dev || entry->dev == dev)) + return entry; + return NULL; +} /* - * try to switch to alias device whose addr is tip or closest to sip. + * Find an arp mapping in the cache. If not found, return false. */ -#ifdef CONFIG_NET_ALIAS - if (tip != dev->pa_addr && net_alias_has(skb->dev)) - { - /* - * net_alias_dev_rcv_sel32 returns main dev if it fails to found other. - */ - dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip); +int arp_query(unsigned char *haddr, u32 paddr, struct device * dev) +{ + struct arp_table *entry; - if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP) + arp_fast_lock(); + + entry = arp_lookup(paddr, dev); + + if (entry != NULL) + { + entry->last_used = jiffies; + if (entry->flags & ATF_COM) { - kfree_skb(skb, FREE_READ); - return 0; + memcpy(haddr, entry->ha, dev->addr_len); + arp_unlock(); + return 1; } } -#endif + arp_unlock(); + return 0; +} - if (arp->ar_op == htons(ARPOP_REQUEST)) - { -/* - * Only reply for the real device address or when it's in our proxy tables - */ - if (tip != dev->pa_addr) - { -/* - * To get in here, it is a request for someone else. We need to - * check if that someone else is one of our proxies. If it isn't, - * we can toss it. - */ - arp_fast_lock(); - - for (proxy_entry=arp_proxy_list; - proxy_entry; - proxy_entry = proxy_entry->next) - { - /* we will respond to a proxy arp request - if the masked arp table ip matches the masked - tip. This allows a single proxy arp table - entry to be used on a gateway machine to handle - all requests for a whole network, rather than - having to use a huge number of proxy arp entries - and having to keep them uptodate. - */ - if (proxy_entry->dev == dev && - !((proxy_entry->ip^tip)&proxy_entry->mask)) - break; - - } - if (proxy_entry) - { - memcpy(ha, proxy_entry->ha, dev->addr_len); - arp_unlock(); - arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha, sha); - kfree_skb(skb, FREE_READ); - return 0; - } - else - { - arp_unlock(); - } - } - else - { -/* - * To get here, it must be an arp request for us. We need to reply. - */ - arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); - } - grat = 1; - goto gratuitous; - } -/* - * It is now an arp reply. - */ - if(ip_chk_addr(tip)!=IS_MYADDR) - { -/* - * Replies to other machines get tossed. - */ - kfree_skb(skb, FREE_READ); - return 0; - } -/* - * Now all replies are handled. Next, anything that falls through to here - * needs to be added to the arp cache, or have its entry updated if it is - * there. - */ - -gratuitous: - - arp_fast_lock(); - - - hash = HASH(sip); - for (entry=arp_tables[hash]; entry; entry=entry->next) - if (entry->ip == sip && entry->dev == dev) - break; - - if (entry) - { -/* - * Entry found; update it only if it is not a permanent entry. - */ - if (!(entry->flags & ATF_PERM)) - { - if(memcmp(entry->ha, sha,dev->addr_len)!=0) - { - memcpy(entry->ha, sha, dev->addr_len); - if(entry->flags & ATF_COM) - arp_update_hhs(entry); - } - entry->last_updated = jiffies; - arpd_update(entry, __LINE__); - } - if (!(entry->flags & ATF_COM)) - { -/* - * This entry was incomplete. Delete the retransmit timer - * and switch to complete status. - */ - del_timer(&entry->timer); - entry->flags |= ATF_COM; - arp_update_hhs(entry); -/* - * Send out waiting packets. We might have problems, if someone is - * manually removing entries right now -- entry might become invalid - * underneath us. - */ - arp_send_q(entry); - } - } - else - { -/* - * No entry found. Need to add a new entry to the arp table. - */ - - if (grat) - goto end; - - entry = arp_add_entry(); - if(entry == NULL) - { - arp_unlock(); -#if RT_CACHE_DEBUG >= 2 - printk("ARP: no memory for new arp entry\n"); -#endif - kfree_skb(skb, FREE_READ); - return 0; - } - - entry->mask = DEF_ARP_NETMASK; - entry->ip = sip; - entry->flags = ATF_COM; - entry->hh = NULL; - init_timer(&entry->timer); - entry->timer.function = arp_expire_request; - entry->timer.data = (unsigned long)entry; - memcpy(entry->ha, sha, dev->addr_len); - entry->last_updated = entry->last_used = jiffies; - arpd_update(entry, __LINE__); -/* - * make entry point to 'correct' device - */ - -#ifdef CONFIG_NET_ALIAS - entry->dev = dev; -#else - entry->dev = skb->dev; -#endif - skb_queue_head_init(&entry->skb); - if (arp_lock == 1) - { - entry->next = arp_tables[hash]; - arp_tables[hash] = entry; - } - else - { -#if RT_CACHE_DEBUG >= 2 - printk("arp_rcv: %08x backlogged\n", entry->ip); -#endif - arp_enqueue(&arp_backlog, entry); - arp_bh_mask |= ARP_BH_BACKLOG; - } - } - -/* - * Replies have been sent, and entries have been added. All done. - */ - -end: - kfree_skb(skb, FREE_READ); - arp_unlock(); - return 0; -} - -/* - * Lookup ARP entry by (addr, dev) pair. - * Flags: ATF_PUBL - search for proxy entries - * ATF_NETMASK - search for proxy network entry. - * NOTE: should be called with locked ARP tables. - */ -static struct arp_table *arp_lookup(u32 paddr, unsigned short flags, struct device * dev) -{ - struct arp_table *entry; - - if (!(flags & ATF_PUBL)) - { - for (entry = arp_tables[HASH(paddr)]; - entry != NULL; entry = entry->next) - if (entry->ip == paddr && (!dev || entry->dev == dev)) - break; - return entry; - } - - if (!(flags & ATF_NETMASK)) - { - for (entry = arp_proxy_list; - entry != NULL; entry = entry->next) - if (entry->ip == paddr && (!dev || entry->dev == dev)) - break; - return entry; - } - - for (entry=arp_proxy_list; entry != NULL; entry = entry->next) - if (!((entry->ip^paddr)&entry->mask) && - (!dev || entry->dev == dev)) - break; - return entry; -} - -/* - * Find an arp mapping in the cache. If not found, return false. - */ - -int arp_query(unsigned char *haddr, u32 paddr, struct device * dev) -{ - struct arp_table *entry; - - arp_fast_lock(); - - entry = arp_lookup(paddr, 0, dev); - if (entry == NULL) - entry = arpd_lookup(paddr, 0, dev, __LINE__); - - if (entry != NULL) - { - entry->last_used = jiffies; - if (entry->flags & ATF_COM) - { - memcpy(haddr, entry->ha, dev->addr_len); - arpd_update(entry, __LINE__); - arp_unlock(); - return 1; - } - } - arpd_update(entry, __LINE__); - arp_unlock(); - return 0; -} - - -static int arp_set_predefined(int addr_hint, unsigned char * haddr, __u32 paddr, struct device * dev) +static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct device * dev) { switch (addr_hint) { case IS_MYADDR: - printk("ARP: arp called for own IP address\n"); + printk(KERN_DEBUG "ARP: arp called for own IP address\n"); memcpy(haddr, dev->dev_addr, dev->addr_len); return 1; #ifdef CONFIG_IP_MULTICAST @@ -1387,325 +1297,221 @@ } /* - * Find an arp mapping in the cache. If not found, post a request. + * Create a new unresolved entry. */ -int arp_find(unsigned char *haddr, u32 paddr, struct device *dev, - u32 saddr, struct sk_buff *skb) +struct arp_table * arp_new_entry(u32 paddr, struct device *dev, struct hh_cache *hh, struct sk_buff *skb) { struct arp_table *entry; - unsigned long hash; - - if (arp_set_predefined(ip_chk_addr(paddr), haddr, paddr, dev)) - { - if (skb) - skb->arp = 1; - return 0; - } - - hash = HASH(paddr); - arp_fast_lock(); - - /* - * Find an entry - */ - entry = arp_lookup(paddr, 0, dev); - if (entry == NULL) - entry = arpd_lookup(paddr, 0, dev, __LINE__); - - if (entry != NULL) /* It exists */ - { - if (!(entry->flags & ATF_COM)) - { - /* - * A request was already send, but no reply yet. Thus - * queue the packet with the previous attempt - */ - - if (skb != NULL) - { - if (entry->last_updated) - { - skb_queue_tail(&entry->skb, skb); - skb_device_unlock(skb); - } - /* - * If last_updated==0 host is dead, so - * drop skb's and set socket error. - */ - else - { -#if 0 - /* - * FIXME: ICMP HOST UNREACHABLE should be - * sent in this situation. --ANK - */ - if (skb->sk) - { - skb->sk->err = EHOSTDOWN; - skb->sk->error_report(skb->sk); - } -#else - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); -#endif - dev_kfree_skb(skb, FREE_WRITE); - } - } - arp_unlock(); - return 1; - } - /* - * Update the record - */ - - entry->last_used = jiffies; - memcpy(haddr, entry->ha, dev->addr_len); - arpd_update(entry, __LINE__); - if (skb) - skb->arp = 1; - arp_unlock(); - return 0; - } + entry = arp_alloc_entry(); - /* - * Create a new unresolved entry. - */ - - entry = arp_add_entry(); if (entry != NULL) { - entry->last_updated = entry->last_used = jiffies; - entry->flags = 0; entry->ip = paddr; - entry->mask = DEF_ARP_NETMASK; - memset(entry->ha, 0, dev->addr_len); entry->dev = dev; - entry->hh = NULL; - arpd_update(entry, __LINE__); - init_timer(&entry->timer); - entry->timer.function = arp_expire_request; - entry->timer.data = (unsigned long)entry; + if (hh) + { + entry->hh = hh; + atomic_inc(&hh->hh_refcnt); + hh->hh_arp = (void*)entry; + } entry->timer.expires = jiffies + ARP_RES_TIME; - skb_queue_head_init(&entry->skb); + if (skb != NULL) { skb_queue_tail(&entry->skb, skb); skb_device_unlock(skb); } - if (arp_lock == 1) + + if (!ARP_LOCKED()) { + unsigned long hash = HASH(paddr); entry->next = arp_tables[hash]; arp_tables[hash] = entry; add_timer(&entry->timer); entry->retries = ARP_MAX_TRIES; +#ifdef CONFIG_ARPD + if (!arpd_not_running) + arpd_lookup(paddr, dev); + else +#endif + arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, dev->pa_addr, NULL, + dev->dev_addr, NULL); } else { #if RT_CACHE_DEBUG >= 2 - printk("arp_find: %08x backlogged\n", entry->ip); + printk("arp_new_entry: %08x backlogged\n", entry->ip); #endif - arp_enqueue(&arp_backlog, entry); + arp_enqueue(&arp_req_backlog, entry); arp_bh_mask |= ARP_BH_BACKLOG; } } - else if (skb != NULL) - dev_kfree_skb(skb, FREE_WRITE); - arp_unlock(); - - /* - * If we didn't find an entry, we will try to send an ARP packet. - */ - - arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, saddr, NULL, - dev->dev_addr, NULL); - - return 1; + return entry; } /* - * Write the contents of the ARP cache to a PROCfs file. + * Find an arp mapping in the cache. If not found, post a request. */ -#define HBUFFERLEN 30 - -int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +int arp_find(unsigned char *haddr, u32 paddr, struct device *dev, + u32 saddr, struct sk_buff *skb) { - int len=0; - off_t pos=0; - int size; struct arp_table *entry; - char hbuffer[HBUFFERLEN]; - int i,j,k; - const char hexbuf[] = "0123456789ABCDEF"; - - size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n"); + unsigned long hash; - pos+=size; - len+=size; + if (arp_set_predefined(ip_chk_addr(paddr), haddr, paddr, dev)) + { + if (skb) + skb->arp = 1; + return 0; + } + hash = HASH(paddr); arp_fast_lock(); - for(i=0; inext) + if (entry->flags & ATF_COM) { -/* - * Convert hardware address to XX:XX:XX:XX ... form. - */ -#ifdef CONFIG_AX25 -#ifdef CONFIG_NETROM - if (entry->dev->type == ARPHRD_AX25 || entry->dev->type == ARPHRD_NETROM) - strcpy(hbuffer,ax2asc((ax25_address *)entry->ha)); - else { -#else - if(entry->dev->type==ARPHRD_AX25) - strcpy(hbuffer,ax2asc((ax25_address *)entry->ha)); - else { -#endif -#endif + entry->last_used = jiffies; + memcpy(haddr, entry->ha, dev->addr_len); + if (skb) + skb->arp = 1; + arp_unlock(); + return 0; + } - for(k=0,j=0;kdev->addr_len;j++) + /* + * A request was already send, but no reply yet. Thus + * queue the packet with the previous attempt + */ + + if (skb != NULL) + { + if (entry->last_updated) { - hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ]; - hbuffer[k++]=hexbuf[ entry->ha[j]&15 ]; - hbuffer[k++]=':'; + skb_queue_tail(&entry->skb, skb); + skb_device_unlock(skb); } - hbuffer[--k]=0; - -#ifdef CONFIG_AX25 + /* + * If last_updated==0 host is dead, so + * drop skb's and set socket error. + */ + else + { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); + dev_kfree_skb(skb, FREE_WRITE); } -#endif - size = sprintf(buffer+len, - "%-17s0x%-10x0x%-10x%s", - in_ntoa(entry->ip), - (unsigned int)entry->dev->type, - entry->flags, - hbuffer); -#if RT_CACHE_DEBUG < 2 - size += sprintf(buffer+len+size, - " %-17s %s\n", - entry->mask==DEF_ARP_NETMASK ? - "*" : in_ntoa(entry->mask), entry->dev->name); -#else - size += sprintf(buffer+len+size, - " %-17s %s\t%ld\t%1d\n", - entry->mask==DEF_ARP_NETMASK ? - "*" : in_ntoa(entry->mask), entry->dev->name, - entry->hh ? entry->hh->hh_refcnt : -1, - entry->hh ? entry->hh->hh_uptodate : 0); -#endif - - len += size; - pos += size; - - if (pos <= offset) - len=0; - if (pos >= offset+length) - goto done; } + arp_unlock(); + return 1; } -done: + + entry = arp_new_entry(paddr, dev, NULL, skb); + + if (skb != NULL && !entry) + dev_kfree_skb(skb, FREE_WRITE); + arp_unlock(); - - *start = buffer+len-(pos-offset); /* Start of wanted data */ - len = pos-offset; /* Start slop */ - if (len>length) - len = length; /* Ending slop */ - return len; + return 1; } - +/* + * Binding hardware header cache entry. + * It is the only really complicated part of arp code. + * We have no locking for hh records, so that + * all possible race conditions should be resolved by + * cli()/sti() pairs. + * + * Important note: hhs never disapear from lists, if ARP_LOCKED, + * this fact allows to scan hh lists with enabled interrupts, + * but results in generating duplicate hh entries. + * It is harmless. (and I've never seen such event) + * + * Returns 0, if hh has been just created, so that + * caller should fill it. + */ int arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short htype, u32 paddr) { struct arp_table *entry; - struct hh_cache *hh = *hhp; + struct hh_cache *hh; int addr_hint; unsigned long flags; - if (hh) - return 1; + save_flags(flags); if ((addr_hint = ip_chk_addr(paddr)) != 0) { unsigned char haddr[MAX_ADDR_LEN]; - if (hh) + if (*hhp) return 1; - hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC); + hh = arp_alloc_hh(htype); if (!hh) return 1; arp_set_predefined(addr_hint, haddr, paddr, dev); - hh->hh_uptodate = 0; - hh->hh_refcnt = 1; - hh->hh_arp = NULL; - hh->hh_next = NULL; - hh->hh_type = htype; - *hhp = hh; dev->header_cache_update(hh, dev, haddr); - return 0; + return arp_set_hh(hhp, hh); } - save_flags(flags); - arp_fast_lock(); - entry = arp_lookup(paddr, 0, dev); - if (entry == NULL) - entry = arpd_lookup(paddr, 0, dev, __LINE__); + entry = arp_lookup(paddr, dev); if (entry) { - cli(); for (hh = entry->hh; hh; hh=hh->hh_next) if (hh->hh_type == htype) break; + if (hh) { - hh->hh_refcnt++; - *hhp = hh; - restore_flags(flags); + arp_set_hh(hhp, hh); arp_unlock(); return 1; } - restore_flags(flags); } - hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC); + hh = arp_alloc_hh(htype); if (!hh) { arp_unlock(); return 1; } - hh->hh_uptodate = 0; - hh->hh_refcnt = 1; - hh->hh_arp = NULL; - hh->hh_next = NULL; - hh->hh_type = htype; - if (entry) { - dev->header_cache_update(hh, dev, entry->ha); - *hhp = hh; + cli(); hh->hh_arp = (void*)entry; + hh->hh_next = entry->hh; entry->hh = hh; - hh->hh_refcnt++; + atomic_inc(&hh->hh_refcnt); restore_flags(flags); + + if (entry->flags & ATF_COM) + dev->header_cache_update(hh, dev, entry->ha); + + if (arp_set_hh(hhp, hh)) + { + arp_unlock(); + return 0; + } + entry->last_used = jiffies; - arpd_update(entry, __LINE__); arp_unlock(); return 0; } - - /* - * Create a new unresolved entry. - */ - - entry = arp_add_entry(); + entry = arp_new_entry(paddr, dev, hh, NULL); if (entry == NULL) { kfree_s(hh, sizeof(struct hh_cache)); @@ -1713,91 +1519,74 @@ return 1; } - entry->last_updated = entry->last_used = jiffies; - entry->flags = 0; - entry->ip = paddr; - entry->mask = DEF_ARP_NETMASK; - memset(entry->ha, 0, dev->addr_len); - entry->dev = dev; - entry->hh = hh; - arpd_update(entry, __LINE__); - ATOMIC_INCR(&hh->hh_refcnt); - init_timer(&entry->timer); - entry->timer.function = arp_expire_request; - entry->timer.data = (unsigned long)entry; - entry->timer.expires = jiffies + ARP_RES_TIME; - skb_queue_head_init(&entry->skb); - - if (arp_lock == 1) + if (!arp_set_hh(hhp, hh)) { - unsigned long hash = HASH(paddr); - cli(); - entry->next = arp_tables[hash]; - arp_tables[hash] = entry; - hh->hh_arp = (void*)entry; - entry->retries = ARP_MAX_TRIES; - restore_flags(flags); - - add_timer(&entry->timer); - arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, dev->pa_addr, NULL, dev->dev_addr, NULL); - } - else - { -#if RT_CACHE_DEBUG >= 1 - printk("arp_cache_bind: %08x backlogged\n", entry->ip); -#endif - arp_enqueue(&arp_backlog, entry); - arp_bh_mask |= ARP_BH_BACKLOG; + arp_unlock(); + return 0; } - *hhp = hh; arp_unlock(); - return 0; + return 1; } static void arp_run_bh() { unsigned long flags; struct arp_table *entry, *entry1; + struct device * dev; + unsigned long hash; struct hh_cache *hh; - __u32 sip; + u32 sip; save_flags(flags); cli(); - if (!arp_lock) + arp_fast_lock(); + + while (arp_bh_mask) { - arp_fast_lock(); + arp_bh_mask &= ~ARP_BH_BACKLOG; while ((entry = arp_dequeue(&arp_backlog)) != NULL) { - unsigned long hash; - sti(); + restore_flags(flags); + if (arp_update(entry->ip, entry->ha, entry->dev, entry, 0)) + arp_free_entry(entry); + cli(); + } + + cli(); + while ((entry = arp_dequeue(&arp_req_backlog)) != NULL) + { + restore_flags(flags); + + dev = entry->dev; sip = entry->ip; hash = HASH(sip); - /* It's possible, that an entry with the same pair - * (addr,type) was already created. Our entry is older, - * so it should be discarded. - */ - for (entry1=arp_tables[hash]; entry1; entry1=entry1->next) - if (entry1->ip==sip && entry1->dev == entry->dev) + for (entry1 = arp_tables[hash]; entry1; entry1 = entry1->next) + if (entry1->ip == sip && entry1->dev == dev) break; if (!entry1) { - struct device * dev = entry->dev; cli(); entry->next = arp_tables[hash]; arp_tables[hash] = entry; - for (hh=entry->hh; hh; hh=hh->hh_next) - hh->hh_arp = (void*)entry; - sti(); - del_timer(&entry->timer); + restore_flags(flags); entry->timer.expires = jiffies + ARP_RES_TIME; - add_timer(&entry->timer); entry->retries = ARP_MAX_TRIES; - arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, NULL, dev->dev_addr, NULL); + entry->last_used = jiffies; + if (!(entry->flags & ATF_COM)) + { + add_timer(&entry->timer); +#ifdef CONFIG_ARPD + if (!arpd_not_running) + arpd_lookup(sip, dev); + else +#endif + arp_send(ARPOP_REQUEST, ETH_P_ARP, sip, dev, dev->pa_addr, NULL, dev->dev_addr, NULL); + } #if RT_CACHE_DEBUG >= 1 - printk("arp_run_bh: %08x reinstalled\n", sip); + printk(KERN_DEBUG "arp_run_bh: %08x reinstalled\n", sip); #endif } else @@ -1824,59 +1613,353 @@ while ((skb = skb_dequeue(&entry->skb)) != NULL) { skb_device_lock(skb); - sti(); + restore_flags(flags); skb_queue_tail(&entry1->skb, skb); skb_device_unlock(skb); cli(); } - sti(); + restore_flags(flags); -#if RT_CACHE_DEBUG >= 1 - printk("arp_run_bh: entry %08x was born dead\n", entry->ip); -#endif arp_free_entry(entry); - if (entry1->flags & ATF_COM) - { - arp_update_hhs(entry1); - arp_send_q(entry1); - } + if (entry1->flags & ATF_COM) + { + arp_update_hhs(entry1); + arp_send_q(entry1); + } + } + cli(); + } + cli(); + } + arp_unlock(); + restore_flags(flags); +} + + +/* + * Interface to link layer: send routine and receive handler. + */ + +/* + * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast + * message. + */ + +void arp_send(int type, int ptype, u32 dest_ip, + struct device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw) +{ + struct sk_buff *skb; + struct arphdr *arp; + unsigned char *arp_ptr; + + /* + * No arp on this interface. + */ + + if (dev->flags&IFF_NOARP) + return; + + /* + * Allocate a buffer + */ + + skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + + dev->hard_header_len, GFP_ATOMIC); + if (skb == NULL) + { + printk("ARP: no memory to send an arp packet\n"); + return; + } + skb_reserve(skb, dev->hard_header_len); + arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); + skb->arp = 1; + skb->dev = dev; + skb->free = 1; + skb->protocol = htons (ETH_P_IP); + + /* + * Fill the device header for the ARP frame + */ + + dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len); + + /* Fill out the arp protocol part. */ + arp->ar_hrd = htons(dev->type); +#ifdef CONFIG_AX25 +#ifdef CONFIG_NETROM + arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP); +#else + arp->ar_pro = (dev->type != ARPHRD_AX25) ? htons(ETH_P_IP) : htons(AX25_P_IP); +#endif +#else + arp->ar_pro = htons(ETH_P_IP); +#endif + arp->ar_hln = dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr=(unsigned char *)(arp+1); + + memcpy(arp_ptr, src_hw, dev->addr_len); + arp_ptr+=dev->addr_len; + memcpy(arp_ptr, &src_ip,4); + arp_ptr+=4; + if (target_hw != NULL) + memcpy(arp_ptr, target_hw, dev->addr_len); + else + memset(arp_ptr, 0, dev->addr_len); + arp_ptr+=dev->addr_len; + memcpy(arp_ptr, &dest_ip, 4); + + dev_queue_xmit(skb, dev, 0); +} + + +/* + * Receive an arp request by the device layer. + */ + +int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ +/* + * We shouldn't use this type conversion. Check later. + */ + + struct arphdr *arp = (struct arphdr *)skb->h.raw; + unsigned char *arp_ptr= (unsigned char *)(arp+1); + unsigned char *sha,*tha; + u32 sip,tip; + +/* + * The hardware length of the packet should match the hardware length + * of the device. Similarly, the hardware types should match. The + * device should be ARP-able. Also, if pln is not 4, then the lookup + * is not from an IP number. We can't currently handle this, so toss + * it. + */ + if (arp->ar_hln != dev->addr_len || + dev->type != ntohs(arp->ar_hrd) || + dev->flags & IFF_NOARP || + arp->ar_pln != 4) + { + kfree_skb(skb, FREE_READ); + return 0; + /* Should this be an error/printk? Seems like something */ + /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */ + } + +/* + * Another test. + * The logic here is that the protocol being looked up by arp should + * match the protocol the device speaks. If it doesn't, there is a + * problem, so toss the packet. + */ +/* Again, should this be an error/printk? -- MS */ + + switch (dev->type) + { +#ifdef CONFIG_AX25 + case ARPHRD_AX25: + if(arp->ar_pro != htons(AX25_P_IP)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + break; +#endif +#ifdef CONFIG_NETROM + case ARPHRD_NETROM: + if(arp->ar_pro != htons(AX25_P_IP)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + break; +#endif + case ARPHRD_ETHER: + case ARPHRD_ARCNET: + case ARPHRD_METRICOM: + if(arp->ar_pro != htons(ETH_P_IP)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + break; + + case ARPHRD_IEEE802: + if(arp->ar_pro != htons(ETH_P_IP)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + break; + + default: + printk("ARP: dev->type mangled!\n"); + kfree_skb(skb, FREE_READ); + return 0; + } + +/* + * Extract fields + */ + + sha=arp_ptr; + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4; + tha=arp_ptr; + arp_ptr += dev->addr_len; + memcpy(&tip, arp_ptr, 4); + +/* + * Check for bad requests for 127.x.x.x and requests for multicast + * addresses. If this is one such, delete it. + */ + if (LOOPBACK(tip) || MULTICAST(tip)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + +/* + * Process entry. The idea here is we want to send a reply if it is a + * request for us or if it is a request for someone else that we hold + * a proxy for. We want to add an entry to our cache if it is a reply + * to us or if it is a request for our address. + * (The assumption for this last is that if someone is requesting our + * address, they are probably intending to talk to us, so it saves time + * if we cache their address. Their address is also probably not in + * our cache, since ours is not in their cache.) + * + * Putting this another way, we only care about replies if they are to + * us, in which case we add them to the cache. For requests, we care + * about those for us and those for our proxies. We reply to both, + * and in the case of requests for us we add the requester to the arp + * cache. + */ + +/* + * try to switch to alias device whose addr is tip or closest to sip. + */ + +#ifdef CONFIG_NET_ALIAS + if (tip != dev->pa_addr && net_alias_has(skb->dev)) + { + /* + * net_alias_dev_rcv_sel32 returns main dev if it fails to found other. + */ + dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip); + + if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP) + { + kfree_skb(skb, FREE_READ); + return 0; + } + } +#endif + + if (arp->ar_op == htons(ARPOP_REQUEST)) + { + +/* + * Only reply for the real device address or when it's in our proxy tables + */ + if (tip != dev->pa_addr) + { + struct arp_table *proxy_entry; + +/* + * To get in here, it is a request for someone else. We need to + * check if that someone else is one of our proxies. If it isn't, + * we can toss it. + * + * Make "longest match" lookup, a la routing. + */ + + arp_fast_lock(); + + for (proxy_entry = arp_proxy_list; proxy_entry; + proxy_entry = proxy_entry->next) + { + if (proxy_entry->dev == dev && + !((proxy_entry->ip^tip)&proxy_entry->mask)) + break; + } + + if (proxy_entry && (proxy_entry->mask || ((dev->pa_addr^tip)&dev->pa_mask))) + { + char ha[MAX_ADDR_LEN]; + struct rtable * rt; + + /* Unlock arp tables to make life for + * ip_rt_route easy. Note, that we are obliged + * to make local copy of hardware address. + */ + + memcpy(ha, proxy_entry->ha, dev->addr_len); + arp_unlock(); + + rt = ip_rt_route(tip, 0); + if (rt && rt->rt_dev != dev) + arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha,sha); + ip_rt_put(rt); + } - cli(); + else + arp_unlock(); } - arp_bh_mask &= ~ARP_BH_BACKLOG; + else + arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); + +/* + * Handle gratuitous arp. + */ + arp_fast_lock(); + arp_update(sip, sha, dev, NULL, 1); arp_unlock(); + kfree_skb(skb, FREE_READ); + return 0; } - restore_flags(flags); + + arp_fast_lock(); + arp_update(sip, sha, dev, NULL, ip_chk_addr(tip) != IS_MYADDR); + arp_unlock(); + kfree_skb(skb, FREE_READ); + return 0; } + + /* - * Test if a hardware address is all zero + * User level interface (ioctl, /proc) */ -static inline int empty(unsigned char * addr, int len) -{ - while (len > 0) { - if (*addr) - return 0; - len--; - addr++; - } - return 1; -} - /* * Set (create) an ARP cache entry. */ static int arp_req_set(struct arpreq *r, struct device * dev) { - struct arp_table *entry; + struct arp_table *entry, **entryp; struct sockaddr_in *si; - struct rtable *rt; - struct device *dev1; unsigned char *ha; u32 ip; + u32 mask = DEF_ARP_NETMASK; + unsigned long flags; + + /* + * Extract netmask (if supplied). + */ + + if (r->arp_flags&ATF_NETMASK) + { + si = (struct sockaddr_in *) &r->arp_netmask; + mask = si->sin_addr.s_addr; + } /* * Extract destination. @@ -1885,112 +1968,89 @@ si = (struct sockaddr_in *) &r->arp_pa; ip = si->sin_addr.s_addr; - /* - * Is it reachable ? - */ - if (ip_chk_addr(ip) == IS_MYADDR) - dev1 = dev_get("lo"); - else { - rt = ip_rt_route(ip, 0); - if (!rt) - return -ENETUNREACH; - dev1 = rt->rt_dev; - ip_rt_put(rt); + if (r->arp_flags&ATF_PUBL) + { + if (!mask && ip) + return -EINVAL; + if (!dev) + dev = dev_getbytype(r->arp_ha.sa_family); } - - /* good guess about the device if it isn't a ATF_PUBL entry */ - if (!dev) { - if (dev1->flags&(IFF_LOOPBACK|IFF_NOARP)) - return -ENODEV; - dev = dev1; + else + { + if (ip_chk_addr(ip)) + return -EINVAL; + if (!dev) + { + struct rtable * rt; + rt = ip_rt_route(ip, 0); + if (!rt) + return -ENETUNREACH; + dev = rt->rt_dev; + ip_rt_put(rt); + } } + if (!dev || (dev->flags&(IFF_LOOPBACK|IFF_NOARP))) + return -ENODEV; - /* this needs to be checked only for dev=dev1 but it doesn't hurt */ if (r->arp_ha.sa_family != dev->type) return -EINVAL; - if (((r->arp_flags & ATF_PUBL) && dev == dev1) || - (!(r->arp_flags & ATF_PUBL) && dev != dev1)) - return -EINVAL; - + arp_fast_lock(); #if RT_CACHE_DEBUG >= 1 - if (arp_lock) + if (ARP_LOCKED()) printk("arp_req_set: bug\n"); #endif - arp_fast_lock(); - - /* - * Is there an existing entry for this address? - */ - /* - * Find the entry - */ - - entry = arp_lookup(ip, r->arp_flags & ~ATF_NETMASK, dev); - if (entry == NULL) - entry = arpd_lookup(ip, r->arp_flags & ~ATF_NETMASK, dev, __LINE__); + if (!(r->arp_flags & ATF_PUBL)) + entryp = &arp_tables[HASH(ip)]; + else + entryp = &arp_proxy_list; - if (entry) + while ((entry = *entryp) != NULL) { - arp_destroy(entry); - entry = NULL; + if (entry->ip == ip && entry->mask == mask && entry->dev == dev) + break; + if ((entry->mask & mask) != mask) + { + entry = NULL; + break; + } + entryp = &entry->next; } /* - * Do we need to create a new entry + * Do we need to create a new entry? */ if (entry == NULL) { - entry = arp_add_entry(); + entry = arp_alloc_entry(); if (entry == NULL) { arp_unlock(); return -ENOMEM; } entry->ip = ip; - entry->hh = NULL; - init_timer(&entry->timer); - entry->timer.function = arp_expire_request; - entry->timer.data = (unsigned long)entry; + entry->dev = dev; + entry->mask = mask; + entry->flags = r->arp_flags; - if (r->arp_flags & ATF_PUBL) - { - cli(); - entry->next = arp_proxy_list; - arp_proxy_list = entry; - sti(); - } - else - { - unsigned long hash = HASH(ip); - cli(); - entry->next = arp_tables[hash]; - arp_tables[hash] = entry; - sti(); - } - skb_queue_head_init(&entry->skb); + entry->next = (*entryp)->next; + *entryp = entry; } - /* - * We now have a pointer to an ARP entry. Update it! - */ + ha = r->arp_ha.sa_data; - if ((r->arp_flags & ATF_COM) && empty(ha, dev->addr_len)) + if (empty(ha, dev->addr_len)) ha = dev->dev_addr; + + save_flags(flags); + cli(); memcpy(entry->ha, ha, dev->addr_len); entry->last_updated = entry->last_used = jiffies; - arpd_update(entry, __LINE__); - entry->flags = r->arp_flags | ATF_COM; - if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK)) - { - si = (struct sockaddr_in *) &r->arp_netmask; - entry->mask = si->sin_addr.s_addr; - } - else - entry->mask = DEF_ARP_NETMASK; - entry->dev = dev; + entry->flags |= ATF_COM; + restore_flags(flags); + arpd_update(entry); arp_update_hhs(entry); arp_unlock(); return 0; @@ -2006,77 +2066,88 @@ { struct arp_table *entry; struct sockaddr_in *si; + u32 mask = DEF_ARP_NETMASK; + + if (r->arp_flags&ATF_NETMASK) + { + si = (struct sockaddr_in *) &r->arp_netmask; + mask = si->sin_addr.s_addr; + } si = (struct sockaddr_in *) &r->arp_pa; + arp_fast_lock(); #if RT_CACHE_DEBUG >= 1 - if (arp_lock) - printk("arp_req_set: bug\n"); + if (ARP_LOCKED()) + printk("arp_req_set: impossible\n"); #endif - arp_fast_lock(); - entry = arp_lookup(si->sin_addr.s_addr, r->arp_flags|ATF_NETMASK, dev); - if (entry == NULL) - entry = arpd_lookup(si->sin_addr.s_addr, - r->arp_flags|ATF_NETMASK, dev, __LINE__); + if (!(r->arp_flags & ATF_PUBL)) + entry = arp_tables[HASH(si->sin_addr.s_addr)]; + else + entry = arp_proxy_list; - if (entry == NULL) + for ( ; entry ;entry = entry->next) { - arp_unlock(); - return -ENXIO; + if (entry->ip == si->sin_addr.s_addr + && (!dev || entry->dev == dev) + && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask)) + { + memcpy(r->arp_ha.sa_data, entry->ha, entry->dev->addr_len); + r->arp_ha.sa_family = entry->dev->type; + r->arp_flags = entry->flags; + strncpy(r->arp_dev, entry->dev->name, sizeof(r->arp_dev)); + arp_unlock(); + return 0; + } } - /* - * We found it; copy into structure. - */ - - memcpy(r->arp_ha.sa_data, &entry->ha, entry->dev->addr_len); - r->arp_ha.sa_family = entry->dev->type; - r->arp_flags = entry->flags; - strncpy(r->arp_dev, entry->dev->name, 16); arp_unlock(); - return 0; + return -ENXIO; } static int arp_req_delete(struct arpreq *r, struct device * dev) { - struct arp_table *entry; - struct sockaddr_in *si; + struct sockaddr_in *si; + struct arp_table *entry, **entryp; + int retval = -ENXIO; + u32 mask = DEF_ARP_NETMASK; + + if (r->arp_flags&ATF_NETMASK) + { + si = (struct sockaddr_in *) &r->arp_netmask; + mask = si->sin_addr.s_addr; + } si = (struct sockaddr_in *) &r->arp_pa; + + arp_fast_lock(); #if RT_CACHE_DEBUG >= 1 - if (arp_lock) - printk("arp_req_delete: bug\n"); + if (ARP_LOCKED()) + printk("arp_req_delete: impossible\n"); #endif - arp_fast_lock(); if (!(r->arp_flags & ATF_PUBL)) - { - for (entry = arp_tables[HASH(si->sin_addr.s_addr)]; - entry != NULL; entry = entry->next) - if (entry->ip == si->sin_addr.s_addr - && (!dev || entry->dev == dev)) - { - arp_destroy(entry); - arp_unlock(); - return 0; - } - } + entryp = &arp_tables[HASH(si->sin_addr.s_addr)]; else + entryp = &arp_proxy_list; + + while ((entry = *entryp) != NULL) { - for (entry = arp_proxy_list; - entry != NULL; entry = entry->next) - if (entry->ip == si->sin_addr.s_addr - && (!dev || entry->dev == dev)) - { - arp_destroy(entry); - arp_unlock(); - return 0; - } + if (entry->ip == si->sin_addr.s_addr + && (!dev || entry->dev == dev) + && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask)) + { + *entryp = entry->next; + arp_free_entry(entry); + retval = 0; + continue; + } + entryp = &entry->next; } arp_unlock(); - return -ENXIO; + return retval; } /* @@ -2119,8 +2190,11 @@ if (r.arp_pa.sa_family != AF_INET) return -EPFNOSUPPORT; - if (((struct sockaddr_in *)&r.arp_pa)->sin_addr.s_addr == 0) - return -EINVAL; + + if (!(r.arp_flags & ATF_PUBL)) + r.arp_flags &= ~ATF_NETMASK; + if (!(r.arp_flags & ATF_NETMASK)) + ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=DEF_ARP_NETMASK; if (r.arp_dev[0]) { @@ -2132,14 +2206,6 @@ else if (r.arp_ha.sa_family != dev->type) return -EINVAL; } - else - { - if ((r.arp_flags & ATF_PUBL) && - ((cmd == SIOCSARP) || (cmd == OLD_SIOCSARP))) { - if ((dev = dev_getbytype(r.arp_ha.sa_family)) == NULL) - return -ENODEV; - } - } switch(cmd) { @@ -2199,6 +2265,99 @@ return 0; } +/* + * Write the contents of the ARP cache to a PROCfs file. + */ + +#define HBUFFERLEN 30 + +int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + int len=0; + off_t pos=0; + int size; + struct arp_table *entry; + char hbuffer[HBUFFERLEN]; + int i,j,k; + const char hexbuf[] = "0123456789ABCDEF"; + + size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n"); + + pos+=size; + len+=size; + + arp_fast_lock(); + + for(i=0; inext) + { +/* + * Convert hardware address to XX:XX:XX:XX ... form. + */ +#ifdef CONFIG_AX25 +#ifdef CONFIG_NETROM + if (entry->dev->type == ARPHRD_AX25 || entry->dev->type == ARPHRD_NETROM) + strcpy(hbuffer,ax2asc((ax25_address *)entry->ha)); + else { +#else + if(entry->dev->type==ARPHRD_AX25) + strcpy(hbuffer,ax2asc((ax25_address *)entry->ha)); + else { +#endif +#endif + + for(k=0,j=0;kdev->addr_len;j++) + { + hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ]; + hbuffer[k++]=hexbuf[ entry->ha[j]&15 ]; + hbuffer[k++]=':'; + } + hbuffer[--k]=0; + +#ifdef CONFIG_AX25 + } +#endif + size = sprintf(buffer+len, + "%-17s0x%-10x0x%-10x%s", + in_ntoa(entry->ip), + (unsigned int)entry->dev->type, + entry->flags, + hbuffer); +#if RT_CACHE_DEBUG < 2 + size += sprintf(buffer+len+size, + " %-17s %s\n", + entry->mask==DEF_ARP_NETMASK ? + "*" : in_ntoa(entry->mask), entry->dev->name); +#else + size += sprintf(buffer+len+size, + " %-17s %s\t%d\t%1d\n", + entry->mask==DEF_ARP_NETMASK ? + "*" : in_ntoa(entry->mask), entry->dev->name, + entry->hh ? entry->hh->hh_refcnt : -1, + entry->hh ? entry->hh->hh_uptodate : 0); +#endif + + len += size; + pos += size; + + if (pos <= offset) + len=0; + if (pos >= offset+length) + goto done; + } + } +done: + arp_unlock(); + + *start = buffer+len-(pos-offset); /* Start of wanted data */ + len = pos-offset; /* Start slop */ + if (len>length) + len = length; /* Ending slop */ + return len; +} + + /* * Called once on startup. @@ -2237,5 +2396,8 @@ arp_get_info }); #endif -} +#ifdef CONFIG_ARPD + netlink_attach(NETLINK_ARPD, arpd_callback); +#endif +} diff -u --recursive --new-file v1.3.98/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v1.3.98/linux/net/ipv4/devinet.c Tue Nov 14 16:03:57 1995 +++ linux/net/ipv4/devinet.c Tue May 7 15:22:30 1996 @@ -14,6 +14,8 @@ * Additional Authors: * Alan Cox, */ + +#include /* For CONFIG_IP_CLASSLESS */ #include #include @@ -76,7 +78,9 @@ int ip_chk_addr(unsigned long addr) { struct device *dev; +#ifndef CONFIG_IP_CLASSLESS unsigned long mask; +#endif /* * Accept both `all ones' and `all zeros' as BROADCAST. @@ -90,6 +94,7 @@ addr == htonl(0x7FFFFFFFL)) return IS_BROADCAST; +#ifndef CONFIG_IP_CLASSLESS mask = ip_get_mask(addr); /* @@ -98,6 +103,10 @@ if ((addr & mask) == htonl(0x7F000000L)) return IS_MYADDR; +#else + if ((addr & htonl(0x7F000000L)) == htonl(0x7F000000L)) + return IS_MYADDR; +#endif /* * OK, now check the interface addresses. We could @@ -139,6 +148,7 @@ return IS_BROADCAST; } +#ifndef CONFIG_IP_CLASSLESS /* * Nope. Check for Network broadcast. */ @@ -150,6 +160,7 @@ if ((addr & ~mask) == ~mask) return IS_BROADCAST; } +#endif } if(IN_MULTICAST(ntohl(addr))) return IS_MULTICAST; @@ -181,36 +192,34 @@ /* * Find an interface that can handle addresses for a certain address. - * - * This needs optimising, since it's relatively trivial to collapse - * the two loops into one. */ - -struct device * ip_dev_check(unsigned long addr) + +struct device * ip_dev_bynet(unsigned long addr, unsigned long mask) { struct device *dev; + struct device *best_dev = NULL; + __u32 best_mask = mask; for (dev = dev_base; dev; dev = dev->next) { if (!(dev->flags & IFF_UP)) continue; - if (!(dev->flags & IFF_POINTOPOINT)) - continue; - if (addr != dev->pa_dstaddr) - continue; - return dev; - } - for (dev = dev_base; dev; dev = dev->next) - { - if (!(dev->flags & IFF_UP)) - continue; if (dev->flags & IFF_POINTOPOINT) + { + if (addr == dev->pa_dstaddr) + return dev; continue; + } if (dev->pa_mask & (addr ^ dev->pa_addr)) continue; - return dev; + if (mask == dev->pa_mask) + return dev; + if (best_dev && (best_mask & dev->pa_mask) != best_mask) + continue; + best_dev = dev; + best_mask = dev->pa_mask; } - return NULL; + return best_dev; } /* diff -u --recursive --new-file v1.3.98/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v1.3.98/linux/net/ipv4/igmp.c Fri Apr 12 15:52:12 1996 +++ linux/net/ipv4/igmp.c Mon May 6 12:26:17 1996 @@ -215,7 +215,7 @@ } /* - * Inlined as its only called once. + * Inlined as it's only called once. */ static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time) diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v1.3.98/linux/net/ipv4/ip_forward.c Fri Apr 12 15:52:12 1996 +++ linux/net/ipv4/ip_forward.c Mon May 6 12:26:17 1996 @@ -216,7 +216,7 @@ #ifndef CONFIG_IP_NO_ICMP_REDIRECT if (dev == dev2 && !((iph->saddr^dev->pa_addr)&dev->pa_mask) && - /* The daddr!=raddr test isn't obvious - what its doing + /* The daddr!=raddr test isn't obvious - what it's doing is avoiding sending a frame the receiver will not believe anyway.. */ iph->daddr != raddr/*ANK*/ && !opt->srr) @@ -247,7 +247,7 @@ #ifdef CONFIG_IP_MASQUERADE /* * If this fragment needs masquerading, make it so... - * (Dont masquerade de-masqueraded fragments) + * (Don't masquerade de-masqueraded fragments) */ if (!(is_frag&IPFWD_MASQUERADED) && fw_res==FW_MASQUERADE) ip_fw_masquerade(&skb, dev2); diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v1.3.98/linux/net/ipv4/ip_fragment.c Sat Apr 27 15:20:10 1996 +++ linux/net/ipv4/ip_fragment.c Mon May 6 12:26:17 1996 @@ -754,7 +754,7 @@ ip_options_fragment(skb); /* - * Added AC : If we are fragmenting a fragment thats not the + * Added AC : If we are fragmenting a fragment that's not the * last fragment then keep MF on each bit */ if (left > 0 || (is_frag & 1)) diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v1.3.98/linux/net/ipv4/ip_masq.c Tue Apr 23 13:57:14 1996 +++ linux/net/ipv4/ip_masq.c Mon May 6 12:26:17 1996 @@ -539,7 +539,7 @@ /* * Check if it's an masqueraded port, look it up, - * and send it on it's way... + * and send it on its way... * * Better not have many hosts using the designated portrange * as 'normal' ports, or you'll be spending many time in @@ -639,7 +639,6 @@ */ if (iph->protocol==IPPROTO_UDP) { - unsigned long timeout; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); ip_masq_set_expire(ms, 0); ip_masq_set_expire(ms, ip_masq_expire->udp_timeout); diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v1.3.98/linux/net/ipv4/ip_output.c Wed Apr 24 17:00:43 1996 +++ linux/net/ipv4/ip_output.c Tue May 7 12:06:53 1996 @@ -224,7 +224,7 @@ * release route, so that... */ if (rt) - ATOMIC_INCR(&rt->rt_refcnt); + atomic_inc(&rt->rt_refcnt); } else rt = ip_rt_route(daddr, skb->localroute); @@ -1059,7 +1059,8 @@ nrt->rtmsg_flags=flags; nrt->rtmsg_metric=metric; strcpy(nrt->rtmsg_device,name); - netlink_post(NETLINK_ROUTE, skb); + if (netlink_post(NETLINK_ROUTE, skb)) + kfree_skb(skb, FREE_WRITE); } #endif @@ -1085,6 +1086,7 @@ ip_mc_allhost(dev); #endif ip_netlink_msg(RTMSG_NEWDEVICE, 0,0,0,0,0,dev->name); + ip_rt_update(NETDEV_UP, dev); } return NOTIFY_DONE; } diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v1.3.98/linux/net/ipv4/ip_sockglue.c Sun May 5 08:52:06 1996 +++ linux/net/ipv4/ip_sockglue.c Tue May 7 12:06:53 1996 @@ -181,7 +181,7 @@ case IP_TOS: /* This sets both TOS and Precedence */ if (val<0 || val>63) /* Reject setting of unused bits */ return -EINVAL; - if ((val&3) > 4 && !suser()) /* Only root can set Prec>4 */ + if ((val&7) > 4 && !suser()) /* Only root can set Prec>4 */ return -EPERM; sk->ip_tos=val; switch (val & 0x38) { @@ -297,7 +297,7 @@ { dev=rt->rt_dev; route_src = rt->rt_src; - ATOMIC_DECR(&rt->rt_use); + atomic_dec(&rt->rt_use); ip_rt_put(rt); } } @@ -350,7 +350,7 @@ if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL) { dev=rt->rt_dev; - ATOMIC_DECR(&rt->rt_use); + atomic_dec(&rt->rt_use); route_src = rt->rt_src; ip_rt_put(rt); } diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c --- v1.3.98/linux/net/ipv4/ipip.c Tue Apr 23 13:57:14 1996 +++ linux/net/ipv4/ipip.c Tue May 7 12:06:53 1996 @@ -74,39 +74,15 @@ skb->h.iph=(struct iphdr *)skb->data; skb->ip_hdr=(struct iphdr *)skb->data; memset(skb->proto_priv, 0, sizeof(struct options)); - if (skb->ip_hdr->ihl > 5) - { - if (ip_options_compile(NULL, skb)) - return 0; - } - -#ifdef CONFIG_FIREWALL - /* - * Check the firewall [well spotted Olaf] - */ - - if((err=call_in_firewall(PF_INET, skb->dev, skb->ip_hdr))protocol = htons(ETH_P_IP); + skb->ip_summed = 0; + netif_rx(skb); MOD_DEC_USE_COUNT; return(0); } diff -u --recursive --new-file v1.3.98/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v1.3.98/linux/net/ipv4/ipmr.c Fri Apr 12 15:52:12 1996 +++ linux/net/ipv4/ipmr.c Mon May 6 12:26:17 1996 @@ -397,7 +397,7 @@ return 0; } /* - * Unsolicited update - thats ok add anyway. + * Unsolicited update - that's ok, add anyway. */ @@ -420,7 +420,7 @@ /* * Socket options and virtual interface manipulation. The whole * virtual interface system is a complete heap, but unfortunately - * thats how BSD mrouted happens to think. Maybe one day with a proper + * that's how BSD mrouted happens to think. Maybe one day with a proper * MOSPF/PIM router set up we can clean this up. */ @@ -487,7 +487,7 @@ { if(dev->flags&IFF_MULTICAST) { - /* Most ethernet cards dont know + /* Most ethernet cards don't know how to do this yet.. */ dev->flags|=IFF_ALLMULTI; dev_mc_upload(dev); diff -u --recursive --new-file v1.3.98/linux/net/ipv4/packet.c linux/net/ipv4/packet.c --- v1.3.98/linux/net/ipv4/packet.c Fri Apr 12 15:52:12 1996 +++ linux/net/ipv4/packet.c Mon May 6 12:26:17 1996 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Doesn't belong in IP but its currently too hooked into ip + * Doesn't belong in IP but it's currently too hooked into ip * to separate. * * Version: @(#)packet.c 1.0.6 05/25/93 @@ -176,7 +176,7 @@ /* * If the write buffer is full, then tough. At this level the user gets to - * deal with the problem - do your own algorithmic backoffs. Thats far + * deal with the problem - do your own algorithmic backoffs. That's far * more flexible. */ diff -u --recursive --new-file v1.3.98/linux/net/ipv4/proc.c linux/net/ipv4/proc.c --- v1.3.98/linux/net/ipv4/proc.c Mon Mar 25 08:58:25 1996 +++ linux/net/ipv4/proc.c Tue May 7 12:06:53 1996 @@ -68,11 +68,15 @@ unsigned short destp, srcp; int len=0; off_t pos=0; - off_t begin=0; + off_t begin; + char tmpbuf[129]; s_array = pro->sock_array; - len += sprintf(buffer, "sl local_address rem_address st tx_queue " - "rx_queue tr tm->when uid inode\n"); + if (offset < 128) + len += sprintf(buffer, "%-127s\n", + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout inode"); + pos = 128; /* * This was very pretty but didn't work when a socket is destroyed * at the wrong moment (eg a syn recv socket getting a reset), or @@ -85,6 +89,12 @@ sp = s_array[i]; while(sp != NULL) { + pos += 128; + if (pos < offset) + { + sp = sp->next; + continue; + } dest = sp->daddr; src = sp->saddr; destp = sp->dummy_th.dest; @@ -109,8 +119,8 @@ timer_active=timer_active2; timer_expires=sp->timer.expires; } - len += sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X" - " %02X %08X:%08X %02X:%08lX %08X %d %d %ld\n", + sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", i, src, srcp, dest, destp, sp->state, format==0?sp->write_seq-sp->rcv_ack_seq:sp->wmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->rmem_alloc, @@ -121,32 +131,28 @@ SOCK_INODE(sp->socket)->i_ino : 0); if (timer_active1) add_timer(&sp->retransmit_timer); if (timer_active2) add_timer(&sp->timer); + len += sprintf(buffer+len, "%-127s\n", tmpbuf); /* * All sockets with (port mod SOCK_ARRAY_SIZE) = i * are kept in sock_array[i], so we must follow the * 'next' link to get them all. */ - sp = sp->next; - pos=begin+len; - if(posoffset+length) + if(len >= length) break; + sp = sp->next; } sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up before this will clear before we jump back and cli(), so it's not as bad as it looks */ - if(pos>offset+length) + if(len>= length) break; } - *start=buffer+(offset-begin); - len-=(offset-begin); + begin = len - (pos - offset); + *start = buffer + begin; + len -= begin; if(len>length) - len=length; + len = length; return len; } diff -u --recursive --new-file v1.3.98/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v1.3.98/linux/net/ipv4/raw.c Fri Apr 19 10:08:03 1996 +++ linux/net/ipv4/raw.c Mon May 6 12:26:17 1996 @@ -198,7 +198,7 @@ if(!iph->saddr) iph->saddr=saddr; iph->check=0; - iph->tot_len=htons(fraglen); /* This is right as you cant frag + iph->tot_len=htons(fraglen); /* This is right as you can't frag RAW packets */ /* * Deliberate breach of modularity to keep diff -u --recursive --new-file v1.3.98/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v1.3.98/linux/net/ipv4/route.c Fri Apr 12 15:52:12 1996 +++ linux/net/ipv4/route.c Tue May 7 12:06:54 1996 @@ -321,42 +321,6 @@ } /* - * Used by 'rt_add()' when we can't get the netmask any other way.. - * - * If the lower byte or two are zero, we guess the mask based on the - * number of zero 8-bit net numbers, otherwise we use the "default" - * masks judging by the destination address and our device netmask. - */ - -static __u32 unsigned long default_mask(__u32 dst) -{ - dst = ntohl(dst); - if (IN_CLASSA(dst)) - return htonl(IN_CLASSA_NET); - if (IN_CLASSB(dst)) - return htonl(IN_CLASSB_NET); - return htonl(IN_CLASSC_NET); -} - - -/* - * If no mask is specified then generate a default entry. - */ - -static __u32 guess_mask(__u32 dst, struct device * dev) -{ - __u32 mask; - - if (!dst) - return 0; - mask = default_mask(dst); - if ((dst ^ dev->pa_addr) & mask) - return mask; - return dev->pa_mask; -} - - -/* * Check if a mask is acceptable. */ @@ -527,50 +491,6 @@ struct fib_info * fi; int logmask; - if (flags & RTF_HOST) - mask = 0xffffffff; - /* - * If mask is not specified, try to guess it. - */ - else if (!mask) - { - if (!((dst ^ dev->pa_addr) & dev->pa_mask)) - { - mask = dev->pa_mask; - flags &= ~RTF_GATEWAY; - if (flags & RTF_DYNAMIC) - { - printk("Dynamic route to my own net rejected\n"); - return; - } - } - else - mask = guess_mask(dst, dev); - dst &= mask; - } - - /* - * A gateway must be reachable and not a local address - */ - - if (gw == dev->pa_addr) - flags &= ~RTF_GATEWAY; - - if (flags & RTF_GATEWAY) - { - /* - * Don't try to add a gateway we can't reach.. - * Tunnel devices are exempt from this rule. - */ - - if ((dev != get_gw_dev(gw)) && dev->type!=ARPHRD_TUNNEL) - return; - - flags |= RTF_GATEWAY; - } - else - gw = 0; - /* * Allocate an entry and fill it in. */ @@ -632,7 +552,7 @@ if (fz->fz_nent >= RTZ_HASHING_LIMIT && !fz->fz_hash_table && logmask<32) { struct fib_node ** ht; -#if RT_CACHE_DEBUG +#if RT_CACHE_DEBUG >= 2 printk("fib_add_1: hashing for zone %d started\n", logmask); #endif ht = kmalloc(RTZ_HASH_DIVISOR*sizeof(struct rtable*), GFP_KERNEL); @@ -747,7 +667,12 @@ struct fib_node *f; while ((f = *fp) != NULL) { - if (f->fib_info->fib_dev != dev) { +/* + * "Magic" device route is allowed to point to loopback, + * discard it too. + */ + if (f->fib_info->fib_dev != dev && + (dev != &loopback_dev || f->fib_dst != dev->pa_addr)) { fp = &f->fib_next; continue; } @@ -797,7 +722,7 @@ * * We preserve the old format but pad the buffers out. This means that * we can spin over the other entries as we read them. Remember the - * gated BGP4 code could need to read 60,000+ routes on occasion (thats + * gated BGP4 code could need to read 60,000+ routes on occasion (that's * about 7Mb of data). To do that ok we will need to also cache the * last route we got to (reads will generally be following on from * one another without gaps). @@ -961,12 +886,9 @@ { struct hh_cache * hh = rt->rt_hh; rt->rt_hh = NULL; - if (hh && !--hh->hh_refcnt) - { - restore_flags(flags); - kfree_s(hh, sizeof(struct hh_cache)); - } restore_flags(flags); + if (hh && atomic_dec_and_test(&hh->hh_refcnt)) + kfree_s(hh, sizeof(struct hh_cache)); kfree_s(rt, sizeof(struct rt_table)); return; } @@ -1000,12 +922,9 @@ #endif *rtp = rt->rt_next; rt->rt_hh = NULL; - if (hh && !--hh->hh_refcnt) - { - sti(); - kfree_s(hh, sizeof(struct hh_cache)); - } sti(); + if (hh && atomic_dec_and_test(&hh->hh_refcnt)) + kfree_s(hh, sizeof(struct hh_cache)); kfree_s(rt, sizeof(struct rt_table)); #if RT_CACHE_DEBUG >= 2 printk("rt_kick_free_queue: %08x is free\n", daddr); @@ -1017,7 +936,8 @@ } } -void ip_rt_run_bh() { +void ip_rt_run_bh() +{ unsigned long flags; save_flags(flags); cli(); @@ -1409,7 +1329,7 @@ else { if (rtg->rt_hh) - ATOMIC_INCR(&rtg->rt_hh->hh_refcnt); + atomic_inc(&rtg->rt_hh->hh_refcnt); rth->rt_hh = rtg->rt_hh; ip_rt_put(rtg); } @@ -1570,7 +1490,7 @@ { rt_free(rth); #if RT_CACHE_DEBUG >= 1 - printk("rt_cache: route to %08x was born dead\n", daddr); + printk(KERN_DEBUG "rt_cache: route to %08x was born dead\n", daddr); #endif } @@ -1581,7 +1501,7 @@ void ip_rt_put(struct rtable * rt) { if (rt) - ATOMIC_DECR(&rt->rt_refcnt); + atomic_dec(&rt->rt_refcnt); } struct rtable * ip_rt_route(__u32 daddr, int local) @@ -1595,8 +1515,8 @@ if (rth->rt_dst == daddr) { rth->rt_lastuse = jiffies; - ATOMIC_INCR(&rth->rt_use); - ATOMIC_INCR(&rth->rt_refcnt); + atomic_inc(&rth->rt_use); + atomic_inc(&rth->rt_refcnt); ip_rt_unlock(); return rth; } @@ -1671,42 +1591,49 @@ } } - /* - * Ignore faulty masks - */ - - if (bad_mask(mask, daddr)) - mask=0; - - /* - * Set the mask to nothing for host routes. - */ - - if (flags & RTF_HOST) + if (flags & RTF_HOST) mask = 0xffffffff; else if (mask && r->rt_genmask.sa_family != AF_INET) return -EAFNOSUPPORT; - /* - * You can only gateway IP via IP.. - */ - if (flags & RTF_GATEWAY) { if (r->rt_gateway.sa_family != AF_INET) return -EAFNOSUPPORT; + + /* + * Don't try to add a gateway we can't reach.. + * Tunnel devices are exempt from this rule. + */ + if (!dev) dev = get_gw_dev(gw); + else if (dev != get_gw_dev(gw) && dev->type != ARPHRD_TUNNEL) + return -EINVAL; + if (!dev) + return -ENETUNREACH; } - else if (!dev) - dev = ip_dev_check(daddr); + else + { + gw = 0; + if (!dev) + dev = ip_dev_bynet(daddr, mask); + if (!dev) + return -ENETUNREACH; + if (!mask) + { + if (((daddr ^ dev->pa_addr) & dev->pa_mask) == 0) + mask = dev->pa_mask; + } + } - /* - * Unknown device. - */ - - if (dev == NULL) - return -ENETUNREACH; +#ifndef CONFIG_IP_CLASSLESS + if (!mask) + mask = ip_get_mask(daddr); +#endif + + if (bad_mask(mask, daddr)) + return -EINVAL; /* * Add the route @@ -1783,3 +1710,10 @@ return; } +void ip_rt_update(int event, struct device *dev) +{ + if (event == NETDEV_UP) + rt_add(RTF_HOST|RTF_UP, dev->pa_addr, ~0, 0, dev, 0, 0, 0, 0); + else if (event == NETDEV_DOWN) + rt_del(dev->pa_addr, ~0, dev, 0, RTF_HOST|RTF_UP, 0); +} diff -u --recursive --new-file v1.3.98/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v1.3.98/linux/net/ipv4/tcp.c Sat Apr 27 15:20:10 1996 +++ linux/net/ipv4/tcp.c Mon May 6 12:26:17 1996 @@ -172,7 +172,7 @@ * ack if stat is TCP_CLOSED. * Alan Cox : Look up device on a retransmit - routes may * change. Doesn't yet cope with MSS shrink right - * but its a start! + * but it's a start! * Marc Tamsky : Closing in closing fixes. * Mike Shaver : RFC1122 verifications. * Alan Cox : rcv_saddr errors. @@ -1962,7 +1962,7 @@ /* * SKIP devices set their MTU to 65535. This is so they can take packets * unfragmented to security process then fragment. They could lie to the - * TCP layer about a suitable MTU, but its easier to let skip sort it out + * TCP layer about a suitable MTU, but it's easier to let skip sort it out * simply because the final package we want unfragmented is going to be * * [IPHDR][IPSP][Security data][Modified TCP data][Security data] diff -u --recursive --new-file v1.3.98/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v1.3.98/linux/net/ipv4/tcp_input.c Fri Apr 19 10:08:03 1996 +++ linux/net/ipv4/tcp_input.c Mon May 6 12:26:17 1996 @@ -27,7 +27,7 @@ #include /* - * Policy code extracted so its now separate + * Policy code extracted so it's now separate */ /* @@ -344,7 +344,7 @@ * flurry of syns from eating up all our memory. * * BSD does some funnies here and allows 3/2 times the - * set backlog as a fudge factor. Thats just too gross. + * set backlog as a fudge factor. That's just too gross. */ if (sk->ack_backlog >= sk->max_ack_backlog) @@ -502,7 +502,7 @@ /* * SKIP devices set their MTU to 65535. This is so they can take packets * unfragmented to security process then fragment. They could lie to the - * TCP layer about a suitable MTU, but its easier to let skip sort it out + * TCP layer about a suitable MTU, but it's easier to let skip sort it out * simply because the final package we want unfragmented is going to be * * [IPHDR][IPSP][Security data][Modified TCP data][Security data] @@ -607,7 +607,7 @@ */ if(sk->zapped) - return(1); /* Dead, cant ack any more so why bother */ + return(1); /* Dead, can't ack any more so why bother */ /* * We have dropped back to keepalive timeouts. Thus we have @@ -1736,7 +1736,7 @@ /* * Retransmitted SYN for our socket. This is uninteresting. If sk->state==TCP_LISTEN - * then its a new connection + * then it's a new connection */ if (sk->state == TCP_SYN_RECV && th->syn && skb->seq+1 == sk->acked_seq) @@ -1759,7 +1759,7 @@ /* We got an ack, but it's not a good ack */ if(!tcp_ack(sk,th,skb->ack_seq,len)) { - /* Reset the ack - its an ack from a + /* Reset the ack - it's an ack from a different connection [ th->rst is checked in tcp_send_reset()] */ tcp_statistics.TcpAttemptFails++; tcp_send_reset(daddr, saddr, th, diff -u --recursive --new-file v1.3.98/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v1.3.98/linux/net/ipv4/tcp_output.c Sun Apr 21 12:39:03 1996 +++ linux/net/ipv4/tcp_output.c Mon May 6 16:25:53 1996 @@ -26,6 +26,68 @@ #include /* + * RFC 1122 says: + * + * "the suggested [SWS] avoidance algorithm for the receiver is to keep + * RECV.NEXT + RCV.WIN fixed until: + * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" + * + * Experiments against BSD and Solaris machines show that following + * these rules results in the BSD and Solaris machines making very + * bad guesses about how much data they can have in flight. + * + * Instead we follow the BSD lead and offer a window that gives + * the size of the current free space, truncated to a multiple + * of 1024 bytes. If the window is smaller than + * min(sk->mss, MAX_WINDOW/2) + * then we advertise the window as having size 0, unless this + * would shrink the window we offered last time. + * This results in as much as double the throughput as the original + * implementation. + * + * We do BSD style SWS avoidance -- note that RFC1122 only says we + * must do silly window avoidance, it does not require that we use + * the suggested algorithm. + * + * The "rcvbuf" and "rmem_alloc" values are shifted by 1, because + * they also contain buffer handling overhead etc, so the window + * we actually use is essentially based on only half those values. + */ +int tcp_new_window(struct sock * sk) +{ + unsigned long window; + unsigned long minwin, maxwin; + + /* Get minimum and maximum window values.. */ + minwin = sk->mss; + if (!minwin) + minwin = sk->mtu; + maxwin = sk->window_clamp; + if (!maxwin) + maxwin = MAX_WINDOW; + if (minwin > maxwin/2) + minwin = maxwin/2; + + /* Get current rcvbuf size.. */ + window = sk->rcvbuf/2; + if (window < minwin) { + sk->rcvbuf = minwin*2; + window = minwin; + } + + /* Check rcvbuf against used and minimum window */ + window -= sk->rmem_alloc/2; + if ((long)(window - minwin) < 0) /* SWS avoidance */ + window = 0; + + if (window > 1023) + window &= ~1023; + if (window > maxwin) + window = maxwin; + return window; +} + +/* * Get rid of any delayed acks, we sent one already.. */ static __inline__ void clear_delayed_acks(struct sock * sk) diff -u --recursive --new-file v1.3.98/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v1.3.98/linux/net/ipx/af_ipx.c Fri Apr 12 15:52:13 1996 +++ linux/net/ipx/af_ipx.c Tue May 7 12:06:54 1996 @@ -44,6 +44,14 @@ * Revision 0.34: Module support. * Revision 0.35: Checksum support. , hooked in by * + * Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT + * pair. Also, now usage count is managed this way + * -Count one if the auto_interface mode is on + * -Count one per configured interface + * + * Jacques Gelinas (jacques@solucorp.qc.ca) + * + * * Portions Copyright (c) 1995 Caldera, Inc. * Neither Greg Page nor Caldera, Inc. admit liability nor provide * warranty for any of this software. This material is provided @@ -105,7 +113,14 @@ static int ipxcfg_set_auto_create(char val) { - ipxcfg_auto_create_interfaces = val; + if (ipxcfg_auto_create_interfaces != val){ + if (val){ + MOD_INC_USE_COUNT; + }else{ + MOD_DEC_USE_COUNT; + } + ipxcfg_auto_create_interfaces = val; + } return 0; } @@ -336,6 +351,7 @@ /* sockets still dangling * - must be closed from user space */ + MOD_DEC_USE_COUNT; return; } @@ -803,6 +819,7 @@ if (ipxcfg_auto_select_primary && (ipx_primary_net == NULL)) ipx_primary_net = intrfc; + MOD_INC_USE_COUNT; return; } @@ -1015,7 +1032,7 @@ } static int -ipxitf_ioctl(unsigned int cmd, void *arg) +ipxitf_ioctl_real(unsigned int cmd, void *arg) { int err; switch(cmd) @@ -1080,6 +1097,15 @@ } } +static int +ipxitf_ioctl(unsigned int cmd, void *arg) +{ + int ret; + MOD_INC_USE_COUNT; + ret = ipxitf_ioctl_real (cmd,arg); + MOD_DEC_USE_COUNT; + return ret; +} /*******************************************************************************************************************\ * * * Routing tables for the IPX socket layer * @@ -1312,7 +1338,7 @@ * Apply checksum. Not allowed on 802.3 links. */ - if(sk->no_check || intrfc->if_dlink_type!=IPX_FRAME_8023) + 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)); diff -u --recursive --new-file v1.3.98/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v1.3.98/linux/net/netrom/af_netrom.c Fri Apr 19 10:08:03 1996 +++ linux/net/netrom/af_netrom.c Mon May 6 12:26:17 1996 @@ -235,7 +235,7 @@ * Once it is removed from the queue no interrupt or bottom half will * touch it and we are (fairly 8-) ) safe. */ -void nr_destroy_socket(struct sock *sk) /* Not static as its used by the timer */ +void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */ { struct sk_buff *skb; unsigned long flags; @@ -954,7 +954,7 @@ unsigned short frametype, window, timeout; - skb->sk = NULL; /* Initially we don't know who its for */ + skb->sk = NULL; /* Initially we don't know who it's for */ /* * skb->data points to the netrom frame start @@ -980,7 +980,7 @@ #endif /* - * Find an existing socket connection, based on circuit ID, if its + * Find an existing socket connection, based on circuit ID, if it's * a Connect Request base it on their circuit ID. */ if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) || diff -u --recursive --new-file v1.3.98/linux/net/socket.c linux/net/socket.c --- v1.3.98/linux/net/socket.c Sat Apr 27 15:20:10 1996 +++ linux/net/socket.c Mon May 6 12:26:18 1996 @@ -395,7 +395,7 @@ /* * With an ioctl arg may well be a user mode pointer, but we don't know what to do - * with it - thats up to the protocol still. + * with it - that's up to the protocol still. */ int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, diff -u --recursive --new-file v1.3.98/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v1.3.98/linux/net/unix/af_unix.c Fri Apr 12 15:52:13 1996 +++ linux/net/unix/af_unix.c Tue May 7 12:06:54 1996 @@ -27,6 +27,7 @@ * Marty Leisner : Fixes to fd passing * Nick Nevin : recvmsg bugfix. * Alan Cox : Started proper garbage collector + * Heiko EiBfeldt : Missing verify_area check * * Known differences from reference BSD that was tested: * @@ -352,7 +353,7 @@ if(skpair!=NULL) skpair->protinfo.af_unix.locks--; /* It may now die */ sk->protinfo.af_unix.other=NULL; /* No pair */ - unix_destroy_socket(sk); /* Try and flush out this socket. Throw our buffers at least */ + unix_destroy_socket(sk); /* Try to flush out this socket. Throw out buffers at least */ /* * FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In @@ -1222,6 +1223,8 @@ if((skb=skb_peek(&sk->receive_queue))!=NULL) amount=skb->len; err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long)); + if(err) + return err; put_fs_long(amount,(unsigned long *)arg); return 0; } diff -u --recursive --new-file v1.3.98/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v1.3.98/linux/scripts/Menuconfig Sun May 5 08:52:07 1996 +++ linux/scripts/Menuconfig Mon May 6 12:26:18 1996 @@ -1110,7 +1110,7 @@ # # Check kernel version of previous menuconfig build. # If it's different then we should tell the sound driver -# to rebuild it's Config.in file. +# to rebuild its Config.in file. # rebuildsound=TRUE if [ -e .menuconfig ] diff -u --recursive --new-file v1.3.98/linux/scripts/tkcond.c linux/scripts/tkcond.c --- v1.3.98/linux/scripts/tkcond.c Fri Apr 12 15:52:13 1996 +++ linux/scripts/tkcond.c Mon May 6 12:26:18 1996 @@ -449,7 +449,7 @@ { /* * Now search the condition list for a known configuration variable - * that has conditions of it's own. + * that has conditions of its own. */ if(cnd->op != op_kvariable) continue; if(cnd->variable.cfg->cond == NULL) continue; diff -u --recursive --new-file v1.3.98/linux/scripts/tkparse.c linux/scripts/tkparse.c --- v1.3.98/linux/scripts/tkparse.c Wed Apr 10 17:02:29 1996 +++ linux/scripts/tkparse.c Mon May 6 12:26:18 1996 @@ -662,7 +662,7 @@ * Input file is now parsed. Next we need to go through and attach * the correct conditions to each of the actual menu items and kill * the if/else/endif tokens from the list. We also flag the menu items - * that have other things that depend upon it's setting. + * that have other things that depend upon its setting. */ fix_conditionals(config);