]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.61 1.3.61
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:32 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:32 +0000 (15:10 -0500)
91 files changed:
CREDITS
Documentation/Configure.help
Documentation/smp.tex [new file with mode: 0644]
Makefile
Rules.make
arch/alpha/config.in
arch/alpha/defconfig
arch/alpha/kernel/ksyms.c
arch/i386/Makefile
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/ksyms.c
arch/mips/config.in
arch/mips/defconfig
arch/ppc/config.in
arch/sparc/config.in
arch/sparc/defconfig
drivers/block/Config.in
drivers/block/Makefile
drivers/block/README.ide
drivers/block/ali14xx.c [new file with mode: 0644]
drivers/block/cmd640.c
drivers/block/dtc2278.c [new file with mode: 0644]
drivers/block/floppy.c
drivers/block/genhd.c
drivers/block/ht6560b.c [new file with mode: 0644]
drivers/block/ide.c
drivers/block/ide.h
drivers/block/qd6580.c [new file with mode: 0644]
drivers/block/rz1000.c [new file with mode: 0644]
drivers/block/triton.c
drivers/block/umc8672.c
drivers/char/vesa_blank.c
drivers/net/Config.in
drivers/net/loopback.c
drivers/net/slip.c
drivers/net/slip.h
drivers/scsi/NCR5380.c
drivers/scsi/t128.c
drivers/sound/configure.c
fs/Makefile
fs/binfmt_aout.c [new file with mode: 0644]
fs/binfmt_elf.c
fs/buffer.c
fs/exec.c
fs/fat/buffer.c
fs/fat/cache.c
fs/fat/dir.c
fs/fat/fatfs_syms.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/fat/mmap.c
fs/fat/tables.c
fs/filesystems.c
fs/locks.c
fs/msdos/msdosfs_syms.c
fs/msdos/namei.c
fs/proc/array.c
fs/umsdos/inode.c
fs/vfat/namei.c
include/asm-i386/smp_lock.h
include/linux/binfmts.h
include/linux/fs.h
include/linux/hdreg.h
include/linux/if_slip.h
include/linux/interrupt.h
include/linux/ip_fw.h
include/linux/msdos_fs.h
include/linux/proc_fs.h
include/linux/skbuff.h
include/linux/smp.h
include/linux/sockios.h
kernel/ksyms.c
kernel/sched.c
net/appletalk/ddp.c
net/core/dev.c
net/ipv4/igmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_fw.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/tcp.c
net/ipv4/udp.c
net/ipx/af_ipx.c
net/unix/af_unix.c
scripts/Configure
scripts/lxdialog/Makefile
scripts/lxdialog/dialog.h
scripts/tkgen.c

diff --git a/CREDITS b/CREDITS
index 14bb7c275c3cab808408b508ac36f81d9c1d91df..3634becfe9d9f5514eab9578514741a2f8addfd4 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -562,6 +562,11 @@ S: Mr. v. Boemellaan 39
 S: NL-5237 KA 's-Hertogenbosch
 S: The Netherlands
 
+N: Savio Lam
+E: lam836@cs.cuhk.hk
+D: Author of the dialog utility, foundation
+D: for Menuconfig's lxdialog.
+
 N: Volker Lendecke
 E: lendecke@namu01.gwdg.de
 D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
@@ -857,6 +862,14 @@ D: Instigator, FHS standard
 D: Keeper of the Jargon File and curator of the Retrocomputing Museum
 D: Author, Emacs VC and GUD modes
 
+N: William E. Roadcap
+E: roadcapw@cfw.com
+W: http://www.cfw.com/~roadcapw
+D: Author of menu based configuration tool, Menuconfig.
+S: 1407 Broad Street
+S: Waynesboro, Va  22980
+S: USA
+
 N: Florian La Roche
 E: rzsfl@rz.uni-sb.de
 E: flla@stud.uni-sb.de
@@ -1083,6 +1096,18 @@ S: 4130 Upson Hall
 S: Ithaca NY 14850
 S: USA
 
+N: Greg Wettstein
+E: greg@wind.rmcc.com
+D: Filesystem valid flag for MINIX filesystem.
+D: Minor kernel debugging.
+D: Monitoring of development kernels for long-term stability.
+D: Early implementations of Linux in a commercial environment.
+S: Dr. Greg Wettstein, Ph.D.
+S: Oncology Research Division Computing Facility
+S: Roger Maris Cancer Center
+S: 820 4th St. N.
+S: Fargo, ND  58122
+
 N: Marco van Wieringen
 E: mvw@mercury.mcs.nl.mugnet.org
 D: Author of acct and quota
index d47889d9c9b606c3d45a6c34c2edadb2c8480884..0660c08d0b3401b6e1ce4734dc3886dc843d67de 100644 (file)
@@ -342,6 +342,21 @@ CONFIG_KERNEL_ELF
   kernel in ELF by saying Y here and editing the variables CC
   and LD in the toplevel Makefile.
 
+Kernel support for A.OUT binaries
+CONFIG_BINFMT_AOUT
+  A.OUT (Assembler.OUTput) format is a format for libraries and
+  executables used in the earliest versions of UNIX. Linux used this
+  format until it was replaced with the ELF format.
+  As more and more programs are converted to ELF, the use for A.OUT
+  will gradually diminish. If you disable this option it will reduce
+  your kernel by one page. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea when
+  you wish to ensure that absolutely none of your programs will use
+  this older executable format. If you don't know what to answer at
+  this point then answer Y. You may answer M for module support and
+  later load the module when you find a program which needs a.out
+  format.
+
 Processor type
 CONFIG_M386
   This is the processor type of your CPU. It is used for optimizing
@@ -1117,6 +1132,11 @@ CONFIG_SLIP_COMPRESSED
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, explains how to configure
   CSLIP. This won't enlarge your kernel.
 
+Keepalive and linefill
+CONFIG_SLIP_SMART
+  Adds additional capabilities to the SLIP driver to support the RELCOM
+  line fill and keepalive monitoring. Ideal on poor quality analogue lines.
+
 PPP (point-to-point) support
 CONFIG_PPP
   PPP (Point to Point Protocol) is a newer and better SLIP. It serves
diff --git a/Documentation/smp.tex b/Documentation/smp.tex
new file mode 100644 (file)
index 0000000..d7d7c96
--- /dev/null
@@ -0,0 +1,345 @@
+From: michael@Physik.Uni-Dortmund.DE (Michael Dirkmann)
+
+thanks for your information. Attached is the tex-code of your
+SMP-documentation :
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+\documentclass[]{article}
+\parindent0.0cm
+\parskip0.2cm
+
+\begin{document}
+
+\begin{center}
+\LARGE \bf
+An Implementation Of Multiprocessor Linux
+\normalsize
+\end{center}
+
+{ \it
+This document describes the implementation of a simple SMP 
+Linux kernel extension and how to use this to develop SMP Linux kernels for 
+architectures other than the Intel MP v1.1 architecture for Pentium and 486 
+processors.}
+
+\hfill Alan Cox, 1995
+
+
+The author wishes to thank Caldera Inc whose donation of an ASUS dual 
+pentium board made this project possible, and Thomas Radke, whose initial 
+work on multiprocessor Linux formed the backbone of this project.
+
+\section{Background: The Intel MP specification.}
+Most IBM PC style multiprocessor motherboards combine Intel 486 or Pentium 
+processors and glue chipsets with a hardware/software specification. The 
+specification places much of the onus for hard work on the chipset and 
+hardware rather than the operating system.
+
+The Intel pentium processors have a wide variety of inbuilt facilities for 
+supporting multiprocessing, including hardware cache coherency, built in 
+interprocessor interrupt handling and a set of atomic test and set, 
+exchange and similar operations. The cache coherency in paticular makes the 
+operating systems job far easier.
+
+The specification defines a detailed configuration structure in ROM that 
+the boot up processor can read to find the full configuration of the 
+processors and busses. It also defines a procedure for starting up the 
+other processors.
+
+
+\section{Mutual Exclusion Within A Single Processor Linux Kernel}
+For any kernel to function in a sane manner it has to provide internal 
+locking and protection of its own tables to prevent two processes updating 
+them at once and for example allocating the same memory block. There are 
+two strategies for this within current Unix and Unixlike kernels. 
+Traditional unix systems from the earliest of days use a scheme of 'Coarse 
+Grained Locking' where the entire kernel is protected as a small number of 
+locks only. Some modern systems use fine grained locking. Because fine 
+grained locking has more overhead it is normally used only on 
+multiprocessor kernels and real time kernels. In a real time kernel the 
+fine grained locking reduces the amount of time locks are held and reduces 
+the critical (to real time programming at least) latency times.
+
+Within the Linux kernel certain guarantees are made. No process running in 
+kernel mode will be pre-empted by another kernel mode process unless it 
+voluntarily sleeps.  This ensures that blocks of kernel code are 
+effectively atomic with respect to other processes and greatly simplifies 
+many operation. Secondly interrupts may pre-empt a kernel running process, 
+but will always return to that process. A process in kernel mode may 
+disable interrupts on the processor and guarantee such an interruption will 
+not occur. The final guarantee is that an interrupt will not bne pre-empted 
+by a kernel task. That is interrupts will run to completion or be 
+pre-empted by other interrupts only.
+
+The SMP kernel chooses to continue these basic guarantees in order to make 
+initial implementation and deployment easier.  A single lock is maintained 
+across all processors. This lock is required to access the kernel space. 
+Any processor may hold it and once it is held may also re-enter the kernel 
+for interrupts and other services whenever it likes until the lock is 
+relinquished. This lock ensures that a kernel mode process will not be 
+pre-empted and ensures that blocking interrupts in kernel mode behaves 
+correctly. This is guaranteed because only the processor holding the lock 
+can be in kernel mode, only kernel mode processes can disable interrupts 
+and only the processor holding the lock may handle an interrupt.
+
+Such a choice is however poor for performance. In the longer term it is 
+neccessary to move to finer grained parallelisn in order to get the best 
+system performance. This can be done heirarchically by gradually refining 
+the locks to cover smaller areas. With the current kernel highly CPU bound 
+process sets perform well but I/O bound task sets can easily degenerate to 
+near single processor performance levels. This refinement will be needed to 
+get the best from Linux/SMP.
+
+\subsection{Changes To The Portable Kernel Components}
+The kernel changes are split into generic SMP support changes and 
+architecture specific changes neccessary to accomodate each different 
+processor type Linux is ported to.
+
+
+\subsubsection{Initialisation}
+The first problem with a multiprocessor kernel is starting the other 
+processors up. Linux/SMP defines that a single processor enters the normal 
+kernel entry point start\_kernel(). Other processors are assumed not to be 
+started or to have been captured elsewhere. The first processor begins the 
+normal Linux initialisation sequences and sets up paging, interrupts and 
+trap handlers. After it has obtained the processor information about the 
+boot CPU, the architecture specific function 
+
+
+{\tt \bf{void smp\_store\_cpu\_info(int processor\_id) }}
+
+is called to store any information about the processor into a per processor 
+array. This includes things like the bogomips speed ratings.
+
+Having completed the kernel initialisation the architecture specific 
+function
+
+{\tt \bf void smp\_boot\_cpus(void) }
+
+is called and is expected to start up each other processor and cause it to 
+enter start\_kernel() with its paging registers and other control 
+information correctly loaded. Each other processor skips the setup except 
+for calling the trap and irq initialisation functions that are needed on 
+some processors to set each CPU up correctly.  These functions will 
+probably need to be modified in existing kernels to cope with this.
+
+
+Each additional CPU the calls the architecture specific function
+
+{\tt \bf void smp\_callin(void)}
+
+which does any final setup and then spins the processor while the boot 
+up processor forks off enough idle threads for each processor. This is 
+neccessary because the scheduler assumes there is always something to run. 
+Having generated these threads and forked init the architecture specific 
+
+{\tt \bf void smp\_commence(void)}
+
+function is invoked. This does any final setup and indicates to the system 
+that multiprocessor mode is now active. All the processors spinning in the 
+smp\_callin() function are now released to run the idle processes, which 
+they will run when they have no real work to process.
+
+
+\subsubsection{Scheduling}
+The kernel scheduler implements a simple but very and effective task 
+scheduler. The basic structure of this scheduler is unchanged in the 
+multiprocessor kernel. A processor field is added to each task, and this 
+maintains the number of the processor executing a given task, or a magic 
+constant (NO\_PROC\_ID)  indicating the job is not allocated to a processor. 
+        
+Each processor executes the scheduler itself and will select the next task 
+to run from all runnable processes not allocated to a different processor. 
+The algorithm used by the selection is otherwise unchanged. This is 
+actually inadequate for the final system because there are advantages to 
+keeping a process on the same CPU, especially on processor boards with per 
+processor second level caches.
+
+Throughout the kernel the variable 'current' is used as a global for the 
+current process. In Linux/SMP this becomes a macro which expands to 
+current\_set[smp\_processor\_id()]. This enables almost the entire kernel to 
+be unaware of the array of running processors, but still allows the SMP 
+aware kernel modules to see all of the running processes.
+
+The fork system call is modified to generate multiple processes with a 
+process id of zero until the SMP kernel starts up properly. This is 
+neccessary because process number 1 must be init, and it is desirable that 
+all the system threads are process 0. 
+
+The final area within the scheduling of processes that does cause problems 
+is the fact the uniprocessor kernel hard codes tests for the idle threads 
+as task[0] and the init process as task[1]. Because there are multiple idle 
+threads it is neccessary to replace these with tests that the process id is 
+0 and a search for process ID 1, respectively.
+
+\subsubsection{Memory Management}
+The memory management core of the existing Linux system functions 
+adequately within the multiprocessor framework providing the locking is 
+used. Certain processor specific areas do need changing, in paticular 
+invalidate() must invalidate the TLB's of all processors before it returns.
+
+
+\subsubsection{Miscellaneous Functions}
+The portable SMP code rests on a small set of functions and variables 
+that are provided by the processor specification functionality. These are
+
+{\tt \bf int smp\_processor\_id(void) }
+
+which returns the identity of the process the call is executed upon. This 
+call is assumed to be valid at all times. This may mean additional tests 
+are needed during initialisation.
+
+
+{\tt \bf int smp\_num\_cpus;}
+
+This is the number of processors in the system. \
+
+{\tt \bf void smp\_message\_pass(int target, int msg, unsigned long data,
+               int wait)}
+
+This function passes messages between processors. At the moment it is not 
+sufficiently defined to sensibly document and needs cleaning up and further 
+work. Refer to the processor specific code documentation for more details.
+
+
+\subsection{Architecture Specific Code For the Intel MP Port}
+The architecture specific code for the intel port splits fairly cleanly 
+into four sections. Firstly the initialisation code used to boot the 
+system, secondly the message handling and support code, thirdly the 
+interrupt and kernel syscall entry function handling and finally the 
+extensions to standard kernel facilities to cope with multiple processors.
+
+\subsubsection{Initialisation} 
+The intel MP architecture captures all the processors except for a single 
+processor known as the 'boot processor' in the BIOS at boot time. Thus a 
+single processor enters the kernel bootup code. The first processor 
+executes the bootstrap code, loads and uncompresses the kernel. Having 
+unpacked the kernel it sets up the paging and control registers then enters 
+the C kernel startup.
+
+The assembler startup code for the kernel is modified so that it can be 
+used by the other processors to do the processor identification and various 
+other low level configurations but does not execute those parts of the 
+startup code that would damage the running system (such as clearing the BSS 
+segment). 
+
+In the initialisation done by the first processor the arch/i386/mm/init 
+code is modified to scan the low page, top page and BIOS for intel MP 
+signature blocks. This is neccessary because the MP signature blocks must 
+be read and processed before the kernel is allowed to allocate and destroy 
+the page at the top of low memory. Having established the number of 
+processors it reserves a set of pages to provide a stack come boot up area 
+for each processor in the system. These must be allocated at startup to 
+ensure they fall below the 1Mb boundary.
+
+Further processors are started up in smp\_boot\_cpus() by programming the 
+APIC controller registers and sending an inter-processor interrupt (IPI) to 
+the processor. This message causes the target processor to begin executing 
+code at the start of any page of memory within the lowest 1Mb, in 16bit 
+real mode. The kernel uses the single page it allocated for each processor 
+to use as stack. Before booting a given CPU the relocatable code from 
+trampoline.S and trampoline32.S is copied to the bottom of its stack page 
+and used as the target for the startup. 
+
+The trampoline code calculates the desired stack base from the code 
+segment (since the code segment on startup is the bottom of the stack), 
+ enters 32bit mode and jumps to the kernel entry assembler. This as 
+described above is modified to only execute the parts necessary for each 
+processor, and then to enter start\_kernel(). On entering the kernel the 
+processor initialises its trap and interrupt handlers before entering 
+smp\_callin(), where it reports its status and sets a flag that causes the 
+boot processor to continue and look for further processors. The processor 
+then spins until smp\_commence() is invoked.
+
+Having started each processor up the smp\_commence( ) function flips a 
+flag. Each processor spinning in smp\_callin() then loads the task register 
+with the task state segment (TSS) of its idle thread as is needed for task 
+switching.
+
+\subsubsection{Message Handling and Support Code}
+The architecture specific code implements the smp\_processor\_id() function 
+by querying the APIC logical identity register. Because the APIC isnt 
+mapped into the kernel address space at boot, the initial value returned is 
+rigged by setting the APIC base pointer to point at a suitable constant. 
+Once the system starts doing the SMP setup (in smp\_boot\_cpus()), the APIC 
+is mapped with a vremap() call and the apic pointer is adjusted 
+appropriately. From then on the real APIC logical identity register is 
+read.
+
+Message passing is accomplished using a pair of IPI's on interrupt 13 
+(unused by the 80486 FPU's in SMP mode) and interrupt 16. Two are used in 
+order to seperate messages that cannot be processed until the receiver 
+obtains the kernel spinlock from messages that can be processed 
+immediately. In effect IRQ 13 is a fast IRQ handler that does not obtain 
+the locks, and cannot cause a reschedule, while IRQ 16 is a slow IRQ that 
+must acquire the kernel spinlocks and can cause a reschedule. This 
+interrupt is used for passing on slave timer messages from the processor 
+that receives the timer interrupt to the rest of the processors, so that 
+they can reschedule running tasks.
+
+
+\subsubsection{Entry And Exit Code}
+A single spinlock protects the entire kernel. The interrupt handlers, the 
+syscall entry code and the exception handlers all acquire the lock before 
+entering the kernel proper. When the processor is trying to acquire the 
+spinlock it spins continually on the lock with interrupts disabled. This 
+causes a specific deadlock problem. The lock owner may need to send an 
+invalidate request to the rest of the processors and wait for these to 
+complete before continuing. A processor spinning on the lock would not be 
+able to do thus. Thus the loop of the spinlock tests and handles invalidate 
+requests. If the invalidate bit for the spinning CPU is set the processor 
+invalidates its TLB and atomically clears the bit. When the spinlock is 
+obtained that processor will take an IPI and in the IPI test the bit and 
+skip the invalidate as the bit is clear.
+
+One complexity of the spinlock is that a process running in kernel mode 
+can sleep voluntarily and be pre-empted. A switch from such a process to a 
+process executing in user space may reduce the lock count. To track this 
+the kernel uses a syscall\_count and a per process lock\_depth parameter to 
+track the kernel lock state. The switch\_to() function is modified in SMP 
+mode to adjust the lock appropriately.
+
+The final problem is the idle thread. In the single processor kernel the 
+idle thread executes 'hlt' instructions. This saves power and reduces the 
+running temperature of the processors when they are idle. However it means 
+the process spends all its time in kernel mode and would thus hold the 
+kernel spinlock. The SMP idle thread continually reschedules a new task and 
+returns to user mode. This is far from ideal and will be modified to use 
+'hlt' instructions and release the spinlock soon. Using 'hlt' is even more 
+beneficial on a multiprocessor system as it almost completely takes an idle 
+processor off the bus.
+
+Interrupts are distributed by an i82489 APIC. This chip is set up to work 
+as an emulation of the traditional PC interrupt controllers when the 
+machine boots (so that an Intel MP machine boots one CPU and PC 
+compatible). The kernel has all the relevant locks but does not yet 
+reprogram the 82489 to deliver interrupts to arbitary processors as it 
+should. This requires further modification of the standard Linux interrupt 
+handling code, and is paticularly messy as the interrupt handler behaviour 
+has to change as soon as the 82489 is switched into SMP mode.
+
+
+\subsubsection{Extensions To Standard Facilities}
+The kernel maintains a set of per processor control information such as 
+the speed of the processor for delay loops. These functions on the SMP 
+kernel look the values up in a per processor array that is set up from the 
+data generated at boot up by the smp\_store\_cpu\_info() function. This 
+includes other facts such as whether there is an FPU on the processor. The 
+current kernel does not handle floating point correctly, this requires some 
+changes to the techniques the single CPU kernel uses to minimise floating 
+point processor reloads.
+
+The highly useful atomic bit operations are prefixed with the 'lock' 
+prefix in the SMP kernel to maintain their atomic properties when used 
+outside of (and by) the spinlock and message code. Amongst other things 
+this is needed for the invalidate handler, as all  CPU's will invalidate at 
+the same time without any locks.
+
+Interrupt 13 floating point error reporting is removed. This facility is 
+not usable on a multiprocessor board, nor relevant to the Intel MP 
+architecture which does not cover the 80386/80387 processor pair. \
+
+The /proc filesystem support is changed so that the /proc/cpuinfo file 
+contains a column for each processor present. This information is extracted 
+from the data save by smp\_store\_cpu\_info().
+
+\end{document}
index 430a402397d64225c7251802cf546d933edbd784..4ecd8861aacd4f89b41795c472e9db87a28a2fe5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 60
+SUBLEVEL = 61
 
 ARCH = i386
 
index fa2a4daa84aaa199729b053a29ba9e2918c5ddc4..3ff4e48e3ddf556828f85c343fd0591d49893926 100644 (file)
@@ -34,7 +34,8 @@ unexport MOD_LIST_NAME
 #
 # Get things started.
 #
-first_rule: sub_dirs $(O_TARGET) $(L_TARGET)
+first_rule: sub_dirs
+       $(MAKE) all_targets
 
 #
 # Common rules
@@ -49,6 +50,11 @@ first_rule: sub_dirs $(O_TARGET) $(L_TARGET)
 %.o: %.s
        $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
 
+#
+#
+#
+all_targets: $(O_TARGET) $(L_TARGET)
+
 #
 # Rule to compile a set of .o files into one .o file
 #
index 2852caa8a146d386baedc8e41623b085b5eb65eb..4dadd91c2e056ed2b3b52809888001ef43591bc5 100644 (file)
@@ -57,6 +57,7 @@ if [ "$CONFIG_PCI" = "y" ]; then
 fi
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
+tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 endmenu
 
index 94c62bafcdfc2d8e5f37c603ada6c340d80a9621..2b0a0a1e02d2cd03f608f3a4d8a1ee3862f28926 100644 (file)
@@ -15,10 +15,10 @@ CONFIG_NATIVE=y
 # CONFIG_ALPHA_AVANTI is not set
 # CONFIG_ALPHA_JENSEN is not set
 # CONFIG_ALPHA_NONAME is not set
-CONFIG_ALPHA_CABRIOLET=y
+# CONFIG_ALPHA_CABRIOLET is not set
 # CONFIG_ALPHA_EB66 is not set
 # CONFIG_ALPHA_EB66P is not set
-# CONFIG_ALPHA_EB64P is not set
+CONFIG_ALPHA_EB64P=y
 # CONFIG_ALPHA_SRM is not set
 CONFIG_PCI=y
 CONFIG_ALPHA_APECS=y
@@ -28,10 +28,11 @@ CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_ELF is not set
 
 #
-# block devices
+# Block devices
 #
 CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_DEV_RAM is not set
@@ -42,7 +43,9 @@ CONFIG_ST506=y
 #
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_IDEATAPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_BLK_DEV_XD is not set
 
@@ -65,6 +68,10 @@ CONFIG_INET=y
 # CONFIG_TCP_NAGLE_OFF is not set
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
@@ -92,6 +99,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # SCSI low-level drivers
 #
+# CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
@@ -112,6 +120,7 @@ CONFIG_SCSI_NCR53C7xx=y
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_AM53C974 is not set
 
 #
 # Network device support
@@ -149,17 +158,19 @@ CONFIG_DE4X5=y
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_XIA_FS is not set
+CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_NFS_FS is not set
+CONFIG_NFS_FS=y
 # CONFIG_SMB_FS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 
 #
-# character devices
+# Character devices
 #
 # CONFIG_CYCLADES is not set
 # CONFIG_STALDRV is not set
index c8269abee5979da7237030fb7a1cd6a3966a56b8..9924b3eb2e1b6f68d9c9df3b968be5075e095e10 100644 (file)
@@ -5,7 +5,7 @@
  * modules.
  */
 
-#include <linux/config.h>
+#include <linux/string.h>
 #include <linux/module.h>
 # include <asm/io.h>
 # include <asm/hwrpb.h>
index 76670655fdc4eb39606624271c177b4d2846caa8..12f97651b940e2484b8d2e65b983c1f1633c8863 100644 (file)
 #
 #
 
+AS86    =$(CROSS_COMPILE)as86 -0 -a
+AS386   =$(CROSS_COMPILE)as86 -3
+LD86    =$(CROSS_COMPILE)ld86 -0
+
 ifdef CONFIG_KERNEL_ELF
 
 LD=$(CROSS_COMPILE)ld -m elf_i386
 CPP=$(CC) -E -D__ELF__
 OBJDUMP =$(CROSS_COMPILE)objdump
 ENCAPS=$(CROSS_COMPILE)encaps
-AS86    =$(CROSS_COMPILE)as86 -0 -a
-AS386   =$(CROSS_COMPILE)as86 -3
-LD86    =$(CROSS_COMPILE)ld86 -0
 OBJDUMP_FLAGS=-k -q 
 ZLDFLAGS=-e startup_32 
 LDFLAGS=-e stext
@@ -51,15 +52,19 @@ endif
 CFLAGS := $(CFLAGS) -pipe
 
 ifdef CONFIG_M386
-CFLAGS := $(CFLAGS) -m386
+CFLAGS := $(CFLAGS) -m386 -DCPU=386
 endif
 
 ifdef CONFIG_M486
-CFLAGS := $(CFLAGS) -m486
+CFLAGS := $(CFLAGS) -m486 -DCPU=486
 endif
 
 ifdef CONFIG_M586
-CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2
+CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
+endif
+
+ifdef CONFIG_M686
+CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686
 endif
 
 ifdef SMP
index 200c373d8ce84d6983e78d11b58652b0aadddbc8..144019f7688122b9e9e3e75be31958acd3c8b80e 100644 (file)
@@ -24,6 +24,7 @@ if [ "$CONFIG_PCI" = "y" ]; then
   bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 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
@@ -31,7 +32,8 @@ fi
 choice 'Processor type' \
        "386            CONFIG_M386     \
         486            CONFIG_M486     \
-        Pentium        CONFIG_M586" Pentium
+        Pentium        CONFIG_M586     \
+        PPro           CONFIG_M686" Pentium
 endmenu
 
 source drivers/block/Config.in
index 816a4fc4125cdf8bda7e5406d941314f223671d2..33d26066598142530dde406714c10ed3969c7f65 100644 (file)
@@ -18,11 +18,13 @@ CONFIG_NET=y
 CONFIG_PCI=y
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_SYSVIPC=y
+CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
 CONFIG_M586=y
+# CONFIG_M686 is not set
 
 #
 # Block devices
@@ -38,8 +40,10 @@ CONFIG_ST506=y
 CONFIG_BLK_DEV_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_RZ1000=y
 CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_DEV_XD is not set
 
 #
index 0e24808feff38b9d4f9112403252ce4dc055b956..127d165290458150c91783ce1ab8b7bc1e6702ed 100644 (file)
@@ -7,6 +7,7 @@ static struct symbol_table arch_symbol_table = {
        /* platform dependent support */
 #ifdef __SMP__
        X(apic_reg),            /* Needed internally for the I386 inlines */
+       X(cpu_data),
 #endif
 #include <linux/symtab_end.h>
 };
index ac77d884e4f43d00949bb93f8e8330b09f678122..08208a01e85e16ec0fe91e5069a4cc9c6f604a3a 100644 (file)
@@ -36,6 +36,7 @@ if [ "$CONFIG_CPU_R3000" = "y" -o \
 fi
 
 define_bool CONFIG_BINFMT_ELF y
+define_bool CONFIG_BINFMT_AOUT y
 bool 'Compile the kernel into the ELF object format' CONFIG_ELF_KERNEL
 if [ "$CONFIG_ELF_KERNEL" = "y" ]; then
   bool 'Is your ELF compiler an extra compiler' CONFIG_EXTRA_ELF_COMPILER
index aba2789cc865b73c937e980237a5f5c3a9cfad88..923745b875b8bc273dc99484117101bcdcf7286d 100644 (file)
@@ -21,6 +21,7 @@ CONFIG_CPU_R4X00=y
 # CONFIG_CPU_R10000 is not set
 CONFIG_TLB_SHUTDOWN=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_ELF_KERNEL is not set
 CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_NET is not set
index 53bf958248bf28fe64aac51c7592703166d4470a..7889294ed2c684d1b9f591dca1727d8ca01a0e43 100644 (file)
@@ -39,6 +39,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
 if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
 bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF y
 fi
+tristate 'Kernel support for A.OUT binaries' CONFIG_BINFMT_AOUT y
 #bool 'Use -mpentium flag for Pentium-specific optimizations' CONFIG_M586 n
 #if [ "$CONFIG_M586" = "n" ]; then
 #bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
index 9b4e9cdf8e8dc35c090e6954f187906d19ce4af0..a8c65c78d8207834fad35c1fa745820fdaebc864 100644 (file)
@@ -17,6 +17,7 @@ define_bool CONFIG_SUN_CONSOLE y
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for A.OUT binaries' CONFIG_BINFMT_AOUT
 endmenu
 
 source drivers/block/Config.in
index e995ced423eb55c0e0ac338f6713e916a5dfab11..12220c708db486b1714ee1dfc6e45e59841f73f1 100644 (file)
@@ -13,6 +13,7 @@ CONFIG_SUN_CONSOLE=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BINFMT_ELF is not set
+CONFIG_BINFMT_AOUT=y
 
 #
 # block devices
index 57fbc9180c1714c64195a9be688d67701ca26897..9aa221bddd1dcac29ea840dfad02a3a8edcb61f9 100644 (file)
@@ -18,9 +18,19 @@ if [ "$CONFIG_ST506" = "y" ]; then
   if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
     bool '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD
     bool '   Include (ALPHA) IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE
-    bool '   Special CMD640 chipset support' CONFIG_BLK_DEV_CMD640
+    bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
+    bool '   CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
     if [ "$CONFIG_PCI" = "y" ]; then
-      bool '   PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON
+      bool '   TRITON chipset DMA support' CONFIG_BLK_DEV_TRITON
+    fi
+    bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
+    if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
+      comment 'Note: most of these also require special kernel boot parameters'
+      bool '     DTC2278 chipset support' CONFIG_BLK_DEV_DTC2278
+      bool '     HT6560B chipset support' CONFIG_BLK_DEV_HT6560B
+      bool '     QD6580  chipset support' CONFIG_BLK_DEV_QD6580
+      bool '     UMC8672 chipset support' CONFIG_BLK_DEV_UMC8672
+      bool '     ALI14XX chipset support' CONFIG_BLK_DEV_ALI14XX
     fi
   fi
 fi
index 7da812f5504efc4b5e7d280f7872e300cb2f4ad6..ccd48e9f833343b06f0b94a94d8c88be8a849ce4 100644 (file)
@@ -44,14 +44,38 @@ ifeq ($(CONFIG_BLK_DEV_IDE),y)
 L_OBJS += ide.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_TRITON),y)
-L_OBJS += triton.o
+ifeq ($(CONFIG_BLK_DEV_RZ1000),y)
+L_OBJS += rz1000.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_CMD640),y)
 L_OBJS += cmd640.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_TRITON),y)
+L_OBJS += triton.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_DTC2278),y)
+L_OBJS += dtc2278.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_HT6560B),y)
+L_OBJS += ht6560b.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_QD6580),y)
+L_OBJS += qd6580.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_UMC8672),y)
+L_OBJS += umc8672.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_ALI14XX),y)
+L_OBJS += ali14xx.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_IDECD),y)
 L_OBJS += ide-cd.o
 endif
index b040bc3760467454fae0400de98ae60199581984..ac52506e56cc41c8946b234ffccc41238ce50906 100644 (file)
@@ -13,7 +13,7 @@ See description later on below for handling BIG IDE drives with >1024 cyls.
 Major features of ide.c & ide-cd.c:
 
 NEW!   - support for IDE ATAPI *tape* drives, courtesy of Gadi Oxman
-               (run MAKEDEV.ide to create the tape device entries in /dev/)
+               (re-run MAKEDEV.ide to create the tape device entries in /dev/)
 NEW!   - support for up to *four* IDE interfaces on one or more IRQs
 NEW!   - support for any mix of up to *eight* disk and/or cdrom drives
        - support for reading IDE ATAPI cdrom drives (NEC,MITSUMI,VERTOS,SONY)
@@ -31,28 +31,27 @@ NEW!                  (both are now probed for)
        - can co-exist with hd.c controlling the first interface
        - run-time selectable 32bit interface support (using hdparm-2.3)
 NEW!   - support for reliable operation of buggy RZ1000 interfaces
-               - PCI support is automatic
+               - PCI support is automatic when rz1000 support is configured
 NEW!   - support for reliable operation of buggy CMD-640 interfaces
-               - PCI support is automatic
+               - PCI support is automatic when cmd640 support is configured
                - for VLB, use kernel command line option:   ide0=cmd640_vlb
                - this support also enables the secondary i/f on most cards
                - experimental interface timing parameter support
 NEW!   - experimental support for UMC 8672 interfaces
 NEW!   - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f
-               - use kernel command line option:   ide1=ht6560
-NEW!   - experimental "fast" speed support for QD6580 interfaces
-               - use kernel command line option:   ide0=qd6580
-NEW!   - experimental support for DTC-2278D interfaces
-               - use kernel command line option:   ide1=dtc2278
+               - use kernel command line option:   ide0=ht6560
+NEW!   - experimental support for various IDE chipsets
+               - use appropriate kernel command line option from list below
 NEW!   - support for drives with a stuck WRERR_STAT bit
 NEW!   - support for removeable devices, including door lock/unlock
 NEW!   - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay"
        - works with Linux fdisk, LILO, loadlin, bootln, etc..
-NEW!   - mostly transparent support for EZ-Drive
+NEW!   - mostly transparent support for EZ-Drive disk translation software
 NEW!           - to use LILO with EZ, install LILO on the linux partition
                  rather than on the master boot record, and then mark the
                  linux partition as "bootable" or "active" using fdisk.
                  (courtesy of Juha Laiho <jlaiho@ichaos.nullnet.fi>).
+NEW!   - auto-detect of disk translations by examining partition table
 NEW!   - ide-cd.c now compiles separate from ide.c
 NEW!   - Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces
                - for details, see comments at top of triton.c
@@ -222,36 +221,48 @@ snyder@fnald0.fnal.gov
 
 Summary of ide driver parameters for kernel "command line":
 ----------------------------------------------------------
+ "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
+ "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
+
+ "hdx=noprobe"         : drive may be present, but do not probe for it
+ "hdx=nowerr"          : ignore the WRERR_STAT bit on this drive
+ "hdx=cdrom"           : drive is present, and is a cdrom drive
+ "hdx=cyl,head,sect"   : disk drive is present, with specified geometry
+ "hdx=autotune"                : driver will attempt to tune interface speed
+                               to the fastest PIO mode supported,
+                               if possible for this drive only.
+                               Not fully supported by all chipset types,
+                               and quite likely to cause trouble with
+                               older/odd IDE drives.
+
+ "idex=noprobe"                : do not attempt to access/use this interface
+ "idex=base"           : probe for an interface at the addr specified,
+                               where "base" is usually 0x1f0 or 0x170
+                               and "ctl" is assumed to be "base"+0x206
+ "idex=base,ctl"       : specify both base and ctl
+ "idex=base,ctl,irq"   : specify base, ctl, and irq number
+ "idex=autotune"       : driver will attempt to tune interface speed
+                               to the fastest PIO mode supported,
+                               for all drives on this interface.
+                               Not fully supported by all chipset types,
+                               and quite likely to cause trouble with
+                               older/odd IDE drives.
+ "idex=noautotune"     : driver will NOT attempt to tune interface speed
+                               This is the default for most chipsets,
+                               except the cmd640.
+
+ The following two are valid ONLY on ide0,
+ and the defaults for the base,ctl ports must not be altered.
+
+ "ide0=serialize"      : do not overlap operations on ide0 and ide1.
+ "ide0=dtc2278"                : probe/support DTC2278 interface
+ "ide0=ht6560b"                : probe/support HT6560B interface
+ "ide0=cmd640_vlb"     : *REQUIRED* for VLB cards with the CMD640 chip
+                         (not for PCI -- automatically detected)
+ "ide0=qd6580"         : probe/support qd6580 interface
+ "ide0=ali14xx"                : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
+ "ide0=umc8672"                : probe/support umc8672 chipsets
 
-  "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
-  "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
-  "hdx=noprobe"        : drive may be present, but do not probe for it
-  "hdx=nowerr"         : ignore the WRERR_STAT bit on this drive
-  "hdx=cdrom"          : drive is present, and is a cdrom drive
-  "hdx=cyl,head,sect"  : disk drive is present, with specified geometry
-  "idex=noprobe"       : do not attempt to access/use this interface
-  "idex=base"          : probe for an interface at the addr specified,
-                               where "base" is usually 0x1f0 or 0x170
-                               and "ctl" is assumed to be "base"+0x206
-  "idex=base,ctl"      : specify both base and ctl
-  "idex=base,ctl,irq"  : specify base, ctl, and irq number
-  The following two are valid ONLY on ide0 or ide1,
-  and the defaults for the base,ctl ports must not be altered.
-  "idex=serialize"     : do not overlap operations on ide0 and ide1.
-  "idex=dtc2278"       : enables use of DTC2278 secondary i/f
-  "idex=ht6560b"       : enables use of HT6560B secondary i/f
-  "idex=cmd640_vlb"    : required for VLB cards with the CMD640 chip
-                         (not for PCI -- automatically detected)
-  This option is valid ONLY on ide0, and the defaults for the base,ctl ports 
-  must not be altered.
-  
-  "ide0=qd6580"        : select "fast" interface speed on a qd6580 interface
 Everything else is rejected with a "BAD OPTION" message.
 
 ================================================================================
diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c
new file mode 100644 (file)
index 0000000..6d5c47f
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *  linux/drivers/block/ali14xx.c       Version 0.01  Feb 06, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ * ALI M14xx chipset EIDE controller
+ *
+ * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
+ * Derek's notes follow:
+ *
+ * I think the code should be pretty understandable,
+ * but I'll be happy to (try to) answer questions.
+ *
+ * The critical part is in the setupDrive function.  The initRegisters
+ * function doesn't seem to be necessary, but the DOS driver does it, so
+ * I threw it in.
+ *
+ * I've only tested this on my system, which only has one disk.  I posted
+ * it to comp.sys.linux.hardware, so maybe some other people will try it
+ * out.
+ *
+ * Derek Noonburg  (derekn@ece.cmu.edu)
+ * 95-sep-26
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include "ide.h"
+
+#define ALI_14xx_BUS_SPEED     40      /* PCI / VLB bus speed */
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
+
+/* register initialization data */
+typedef struct { byte reg, data; } RegInitializer;
+
+static RegInitializer initData[] = {
+       {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
+       {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
+       {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+       {0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
+       {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
+       {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
+       {0x35, 0x03}, {0x00, 0x00}
+};
+
+/* default timing parameters for each PIO mode */
+static struct { int time1, time2; } timeTab[4] = {
+       {600, 165},     /* PIO 0 */
+       {383, 125},     /* PIO 1 */
+       {240, 100},     /* PIO 2 */
+       {180,  80}      /* PIO 3 */
+};
+
+/* timing parameter registers for each drive */
+static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
+       {0x03, 0x26, 0x04, 0x27},     /* drive 0 */
+       {0x05, 0x28, 0x06, 0x29},     /* drive 1 */
+       {0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
+       {0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
+};
+
+static int basePort = 0;       /* base port address */
+static int regPort = 0;                /* port for register number */
+static int dataPort = 0;       /* port for register data */
+static byte regOn;     /* output to base port to access registers */
+static byte regOff;    /* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Read a controller register.
+ */
+static inline byte inReg (byte reg)
+{
+       outb_p(reg, regPort);
+       return inb(dataPort);
+}
+
+/*
+ * Write a controller register.
+ */
+static void outReg (byte data, byte reg)
+{
+       outb_p(reg, regPort);
+       outb_p(data, dataPort);
+}
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
+{
+       int driveNum;
+       int time1, time2, time1a;
+       byte param1, param2, param3, param4;
+       struct hd_driveid *id = drive->id;
+       unsigned long flags;
+
+       if (pio == 255)  {      /* auto-tune */
+               pio = id->tPIO;
+               if ((id->field_valid & 0x02) && (id->eide_pio_modes & 0x01))
+                       pio = 3;
+       }
+       /* calculate timing, according to PIO mode */
+       time1 = timeTab[pio].time1;
+       time2 = timeTab[pio].time2;
+       if (pio == 3) {
+               time1a = (id->capability & 0x08) ? id->eide_pio_iordy : id->eide_pio;
+               if (time1a != 0 && time1a < time1)
+                       time1 = time1a;
+       }
+       param3 = param1 = (time2 * ALI_14xx_BUS_SPEED + 999) / 1000;
+       param4 = param2 = (time1 * ALI_14xx_BUS_SPEED + 999) / 1000 - param1;
+       if (pio != 3) {
+               param3 += 8;
+               param4 += 8;
+       }
+       printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+               drive->name, pio, time1, time2, param1, param2, param3, param4);
+
+       /* stuff timing parameters into controller registers */
+       driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+       save_flags(flags);
+       cli();
+       outb_p(regOn, basePort);
+       outReg(param1, regTab[driveNum].reg1);
+       outReg(param2, regTab[driveNum].reg2);
+       outReg(param3, regTab[driveNum].reg3);
+       outReg(param4, regTab[driveNum].reg4);
+       outb_p(regOff, basePort);
+       restore_flags(flags);
+}
+
+/*
+ * Auto-detect the IDE controller port.
+ */
+static int findPort (void)
+{
+       int i;
+       byte t;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       for (i = 0; i < ALI_NUM_PORTS; ++i) {
+               basePort = ports[i];
+               regOff = inb(basePort);
+               for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+                       outb_p(regOn, basePort);
+                       if (inb(basePort) == regOn) {
+                               regPort = basePort + 4;
+                               dataPort = basePort + 8;
+                               t = inReg(0) & 0xf0;
+                               outb_p(regOff, basePort);
+                               restore_flags(flags);
+                               if (t != 0x50)
+                                       return 0;
+                               return 1;  /* success */
+                       }
+               }
+               outb_p(regOff, basePort);
+       }
+       restore_flags(flags);
+       return 0;
+}
+
+/*
+ * Initialize controller registers with default values.
+ */
+static int initRegisters (void) {
+       RegInitializer *p;
+       byte t;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       outb_p(regOn, basePort);
+       for (p = initData; p->reg != 0; ++p)
+               outReg(p->data, p->reg);
+       outb_p(0x01, regPort);
+       t = inb(regPort) & 0x01;
+       outb_p(regOff, basePort);
+       restore_flags(flags);
+       return t;
+}
+
+void init_ali14xx (void)
+{
+       /* auto-detect IDE controller port */
+       if (!findPort()) {
+               printk("ali14xx: not found\n");
+               return;
+       }
+
+       printk("ali14xx: base= 0x%03x, regOn = 0x%02x\n", basePort, regOn);
+       ide_hwifs[0].chipset = ide_ali14xx;
+       ide_hwifs[1].chipset = ide_ali14xx;
+       ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
+       ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
+
+       /* initialize controller registers */
+       if (!initRegisters()) {
+               printk("ali14xx: Chip initialization failed\n");
+               return;
+       }
+}
index 9082404f99af693764024690aaf4f5aa262df6e4..927958f8a61fb551e72edafe6e8478922ecbcc0c 100644 (file)
@@ -1,11 +1,11 @@
 /*
- *  linux/drivers/block/cmd640.c       Version 0.04  Jan 11, 1996
+ *  linux/drivers/block/cmd640.c       Version 0.07  Jan 27, 1996
  *
  *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
  */
 
 /*
- *  Principal Author/Maintainer:  abramov@cecmow.enet.dec.com (Igor)
+ *  Principal Author/Maintainer:  abramov@cecmow.enet.dec.com (Igor Abramov)
  *
  *  This file provides support for the advanced features and bugs
  *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
  *                     with read ahead mode. Separate function for setting
  *                     readahead is added, possibly it will be called some
  *                     day from ioctl processing code.
+ *  
+ *  Version 0.04       Now configs/compiles separate from ide.c  -ml 
  *
- *  Version 0.04       Now configs/compiles separate from ide.c  -ml
- */
-
-/*
- *  There is a known problem with current version of this driver.
- *  If the only device on secondary interface is CD-ROM, at some
- *  computers it is not recognized. In all reported cases CD-ROM
- *  was 2x or 4x speed Mitsumi drive.
+ *  Version 0.05       Major rewrite of interface timing code.
+ *                     Added new function cmd640_set_mode to set PIO mode
+ *                     from ioctl call. New drives added to black list.
  *
- *  The following workarounds could work:
+ *  Version 0.06       More code cleanup. Readahead is enabled only for
+ *                     detected hard drives, not included in readahed
+ *                     black list.
  * 
- *    1. put CD-ROM as slave on primary interface
+ *  Version 0.07       Changed to more conservative drive tuning policy.
+ *                     Unknown drives, which report PIO < 4 are set to 
+ *                     (reported_PIO - 1) if it is supported, or to PIO0.
+ *                     List of known drives extended by info provided by
+ *                     CMD at their ftp site.
  *
- *    2. or define symbol at next line as 0
- * 
+ *  Version 0.08       Added autotune/noautotune support.  -ml
+ *                     
  */
 
-#define CMD640_NORMAL_INIT 1
-
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
 #include <linux/types.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <asm/io.h>
-
 #include "ide.h"
 
-extern ide_hwif_t ide_hwifs[];
-
 int cmd640_vlb = 0;
 
 /*
@@ -104,63 +102,64 @@ int cmd640_vlb = 0;
 #define DRWTIM23       0x58
 #define BRST           0x59
 
+static ide_tuneproc_t cmd640_tune_drive;
+
 /* Interface to access cmd640x registers */
-static void (*put_cmd640_reg)(int key, int reg_no, int val);
-static byte (*get_cmd640_reg)(int key, int reg_no);
+static void (*put_cmd640_reg)(int reg_no, int val);
+static byte (*get_cmd640_reg)(int reg_no);
 
 enum { none, vlb, pci1, pci2 };
 static int     bus_type = none;
 static int     cmd640_chip_version;
 static int     cmd640_key;
-static byte    is_cmd640[MAX_HWIFS];
 static int     bus_speed; /* MHz */
 
 /*
  * For some unknown reasons pcibios functions which read and write registers
- * do not always work with cmd640. We use direct io instead.
+ * do not always work with cmd640. We use direct IO instead.
  */
 
 /* PCI method 1 access */
 
-static void put_cmd640_reg_pci1(int key, int reg_no, int val)
+static void put_cmd640_reg_pci1(int reg_no, int val)
 {
        unsigned long flags;
 
        save_flags(flags);
        cli();
-       outl_p((reg_no & 0xfc) | key, 0xcf8);
+       outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8);
        outb_p(val, (reg_no & 3) + 0xcfc);
        restore_flags(flags);
 }
 
-static byte get_cmd640_reg_pci1(int key, int reg_no)
+static byte get_cmd640_reg_pci1(int reg_no)
 {
        byte b;
        unsigned long flags;
 
        save_flags(flags);
        cli();
-       outl_p((reg_no & 0xfc) | key, 0xcf8);
+       outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8);
        b = inb_p(0xcfc + (reg_no & 3));
        restore_flags(flags);
        return b;
 }
 
 /* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2(int key, int reg_no, int val)
+static void put_cmd640_reg_pci2(int reg_no, int val)
 {
        unsigned long flags;
 
        save_flags(flags);
        cli();
        outb_p(0x10, 0xcf8);
-       outb_p(val, key + reg_no);
+       outb_p(val, cmd640_key + reg_no);
        outb_p(0, 0xcf8);
        restore_flags(flags);
 }
 
-static byte get_cmd640_reg_pci2(int key, int reg_no)
+static byte get_cmd640_reg_pci2(int reg_no)
 {
        byte b;
        unsigned long flags;
@@ -168,7 +167,7 @@ static byte get_cmd640_reg_pci2(int key, int reg_no)
        save_flags(flags);
        cli();
        outb_p(0x10, 0xcf8);
-       b = inb_p(key + reg_no);
+       b = inb_p(cmd640_key + reg_no);
        outb_p(0, 0xcf8);
        restore_flags(flags);
        return b;
@@ -176,26 +175,26 @@ static byte get_cmd640_reg_pci2(int key, int reg_no)
 
 /* VLB access */
 
-static void put_cmd640_reg_vlb(int key, int reg_no, int val)
+static void put_cmd640_reg_vlb(int reg_no, int val)
 {
        unsigned long flags;
 
        save_flags(flags);
        cli();
-       outb_p(reg_no, key + 8);
-       outb_p(val, key + 0xc);
+       outb_p(reg_no, cmd640_key + 8);
+       outb_p(val, cmd640_key + 0xc);
        restore_flags(flags);
 }
 
-static byte get_cmd640_reg_vlb(int key, int reg_no)
+static byte get_cmd640_reg_vlb(int reg_no)
 {
        byte b;
        unsigned long flags;
 
        save_flags(flags);
        cli();
-       outb_p(reg_no, key + 8);
-       b = inb_p(key + 0xc);
+       outb_p(reg_no, cmd640_key + 8);
+       b = inb_p(cmd640_key + 0xc);
        restore_flags(flags);
        return b;
 }
@@ -305,13 +304,8 @@ static void cmd640_reset_controller(int iface_no)
 
 int ide_probe_for_cmd640x(void)
 {
-       int  i;
        int  second_port;
-       int  cmd_read_ahead;
-       byte b;
-
-       for (i = 0; i < MAX_HWIFS; i++)
-               is_cmd640[i] = 0;
+        byte b;
 
        if (probe_for_cmd640_pci1()) {
                bus_type = pci1;
@@ -324,27 +318,45 @@ int ide_probe_for_cmd640x(void)
                return 0;
        }
 
+       ide_hwifs[0].serialized = 1;    /* ensure this *always* gets set */
+       
+#if 0  
+       /* Dump initial state of chip registers */
+       for (b = 0; b != 0xff; b++) {
+               printk(" %2x%c", get_cmd640_reg(b),
+                               ((b&0xf) == 0xf) ? '\n' : ',');
+       }
+
+#endif
+
        /*
         * Undocumented magic. (There is no 0x5b port in specs)
         */
 
-       put_cmd640_reg(cmd640_key, 0x5b, 0xbd);
-       if (get_cmd640_reg(cmd640_key, 0x5b) != 0xbd) {
+       put_cmd640_reg(0x5b, 0xbd);
+       if (get_cmd640_reg(0x5b) != 0xbd) {
                printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
                return 0;
        }
-       put_cmd640_reg(cmd640_key, 0x5b, 0);
+       put_cmd640_reg(0x5b, 0);
 
        /*
         * Documented magic.
         */
 
-       cmd640_chip_version = get_cmd640_reg(cmd640_key, CFR) & CFR_DEVREV;
+       cmd640_chip_version = get_cmd640_reg(CFR) & CFR_DEVREV;
        if (cmd640_chip_version == 0) {
                printk ("ide: wrong CMD640 version -- 0\n");
                return 0;
        }
 
+       /*
+        * Setup the most conservative timings for all drives,
+        */
+       put_cmd640_reg(ARTTIM0, 0xc0);
+       put_cmd640_reg(ARTTIM1, 0xc0);
+       put_cmd640_reg(ARTTIM23, 0xcc); /* 0xc0? */
+
        /*
         * Do not initialize secondary controller for vlbus
         */
@@ -357,45 +369,51 @@ int ide_probe_for_cmd640x(void)
         */
        bus_speed = (bus_type == vlb) ? 50 : 40; 
 
-       /*
-        * Enable readahead for versions above 'A'
-        */
-       cmd_read_ahead = (cmd640_chip_version > 1);
-
-       /*
+        /*
         * Setup Control Register
         */
-       b = get_cmd640_reg(cmd640_key, CNTRL);  
+       b = get_cmd640_reg(CNTRL);      
 
-#if CMD640_NORMAL_INIT
        if (second_port)
                b |= CNTRL_ENA_2ND;
        else
                b &= ~CNTRL_ENA_2ND;
-#endif 
 
-       if (cmd_read_ahead)
-               b &= ~(CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
-       else
-               b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
+       /*
+        * Disable readahead for drives at primary interface
+        */
+       b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
 
+        put_cmd640_reg(CNTRL, b);
 
-       put_cmd640_reg(cmd640_key, CNTRL, b);
+       /*
+        * Note that we assume that the first interface is at 0x1f0,
+        * and that the second interface, if enabled, is at 0x170.
+        */
+       ide_hwifs[0].chipset = ide_cmd640;
+       ide_hwifs[0].tuneproc = &cmd640_tune_drive;
+       if (ide_hwifs[0].drives[0].autotune == 0)
+               ide_hwifs[0].drives[0].autotune = 1;
+       if (ide_hwifs[0].drives[1].autotune == 0)
+               ide_hwifs[0].drives[1].autotune = 1;
 
        /*
         * Initialize 2nd IDE port, if required
         */
        if (second_port) {
-               /* We reset timings, and setup read-ahead */
-               b = cmd_read_ahead ? 0 : (DIS_RA2 | DIS_RA3);
-               put_cmd640_reg(cmd640_key, ARTTIM23, b);
-               put_cmd640_reg(cmd640_key, DRWTIM23, 0);
+               ide_hwifs[1].chipset = ide_cmd640;
+               ide_hwifs[1].tuneproc = &cmd640_tune_drive;
+               if (ide_hwifs[1].drives[0].autotune == 0)
+                       ide_hwifs[1].drives[0].autotune = 1;
+               if (ide_hwifs[1].drives[1].autotune == 0)
+                       ide_hwifs[1].drives[1].autotune = 1;
+               /* We reset timings, and disable read-ahead */
+               put_cmd640_reg(ARTTIM23, (DIS_RA2 | DIS_RA3));
+               put_cmd640_reg(DRWTIM23, 0);
 
                cmd640_reset_controller(1);
        }
 
-       ide_hwifs[0].serialized = 1;
-
        printk("ide: buggy CMD640%c interface at ", 
               'A' - 1 + cmd640_chip_version);
        switch (bus_type) {
@@ -410,28 +428,28 @@ int ide_probe_for_cmd640x(void)
                        break;
        }
 
-       is_cmd640[0] = is_cmd640[1] = 1;
-
        /*
         * Reset interface timings
         */
-       put_cmd640_reg(cmd640_key, CMDTIM, 0);
+       put_cmd640_reg(CMDTIM, 0);
 
-       printk("\n ... serialized, %s read-ahead, secondary interface %s\n",
-              cmd_read_ahead ? "enabled" : "disabled",
+       printk("\n ... serialized, secondary interface %s\n",
               second_port ? "enabled" : "disabled");
 
        return 1;
 }
 
-static int as_clocks(int a) {
-       switch (a & 0xc0) {
-               case 0 :        return 4;
-               case 0x40 :     return 2;
-               case 0x80 :     return 3;
-               case 0xc0 :     return 5;
-               default :       return -1;
-       }
+int cmd640_off(void) {
+       static int a = 0;
+       byte b;
+
+       if (bus_type == none || a == 1)
+               return 0;
+       a = 1;
+       b = get_cmd640_reg(CNTRL);      
+       b &= ~CNTRL_ENA_2ND;
+       put_cmd640_reg(CNTRL, b);
+       return 1;
 }
 
 /*
@@ -451,72 +469,122 @@ static void set_readahead_mode(int mode, int if_num, int dr_num)
        int mask = masks[if_num][dr_num];
        byte b;
 
-       b = get_cmd640_reg(cmd640_key, port);
+       b = get_cmd640_reg(port);
        if (mode)
-               b &= mask; /* Enable readahead for specific drive */
+               b &= ~mask;     /* Enable readahead for specific drive */
        else
-               b |= mask; /* Disable readahed for specific drive */
-       put_cmd640_reg(cmd640_key, port, b);
+               b |= mask;      /* Disable readahed for specific drive */
+       put_cmd640_reg(port, b);
 }              
 
 static struct readahead_black_list {
        const char*     name;
        int             mode;   
 } drives_ra[] = {
-       { "ST3655A",    0 },
+        { "ST3655A",   0 },
+        { "SAMSUNG",   0 },    /* Be conservative */
        { NULL, 0 }
 };     
 
+static int strmatch(const char* pattern, const char* name) {
+       char c1, c2;
+
+       while (1) {
+               c1 = *pattern++;
+               c2 = *name++;
+               if (c1 == 0) {
+                       return 0;
+               }
+               if (c1 != c2)
+                       return 1;
+       }
+}
+
 static int known_drive_readahead(char* name) {
        int i;
 
-       for (i = 0; drives_ra[i].name != NULL; i++)
-               if (strcmp(name, drives_ra[i].name) == 0)
+       for (i = 0; drives_ra[i].name != NULL; i++) {
+               if (strmatch(drives_ra[i].name, name) == 0) {
                        return drives_ra[i].mode;
-       return -1;
+               }
+       }
+        return -1;
 }
 
+static int arttim[4]  = {2, 2, 2, 2};  /* Address setup count (in clocks) */
+static int a_count[4] = {1, 1, 1, 1};  /* Active count   (encoded) */
+static int r_count[4] = {1, 1, 1, 1};  /* Recovery count (encoded) */
+
 /*
- * Tuning of drive parameters
+ * Convert address setup count from number of clocks 
+ * to representation used by controller
  */
 
-static void cmd640_set_timing(int if_num, int dr_num, int r1, int r2) {
-       int  b_reg;
-       byte b;
-       int  r52;
-       static int a = 0;
+inline static int pack_arttim(int clocks)
+{
+       if (clocks <= 2) return 0x40;
+       else if (clocks == 3) return 0x80;
+       else if (clocks == 4) return 0x00;
+       else return 0xc0;
+}
+
+/*
+ * Pack active and recovery counts into single byte representation
+ * used by controller
+ */
 
-       b_reg = if_num ? ARTTIM23 : dr_num ? ARTTIM1 : ARTTIM0;
+inline static int pack_counts(int act_count, int rec_count)
+{
+       return ((act_count & 0x0f)<<4) | (rec_count & 0x0f);
+}
+
+inline int max(int a, int b) { return a > b ? a : b; }
+inline int max4(int *p) { return max(p[0], max(p[1], max(p[2], p[3]))); }
+
+/*
+ * Set timing parameters
+ */
+
+static void cmd640_set_timing(int if_num, int dr_num)
+{
+       int     b_reg;
+       int     ac, rc, at;
+
+       /*
+        * Set address setup count and drive read/write timing registers.
+        * Primary interface has individual count/timing registers for
+        * each drive. Secondary interface has common set of registers, and
+        * we should set timings for the slowest drive.
+        */
 
        if (if_num == 0) {
-               put_cmd640_reg(cmd640_key, b_reg, r1);
-               put_cmd640_reg(cmd640_key, b_reg + 1, r2);
+               b_reg = dr_num ? ARTTIM1 : ARTTIM0;
+               at = arttim[dr_num];
+               ac = a_count[dr_num];
+               rc = r_count[dr_num];
        } else {
-               b = get_cmd640_reg(cmd640_key, b_reg);
-               if (a == 0 || as_clocks(b) < as_clocks(r1))
-                       put_cmd640_reg(cmd640_key, b_reg, (b & 0xc0) | r1);
-               
-               if (a == 0) {
-                       put_cmd640_reg(cmd640_key, b_reg + 1, r2);
-               } else {
-                       b = get_cmd640_reg(cmd640_key, b_reg + 1);
-                       r52 =  (b&0x0f) < (r2&0x0f) ? (r2&0x0f) : (b&0x0f);
-                       r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
-                       put_cmd640_reg(cmd640_key, b_reg+1, r52);
-               }
-               a = 1;
+               b_reg = ARTTIM23;
+               at = max(arttim[2], arttim[3]);
+               ac = max(a_count[2], a_count[3]);
+               rc = max(r_count[2], r_count[3]);
        }
 
-       b = get_cmd640_reg(cmd640_key, CMDTIM);
-       if (b == 0) {
-               put_cmd640_reg(cmd640_key, CMDTIM, r2);
-       } else {
-               r52  = (b&0x0f) < (r2&0x0f) ? (r2&0x0f) : (b&0x0f);
-               r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
-               put_cmd640_reg(cmd640_key, CMDTIM, r52);
-       }
+       put_cmd640_reg(b_reg, pack_arttim(at));
+       put_cmd640_reg(b_reg + 1, pack_counts(ac, rc));
+
+       /*
+        * Update CMDTIM (IDE Command Block Timing Register) 
+        */
+
+       ac = max4(r_count);
+       rc = max4(a_count);
+       put_cmd640_reg(CMDTIM, pack_counts(ac, rc));
 }
 
+/*
+ * Standard timings for PIO modes
+ */
+
 static struct pio_timing {
        int     mc_time;        /* Minimal cycle time (ns) */
        int     av_time;        /* Address valid to DIOR-/DIOW- setup (ns) */
@@ -527,23 +595,74 @@ static struct pio_timing {
        { 30,   100,    240 },  /* PIO Mode 2 */
        { 30,   80,     180 },  /* PIO Mode 3 */
        { 25,   70,     125 },  /* PIO Mode 4 */
-       { 20,   50,     100 }   /* PIO Mode ? */
+       { 20,   50,     100 }   /* PIO Mode ? (nonstandard) */
 };
 
+/*
+ * Black list. Some drives incorrectly report their maximal PIO modes, at least
+ * in respect to CMD640. Here we keep info on some known drives.
+ */
+
 static struct drive_pio_info {
        const char      *name;
        int             pio;
 } drive_pios[] = {
+/*     { "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+
+       { "WDC AC2700",  3 },
+       { "WDC AC2540",  3 },
+       { "WDC AC2420",  3 },
+       { "WDC AC2340",  3 },
+       { "WDC AC2250",  0 },
+       { "WDC AC2200",  0 },
+       { "WDC AC2120",  0 },
+       { "WDC AC2850",  3 },
+       { "WDC AC1270",  3 },
+       { "WDC AC1170",  3 },
+       { "WDC AC1210",  1 },
+       { "WDC AC280",   0 },
+/*     { "WDC AC21000", 4 }, */
+       { "WDC AC31000", 3 },
+/*     { "WDC AC21200", 4 }, */
+       { "WDC AC31200", 3 },
+/*     { "WDC AC31600", 4 }, */
+
        { "Maxtor 7131 AT", 1 },
        { "Maxtor 7171 AT", 1 },
        { "Maxtor 7213 AT", 1 },
        { "Maxtor 7245 AT", 1 },
+       { "Maxtor 7345 AT", 1 },
+       { "Maxtor 7546 AT", 3 },
+       { "Maxtor 7540 AV", 3 },
+
+       { "SAMSUNG SHD-3121A", 1 },
        { "SAMSUNG SHD-3122A", 1 },
+       { "SAMSUNG SHD-3172A", 1 },
+
+/*     { "ST51080A", 4 },
+ *     { "ST51270A", 4 },
+ *     { "ST31220A", 4 },
+ *     { "ST31640A", 4 },
+ *     { "ST32140A", 4 },
+ *     { "ST3780A",  4 },
+ */    { "ST5660A",  3 },
+       { "ST3660A",  3 },
+       { "ST3630A",  3 },
+       { "ST3655A",  3 },
+       { "ST3391A",  3 },
+       { "ST3390A",  1 },
+       { "ST3600A",  1 },
+       { "ST3290A",  0 },
+       { "ST3144A",  0 },
+
        { "QUANTUM ELS127A", 0 },
+       { "QUANTUM ELS170A", 0 },
        { "QUANTUM LPS240A", 0 },
+       { "QUANTUM LPS210A", 3 },
        { "QUANTUM LPS270A", 3 },
+       { "QUANTUM LPS365A", 3 },
        { "QUANTUM LPS540A", 3 },
-       { "QUANTUM FIREBALL1080A", 3 },
+       { "QUANTUM FIREBALL", 3 }, /* For models 540/640/1080/1280 */
        { NULL, 0 }
 };
 
@@ -551,23 +670,18 @@ static int known_drive_pio(char* name) {
        struct drive_pio_info* pi;
 
        for (pi = drive_pios; pi->name != NULL; pi++) {
-               if (strcmp(pi->name, name) == 0)
+               if (strmatch(pi->name, name) == 0)
                        return pi->pio;
        }
        return -1;
 }
 
-static void cmd640_timings_to_regvals(int mc_time, int av_time, int ds_time,
-                               int clock_time,
-                               int* r1, int* r2)
+static void cmd640_timings_to_clocks(int mc_time, int av_time, int ds_time,
+                               int clock_time, int drv_idx)
 {
        int a, b;
 
-       a = (mc_time + clock_time - 1)/clock_time;
-       if (a <= 2) *r1 = 0x40;
-       else if (a == 3) *r1 = 0x80;
-       else if (a == 4) *r1 = 0;
-       else *r1 = 0xc0;
+       arttim[drv_idx] = (mc_time + clock_time - 1)/clock_time;
 
        a = (av_time + clock_time - 1)/clock_time;
        if (a < 2)
@@ -579,13 +693,15 @@ static void cmd640_timings_to_regvals(int mc_time, int av_time, int ds_time,
                a += b - 0x11;
                b = 0x11;
        }
-       if (a > 0xf)
-               a = 0;
+       if (a > 0x10)
+               a = 0x10;
        if (cmd640_chip_version > 1)
                b -= 1;
-       if (b > 0xf)
-               b = 0;
-       *r2 = (a << 4) | b;
+       if (b > 0x10)
+               b = 0x10;
+
+       a_count[drv_idx] = a;
+       r_count[drv_idx] = b;
 }
 
 static void set_pio_mode(int if_num, int drv_num, int mode_num) {
@@ -601,34 +717,57 @@ static void set_pio_mode(int if_num, int drv_num, int mode_num) {
                udelay(10000);
 }
 
-void cmd640_tune_drive(ide_drive_t* drive) {
+/*
+ * Set a specific pio_mode for a drive
+ */
+
+static void cmd640_set_mode(ide_drive_t* drive, int pio_mode) {
+       int interface_number;
+       int drive_number;
+       int clock_time; /* ns */
+       int mc_time, av_time, ds_time;
+
+       interface_number = HWIF(drive)->index;
+       drive_number = drive->select.b.unit;
+       clock_time = 1000/bus_speed;
+
+       mc_time = pio_timings[pio_mode].mc_time;
+       av_time = pio_timings[pio_mode].av_time;
+       ds_time = pio_timings[pio_mode].ds_time;
+
+       cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time,
+                               interface_number*2 + drive_number);
+       set_pio_mode(interface_number, drive_number, pio_mode);
+       cmd640_set_timing(interface_number, drive_number);
+}
+
+/*
+ * Drive PIO mode "autoconfiguration".
+ * Ideally, this code should *always* call cmd640_set_mode(), but it doesn't.
+ */
+
+static void cmd640_tune_drive(ide_drive_t *drive, byte pio_mode) {
        int interface_number;
        int drive_number;
        int clock_time; /* ns */
        int max_pio;
        int mc_time, av_time, ds_time;
        struct hd_driveid* id;
-       int r1, r2;
-       int mode;
+       int readahead;  /* there is a global named read_ahead */
 
-       /*
-        * Determine if drive is under cmd640 control
-        */
-       interface_number = HWIF(drive) - ide_hwifs;
-       if (!is_cmd640[interface_number])
+       if (pio_mode != 255) {
+               cmd640_set_mode(drive, pio_mode);
                return;
+       }
 
-       drive_number = drive - HWIF(drive)->drives;
+       interface_number = HWIF(drive)->index;
+       drive_number = drive->select.b.unit;
        clock_time = 1000/bus_speed;
        id = drive->id;
        if ((max_pio = known_drive_pio(id->model)) != -1) {
-               mc_time = pio_timings[max_pio].mc_time;
-               av_time = pio_timings[max_pio].av_time;
                ds_time = pio_timings[max_pio].ds_time;
        } else {
                max_pio = id->tPIO;
-               mc_time = pio_timings[max_pio].mc_time;
-               av_time = pio_timings[max_pio].av_time;
                ds_time = pio_timings[max_pio].ds_time;
                if (id->field_valid & 2) {
                        if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
@@ -636,26 +775,41 @@ void cmd640_tune_drive(ide_drive_t* drive) {
                                else if (id->eide_pio_modes & 2) max_pio = 4;
                                else max_pio = 3;
                                ds_time = id->eide_pio_iordy;
-                               mc_time = pio_timings[max_pio].mc_time;
-                               av_time = pio_timings[max_pio].av_time;
                        } else {
                                ds_time = id->eide_pio;
                        }
                        if (ds_time == 0)
                                ds_time = pio_timings[max_pio].ds_time;
                }
+
+               /*
+                * Conservative "downgrade"
+                */
+               if (max_pio < 4 && max_pio != 0) {
+                       max_pio -= 1;
+                       ds_time = pio_timings[max_pio].ds_time;         
+               }
        }
-       cmd640_timings_to_regvals(mc_time, av_time, ds_time, clock_time,
-                               &r1, &r2);
+       mc_time = pio_timings[max_pio].mc_time;
+       av_time = pio_timings[max_pio].av_time;
+       cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time,
+                               interface_number*2 + drive_number);
        set_pio_mode(interface_number, drive_number, max_pio);
-       cmd640_set_timing(interface_number, drive_number, r1, r2);
+       cmd640_set_timing(interface_number, drive_number);
 
        /*
-        * Disable (or set) readahead mode for known drive
+        * Disable (or set) readahead mode
         */
-       if ((mode = known_drive_readahead(id->model)) != -1) {
-               set_readahead_mode(mode, interface_number, drive_number);
-               printk("Readahead %s,", mode ? "enabled" : "disabled");
-       }
-       printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2);
+
+       readahead = 0;
+       if (cmd640_chip_version > 1) {  /* Mmmm.. probably should be > 2 ?? */
+               readahead = known_drive_readahead(id->model);
+               if (readahead == -1)
+                       readahead = 1;  /* Mmmm.. probably be 0 ?? */
+               set_readahead_mode(readahead, interface_number, drive_number);
+       }   
+
+       printk ("Mode and Timing set to PIO%d, Readahead is %s\n", 
+               max_pio, readahead ? "enabled" : "disabled");
 }
+
diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c
new file mode 100644 (file)
index 0000000..f291e57
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  linux/drivers/block/dtc2278.c       Version 0.01  Feb 06, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include "ide.h"
+
+/*
+ * From: andy@cercle.cts.com (Dyan Wile)
+ *
+ * Below is a patch for DTC-2278 - alike software-programmable controllers
+ * The code enables the secondary IDE controller and the PIO4 (3?) timings on
+ * the primary (EIDE). You may probably have to enable the 32-bit support to
+ * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem  corrupted with -u1, but under heavy disk load only :-)
+ *
+ * From: mlord@bnr.ca -- this chipset is now forced to use the "serialize" feature,
+ * which hopefully will make it more reliable to use.. maybe it has the same bugs
+ * as the CMD640B and RZ1000 ??
+ */
+
+static void sub22 (char b, char c)
+{
+       int i;
+
+       for(i = 0; i < 3; ++i) {
+               inb(0x3f6);
+               outb_p(b,0xb0);
+               inb(0x3f6);
+               outb_p(c,0xb4);
+               inb(0x3f6);
+               if(inb(0xb4) == c) {
+                       outb_p(7,0xb0);
+                       inb(0x3f6);
+                       return; /* success */
+               }
+       }
+}
+
+static void tune_dtc2278 (ide_drive_t *drive, byte pio_mode)
+{
+       unsigned long flags;
+
+       if (pio_mode != 255) {  /* auto-tune not yet supported here */
+               if (pio_mode >= 3) {
+                       save_flags(flags);
+                       cli();
+                       /*
+                        * This enables PIO mode4 (3?) on the first interface
+                        */
+                       sub22(1,0xc3);
+                       sub22(0,0xa0);
+                       restore_flags(flags);
+               } else {
+                       /* we don't know how to set it back again.. */
+               }
+       }
+}
+
+void init_dtc2278 (void)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       /*
+        * This enables the second interface
+        */
+       outb_p(4,0xb0);
+       inb(0x3f6);
+       outb_p(0x20,0xb4);
+       inb(0x3f6);
+       restore_flags(flags);
+
+       ide_hwifs[0].serialized = 1;
+       ide_hwifs[0].chipset = ide_dtc2278;
+       ide_hwifs[1].chipset = ide_dtc2278;
+       ide_hwifs[0].tuneproc = &tune_dtc2278;
+}
index 17e4a27618799d651a1e5cb498b35d34caf1840e..f2967d5c720669ad0fea675d0a3971b248f7814e 100644 (file)
@@ -3682,7 +3682,7 @@ static char get_fdc_version(void)
                case 0x0:
                        output_byte(FD_SAVE);
                        r = result();
-                       if (r != 17) {
+                       if (r != 16) {
                                printk("FDC %d init: SAVE: unexpected return of %d bytes.\n", fdc, r);
                                return FDC_UNKNOWN;
                        }
index 2024236927c3e48acff11c5095c92495eda1dc7d..e7774115fdaeb3b8cdc0ebe3c826c64f02940e95 100644 (file)
@@ -14,6 +14,8 @@
  *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  *
  *  More flexible handling of extended partitions - aeb, 950831
+ *
+ *  Check partition table on IDE disks for common CHS translations
  */
 
 #include <linux/config.h>
@@ -198,7 +200,7 @@ static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s
        unsigned char *data;
        int mask = (1 << hd->minor_shift) - 1;
 #ifdef CONFIG_BLK_DEV_IDE
-       int tested_for_dm6 = 0;
+       int tested_for_xlate = 0;
 
 read_mbr:
 #endif
@@ -221,12 +223,12 @@ check_table:
        p = (struct partition *) (0x1be + data);
 
 #ifdef CONFIG_BLK_DEV_IDE
-       /*
-        *  Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation
-        */
-       if (!tested_for_dm6++) {        /* only check for DM6 *once* */
+       if (!tested_for_xlate++) {      /* Do this only once per disk */
+               /*
+                * Look for various forms of IDE disk geometry translation
+                */
                extern int ide_xlate_1024(kdev_t, int, const char *);
-               /* check for various "disk managers" which do strange things */
+               unsigned int sig = *(unsigned short *)(data + 2);
                if (p->sys_ind == EZD_PARTITION) {
                        /*
                         * The remainder of the disk must be accessed using
@@ -256,20 +258,33 @@ check_table:
                                brelse(bh);
                                goto read_mbr;  /* start over with new MBR */
                        }
-               } else {
-                       /* look for DM6 signature in MBR, courtesy of OnTrack */
-                       unsigned int sig = *(unsigned short *)(data + 2);
-                       if (sig <= 0x1ae
-                        && *(unsigned short *)(data + sig) == 0x55AA
+               } else if (sig <= 0x1ae && *(unsigned short *)(data + sig) == 0x55AA
                         && (1 & *(unsigned char *)(data + sig + 2)) ) 
-                       {
-                               (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
-                       } else {
-                               /* look for DM6 AUX partition type in slot 1 */
-                               if (p->sys_ind == DM6_AUX1PARTITION
-                                || p->sys_ind == DM6_AUX3PARTITION)
-                               {
-                                       (void)ide_xlate_1024(dev, 0, " [DM6:AUX]");
+               {
+                       /*
+                        * DM6 signature in MBR, courtesy of OnTrack
+                        */
+                       (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
+               } else if (p->sys_ind == DM6_AUX1PARTITION || p->sys_ind == DM6_AUX3PARTITION) {
+                       /*
+                        * DM6 on other than the first (boot) drive
+                        */
+                       (void) ide_xlate_1024(dev, 0, " [DM6:AUX]");
+               } else {
+                       /*
+                        * Examine the partition table for common translations.
+                        * This is necessary for drives for situations where
+                        * the translated geometry is unavailable from the BIOS.
+                        */
+                       for (i = 0; i < 4 ; i++) {
+                               struct partition *q = &p[i];
+                               if (NR_SECTS(q) && q->sector == 1 && q->end_sector == 63) {
+                                       unsigned int heads = q->end_head + 1;
+                                       if (heads == 32 || heads == 64 || heads == 128) {
+
+                                               (void) ide_xlate_1024(dev, heads, " [PTBL]");
+                                               break;
+                                       }
                                }
                        }
                }
diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c
new file mode 100644 (file)
index 0000000..a80abf5
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *  linux/drivers/block/ht6580.c       Version 0.01  Feb 06, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include "ide.h"
+
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ *
+ * This stuff is courtesy of malafoss@snakemail.hut.fi
+ *
+ * At least one user has reported that this code can confuse the floppy
+ * controller and/or driver -- perhaps this should be changed to use
+ * a read-modify-write sequence, so as not to disturb other bits in the reg?
+ */
+
+/*
+ * We don't know what all of the bits are for, but we *do* know about these:
+ *     bit5 (0x20): "1" selects slower speed (?)
+ *     bit0 (0x01): "1" selects second interface
+ */
+static byte qd6560b_selects [2][MAX_DRIVES] = {{0x3c,0x3c}, {0x3d,0x3d}};
+
+static void qd6560b_selectproc (ide_drive_t *drive)    /* called from ide.c */
+{
+       static byte current_select = 0;
+       byte drive_select = qd6560b_selects[HWIF(drive)->index][drive->select.b.unit];
+
+       if (drive_select != current_select) {
+               byte t;
+               unsigned long flags;
+               save_flags (flags);
+               cli();
+               current_select = drive_select;
+               (void) inb(0x3e6);
+               (void) inb(0x3e6);
+               (void) inb(0x3e6);
+               /*
+                * Note: input bits are reversed to output bits!!
+                */
+               t = inb(0x3e6) ^ 0x3f;
+               t &= (~0x21);
+               t |= (current_select & 0x21);
+               outb(t,0x3e6);
+               restore_flags (flags);
+       }
+}
+
+/*
+ * Autodetection and initialization of ht6560b
+ */
+int try_to_init_ht6560b(void)
+{
+       byte orig_value;
+       int i;
+
+       /* Autodetect ht6560b */
+       if ((orig_value=inb(0x3e6)) == 0xff)
+               return 0;
+
+       for (i=3;i>0;i--) {
+               outb(0x00,0x3e6);
+               if (!( (~inb(0x3e6)) & 0x3f )) {
+                         outb(orig_value,0x3e6);
+                         return 0;
+               }
+       }
+       outb(0x00,0x3e6);
+       if ((~inb(0x3e6))& 0x3f) {
+               outb(orig_value,0x3e6);
+               return 0;
+       }
+       /* 
+        * Ht6560b autodetected:
+        *     reverse input bits to output bits
+        *     initialize bit1 to 0
+        */
+       outb((orig_value ^ 0x3f) & 0xfd,0x3e6);
+       printk("ht6560b: detected and initialized\n");
+       return 1;
+}
+
+static void tune_ht6560b (ide_drive_t *drive, byte pio)
+{
+       unsigned int hwif, unit;
+
+       if (pio == 255)  {      /* auto-tune */
+               if (drive->media != ide_disk) {
+                       pio = 0; /* cdroms don't like our fast mode */
+               } else {
+                       struct hd_driveid *id = drive->id;
+                       pio = id->tPIO;
+                       if ((id->field_valid & 0x02) && (id->eide_pio_modes & 0x01))
+                               pio = 3;
+               }
+       }
+       hwif = HWIF(drive)->index;
+       unit = drive->select.b.unit;
+       if (pio < 3)
+               qd6560b_selects[hwif][unit] |= 0x20;
+       else
+               qd6560b_selects[hwif][unit] &= ~0x20;
+}
+
+void init_ht6560b (void)
+{
+       if (check_region(0x3e6,1)) {
+               printk("\nht6560b: PORT 0x3e6 ALREADY IN USE\n");
+       } else {
+               if (try_to_init_ht6560b()) {
+                       request_region(0x3e6, 1, "ht6560b");
+                       ide_hwifs[0].chipset = ide_ht6560b;
+                       ide_hwifs[1].chipset = ide_ht6560b;
+                       ide_hwifs[0].selectproc = &qd6560b_selectproc;
+                       ide_hwifs[1].selectproc = &qd6560b_selectproc;
+                       ide_hwifs[0].tuneproc = &tune_ht6560b;
+                       ide_hwifs[1].tuneproc = &tune_ht6560b;
+                       ide_hwifs[0].serialized = 1;
+               }
+       }
+}
index ef8bf7fe498c6bde13dabd34477f44293835a61b..d53e19038ae1ff559bcb8ed3240894f76959c4ce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 5.25  Jan 11, 1996
+ *  linux/drivers/block/ide.c  Version 5.27  Feb  8, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
  *  Version 5.24       fix #if's for SUPPORT_CMD640
  *  Version 5.25       more touch-ups, fix cdrom resets, ...
  *                     cmd640.c now configs/compiles separate from ide.c
+ *  Version 5.26       keep_settings now maintains the using_dma flag
+ *                     fix [EZD] remap message to only output at boot time
+ *                     fix "bad /dev/ entry" message to say hdc, not hdc0
+ *                     fix ide_xlate_1024() to respect user specified CHS
+ *                     use CHS from partn table if it looks translated
+ *                     re-merged flags chipset,vlb_32bit,vlb_sync into io_32bit
+ *                     keep track of interface chipset type, when known
+ *                     add generic PIO mode "tuneproc" mechanism
+ *                     fix cmd640_vlb option
+ *                     fix ht6560b support (was completely broken)
+ *                     umc8672.c now configures/compiles separate from ide.c
+ *                     move dtc2278 support to dtc2278.c
+ *                     move ht6560b support to ht6560b.c
+ *                     move qd6580  support to qd6580.c
+ *                     add  ali14xx support in ali14xx.c
+ * Version 5.27                add [no]autotune parameters to help cmd640
+ *                     move rz1000  support to rz1000.c
  *
- *  Driver compile-time options are in ide.h
+ *  Some additional driver compile-time options are in ide.h
  *
  *  To do, in likely order of completion:
- *     - make umc8672.c compile separately from ide.c
- *     - add ALI M1443/1445 chipset support from derekn@vw.ece.cmu.edu
- *     - add ioctls to get/set interface timings on various interfaces
- *     - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
+ *     - add Promise DC4030VL support from peterd@pnd-pc.demon.co.uk
  *     - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *     - add new HT6560B code from malafoss@snakemail.hut.fi
- */
+*/
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
 
 #include "ide.h"
 
-       ide_hwif_t      ide_hwifs[MAX_HWIFS];           /* hwif info */
 static ide_hwgroup_t   *irq_to_hwgroup [16];
 static const byte      ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
 
 static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168};
 static const byte      default_irqs[MAX_HWIFS]     = {14, 15, 11, 10};
-static int             disallow_unmask = 0;    /* for buggy hardware */
+       int             ide_disallow_unmask = 0;        /* for buggy hardware */
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
@@ -303,6 +315,7 @@ static void init_ide_data (void)
                ide_hwif_t *hwif = &ide_hwifs[h];
 
                /* fill in any non-zero initial values */
+               hwif->index     = h;
                hwif->noprobe   = (h > 1);
                hwif->io_base   = default_io_base[h];
                hwif->ctl_port  = hwif->io_base ? hwif->io_base+0x206 : 0x000;
@@ -357,10 +370,11 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
        unsigned short io_base  = HWIF(drive)->io_base;
        unsigned short data_reg = io_base+IDE_DATA_OFFSET;
+       byte io_32bit = drive->io_32bit;
 
-       if (drive->vlb_32bit) {
+       if (io_32bit) {
 #ifdef VLB_SYNC
-               if (drive->vlb_sync) {
+               if (io_32bit & 2) {
                        cli();
                        do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
                        insl(data_reg, buffer, wcount);
@@ -380,10 +394,11 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
        unsigned short io_base  = HWIF(drive)->io_base;
        unsigned short data_reg = io_base+IDE_DATA_OFFSET;
+       byte io_32bit = drive->io_32bit;
 
-       if (drive->vlb_32bit) {
+       if (io_32bit) {
 #ifdef VLB_SYNC
-               if (drive->vlb_sync) {
+               if (io_32bit & 2) {
                        cli();
                        do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
                        outsl(data_reg, buffer, wcount);
@@ -396,50 +411,6 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
                outsw(data_reg, buffer, wcount<<1);
 }
 
-#if SUPPORT_HT6560B
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- *
- * Apparently, systems with multiple CMD640 chips may need something similar..
- *
- * This algorithm courtesy of malafoss@snakemail.hut.fi
- *
- * At least one user has reported that this code can confuse the floppy
- * controller and/or driver -- perhaps this should be changed to use
- * a read-modify-write sequence, so as not to disturb other bits in the reg?
- */
-
-void ide_hwif_select (ide_hwif_t *hwif)
-{
-       static byte current_select = 0;
-
-       if (hwif->select != current_select) {
-               byte t;
-               unsigned long flags;
-               save_flags (flags);
-               cli();
-               current_select = hwif->select;
-               (void) inb(0x3e6);
-               (void) inb(0x3e6);
-               (void) inb(0x3e6);
-               /*
-                * Avoid clobbering existing bits at 0x3e6:
-                *      bit5 (0x20) - disables fast interface speed
-                *      bit0 (0x01) - enables secondary interface
-                *      we don't touch any other bits
-                */
-               t = inb(0x3e6);
-               t &= (~0x21);
-               t |= (current_select & 0x21);
-               outb(t,0x3e6);
-               restore_flags (flags);
-       }
-}
-#endif /* SUPPORT_HT6560B */
-
 /*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
@@ -713,12 +684,13 @@ static void do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
         */
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *rdrive = &hwif->drives[unit];
+               rdrive->special.all = 0;
                rdrive->special.b.set_geometry = 1;
                rdrive->special.b.recalibrate  = 1;
-               rdrive->special.b.set_multmode = 0;
                if (OK_TO_RESET_CONTROLLER)
                        rdrive->mult_count = 0;
                if (!rdrive->keep_settings) {
+                       rdrive->using_dma = 0;
                        rdrive->mult_req = 0;
                        rdrive->unmask = 0;
                }
@@ -900,14 +872,6 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat)
        if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
                rq->errors |= ERROR_RESET;      /* Mmmm.. timing problem */
 
-#ifdef CONFIG_BLK_DEV_TRITON
-       if (rq->errors > 3 && drive->using_dma) {       /* DMA troubles? */
-               drive->using_dma = 0;
-               printk("%s: DMA disabled\n", drive->name);
-               --rq->errors;
-               return;
-       }
-#endif /* CONFIG_BLK_DEV_TRITON */
        if (rq->errors >= ERROR_MAX)
                ide_end_request(0, HWGROUP(drive));
        else {
@@ -1035,7 +999,7 @@ static void multwrite (ide_drive_t *drive)
 }
 
 /*
- * write_intr() is the handler for disk multwrite interrupts
+ * multwrite_intr() is the handler for disk multwrite interrupts
  */
 static void multwrite_intr (ide_drive_t *drive)
 {
@@ -1134,12 +1098,12 @@ static void drive_cmd_intr (ide_drive_t *drive)
 
 /*
  * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- * commands to a drive.  It used to do much more, but has been scaled back
- * in recent updates, and could be completely eliminated with a bit more effort.
+ * commands to a drive.  It used to do much more, but has been scaled back.
  */
 static inline void do_special (ide_drive_t *drive)
 {
        special_t *s = &drive->special;
+next:
 #ifdef DEBUG
        printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
@@ -1157,6 +1121,12 @@ static inline void do_special (ide_drive_t *drive)
                if (drive->media == ide_disk) {
                        ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
                }
+       } else if (s->b.set_pio) {
+               ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+               s->b.set_pio = 0;
+               if (tuneproc != NULL)
+                       tuneproc(drive, drive->pio_req);
+               goto next;
        } else if (s->b.set_multmode) {
                s->b.set_multmode = 0;
                if (drive->media == ide_disk) {
@@ -1342,19 +1312,17 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq)
        }
        block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
 #if FAKE_FDISK_FOR_EZDRIVE
-       if (block == 0 && drive->ezdrive) {
-               block = 1;
-               printk("%s: [EZD] accessing sector 1 in place of sector 0\n", drive->name);
-       }
+       if (block == 0 && drive->remap_0_to_1)
+               block = 1;  /* redirect MBR access to EZ-Drive partn table */
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
        ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
+#ifdef CONFIG_BLK_DEV_HT6560B
+       if (hwif->selectproc)
+               hwif->selectproc (drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
 #if (DISK_RECOVERY_TIME > 0)
        while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
-#if SUPPORT_HT6560B
-       if (hwif->select)
-               ide_hwif_select (hwif);
-#endif
 
 #ifdef CONFIG_BLK_DEV_IDETAPE
        POLL_HWIF_TAPE_DRIVE;   /* macro from ide-tape.h */
@@ -1377,7 +1345,6 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq)
                                ide_do_rw_cdrom (drive, block);
                                return;
 #endif /* CONFIG_BLK_DEV_IDECD */
-
 #ifdef CONFIG_BLK_DEV_IDETAPE
                        case ide_tape:
                                idetape_do_request (drive, rq, block);
@@ -1546,14 +1513,14 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
         */
        do {
                if (hwif->irq == irq) {
-#if SUPPORT_HT6560B
-                       if (hwif->select)
-                               ide_hwif_select (hwif);
-#endif
                        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                                ide_drive_t *drive = &hwif->drives[unit];
                                if (!drive->present)
                                        continue;
+#ifdef CONFIG_BLK_DEV_HT6560B
+                               if (hwif->selectproc)
+                                       hwif->selectproc (drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
                                if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT))
                                        (void) ide_dump_status(drive, "unexpected_intr", stat);
                                if ((stat & DRQ_STAT))
@@ -1561,6 +1528,10 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
                        }
                }
        } while ((hwif = hwif->next) != hwgroup->hwif);
+#ifdef CONFIG_BLK_DEV_HT6560B
+       if (hwif->selectproc)
+               hwif->selectproc (hwgroup->drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
 }
 
 /*
@@ -1607,8 +1578,7 @@ static ide_drive_t *get_info_ptr (kdev_t i_rdev)
                                if (drive->present)
                                        return drive;
                        } else if (major == IDE0_MAJOR && unit < 4) {
-                               printk("ide: probable bad entry for /dev/hd%c%d\n",
-                                'a' + unit, MINOR(i_rdev) & PARTN_MASK);
+                               printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit);
                                printk("ide: to fix it, run:  /usr/src/linux/drivers/block/MAKEDEV.ide\n");
                        }
                        break;
@@ -1889,8 +1859,8 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                case HDIO_GET_DMA:
                        return write_fs_long(arg, drive->using_dma);
 
-               case HDIO_GET_CHIPSET:
-                       return write_fs_long(arg, drive->chipset);
+               case HDIO_GET_32BIT:
+                       return write_fs_long(arg, drive->io_32bit);
 
                case HDIO_GET_MULTCOUNT:
                        return write_fs_long(arg, drive->mult_count);
@@ -1918,7 +1888,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                case HDIO_SET_NOWERR:
                        if (arg > 1)
                                return -EINVAL;
-               case HDIO_SET_CHIPSET:
+               case HDIO_SET_32BIT:
                        if (!suser())
                                return -EACCES;
                        if ((MINOR(inode->i_rdev) & PARTN_MASK))
@@ -1937,7 +1907,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                        drive->keep_settings = arg;
                                        break;
                                case HDIO_SET_UNMASKINTR:
-                                       if (arg && disallow_unmask) {
+                                       if (arg && ide_disallow_unmask) {
                                                restore_flags(flags);
                                                return -EPERM;
                                        }
@@ -1946,12 +1916,10 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                case HDIO_SET_NOWERR:
                                        drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
                                        break;
-                               case HDIO_SET_CHIPSET:
-                                       drive->chipset   = arg;
-                                       drive->vlb_32bit = (arg & 1);
-                                       drive->vlb_sync  = (arg & 2) >> 1;
+                               case HDIO_SET_32BIT:
+                                       drive->io_32bit = arg;
 #ifndef VLB_SYNC
-                                       if (drive->vlb_sync)
+                                       if (arg & 2)
                                                printk("%s: VLB_SYNC not supported by this kernel\n", drive->name);
 #endif
                                        break;
@@ -1997,6 +1965,19 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        }
                        return err;
                }
+               case HDIO_SET_PIO_MODE:
+                       if (!suser())
+                               return -EACCES;
+                       if (MINOR(inode->i_rdev) & PARTN_MASK)
+                               return -EINVAL;
+                       if (!HWIF(drive)->tuneproc)
+                               return -ENOSYS;
+                       save_flags(flags);
+                       cli();
+                       drive->pio_req = (int) arg;
+                       drive->special.b.set_pio = 1;
+                       restore_flags(flags);
+                       return 0;
 
                RO_IOCTLS(inode->i_rdev, arg);
 
@@ -2098,7 +2079,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                byte type = (id->config >> 8) & 0x1f;
                printk("%s: %s, ATAPI ", drive->name, id->model);
                switch (type) {
-                       case 0:                         /* Early cdrom models used zero */
+                       case 0:         /* Early cdrom models used zero */
                        case 5:
 #ifdef CONFIG_BLK_DEV_IDECD
                                printk ("CDROM drive\n");
@@ -2128,9 +2109,11 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                                break;
 #endif /* CONFIG_BLK_DEV_IDETAPE */
                        default:
+                               drive->present = 0;
                                printk("Type %d - Unknown device\n", type);
                                return;
                }
+               drive->present = 0;
                printk("- not supported by this kernel\n");
                return;
        }
@@ -2208,17 +2191,12 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                        printk(", DMA");
        }
        printk("\n");
-#ifdef CONFIG_BLK_DEV_CMD640
-       {
-               extern void cmd640_tune_drive (ide_drive_t *);
-               cmd640_tune_drive(drive);       /* but can we tune a fish? */
-       }
-#endif
 }
 
 /*
  * Delay for *at least* 10ms.  As we don't know how much time is left
  * until the next tick occurs, we wait an extra tick to be safe.
+ * This is used only during the probing/polling for drives at boot time.
  */
 static void delay_10ms (void)
 {
@@ -2271,7 +2249,12 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
        if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
                cli();                  /* some systems need this */
                do_identify(drive, cmd); /* drive returned ID */
-               rc = 0;                 /* success */
+               if (drive->present && (drive->media == ide_disk || drive->media == ide_cdrom)) {
+                       ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+                       if (tuneproc != NULL && drive->autotune == 1)
+                               tuneproc(drive, 255);   /* auto-tune PIO mode */
+               }
+               rc = 0;                 /* drive responded with ID */
        } else
                rc = 2;                 /* drive refused ID */
        if (!HWIF(drive)->irq) {
@@ -2314,10 +2297,10 @@ static int do_probe (ide_drive_t *drive, byte cmd)
                drive->name, drive->present, drive->media,
                (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-#if SUPPORT_HT6560B
-       if (HWIF(drive)->select)
-               ide_hwif_select (HWIF(drive));
-#endif
+#ifdef CONFIG_BLK_DEV_HT6560B
+       if (HWIF(drive)->selectproc)
+               HWIF(drive)->selectproc (drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
        OUT_BYTE(drive->select.all,IDE_SELECT_REG);     /* select target drive */
        delay_10ms();                           /* wait for BUSY_STAT */
        if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
@@ -2435,99 +2418,6 @@ static void probe_for_drives (ide_hwif_t *hwif)
        }
 }
 
-#if SUPPORT_DTC2278
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * From: mlord@bnr.ca -- this chipset is now forced to use the "serialize" feature,
- * which hopefully will make it more reliable to use.. maybe it has the same bugs
- * as the CMD640B and RZ1000 ??
- */
-
-#if SET_DTC2278_MODE4
-static void sub22 (char b, char c)
-{
-       int i;
-
-       for(i = 0; i < 3; ++i) {
-               inb(0x3f6);
-               outb_p(b,0xb0);
-               inb(0x3f6);
-               outb_p(c,0xb4);
-               inb(0x3f6);
-               if(inb(0xb4) == c) {
-                       outb_p(7,0xb0);
-                       inb(0x3f6);
-                       return; /* success */
-               }
-       }
-}
-#endif /* SET_DTC2278_MODE4 */
-
-static void init_dtc2278 (void)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-#if SET_DTC2278_MODE4
-       /*
-        * This enables PIO mode4 (3?) on the first interface
-        */
-       sub22(1,0xc3);
-       sub22(0,0xa0);
-#endif /* SET_DTC2278_MODE4 */
-       /*
-        * This enables the second interface
-        */
-       outb_p(4,0xb0);
-       inb(0x3f6);
-       outb_p(0x20,0xb4);
-       inb(0x3f6);
-       restore_flags(flags);
-}
-#endif /* SUPPORT_DTC2278 */
-
-#ifdef SUPPORT_QD6580
-/*
- * QDI QD6580 EIDE controller fast support by Colten Edwards.
- * no net access but I can be reached at pje120@cs.usask.ca
- *
- * I suppose that a IOCTL could be used for this and other
- * cards like it to modify the speed using hdparm.  Someday..
- */
-static void init_qd6580 (void)
-{
-       unsigned long flags;
-
-       /* looks like   0x4f is fast
-        *              0x3f is medium
-        *              0x2f is slower
-        *              0x1f is slower yet
-        *              ports are 0xb0 0xb2 and 0xb3
-        */
-
-       save_flags(flags);
-       cli();
-       outb_p(0x8d,0xb0);
-       outb_p(0x0 ,0xb2);
-       outb_p(0x4f,0xb3);      /* select "fast" 0x4f */
-       inb(0x3f6);
-       restore_flags(flags);
-}
-#endif /* SUPPORT_QD6580 */
-
-#ifdef SUPPORT_UMC8672
-#include "umc8672.c"   /* until we tidy up the interface some more */
-#endif
-
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -2602,6 +2492,12 @@ static int match_parm (char *s, const char *keywords[], int vals[], int max_vals
  * "hdx=nowerr"                : ignore the WRERR_STAT bit on this drive
  * "hdx=cdrom"         : drive is present, and is a cdrom drive
  * "hdx=cyl,head,sect" : disk drive is present, with specified geometry
+ * "hdx=autotune"      : driver will attempt to tune interface speed
+ *                             to the fastest PIO mode supported,
+ *                             if possible for this drive only.
+ *                             Not fully supported by all chipset types,
+ *                             and quite likely to cause trouble with
+ *                             older/odd IDE drives.
  *
  * "idex=noprobe"      : do not attempt to access/use this interface
  * "idex=base"         : probe for an interface at the addr specified,
@@ -2609,24 +2505,31 @@ static int match_parm (char *s, const char *keywords[], int vals[], int max_vals
  *                             and "ctl" is assumed to be "base"+0x206
  * "idex=base,ctl"     : specify both base and ctl
  * "idex=base,ctl,irq" : specify base, ctl, and irq number
+ * "idex=autotune"     : driver will attempt to tune interface speed
+ *                             to the fastest PIO mode supported,
+ *                             for all drives on this interface.
+ *                             Not fully supported by all chipset types,
+ *                             and quite likely to cause trouble with
+ *                             older/odd IDE drives.
+ * "idex=noautotune"   : driver will NOT attempt to tune interface speed
+ *                             This is the default for most chipsets,
+ *                             except the cmd640.
  *
- * The following two are valid ONLY on ide0 or ide1,
+ * The following two are valid ONLY on ide0,
  * and the defaults for the base,ctl ports must not be altered.
  *
- * "idex=serialize"    : do not overlap operations on ide0 and ide1.
- * "idex=dtc2278"      : enables use of DTC2278 secondary i/f
- * "idex=ht6560b"      : enables use of HT6560B secondary i/f
- * "idex=cmd640_vlb"   : required for VLB cards with the CMD640 chip
+ * "ide0=serialize"    : do not overlap operations on ide0 and ide1.
+ * "ide0=dtc2278"      : probe/support DTC2278 interface
+ * "ide0=ht6560b"      : probe/support HT6560B interface
+ * "ide0=cmd640_vlb"   : *REQUIRED* for VLB cards with the CMD640 chip
  *                       (not for PCI -- automatically detected)
- *
- * This option is valid ONLY on ide0, and the defaults for the base,ctl ports
- * must not be altered.
- *
- * "ide0=qd6580"       : select "fast" interface speed on a qd6580 interface
+ * "ide0=qd6580"       : probe/support qd6580 interface
+ * "ide0=ali14xx"      : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
+ * "ide0=umc8672"      : probe/support umc8672 chipsets
  */
 void ide_setup (char *s)
 {
-       int vals[3];
+       int i, vals[3];
        ide_hwif_t *hwif;
        ide_drive_t *drive;
        unsigned int hw, unit;
@@ -2640,7 +2543,8 @@ void ide_setup (char *s)
         * Look for drive options:  "hdx="
         */
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
-               const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize", NULL};
+               const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize",
+                                               "autotune", "noautotune", NULL};
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
                unit = unit % MAX_DRIVES;
@@ -2662,12 +2566,19 @@ void ide_setup (char *s)
                        case -4: /* "serialize" */
                                printk(" -- USE \"ide%c=serialize\" INSTEAD", '0'+hw);
                                goto do_serialize;
+                       case -5: /* "autotune" */
+                               drive->autotune = 1;
+                               goto done;
+                       case -6: /* "noautotune" */
+                               drive->autotune = 2;
+                               goto done;
                        case 3: /* cyl,head,sect */
                                drive->media    = ide_disk;
                                drive->cyl      = drive->bios_cyl  = vals[0];
                                drive->head     = drive->bios_head = vals[1];
                                drive->sect     = drive->bios_sect = vals[2];
                                drive->present  = 1;
+                               drive->forced_geom = 1;
                                hwif->noprobe = 0;
                                goto done;
                        default:
@@ -2678,69 +2589,97 @@ void ide_setup (char *s)
         * Look for interface options:  "idex="
         */
        if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) {
-               const char *ide_words[] = {"noprobe", "serialize", "dtc2278", "ht6560b",
-                                       "cmd640_vlb", "qd6580", "umc8672", NULL};
+               /*
+                * Be VERY CAREFUL changing this: note hardcoded indexes below
+                */
+               const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune",
+                       "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", NULL};
                hw = s[3] - '0';
                hwif = &ide_hwifs[hw];
+               i = match_parm(&s[4], ide_words, vals, 3);
 
-               switch (match_parm(&s[4], ide_words, vals, 3)) {
-#if SUPPORT_UMC8672
-                       case -7: /* "umc8672" */
-                               if (hw != 0) goto bad_hwif;
+               /*
+                * Cryptic check to ensure chipset not already set for hwif:
+                */
+               if (i != -1 && i != -2) {
+                       if (hwif->chipset != ide_unknown)
+                               goto bad_option;
+                       if (i < 0 && ide_hwifs[1].chipset != ide_unknown)
+                               goto bad_option;
+               }
+               /*
+                * Interface keywords work only for ide0:
+                */
+               if (i <= -6 && hw != 0)
+                       goto bad_hwif;
+
+               switch (i) {
+#ifdef CONFIG_BLK_DEV_ALI14XX
+                       case -10: /* "ali14xx" */
+                       {
+                               extern void init_ali14xx (void);
+                               init_ali14xx();
+                               goto done;
+                       }
+#endif /* CONFIG_BLK_DEV_ALI14XX */
+#ifdef CONFIG_BLK_DEV_UMC8672
+                       case -9: /* "umc8672" */
+                       {
+                               extern void init_umc8672 (void);
                                init_umc8672();
                                goto done;
-#endif /* SUPPORT_UMC8672 */
-#if SUPPORT_QD6580
-                       case -6: /* "qd6580" */
-                               if (hw != 0) goto bad_hwif;
-                               init_qd6580();
+                       }
+#endif /* CONFIG_BLK_DEV_UMC8672 */
+#ifdef CONFIG_BLK_DEV_DTC2278
+                       case -8: /* "dtc2278" */
+                       {
+                               extern void init_dtc2278 (void);
+                               init_dtc2278();
                                goto done;
-#endif /* SUPPORT_QD6580 */
+                       }
+#endif /* CONFIG_BLK_DEV_DTC2278 */
 #ifdef CONFIG_BLK_DEV_CMD640
-                       case -5: /* "cmd640_vlb" */
-                               {
-                               extern int cmd640_vlb;
-                               if (hw > 1) goto bad_hwif;
-                                       cmd640_vlb = 1;
-                               }
-                               break;
+                       case -7: /* "cmd640_vlb" */
+                       {
+                               extern int cmd640_vlb; /* flag for cmd640.c */
+                               cmd640_vlb = 1;
+                               goto done;
+                       }
 #endif /* CONFIG_BLK_DEV_CMD640 */
-#if SUPPORT_HT6560B
-                       case -4: /* "ht6560b" */
-                               if (hw > 1) goto bad_hwif;
-                               /*
-                                * Using 0x1c and 0x1d apparently selects a
-                                * faster interface speed than 0x3c and 0x3d.
-                                * (bit5 (0x20) selects fast speed when set)
-                                * (bit0 (0x01) selects second interface)
-                                *
-                                * Need to set these per-drive, rather than
-                                * per-hwif, and also add an ioctl to select
-                                * between them.
-                                */
-                               if (check_region(0x3e6,1)) {
-                                       printk(" -- HT6560 PORT 0x3e6 ALREADY IN USE");
-                                       goto done;
-                               }
-                               request_region(0x3e6, 1, hwif->name);
-                               ide_hwifs[0].select = 0x1c;
-                               ide_hwifs[1].select = 0x3d;
-                               goto do_serialize;
-#endif /* SUPPORT_HT6560B */
-#if SUPPORT_DTC2278
-                       case -3: /* "dtc2278" */
-                               if (hw > 1) goto bad_hwif;
-                               init_dtc2278();
-                               goto do_serialize;
-#endif /* SUPPORT_DTC2278 */
+#ifdef CONFIG_BLK_DEV_HT6560B
+                       case -6: /* "ht6560b" */
+                       {
+                               extern void init_ht6560b (void);
+                               init_ht6560b();
+                               goto done;
+                       }
+#endif /* CONFIG_BLK_DEV_HT6560B */
+#if CONFIG_BLK_DEV_QD6580
+                       case -5: /* "qd6580" (no secondary i/f) */
+                       {
+                               extern void init_qd6580 (void);
+                               init_qd6580();
+                               goto done;
+                       }
+#endif /* CONFIG_BLK_DEV_QD6580 */
+                       case -4: /* "noautotune" */
+                               hwif->drives[0].autotune = 2;
+                               hwif->drives[1].autotune = 2;
+                               goto done;
+                       case -3: /* "autotune" */
+                               hwif->drives[0].autotune = 1;
+                               hwif->drives[1].autotune = 1;
+                               goto done;
                        case -2: /* "serialize" */
                        do_serialize:
                                if (hw > 1) goto bad_hwif;
                                ide_hwifs[0].serialized = 1;
                                goto done;
+
                        case -1: /* "noprobe" */
                                hwif->noprobe = 1;
                                goto done;
+
                        case 1: /* base */
                                vals[1] = vals[0] + 0x206; /* default ctl */
                        case 2: /* base,ctl */
@@ -2749,8 +2688,14 @@ void ide_setup (char *s)
                                hwif->io_base  = vals[0];
                                hwif->ctl_port = vals[1];
                                hwif->irq      = vals[2];
-                               hwif->noprobe = 0;
+                               hwif->noprobe  = 0;
+                               hwif->chipset  = ide_generic;
                                goto done;
+
+                       case 0: goto bad_option;
+                       default:
+                               printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
+                               return;
                }
        }
 bad_option:
@@ -2764,19 +2709,35 @@ done:
 
 /*
  * This routine is called from the partition-table code in genhd.c
- * to "convert" a drive to a logical geometry with fewer than 1024 cyls
- * It mimics the method used by Ontrack Disk Manager.
+ * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
+ *
+ * The second parameter, "xparm", determines exactly how the translation 
+ * will be handled:
+ *              0 = convert to CHS with fewer than 1024 cyls
+ *                     using the same method as Ontrack DiskManager.
+ *              1 = same as "0", plus offset everything by 63 sectors.
+ *             -1 = similar to "0", plus redirect sector 0 to sector 1.
+ *             >1 = convert to a CHS geometry with "xparm" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not 
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
  */
-int ide_xlate_1024 (kdev_t i_rdev, int offset, const char *msg)
+int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
 {
        ide_drive_t *drive;
        static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
        const byte *heads = head_vals;
        unsigned long tracks;
 
-       if ((drive = get_info_ptr(i_rdev)) == NULL)
+       if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom)
                return 0;
 
+       if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63)
+               return 0;               /* we already have a translation */
+
+       printk("%s ", msg);
+
        if (drive->id) {
                drive->cyl  = drive->id->cyls;
                drive->head = drive->id->heads;
@@ -2789,25 +2750,31 @@ int ide_xlate_1024 (kdev_t i_rdev, int offset, const char *msg)
 
        tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
        drive->bios_sect = 63;
-       while (drive->bios_cyl >= 1024) {
-               drive->bios_head = *heads;
+       if (xparm > 1) {
+               drive->bios_head = xparm;
                drive->bios_cyl = tracks / drive->bios_head;
-               if (0 == *++heads)
-                       break;
-       }
-       if (offset) {
+       } else {
+               while (drive->bios_cyl >= 1024) {
+                       drive->bios_head = *heads;
+                       drive->bios_cyl = tracks / drive->bios_head;
+                       if (0 == *++heads)
+                               break;
+               }
 #if FAKE_FDISK_FOR_EZDRIVE
-               if (offset == -1)
-                       drive->ezdrive = 1;
-               else
+               if (xparm == -1) {
+                       drive->remap_0_to_1 = 1;
+                       msg = "0->1";
+               } else
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
-               {
+               if (xparm == 1) {
                        drive->sect0 = 63;
                        drive->bios_cyl = (tracks - 1) / drive->bios_head;
+                       msg = "+63";
                }
+               printk("[remap %s] ", msg);
        }
        drive->part[0].nr_sects = current_capacity(drive);
-       printk("%s [%d/%d/%d]", msg, drive->bios_cyl, drive->bios_head, drive->bios_sect);
+       printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
        return 1;
 }
 
@@ -2940,37 +2907,7 @@ static struct file_operations ide_fops = {
 };
 
 #ifdef CONFIG_PCI
-
-#if SUPPORT_RZ1000
-
-static void ide_pci_access_error (int rc)
-{
-       printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
-}
-
-static void init_rz1000 (byte bus, byte fn)
-{
-       int rc;
-       unsigned short reg;
-
-       printk("ide: buggy RZ1000 interface: ");
-       if ((rc = pcibios_read_config_word (bus, fn, PCI_COMMAND, &reg))) {
-               ide_pci_access_error (rc);
-       } else if (!(reg & 1)) {
-               printk("not enabled\n");
-       } else {
-               if ((rc = pcibios_read_config_word(bus, fn, 0x40, &reg))
-                || (rc =  pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff)))
-               {
-                       ide_pci_access_error (rc);
-                       ide_hwifs[0].serialized = 1;
-                       disallow_unmask = 1;
-                       printk("serialized, disabled unmasking\n");
-               } else
-                       printk("disabled read-ahead\n");
-       }
-}
-#endif /* SUPPORT_RZ1000 */
+#if defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON)
 
 typedef void (ide_pci_init_proc_t)(byte, byte);
 
@@ -2992,27 +2929,44 @@ static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci
        restore_flags(flags);
 }
 
+#endif /* defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON) */
+#endif /* CONFIG_PCI */
+
 /*
  * ide_init_pci() finds/initializes "known" PCI IDE interfaces
  *
  * This routine should ideally be using pcibios_find_class() to find
  * all IDE interfaces, but that function causes some systems to "go weird".
  */
-static void ide_init_pci (void)
+static void probe_for_hwifs (void)
 {
-#if SUPPORT_RZ1000
-       ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0);
-#endif
-#ifdef CONFIG_BLK_DEV_TRITON
+#ifdef CONFIG_PCI
        /*
-        * Apparently the BIOS32 services on Intel motherboards are buggy,
-        * and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us.
-        * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0, and then add 1.
+        * Find/initialize PCI IDE interfaces
         */
-       ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
+       if (pcibios_present()) {
+#ifdef CONFIG_BLK_DEV_RZ1000
+               ide_pci_init_proc_t init_rz1000;
+               ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0);
+#endif /* CONFIG_BLK_DEV_RZ1000 */
+#ifdef CONFIG_BLK_DEV_TRITON
+               /*
+                * Apparently the BIOS32 services on Intel motherboards are
+                * buggy and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us.
+                * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0,
+                * and then add 1.
+                */
+               ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
+#endif /* CONFIG_BLK_DEV_TRITON */
+       }
+#endif /* CONFIG_PCI */
+#ifdef CONFIG_BLK_DEV_CMD640
+       {
+               extern void ide_probe_for_cmd640x (void);
+               ide_probe_for_cmd640x();
+       }
 #endif
 }
-#endif /* CONFIG_PCI */
 
 /*
  * This is gets invoked once during initialization, to set *everything* up
@@ -3023,22 +2977,9 @@ int ide_init (void)
 
        init_ide_data ();
        /*
-        * First, we determine what hardware is present
-        */
-
-#ifdef CONFIG_PCI
-       /*
-        * Find/initialize PCI IDE interfaces
+        * Probe for special "known" interface chipsets
         */
-       if (pcibios_present())
-               ide_init_pci ();
-#endif /* CONFIG_PCI */
-#ifdef CONFIG_BLK_DEV_CMD640
-       {
-               extern void ide_probe_for_cmd640x (void);
-               ide_probe_for_cmd640x();
-       }
-#endif
+       probe_for_hwifs ();
 
        /*
         * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
index 65db50d8f0604c6791dc1eeb577fd673dcd96d7e..e8c3834d15005c6b2328ee1b88bf9f8aeb545acc 100644 (file)
 #ifndef FAKE_FDISK_FOR_EZDRIVE         /* 1 to help linux fdisk with EZDRIVE */
 #define FAKE_FDISK_FOR_EZDRIVE         1       /* 0 to reduce kernel size */
 #endif
-#ifndef SUPPORT_RZ1000                 /* 1 to support RZ1000 chipset */
-#define SUPPORT_RZ1000         1       /* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_UMC8672                        /* 1 to support UMC8672 chipset */
-#define SUPPORT_UMC8672                1       /* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_HT6560B                        /* 1 to support HT6560B chipset */
-#define SUPPORT_HT6560B                1       /* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_QD6580                 /* 1 to support QD6580 chipset */
-#define SUPPORT_QD6580         1       /* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_DTC2278                        /* 1 to support DTC2278 chipset */
-#define SUPPORT_DTC2278                1       /* 0 to reduce kernel size */
-#ifndef SET_DTC2278_MODE4
-#define SET_DTC2278_MODE4      0       /* 1 to init primary i/f for PIO mode4 */
-#endif
-#endif
 #ifndef FANCY_STATUS_DUMPS             /* 1 for human-readable drive errors */
 #define FANCY_STATUS_DUMPS     1       /* 0 to reduce kernel size */
 #endif
@@ -293,7 +275,8 @@ typedef union {
                unsigned set_geometry   : 1;    /* respecify drive geometry */
                unsigned recalibrate    : 1;    /* seek to cyl 0      */
                unsigned set_multmode   : 1;    /* set multmode count */
-               unsigned reserved       : 5;    /* unused */
+               unsigned set_pio        : 1;    /* set pio mode */
+               unsigned reserved       : 4;    /* unused */
                } b;
        } special_t;
 
@@ -310,26 +293,26 @@ typedef union {
 
 typedef struct ide_drive_s {
        special_t       special;        /* special action flags */
-#if FAKE_FDISK_FOR_EZDRIVE
-       unsigned ezdrive        : 1;    /* flag: partitioned with ezdrive */
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
        unsigned present        : 1;    /* drive is physically present */
        unsigned noprobe        : 1;    /* from:  hdx=noprobe */
        unsigned keep_settings  : 1;    /* restore settings after drive reset */
        unsigned busy           : 1;    /* currently doing revalidate_disk() */
-       unsigned vlb_32bit      : 1;    /* use 32bit in/out for data */
-       unsigned vlb_sync       : 1;    /* needed for some 32bit chip sets */
        unsigned removeable     : 1;    /* 1 if need to do check_media_change */
        unsigned using_dma      : 1;    /* disk is using dma for read/write */
+       unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
        unsigned unmask         : 1;    /* flag: okay to unmask other irqs */
+       unsigned autotune       : 2;    /* 1=autotune, 2=noautotune, 0=default */
+#if FAKE_FDISK_FOR_EZDRIVE
+       unsigned remap_0_to_1   : 1;    /* flag: partitioned with ezdrive */
+#endif /* FAKE_FDISK_FOR_EZDRIVE */
        ide_media_t     media;          /* disk, cdrom, tape */
        select_t        select;         /* basic drive/head select reg value */
-       void            *hwif;          /* actually (ide_hwif_t *) */
        byte            ctl;            /* "normal" value for IDE_CONTROL_REG */
        byte            ready_stat;     /* min status value for drive ready */
        byte            mult_count;     /* current multiple sector setting */
        byte            mult_req;       /* requested multiple sector setting */
-       byte            chipset;        /* interface chipset access method */
+       byte            pio_req;        /* requested multiple sector setting */
+       byte            io_32bit;       /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
        byte            bad_wstat;      /* used for ignoring WRERR_STAT */
        byte            sect0;          /* offset of first sector for DM6:DDO */
        byte            usage;          /* current "open()" count for drive */
@@ -339,27 +322,16 @@ typedef struct ide_drive_s {
        byte            bios_sect;      /* BIOS/fdisk/LILO sectors per track */
        unsigned short  bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
        unsigned short  cyl;            /* "real" number of cyls */
+       void              *hwif;        /* actually (ide_hwif_t *) */
        struct wait_queue *wqueue;      /* used to wait for drive in open() */
        struct hd_driveid *id;          /* drive model identification info */
        struct hd_struct  *part;        /* drive partition table */
        char            name[4];        /* drive name, such as "hda" */
 #ifdef CONFIG_BLK_DEV_IDECD
-       struct cdrom_info cdrom_info;   /* from ide-cd.c */
+       struct cdrom_info cdrom_info;   /* for ide-cd.c */
 #endif /* CONFIG_BLK_DEV_IDECD */
-
-#ifdef CONFIG_BLK_DEV_IDETAPE          /* ide-tape specific data */
-
-/*
- *     Most of our global data which we need to save even as we leave the
- *     driver due to an interrupt or a timer event is stored here.
- *
- *     Additional global variables which provide the link between the
- *     character device interface to this structure are defined in
- *     ide-tape.c
- */
-
-       idetape_tape_t tape;
-
+#ifdef CONFIG_BLK_DEV_IDETAPE
+       idetape_tape_t  tape;           /* for ide-tape.c */
 #endif /* CONFIG_BLK_DEV_IDETAPE */
 
        } ide_drive_t;
@@ -378,6 +350,35 @@ typedef struct ide_drive_s {
 typedef enum {ide_dma_read = 0, ide_dma_write = 1, ide_dma_abort = 2, ide_dma_check = 3} ide_dma_action_t;
 typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
 
+
+/*
+ * An ide_tuneproc_t() is used to set the speed of an IDE interface
+ * to a particular PIO mode.  The "byte" parameter is used
+ * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
+ * indicates that the interface driver should "auto-tune" the PIO mode
+ * according to the drive capabilities in drive->id;
+ *
+ * Not all interface types support tuning, and not all of those
+ * support all possible PIO settings.  They may silently ignore
+ * or round values as they see fit.
+ */
+typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
+
+/*
+ * This is used to provide HT6560B interface support.
+ * It will probably also be used by the DC4030VL driver.
+ */
+typedef void (ide_selectproc_t) (ide_drive_t *);
+
+/*
+ * hwif_chipset_t is used to keep track of the specific hardware
+ * chipset used by each IDE interface, if known.
+ */
+typedef enum { ide_unknown,    ide_generic,    ide_triton,
+               ide_cmd640,     ide_dtc2278,    ide_ali14xx,
+               ide_qd6580,     ide_umc8672,    ide_ht6560b }
+       hwif_chipset_t;
+
 typedef struct hwif_s {
        struct hwif_s   *next;          /* for linked-list in ide_hwgroup_t */
        void            *hwgroup;       /* actually (ide_hwgroup_t *) */
@@ -385,13 +386,18 @@ typedef struct hwif_s {
        unsigned short  ctl_port;       /* usually io_base+0x206 */
        ide_drive_t     drives[MAX_DRIVES];     /* drive info */
        struct gendisk  *gd;            /* gendisk structure */
+       ide_tuneproc_t  *tuneproc;      /* routine to tune PIO mode for drives */
+#ifdef CONFIG_BLK_DEV_HT6560B
+       ide_selectproc_t *selectproc;   /* tweaks hardware to select drive */
+#endif /* CONFIG_BLK_DEV_HT6560B */
        ide_dmaproc_t   *dmaproc;       /* dma read/write/abort routine */
        unsigned long   *dmatable;      /* dma physical region descriptor table */
        unsigned short  dma_base;       /* base addr for dma ports (triton) */
        byte            irq;            /* our irq number */
        byte            major;          /* our major number */
-       byte            select;         /* pri/sec hwif select for ht6560b */
        char            name[5];        /* name of interface, eg. "ide0" */
+       byte            index;          /* 0 for ide0; 1 for ide1; ... */
+       hwif_chipset_t  chipset;        /* sub-module for tuning.. */
        unsigned        noprobe : 1;    /* don't probe for this interface */
        unsigned        present : 1;    /* this interface exists */
        unsigned        serialized : 1; /* valid only for ide_hwifs[0] */
@@ -422,6 +428,19 @@ typedef struct hwgroup_s {
        unsigned long           poll_timeout;   /* timeout value during long polls */
        } ide_hwgroup_t;
 
+/*
+ * ide_hwifs[] is the master data structure used to keep track
+ * of just about everything in ide.c.  Whenever possible, routines
+ * should be using pointers to a drive (ide_drive_t *) or 
+ * pointers to a hwif (ide_hwif_t *), rather than indexing this
+ * structure directly (the allocation/layout may change!).
+ */
+#ifdef _IDE_C
+       ide_hwif_t      ide_hwifs[MAX_HWIFS];   /* master data repository */
+#else
+extern ide_hwif_t      ide_hwifs[];
+#endif
+
 /*
  * One final include file, which references some of the data/defns from above
  */
@@ -480,9 +499,22 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap);
 int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
 
 /*
- * This is called from genhd.c to correct DiskManager/EZ-Drive geometries
+ * This routine is called from the partition-table code in genhd.c
+ * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
+ *
+ * The second parameter, "xparm", determines exactly how the translation
+ * will be handled:
+ *              0 = convert to CHS with fewer than 1024 cyls
+ *                     using the same method as Ontrack DiskManager.
+ *              1 = same as "0", plus offset everything by 63 sectors.
+ *             -1 = similar to "0", plus redirect sector 0 to sector 1.
+ *             >1 = convert to a CHS geometry with "xparm" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
  */
-int ide_xlate_1024(kdev_t, int, const char *);
+int ide_xlate_1024 (kdev_t, int, const char *);
 
 /*
  * Start a reset operation for an IDE interface.
diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c
new file mode 100644 (file)
index 0000000..553cd77
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  linux/drivers/block/qd6580.c       Version 0.01  Feb 06, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ * QDI QD6580 EIDE controller fast support by Colten Edwards.
+ * No net access, but (maybe) can be reached at pje120@cs.usask.ca
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include "ide.h"
+
+/*
+ * Register 0xb3 looks like:
+ *     0x4f is fast            mode3 ?
+ *     0x3f is medium          mode2 ?
+ *     0x2f is slower          mode1 ?
+ *     0x1f is slower yet      mode0 ?
+ *     0x0f ???                ???
+ *
+ * Don't know whether this sets BOTH drives, or just the first drive.
+ * Don't know if there is a separate setting for the second drive.
+ *
+ * Feel free to patch this if you have one of these beasts
+ * and can work out the answers!
+ *
+ * I/O ports are 0xb0 0xb2 and 0xb3
+ */
+
+static void tune_qd6580 (ide_drive_t *drive, byte pio)
+{
+       unsigned long flags;
+
+       if (pio == 255)  {      /* auto-tune */
+               struct hd_driveid *id = drive->id;
+               pio = id->tPIO;
+               if ((id->field_valid & 0x02) && (id->eide_pio_modes & 0x03))
+                       pio = 3;
+       }
+       pio++;  /* is this correct? */
+
+       save_flags(flags);
+       cli();
+       outb_p(0x8d,0xb0);
+       outb_p(0x0 ,0xb2);
+       outb_p((pio<<4)|0x0f,0xb3);
+       inb(0x3f6);
+       restore_flags(flags);
+}
+
+void init_qd6580 (void)
+{
+       ide_hwifs[0].chipset = ide_qd6580;
+       ide_hwifs[0].tuneproc = &tune_qd6580;
+}
diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c
new file mode 100644 (file)
index 0000000..ca417c6
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  linux/drivers/block/rz1000.c       Version 0.02  Feb 08, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  mlord@bnr.ca (Mark Lord)
+ *
+ *  This file provides support for disabling the buggy read-ahead
+ *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ */
+
+#undef REALLY_SLOW_IO          /* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include "ide.h"
+
+static void ide_pci_access_error (int rc)
+{
+       printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
+}
+
+void init_rz1000 (byte bus, byte fn)
+{
+       int rc;
+       unsigned short reg;
+
+       printk("ide: buggy RZ1000 interface: ");
+       if ((rc = pcibios_read_config_word (bus, fn, PCI_COMMAND, &reg))) {
+               ide_pci_access_error (rc);
+       } else if (!(reg & 1)) {
+               printk("not enabled\n");
+       } else {
+               if ((rc = pcibios_read_config_word(bus, fn, 0x40, &reg))
+                || (rc =  pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff)))
+               {
+                       extern int ide_disallow_unmask;
+                       ide_disallow_unmask = 1;
+                       ide_hwifs[0].serialized = 1;
+                       ide_pci_access_error (rc);
+                       printk("serialized, disabled unmasking\n");
+               } else
+                       printk("disabled read-ahead\n");
+       }
+}
index 5c1d2ee3031dab6a73323b54561603708fba3fd4..fe0a6dae7aa59c6f1dc108bc9c1324d37e2ae513 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/triton.c       Version 1.05  Jan 11, 1996
+ *  linux/drivers/block/triton.c       Version 1.06  Feb 6, 1996
  *
  *  Copyright (c) 1995-1996  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -319,7 +319,7 @@ static void init_triton_dma (ide_hwif_t *hwif, unsigned short base)
        if (check_region(base, 8)) {
                printk(" -- ERROR, PORTS ALREADY IN USE");
        } else {
-               request_region(base, 8, hwif->name);
+               request_region(base, 8, "triton DMA");
                hwif->dma_base = base;
                if (!dmatable) {
                        /*
@@ -364,7 +364,6 @@ void ide_init_triton (byte bus, byte fn)
        int dma_enabled = 0;
        unsigned short bmiba, pcicmd;
        unsigned int timings;
-       extern ide_hwif_t ide_hwifs[];
 
        printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn);
        /*
@@ -409,12 +408,14 @@ void ide_init_triton (byte bus, byte fn)
                        time = timings & 0xffff;
                        if ((timings & 0x8000) == 0)    /* interface enabled? */
                                continue;
+                       hwif->chipset = ide_triton;
                        if (dma_enabled)
                                init_triton_dma(hwif, bmiba);
                } else if (hwif->io_base == 0x170) {
                        time = timings >> 16;
                        if ((timings & 0x8000) == 0)    /* interface enabled? */
                                continue;
+                       hwif->chipset = ide_triton;
                        if (dma_enabled)
                                init_triton_dma(hwif, bmiba + 8);
                } else
index be793053bd9458a6e2d62170d4e09baffe9c96cb..516a2bf85b4699fafcd2bcb5fac395219b100df0 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/umc8672.c      Version 0.01  Nov 16, 1995
+ *  linux/drivers/block/umc8672.c      Version 0.02  Feb 06, 1996
  *
- *  Copyright (C) 1995  Linus Torvalds & author (see below)
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
  */
 
 /*
@@ -13,6 +13,8 @@
  *  Version 0.01       Initial version, hacked out of ide.c,
  *                     and #include'd rather than compiled separately.
  *                     This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02       now configs/compiles separate from ide.c  -ml
  */
 
 /*
  * the results from the DOS speed test programm supplied from UMC. 11 is the 
  * highest speed (about PIO mode 3)
  */
+#undef REALLY_SLOW_IO          /* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include "ide.h"
 
 /*
  * The speeds will eventually become selectable using hdparm via ioctl's,
  * but for now they are coded here:
  */
-#define UMC_DRIVE0      11              /* DOS messured drive Speeds */
-#define UMC_DRIVE1      11              /* 0 - 11 allowed */
-#define UMC_DRIVE2      11              /* 11 = Highest Speed */
-#define UMC_DRIVE3      11              /* In case of crash reduce speed */
+#define UMC_DRIVE0      1              /* DOS measured drive speeds */
+#define UMC_DRIVE1      1              /* 0 to 11 allowed */
+#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
+#define UMC_DRIVE3      1              /* In case of crash reduce speed */
+
+static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const byte pio_to_umc [5] = {0,3,6,10,11};      /* rough guesses */
+
+/*       0    1    2    3    4    5    6    7    8    9    10   11      */
+static const byte speedtab [3][12] = {
+       {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+       {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+       {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
 
-void out_umc (char port,char wert)
+static void out_umc (char port,char wert)
 {
        outb_p (port,0x108);
        outb_p (wert,0x109);
 }
 
-byte in_umc (char port)
+static byte in_umc (char port)
 {
        outb_p (port,0x108);
        return inb_p (0x109);
 }
 
-void init_umc8672(void)
+static void umc_set_speeds (byte speeds[])
 {
-       int i,tmp;
-       int speed [4];
-/*      0    1    2    3    4    5    6    7    8    9    10   11      */
-       char speedtab [3][12] = {
-       {0xf ,0xb ,0x2 ,0x2 ,0x2 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 },
-       {0x3 ,0x2 ,0x2 ,0x2 ,0x2 ,0x2 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 },
-       {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+       int i, tmp;
+       unsigned long flags;
 
+       save_flags(flags);
        cli ();
        outb_p (0x5A,0x108); /* enable umc */
-       if (in_umc (0xd5) != 0xa0)
-       {
-               sti ();
-               printk ("UMC8672 not found\n");
-               return;  
-       }
-       speed[0] = UMC_DRIVE0;
-       speed[1] = UMC_DRIVE1;
-       speed[2] = UMC_DRIVE2;
-       speed[3] = UMC_DRIVE3;
-       for (i = 0;i < 4;i++)
-       {
-               if ((speed[i] < 0) || (speed[i] > 11))
-               {
-                       sti ();
-                       printk ("UMC 8672 drive speed out of range. Drive %d Speed %d\n",
-                               i, speed[i]);
-                       printk ("UMC support aborted\n");
-                       return; 
-               }
-       }
-       out_umc (0xd7,(speedtab[0][speed[2]] | (speedtab[0][speed[3]]<<4)));
-       out_umc (0xd6,(speedtab[0][speed[0]] | (speedtab[0][speed[1]]<<4)));
+
+       out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+       out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
        tmp = 0;
        for (i = 3; i >= 0; i--)
        {
-               tmp = (tmp << 2) | speedtab[1][speed[i]];
+               tmp = (tmp << 2) | speedtab[1][speeds[i]];
        }
        out_umc (0xdc,tmp);
        for (i = 0;i < 4; i++)
        {
-               out_umc (0xd0+i,speedtab[2][speed[i]]);
-               out_umc (0xd8+i,speedtab[2][speed[i]]);
+               out_umc (0xd0+i,speedtab[2][speeds[i]]);
+               out_umc (0xd8+i,speedtab[2][speeds[i]]);
        }
        outb_p (0xa5,0x108); /* disable umc */
-       sti ();
-       printk ("Speeds for UMC8672 \n");
-       for (i = 0;i < 4;i++)
-                printk ("Drive %d speed %d\n",i,speed[i]);
+       restore_flags(flags);
+
+       printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+               speeds[0], speeds[1], speeds[2], speeds[4]);
+}
+
+static void tune_umc (ide_drive_t *drive, byte pio)
+{
+       if (pio == 255)  {      /* auto-tune */
+               struct hd_driveid *id = drive->id;
+               pio = id->tPIO;
+               if (id->field_valid & 0x02) {
+                       if (id->eide_pio_modes & 0x01)
+                               pio = 3;
+                       if (id->eide_pio_modes & 0x02)
+                               pio = 4;
+               }
+       }
+       if (pio > 4)
+               pio = 4;
+       current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+       umc_set_speeds (current_speeds);
+}
+
+void init_umc8672 (void)       /* called from ide.c */
+{
+       unsigned long flags;
+
+       if (check_region(0x108, 2)) {
+               printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
+               return;
+       }
+       save_flags(flags);
+       cli ();
+       outb_p (0x5A,0x108); /* enable umc */
+       if (in_umc (0xd5) != 0xa0)
+       {
+               sti ();
+               printk ("umc8672: not found\n");
+               return;  
+       }
+       outb_p (0xa5,0x108); /* disable umc */
+       restore_flags(flags);
+
+       umc_set_speeds (current_speeds);
+
+       request_region(0x108, 2, "umc8672");
+       ide_hwifs[0].chipset = ide_umc8672;
+       ide_hwifs[1].chipset = ide_umc8672;
+       ide_hwifs[0].tuneproc = &tune_umc;
+       ide_hwifs[1].tuneproc = &tune_umc;
+
 }
index d10c6733746c391d047f4686b105084de2871930..41a8ef1710bf56cf94f4f1900d377f8a17aef5ad 100644 (file)
@@ -84,13 +84,17 @@ You can choose from two options:
     the vertical synchronization pulse (mode 1) or horizontal
     synchronization pulse (mode 2).  Mode 1 should work with most
     monitors, but the VESA spec allows mode 2, so it's included for
-    completeness.
+    completeness. You may set this blanking interval in minutes by
+    echoing the escape sequence 'ESC[9;interval]' to the terminal.
+    By default this interval is set to 10 minutes.
 
     If you use one of these modes, you can also set a second interval
-    by echoing the escape sequence ESC[10;interval] to the terminal.
+    by echoing the escape sequence 'ESC[14;interval]' to the terminal.
     The monitor will be turned off completely (mode 3) after being in
-    suspend mode for the specified interval.  The interval defaults to
-    60 minutes. An interval of 0 disables this feature.
+    suspend mode for the specified interval. An interval of 0 disables
+    this feature which is the default.
+
+    Both intervals may be set within the range of 0..60 minutes.
 
 (2) Setting vesa_blanking_mode to 3.
     If your monitor locally has an Off_Mode timer then you should not
@@ -108,6 +112,8 @@ sends the signal to enter Standby mode, you have the chance to interfere
 before the monitor powers down. Do not set a too short period, if you love
 your hardware :-)) .
 
+By default vesa_blanking_mode is set to 0, thus not using any power saving
+features.
 */
 
 #define seq_port_reg   (0x3c4)         /* Sequencer register select port */
index b056a2fc12d6d903c10e7ba077d79c708b4259cd..aeb7cb4ace922fb2bb659534de1c02b241761684 100644 (file)
@@ -5,6 +5,7 @@ tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'SLIP (serial line) support' CONFIG_SLIP
 if [ "$CONFIG_SLIP" != "n" ]; then
   bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
 fi
 tristate 'PPP (point-to-point) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
index af2ff6f74b34bd9c61fc647b80ff4174a0c91ccc..e5f54a72215022eddb9cc5aa7575f0a717ff0a91 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 
+#define LOOPBACK_MTU (PAGE_SIZE*7/8)
 
 static int loopback_xmit(struct sk_buff *skb, struct device *dev)
 {
@@ -99,6 +100,9 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
        skb->dev=dev;
        save_flags(flags);
        cli();
+#ifndef LOOPBACK_MUST_CHECKSUM
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+#endif
        netif_rx(skb);
        if(unlock)
                skb_device_unlock(skb);
@@ -127,14 +131,8 @@ static int loopback_open(struct device *dev)
 int loopback_init(struct device *dev)
 {
        int i;
-#if LINUS_EVER_SOLVES_THE_LARGE_ATOMIC_BUFFER_ISSUE
-       dev->mtu                = 7900;                 /* MTU                  */
-#else
-/*
- *     If Alpha uses 8K pages then I guess 7K would be good for it.
- */
-       dev->mtu                = 2000;                 /* Kept under 1 page    */
-#endif 
+
+       dev->mtu                = LOOPBACK_MTU;
        dev->tbusy              = 0;
        dev->hard_start_xmit    = loopback_xmit;
        dev->open               = NULL;
index b1c3579881763ff132bb1850d358351a06af385b..d2771cf2904e5f1a2a014de2f35183db015ba149 100644 (file)
  *                                     With MODULE-loading ``insmod'', user can
  *                                     issue parameter:   slip_maxdev=1024
  *                                     (Or how much he/she wants.. Default is 256)
- *
+ * *   Stanislav Voronyi       :       Slip line checking, with ideas taken
+ *                                     from multislip BSDI driver which was written
+ *                                     by Igor Chechik, RELCOM Corp. Only algorithms
+ *                                     have been ported to Linux SLIP driver.
  */
 
 #define SL_CHECK_TRANSMIT
@@ -81,9 +84,9 @@
 #endif
 
 #ifdef MODULE
-#define SLIP_VERSION    "0.8.3-NET3.019-NEWTTY-MODULAR"
+#define SLIP_VERSION    "0.8.4-NET3.019-NEWTTY-MODULAR"
 #else
-#define        SLIP_VERSION    "0.8.3-NET3.019-NEWTTY"
+#define        SLIP_VERSION    "0.8.4-NET3.019-NEWTTY"
 #endif
 
 
@@ -103,7 +106,10 @@ static void slip_unesc(struct slip *sl, unsigned char c);
 static int slip_esc6(unsigned char *p, unsigned char *d, int len);
 static void slip_unesc6(struct slip *sl, unsigned char c);
 #endif
-
+#ifdef CONFIG_SLIP_SMART
+static void sl_keepalive(unsigned long sls);
+static void sl_outfill(unsigned long sls);
+#endif
 
 /* Find a free SLIP channel, and link in this `tty' line. */
 static inline struct slip *
@@ -442,6 +448,8 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
 #endif
        sl->xleft = count - actual;
        sl->xhead = sl->xbuff + actual;
+       /* VSV */
+       clear_bit(SLF_OUTWAIT, &sl->flags);     /* reset outfill flag */
 }
 
 /*
@@ -457,13 +465,13 @@ static void slip_write_wakeup(struct tty_struct *tty)
        if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) {
                return;
        }
-
        if (sl->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
                sl->tx_packets++;
                tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               sl_unlock(sl);
+               if (test_bit(0, (void *) &sl->dev->tbusy)) /* add by VSV */
+                       sl_unlock(sl);
                mark_bh(NET_BH);
                return;
        }
@@ -620,7 +628,16 @@ sl_open(struct device *dev)
        sl->xbits    = 0;
 #endif
        sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
-
+#ifdef CONFIG_SLIP_SMART       
+       sl->keepalive=0;                /* no keepalive by default = VSV */
+       init_timer(&sl->keepalive_timer);       /* initialize timer_list struct */
+       sl->keepalive_timer.data=(unsigned long)sl;
+       sl->keepalive_timer.function=sl_keepalive;      
+       sl->outfill=0;                  /* & outfill too */
+       init_timer(&sl->outfill_timer);
+       sl->outfill_timer.data=(unsigned long)sl;
+       sl->outfill_timer.function=sl_outfill;
+#endif
        /* Needed because address '0' is special */
        if (dev->pa_addr == 0)  {
                dev->pa_addr=ntohl(0xC0A80001);
@@ -873,6 +890,10 @@ slip_unesc(struct slip *sl, unsigned char s)
 
        switch(s) {
         case END:
+               /* drop keeptest bit = VSV */
+               if (test_bit(SLF_KEEPTEST, &sl->flags))
+                       clear_bit(SLF_KEEPTEST, &sl->flags);
+
                if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
                        sl_bump(sl);
                }
@@ -954,6 +975,10 @@ slip_unesc6(struct slip *sl, unsigned char s)
        unsigned char c;
 
        if (s == 0x70) {
+               /* drop keeptest bit = VSV */
+               if (test_bit(SLF_KEEPTEST, &sl->flags))
+                       clear_bit(SLF_KEEPTEST, &sl->flags);
+
                if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
                        sl_bump(sl);
                }
@@ -1086,6 +1111,60 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
                return -EINVAL;
 #endif
 
+#ifdef CONFIG_SLIP_SMART
+       /* VSV changes start here */
+        case SIOCSKEEPALIVE:
+                if (sl->keepalive)
+                        del_timer (&sl->keepalive_timer);
+               err = verify_area(VERIFY_READ, arg, sizeof(int));
+               if (err)  {
+                       return -err;
+               }
+               tmp = get_user((int *)arg);
+                if (tmp > 255) /* max for unchar */
+                       return -EINVAL; 
+               if ((sl->keepalive = (unchar) tmp) != 0) {
+                       sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
+                       add_timer(&sl->keepalive_timer);
+                       set_bit(SLF_KEEPTEST, &sl->flags);
+                }
+               return 0;
+
+        case SIOCGKEEPALIVE:
+               err = verify_area(VERIFY_WRITE, arg, sizeof(int));
+               if (err)  {
+                       return -err;
+               }
+               put_user(sl->keepalive, (int *)arg);
+               return 0;
+
+        case SIOCSOUTFILL:
+                if (sl->outfill)
+                         (void)del_timer (&sl->outfill_timer);
+               err = verify_area(VERIFY_READ, arg, sizeof(int));
+               if (err)  {
+                       return -err;
+               }
+               tmp = get_user((int *)arg);
+                if (tmp > 255) /* max for unchar */
+                       return -EINVAL; 
+                if ((sl->outfill = (unchar) tmp) != 0){
+                       sl->outfill_timer.expires=jiffies+sl->outfill*HZ;
+                       add_timer(&sl->outfill_timer);
+                       set_bit(SLF_OUTWAIT, &sl->flags);
+               }
+                return 0;
+
+        case SIOCGOUTFILL:
+               err = verify_area(VERIFY_WRITE, arg, sizeof(int));
+               if (err)  {
+                       return -err;
+               }
+               put_user(sl->outfill, (int *)arg);
+               return 0;
+       /* VSV changes end */
+#endif 
+
        /* Allow stty to read, but not set, the serial port */
        case TCGETS:
        case TCGETA:
@@ -1108,8 +1187,7 @@ static int sl_open_dev(struct device *dev)
 #ifdef MODULE
 static int slip_init_ctrl_dev(void)
 #else  /* !MODULE */
-int
-slip_init_ctrl_dev(struct device *dummy)
+int slip_init_ctrl_dev(struct device *dummy)
 #endif /* !MODULE */
 {
        int status;
@@ -1120,19 +1198,23 @@ slip_init_ctrl_dev(struct device *dummy)
 #ifdef CONFIG_SLIP_MODE_SLIP6
               " (6 bit encapsulation enabled)"
 #endif
-              "\n",
+              ".\n",
               SLIP_VERSION, slip_maxdev );
 #if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)
-       printk("CSLIP: code copyright 1989 Regents of the University of California\n");
+       printk("CSLIP: code copyright 1989 Regents of the University of California.\n");
 #endif
 #ifdef CONFIG_AX25
-       printk("AX25: KISS encapsulation enabled\n");
+       printk("AX25: KISS encapsulation enabled.\n");
 #endif
+#ifdef CONFIG_SLIP_SMART
+       printk("SLIP linefill/keepalive option.\n");
+#endif 
 
        slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL);
-       if (slip_ctrls == NULL) {
-         printk("SLIP: Can't allocate slip_ctrls[] array!  Uaargh! (-> No SLIP available)\n");
-         return -ENOMEM;
+       if (slip_ctrls == NULL) 
+       {
+               printk("SLIP: Can't allocate slip_ctrls[] array!  Uaargh! (-> No SLIP available)\n");
+               return -ENOMEM;
        }
        
        /* Clear the pointer array, we allocate devices when we need them */
@@ -1153,7 +1235,7 @@ slip_init_ctrl_dev(struct device *dummy)
        sl_ldisc.receive_room = slip_receive_room;
        sl_ldisc.write_wakeup = slip_write_wakeup;
        if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)  {
-         printk("SLIP: can't register line discipline (err = %d)\n", status);
+               printk("SLIP: can't register line discipline (err = %d)\n", status);
        }
 
 
@@ -1242,18 +1324,95 @@ cleanup_module(void)
 {
        int i;
 
-       if (slip_ctrls != NULL) {
-         for (i = 0; i < slip_maxdev; i++)  {
-           if (slip_ctrls[i] != NULL) {
-             unregister_netdev(&(slip_ctrls[i]->dev));
-             kfree(slip_ctrls[i]);
-           }
-         }
-         kfree(slip_ctrls);
-         slip_ctrls = NULL;
+       if (slip_ctrls != NULL) 
+       {
+               for (i = 0; i < slip_maxdev; i++)  
+               {
+                       if (slip_ctrls[i] != NULL) 
+                       {
+                               unregister_netdev(&(slip_ctrls[i]->dev));
+                               kfree(slip_ctrls[i]);
+                       }
+               }
+               kfree(slip_ctrls);
+               slip_ctrls = NULL;
        }
-       if ((i = tty_register_ldisc(N_SLIP, NULL)))  {
-         printk("SLIP: can't unregister line discipline (err = %d)\n", i);
+       if ((i = tty_register_ldisc(N_SLIP, NULL)))  
+       {
+               printk("SLIP: can't unregister line discipline (err = %d)\n", i);
        }
 }
 #endif /* MODULE */
+
+#ifdef CONFIG_SLIP_SMART
+/*
+ * This is start of the code for multislip style line checking
+ * added by Stanislav Voronyi. All changes before marked VSV
+ */
+static void sl_outfill(unsigned long sls)
+{
+       struct slip *sl=(struct slip *)sls;
+
+       if(sls==NULL)
+               return;
+
+       if(sl->outfill)
+       {
+               if( test_bit(SLF_OUTWAIT, &sl->flags) )
+               {
+                       /* no packets was transmited, do outfill */
+#ifdef CONFIG_SLIP_MODE_SLIP6
+                       unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;
+#else
+                       unsigned char s = END;
+#endif
+                       /* put END into tty queue. Is it right ??? */
+                       if (!test_bit(0, (void *) &sl->dev->tbusy))
+                       { 
+                               /* if device busy no outfill */
+                               sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+                               sl->tty->driver.write(sl->tty, 0, &s, 1);
+                       }
+               }
+               else
+                       set_bit(SLF_OUTWAIT, &sl->flags);
+               (void)del_timer(&sl->outfill_timer);
+               sl->outfill_timer.expires=jiffies+sl->outfill*HZ;
+               add_timer(&sl->outfill_timer);
+       }
+       else
+               del_timer(&sl->outfill_timer);
+}
+
+static void sl_keepalive(unsigned long sls)
+{
+       struct slip *sl=(struct slip *)sls;
+
+       if(sls==NULL)
+               return;
+
+       if( sl->keepalive)
+       {
+               if(test_bit(SLF_KEEPTEST, &sl->flags))
+               {
+                       /* keepalive still high :(, we must hangup */
+                       (void)del_timer(&sl->keepalive_timer);
+                       if( sl->outfill ) /* outfill timer must be deleted too */
+                               (void)del_timer(&sl->outfill_timer);
+                       printk("%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name);
+                       tty_hangup(sl->tty); /* this must hangup tty & close slip */
+                       /* I think we need not something else */
+                       return;
+               }
+               else
+                       set_bit(SLF_KEEPTEST, &sl->flags);
+               (void)del_timer(&sl->keepalive_timer);
+                sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
+               add_timer(&sl->keepalive_timer);
+       }
+       else
+               (void)del_timer(&sl->keepalive_timer);
+}
+
+#endif
index c5f8bc111e485aed5e46c6ff1fe681578bd6702a..b7daa2d4bcb7562c863d3fd014e00ee9fd8ddca0 100644 (file)
@@ -12,6 +12,8 @@
  *             Alan Cox        :       Added SL_SLIP_LOTS
  *     Dmitry Gorodchanin      :       A lot of changes in the 'struct slip'
  *     Dmitry Gorodchanin      :       Added CSLIP statistics.
+ *     Stanislav Voronyi       :       Make line checking as created by
+ *                                     Igor Chechik, RELCOM Corp.
  *
  * Author:     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  */
@@ -87,6 +89,8 @@ struct slip {
 #define SLF_INUSE      0               /* Channel in use               */
 #define SLF_ESCAPE     1               /* ESC received                 */
 #define SLF_ERROR      2               /* Parity, etc. error           */
+#define SLF_KEEPTEST   4               /* Keepalive test flag          */
+#define SLF_OUTWAIT    8               /* is outpacket was flag        */
 
   unsigned char                mode;           /* SLIP mode                    */
 #define SL_MODE_SLIP   0
@@ -95,6 +99,12 @@ struct slip {
 #define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP)
 #define SL_MODE_AX25   4
 #define SL_MODE_ADAPTIVE 8
+#ifdef CONFIG_SLIP_SMART  
+  unsigned char                outfill;        /* # of sec betwen outfill packet */
+  unsigned char                keepalive;      /* keepalive seconds            */
+  struct timer_list    outfill_timer;
+  struct timer_list    keepalive_timer;
+#endif  
 };
 
 
index ebd42b7328582412f74fe895cc30d6369411abad..90f935ea0ce899737243a68c91028d88fc09a7be 100644 (file)
@@ -68,6 +68,8 @@
  *      the high level code.
  */
 
+#include "g_NCR5380.h"
+
 #if (NDEBUG & NDEBUG_LISTS)
 #define LIST(x,y) {printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
 #define REMOVE(w,x,y,z) {printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
index ddcb72b7246fba9353c413ecf13f9c8e87c2d6e8..b6b10300a1c36efa792c6a3393ea489bba0ad894 100644 (file)
 #include <asm/system.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
index 954918226062d2b7e95f33066890d4a91e1fbe8e..770e17d2a094587f7eda03c8d35753a1233aff36 100644 (file)
@@ -678,7 +678,7 @@ ask_parameters (void)
 
 
   ask_int_choice (B (OPT_GUS), "GUS_BASE",
-                 "I/O base for Gravis UltraSound (GUS)",
+                 "I/O base for GUS",
                  FMT_HEX,
                  0x220,
                  "210, 220, 230, 240, 250 or 260");
index 8b888d7246c5f5ff915399bded845a581b00f2aa..aeb1e8eb468a40591a6546448e50fcfe047e2367 100644 (file)
@@ -52,7 +52,7 @@ endif
 ifeq ($(CONFIG_FAT_FS),y)
 SUB_DIRS += fat
 else
-  ifeq ($(CONFIG_MSDOS_FS),m)
+  ifeq ($(CONFIG_FAT_FS),m)
   MOD_SUB_DIRS += fat
   endif
 endif
@@ -149,4 +149,12 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_BINFMT_AOUT),y)
+BINFMTS += binfmt_aout.o
+else
+  ifeq ($(CONFIG_BINFMT_AOUT),m)
+  M_OBJS += binfmt_aout.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
new file mode 100644 (file)
index 0000000..fcd23ff
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ *  linux/fs/binfmt_aout.c
+ *
+ *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
+ */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+#include <linux/personality.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+
+static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
+static int load_aout_library(int fd);
+static int aout_core_dump(long signr, struct pt_regs * regs);
+
+extern void dump_thread(struct pt_regs *, struct user *);
+
+static struct linux_binfmt aout_format = {
+#ifndef MODULE
+       NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
+#else
+       NULL, &mod_use_count_, load_aout_binary, load_aout_library, aout_core_dump
+#endif
+};
+
+static void set_brk(unsigned long start, unsigned long end)
+{
+       start = PAGE_ALIGN(start);
+       end = PAGE_ALIGN(end);
+       if (end <= start)
+               return;
+       do_mmap(NULL, start, end - start,
+               PROT_READ | PROT_WRITE | PROT_EXEC,
+               MAP_FIXED | MAP_PRIVATE, 0);
+}
+
+/*
+ * These are the only things you should do on a core-file: use only these
+ * macros to write out all the necessary info.
+ */
+#define DUMP_WRITE(addr,nr) \
+while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
+
+#define DUMP_SEEK(offset) \
+if (file.f_op->lseek) { \
+       if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \
+               goto close_coredump; \
+} else file.f_pos = (offset)           
+
+/*
+ * Routine writes a core dump image in the current directory.
+ * Currently only a stub-function.
+ *
+ * Note that setuid/setgid files won't make a core-dump if the uid/gid
+ * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
+ * field, which also makes sure the core-dumps won't be recursive if the
+ * dumping of the process results in another error..
+ */
+
+static inline int
+do_aout_core_dump(long signr, struct pt_regs * regs)
+{
+       struct inode * inode = NULL;
+       struct file file;
+       unsigned short fs;
+       int has_dumped = 0;
+       char corefile[6+sizeof(current->comm)];
+       unsigned long dump_start, dump_size;
+       struct user dump;
+#ifdef __alpha__
+#       define START_DATA(u)   (u.start_data)
+#else
+#       define START_DATA(u)   (u.u_tsize << PAGE_SHIFT)
+#endif
+
+       if (!current->dumpable)
+               return 0;
+       current->dumpable = 0;
+
+/* See if we have enough room to write the upage.  */
+       if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
+               return 0;
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       memcpy(corefile,"core.",5);
+#if 0
+       memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+       corefile[4] = '\0';
+#endif
+       if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+               inode = NULL;
+               goto end_coredump;
+       }
+       if (!S_ISREG(inode->i_mode))
+               goto end_coredump;
+       if (!inode->i_op || !inode->i_op->default_file_ops)
+               goto end_coredump;
+       if (get_write_access(inode))
+               goto end_coredump;
+       file.f_mode = 3;
+       file.f_flags = 0;
+       file.f_count = 1;
+       file.f_inode = inode;
+       file.f_pos = 0;
+       file.f_reada = 0;
+       file.f_op = inode->i_op->default_file_ops;
+       if (file.f_op->open)
+               if (file.f_op->open(inode,&file))
+                       goto done_coredump;
+       if (!file.f_op->write)
+               goto close_coredump;
+       has_dumped = 1;
+               strncpy(dump.u_comm, current->comm, sizeof(current->comm));
+       dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
+       dump.signal = signr;
+       dump_thread(regs, &dump);
+
+/* If the size of the dump file exceeds the rlimit, then see what would happen
+   if we wrote the stack, but not the data area.  */
+       if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
+           current->rlim[RLIMIT_CORE].rlim_cur)
+               dump.u_dsize = 0;
+
+/* Make sure we have enough room to write the stack and data areas. */
+       if ((dump.u_ssize+1) * PAGE_SIZE >
+           current->rlim[RLIMIT_CORE].rlim_cur)
+               dump.u_ssize = 0;
+
+/* make sure we actually have a data and stack area to dump */
+       set_fs(USER_DS);
+       if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
+               dump.u_dsize = 0;
+       if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
+               dump.u_ssize = 0;
+
+       set_fs(KERNEL_DS);
+/* struct user */
+       DUMP_WRITE(&dump,sizeof(dump));
+/* Now dump all of the user data.  Include malloced stuff as well */
+       DUMP_SEEK(PAGE_SIZE);
+/* now we start writing out the user space info */
+       set_fs(USER_DS);
+/* Dump the data area */
+       if (dump.u_dsize != 0) {
+               dump_start = START_DATA(dump);
+               dump_size = dump.u_dsize << PAGE_SHIFT;
+               DUMP_WRITE(dump_start,dump_size);
+       }
+/* Now prepare to dump the stack area */
+       if (dump.u_ssize != 0) {
+               dump_start = dump.start_stack;
+               dump_size = dump.u_ssize << PAGE_SHIFT;
+               DUMP_WRITE(dump_start,dump_size);
+       }
+/* Finally dump the task struct.  Not be used by gdb, but could be useful */
+       set_fs(KERNEL_DS);
+       DUMP_WRITE(current,sizeof(*current));
+close_coredump:
+       if (file.f_op->release)
+               file.f_op->release(inode,&file);
+done_coredump:
+       put_write_access(inode);
+end_coredump:
+       set_fs(fs);
+       iput(inode);
+       return has_dumped;
+}
+
+static int
+aout_core_dump(long signr, struct pt_regs * regs)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+       retval = do_aout_core_dump(signr, regs);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+/*
+ * These are the functions used to load a.out style executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+
+static inline int
+do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+       struct exec ex;
+       struct file * file;
+       int fd;
+       unsigned long error;
+       unsigned long p = bprm->p;
+       unsigned long fd_offset;
+       unsigned long rlim;
+
+       ex = *((struct exec *) bprm->buf);              /* exec-header */
+       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && 
+            N_MAGIC(ex) != QMAGIC) ||
+           N_TRSIZE(ex) || N_DRSIZE(ex) ||
+           bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+               return -ENOEXEC;
+       }
+
+       current->personality = PER_LINUX;
+       fd_offset = N_TXTOFF(ex);
+
+#ifdef __i386__
+       if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
+               printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
+               return -ENOEXEC;
+       }
+
+       if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
+           (fd_offset < bprm->inode->i_sb->s_blocksize)) {
+               printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
+               return -ENOEXEC;
+       }
+#endif
+
+       /* Check initial limits. This avoids letting people circumvent
+        * size limits imposed on them by creating programs with large
+        * arrays in the data or bss.
+        */
+       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+       if (rlim >= RLIM_INFINITY)
+               rlim = ~0;
+       if (ex.a_data + ex.a_bss > rlim)
+               return -ENOMEM;
+
+       /* OK, This is the point of no return */
+       flush_old_exec(bprm);
+
+       current->mm->end_code = ex.a_text +
+               (current->mm->start_code = N_TXTADDR(ex));
+       current->mm->end_data = ex.a_data +
+               (current->mm->start_data = N_DATADDR(ex));
+       current->mm->brk = ex.a_bss +
+               (current->mm->start_brk = N_BSSADDR(ex));
+
+       current->mm->rss = 0;
+       current->mm->mmap = NULL;
+       current->suid = current->euid = current->fsuid = bprm->e_uid;
+       current->sgid = current->egid = current->fsgid = bprm->e_gid;
+       if (N_MAGIC(ex) == OMAGIC) {
+#ifdef __alpha__
+               do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
+                       ex.a_text+ex.a_data + PAGE_SIZE - 1,
+                       PROT_READ|PROT_WRITE|PROT_EXEC,
+                       MAP_FIXED|MAP_PRIVATE, 0);
+               read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+                         ex.a_text+ex.a_data, 0);
+#else
+               do_mmap(NULL, 0, ex.a_text+ex.a_data,
+                       PROT_READ|PROT_WRITE|PROT_EXEC,
+                       MAP_FIXED|MAP_PRIVATE, 0);
+               read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0);
+#endif
+       } else {
+               if (ex.a_text & 0xfff || ex.a_data & 0xfff)
+                       printk(KERN_NOTICE "executable not page aligned\n");
+               
+               fd = open_inode(bprm->inode, O_RDONLY);
+               
+               if (fd < 0)
+                       return fd;
+               file = current->files->fd[fd];
+               if (!file->f_op || !file->f_op->mmap) {
+                       sys_close(fd);
+                       do_mmap(NULL, 0, ex.a_text+ex.a_data,
+                               PROT_READ|PROT_WRITE|PROT_EXEC,
+                               MAP_FIXED|MAP_PRIVATE, 0);
+                       read_exec(bprm->inode, fd_offset,
+                                 (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
+                       goto beyond_if;
+               }
+
+               error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
+                       PROT_READ | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+                       fd_offset);
+
+               if (error != N_TXTADDR(ex)) {
+                       sys_close(fd);
+                       send_sig(SIGKILL, current, 0);
+                       return error;
+               }
+               
+               error = do_mmap(file, N_DATADDR(ex), ex.a_data,
+                               PROT_READ | PROT_WRITE | PROT_EXEC,
+                               MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+                               fd_offset + ex.a_text);
+               sys_close(fd);
+               if (error != N_DATADDR(ex)) {
+                       send_sig(SIGKILL, current, 0);
+                       return error;
+               }
+       }
+beyond_if:
+       if (current->exec_domain && current->exec_domain->use_count)
+               (*current->exec_domain->use_count)--;
+       if (current->binfmt && current->binfmt->use_count)
+               (*current->binfmt->use_count)--;
+       current->exec_domain = lookup_exec_domain(current->personality);
+       current->binfmt = &aout_format;
+       if (current->exec_domain && current->exec_domain->use_count)
+               (*current->exec_domain->use_count)++;
+       if (current->binfmt && current->binfmt->use_count)
+               (*current->binfmt->use_count)++;
+
+       set_brk(current->mm->start_brk, current->mm->brk);
+
+       fd_offset = setup_arg_pages(ex.a_text,bprm->page) - MAX_ARG_PAGES*PAGE_SIZE;
+       p += fd_offset;
+       if (bprm->loader)
+               bprm->loader += fd_offset;
+       bprm->exec += fd_offset;
+       
+       p = (unsigned long)create_tables((char *)p, bprm,
+                                       current->personality != PER_LINUX);
+       current->mm->start_stack = p;
+#ifdef __alpha__
+       regs->gp = ex.a_gpvalue;
+#endif
+       start_thread(regs, ex.a_entry, p);
+       if (current->flags & PF_PTRACED)
+               send_sig(SIGTRAP, current, 0);
+       return 0;
+}
+
+static int
+load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+       retval = do_load_aout_binary(bprm, regs);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+static inline int
+do_load_aout_library(int fd)
+{
+        struct file * file;
+       struct exec ex;
+       struct  inode * inode;
+       unsigned int len;
+       unsigned int bss;
+       unsigned int start_addr;
+       unsigned long error;
+       
+       file = current->files->fd[fd];
+       inode = file->f_inode;
+       
+       if (!file || !file->f_op)
+               return -EACCES;
+
+       /* Seek into the file */
+       if (file->f_op->lseek) {
+               if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0)
+                       return -ENOEXEC;
+       } else
+               file->f_pos = 0;
+
+       set_fs(KERNEL_DS);
+       error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex));
+       set_fs(USER_DS);
+       if (error != sizeof(ex))
+               return -ENOEXEC;
+
+       /* We come in here for the regular a.out style of shared libraries */
+       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
+           N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
+           inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+               return -ENOEXEC;
+       }
+       if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && 
+           (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
+               printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
+               return -ENOEXEC;
+       }
+       
+       if (N_FLAGS(ex)) return -ENOEXEC;
+
+       /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
+          this off to get the starting address for the page */
+
+       start_addr =  ex.a_entry & 0xfffff000;
+
+       /* Now use mmap to map the library into memory. */
+       error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+                       N_TXTOFF(ex));
+       if (error != start_addr)
+               return error;
+       len = PAGE_ALIGN(ex.a_text + ex.a_data);
+       bss = ex.a_text + ex.a_data + ex.a_bss;
+       if (bss > len)
+               do_mmap(NULL, start_addr + len, bss-len,
+                       PROT_READ|PROT_WRITE|PROT_EXEC,
+                       MAP_PRIVATE|MAP_FIXED, 0);
+       return 0;
+}
+
+static int
+load_aout_library(int fd)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+       retval = do_load_aout_library(fd);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+
+int init_aout_binfmt(void) {
+       return register_binfmt(&aout_format);
+}
+
+#ifdef MODULE
+int init_module(void) {
+       return init_aout_binfmt();
+}
+
+void cleanup_module( void) {
+       unregister_binfmt(&aout_format);
+}
+#endif
+
index c8ca4c6b6fdf610b51680619b73196f76ef7e596..d2f0d8b7d1ce9ddb6a8b07a4215d30418cdd36ed 100644 (file)
 
 #include <linux/config.h>
 
-#include <linux/unistd.h>
-typedef int (*sysfun_p)(int, ...);
-extern sysfun_p sys_call_table[];
-#define SYS(name)      (sys_call_table[__NR_##name])
-
 #define DLINFO_ITEMS 12
 
 #include <linux/elf.h>
@@ -47,13 +42,7 @@ static int load_elf_library(int fd);
 static int elf_core_dump(long signr, struct pt_regs * regs);
 extern int dump_fpu (elf_fpregset_t *);
 
-/*
- * Please do not change the default core dump format to ELF when most people
- * do not have a gdb capable of interpreting ELF core files.  Once a gdb has
- * been released that understands ELF, *THEN* switch the core dump format.
- */
-
-struct linux_binfmt elf_format = {
+static struct linux_binfmt elf_format = {
 #ifndef MODULE
        NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
@@ -61,6 +50,18 @@ struct linux_binfmt elf_format = {
 #endif
 };
 
+static void set_brk(unsigned long start, unsigned long end)
+{
+       start = PAGE_ALIGN(start);
+       end = PAGE_ALIGN(end);
+       if (end <= start) 
+               return;
+       do_mmap(NULL, start, end - start,
+               PROT_READ | PROT_WRITE | PROT_EXEC,
+               MAP_FIXED | MAP_PRIVATE, 0);
+}
+
+
 /* We need to explicitly zero any fractional pages
    after the data section (i.e. bss).  This would
    contain the junk from the file that should not
@@ -268,7 +269,7 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
        
        /* Now use mmap to map the library into memory. */
 
-       SYS(close)(elf_exec_fileno);
+       sys_close(elf_exec_fileno);
        if(error < 0 && error > -1024) {
                kfree(elf_phdata);
                return 0xffffffff;
@@ -615,7 +616,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        
        kfree(elf_phdata);
        
-       if(interpreter_type != INTERPRETER_AOUT) SYS(close)(elf_exec_fileno);
+       if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
        current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
        if (current->exec_domain && current->exec_domain->use_count)
@@ -655,10 +656,9 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        current->mm->end_data = end_data;
        current->mm->start_stack = bprm->p;
 
-       /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
+       /* Calling set_brk effectively mmaps the pages that we need for the bss and break
           sections */
-       current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
-       SYS(brk)((elf_brk + 0xfff) & 0xfffff000);
+       set_brk(elf_bss, elf_brk);
 
        padzero(elf_bss);
 
@@ -1221,6 +1221,10 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        return has_dumped;
 }
 
+int init_elf_binfmt(void) {
+       return register_binfmt(&elf_format);
+}
+
 #ifdef MODULE
 
 int init_module(void) {
@@ -1228,7 +1232,7 @@ int init_module(void) {
         * N.B. We *rely* on the table being the right size with the
         * right number of free slots...
         */
-       return register_binfmt(&elf_format);
+       return init_elf_binfmt();
 }
 
 
index 8737adbef58fdafeea52548898ae00343272e2b9..e090e326586dc66edd829fd423d88b5327c8d574 100644 (file)
 #include <asm/segment.h>
 #include <asm/io.h>
 
-#define NR_SIZES 4
-static char buffersize_index[9] = {-1,  0,  1, -1,  2, -1, -1, -1, 3};
-static short int bufferindex_size[NR_SIZES] = {512, 1024, 2048, 4096};
+#define NR_SIZES 5
+static char buffersize_index[17] =
+{-1,  0,  1, -1,  2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4};
+static short int bufferindex_size[NR_SIZES] = {512, 1024, 2048, 4096, 8192};
 
 #define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
 #define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
@@ -99,7 +100,7 @@ static union bdflush_param{
                                   trim back the buffers */
        } b_un;
        unsigned int data[N_PARAM];
-} bdf_prm = {{25, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{60, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 
 /* The lav constant is set for 1 minute, as long as the update process runs
    every 5 seconds.  If you change the frequency of update, the time
@@ -502,9 +503,12 @@ void set_blocksize(kdev_t dev, int size)
        if (!blksize_size[MAJOR(dev)])
                return;
 
+       if (size > PAGE_SIZE)
+               size = 0;
+
        switch(size) {
                default: panic("Invalid blocksize passed to set_blocksize");
-               case 512: case 1024: case 2048: case 4096:;
+               case 512: case 1024: case 2048: case 4096: case 8192: ;
        }
 
        if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
index 6aa3eefef9e5bb023a906c2096115e7430ff5829..a1c8e261112d0fc67c02638e0d400f3942183845 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
 asmlinkage int sys_exit(int exit_code);
 asmlinkage int sys_brk(unsigned long);
 
-static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
-static int load_aout_library(int fd);
-
-extern void dump_thread(struct pt_regs *, struct user *);
-
 /*
  * Here are the actual binaries that will be accepted:
  * add more with "register_binfmt()" if using modules...
+ *
+ * These are defined again for the 'real' modules if you are using a
+ * module definition for these routines.
  */
-extern struct linux_binfmt elf_format;
 
-static struct linux_binfmt aout_format = {
-#ifndef CONFIG_BINFMT_ELF
-       NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
-#else
-       &elf_format, NULL, load_aout_binary, load_aout_library, aout_core_dump
+static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;
+
+void binfmt_setup(void)
+{
+#ifdef CONFIG_BINFMT_ELF
+       init_elf_binfmt();
 #endif
-};
 
-static struct linux_binfmt *formats = &aout_format;
+#ifdef CONFIG_BINFMT_AOUT
+       init_aout_binfmt();
+#endif
+}
 
-#ifdef CONFIG_MODULES
 int register_binfmt(struct linux_binfmt * fmt)
 {
        struct linux_binfmt ** tmp = &formats;
@@ -91,6 +90,7 @@ int register_binfmt(struct linux_binfmt * fmt)
        return 0;       
 }
 
+#ifdef CONFIG_MODULES
 int unregister_binfmt(struct linux_binfmt * fmt)
 {
        struct linux_binfmt ** tmp = &formats;
@@ -146,137 +146,6 @@ int open_inode(struct inode * inode, int mode)
        return fd;
 }
 
-/*
- * These are the only things you should do on a core-file: use only these
- * macros to write out all the necessary info.
- */
-#define DUMP_WRITE(addr,nr) \
-while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
-
-#define DUMP_SEEK(offset) \
-if (file.f_op->lseek) { \
-       if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \
-               goto close_coredump; \
-} else file.f_pos = (offset)           
-
-/*
- * Routine writes a core dump image in the current directory.
- * Currently only a stub-function.
- *
- * Note that setuid/setgid files won't make a core-dump if the uid/gid
- * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
- * field, which also makes sure the core-dumps won't be recursive if the
- * dumping of the process results in another error..
- */
-int aout_core_dump(long signr, struct pt_regs * regs)
-{
-       struct inode * inode = NULL;
-       struct file file;
-       unsigned short fs;
-       int has_dumped = 0;
-       char corefile[6+sizeof(current->comm)];
-       unsigned long dump_start, dump_size;
-       struct user dump;
-#ifdef __alpha__
-#       define START_DATA(u)   (u.start_data)
-#else
-#       define START_DATA(u)   (u.u_tsize << PAGE_SHIFT)
-#endif
-
-       if (!current->dumpable)
-               return 0;
-       current->dumpable = 0;
-
-/* See if we have enough room to write the upage.  */
-       if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
-               return 0;
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       memcpy(corefile,"core.",5);
-#if 0
-       memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
-       corefile[4] = '\0';
-#endif
-       if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
-               inode = NULL;
-               goto end_coredump;
-       }
-       if (!S_ISREG(inode->i_mode))
-               goto end_coredump;
-       if (!inode->i_op || !inode->i_op->default_file_ops)
-               goto end_coredump;
-       if (get_write_access(inode))
-               goto end_coredump;
-       file.f_mode = 3;
-       file.f_flags = 0;
-       file.f_count = 1;
-       file.f_inode = inode;
-       file.f_pos = 0;
-       file.f_reada = 0;
-       file.f_op = inode->i_op->default_file_ops;
-       if (file.f_op->open)
-               if (file.f_op->open(inode,&file))
-                       goto done_coredump;
-       if (!file.f_op->write)
-               goto close_coredump;
-       has_dumped = 1;
-               strncpy(dump.u_comm, current->comm, sizeof(current->comm));
-       dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
-       dump.signal = signr;
-       dump_thread(regs, &dump);
-
-/* If the size of the dump file exceeds the rlimit, then see what would happen
-   if we wrote the stack, but not the data area.  */
-       if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
-           current->rlim[RLIMIT_CORE].rlim_cur)
-               dump.u_dsize = 0;
-
-/* Make sure we have enough room to write the stack and data areas. */
-       if ((dump.u_ssize+1) * PAGE_SIZE >
-           current->rlim[RLIMIT_CORE].rlim_cur)
-               dump.u_ssize = 0;
-
-/* make sure we actually have a data and stack area to dump */
-       set_fs(USER_DS);
-       if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
-               dump.u_dsize = 0;
-       if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
-               dump.u_ssize = 0;
-
-       set_fs(KERNEL_DS);
-/* struct user */
-       DUMP_WRITE(&dump,sizeof(dump));
-/* Now dump all of the user data.  Include malloced stuff as well */
-       DUMP_SEEK(PAGE_SIZE);
-/* now we start writing out the user space info */
-       set_fs(USER_DS);
-/* Dump the data area */
-       if (dump.u_dsize != 0) {
-               dump_start = START_DATA(dump);
-               dump_size = dump.u_dsize << PAGE_SHIFT;
-               DUMP_WRITE(dump_start,dump_size);
-       }
-/* Now prepare to dump the stack area */
-       if (dump.u_ssize != 0) {
-               dump_start = dump.start_stack;
-               dump_size = dump.u_ssize << PAGE_SHIFT;
-               DUMP_WRITE(dump_start,dump_size);
-       }
-/* Finally dump the task struct.  Not be used by gdb, but could be useful */
-       set_fs(KERNEL_DS);
-       DUMP_WRITE(current,sizeof(*current));
-close_coredump:
-       if (file.f_op->release)
-               file.f_op->release(inode,&file);
-done_coredump:
-       put_write_access(inode);
-end_coredump:
-       set_fs(fs);
-       iput(inode);
-       return has_dumped;
-}
-
 /*
  * Note that a shared library must be both readable and executable due to
  * security reasons.
@@ -822,228 +691,3 @@ exec_error1:
                free_page(bprm.page[i]);
        return(retval);
 }
-
-static void set_brk(unsigned long start, unsigned long end)
-{
-       start = PAGE_ALIGN(start);
-       end = PAGE_ALIGN(end);
-       if (end <= start)
-               return;
-       do_mmap(NULL, start, end - start,
-               PROT_READ | PROT_WRITE | PROT_EXEC,
-               MAP_FIXED | MAP_PRIVATE, 0);
-}
-
-/*
- * These are the functions used to load a.out style executables and shared
- * libraries.  There is no binary dependent code anywhere else.
- */
-
-static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
-       struct exec ex;
-       struct file * file;
-       int fd;
-       unsigned long error;
-       unsigned long p = bprm->p;
-       unsigned long fd_offset;
-       unsigned long rlim;
-
-       ex = *((struct exec *) bprm->buf);              /* exec-header */
-       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && 
-            N_MAGIC(ex) != QMAGIC) ||
-           N_TRSIZE(ex) || N_DRSIZE(ex) ||
-           bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
-               return -ENOEXEC;
-       }
-
-       current->personality = PER_LINUX;
-       fd_offset = N_TXTOFF(ex);
-
-#ifdef __i386__
-       if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
-               printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
-               return -ENOEXEC;
-       }
-
-       if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
-           (fd_offset < bprm->inode->i_sb->s_blocksize)) {
-               printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
-               return -ENOEXEC;
-       }
-#endif
-
-       /* Check initial limits. This avoids letting people circumvent
-        * size limits imposed on them by creating programs with large
-        * arrays in the data or bss.
-        */
-       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
-       if (rlim >= RLIM_INFINITY)
-               rlim = ~0;
-       if (ex.a_data + ex.a_bss > rlim)
-               return -ENOMEM;
-
-       /* OK, This is the point of no return */
-       flush_old_exec(bprm);
-
-       current->mm->end_code = ex.a_text +
-               (current->mm->start_code = N_TXTADDR(ex));
-       current->mm->end_data = ex.a_data +
-               (current->mm->start_data = N_DATADDR(ex));
-       current->mm->brk = ex.a_bss +
-               (current->mm->start_brk = N_BSSADDR(ex));
-
-       current->mm->rss = 0;
-       current->mm->mmap = NULL;
-       current->suid = current->euid = current->fsuid = bprm->e_uid;
-       current->sgid = current->egid = current->fsgid = bprm->e_gid;
-       if (N_MAGIC(ex) == OMAGIC) {
-#ifdef __alpha__
-               do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
-                       ex.a_text+ex.a_data + PAGE_SIZE - 1,
-                       PROT_READ|PROT_WRITE|PROT_EXEC,
-                       MAP_FIXED|MAP_PRIVATE, 0);
-               read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
-                         ex.a_text+ex.a_data, 0);
-#else
-               do_mmap(NULL, 0, ex.a_text+ex.a_data,
-                       PROT_READ|PROT_WRITE|PROT_EXEC,
-                       MAP_FIXED|MAP_PRIVATE, 0);
-               read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0);
-#endif
-       } else {
-               if (ex.a_text & 0xfff || ex.a_data & 0xfff)
-                       printk(KERN_NOTICE "executable not page aligned\n");
-               
-               fd = open_inode(bprm->inode, O_RDONLY);
-               
-               if (fd < 0)
-                       return fd;
-               file = current->files->fd[fd];
-               if (!file->f_op || !file->f_op->mmap) {
-                       sys_close(fd);
-                       do_mmap(NULL, 0, ex.a_text+ex.a_data,
-                               PROT_READ|PROT_WRITE|PROT_EXEC,
-                               MAP_FIXED|MAP_PRIVATE, 0);
-                       read_exec(bprm->inode, fd_offset,
-                                 (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
-                       goto beyond_if;
-               }
-
-               error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
-                       PROT_READ | PROT_EXEC,
-                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
-                       fd_offset);
-
-               if (error != N_TXTADDR(ex)) {
-                       sys_close(fd);
-                       send_sig(SIGKILL, current, 0);
-                       return error;
-               }
-               
-               error = do_mmap(file, N_DATADDR(ex), ex.a_data,
-                               PROT_READ | PROT_WRITE | PROT_EXEC,
-                               MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
-                               fd_offset + ex.a_text);
-               sys_close(fd);
-               if (error != N_DATADDR(ex)) {
-                       send_sig(SIGKILL, current, 0);
-                       return error;
-               }
-       }
-beyond_if:
-       if (current->exec_domain && current->exec_domain->use_count)
-               (*current->exec_domain->use_count)--;
-       if (current->binfmt && current->binfmt->use_count)
-               (*current->binfmt->use_count)--;
-       current->exec_domain = lookup_exec_domain(current->personality);
-       current->binfmt = &aout_format;
-       if (current->exec_domain && current->exec_domain->use_count)
-               (*current->exec_domain->use_count)++;
-       if (current->binfmt && current->binfmt->use_count)
-               (*current->binfmt->use_count)++;
-
-       set_brk(current->mm->start_brk, current->mm->brk);
-
-       fd_offset = setup_arg_pages(ex.a_text,bprm->page) - MAX_ARG_PAGES*PAGE_SIZE;
-       p += fd_offset;
-       if (bprm->loader)
-               bprm->loader += fd_offset;
-       bprm->exec += fd_offset;
-       
-       p = (unsigned long)create_tables((char *)p, bprm,
-                                       current->personality != PER_LINUX);
-       current->mm->start_stack = p;
-#ifdef __alpha__
-       regs->gp = ex.a_gpvalue;
-#endif
-       start_thread(regs, ex.a_entry, p);
-       if (current->flags & PF_PTRACED)
-               send_sig(SIGTRAP, current, 0);
-       return 0;
-}
-
-
-static int load_aout_library(int fd)
-{
-        struct file * file;
-       struct exec ex;
-       struct  inode * inode;
-       unsigned int len;
-       unsigned int bss;
-       unsigned int start_addr;
-       unsigned long error;
-       
-       file = current->files->fd[fd];
-       inode = file->f_inode;
-       
-       if (!file || !file->f_op)
-               return -EACCES;
-
-       /* Seek into the file */
-       if (file->f_op->lseek) {
-               if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0)
-                       return -ENOEXEC;
-       } else
-               file->f_pos = 0;
-
-       set_fs(KERNEL_DS);
-       error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex));
-       set_fs(USER_DS);
-       if (error != sizeof(ex))
-               return -ENOEXEC;
-
-       /* We come in here for the regular a.out style of shared libraries */
-       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
-           N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
-           inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
-               return -ENOEXEC;
-       }
-       if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && 
-           (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
-               printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
-               return -ENOEXEC;
-       }
-       
-       if (N_FLAGS(ex)) return -ENOEXEC;
-
-       /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
-          this off to get the starting address for the page */
-
-       start_addr =  ex.a_entry & 0xfffff000;
-
-       /* Now use mmap to map the library into memory. */
-       error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
-                       PROT_READ | PROT_WRITE | PROT_EXEC,
-                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
-                       N_TXTOFF(ex));
-       if (error != start_addr)
-               return error;
-       len = PAGE_ALIGN(ex.a_text + ex.a_data);
-       bss = ex.a_text + ex.a_data + ex.a_bss;
-       if (bss > len)
-               do_mmap(NULL, start_addr + len, bss-len,
-                       PROT_READ|PROT_WRITE|PROT_EXEC,
-                       MAP_PRIVATE|MAP_FIXED, 0);
-       return 0;
-}
index f21827472f368b8798cfe8801ad1edfbc442d73d..2c0eaadbb7af68763d34b8207768343e4774bbbd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/msdos/buffer.c
+ * linux/fs/fat/buffer.c
  *
  *
  */
index 6613aad525fd6462526f810b9241a19042f42b20..cb05f26c581caf0bf87bfe653921adbaa8494e4c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/fs/msdos/cache.c
+ *  linux/fs/fat/cache.c
  *
  *  Written 1992,1993 by Werner Almesberger
  */
index 606da5f548d5a08afa3a30dcc58ce76423512e36..e40ea14e64ad8df070dcf5b0752d905e4ed83fa7 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *  linux/fs/msdos/dir.c
- *  MS-DOS directory handling functions
+ *  linux/fs/fat/dir.c
+ *
+ *  directory handling functions for fat-based filesystems
  *
  *  Written 1992,1993 by Werner Almesberger
  *
index 74f34f2ab578462cff0695e70f4a4789bcbe0078..3b1b137e2a2d25ff25dad0ff8749ab5f8846408a 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * linux/fs/fat/fatfs_syms.c
+ *
+ * Exported kernel symbols for the low-level FAT-based fs support.
+ *
+ */
 #include <linux/module.h>
 
 #include <linux/msdos_fs.h>
@@ -5,6 +11,8 @@
 #include "msbuffer.h"
 #include "tables.h"
 
+extern struct file_operations fat_dir_operations;
+
 static struct symbol_table fat_syms = {
 #include <linux/symtab_begin.h>
        X(fat_a2alias),
index 444e1ddaff304f1e0fb40a1023d4178545cf29f5..3cf3a973cdbbafc606e6c28a6f6845ae5aaa1dc9 100644 (file)
@@ -1,9 +1,9 @@
 /*
- *  linux/fs/msdos/file.c
+ *  linux/fs/fat/file.c
  *
  *  Written 1992,1993 by Werner Almesberger
  *
- *  MS-DOS regular file handling primitives
+ *  regular file handling primitives for fat-based filesystems
  */
 
 #include <linux/sched.h>
index 1a8b69e46636d69f3d4beced7e333e000e185d9c..34dddcd12eee7cf3c48fc8fdaa8282f36d5d991c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/fs/msdos/inode.c
+ *  linux/fs/fat/inode.c
  *
  *  Written 1992,1993 by Werner Almesberger
  *  VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
index a18266c2445d9f50003f3819ed494d05ba873609..b01f07a9aaa913fc3345585dbe703fdf75e95113 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/fs/msdos/misc.c
+ *  linux/fs/fat/misc.c
  *
  *  Written 1992,1993 by Werner Almesberger
  */
index 504b0b3d0fbf63e6065fc9de666f4ffd48604e2e..779710c38a4b3f361797087c411b120ae709be77 100644 (file)
@@ -1,10 +1,10 @@
 /*
- *     fs/msdos/mmap.c
+ *     linux/fs/fat/mmap.c
  *
  *     Written by Jacques Gelinas (jacques@solucorp.qc.ca)
  *     Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993)
  *
- *     msdos mmap handling
+ *     mmap handling for fat-based filesystems
  */
 
 #include <linux/stat.h>
index 564da0d7cfeb3261870422ed5cab56ddaa6d7c3a..afe157d83f3225fe6933b816f306975387683c9b 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * linux/fs/msdos/tables.c
+ * linux/fs/fat/tables.c
  *
  * ASCII / Unicode translation tables for VFAT filename handling.
  * By Gordon Chaffee.
+ *
+ * Note: This file is used by all fat-based filesystems.
  */
 
 #include <linux/kernel.h>
index 70be1422cf024be2b7c3e3619fcc8f0c4a93b8ef..6f7df2c9ea182bb0062b6e2ad9e3176cb5ba42d1 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/major.h>
 
 extern void device_setup(void);
+extern void binfmt_setup(void);
 
 #ifdef CONFIG_ROOT_NFS
 extern int nfs_root_init(char *nfsname, char *nfsaddrs);
@@ -43,6 +44,8 @@ asmlinkage int sys_setup(void)
 
        device_setup();
 
+       binfmt_setup();
+
 #ifdef CONFIG_EXT_FS
        init_ext_fs();
 #endif
@@ -59,6 +62,10 @@ asmlinkage int sys_setup(void)
        init_minix_fs();
 #endif
 
+#ifdef CONFIG_UMSDOS_FS
+       init_umsdos_fs();
+#endif
+
 #ifdef CONFIG_FAT_FS
        init_fat_fs();
 #endif
@@ -71,10 +78,6 @@ asmlinkage int sys_setup(void)
        init_vfat_fs();
 #endif
 
-#ifdef CONFIG_UMSDOS_FS
-       init_umsdos_fs();
-#endif
-
 #ifdef CONFIG_PROC_FS
        init_proc_fs();
 #endif
index 9b64fa1851f3eeee83449cc3fe0b54b725bcde1a..d113bf9f430866558471be446aced1d9859acd30 100644 (file)
  *  above, mandatory locks requires lots of changes elsewhere and I am
  *  reluctant to start something so drastic for so little gain.
  *  Andy Walker (andy@keo.kvaerner.no), June 09, 1995
+ * 
+ *  Removed some race conditions in flock_lock_file(), marked other possible
+ *  races. Just grep for FIXME to see them. 
+ *  Dmitry Gorodchanin (begemot@bgm.rosprint.net), Feb 09, 1996.
  */
 
 #include <asm/segment.h>
@@ -66,6 +70,7 @@
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 
+
 #define OFFSET_MAX     ((off_t)0x7fffffff)     /* FIXME: move elsewhere? */
 
 static int flock_make_lock(struct file *filp, struct file_lock *fl,
@@ -88,10 +93,60 @@ static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2);
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
 static void locks_delete_lock(struct file_lock **fl, unsigned int wait);
-static void locks_insert_block(struct file_lock **block, struct file_lock *fl);
 
 static struct file_lock *file_lock_table = NULL;
 
+/* Free lock not inserted in any queue */
+static inline void locks_free_lock(struct file_lock **fl)
+{
+       kfree(*fl);
+       *fl = NULL;                    /* Just in case */
+}
+
+/* Add lock fl to the blocked list pointed to by block.
+ * We search to the end of the existing list and insert the the new
+ * struct. This ensures processes will be woken up in the order they
+ * blocked.
+ * NOTE: nowhere does the documentation insist that processes be woken
+ * up in this order, but it seems like the reasonable thing to do.
+ * If the blocked list gets long then this search could get expensive,
+ * in which case we could consider waking the processes up in reverse
+ * order, or making the blocked list a doubly linked circular list.
+ * 
+ * This functions are called only from one place (flock_lock_file)
+ * so they are inlined now. -- Dmitry Gorodchanin 02/09/96.
+ */
+
+static inline void locks_insert_block(struct file_lock **block, 
+                                     struct file_lock *fl)
+{
+       struct file_lock *bfl;
+
+       while ((bfl = *block) != NULL) {
+               block = &bfl->fl_block;
+       }
+
+       *block = fl;
+       fl->fl_block = NULL;
+       
+       return;
+}
+
+static inline void locks_delete_block(struct file_lock **block,
+                                     struct file_lock *fl)
+{
+       struct file_lock *bfl;
+       
+       while ((bfl = *block) != NULL) {
+               if (bfl == fl) {
+                       *block = fl->fl_block;
+                       fl->fl_block = NULL;
+                       return;
+               }
+               block = &bfl->fl_block;
+       }
+}
+
 /* flock() system call entry point. Apply a FLOCK style locks to
  * an open file descriptor.
  */
@@ -378,6 +433,11 @@ static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
  * The detection scheme is recursive... we may need a test to make it exit if the
  * function gets stuck due to bad lock data. 4.4 BSD uses a maximum depth of 50
  * for this.
+ * 
+ * FIXME: 
+ * IMHO this function is dangerous, deep recursion may result in kernel stack
+ * corruption. Perhaps we need to limit depth here. 
+ *             Dmitry Gorodchanin 09/02/96
  */
 static int posix_locks_deadlock(struct task_struct *my_task,
                                struct task_struct *blocked_task)
@@ -447,19 +507,33 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
                
                if (wait) {
                        if (current->signal & ~current->blocked) {
-                               locks_delete_lock(&new_fl, 0);
+                               /* Note: new_fl is not in any queue at this
+                                * point. So we must use locks_free_lock()
+                                * instead of locks_delete_lock()
+                                *      Dmitry Gorodchanin 09/02/96.
+                                */
+                               locks_free_lock(&new_fl);
                                return (-ERESTARTSYS);
                        }
                        locks_insert_block(&fl->fl_block, new_fl);
                        interruptible_sleep_on(&new_fl->fl_wait);
                        wake_up(&new_fl->fl_wait);
                        if (current->signal & ~current->blocked) {
-                               locks_delete_lock(&new_fl, 0);
+                               /* If we are here, than we were awaken
+                                * by signal, so new_fl is still in 
+                                * block queue of fl. We need remove 
+                                * new_fl and then free it. 
+                                *      Dmitry Gorodchanin 09/02/96.
+                                */
+
+                               locks_delete_block(&fl->fl_block, new_fl);
+                               locks_free_lock(&new_fl);
                                return (-ERESTARTSYS);
                        }
                        goto repeat;
                }
-               locks_delete_lock(&new_fl, 0);
+               
+               locks_free_lock(&new_fl);
                return (-EAGAIN);
        }
        locks_insert_lock(&filp->f_inode->i_flock, new_fl);
@@ -516,8 +590,10 @@ repeat:
        /* First skip FLOCK locks and locks owned by other processes.
         */
        while ((fl = *before) && ((fl->fl_flags == F_FLOCK) ||
-                                 (caller->fl_owner != fl->fl_owner)))
+                                 (caller->fl_owner != fl->fl_owner))) {
                before = &fl->fl_next;
+       }
+       
 
        /* Process locks with this owner.
         */
@@ -596,6 +672,18 @@ repeat:
                before = &(*before)->fl_next;
        }
 
+       /* FIXME:
+        * Note: We may sleep in locks_alloc_lock(), so
+        * the 'before' pointer may be not valid any more.
+        * This can cause random kernel memory corruption.
+        * It seems the right way is to alloc two locks
+        * at the begining of this func, and then free them
+        * if they were not needed.
+        * Another way is to change GFP_KERNEL to GFP_ATOMIC
+        * in locks_alloc_lock() for this case.
+        * 
+        * Dmitry Gorodchanin 09/02/96.
+        */ 
        if (!added) {
                if (caller->fl_type == F_UNLCK)
                        return (0);
@@ -691,9 +779,10 @@ static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
 
        if (fl->fl_prevlink != NULL)
                fl->fl_prevlink->fl_nextlink = fl->fl_nextlink;
-       else
+       else {
                file_lock_table = fl->fl_nextlink;
-
+       }
+       
        while ((bfl = fl->fl_block) != NULL) {
                fl->fl_block = bfl->fl_block;
                bfl->fl_block = NULL;
@@ -707,27 +796,3 @@ static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
 
        return;
 }
-
-/* Add lock fl to the blocked list pointed to by block.
- * We search to the end of the existing list and insert the the new
- * struct. This ensures processes will be woken up in the order they
- * blocked.
- * NOTE: nowhere does the documentation insist that processes be woken
- * up in this order, but it seems like the reasonable thing to do.
- * If the blocked list gets long then this search could get expensive,
- * in which case we could consider waking the processes up in reverse
- * order, or making the blocked list a doubly linked circular list.
- */
-static void locks_insert_block(struct file_lock **block, struct file_lock *fl)
-{
-       struct file_lock *bfl;
-
-       while ((bfl = *block) != NULL)
-               block = &bfl->fl_block;
-
-       *block = fl;
-       fl->fl_block = NULL;
-
-       return;
-}
-
index 7e6e7633ba4c75c7fedff4cd13b20338b0f0d851..61d1de80aa45e6f27bda8a8e97cfacbcf9f6d44d 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * linux/fs/msdos/msdosfs_syms.c
+ *
+ * Exported kernel symbols for the MS-DOS filesystem.
+ * These symbols are used by umsdos.
+ */
+
 #include <linux/module.h>
 
 #include <linux/msdos_fs.h>
index 483a1826a0d601509f66863be536b2b6ebecbd68..68fedcc04b267ec42782321e7a44ac5858e0595f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/fs/msdos/msdos.c
+ *  linux/fs/msdos/namei.c
  *
  *  Written 1992,1993 by Werner Almesberger
  *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
index 6a3ab8fdf9b20925b7e548f7ea873c5de0e233e1..1e2c9c64b072dfefc9e6831feaba9a7d3980f2e0 100644 (file)
@@ -134,24 +134,24 @@ extern unsigned long prof_shift;
  */
 static int read_profile(struct inode *inode, struct file *file, char *buf, int count)
 {
-    unsigned long p = file->f_pos;
+       unsigned long p = file->f_pos;
        int read;
        char * pnt;
        unsigned long sample_step = 1 << prof_shift;
 
        if (count < 0)
-           return -EINVAL;
+               return -EINVAL;
        if (p >= (prof_len+1)*sizeof(unsigned long))
-           return 0;
+               return 0;
        if (count > (prof_len+1)*sizeof(unsigned long) - p)
-           count = (prof_len+1)*sizeof(unsigned long) - p;
-    read = 0;
+               count = (prof_len+1)*sizeof(unsigned long) - p;
+       read = 0;
 
-    while (p < sizeof(unsigned long) && count > 0) {
-        put_user(*((char *)(&sample_step)+p),buf);
+       while (p < sizeof(unsigned long) && count > 0) {
+               put_user(*((char *)(&sample_step)+p),buf);
                buf++; p++; count--; read++;
-    }
-    pnt = (char *)prof_buffer + p - sizeof(unsigned long);
+       }
+       pnt = (char *)prof_buffer + p - sizeof(unsigned long);
        memcpy_tofs(buf,(void *)pnt,count);
        read += count;
        file->f_pos += read;
index a7aa5e1a0dc07c6d53a8be61cedcf40bda2a7c83..49ad128c7ae2c683fb344bb2b679495e1e8ebcbd 100644 (file)
@@ -50,7 +50,7 @@ void UMSDOS_put_inode(struct inode *inode)
 
 void UMSDOS_put_super(struct super_block *sb)
 {
-       fat_put_super(sb);
+       msdos_put_super(sb);
        MOD_DEC_USE_COUNT;
 }
 
@@ -400,7 +400,7 @@ struct super_block *UMSDOS_read_super(
        */
        struct super_block *sb;
        MOD_INC_USE_COUNT;
-       sb = fat_read_super(s,data,silent);
+       sb = msdos_read_super(s,data,silent);
        printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
                ,UMSDOS_VERSION,UMSDOS_RELEASE);
        if (sb != NULL){
index 49e17dbfa6bee6d9551300a07810cd567e462359..024c567bb312e0fade954908e7ff546340ec9ca8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/fs/msdos/vfat.c
+ *  linux/fs/vfat/namei.c
  *
  *  Written 1992,1993 by Werner Almesberger
  *
index f778685dc1702c340af56c2940674ecfb3ea7416..04b60fdc5f5de695d5152088c2d8863962cc2f61 100644 (file)
@@ -24,7 +24,9 @@ extern __inline void lock_kernel(void)
                        break;
                do 
                {
+#ifdef __SMP_PROF__            
                        smp_spins[smp_processor_id()]++;
+#endif                 
                        /*
                         *      Doing test_bit here doesn't lock the bus 
                         */
index cd5beb22b1c1c8d53dd400e593e22b60c14c4973..0d1c403a6b4c9e0356ad752eada6aab39ae015c1 100644 (file)
@@ -44,7 +44,9 @@ extern int read_exec(struct inode *inode, unsigned long offset,
        char * addr, unsigned long count, int to_kmem);
 
 extern int open_inode(struct inode * inode, int mode);
-extern int aout_core_dump(long signr, struct pt_regs * regs);
+
+extern int init_elf_binfmt(void);
+extern int init_aout_binfmt(void);
 
 extern void flush_old_exec(struct linux_binprm * bprm);
 extern unsigned long setup_arg_pages(unsigned long text_size,unsigned long * page);
index 442bf3ea35f5c1ef53ba806ae04e0a0d1d871385..54f9271bcef36285b1f49cf98fe138f9e40b3809 100644 (file)
@@ -505,7 +505,6 @@ extern int fs_may_umount(kdev_t dev, struct inode * mount_root);
 extern int fs_may_remount_ro(kdev_t dev);
 
 extern struct file *first_file;
-extern int nr_files;
 extern struct super_block super_blocks[NR_SUPER];
 
 extern void refile_buffer(struct buffer_head * buf);
index 80043f478eb4b079f38ecf27c110536133cc9f0b..58a9a5dfc09b414a8fa6817ad09bd32f2589083b 100644 (file)
@@ -88,18 +88,19 @@ struct hd_geometry {
 #define HDIO_GET_MULTCOUNT     0x0304  /* get current IDE blockmode setting */
 #define HDIO_GET_IDENTITY      0x0307  /* get IDE identification info */
 #define HDIO_GET_KEEPSETTINGS  0x0308  /* get keep-settings-on-reset flag */
-#define HDIO_GET_CHIPSET       0x0309  /* get current interface type setting */
+#define HDIO_GET_32BIT                 0x0309  /* get current io_32bit setting */
 #define HDIO_GET_NOWERR                0x030a  /* get ignore-write-error flag */
 #define HDIO_GET_DMA           0x030b  /* get use-dma flag */
 #define HDIO_DRIVE_CMD         0x031f  /* execute a special drive command */
 
 /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
-#define HDIO_SET_MULTCOUNT     0x0321  /* set IDE blockmode */
+#define HDIO_SET_MULTCOUNT     0x0321  /* change IDE blockmode */
 #define HDIO_SET_UNMASKINTR    0x0322  /* permit other irqs during I/O */
 #define HDIO_SET_KEEPSETTINGS  0x0323  /* keep ioctl settings on reset */
-#define HDIO_SET_CHIPSET       0x0324  /* optimise driver for interface type */
-#define HDIO_SET_NOWERR                0x0325  /* set ignore-write-error flag */
-#define HDIO_SET_DMA           0x0326  /* set use-dma flag */
+#define HDIO_SET_32BIT         0x0324  /* change io_32bit flags */
+#define HDIO_SET_NOWERR                0x0325  /* change ignore-write-error flag */
+#define HDIO_SET_DMA           0x0326  /* change use-dma flag */
+#define HDIO_SET_PIO_MODE      0x0327  /* reconfig interface to new speed */
 
 /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
 struct hd_driveid {
index 0cb7f71b8a404d1213e3ae7b7bff63a75639be84..b86c05998f979189ec13f0dd1d74f6c9b19527ca 100644 (file)
 #define                SL_OPT_SIXBIT           2
 #define                SL_OPT_ADAPTIVE         8
 
+/*
+ *     VSV = ioctl for keepalive & outfill in SLIP driver 
+ */
+#define SIOCSKEEPALIVE (SIOCDEVPRIVATE)                /* Set keepalive timeout in sec */
+#define SIOCGKEEPALIVE (SICODEVPRIVATE+1)              /* Get keepalive timeout */
+#define SIOCSOUTFILL   (SIOCDEVPRIVATE+2)              /* Set outfill timeout */
+#define        SIOCGOUTFILL    (SIOCDEVPRIVATE+3)              /* Get outfill timeout */
+
 
 #endif
index 08b9b0be91ea7944294adc8a8e2eecbf488428de..b1ecd0750288466db113940cf619df58952a469d 100644 (file)
@@ -53,8 +53,6 @@ extern inline void start_bh_atomic(void)
 
 extern inline void end_bh_atomic(void)
 {
-       if (intr_count == 1 && (bh_active & bh_mask))
-               do_bottom_half();
        intr_count--;
 }
 
index 8457657c612810bad002d29fcacfc721335380ce..968bf3fd6da44c02030639f548e57028469af7b0 100644 (file)
  *
  * Fixes:
  *     Pauline Middelink       :       Added masquerading.
+ *     Jos Vos                 :       Separate input  and output firewall
+ *                                     chains, new "insert" and "append"
+ *                                     commands to replace "add" commands,
+ *                                     add ICMP header to struct ip_fwpkt.
  *
  *     All the real work was done by .....
  */
@@ -59,23 +63,7 @@ struct ip_fw
 #define IP_FW_MAX_PORTS        10                      /* A reasonable maximum */
        unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
        unsigned long  fw_pcnt,fw_bcnt;         /* Packet and byte counters */
-       unsigned short fw_priority;             /* Revised packet priority */
-};
-
-struct ip_fw_old
-{
-       struct ip_fw  *fw_next;                 /* Next firewall on chain */
-       struct in_addr fw_src, fw_dst;          /* Source and destination IP addr */
-       struct in_addr fw_smsk, fw_dmsk;        /* Mask for src and dest IP addr */
-       struct in_addr fw_via;                  /* IP address of interface "via" */
-       unsigned short fw_flg;                  /* Flags word */
-       unsigned short fw_nsp, fw_ndp;          /* N'of src ports and # of dst ports */
-                                               /* in ports array (dst ports follow */
-                                               /* src ports; max of 10 ports in all; */
-                                               /* count of 0 means match all ports) */
-#define IP_FW_MAX_PORTS        10                      /* A reasonable maximum */
-       unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
-       unsigned long  fw_pcnt,fw_bcnt;         /* Packet and byte counters */
+       unsigned char fw_tosand, fw_tosxor;     /* Revised packet priority */
 };
 
 /*
@@ -105,9 +93,8 @@ struct ip_fw_old
 #define IP_FW_F_ICMPRPL 0x100  /* Send back icmp unreachable packet  */
 #define IP_FW_F_MASQ   0x200   /* Masquerading                       */
 #define IP_FW_F_TCPACK 0x400   /* For tcp-packets match if ACK is set*/
-#define IP_FW_F_APPEND 0x800   /* Dont try to guess placement        */
 
-#define IP_FW_F_MASK   0xFFF   /* All possible flag bits mask        */
+#define IP_FW_F_MASK   0x7FF   /* All possible flag bits mask        */
 
 /*    
  *     New IP firewall options for [gs]etsockopt at the RAW IP level.
@@ -115,25 +102,54 @@ struct ip_fw_old
  *     a raw socket for this. Instead we check rights in the calls.
  */     
 
-#define IP_FW_BASE_CTL   64
-
-#define IP_FW_ADD_BLK    (IP_FW_BASE_CTL)
-#define IP_FW_ADD_FWD    (IP_FW_BASE_CTL+1)   
-#define IP_FW_CHK_BLK    (IP_FW_BASE_CTL+2)
-#define IP_FW_CHK_FWD    (IP_FW_BASE_CTL+3)
-#define IP_FW_DEL_BLK    (IP_FW_BASE_CTL+4)
-#define IP_FW_DEL_FWD    (IP_FW_BASE_CTL+5)
-#define IP_FW_FLUSH_BLK  (IP_FW_BASE_CTL+6)
-#define IP_FW_FLUSH_FWD  (IP_FW_BASE_CTL+7)
-#define IP_FW_ZERO_BLK   (IP_FW_BASE_CTL+8)
-#define IP_FW_ZERO_FWD   (IP_FW_BASE_CTL+9)
-#define IP_FW_POLICY_BLK (IP_FW_BASE_CTL+10)
-#define IP_FW_POLICY_FWD (IP_FW_BASE_CTL+11)
-
-#define IP_ACCT_ADD      (IP_FW_BASE_CTL+16)
-#define IP_ACCT_DEL      (IP_FW_BASE_CTL+17)
-#define IP_ACCT_FLUSH    (IP_FW_BASE_CTL+18)
-#define IP_ACCT_ZERO     (IP_FW_BASE_CTL+19)
+#define IP_FW_BASE_CTL         64      /* base for firewall socket options */
+
+#define IP_FW_COMMAND          0x00FF  /* mask for command without chain */
+#define IP_FW_TYPE             0x0300  /* mask for type (chain) */
+#define IP_FW_SHIFT            8       /* shift count for type (chain) */
+
+#define IP_FW_FWD              0
+#define IP_FW_IN               1
+#define IP_FW_OUT              2
+#define IP_FW_ACCT             3
+
+#define IP_FW_INSERT           (IP_FW_BASE_CTL)
+#define IP_FW_APPEND           (IP_FW_BASE_CTL+1)
+#define IP_FW_DELETE           (IP_FW_BASE_CTL+2)
+#define IP_FW_FLUSH            (IP_FW_BASE_CTL+3)
+#define IP_FW_ZERO             (IP_FW_BASE_CTL+4)
+#define IP_FW_POLICY           (IP_FW_BASE_CTL+5)
+#define IP_FW_CHECK            (IP_FW_BASE_CTL+6)
+
+#define IP_FW_INSERT_FWD       (IP_FW_INSERT | (IP_FW_FWD << IP_FW_SHIFT))
+#define IP_FW_APPEND_FWD       (IP_FW_APPEND | (IP_FW_FWD << IP_FW_SHIFT))
+#define IP_FW_DELETE_FWD       (IP_FW_DELETE | (IP_FW_FWD << IP_FW_SHIFT))
+#define IP_FW_FLUSH_FWD                (IP_FW_FLUSH  | (IP_FW_FWD << IP_FW_SHIFT))
+#define IP_FW_ZERO_FWD         (IP_FW_ZERO   | (IP_FW_FWD << IP_FW_SHIFT))
+#define IP_FW_POLICY_FWD       (IP_FW_POLICY | (IP_FW_FWD << IP_FW_SHIFT))
+#define IP_FW_CHECK_FWD                (IP_FW_CHECK  | (IP_FW_FWD << IP_FW_SHIFT))
+
+#define IP_FW_INSERT_IN                (IP_FW_INSERT | (IP_FW_IN << IP_FW_SHIFT))
+#define IP_FW_APPEND_IN                (IP_FW_APPEND | (IP_FW_IN << IP_FW_SHIFT))
+#define IP_FW_DELETE_IN                (IP_FW_DELETE | (IP_FW_IN << IP_FW_SHIFT))
+#define IP_FW_FLUSH_IN         (IP_FW_FLUSH  | (IP_FW_IN << IP_FW_SHIFT))
+#define IP_FW_ZERO_IN          (IP_FW_ZERO   | (IP_FW_IN << IP_FW_SHIFT))
+#define IP_FW_POLICY_IN                (IP_FW_POLICY | (IP_FW_IN << IP_FW_SHIFT))
+#define IP_FW_CHECK_IN         (IP_FW_CHECK  | (IP_FW_IN << IP_FW_SHIFT))
+
+#define IP_FW_INSERT_OUT       (IP_FW_INSERT | (IP_FW_OUT << IP_FW_SHIFT))
+#define IP_FW_APPEND_OUT       (IP_FW_APPEND | (IP_FW_OUT << IP_FW_SHIFT))
+#define IP_FW_DELETE_OUT       (IP_FW_DELETE | (IP_FW_OUT << IP_FW_SHIFT))
+#define IP_FW_FLUSH_OUT                (IP_FW_FLUSH  | (IP_FW_OUT << IP_FW_SHIFT))
+#define IP_FW_ZERO_OUT         (IP_FW_ZERO   | (IP_FW_OUT << IP_FW_SHIFT))
+#define IP_FW_POLICY_OUT       (IP_FW_POLICY | (IP_FW_OUT << IP_FW_SHIFT))
+#define IP_FW_CHECK_OUT                (IP_FW_CHECK  | (IP_FW_OUT << IP_FW_SHIFT))
+
+#define IP_ACCT_INSERT         (IP_FW_INSERT | (IP_FW_ACCT << IP_FW_SHIFT))
+#define IP_ACCT_APPEND         (IP_FW_APPEND | (IP_FW_ACCT << IP_FW_SHIFT))
+#define IP_ACCT_DELETE         (IP_FW_DELETE | (IP_FW_ACCT << IP_FW_SHIFT))
+#define IP_ACCT_FLUSH          (IP_FW_FLUSH  | (IP_FW_ACCT << IP_FW_SHIFT))
+#define IP_ACCT_ZERO           (IP_FW_ZERO   | (IP_FW_ACCT << IP_FW_SHIFT))
 
 struct ip_fwpkt
 {
@@ -141,6 +157,7 @@ struct ip_fwpkt
        union {
                struct tcphdr fwp_tcph;         /* TCP header or */
                struct udphdr fwp_udph;         /* UDP header */
+               struct icmphdr fwp_icmph;       /* ICMP header */
        } fwp_protoh;
        struct in_addr fwp_via;                 /* interface address */
 };
@@ -171,9 +188,11 @@ extern void ip_fw_masquerade(struct sk_buff **, struct device *);
 extern int ip_fw_demasquerade(struct sk_buff *);
 #endif
 #ifdef CONFIG_IP_FIREWALL
-extern struct ip_fw *ip_fw_blk_chain;
+extern struct ip_fw *ip_fw_in_chain;
+extern struct ip_fw *ip_fw_out_chain;
 extern struct ip_fw *ip_fw_fwd_chain;
-extern int ip_fw_blk_policy;
+extern int ip_fw_in_policy;
+extern int ip_fw_out_policy;
 extern int ip_fw_fwd_policy;
 extern int ip_fw_ctl(int, void *, int);
 #endif
index 3d106e13a4b6f896e7f6fbb43c98b1d73b419301..dfd14116da862486eaa44d32acd12ce4219c067e 100644 (file)
@@ -184,6 +184,7 @@ extern void fat_put_inode(struct inode *inode);
 extern void fat_put_super(struct super_block *sb);
 extern void fat_read_inode(struct inode *inode, struct inode_operations *dir_ops);
 extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent);
+extern void msdos_put_super(struct super_block *sb);
 extern void fat_statfs(struct super_block *sb,struct statfs *buf, int);
 extern void fat_write_inode(struct inode *inode);
 
index 7ded4c4c7e546ffc002c3400c892fd590046bacb..8e7128167fd7432fe0372fd4c8bec78d40bb3303 100644 (file)
@@ -75,7 +75,8 @@ enum net_directory_inos {
        PROC_NET_IPMR_VIF,
        PROC_NET_IPMR_MFC,
        PROC_NET_IPFWFWD,
-       PROC_NET_IPFWBLK,
+       PROC_NET_IPFWIN,
+       PROC_NET_IPFWOUT,
        PROC_NET_IPACCT,
        PROC_NET_IPMSQHST,
        PROC_NET_WAVELAN,
index 0d2261b8af5d682d438216cab6f7cf2a59568702..be9ecf390a069936d563421d7fe1b9dd91341246 100644 (file)
@@ -27,6 +27,9 @@
 #define FREE_READ      1
 #define FREE_WRITE     0
 
+#define CHECKSUM_NONE 0
+#define CHECKSUM_HW 1
+#define CHECKSUM_UNNECESSARY 2
 
 struct sk_buff_head 
 {
index 2cc9576a9294c06fbfc1ec97fba9461c665e0a3f..72984f1541c65903e3d9e9670f2ef65da1f37a91 100644 (file)
@@ -24,7 +24,7 @@ extern volatile unsigned long smp_spins_syscall_cur[];        /* count of syscall spins
 extern volatile unsigned long smp_idle_count[1+NR_CPUS];/* count idle ticks */
 extern volatile unsigned long smp_idle_map;            /* map with idle cpus */
 #else
-exern volatile unsigned long smp_spins;
+extern volatile unsigned long smp_spins;
 #endif
 
 
index a93fa3068fd8663b3a2d24389aeaf7f521827992..ee20a0b12ad4ca8760c4c3eb81fb8ae68bb49a2a 100644 (file)
@@ -71,6 +71,7 @@
 #define SIOCGIFMAP     0x8970          /* Get device parameters        */
 #define SIOCSIFMAP     0x8971          /* Set device parameters        */
 
+
 /* Device private ioctl calls */
 
 /*
index 6051b3d021ec727a3fc11796c284b407522a665b..87da8404e6c4b6e63888c96f54d8d62c08322a5b 100644 (file)
@@ -113,6 +113,8 @@ extern void (* iABI_hook)(struct pt_regs * regs);
 extern int dump_fpu(elf_fpregset_t *);
 #endif
 
+extern void dump_thread(struct pt_regs *, struct user *);
+
 struct symbol_table symbol_table = {
 #include <linux/symtab_begin.h>
 #ifdef MODVERSIONS
@@ -182,6 +184,7 @@ struct symbol_table symbol_table = {
        X(namei),
        X(lnamei),
        X(open_namei),
+       X(sys_close),
        X(close_fp),
        X(check_disk_change),
        X(invalidate_buffers),
@@ -203,7 +206,6 @@ struct symbol_table symbol_table = {
        X(unlock_buffer),
        X(dcache_lookup),
        X(dcache_add),
-       X(aout_core_dump),
        X(add_blkdev_randomness),
        X(generic_file_read),
        X(generic_readpage),
@@ -344,6 +346,12 @@ struct symbol_table symbol_table = {
        /* Socket layer registration */
        X(sock_register),
        X(sock_unregister),
+       /* Socket layer support routines */
+       X(skb_recv_datagram),
+       X(skb_free_datagram),
+       X(skb_copy_datagram),
+       X(skb_copy_datagram_iovec),
+       X(datagram_select),
 #ifdef CONFIG_FIREWALL
        /* Firewall registration */
        X(register_firewall),
@@ -468,6 +476,10 @@ struct symbol_table symbol_table = {
 #ifdef CONFIG_BINFMT_ELF
        X(dump_fpu),
 #endif
+       /* bimfm_aout */
+       X(dump_thread),
+       X(get_write_access),
+       X(put_write_access),
 
        /********************************************************
         * Do not add anything below this line,
index 24dd7d067b63a073f161878307cf0a5e23e466f5..4fe4b07a7fd80dcdcdfa5a13fdb4c67f330f7392 100644 (file)
@@ -261,6 +261,11 @@ asmlinkage void schedule(void)
                printk("Aiee: scheduling in interrupt\n");
                return;
        }
+       if (bh_active & bh_mask) {
+               intr_count = 1;
+               do_bottom_half();
+               intr_count = 0;
+       }
        run_task_queue(&tq_scheduler);
 
        need_resched = 0;
@@ -466,7 +471,7 @@ void sleep_on(struct wait_queue **p)
  * and the sorting routine counts on this..
  */
 static struct timer_list timer_head = { &timer_head, &timer_head, ~0, 0, NULL };
-#define SLOW_BUT_DEBUGGING_TIMERS 1
+#define SLOW_BUT_DEBUGGING_TIMERS 0
 
 void add_timer(struct timer_list * timer)
 {
@@ -516,18 +521,18 @@ int del_timer(struct timer_list * timer)
                        __builtin_return_address(0));
        restore_flags(flags);
        return 0;
-#else  
+#else
+       struct timer_list * next;
+       int ret = 0;
        save_flags(flags);
        cli();
-       if (timer->next) {
-               timer->next->prev = timer->prev;
-               timer->prev->next = timer->next;
+       if ((next = timer->next) != NULL) {
+               (next->prev = timer->prev)->next = next;
                timer->next = timer->prev = NULL;
-               restore_flags(flags);
-               return 1;
+               ret = 1;
        }
        restore_flags(flags);
-       return 0;
+       return ret;
 #endif
 }
 
index 0b239e2659f60568cfd7ba87c5e164ad5249181c..ac7001d9bf765473038e0520f9d8ab9f26b1e869 100644 (file)
@@ -1033,7 +1033,8 @@ static int atalk_getsockopt(struct socket *sock, int level, int optname,
                return err;
        put_user(sizeof(int),optlen);
        err=verify_area(VERIFY_WRITE,optval,sizeof(int));
-       if (err) return err;
+       if (err) 
+               return err;
        put_user(val,optval);
        return(0);
 }
index 1f82ef6b46fe287cf36380ea6e6198c78c3625f0..1ebe258fa44458198098cd13eb707ae17dbc0e97 100644 (file)
@@ -1343,7 +1343,7 @@ int net_dev_init(void)
         *      SLHC if present needs attaching so other people see it
         *      even if not opened.
         */
-#if defined(CONFIG_SLIP_COMPRESSED) || defined(CONFIG_PPP)
+#if (defined(CONFIG_SLIP_COMPRESSED) || defined(CONFIG_PPP)) && defined(CONFIG_SLHC_BUILTIN)
        slhc_install();
 #endif 
 
index f0f1e57d4668c410228d95554552d49dbe56175c..f2363c9e6fa68be9d4e193ab7c25b2107dc2de46 100644 (file)
@@ -51,6 +51,8 @@
  *                                     which caused a "del_timer() called 
  *                                     from %p with timer not initialized\n"
  *                                     message (960131).
+ *             Christian Daudt :       removed del_timer from 
+ *                                     igmp_timer_expire function (960205).
  */
 
 
@@ -259,7 +261,8 @@ static void igmp_timer_expire(unsigned long data)
 {
        struct ip_mc_list *im=(struct ip_mc_list *)data;
        struct ip_router_info *r;
-       igmp_stop_timer(im);
+
+       im->tm_running=0;
        r=igmp_get_mrouter_info(im->interface);
        if(r==NULL)
                return;
index 2b9ed52a4a0fb2ecf5b97f31969080484beb015b..16afa1c168f7edcaeabdc559a0ff9ea931c91904 100644 (file)
@@ -10,6 +10,8 @@
  * Fixes:
  *             Many            :       Split from ip.c , see ip_input.c for history.
  *             Dave Gregorich  :       NULL ip_rt_put fix for multicast routing.
+ *             Jos Vos         :       Add call_out_firewall before sending,
+ *                                     use output device for accounting.
  */
 
 #include <linux/config.h>
@@ -340,8 +342,20 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
 #ifdef CONFIG_IP_MROUTE
                        }                               
 #endif                 
-                       ip_statistics.IpForwDatagrams++;
                }
+#ifdef CONFIG_FIREWALL
+               if((fw_res = call_out_firewall(PF_INET, skb2, iph)) < FW_ACCEPT)
+               {
+                       /* FW_ACCEPT and FW_MASQUERADE are treated equal:
+                          masquerading is only supported via forward rules */
+                       if (fw_res == FW_REJECT)
+                               icmp_send(skb2, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
+                       if (skb != skb2)
+                               kfree_skb(skb2,FREE_WRITE);
+                       return -1;
+               }
+#endif
+               ip_statistics.IpForwDatagrams++;
 
                if (opt->optlen) 
                {
@@ -413,7 +427,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
                         *      Count mapping we shortcut
                         */
                         
-                       ip_fw_chk(iph,dev,ip_acct_chain,IP_FW_F_ACCEPT,1);
+                       ip_fw_chk(iph,dev2,ip_acct_chain,IP_FW_F_ACCEPT,1);
 #endif                 
                        
                        /*
index 78ca5fcffb6e4dd209fb8f4eb3e5b5b2c622f58e..d3a558594461e6033c3b074885da748cb65ec9e5 100644 (file)
  *             Alan Cox 25/8/95, based on information from bugtraq.
  *     ICMP type printk, IP_FW_F_APPEND
  *             Bernd Eckenfels 1996-01-31
+ *     Split blocking chain into input and output chains, add new "insert" and
+ *     "append" commands to replace semi-intelligent "add" command, let "delete".
+ *     only delete the first matching entry, use 0xFFFF (0xFF) as ports (ICMP
+ *     types) when counting packets being 2nd and further fragments.
+ *             Jos Vos <jos@xos.nl> 8/2/1996.
  *
  * Masquerading functionality
  *
  *     Implement IP packet firewall
  */
 
-#ifdef CONFIG_IPFIREWALL_DEBUG 
+#ifdef CONFIG_IP_FIREWALL_DEBUG 
 #define dprintf1(a)            printk(a)
 #define dprintf2(a1,a2)                printk(a1,a2)
 #define dprintf3(a1,a2,a3)     printk(a1,a2,a3)
                                              (ntohl(a)>>8)&0xFF,\
                                              (ntohl(a))&0xFF);
 
-#ifdef IPFIREWALL_DEBUG
+#ifdef CONFIG_IP_FIREWALL_DEBUG
 #define dprint_ip(a)   print_ip(a)
 #else
 #define dprint_ip(a)   
 #endif
 
-#ifdef CONFIG_IP_FIREWALL
+#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
+
 struct ip_fw *ip_fw_fwd_chain;
-struct ip_fw *ip_fw_blk_chain;
-int ip_fw_blk_policy=IP_FW_F_ACCEPT;
-int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
-#endif
-#ifdef CONFIG_IP_ACCT
+struct ip_fw *ip_fw_in_chain;
+struct ip_fw *ip_fw_out_chain;
 struct ip_fw *ip_acct_chain;
-#endif
 
-#define IP_INFO_BLK    0
-#define IP_INFO_FWD    1
-#define IP_INFO_ACCT   2
+static struct ip_fw **chains[] =
+       {&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain};
+
+int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
+int ip_fw_in_policy=IP_FW_F_ACCEPT;
+int ip_fw_out_policy=IP_FW_F_ACCEPT;
+
+static int *policies[] =
+       {&ip_fw_fwd_policy, &ip_fw_in_policy, &ip_fw_out_policy};
+
+#endif
 
 #ifdef CONFIG_IP_MASQUERADE
 /*
@@ -195,11 +205,12 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
        struct udphdr           *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
        struct icmphdr          *icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
        __u32                   src, dst;
-       __u16                   src_port=0, dst_port=0, icmp_type=0;
+       __u16                   src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
        unsigned short          f_prt=0, prt;
        char                    notcpsyn=1, notcpack=1, match;
        unsigned short          offset;
-       int                     answer, priority;
+       int                     answer;
+       unsigned char           tosand, tosxor;
 
        /*
         *      If the chain is empty follow policy. The BSD one
@@ -237,7 +248,7 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
                return FW_BLOCK;
                
        if (offset!=0 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
-                       ip->protocol == IPPROTO_UDP))
+                       ip->protocol == IPPROTO_UDP || ip->protocol == IPPROTO_ICMP))
                return FW_ACCEPT;
                
        /*
@@ -270,7 +281,7 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
        {
                case IPPROTO_TCP:
                        dprintf1("TCP ");
-                       /* ports stay 0 if it is not the first fragment */
+                       /* ports stay 0xFFFF if it is not the first fragment */
                        if (!offset) {
                                src_port=ntohs(tcp->source);
                                dst_port=ntohs(tcp->dest);
@@ -285,7 +296,7 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
                        break;
                case IPPROTO_UDP:
                        dprintf1("UDP ");
-                       /* ports stay 0 if it is not the first fragment */
+                       /* ports stay 0xFFFF if it is not the first fragment */
                        if (!offset) {
                                src_port=ntohs(udp->source);
                                dst_port=ntohs(udp->dest);
@@ -293,7 +304,9 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
                        prt=IP_FW_F_UDP;
                        break;
                case IPPROTO_ICMP:
-                       icmp_type=(__u16)(icmp->type);
+                       /* icmp_type stays 255 if it is not the first fragment */
+                       if (!offset)
+                               icmp_type=(__u16)(icmp->type);
                        dprintf2("ICMP:%d ",icmp_type);
                        prt=IP_FW_F_ICMP;
                        break;
@@ -306,11 +319,11 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
        dprint_ip(ip->saddr);
        
        if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
-               /* This will print 0 when it is not the first fragment! */
+               /* This will print 65535 when it is not the first fragment! */
                dprintf2(":%d ", src_port);
        dprint_ip(ip->daddr);
        if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
-               /* This will print 0 when it is not the first fragment! */
+               /* This will print 65535 when it is not the first fragment! */
                dprintf2(":%d ",dst_port);
        dprintf1("\n");
 #endif 
@@ -372,28 +385,17 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
                if (f_prt!=IP_FW_F_ALL) 
                {
                        /*
-                        * This is actually buggy as if you set SYN flag 
+                        * This is actually buggy as if you set ACK/SYN flags
                         * on UDP or ICMP firewall it will never work,but 
                         * actually it is a concern of software which sets
                         * firewall entries.
                         */
                         
-                        if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
+                       if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
                                continue;
 
-                       /*
-                        * When a bidirectional rule is used we only check
-                        * for ack bits on reverse matches. This way it's
-                        * easy to set up rules which only allow connections
-                        * initiated from "normal" match adresses.
-                        */
-
                        if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
-                               if(f->fw_flg&IP_FW_F_BIDIR) {
-                                       if(match & 0x02)
-                                               continue;
-                               } else
-                                       continue;
+                               continue;
 
                        /*
                         *      Specific firewall - packet's protocol
@@ -422,15 +424,18 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
 #ifdef CONFIG_IP_FIREWALL_VERBOSE
                /*
                 * VERY ugly piece of code which actually
-                * makes kernel printf for denied packets...
+                * makes kernel printf for matching packets...
                 */
 
                if (f->fw_flg & IP_FW_F_PRN)
                {
                        if(opt != 1) {
-                               if(f->fw_flg&IP_FW_F_ACCEPT)
-                                       printk("Accept ");
-                               else if(f->fw_flg&IP_FW_F_ICMPRPL)
+                               if(f->fw_flg&IP_FW_F_ACCEPT) {
+                                       if(f->fw_flg&IP_FW_F_MASQ)
+                                               printk("Masquerade ");
+                                       else
+                                               printk("Accept ");
+                               } else if(f->fw_flg&IP_FW_F_ICMPRPL)
                                        printk("Reject ");
                                else
                                        printk("Deny ");
@@ -443,7 +448,7 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
                                case IPPROTO_UDP:
                                        printk("UDP ");
                                case IPPROTO_ICMP:
-                                       printk("ICMP:%d ",icmp_type);
+                                       printk("ICMP:%d ", icmp_type);
                                        break;
                                default:
                                        printk("p=%d ",ip->protocol);
@@ -478,10 +483,12 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
        if(f!=NULL) 
        {
                policy=f->fw_flg;
-               priority=f->fw_priority;
+               tosand=f->fw_tosand;
+               tosxor=f->fw_tosxor;
        }
        else
-               priority=0xFF00;
+               tosand=0xFF;
+               tosxor=0x00;
 
        if(opt != 1) 
        {
@@ -492,9 +499,9 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int pol
                                answer = FW_REJECT;
        }
 
-       if (answer == 0) { /* Adjust priority and recompute checksum */
+       if (policy&IP_FW_F_ACCEPT) { /* Adjust priority and recompute checksum */
                __u8 old_tos = ip->tos;
-               ip->tos = (old_tos & (priority>>8)) ^ priority;
+               ip->tos = (old_tos & tosand) ^ tosxor;
                if (ip->tos != old_tos)
                        ip_send_check(ip);
        }
@@ -1039,18 +1046,10 @@ static void free_fw_chain(struct ip_fw *volatile* chainptr)
 
 /* Volatiles to keep some of the compiler versions amused */
 
-static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
+static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
 {
        struct ip_fw *ftmp;
-       struct ip_fw *chtmp=NULL;
-       struct ip_fw *volatile chtmp_prev=NULL;
        unsigned long flags;
-       unsigned long m_src_mask,m_dst_mask;
-       unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm;
-       unsigned short n_sr,n_dr,o_sr,o_dr; 
-       unsigned short oldkind,newkind;
-       int addb4=0;
-       int n_o,n_n;
 
        save_flags(flags);
 
@@ -1064,164 +1063,50 @@ static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int
        }
 
        memcpy(ftmp, frwl, len);
-       if (len == sizeof (struct ip_fw_old))
-               ftmp->fw_priority = 0xFF00; /* and_mask, xor_mask */
-
-       ftmp->fw_priority = (ftmp->fw_priority & 0xFFFC) | 0x0300;
+       ftmp->fw_tosand |= 0x03;
+       ftmp->fw_tosxor &= 0xFC;
        ftmp->fw_pcnt=0L;
        ftmp->fw_bcnt=0L;
 
-       ftmp->fw_next = NULL;
-
        cli();
 
-       if (*chainptr==NULL)
-       {
-               *chainptr=ftmp;
-       }
-       else
-       {
-               chtmp_prev=NULL;
-               for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
-               {
-                       if (ftmp->fw_flg & IP_FW_F_APPEND) {
-                               chtmp_prev=chtmp;
-                               continue;
-                       }
-                       addb4=0;
-                       newkind=ftmp->fw_flg & IP_FW_F_KIND;
-                       oldkind=chtmp->fw_flg & IP_FW_F_KIND;
-       
-                       if (newkind!=IP_FW_F_ALL 
-                               &&  oldkind!=IP_FW_F_ALL
-                               &&  oldkind!=newkind) 
-                       {
-                               chtmp_prev=chtmp;
-                               continue;
-                       }
-
-                       /*
-                        *      Very very *UGLY* code...
-                        *      Sorry,but i had to do this....
-                        */
+       ftmp->fw_next = *chainptr;
+               *chainptr=ftmp;
+       restore_flags(flags);
+       return(0);
+}
 
-                       n_sa=ntohl(ftmp->fw_src.s_addr);
-                       n_da=ntohl(ftmp->fw_dst.s_addr);
-                       n_sm=ntohl(ftmp->fw_smsk.s_addr);
-                       n_dm=ntohl(ftmp->fw_dmsk.s_addr);
+static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
+{
+       struct ip_fw *ftmp;
+       struct ip_fw *chtmp=NULL;
+       struct ip_fw *volatile chtmp_prev=NULL;
+       unsigned long flags;
 
-                       o_sa=ntohl(chtmp->fw_src.s_addr);
-                       o_da=ntohl(chtmp->fw_dst.s_addr);
-                       o_sm=ntohl(chtmp->fw_smsk.s_addr);
-                       o_dm=ntohl(chtmp->fw_dmsk.s_addr);
+       save_flags(flags);
 
-                       m_src_mask = o_sm & n_sm;
-                       m_dst_mask = o_dm & n_dm;
+       ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
+       if ( ftmp == NULL ) 
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printk("ip_fw_ctl:  malloc said no\n");
+#endif
+               return( ENOMEM );
+       }
 
-                       if ((o_sa & m_src_mask) == (n_sa & m_src_mask)) 
-                       {
-                               if (n_sm > o_sm) 
-                                       addb4++;
-                               if (n_sm < o_sm) 
-                                       addb4--;
-                       }
+       memcpy(ftmp, frwl, len);
+       ftmp->fw_tosand |= 0x03;
+       ftmp->fw_tosxor &= 0xFC;
+       ftmp->fw_pcnt=0L;
+       ftmp->fw_bcnt=0L;
 
-                       if ((o_da & m_dst_mask) == (n_da & m_dst_mask)) 
-                       {
-                               if (n_dm > o_dm)
-                                       addb4++;
-                               if (n_dm < o_dm)
-                                       addb4--;
-                       }
+       ftmp->fw_next = NULL;
 
-                       if (((o_da & o_dm) == (n_da & n_dm))
-                                       &&((o_sa & o_sm) == (n_sa & n_sm)))
-                       {
-                               if (newkind!=IP_FW_F_ALL &&
-                                       oldkind==IP_FW_F_ALL)
-                                       addb4++;
-                               if (newkind==oldkind && (oldkind==IP_FW_F_TCP
-                                       ||  oldkind==IP_FW_F_UDP)) 
-                               {
+       cli();
 
-                                       /*
-                                        *      Here the main idea is to check the size
-                                        *      of port range which the frwl covers
-                                        *      We actually don't check their values but
-                                        *      just the wideness of range they have
-                                        *      so that less wide ranges or single ports
-                                        *      go first and wide ranges go later. No ports
-                                        *      at all treated as a range of maximum number
-                                        *      of ports.
-                                        */
-
-                                       if (ftmp->fw_flg & IP_FW_F_SRNG) 
-                                               n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0];
-                                       else 
-                                               n_sr=(ftmp->fw_nsp)?
-                                                       ftmp->fw_nsp : 0xFFFF;
-                                               
-                                       if (chtmp->fw_flg & IP_FW_F_SRNG) 
-                                               o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0];
-                                       else 
-                                               o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF;
-
-                                       if (n_sr<o_sr)
-                                               addb4++;
-                                       if (n_sr>o_sr)
-                                               addb4--;
-                                       
-                                       n_n=ftmp->fw_nsp;
-                                       n_o=chtmp->fw_nsp;
-       
-                                       /*
-                                        * Actually this cannot happen as the frwl control
-                                        * procedure checks for number of ports in source and
-                                        * destination range but we will try to be more safe.
-                                        */
-                                        
-                                       if ((n_n>(IP_FW_MAX_PORTS-2)) ||
-                                               (n_o>(IP_FW_MAX_PORTS-2)))
-                                               goto skip_check;
-
-                                       if (ftmp->fw_flg & IP_FW_F_DRNG) 
-                                              n_dr=ftmp->fw_pts[n_n+1]-ftmp->fw_pts[n_n];
-                                       else 
-                                              n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF;
-
-                                       if (chtmp->fw_flg & IP_FW_F_DRNG) 
-                                               o_dr=chtmp->fw_pts[n_o+1]-chtmp->fw_pts[n_o];
-                                       else 
-                                               o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF;
-                                       if (n_dr<o_dr)
-                                               addb4++;
-                                       if (n_dr>o_dr)
-                                               addb4--;
-skip_check:
-                               }
-                               /* finally look at the interface address */
-                               if ((addb4 == 0) && ftmp->fw_via.s_addr &&
-                                               !(chtmp->fw_via.s_addr))
-                                       addb4++;
-                       }
-                       if (addb4>0) 
-                       {
-                               if (chtmp_prev) 
-                               {
-                                       chtmp_prev->fw_next=ftmp; 
-                                       ftmp->fw_next=chtmp;
-                               } 
-                               else 
-                               {
-                                       *chainptr=ftmp;
-                                       ftmp->fw_next=chtmp;
-                               }
-                               restore_flags(flags);
-                               return 0;
-                       }
-                       chtmp_prev=chtmp;
-               }
-       }
+       chtmp_prev=NULL;
+       for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
+               chtmp_prev=chtmp;
        
        if (chtmp_prev)
                chtmp_prev->fw_next=ftmp;
@@ -1255,7 +1140,7 @@ static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
        ltmp=NULL;
        was_found=0;
 
-       while( ftmp != NULL )
+       while( !was_found && ftmp != NULL )
        {
                matches=1;
             if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr 
@@ -1310,7 +1195,7 @@ static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
 struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
 {
 
-       if ( len != sizeof(struct ip_fw) && len != sizeof(struct ip_fw_old))
+       if ( len != sizeof(struct ip_fw) )
        {
 #ifdef DEBUG_CONFIG_IP_FIREWALL
                printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw));
@@ -1382,9 +1267,8 @@ int ip_acct_ctl(int stage, void *m, int len)
                zero_fw_chain(ip_acct_chain);
                return(0);
        }
-       if ( stage == IP_ACCT_ADD
-         || stage == IP_ACCT_DEL
-          )
+       if ( stage == IP_ACCT_INSERT || stage == IP_ACCT_APPEND ||
+                                       stage == IP_ACCT_DELETE )
        {
                struct ip_fw *frwl;
 
@@ -1393,9 +1277,11 @@ int ip_acct_ctl(int stage, void *m, int len)
 
                switch (stage) 
                {
-                       case IP_ACCT_ADD:
-                               return( add_to_chain(&ip_acct_chain,frwl,len));
-                       case IP_ACCT_DEL:
+                       case IP_ACCT_INSERT:
+                               return( insert_in_chain(&ip_acct_chain,frwl,len));
+                       case IP_ACCT_APPEND:
+                               return( append_to_chain(&ip_acct_chain,frwl,len));
+                       case IP_ACCT_DELETE:
                                return( del_from_chain(&ip_acct_chain,frwl));
                        default:
                                /*
@@ -1417,44 +1303,32 @@ int ip_acct_ctl(int stage, void *m, int len)
 #ifdef CONFIG_IP_FIREWALL
 int ip_fw_ctl(int stage, void *m, int len)
 {
-       int ret;
+       int ret, cmd, fwtype;
 
-       if ( stage == IP_FW_FLUSH_BLK )
-       {
-               free_fw_chain(&ip_fw_blk_chain);
-               return(0);
-       }  
-
-       if ( stage == IP_FW_FLUSH_FWD )
-       {
-               free_fw_chain(&ip_fw_fwd_chain);
-               return(0);
-       }  
+       cmd = stage & IP_FW_COMMAND;
+       fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
 
-       if ( stage == IP_FW_ZERO_BLK )
+       if ( cmd == IP_FW_FLUSH )
        {
-               zero_fw_chain(ip_fw_blk_chain);
+               free_fw_chain(chains[fwtype]);
                return(0);
        }  
 
-       if ( stage == IP_FW_ZERO_FWD )
+       if ( cmd == IP_FW_ZERO )
        {
-               zero_fw_chain(ip_fw_fwd_chain);
+               zero_fw_chain(*chains[fwtype]);
                return(0);
        }  
 
-       if ( stage == IP_FW_POLICY_BLK || stage == IP_FW_POLICY_FWD )
+       if ( cmd == IP_FW_POLICY )
        {
                int *tmp_policy_ptr;
                tmp_policy_ptr=(int *)m;
-               if ( stage == IP_FW_POLICY_BLK )
-                       ip_fw_blk_policy=*tmp_policy_ptr;
-               else
-                       ip_fw_fwd_policy=*tmp_policy_ptr;
+               *policies[fwtype] = *tmp_policy_ptr;
                return 0;
        }
 
-       if ( stage == IP_FW_CHK_BLK || stage == IP_FW_CHK_FWD )
+       if ( cmd == IP_FW_CHECK )
        {
                struct device viadev;
                struct ip_fwpkt *ipfwp;
@@ -1483,16 +1357,14 @@ int ip_fw_ctl(int stage, void *m, int len)
 
                viadev.pa_addr = ipfwp->fwp_via.s_addr;
 
-               if ((ret = ip_fw_chk(ip, &viadev,
-                       stage == IP_FW_CHK_BLK ?
-                       ip_fw_blk_chain : ip_fw_fwd_chain,
-                       stage == IP_FW_CHK_BLK ?
-                       ip_fw_blk_policy : ip_fw_fwd_policy, 2 )) > 0
-                  )
+               if ((ret = ip_fw_chk(ip, &viadev, *chains[fwtype],
+                               *policies[fwtype], 2)) == FW_ACCEPT)
                        return(0);
-               else if (ret == -1)     
+               else if (ret == FW_MASQUERADE)  
+                       return(ECONNRESET);
+               else if (ret == FW_REJECT)      
                        return(ECONNREFUSED);
-               else
+               else /* ret == FW_BLOCK */
                        return(ETIMEDOUT);
        }
 
@@ -1501,25 +1373,24 @@ int ip_fw_ctl(int stage, void *m, int len)
  *     to blocking/forwarding chains or deleting 'em
  */
 
-       if ( stage == IP_FW_ADD_BLK || stage == IP_FW_ADD_FWD
-               || stage == IP_FW_DEL_BLK || stage == IP_FW_DEL_FWD
-               )
+       if ( cmd == IP_FW_INSERT || cmd == IP_FW_APPEND || cmd == IP_FW_DELETE )
        {
                struct ip_fw *frwl;
+               int fwtype;
+
                frwl=check_ipfw_struct(m,len);
                if (frwl==NULL)
                        return (EINVAL);
+               fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
                
-               switch (stage
+               switch (cmd
                {
-                       case IP_FW_ADD_BLK:
-                               return(add_to_chain(&ip_fw_blk_chain,frwl,len));
-                       case IP_FW_ADD_FWD:
-                               return(add_to_chain(&ip_fw_fwd_chain,frwl,len));
-                       case IP_FW_DEL_BLK:
-                               return(del_from_chain(&ip_fw_blk_chain,frwl));
-                       case IP_FW_DEL_FWD: 
-                               return(del_from_chain(&ip_fw_fwd_chain,frwl));
+                       case IP_FW_INSERT:
+                               return(insert_in_chain(chains[fwtype],frwl,len));
+                       case IP_FW_APPEND:
+                               return(append_to_chain(chains[fwtype],frwl,len));
+                       case IP_FW_DELETE:
+                               return(del_from_chain(chains[fwtype],frwl));
                        default:
                        /*
                         *      Should be panic but... (Why are BSD people panic obsessed ??)
@@ -1552,19 +1423,24 @@ static int ip_chain_procinfo(int stage, char *buffer, char **start,
        switch(stage)
        {
 #ifdef CONFIG_IP_FIREWALL
-               case IP_INFO_BLK:
-                       i = ip_fw_blk_chain;
-                       len=sprintf(buffer, "IP firewall block rules, default %d\n",
-                               ip_fw_blk_policy);
+               case IP_FW_IN:
+                       i = ip_fw_in_chain;
+                       len=sprintf(buffer, "IP firewall input rules, default %d\n",
+                               ip_fw_in_policy);
+                       break;
+               case IP_FW_OUT:
+                       i = ip_fw_out_chain;
+                       len=sprintf(buffer, "IP firewall output rules, default %d\n",
+                               ip_fw_out_policy);
                        break;
-               case IP_INFO_FWD:
+               case IP_FW_FWD:
                        i = ip_fw_fwd_chain;
                        len=sprintf(buffer, "IP firewall forward rules, default %d\n",
                                ip_fw_fwd_policy);
                        break;
 #endif
 #ifdef CONFIG_IP_ACCT
-               case IP_INFO_ACCT:
+               case IP_FW_ACCT:
                        i = ip_acct_chain;
                        len=sprintf(buffer,"IP accounting rules\n");
                        break;
@@ -1589,7 +1465,7 @@ static int ip_chain_procinfo(int stage, char *buffer, char **start,
                        i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
                for (p = 0; p < IP_FW_MAX_PORTS; p++)
                        len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
-               len+=sprintf(buffer+len, " M%04X", i->fw_priority);
+               len+=sprintf(buffer+len, " A%02X X%02X", i->fw_tosand, i->fw_tosxor);
                buffer[len++]='\n';
                buffer[len]='\0';
                pos=begin+len;
@@ -1622,7 +1498,7 @@ static int ip_chain_procinfo(int stage, char *buffer, char **start,
 static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
                            int length, int reset)
 {
-       return ip_chain_procinfo(IP_INFO_ACCT, buffer,start, offset,length,
+       return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length,
                                 reset);
 }
 
@@ -1630,17 +1506,24 @@ static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
 
 #ifdef CONFIG_IP_FIREWALL
 
-static int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset,
+static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset,
                              int length, int reset)
 {
-       return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,
+       return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length,
+                                reset);
+}
+
+static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset,
+                             int length, int reset)
+{
+       return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length,
                                 reset);
 }
 
 static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
                              int length, int reset)
 {
-       return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,
+       return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length,
                                 reset);
 }
 #endif
@@ -1655,7 +1538,7 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
        unsigned long flags;
        int len=0;
        
-       len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq Delta PDelta Expires\n"); 
+       len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires\n"); 
        save_flags(flags);
        cli();
        
@@ -1665,7 +1548,7 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
                int timer_active = del_timer(&ms->timer);
                if (!timer_active)
                        ms->timer.expires = jiffies;
-               len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %5d %lu\n",
+               len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n",
                        strProt[ms->protocol==IPPROTO_TCP],
                        ntohl(ms->src),ntohs(ms->sport),
                        ntohl(ms->dst),ntohs(ms->dport),
@@ -1701,7 +1584,12 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
  
 int ipfw_input_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
 {
-       return ip_fw_chk(phdr, skb->dev, ip_fw_blk_chain, ip_fw_blk_policy, 0);
+       return ip_fw_chk(phdr, skb->dev, ip_fw_in_chain, ip_fw_in_policy, 0);
+}
+
+int ipfw_output_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
+{
+       return ip_fw_chk(phdr, skb->dev, ip_fw_out_chain, ip_fw_out_policy, 0);
 }
 
 int ipfw_forward_check(struct firewall_ops *this, int pf, struct sk_buff *skb, void *phdr)
@@ -1714,7 +1602,7 @@ struct firewall_ops ipfw_ops=
        NULL,
        ipfw_forward_check,
        ipfw_input_check,
-       ipfw_input_check,
+       ipfw_output_check,
        PF_INET,
        0       /* We don't even allow a fall through so we are last */
 };
@@ -1737,10 +1625,16 @@ void ip_fw_init(void)
                panic("Unable to register IP firewall.\n");
                
        proc_net_register(&(struct proc_dir_entry) {
-               PROC_NET_IPFWBLK, 8, "ip_block",
+               PROC_NET_IPFWIN, 8, "ip_input",
+               S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+               0, &proc_net_inode_operations,
+               ip_fw_in_procinfo
+       });
+       proc_net_register(&(struct proc_dir_entry) {
+               PROC_NET_IPFWOUT, 9, "ip_output",
                S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
                0, &proc_net_inode_operations,
-               ip_fw_blk_procinfo
+               ip_fw_out_procinfo
        });
        proc_net_register(&(struct proc_dir_entry) {
                PROC_NET_IPFWFWD, 10, "ip_forward",
index 560ac9cb9e064859b1599158933ec8f6156be135..7bb3a71bed434e5e8c35d4c8560d6955e4f7d3a2 100644 (file)
@@ -95,6 +95,7 @@
  *             Alan Cox        :       Outgoing firewall on build_xmit
  *             A.N.Kuznetsov   :       IP_OPTIONS support throughout the kernel
  *             Alan Cox        :       Multicast routing hooks
+ *             Jos Vos         :       Do accounting *before* call_in_firewall
  *
  *  
  *
@@ -286,11 +287,20 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 #endif
 
        /*
-        *      See if the firewall wants to dispose of the packet. 
+        *      Account for the packet (even if the packet is
+        *      not accepted by the firewall!).
         */
 
-#ifdef CONFIG_FIREWALL
+#ifdef CONFIG_IP_ACCT
+       ip_fw_chk(iph,dev,ip_acct_chain,IP_FW_F_ACCEPT,1);
+#endif 
+
+       /*
+        *      See if the firewall wants to dispose of the packet. 
+        */
        
+#ifdef CONFIG_FIREWALL
+
        if ((err=call_in_firewall(PF_INET, skb, iph))<FW_ACCEPT)
        {
                if(err==FW_REJECT)
@@ -422,14 +432,6 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                }
 #endif
 
-               /*
-                *      Account for the packet
-                */
-#ifdef CONFIG_IP_ACCT
-               ip_fw_chk(iph,dev,ip_acct_chain,IP_FW_F_ACCEPT,1);
-#endif 
-
                /*
                 *      Reassemble IP fragments.
                 */
index a2a871a25227e2178e3436c6050d5244b80f8692..3937434c580d8d1372d4e9e2332c7753416745dd 100644 (file)
@@ -715,7 +715,7 @@ int ip_build_xmit(struct sock *sk,
                }
 #endif
 #ifdef CONFIG_IP_ACCT
-               ip_fw_chk((void *)skb->data,dev,ip_acct_chain, IP_FW_F_ACCEPT,1);
+               ip_fw_chk(iph,dev,ip_acct_chain, IP_FW_F_ACCEPT,1);
 #endif         
                if(dev->flags&IFF_UP)
                        dev_queue_xmit(skb,dev,sk->priority);
index 82d057be86f77aeec6b85fe787463791210df096..4c1c552435c9a596362a6566aa2b85fde5ecb2fa 100644 (file)
@@ -366,17 +366,26 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                }
 #endif                 
 #ifdef CONFIG_IP_FIREWALL
-               case IP_FW_ADD_BLK:
-               case IP_FW_DEL_BLK:
-               case IP_FW_ADD_FWD:
-               case IP_FW_DEL_FWD:
-               case IP_FW_CHK_BLK:
-               case IP_FW_CHK_FWD:
-               case IP_FW_FLUSH_BLK:
+               case IP_FW_INSERT_IN:
+               case IP_FW_INSERT_OUT:
+               case IP_FW_INSERT_FWD:
+               case IP_FW_APPEND_IN:
+               case IP_FW_APPEND_OUT:
+               case IP_FW_APPEND_FWD:
+               case IP_FW_DELETE_IN:
+               case IP_FW_DELETE_OUT:
+               case IP_FW_DELETE_FWD:
+               case IP_FW_CHECK_IN:
+               case IP_FW_CHECK_OUT:
+               case IP_FW_CHECK_FWD:
+               case IP_FW_FLUSH_IN:
+               case IP_FW_FLUSH_OUT:
                case IP_FW_FLUSH_FWD:
-               case IP_FW_ZERO_BLK:
+               case IP_FW_ZERO_IN:
+               case IP_FW_ZERO_OUT:
                case IP_FW_ZERO_FWD:
-               case IP_FW_POLICY_BLK:
+               case IP_FW_POLICY_IN:
+               case IP_FW_POLICY_OUT:
                case IP_FW_POLICY_FWD:
                        if(!suser())
                                return -EPERM;
@@ -391,8 +400,9 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                        
 #endif
 #ifdef CONFIG_IP_ACCT
-               case IP_ACCT_DEL:
-               case IP_ACCT_ADD:
+               case IP_ACCT_INSERT:
+               case IP_ACCT_APPEND:
+               case IP_ACCT_DELETE:
                case IP_ACCT_FLUSH:
                case IP_ACCT_ZERO:
                        if(!suser())
index 778a94498b7cb6330d4d926a2a04e7ada329568a..58d58e07960419ab5446a31c8a44bb817a8635aa 100644 (file)
@@ -1988,7 +1988,7 @@ static int tcp_sendmsg(struct sock *sk, struct msghdr *msg,
                 */
                 
                        send_tmp = NULL;
-                       if (copy < sk->mss && !(flags & MSG_OOB)) 
+                       if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out
                        {
                                /*
                                 *      We will release the socket in case we sleep here. 
@@ -2105,7 +2105,7 @@ static int tcp_sendmsg(struct sock *sk, struct msghdr *msg,
                        skb->free = 0;
                        sk->write_seq += copy;
                
-                       if (send_tmp != NULL && sk->packets_out
+                       if (send_tmp != NULL) 
                        {
                                tcp_enqueue_partial(send_tmp, sk);
                                continue;
@@ -2230,32 +2230,33 @@ static void tcp_read_wakeup(struct sock *sk)
 static void cleanup_rbuf(struct sock *sk)
 {
        unsigned long flags;
-       unsigned long left;
        struct sk_buff *skb;
        unsigned long rspace;
 
-       if(sk->debug)
-               printk("cleaning rbuf for sk=%p\n", sk);
-  
        save_flags(flags);
        cli();
-  
-       left = sock_rspace(sk);
+
+       /*
+        * See if we have anything to free up?
+        */
+
+       skb = skb_peek(&sk->receive_queue);
+       if (!skb || !skb->used || skb->users) {
+               restore_flags(flags);
+               return;
+       }
+
        /*
         *      We have to loop through all the buffer headers,
         *      and try to free up all the space we can.
         */
 
-       while((skb=skb_peek(&sk->receive_queue)) != NULL) 
-       {
-               if (!skb->used || skb->users) 
-                       break;
+       do {
                skb_unlink(skb);
                skb->sk = sk;
                kfree_skb(skb, FREE_READ);
-       }
-
+               skb = skb_peek(&sk->receive_queue);
+       } while (skb && skb->used && !skb->users);
        restore_flags(flags);
 
        /*
@@ -2265,22 +2266,21 @@ static void cleanup_rbuf(struct sock *sk)
         *      TCP_WINDOW_DIFF.
         */
 
+       rspace=sock_rspace(sk);
        if(sk->debug)
-               printk("sk->rspace = %lu, was %lu\n", sock_rspace(sk),
-                                           left);
-       if ((rspace=sock_rspace(sk)) != left) 
-       {
-               /*
-                * This area has caused the most trouble.  The current strategy
-                * is to simply do nothing if the other end has room to send at
-                * least 3 full packets, because the ack from those will auto-
-                * matically update the window.  If the other end doesn't think
-                * we have much space left, but we have room for at least 1 more
-                * complete packet than it thinks we do, we will send an ack
-                * immediately.  Otherwise we will wait up to .5 seconds in case
-                * the user reads some more.
-                */
-               sk->ack_backlog++;
+               printk("sk->rspace = %lu\n", rspace);
+       /*
+        * This area has caused the most trouble.  The current strategy
+        * is to simply do nothing if the other end has room to send at
+        * least 3 full packets, because the ack from those will auto-
+        * matically update the window.  If the other end doesn't think
+        * we have much space left, but we have room for at least 1 more
+        * complete packet than it thinks we do, we will send an ack
+        * immediately.  Otherwise we will wait up to .5 seconds in case
+        * the user reads some more.
+        */
+       sk->ack_backlog++;
+
        /*
         * It's unclear whether to use sk->mtu or sk->mss here.  They differ only
         * if the other end is offering a window smaller than the agreed on MSS
@@ -2290,22 +2290,21 @@ static void cleanup_rbuf(struct sock *sk)
         * only on the send side, so I'm putting mtu here.
         */
 
-               if (rspace > (sk->window - sk->bytes_rcv + sk->mtu)) 
+       if (rspace > (sk->window - sk->bytes_rcv + sk->mtu)) 
+       {
+               /* Send an ack right now. */
+               tcp_read_wakeup(sk);
+       } 
+       else 
+       {
+               /* Force it to send an ack soon. */
+               int was_active = del_timer(&sk->retransmit_timer);
+               if (!was_active || jiffies+TCP_ACK_TIME < sk->timer.expires) 
                {
-                       /* Send an ack right now. */
-                       tcp_read_wakeup(sk);
+                       reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
                } 
-               else 
-               {
-                       /* Force it to send an ack soon. */
-                       int was_active = del_timer(&sk->retransmit_timer);
-                       if (!was_active || jiffies+TCP_ACK_TIME < sk->timer.expires) 
-                       {
-                               reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
-                       } 
-                       else
-                               add_timer(&sk->retransmit_timer);
-               }
+               else
+                       add_timer(&sk->retransmit_timer);
        }
 } 
 
@@ -4180,7 +4179,7 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
  *     room, then we will just have to discard the packet.
  */
 
-extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk, 
+extern /* __inline__ */ int tcp_data(struct sk_buff *skb, struct sock *sk, 
         unsigned long saddr, unsigned short len)
 {
        struct sk_buff *skb1, *skb2;
@@ -4798,44 +4797,14 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
        return(0);
 }
 
-
 /*
- *     This functions checks to see if the tcp header is actually acceptable. 
+ * React to a out-of-window TCP sequence number in an incoming packet
  */
-extern __inline__ int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
+static void bad_tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
             struct options *opt, unsigned long saddr, struct device *dev)
 {
-       u32 next_seq;
-
-       next_seq = len - 4*th->doff;
-       if (th->fin)
-               next_seq++;
-       /* if we have a zero window, we can't have any data in the packet.. */
-       if (next_seq && !sk->window)
-               goto ignore_it;
-       next_seq += ntohl(th->seq);
-
-       /*
-        * This isn't quite right.  sk->acked_seq could be more recent
-        * than sk->window.  This is however close enough.  We will accept
-        * slightly more packets than we should, but it should not cause
-        * problems unless someone is trying to forge packets.
-        */
-
-       /* have we already seen all of this packet? */
-       if (!after(next_seq+1, sk->acked_seq))
-               goto ignore_it;
-       /* or does it start beyond the window? */
-       if (!before(ntohl(th->seq), sk->acked_seq + sk->window + 1))
-               goto ignore_it;
-
-       /* ok, at least part of this packet would seem interesting.. */
-       return 1;
-
-ignore_it:
        if (th->rst)
-               return 0;
+               return;
 
        /*
         *      Send a reset if we get something not ours and we are
@@ -4847,12 +4816,24 @@ ignore_it:
        if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) 
        {
                tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
-               return 1;
+               return;
        }
 
        /* Try to resync things. */
        tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
-       return 0;
+       return;
+}
+
+/*
+ *     This functions checks to see if the tcp header is actually acceptable. 
+ */
+extern __inline__ int tcp_sequence(struct sock *sk, u32 seq, u32 end_seq)
+{
+       /* does the packet contain any unseen data AND */
+       /* does the packet start before the window? */
+       return  after(end_seq+1, sk->acked_seq) &&
+               before(seq, sk->acked_seq + sk->window + 1);
 }
 
 /*
@@ -4887,6 +4868,29 @@ static int tcp_std_reset(struct sock *sk, struct sk_buff *skb)
        return(0);
 }
 
+/*
+ *     Find the socket, using the last hit cache if applicable.
+ */
+static inline struct sock * get_tcp_sock(u32 saddr, u16 sport, u32 daddr, u16 dport)
+{
+       struct sock * sk;
+
+       sk = (struct sock *) th_cache_sk;
+       if (saddr != th_cache_saddr || daddr != th_cache_daddr ||
+           sport != th_cache_sport || dport != th_cache_dport) {
+               sk = get_sock(&tcp_prot, dport, saddr, sport, daddr);
+               if (sk) {
+                       th_cache_saddr=saddr;
+                       th_cache_daddr=daddr;
+                       th_cache_dport=dport;
+                       th_cache_sport=sport;
+                       th_cache_sk=sk;
+               }
+       }
+       return sk;
+}
+
+
 /*
  *     A TCP packet has arrived.
  *             skb->h.raw is the TCP header.
@@ -4900,52 +4904,21 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        struct sock *sk;
        int syn_ok=0;
 
-       tcp_statistics.TcpInSegs++;
-       if(skb->pkt_type!=PACKET_HOST)
-       {
-               kfree_skb(skb,FREE_READ);
-               return(0);
-       }
-  
-       th = skb->h.th;
-
        /*
-        *      Find the socket, using the last hit cache if applicable.
+        * "redo" is 1 if we have already seen this skb but couldn't
+        * use it at that time (the socket was locked).  In that case
+        * we have already done a lot of the work (looked up the socket
+        * etc).
         */
-
-       if(!redo && saddr==th_cache_saddr && daddr==th_cache_daddr && th->dest==th_cache_dport && th->source==th_cache_sport)
-       {
-               sk=(struct sock *)th_cache_sk;
-               /*
-                *      We think this is causing the bug so
-                */
-                if(sk!=get_sock(&tcp_prot,th->dest, saddr, th->source, daddr))
-                       printk("Cache mismatch on TCP.\n");
-       }
-       else
-       {
-               sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
-               th_cache_saddr=saddr;
-               th_cache_daddr=daddr;
-               th_cache_dport=th->dest;
-               th_cache_sport=th->source;
-               th_cache_sk=sk;
-       }               
-
-       /*
-        *      If this socket has got a reset it's to all intents and purposes 
-        *      really dead. Count closed sockets as dead.
-        *
-        *      Note: BSD appears to have a bug here. A 'closed' TCP in BSD
-        *      simply drops data. This seems incorrect as a 'closed' TCP doesn't
-        *      exist so should cause resets as if the port was unreachable.
-        */
-        
-       if (sk!=NULL && (sk->zapped || sk->state==TCP_CLOSE))
-               sk=NULL;
-
-       if (!redo) 
-       {
+       th = skb->h.th;
+       sk = skb->sk;
+       if (!redo) {
+               tcp_statistics.TcpInSegs++;
+               if (skb->pkt_type!=PACKET_HOST)
+               {
+                       kfree_skb(skb,FREE_READ);
+                       return(0);
+               }
                /*
                 *      Pull up the IP header.
                 */
@@ -4954,8 +4927,9 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                 *      Try to use the device checksum if provided.
                 */
                if (
-                       (skb->ip_summed && tcp_check(th, len, saddr, daddr, skb->csum ))||
-                       (!skb->ip_summed && tcp_check(th, len, saddr, daddr, csum_partial((char *)th, len, 0)))
+                       ((skb->ip_summed == CHECKSUM_HW) && tcp_check(th, len, saddr, daddr, skb->csum ))||
+                       ((skb->ip_summed == CHECKSUM_NONE) && tcp_check(th, len, saddr, daddr, csum_partial((char *)th, len, 0)))
+                   /* skip if CHECKSUM_UNNECESSARY */
                    )
                {
                        skb->sk = NULL;
@@ -4966,26 +4940,14 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                         */
                        return(0);
                }
-
+               sk = get_tcp_sock(saddr, th->source, daddr, th->dest);
+               if (!sk)
+                       goto no_tcp_socket;
+               skb->sk = sk;
                skb->seq = ntohl(th->seq);
                skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4;
                skb->ack_seq = ntohl(th->ack_seq);
 
-               /* See if we know about the socket. */
-               if (sk == NULL) 
-               {
-                       /*
-                        *      No such TCB. If th->rst is 0 send a reset (checked in tcp_reset)
-                        */
-                       tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
-                       skb->sk = NULL;
-                       /*
-                        *      Discard frame
-                        */
-                       kfree_skb(skb, FREE_READ);
-                       return(0);
-               }
-
                skb->acked = 0;
                skb->used = 0;
                skb->free = 0;
@@ -5003,17 +4965,18 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                sk->inuse = 1;
                sti();
        }
-       else
-       {
-               if (sk==NULL) 
-               {
-                       tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
-                       skb->sk = NULL;
-                       kfree_skb(skb, FREE_READ);
-                       return(0);
-               }
-       }
 
+       /*
+        *      If this socket has got a reset it's to all intents and purposes 
+        *      really dead. Count closed sockets as dead.
+        *
+        *      Note: BSD appears to have a bug here. A 'closed' TCP in BSD
+        *      simply drops data. This seems incorrect as a 'closed' TCP doesn't
+        *      exist so should cause resets as if the port was unreachable.
+        */
+
+       if (sk->zapped || sk->state==TCP_CLOSE)
+               goto no_tcp_socket;
 
        if (!sk->prot) 
        {
@@ -5223,8 +5186,9 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
         *      I have time to test it hard and look at what gcc outputs 
         */
        
-       if(!tcp_sequence(sk,th,len,opt,saddr,dev))
+       if (!tcp_sequence(sk, skb->seq, skb->end_seq))
        {
+               bad_tcp_sequence(sk, th, len, opt, saddr, dev);
                kfree_skb(skb, FREE_READ);
                release_sock(sk);
                return 0;
@@ -5344,6 +5308,18 @@ rfc_step6:               /* I'll clean this up later */
        
        release_sock(sk);
        return 0;
+
+no_tcp_socket:
+       /*
+        *      No such TCB. If th->rst is 0 send a reset (checked in tcp_reset)
+        */
+       tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
+       skb->sk = NULL;
+       /*
+        *      Discard frame
+        */
+       kfree_skb(skb, FREE_READ);
+       return 0;
 }
 
 /*
index 99f8cd94f2eedb45437e64138975145bc7bcf45b..dd0eda4c2793863c18165cf83fefc05fbae1521a 100644 (file)
@@ -633,8 +633,9 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        /* (That's the Right Place to do it, IMHO.) -- MS */
 
        if (uh->check && (
-               ( skb->ip_summed && udp_check(uh, len, saddr, daddr, skb->csum ) ) ||
-               ( !skb->ip_summed && udp_check(uh, len, saddr, daddr,csum_partial((char*)uh, len, 0)))
+               ( (skb->ip_summed == CHECKSUM_HW) && udp_check(uh, len, saddr, daddr, skb->csum ) ) ||
+               ( (skb->ip_summed == CHECKSUM_NONE) && udp_check(uh, len, saddr, daddr,csum_partial((char*)uh, len, 0)))
+                         /* skip if CHECKSUM_UNNECESSARY */
                         )
           )
        {
index 27449d5605b671f2c04c3d77e844b88a27f2aa69..970097e1d0db8976c29bee3e2cf16ace24031cb0 100644 (file)
@@ -2162,7 +2162,7 @@ static struct proto_ops ipx_proto_ops = {
        ipx_recvmsg
 };
 
-/* Called by ddi.c on kernel start up */
+/* Called by protocol.c on kernel start up */
 
 static struct packet_type ipx_8023_packet_type = 
 
index 35b5c742719f27df3d53f1596b1e9dce327d9217..278693ca4fe62cda6b485057bc941b831f71c3c4 100644 (file)
@@ -771,6 +771,7 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                                sk->protinfo.af_unix.other=NULL;
                                sock->state=SS_UNCONNECTED;
                                sti();
+                               kfree_skb(skb, FREE_WRITE);
                                if(!sent)
                                        return -ECONNRESET;
                                else
@@ -783,8 +784,8 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                        other=unix_find_other(sunaddr->sun_path, &err);
                        if(other==NULL)
                        {
-                               kfree_skb(skb, FREE_WRITE);
                                sti();
+                               kfree_skb(skb, FREE_WRITE);
                                if(sent)
                                        return sent;
                                else
index 959672ea67f6846cec2b9d4cf305f95bb0cb9880..c3ed3b8bc1578ea062bf4a8adf01e768389b3199 100644 (file)
@@ -211,7 +211,7 @@ function dep_tristate () {
        if [ "$3" != "m" ]; then
                tristate "$1" "$2"
        else
-           if [ "$MODULES" = "y" ]; then
+           if [ "$CONFIG_MODULES" = "y" ]; then
                case "$def" in
                 "y" | "m") defprompt="M/n/?"
                      def="m"
index d4b475b929a0bb1e698d8b2359856afe92cf44b6..6072f2f436b944296536c774fbab7dace4f1974e 100644 (file)
@@ -12,10 +12,15 @@ ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h)
         CFLAGS += -I/usr/include/ncurses
         CURSES =  -DCURSES_LOC="<ncurses.h>"
 else
+ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
+        CFLAGS += -I/usr/include/ncurses
+        CURSES =  -DCURSES_LOC="<curses.h>"
+else
 ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
         CURSES =  -DCURSES_LOC="<ncurses.h>"
 endif
 endif
+endif
 
 OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \
        util.o lxdialog.o msgbox.o
index 2d637501d60e72e6cd207022d7e16bd70c35e231..85f5b5115f09b63360776ca7c71eb64e8d02fc98 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  *  dialog.h -- common declarations for all dialog modules
  *
@@ -27,7 +28,6 @@
 
 #include CURSES_LOC
 
-
 #define ESC 27
 #define TAB 9
 #define MAX_LEN 2048
index ea58ff86869849c1dbaaf2a93e3b32aaf934b893..316d0b859f56d8279f4c5c788527c8f56b49010c 100644 (file)
@@ -432,7 +432,11 @@ static end_proc(int menu_num, int first, int last)
   printf("\tglobal winx; global winy\n");
   printf("\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n");
   printf("\twm geometry $w +$winx+$winy\n");
-  printf("\twm resizable $w no yes\n\n");
+  /*
+   *   We have a cunning plan....
+   */
+  if(access("/usr/lib/tk4.0",0)==0)
+         printf("\twm resizable $w no yes\n\n");
   
   /*
    * Now that the whole window is in place, we need to wait for an "update"