aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cs.Helsinki.FI>1993-07-18 20:13:34 -0400
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:16 -0400
commit46db5850d3c10ede04f645bd1e8bd7bcbc65acb9 (patch)
tree93499a7b1d8f367c47ed9bb1ed7cb285235ec490
parentd3465417f56e99c858e0bc136e63aa67e6ef90bf (diff)
downloadarchive-46db5850d3c10ede04f645bd1e8bd7bcbc65acb9.tar.gz
[ANNOUNCE]: linux 0.99 patchlevel 11v0.99-pl11
Nic.funet.fi now contains the newest linux kernel: this is 0.99 patchlevel 11. I've had a few problems with the "ls" and "dir" commands on nic, so if this is true for others as well, you may not be able to see the files, but they are available as: pub/OS/Linux/PEOPLE/Linus: - RELEASE-0.99.11 -- release notes - README -- same as RELEASE.. - linux-0.99.11.tar.gz -- full sources - linux-0.99.patch11.gz -- patches against pl10 I don't know if I'll actually have the energy to update the RELEASE files every time, but that's the idea (with README being a copy of the latest one). The README gives info on what changed, how to install it, how to compile the kernel, and what to do with error dumps like "unable to handler kernel paging request" and the like. Maybe it results in better bug-reports. Maybe not. Pl11 uses (as you all know by now) C++, so you'll need to have g++ installed. Also, there seems to be problems compiling the newer kernels with gcc-2.3.3: there have been various reports that even pl10 (which isn't C++) had problems which go away when compiled with gcc-2.4.3 or newer. As always, please send any bug-reports etc at least Cc'd to me: I'll be wanting to know if things work or not. Linus <RELEASE-0.99.11> Linux kernel release 0.99 patchlevel 11 These are the release notes for linux version 0.99.11. Read them carefully, as they explain how to install the kernel, and what to do if something goes wrong. CHANGES since 0.99 patchlevel 10 and earlier: - The keyboard is dynamically changeable (this is true of pl10 as well), and you need to get the "keytables.tar.z" archive to set the keyboard to suit your taske unless you want to live with the default US keymaps. Use the "loadkeys map/xxx.map" command to load the keyboard map: you can edit the maps to suit yourself if you can't find a suitable one. The syntax of the keyboard maps should be obvious after looking at the examples. - The memory manager has been cleaned up substantially, and mmap() works for MAP_PRIVATE. MAP_SHARED is still not supported for anything else than /dev/mem, but even so it actually is usable for a lot of applications. The shared library routines have been rewritten to use mmap() instead of the old hardcoded behaviour. - The kernel is now compiled with C++ instead of plain C. Very few actual C++ features are used, but even so C++ allows for more type-checking and type-safe linkage. - The filesystem routines have been cleaned up for multiple block sizes. None of the filesystems use it yet, but people are working on it. - named pipes and normal pipes should hopefully have the right select() semantics in the presense/absense of writers. - QIC-02 tape driver by Hennus Bergman - selection patches in the default kernel - fixed a bug in the pty code which led to busy waiting in some circumstances instead of sleeping. - Compressed SLIP support (Charles Hedrick). See net/inet/CONFIG INTERNAL kernel changes: - the 'clear_bit()' function was changed to return the previous setting of the bit instead of the old "error-code". This makes use of the bit operations more logical. - udelay() function for short delays (busy-waiting) added. Used currently only by the QIC driver. - fork() and sheduler changes to make task switches happen only from kernel mode to kernel mode. Cleaner and more portable than the old code which counted on being able to task-switch directly into user mode. - debugging malloc code. INSTALLING the kernel: - if you install by patching, you need a *clean* 0.99.10 source tree, which presumably exists in /usr/src/linux. If so, to get the kernel patched, just do a cd /usr/src patch -p0 < linux-0.99.patch11 and you should be ok. You may want to remove the backup files (xxx~ or xxx.orig), and make sure that there are no failed patches (xxx# or xxx.rej). - If you install the full sources, do a cd /usr/src tar xvf linux-0.99.11.tar to get it all put in place. - make sure your /usr/include/linux and /usr/include/asm directories are just symlinks to the kernel sources: cd /usr/include rm -rf linux rm -rf asm ln -s /usr/src/linux/include/linux . ln -s /usr/src/linux/include/asm . - make sure you have no stale .o files and dependencies lying around: cd /usr/src/linux make mrproper make dep You should now have the sources correctly installed. CONFIGURING the kernel: - do a "make config" to configure the basic kernel. "make config" needs bash to work: it will search for bash in $BASH, /bin/bash and /bin/sh (in that order), so hopefully one of those is correct. - edit net/inet/CONFIG to configure the networking parts of the kernel. The comments should hopefully clarify it all. - Check the top Makefile for further site-dependent configuration (default SVGA mode etc). COMPILING the kernel: - make sure you have gcc-2.4.3 or newer available with g++. It seems older gcc versions can have problems compiling linux 0.99.10 and newer versions. If you upgrade, remember to get the new binutils package too (for as/ld/nm and company) - do a "make zImage" to create a compressed kernel image. If you want to make a bootdisk (without root filesystem or lilo), insert a floppy in your A: drive, and do a "make zdisk". It is also possible to do "make zlilo" if you have lilo installed to suit the kernel makefiles, but you may want to check your particular lilo setup first. - keep a backup kernel handy in case something goes wrong. - reboot with the new kernel. IF SOMETHING GOES WRONG: - if you have problems that seem to be due to kernel bugs, please mail them to me (Linus.Torvalds@Helsinki.FI), and possibly to any other relevant mailing-list or to the newsgroup. The mailing-lists are useful especially for SCSI and NETworking problems, as I can't test either of those personally anyway. - In all bug-reports, *please* tell what kernel you are talking about, how to duplicate the problem, and what your setup is (use your common sense). If the problem is new, tell me so, and if the problem is old, please try to tell me when you first noticed it. - if the bug results in a message like unable to handle kernel paging request at address C0000010 Oops: 0002 EIP: 0010:xxxxxxxx eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx ds: xxxx es: xxxx fs: xxxx gs: xxxx Pid: xx, process nr: xx xx xx xx xx xx xx xx xx xx xx or similar kernel debugging information on your screen or in your system log, please duplicate it *exactly*. The dump may look incomprehensible to you, but it does contain information that may help debugging the problem. The text above the dump is also important: it tells something about why the kernel dumped code (in the above example it's due to a bad kernel pointer) - in debugging dumps like the above, it helps enourmously if you can look up what the EIP value means. The hex value as such doesn't help me or anybody else very much: it will depend on your particular kernel setup. What you should do is take the hex value from the EIP line (ignore the "0010:"), and look it up in the kernel namelist to see which kernel function contains the offending address. To find out the kernel function name, you'll need to find the system binary associated with the kernel that exhibited the symptom. In the case of compressed kernels, this will be 'linux/tools/zSystem', while uncompressed kernels use the file 'tools/system'. To extract the namelist and match it against the EIP from the kernel crash, do: nm tools/zSystem | sort | less This will give you a list of kernel addresses sorted in ascending order, from which it is simple to find the function that contains the offending address. Note that the address given by the kernel debugging messages will not necessarily match exactly with the function addresses (in fact, that is very unlikely), so you can't just 'grep' the list: the list will, however, give you the starting point of each kernel function, so by looking for the function that has a starting address lower than the one you are searching for but is followed by a function with a higher address you will find the one you want. In fact, it may be a good idea to include a bit of "context" in your problem report, giving a few lines around the interesting one. If you for some reason cannot do the above (you have a pre-compiled kernel image or similar), telling me as much about your setup as possible will help. ----- From: torvalds@cc.helsinki.fi (Linus Torvalds) Subject: ALPHA-pl11 available on nic: C++ support Date: Sun, 4 Jul 93 00:03:03 GMT For those brave souls that enjoy testing new releases, there is an ALPHA-release of the 0.99.11 version available on nic.funet.fi in the usual place (pub/OS/Linux/PEOPLE/Linus). This has a few changes from the last one, the most notable being that it is compiled using C++, as there was some interest in that on the c.o.l newsgroup. Note that very few C++ features are actually used: the major changes were some minor syntactic editing and the addition of 'extern "C"' to functions called from assembly code. The C++ changes are not the same as those done by Tristan (although you should thank him for getting it rolling), as I wanted to resolve the differences between C and C++ a bit differently. The C++ changes shouldn't actually change the way the kernel works, and it's mainly used currently to do stricter pointer checking. The name mangling probably breaks the kmem based 'ps' once again.. Actual code changes for this test-version: - I added the patches by Charles Hedrick for SLIP: this actually means that only CSLIP is available for now, so.. The net code is still not ready: Fred is working on it, so this is just an interim version when it comes to networking (there are some other minor patches in there as well). - The mm has been cleaned up since pl10, and mmap() actually works for most things, while malloc() will return NULL when the kernel thinks there isn't enough memory. Similarly, the buffer cache code should now support different block sizes (although this is still in the "early alpha" stage. Most of the changes by Eric Youngdale, with mm cleanups by me. - A problem with the dynamic inode code (insufficient inode invalidation) that could result in fs corruption under some circumstances is fixed. People who have written drivers etc should probably check out the changes I did due to the stricter C++ pointer checking. Linus
-rw-r--r--COPYING12
-rw-r--r--Configure319
-rw-r--r--Makefile24
-rw-r--r--README11
-rw-r--r--boot/head.S14
-rw-r--r--config.in152
-rw-r--r--fs/block_dev.c64
-rw-r--r--fs/buffer.c78
-rw-r--r--fs/exec.c234
-rw-r--r--fs/ext/file.c2
-rw-r--r--fs/ext/freelists.c53
-rw-r--r--fs/ext/fsync.c2
-rw-r--r--fs/ext/inode.c2
-rw-r--r--fs/ext/namei.c16
-rw-r--r--fs/ext2/balloc.c2
-rw-r--r--fs/ext2/dir.c3
-rw-r--r--fs/ext2/file.c8
-rw-r--r--fs/ext2/ialloc.c3
-rw-r--r--fs/ext2/inode.c25
-rw-r--r--fs/ext2/namei.c16
-rw-r--r--fs/fcntl.c11
-rw-r--r--fs/fifo.c12
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/inode.c70
-rw-r--r--fs/ioctl.c2
-rw-r--r--fs/isofs/dir.c36
-rw-r--r--fs/isofs/file.c21
-rw-r--r--fs/isofs/inode.c110
-rw-r--r--fs/isofs/namei.c43
-rw-r--r--fs/isofs/rock.c58
-rw-r--r--fs/locks.c26
-rw-r--r--fs/minix/bitmap.c15
-rw-r--r--fs/minix/file.c2
-rw-r--r--fs/minix/inode.c5
-rw-r--r--fs/minix/namei.c16
-rw-r--r--fs/msdos/fat.c42
-rw-r--r--fs/msdos/file.c2
-rw-r--r--fs/msdos/inode.c37
-rw-r--r--fs/msdos/misc.c28
-rw-r--r--fs/namei.c61
-rw-r--r--fs/nfs/dir.c18
-rw-r--r--fs/nfs/inode.c11
-rw-r--r--fs/nfs/proc.c5
-rw-r--r--fs/open.c34
-rw-r--r--fs/pipe.c82
-rw-r--r--fs/proc/array.c13
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/fd.c17
-rw-r--r--fs/proc/inode.c12
-rw-r--r--fs/proc/kmsg.c2
-rw-r--r--fs/proc/link.c15
-rw-r--r--fs/proc/root.c6
-rw-r--r--fs/read_write.c8
-rw-r--r--fs/select.c2
-rw-r--r--fs/stat.c43
-rw-r--r--fs/super.c20
-rw-r--r--fs/xiafs/bitmap.c16
-rw-r--r--fs/xiafs/file.c2
-rw-r--r--fs/xiafs/fsync.c8
-rw-r--r--fs/xiafs/inode.c13
-rw-r--r--fs/xiafs/namei.c16
-rw-r--r--ibcs/emulate.c2
-rw-r--r--include/asm/bitops.h28
-rw-r--r--include/asm/dma.h4
-rw-r--r--include/asm/io.h87
-rw-r--r--include/asm/irq.h35
-rw-r--r--include/asm/segment.h87
-rw-r--r--include/asm/system.h33
-rw-r--r--include/linux/delay.h37
-rw-r--r--include/linux/ext2_fs.h4
-rw-r--r--include/linux/ext_fs.h3
-rw-r--r--include/linux/fs.h18
-rw-r--r--include/linux/genhd.h2
-rw-r--r--include/linux/ipc.h4
-rw-r--r--include/linux/iso_fs.h14
-rw-r--r--include/linux/kernel.h30
-rw-r--r--include/linux/keyboard.h2
-rw-r--r--include/linux/minix_fs.h3
-rw-r--r--include/linux/mm.h20
-rw-r--r--include/linux/msdos_fs.h4
-rw-r--r--include/linux/mtio.h2
-rw-r--r--include/linux/sched.h170
-rw-r--r--include/linux/sem.h1
-rw-r--r--include/linux/string.h24
-rw-r--r--include/linux/sys.h6
-rw-r--r--include/linux/timer.h4
-rw-r--r--include/linux/tpqic02.h376
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/wait.h10
-rw-r--r--include/linux/xd.h6
-rw-r--r--include/linux/xia_fs.h3
-rw-r--r--include/linux/xia_fs_i.h6
-rw-r--r--init/main.c147
-rw-r--r--ipc/msg.c34
-rw-r--r--ipc/sem.c92
-rw-r--r--ipc/shm.c44
-rw-r--r--ipc/util.c6
-rw-r--r--kernel/FPU-emu/Makefile5
-rw-r--r--kernel/FPU-emu/errors.c18
-rw-r--r--kernel/FPU-emu/fpu_emu.h36
-rw-r--r--kernel/FPU-emu/fpu_entry.c6
-rw-r--r--kernel/FPU-emu/fpu_proto.h37
-rw-r--r--kernel/FPU-emu/load_store.c6
-rw-r--r--kernel/FPU-emu/reg_compare.c18
-rw-r--r--kernel/FPU-emu/reg_ld_str.c4
-rw-r--r--kernel/blk_drv/blk.h15
-rw-r--r--kernel/blk_drv/floppy.c45
-rw-r--r--kernel/blk_drv/genhd.c8
-rw-r--r--kernel/blk_drv/hd.c27
-rw-r--r--kernel/blk_drv/ll_rw_blk.c51
-rw-r--r--kernel/blk_drv/ramdisk.c5
-rw-r--r--kernel/blk_drv/scsi/Makefile2
-rw-r--r--kernel/blk_drv/scsi/aha1542.c15
-rw-r--r--kernel/blk_drv/scsi/aha1740.c22
-rw-r--r--kernel/blk_drv/scsi/fdomain.c971
-rw-r--r--kernel/blk_drv/scsi/fdomain.h52
-rw-r--r--kernel/blk_drv/scsi/scsi.c47
-rw-r--r--kernel/blk_drv/scsi/scsi.h6
-rw-r--r--kernel/blk_drv/scsi/scsi_ioctl.c10
-rw-r--r--kernel/blk_drv/scsi/scsi_ioctl.h2
-rw-r--r--kernel/blk_drv/scsi/sd.c34
-rw-r--r--kernel/blk_drv/scsi/sd_ioctl.c4
-rw-r--r--kernel/blk_drv/scsi/seagate.c34
-rw-r--r--kernel/blk_drv/scsi/seagate.h10
-rw-r--r--kernel/blk_drv/scsi/sr.c31
-rw-r--r--kernel/blk_drv/scsi/st.c3
-rw-r--r--kernel/blk_drv/scsi/ultrastor.c22
-rw-r--r--kernel/blk_drv/scsi/wd7000.c12
-rw-r--r--kernel/blk_drv/xd.c28
-rw-r--r--kernel/chr_drv/Makefile3
-rw-r--r--kernel/chr_drv/busmouse.c11
-rw-r--r--kernel/chr_drv/console.c317
-rw-r--r--kernel/chr_drv/keyboard.c47
-rw-r--r--kernel/chr_drv/lp.c29
-rw-r--r--kernel/chr_drv/mem.c27
-rw-r--r--kernel/chr_drv/msbusmouse.c86
-rw-r--r--kernel/chr_drv/psaux.c5
-rw-r--r--kernel/chr_drv/pty.c7
-rw-r--r--kernel/chr_drv/serial.c64
-rw-r--r--kernel/chr_drv/tpqic02.c2618
-rw-r--r--kernel/chr_drv/tty_io.c48
-rw-r--r--kernel/chr_drv/tty_ioctl.c18
-rw-r--r--kernel/chr_drv/vt.c17
-rw-r--r--kernel/chr_drv/vt_kern.h2
-rw-r--r--kernel/exit.c28
-rw-r--r--kernel/fork.c153
-rw-r--r--kernel/info.c2
-rw-r--r--kernel/ioport.c15
-rw-r--r--kernel/irq.c47
-rw-r--r--kernel/itimer.c4
-rw-r--r--kernel/panic.c5
-rw-r--r--kernel/printk.c4
-rw-r--r--kernel/ptrace.c8
-rw-r--r--kernel/sched.c142
-rw-r--r--kernel/signal.c41
-rw-r--r--kernel/sys.c181
-rw-r--r--kernel/sys_call.S58
-rw-r--r--kernel/traps.c123
-rw-r--r--lib/_exit.c4
-rw-r--r--lib/malloc.c248
-rw-r--r--mm/memory.c234
-rw-r--r--mm/mmap.c212
-rw-r--r--mm/swap.c57
-rw-r--r--net/inet/8390.c44
-rw-r--r--net/inet/8390.h2
-rw-r--r--net/inet/CONFIG9
-rw-r--r--net/inet/Makefile4
-rw-r--r--net/inet/Space.c6
-rw-r--r--net/inet/arp.c25
-rw-r--r--net/inet/d_link.c10
-rw-r--r--net/inet/dev.c17
-rw-r--r--net/inet/dev.h2
-rw-r--r--net/inet/eth.c23
-rw-r--r--net/inet/hp.c8
-rw-r--r--net/inet/icmp.c18
-rw-r--r--net/inet/ip.c39
-rw-r--r--net/inet/ip.h1
-rw-r--r--net/inet/loopback.c15
-rw-r--r--net/inet/ne.c8
-rw-r--r--net/inet/packet.c6
-rw-r--r--net/inet/plip.c16
-rw-r--r--net/inet/proc.c2
-rw-r--r--net/inet/raw.c25
-rw-r--r--net/inet/route.c2
-rw-r--r--net/inet/slhc.c721
-rw-r--r--net/inet/slhc.h187
-rw-r--r--net/inet/slip.c131
-rw-r--r--net/inet/slip.h2
-rw-r--r--net/inet/sock.c66
-rw-r--r--net/inet/sock.h4
-rw-r--r--net/inet/tcp.c92
-rw-r--r--net/inet/tcp.h4
-rw-r--r--net/inet/timer.c36
-rw-r--r--net/inet/udp.c4
-rw-r--r--net/inet/utils.c4
-rw-r--r--net/inet/wd.c4
-rw-r--r--net/socket.c9
-rw-r--r--net/unix/proc.c6
-rw-r--r--net/unix/sock.c20
199 files changed, 8659 insertions, 2698 deletions
diff --git a/COPYING b/COPYING
index a43ea21..c0ff68a 100644
--- a/COPYING
+++ b/COPYING
@@ -1,3 +1,15 @@
+
+ NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+ Linus Torvalds
+
+----------------------------------------
+
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
diff --git a/Configure b/Configure
index b362474..13197bb 100644
--- a/Configure
+++ b/Configure
@@ -1,110 +1,241 @@
#! /bin/sh
-# Configure This script is used to configure the Linux kernel.
#
-# Usage: Configure [-pro]
+# This script is used to configure the linux kernel.
#
-# Version; @(#)Configure 1.3 04/05/93
+# It was inspired by the challenge in the original Configure script
+# to ``do something better'', combined with the actual need to ``do
+# something better'' because the old configure script wasn't flexible
+# enough.
#
-# Author: Linus Torvalds, <torvalds@helsinki.fi>
+# Please send comments / questions / bug fixes to raymondc@microsoft.com.
#
+# Each line in the config file is a command.
+#
+# # internal comment
+#
+# Lines beginning with a `#' are ignored.
+#
+# : message
+#
+# `:' causes the line to be echoed to the screen.
+#
+# * external comment
+#
+# `*' causes the line to be placed in the output
+# configuration file as a comment as well as being
+# echoed to the screen.
+#
+# if condition
+# ... commands ...
+# else
+# ... commands ...
+# fi
+#
+# This does the obvious thing. The `else' clause is
+# optional. Conditionals can be nested.
+#
+# The `condition' can be any valid bash expression.
+# They typically involve tests against environment
+# variables set by configuration options. For example,
+#
+# if [ "$CONFIG_SCSI" = "y" ]
+# ...More stuff...
+# fi
+#
+# Note! That there is no `then' keyword.
+#
+# bool 'prompt' CONFIG_VARIABLE default
+#
+# This prompts the user for a boolean value.
+# The prompt may not contain an apostrophe.
+# `default' should be either `y' or `n'.
+# The user's response is recorded in four places.
+#
+# In .config, if `y'
+# CONFIG_VARIABLE = CONFIG_VARIABLE
+# In .config, if `n'
+# # CONFIG_VARIABLE is not set
+#
+# In autoconf.h, if `y'
+# #define CONFIG_VARIABLE 1
+# In autoconf.h, if `n'
+# #undef CONFIG_VARIABLE
+#
+# In config.in, if `y'
+# bool 'prompt' CONFIG_VARIABLE y
+# In config.in, if `n'
+# bool 'prompt' CONFIG_VARIABLE n
+#
+# In the environment of the Configure script, if `y'
+# CONFIG_VARIABLE = y
+# In the environment of the Configure script, if `n'
+# CONFIG_VARIABLE = n
+#
+# The value is placed into the environment of the Configure
+# script so that later parts of config.in can use the `if'
+# command to inspect the results of previous queries.
+#
+# int 'prompt' CONFIG_VARIABLE default
+#
+# This prompts the user for an integer value.
+# The prompt may not contain an apostrophe.
+# `default' should be an integer.
+#
+# The response is recorded as follows.
+#
+# In .config
+# CONFIG_VARIABLE = response
+# In autoconf.h
+# #define CONFIG_VARIABLE (response)
+# In config.in
+# int 'prompt' CONFIG_VARIABLE response
+# In the environment of the Configure script
+# CONFIG_VARIABLE = response
+#
+# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
+# with an empty IFS.
- # Set variables to initial state.
- OPTS=""
- CONFIG=.config~
- CONFIG_H=include/linux/autoconf.h
- next="y"
- old="y"
+#
+# Make sure we're really running bash.
+#
+# I would really have preferred to write this script in a language with
+# better string handling, but alas, bash is the only scripting language
+# that I can be reasonable sure everybody has on their linux machine.
+#
+[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
- # Check commandline arguments.
- >config.new
- while [ $# != 0 ]
- do
- case $1 in
- -pro) OPTS="UTS_SYSNAME \"LINUX/Pro\""
- ;;
- *) echo "Usage: Configure [-pro]"
- exit 1
- ;;
- esac
- shift
- done
-
- echo "#" > $CONFIG
- echo "# Automatically generated make config: don't edit" >> $CONFIG
- echo "#" >> $CONFIG
+# Disable filename globbing once and for all.
+# Enable function cacheing.
+set -f -h
- echo "/*" > $CONFIG_H
- echo " * Automatically generated C config: don't edit" >> $CONFIG_H
- echo " */" >> $CONFIG_H
+#
+# readln reads a line into $ans.
+#
+# readln prompt default
+#
+function readln () {
+ echo -n "$1"
+ IFS='@' read ans </dev/tty || exit 1
+ [ -z "$ans" ] && ans=$2
+}
- # First of all, emit the "special" features to <linux/autoconf.h>.
- if [ "${OPTS}" ]
- then
- echo "#define ${OPTS}" >> $CONFIG_H
- fi
+# bool processes a boolean argument
+#
+# bool tail
+#
+function bool () {
+ # Slimier hack to get bash to rescan a line.
+ eval "set -- $1"
+ ans=""
+ while [ "$ans" != "y" -a "$ans" != "n" ]; do
+ readln "$1 ($2) [$3] " "$3"
+ done
+ if [ "$ans" = "y" ]; then
+ echo "$2 = $2" >>$CONFIG
+ echo "#define $2 1" >>$CONFIG_H
+ else
+ echo "# $2 is not set" >>$CONFIG
+ echo "#undef $2" >>$CONFIG_H
+ fi
+ raw_input_line="bool '$1' $2 $ans"
+ eval "$2=$ans"
+}
- # Read our standard input (which is the CONFIG.IN file).
- while read i
- do
- echo $i >> config.new
- echo >> $CONFIG
- echo >> $CONFIG_H
- echo
- echo "#" >> $CONFIG
- echo "/*" >> $CONFIG_H
- echo "**"
- while [ "$i" != "." -a "$i" != ":" ]
- do
- echo "# "$i >> $CONFIG
- echo " * "$i >> $CONFIG_H
- echo "**" $i
- read i || break
- echo $i >> config.new
+# int processes an integer argument
+#
+# int tail
+#
+function int () {
+ # Slimier hack to get bash to rescan a line.
+ eval "set -- $1"
+ ans="x"
+ while [ $[$ans+0] != "$ans" ]; do
+ readln "$1 ($2) [$3] " "$3"
done
- echo "#" >> $CONFIG
- echo " */" >> $CONFIG_H
- echo "**"
- read i || break
- echo $i >> config.new
- while [ "$i" != "." -a "$i" != ":" ]
- do
- read j ques def || break
- if [ "$old" = "n" ]
- then
- echo No $i
- ans="n"
- else
- echo -n $i '('$ques', default='$def')? '
- read ans < /dev/tty
- if [ "$ans" = "" ]
- then
- ans=$def
+ echo "$2 = $ans" >>$CONFIG
+ echo "#define $2 ($ans)" >>$CONFIG_H
+ raw_input_line="int '$1' $2 $ans"
+ eval "$2=$ans"
+}
+
+CONFIG=.config~
+CONFIG_H=include/linux/autoconf.h
+
+#
+# Make sure we start out with a clean slate.
+#
+> config.new
+echo "#" > $CONFIG
+echo "# Automatically generated make config: don't edit" >> $CONFIG
+echo "#" >> $CONFIG
+
+echo "/*" > $CONFIG_H
+echo " * Automatically generated C config: don't edit" >> $CONFIG_H
+echo " */" >> $CONFIG_H
+
+stack=''
+branch='t'
+
+while IFS='@' read raw_input_line
+do
+ # Slimy hack to get bash to rescan a line.
+ read cmd rest <<-END_OF_COMMAND
+ $raw_input_line
+ END_OF_COMMAND
+
+ if [ "$cmd" = "*" ]; then
+ if [ "$branch" = "t" ]; then
+ echo "$raw_input_line"
+ echo "# $rest" >>$CONFIG
+ if [ "$prevcmd" != "*" ]; then
+ echo >>$CONFIG_H
+ echo "/* $rest" >>$CONFIG_H
+ else
+ echo " * $rest" >>$CONFIG_H
fi
+ prevcmd="*"
fi
- echo $j $ques $ans >> config.new
- if [ "$ans" = "y" ]
- then
- echo $j = $j >> $CONFIG
- echo "#define" $j 1 >> $CONFIG_H
- next="y";
- fi
- read i || break
- echo $i >> config.new
- done
- old=$next
- next="y"
- if [ "$i" = ":" ]
- then
- next="n"
+ else
+ [ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H
+ prevcmd=""
+ case "$cmd" in
+ :) [ "$branch" = "t" ] && echo "$raw_input_line" ;;
+ int) [ "$branch" = "t" ] && int "$rest" ;;
+ bool) [ "$branch" = "t" ] && bool "$rest" ;;
+ if) stack="$branch $stack"
+ if [ "$branch" = "t" ] && eval "$rest"; then
+ branch=t
+ else
+ branch=f
+ fi ;;
+ else) if [ "$branch" = "t" ]; then
+ branch=f
+ else
+ read branch rest <<-END_OF_STACK
+ $stack
+ END_OF_STACK
+ fi ;;
+ fi) [ -z "$stack" ] && echo "Error! Extra fi." 1>&2
+ read branch stack <<-END_OF_STACK
+ $stack
+ END_OF_STACK
+ ;;
+ esac
fi
- done
- mv config.new config.in
+ echo "$raw_input_line" >>config.new
+done
+[ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H
+
+[ -z "$stack" ] || echo "Error! Untermiated if." 1>&2
+
+mv config.in config.old
+mv config.new config.in
- echo
- echo "The linux kernel is now hopefully configured for your setup."
- echo "Check the top-level Makefile for additional configuration,"
- echo "and do a 'make dep ; make clean' if you want to be sure all"
- echo "the files are correctly re-made"
- echo
+echo
+echo "The linux kernel is now hopefully configured for your setup."
+echo "Check the top-level Makefile for additional configuration,"
+echo "and do a 'make dep ; make clean' if you want to be sure all"
+echo "the files are correctly re-made"
+echo
- exit 0
+exit 0
diff --git a/Makefile b/Makefile
index e06a89c..7ee2bf5 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,10 @@ all: Version zImage
.EXPORT_ALL_VARIABLES:
+BASH = $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+ else if [ -x /bin/bash ]; then echo /bin/bash; \
+ else echo sh; fi ; fi)
+
#
# Make "config" the default target if there is no configuration file or
# "depend" the target if there is no top-level dependency information.
@@ -18,13 +22,6 @@ else
CONFIGURATION = config
endif
-#
-# This probably won't help at all...
-#
-ifndef CONFIG_CLUEFUL
-CONFIGURATION = config
-endif
-
ifdef CONFIGURATION
CONFIGURE = dummy
endif
@@ -53,7 +50,7 @@ SVGA_MODE= -DSVGA_MODE=3
# standard CFLAGS
#
-CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer
+CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -x c++
ifdef CONFIG_M486
CFLAGS := $(CFLAGS) -m486
@@ -105,7 +102,7 @@ lilo: $(CONFIGURE) Image
/etc/lilo/install
config:
- sh Configure $(OPTS) < config.in
+ $(BASH) Configure $(OPTS) < config.in
mv .config~ .config
$(MAKE) soundconf
@@ -119,7 +116,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile
@./makever.sh
- @echo \#define UTS_RELEASE \"0.99.10\" > tools/version.h
+ @echo \#define UTS_RELEASE \"0.99.11\" > tools/version.h
@echo \#define UTS_VERSION \"\#`cat .version` `date`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
@@ -198,6 +195,9 @@ tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
fs: dummy
$(MAKE) linuxsubdirs SUBDIRS=fs
+lib: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=lib
+
mm: dummy
$(MAKE) linuxsubdirs SUBDIRS=mm
@@ -213,11 +213,11 @@ clean:
mrproper: clean
rm -f include/linux/autoconf.h tools/version.h
- rm -f .version .config*
+ rm -f .version .config* config.old
rm -f .depend `find . -name .depend -print`
backup: mrproper
- cd .. && tar cf - linux | gzip -9 > backup.z
+ cd .. && tar cf - linux | gzip -9 > backup.gz
sync
depend dep:
diff --git a/README b/README
index b7bef84..b10f98a 100644
--- a/README
+++ b/README
@@ -7,11 +7,12 @@ useful if you want to compile the kernel from scratch. It leaves out a
LOT as well, but it shouldn't really be that hard to compile the kernel.
I hope.
-In order to compile this version of the kernel you need GCC 2.3.3 or
-newer (older compiler versions may work, but I haven't tested it). Some
-makefile targets require special commands which may not be available on
-all machines (see below). Normal utilities like ls etc are not
-explicitly listed, they are assumed to be available on all systems.
+In order to compile this version of the kernel you need GCC 2.4.3 or
+newer (older compiler versions have problems - no guarantees it will
+even compile much less work). Some makefile targets require special
+commands which may not be available on all machines (see below). Normal
+utilities like ls etc are not explicitly listed, they are assumed to be
+available on all systems.
Kernel sources are usually kept in /usr/src/linux. If you have them
elsewhere, you will have to change path names in a few places.
diff --git a/boot/head.S b/boot/head.S
index 8b72530..ed12f94 100644
--- a/boot/head.S
+++ b/boot/head.S
@@ -29,7 +29,7 @@
*/
startup_32:
cld
- movl $KERNEL_DS,%eax
+ movl $(KERNEL_DS),%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
@@ -63,11 +63,11 @@ startup_32:
movl $512,%ecx
rep
stosl
- cmpw $CL_MAGIC,CL_MAGIC_ADDR
+ cmpw $(CL_MAGIC),CL_MAGIC_ADDR
jne 1f
movl $_empty_zero_page+2048,%edi
movzwl CL_OFFSET,%esi
- addl $CL_BASE_ADDR,%esi
+ addl $(CL_BASE_ADDR),%esi
movl $2048,%ecx
rep
movsb
@@ -127,8 +127,8 @@ startup_32:
call setup_paging
lgdt gdt_descr
lidt idt_descr
- ljmp $KERNEL_CS,$1f
-1: movl $KERNEL_DS,%eax # reload all the segment registers
+ ljmp $(KERNEL_CS),$1f
+1: movl $(KERNEL_DS),%eax # reload all the segment registers
mov %ax,%ds # after changing gdt.
mov %ax,%es
mov %ax,%fs
@@ -153,7 +153,7 @@ check_x87:
cmpb $0,%al
je 1f
movl %cr0,%eax /* no coprocessor: have to set bits */
- xorl $6,%eax /* reset MP, set EM */
+ xorl $4,%eax /* set EM */
movl %eax,%cr0
ret
.align 2
@@ -274,7 +274,7 @@ ignore_int:
push %ds
push %es
push %fs
- movl $KERNEL_DS,%eax
+ movl $(KERNEL_DS),%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
diff --git a/config.in b/config.in
index 08d2c6c..5620e2c 100644
--- a/config.in
+++ b/config.in
@@ -1,86 +1,70 @@
-General setup
-.
-Kernel math emulation
-CONFIG_MATH_EMULATION y/n n
-Normal harddisk support
-CONFIG_BLK_DEV_HD y/n y
-XT harddisk support
-CONFIG_BLK_DEV_XD y/n n
-TCP/IP Networking
-CONFIG_INET y/n y
-Kernel profiling support
-CONFIG_PROFILE y/n n
-Limit memory to low 16MB
-CONFIG_MAX_16M y/n n
-System V IPC
-CONFIG_SYSVIPC y/n y
-Use -m486 flag for 486-specific optimizations
-CONFIG_M486 y/n y
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+*
+* General setup
+*
+bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
+bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y
+bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
+bool 'TCP/IP networking' CONFIG_INET y
+bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
+bool 'System V IPC' CONFIG_SYSVIPC y
+bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
+*
+* SCSI support
+*
+bool 'SCSI support?' CONFIG_SCSI n
+if [ "$CONFIG_SCSI" = "n" ]
:
-SCSI support
-.
-SCSI support?
-CONFIG_SCSI y/n n
+: Skipping SCSI onfiguration options...
:
-SCSI support type (disk, tape, CDrom)
-.
-Scsi disk support
-CONFIG_BLK_DEV_SD y/n n
-Scsi tape support
-CONFIG_BLK_DEV_ST y/n n
-Scsi CDROM support
-CONFIG_BLK_DEV_SR y/n n
-.
-SCSI low-level drivers
-.
-Adaptec AHA1542 support
-CONFIG_SCSI_AHA1542 y/n n
-Adaptec AHA1740 support
-CONFIG_SCSI_AHA1740 y/n n
-Future Domain SCSI support
-CONFIG_SCSI_FUTURE_DOMAIN y/n n
-Seagate ST-02 and Future Domain TMC-8xx SCSI support
-CONFIG_SCSI_SEAGATE y/n n
-UltraStor SCSI support
-CONFIG_SCSI_ULTRASTOR y/n n
-7000FASST SCSI support
-CONFIG_SCSI_7000FASST y/n n
-.
-Filesystems
-.
-Standard (minix) fs support
-CONFIG_MINIX_FS y/n y
-Extended fs support
-CONFIG_EXT_FS y/n n
-Second extended fs support
-CONFIG_EXT2_FS y/n n
-xiafs filesystem support
-CONFIG_XIA_FS y/n n
-msdos fs support
-CONFIG_MSDOS_FS y/n y
-/proc filesystem support
-CONFIG_PROC_FS y/n y
-NFS filesystem support
-CONFIG_NFS_FS y/n n
-ISO9660 cdrom filesystem support
-CONFIG_ISO9660_FS y/n n
-.
-Various character device drivers..
-.
-Keyboard meta-key sends ESC-prefix
-CONFIG_KBD_META y/n y
-Logitech busmouse support
-CONFIG_BUSMOUSE y/n n
-PS/2 mouse (aka 'auxiliary device') support
-CONFIG_PSMOUSE y/n n
-MicroSoft busmouse support
-CONFIG_MS_BUSMOUSE y/n n
-ATIXL busmouse support
-CONFIG_ATIXL_BUSMOUSE y/n n
-Soundcard support (distributed separately)
-CONFIG_SOUND y/n n
-.
-Final check to see if you are awake
-.
-Have you edited the main Makefile for root device etc
-CONFIG_CLUEFUL y/n n
+else
+ *
+ * SCSI support type (disk, tape, CDrom)
+ *
+bool 'Scsi disk support' CONFIG_BLK_DEV_SD n
+bool 'Scsi tape support' CONFIG_BLK_DEV_ST n
+bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR n
+ *
+ * SCSI low-level drivers
+ *
+bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'Future Domain SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
+bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
+bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
+bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
+fi
+*
+* Filesystems
+*
+bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
+bool 'Extended fs support' CONFIG_EXT_FS n
+bool 'Second extended fs support' CONFIG_EXT2_FS n
+bool 'xiafs filesystem support' CONFIG_XIA_FS n
+bool 'msdos fs support' CONFIG_MSDOS_FS y
+bool '/proc filesystem support' CONFIG_PROC_FS y
+bool 'NFS filesystem support' CONFIG_NFS_FS n
+bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+*
+* character devices
+*
+bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
+bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
+bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
+bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
+bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y
+bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n
+*
+* Sound
+*
+bool 'Sound card support (distributed separately)' CONFIG_SOUND n
+*
+* Kernel hacking
+*
+bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
+bool 'Kernel profiling support' CONFIG_PROFILE n
+
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 4731b57..c50b9b8 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -12,11 +12,13 @@
#include <asm/system.h>
extern int *blk_size[];
+extern int *blksize_size[];
int block_write(struct inode * inode, struct file * filp, char * buf, int count)
{
- int block = filp->f_pos >> BLOCK_SIZE_BITS;
- int offset = filp->f_pos & (BLOCK_SIZE-1);
+ int blocksize, blocksize_bits, i;
+ int block;
+ int offset;
int chars;
int written = 0;
int size;
@@ -25,18 +27,32 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
register char * p;
dev = inode->i_rdev;
+ blocksize = BLOCK_SIZE;
+ if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
+ blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
+
+ i = blocksize;
+ blocksize_bits = 0;
+ while(i != 1) {
+ blocksize_bits++;
+ i >>= 1;
+ }
+
+ block = filp->f_pos >> blocksize_bits;
+ offset = filp->f_pos & (blocksize-1);
+
if (blk_size[MAJOR(dev)])
- size = blk_size[MAJOR(dev)][MINOR(dev)];
+ size = (blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits;
else
size = 0x7fffffff;
while (count>0) {
if (block >= size)
return written;
- chars = BLOCK_SIZE - offset;
+ chars = blocksize - offset;
if (chars > count)
chars=count;
- if (chars == BLOCK_SIZE)
- bh = getblk(dev, block, BLOCK_SIZE);
+ if (chars == blocksize)
+ bh = getblk(dev, block, blocksize);
else
bh = breada(dev,block,block+1,block+2,-1);
block++;
@@ -63,6 +79,8 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
{
unsigned int block;
unsigned int offset;
+ int blocksize;
+ int blocksize_bits, i;
int blocks, left;
int bhrequest, uptodate;
struct buffer_head ** bhb, ** bhe;
@@ -74,6 +92,16 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
int read;
dev = inode->i_rdev;
+ blocksize = BLOCK_SIZE;
+ if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
+ blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
+ i = blocksize;
+ blocksize_bits = 0;
+ while (i != 1) {
+ blocksize_bits++;
+ i >>= 1;
+ }
+
offset = filp->f_pos;
if (blk_size[MAJOR(dev)])
size = blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
@@ -89,13 +117,13 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
if (left <= 0)
return 0;
read = 0;
- block = offset >> BLOCK_SIZE_BITS;
- offset &= BLOCK_SIZE-1;
- size >>= BLOCK_SIZE_BITS;
- blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
+ block = offset >> blocksize_bits;
+ offset &= blocksize-1;
+ size >>= blocksize_bits;
+ blocks = (left + offset + blocksize - 1) >> blocksize_bits;
bhb = bhe = buflist;
if (filp->f_reada) {
- blocks += read_ahead[MAJOR(dev)] / (BLOCK_SIZE >> 9);
+ blocks += read_ahead[MAJOR(dev)] / (blocksize >> 9);
if (block + blocks > size)
blocks = size - block;
}
@@ -111,14 +139,14 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
buffers and caches. */
do {
- bhrequest = 0;
- uptodate = 1;
+ bhrequest = 0;
+ uptodate = 1;
while (blocks) {
--blocks;
- *bhb = getblk(dev, block++, BLOCK_SIZE);
+ *bhb = getblk(dev, block++, blocksize);
if (*bhb && !(*bhb)->b_uptodate) {
- uptodate = 0;
- bhreq[bhrequest++] = *bhb;
+ uptodate = 0;
+ bhreq[bhrequest++] = *bhb;
}
if (++bhb == &buflist[NBUF])
@@ -144,10 +172,10 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
break;
}
}
- if (left < BLOCK_SIZE - offset)
+ if (left < blocksize - offset)
chars = left;
else
- chars = BLOCK_SIZE - offset;
+ chars = blocksize - offset;
filp->f_pos += chars;
left -= chars;
read += chars;
diff --git a/fs/buffer.c b/fs/buffer.c
index cbe8c75..e3eb636 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -48,6 +48,7 @@ int nr_buffers = 0;
int buffermem = 0;
int nr_buffer_heads = 0;
static int min_free_pages = 20; /* nr free pages needed before buffer grows */
+extern int *blksize_size[];
/*
* Rewrote the wait-routines to use the "new" wait-queue functionality,
@@ -153,7 +154,7 @@ int fsync_dev(dev_t dev)
return sync_buffers(dev, 1);
}
-int sys_sync(void)
+extern "C" int sys_sync(void)
{
sync_dev(0);
return 0;
@@ -164,7 +165,7 @@ int file_fsync (struct inode *inode, struct file *filp)
return fsync_dev(inode->i_dev);
}
-int sys_fsync(unsigned int fd)
+extern "C" int sys_fsync(unsigned int fd)
{
struct file * file;
struct inode * inode;
@@ -241,8 +242,8 @@ void check_disk_change(dev_t dev)
printk("VFS: Disk change detected on device %d/%d\n",
MAJOR(dev), MINOR(dev));
for (i=0 ; i<NR_SUPER ; i++)
- if (super_block[i].s_dev == dev)
- put_super(super_block[i].s_dev);
+ if (super_blocks[i].s_dev == dev)
+ put_super(super_blocks[i].s_dev);
invalidate_inodes(dev);
invalidate_buffers(dev);
@@ -370,6 +371,45 @@ struct buffer_head * get_hash_table(dev_t dev, int block, int size)
}
}
+void set_blocksize(dev_t dev, int size)
+{
+ int i;
+ struct buffer_head * bh, *bhnext;
+
+ if (!blksize_size[MAJOR(dev)])
+ return;
+
+ if (size != 512 && size != 1024 && size != 2048 && size != 4096)
+ panic("Invalid blocksize passed to set_blocksize");
+
+ if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
+ blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+ return;
+ };
+ if (blksize_size[MAJOR(dev)][MINOR(dev)] == size)
+ return;
+ sync_buffers(dev, 2);
+ blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+
+ /* We need to be quite careful how we do this - we are moving entries
+ around on the free list, and we can get in a loop if we are not careful.*/
+
+ bh = free_list;
+ for (i = nr_buffers*2 ; --i > 0 ; bh = bhnext) {
+ bhnext = bh->b_next_free;
+ if (bh->b_dev != dev)
+ continue;
+ if (bh->b_size == size)
+ continue;
+
+ wait_on_buffer(bh);
+ if (bh->b_dev == dev && bh->b_size != size)
+ bh->b_uptodate = bh->b_dirt = 0;
+ remove_from_hash_queue(bh);
+/* put_first_free(bh); */
+ }
+}
+
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
@@ -500,10 +540,16 @@ struct buffer_head * bread(dev_t dev, int block, int size)
struct buffer_head * breada(dev_t dev,int first, ...)
{
va_list args;
+ unsigned int blocksize;
struct buffer_head * bh, *tmp;
va_start(args,first);
- if (!(bh = getblk(dev, first, 1024))) {
+
+ blocksize = BLOCK_SIZE;
+ if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
+ blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
+
+ if (!(bh = getblk(dev, first, blocksize))) {
printk("VFS: breada: READ error on device %d/%d\n",
MAJOR(dev), MINOR(dev));
return NULL;
@@ -511,7 +557,7 @@ struct buffer_head * breada(dev_t dev,int first, ...)
if (!bh->b_uptodate)
ll_rw_block(READ, 1, &bh);
while ((first=va_arg(args,int))>=0) {
- tmp = getblk(dev, first, 1024);
+ tmp = getblk(dev, first, blocksize);
if (tmp) {
if (!tmp->b_uptodate)
ll_rw_block(READA, 1, &tmp);
@@ -547,7 +593,7 @@ static void get_more_buffer_heads(void)
if (unused_list)
return;
- page = get_free_page(GFP_KERNEL);
+ page = get_free_page(GFP_BUFFER);
if (!page)
return;
bh = (struct buffer_head *) page;
@@ -751,9 +797,9 @@ static inline unsigned long try_to_share_buffers(unsigned long address,
return try_to_load_aligned(address, dev, b, size);
}
-#define COPYBLK(from,to) \
-__asm__ __volatile__("rep ; movsl" \
- ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
+#define COPYBLK(size,from,to) \
+__asm__ __volatile__("rep ; movsl": \
+ :"c" (((unsigned long) size) >> 2),"S" (from),"D" (to) \
:"cx","di","si")
/*
@@ -767,7 +813,7 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in
{
struct buffer_head * bh[8];
unsigned long where;
- int i;
+ int i, j;
if (!(prot & PAGE_RW)) {
where = try_to_share_buffers(address,dev,b,size);
@@ -775,17 +821,17 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in
return where;
}
++current->maj_flt;
- for (i=0 ; i<4 ; i++) {
+ for (i=0, j=0; j<PAGE_SIZE ; i++, j+= size) {
bh[i] = NULL;
if (b[i])
bh[i] = getblk(dev, b[i], size);
}
read_buffers(bh,4);
where = address;
- for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) {
+ for (i=0, j=0; j<PAGE_SIZE ; i++, j += size,address += size) {
if (bh[i]) {
if (bh[i]->b_uptodate)
- COPYBLK((unsigned long) bh[i]->b_data,address);
+ COPYBLK(size, (unsigned long) bh[i]->b_data,address);
brelse(bh[i]);
}
}
@@ -794,9 +840,7 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in
/*
* Try to increase the number of buffers available: the size argument
- * is used to determine what kind of buffers we want. Currently only
- * 1024-byte buffers are supported by the rest of the system, but I
- * think this will change eventually.
+ * is used to determine what kind of buffers we want.
*/
void grow_buffers(int size)
{
diff --git a/fs/exec.c b/fs/exec.c
index 721a752..74451c8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -21,6 +21,7 @@
#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>
@@ -33,8 +34,6 @@
#include <asm/segment.h>
-extern int sys_exit(int exit_code);
-extern int sys_close(int fd);
extern void shm_exit (void);
/*
@@ -78,11 +77,15 @@ int core_dump(long signr, struct pt_regs * regs)
if (!current->dumpable)
return 0;
current->dumpable = 0;
+
+ if (current->elf_executable)
+ return 0;
+
/* See if we have enough room to write the upage. */
if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
return 0;
- __asm__("mov %%fs,%0":"=r" (fs));
- __asm__("mov %w0,%%fs"::"r" (KERNEL_DS));
+ fs = get_fs();
+ set_fs(KERNEL_DS);
if (open_namei("core",O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
inode = NULL;
goto end_coredump;
@@ -132,7 +135,7 @@ int core_dump(long signr, struct pt_regs * regs)
if (hard_math) {
if ((dump.u_fpvalid = current->used_math) != 0) {
if (last_task_used_math == current)
- __asm__("clts ; fnsave %0"::"m" (dump.i387));
+ __asm__("clts ; fnsave %0": :"m" (dump.i387));
else
memcpy(&dump.i387,&current->tss.i387.hard,sizeof(dump.i387));
}
@@ -141,7 +144,7 @@ int core_dump(long signr, struct pt_regs * regs)
convert it into standard 387 format first.. */
dump.u_fpvalid = 0;
}
- __asm__("mov %w0,%%fs"::"r" (KERNEL_DS));
+ set_fs(KERNEL_DS);
/* struct user */
DUMP_WRITE(&dump,sizeof(dump));
/* name of the executable */
@@ -149,7 +152,7 @@ int core_dump(long signr, struct pt_regs * regs)
/* 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 */
- __asm__("mov %w0,%%fs"::"r" (USER_DS));
+ set_fs(USER_DS);
/* Dump the data area */
if (dump.u_dsize != 0) {
dump_start = dump.u_tsize << 12;
@@ -163,13 +166,13 @@ int core_dump(long signr, struct pt_regs * regs)
DUMP_WRITE(dump_start,dump_size);
};
/* Finally dump the task struct. Not be used by gdb, but could be useful */
- __asm__("mov %w0,%%fs"::"r" (KERNEL_DS));
+ set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
end_coredump:
- __asm__("mov %w0,%%fs"::"r" (fs));
+ set_fs(fs);
iput(inode);
return has_dumped;
}
@@ -180,62 +183,56 @@ end_coredump:
*
* Also note that we take the address to load from from the file itself.
*/
-int sys_uselib(const char * library)
+extern "C" int sys_uselib(const char * library)
{
-#define libnum (current->numlibraries)
+ int fd, error;
+ struct file * file;
struct inode * inode;
- struct buffer_head * bh;
struct exec ex;
- unsigned long offset;
- int error;
-
- if (!library || get_limit(USER_DS) != TASK_SIZE)
- return -EINVAL;
- if ((libnum >= MAX_SHARED_LIBS) || (libnum < 0))
- return -EINVAL;
- error = namei(library,&inode);
- if (error)
- return error;
- if (!inode->i_sb || !S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
- iput(inode);
- return -EACCES;
- }
- if (!inode->i_op || !inode->i_op->bmap) {
- iput(inode);
+ unsigned int len;
+ unsigned int bss;
+
+ fd = sys_open(library, 0, 0);
+ if (fd < 0)
+ return fd;
+ file = current->filp[fd];
+ if (!file || !(inode = file->f_inode) || !file->f_op || !file->f_op->read) {
+ sys_close(fd);
return -ENOEXEC;
}
- if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
- iput(inode);
+ set_fs(KERNEL_DS);
+ if (file->f_op->read(inode, file, (char *) &ex, sizeof(ex)) != sizeof(ex)) {
+ sys_close(fd);
return -EACCES;
}
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- ex = *(struct exec *) bh->b_data;
- brelse(bh);
+ set_fs(USER_DS);
+
+ /* We come in here for the regular a.out style of shared libraries */
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize ||
- ex.a_drsize || ex.a_entry & 0xfff ||
- inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
- iput(inode);
+ ex.a_drsize || ex.a_entry & 0xfff ||
+ inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
+ sys_close(fd);
+ 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");
+ sys_close(fd);
return -ENOEXEC;
}
- current->libraries[libnum].library = inode;
- current->libraries[libnum].start = ex.a_entry;
- offset = (ex.a_data + ex.a_text + 0xfff) & 0xfffff000;
- current->libraries[libnum].length = offset;
- current->libraries[libnum].bss = ex.a_bss;
- offset += ex.a_entry;
- zeromap_page_range(offset, ex.a_bss, PAGE_COPY);
-#if 0
- printk("VFS: Loaded library %d at %08x, length %08x\n",
- libnum,
- current->libraries[libnum].start,
- current->libraries[libnum].length);
-#endif
- libnum++;
+
+ /* Now use mmap to map the library into memory. */
+ error = do_mmap(file, ex.a_entry, ex.a_text + ex.a_data,
+ PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
+ N_TXTOFF(ex));
+ sys_close(fd);
+ if (error != ex.a_entry)
+ return error;
+ len = (ex.a_text + ex.a_data + 0xfff) & 0xfffff000;
+ bss = ex.a_text + ex.a_data + ex.a_bss;
+ if (bss > len)
+ zeromap_page_range(ex.a_entry + len, bss-len, PAGE_COPY);
return 0;
-#undef libnum
}
/*
@@ -410,15 +407,72 @@ end_readexec:
return result;
}
+
/*
- * 'do_execve()' executes a new program.
- *
- * NOTE! We leave 4MB free at the top of the data-area for a loadable
- * library.
+ * This function flushes out all traces of the currently running executable so
+ * that a new one can be started
*/
-int do_execve(unsigned long * eip,long tmp,char * filename,
- char ** argv, char ** envp)
+
+static void flush_old_exec(struct inode * inode, char * filename, int e_uid, int e_gid)
{
+ int i;
+ int ch;
+ struct vm_area_struct * mpnt, *mpnt1;
+
+ current->dumpable = 1;
+ for (i=0; (ch = get_fs_byte(filename++)) != '\0';) {
+ if (ch == '/')
+ i = 0;
+ else
+ if (i < 15)
+ current->comm[i++] = ch;
+ }
+ current->comm[i] = '\0';
+ if (current->shm)
+ shm_exit();
+ if (current->executable) {
+ iput(current->executable);
+ current->executable = NULL;
+ }
+ /* Release all of the old mmap stuff. */
+
+ mpnt = current->mmap;
+ current->mmap = NULL;
+ while (mpnt) {
+ mpnt1 = mpnt->vm_next;
+ if (mpnt->vm_ops->close)
+ mpnt->vm_ops->close(mpnt);
+ kfree(mpnt);
+ mpnt = mpnt1;
+ }
+ if (e_uid != current->euid || e_gid != current->egid || !permission(inode,MAY_READ))
+ current->dumpable = 0;
+ current->signal = 0;
+ for (i=0 ; i<32 ; i++) {
+ current->sigaction[i].sa_mask = 0;
+ current->sigaction[i].sa_flags = 0;
+ if (current->sigaction[i].sa_handler != SIG_IGN)
+ current->sigaction[i].sa_handler = NULL;
+ }
+ for (i=0 ; i<NR_OPEN ; i++)
+ if (FD_ISSET(i,&current->close_on_exec))
+ sys_close(i);
+ FD_ZERO(&current->close_on_exec);
+ clear_page_tables(current);
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
+ current->used_math = 0;
+ current->elf_executable = 0;
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+extern "C" int sys_execve(struct pt_regs regs)
+{
+ char * filename = (char *) regs.ebx;
+ char ** argv = (char **) regs.ecx;
+ char ** envp = (char **) regs.edx;
struct inode * inode;
char buf[128];
unsigned long old_fs;
@@ -429,9 +483,8 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
int retval;
int sh_bang = 0;
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
- int ch;
- if ((0xffff & eip[1]) != USER_CS)
+ if (regs.cs != USER_CS)
panic("VFS: execve called from supervisor mode");
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
page[i]=0;
@@ -565,8 +618,14 @@ restart_interp:
retval = -ENOEXEC;
goto exec_error2;
}
+ if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
+ (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
+ printk("N_TXTOFF < BLOCK_SIZE. Please convert binary.");
+ retval = -ENOEXEC;
+ goto exec_error2;
+ }
if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
- printk("VFS: N_TXTOFF != BLOCK_SIZE. See a.out.h.");
+ printk("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
retval = -ENOEXEC;
goto exec_error2;
}
@@ -579,43 +638,7 @@ restart_interp:
}
}
/* OK, This is the point of no return */
- current->dumpable = 1;
- for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
- if (ch == '/')
- i = 0;
- else
- if (i < 15)
- current->comm[i++] = ch;
- current->comm[i] = '\0';
- if (current->shm)
- shm_exit();
- if (current->executable) {
- iput(current->executable);
- current->executable = NULL;
- }
- i = current->numlibraries;
- while (i-- > 0) {
- iput(current->libraries[i].library);
- current->libraries[i].library = NULL;
- }
- if (e_uid != current->euid || e_gid != current->egid ||
- !permission(inode,MAY_READ))
- current->dumpable = 0;
- current->numlibraries = 0;
- for (i=0 ; i<32 ; i++) {
- current->sigaction[i].sa_mask = 0;
- current->sigaction[i].sa_flags = 0;
- if (current->sigaction[i].sa_handler != SIG_IGN)
- current->sigaction[i].sa_handler = NULL;
- }
- for (i=0 ; i<NR_OPEN ; i++)
- if (FD_ISSET(i,&current->close_on_exec))
- sys_close(i);
- FD_ZERO(&current->close_on_exec);
- clear_page_tables(current);
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- current->used_math = 0;
+ flush_old_exec(inode, filename, e_uid, e_gid);
p += change_ldt(ex.a_text,page);
p -= MAX_ARG_PAGES*PAGE_SIZE;
p = (unsigned long) create_tables((char *)p,argc,envc);
@@ -625,6 +648,7 @@ restart_interp:
current->start_stack = p;
current->rss = (TASK_SIZE - p + PAGE_SIZE-1) / PAGE_SIZE;
current->suid = current->euid = e_uid;
+ current->mmap = NULL;
current->sgid = current->egid = e_gid;
if (N_MAGIC(ex) == OMAGIC) {
read_exec(inode, 32, (char *) 0, ex.a_text+ex.a_data);
@@ -632,11 +656,14 @@ restart_interp:
} else if (!inode->i_op || !inode->i_op->bmap) {
read_exec(inode, 1024, (char *) 0, ex.a_text+ex.a_data);
iput(inode);
- } else
+ } else {
+ if (ex.a_text & 0xfff || ex.a_data & 0xfff)
+ printk("%s: executable not page aligned\n", current->comm);
current->executable = inode;
+ }
zeromap_page_range((ex.a_text + ex.a_data + 0xfff) & 0xfffff000,ex.a_bss, PAGE_COPY);
- eip[0] = ex.a_entry; /* eip, magic happens :-) */
- eip[3] = p; /* stack pointer */
+ regs.eip = ex.a_entry; /* eip, magic happens :-) */
+ regs.esp = p; /* stack pointer */
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
return 0;
@@ -647,3 +674,4 @@ exec_error1:
free_page(page[i]);
return(retval);
}
+
diff --git a/fs/ext/file.c b/fs/ext/file.c
index 6c5019c..e378a05 100644
--- a/fs/ext/file.c
+++ b/fs/ext/file.c
@@ -45,7 +45,7 @@ static struct file_operations ext_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
- NULL, /* mmap */
+ generic_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
ext_sync_file /* fsync */
diff --git a/fs/ext/freelists.c b/fs/ext/freelists.c
index e50d9ff..6462da1 100644
--- a/fs/ext/freelists.c
+++ b/fs/ext/freelists.c
@@ -41,7 +41,8 @@
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
- ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
+ : \
+ :"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
void ext_free_block(struct super_block * sb, int block)
{
@@ -182,7 +183,10 @@ void ext_free_inode(struct inode * inode)
{
struct buffer_head * bh;
struct ext_free_inode * efi;
+ struct super_block * sb;
unsigned long block;
+ unsigned long ino;
+ dev_t dev;
if (!inode)
return;
@@ -202,38 +206,41 @@ void ext_free_inode(struct inode * inode)
printk("free_inode: inode on non-existent device\n");
return;
}
- lock_super (inode->i_sb);
- if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.ext_sb.s_ninodes) {
+ sb = inode->i_sb;
+ ino = inode->i_ino;
+ dev = inode->i_dev;
+ clear_inode(inode);
+ lock_super (sb);
+ if (ino < 1 || ino > sb->u.ext_sb.s_ninodes) {
printk("free_inode: inode 0 or non-existent inode\n");
- unlock_super (inode->i_sb);
+ unlock_super (sb);
return;
}
- if (inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
- efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
- (inode->i_sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
- if (!inode->i_sb->u.ext_sb.s_firstfreeinodeblock || efi->count == 14) {
+ if (sb->u.ext_sb.s_firstfreeinodeblock)
+ efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
+ (sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
+ if (!sb->u.ext_sb.s_firstfreeinodeblock || efi->count == 14) {
#ifdef EXTFS_DEBUG
-printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
+printk("ext_free_inode: inode full, skipping to %d\n", ino);
#endif
- if (inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
- brelse (inode->i_sb->u.ext_sb.s_firstfreeinodeblock);
- block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK;
- if (!(bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize)))
+ if (sb->u.ext_sb.s_firstfreeinodeblock)
+ brelse (sb->u.ext_sb.s_firstfreeinodeblock);
+ block = 2 + (ino - 1) / EXT_INODES_PER_BLOCK;
+ if (!(bh = bread(dev, block, sb->s_blocksize)))
panic("ext_free_inode: unable to read inode block\n");
efi = ((struct ext_free_inode *) bh->b_data) +
- (inode->i_ino - 1) % EXT_INODES_PER_BLOCK;
- efi->next = inode->i_sb->u.ext_sb.s_firstfreeinodenumber;
+ (ino - 1) % EXT_INODES_PER_BLOCK;
+ efi->next = sb->u.ext_sb.s_firstfreeinodenumber;
efi->count = 0;
- inode->i_sb->u.ext_sb.s_firstfreeinodenumber = inode->i_ino;
- inode->i_sb->u.ext_sb.s_firstfreeinodeblock = bh;
+ sb->u.ext_sb.s_firstfreeinodenumber = ino;
+ sb->u.ext_sb.s_firstfreeinodeblock = bh;
} else {
- efi->free[efi->count++] = inode->i_ino;
+ efi->free[efi->count++] = ino;
}
- inode->i_sb->u.ext_sb.s_freeinodescount ++;
- inode->i_sb->s_dirt = 1;
- inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
- unlock_super (inode->i_sb);
- clear_inode(inode);
+ sb->u.ext_sb.s_freeinodescount ++;
+ sb->s_dirt = 1;
+ sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
+ unlock_super (sb);
}
struct inode * ext_new_inode(const struct inode * dir)
diff --git a/fs/ext/fsync.c b/fs/ext/fsync.c
index 1978519..a0c5d01 100644
--- a/fs/ext/fsync.c
+++ b/fs/ext/fsync.c
@@ -127,7 +127,7 @@ static int sync_dindirect(struct inode *inode, unsigned long *diblock,
int rc, err = 0;
rc = sync_iblock (inode, diblock, &dind_bh, wait);
- if (rc || !inode)
+ if (rc || !dind_bh)
return rc;
for (i = 0; i < addr_per_block; i++) {
diff --git a/fs/ext/inode.c b/fs/ext/inode.c
index fa01b33..910ab58 100644
--- a/fs/ext/inode.c
+++ b/fs/ext/inode.c
@@ -62,6 +62,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data,
int dev = s->s_dev,block;
lock_super(s);
+ set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
s->s_dev=0;
unlock_super(s);
@@ -70,6 +71,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data,
}
es = (struct ext_super_block *) bh->b_data;
s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
s->u.ext_sb.s_ninodes = es->s_ninodes;
s->u.ext_sb.s_nzones = es->s_nzones;
s->u.ext_sb.s_firstdatazone = es->s_firstdatazone;
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index 49e22d3..be27571 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -710,27 +710,27 @@ int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int
return 0;
}
-static int subdir(struct inode * new, struct inode * old)
+static int subdir(struct inode * new_inode, struct inode * old_inode)
{
int ino;
int result;
- new->i_count++;
+ new_inode->i_count++;
result = 0;
for (;;) {
- if (new == old) {
+ if (new_inode == old_inode) {
result = 1;
break;
}
- if (new->i_dev != old->i_dev)
+ if (new_inode->i_dev != old_inode->i_dev)
break;
- ino = new->i_ino;
- if (ext_lookup(new,"..",2,&new))
+ ino = new_inode->i_ino;
+ if (ext_lookup(new_inode,"..",2,&new_inode))
break;
- if (new->i_ino == ino)
+ if (new_inode->i_ino == ino)
break;
}
- iput(new);
+ iput(new_inode);
return result;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 32c78fb..7f8b1c8 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -263,7 +263,7 @@ void ext2_free_block (struct super_block * sb, unsigned long block)
printk ("block_group = %d\n", block_group);
panic ("ext2_free_block: Unable to load group bitmap");
}
- if (clear_bit (bit, bh->b_data))
+ if (!clear_bit (bit, bh->b_data))
printk ("ext2_free_block (%04x:%d): bit already cleared\n",
sb->s_dev, block);
else {
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 52045c4..a828ace 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -93,10 +93,11 @@ int ext2_check_dir_entry (char * function, struct inode * dir,
static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
- unsigned int offset, i, err;
+ unsigned int offset, i;
struct buffer_head * bh;
struct ext2_dir_entry * de;
struct super_block * sb;
+ int err;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index c3a16db..a8a7f3e 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -45,7 +45,7 @@ static struct file_operations ext2_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
ext2_ioctl, /* ioctl - default */
- NULL, /* mmap */
+ generic_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
ext2_sync_file /* fsync */
@@ -79,7 +79,8 @@ struct inode_operations ext2_file_inode_operations = {
struct buffer_head * bhreq[NBUF];
struct buffer_head * buflist[NBUF];
struct super_block * sb;
- unsigned int size, err;
+ unsigned int size;
+ int err;
if (!inode) {
printk ("ext2_file_read: inode = NULL\n");
@@ -107,7 +108,8 @@ struct inode_operations ext2_file_inode_operations = {
blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
bhb = bhe = buflist;
if (filp->f_reada) {
- blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
+ blocks += read_ahead[MAJOR(inode->i_dev)] >>
+ (EXT2_BLOCK_SIZE_BITS(sb) - 9);
if (block + blocks > size)
blocks = size - block;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 0719e9b..02f768e 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -235,7 +235,7 @@ void ext2_free_inode (struct inode * inode)
printk ("block_group = %d\n", block_group);
panic ("ext2_free_inode: Unable to load bitmap");
}
- if (clear_bit (bit, bh->b_data))
+ if (!clear_bit (bit, bh->b_data))
printk ("ext2_free_inode (%04x:%d): bit already cleared\n",
sb->s_dev, inode->i_ino);
else {
@@ -438,6 +438,7 @@ repeat:
es->s_free_inodes_count --;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1;
+ inode->i_mode = mode;
inode->i_sb = sb;
inode->i_count = 1;
inode->i_nlink = 1;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index c9c135a..95bc2e6 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -127,6 +127,7 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
#endif
lock_super (s);
+ set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread (dev, 1, BLOCK_SIZE))) {
s->s_dev = 0;
unlock_super (s);
@@ -136,11 +137,22 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
es = (struct ext2_super_block *) bh->b_data;
s->s_magic = es->s_magic;
s->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
+ s->u.ext2_sb.s_log_block_size = es->s_log_block_size;
+ s->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(s);
+ if (s->s_blocksize != BLOCK_SIZE &&
+ (s->s_blocksize == 1024 || s->s_blocksize == 2048 ||
+ s->s_blocksize == 4096)) {
+ brelse(bh);
+ set_blocksize(dev, s->s_blocksize);
+ bh = bread (dev, 0, s->s_blocksize);
+ if(!bh)
+ return NULL;
+ es = (struct ext2_super_block *) (((char *)bh->b_data) + BLOCK_SIZE) ;
+ };
s->u.ext2_sb.s_inodes_count = es->s_inodes_count;
s->u.ext2_sb.s_blocks_count = es->s_blocks_count;
s->u.ext2_sb.s_r_blocks_count = es->s_r_blocks_count;
s->u.ext2_sb.s_first_data_block = es->s_first_data_block;
- s->u.ext2_sb.s_log_block_size = es->s_log_block_size;
s->u.ext2_sb.s_log_frag_size = es->s_log_frag_size;
s->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
es->s_log_frag_size;
@@ -200,6 +212,15 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
dev);
return NULL;
}
+ if (s->s_blocksize != bh->b_size) {
+ s->s_dev = 0;
+ unlock_super (s);
+ brelse (bh);
+ if (!silent)
+ printk("VFS: Unsupported blocksize on dev 0x%04x.\n",
+ dev);
+ return NULL;
+ }
if (s->s_blocksize != s->u.ext2_sb.s_frag_size) {
s->s_dev = 0;
unlock_super (s);
@@ -383,7 +404,7 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf)
put_fs_long (EXT2_SUPER_MAGIC, &buf->f_type);
put_fs_long (sb->s_blocksize, &buf->f_bsize);
- put_fs_long (sb->u.ext2_sb.s_blocks_count << sb->u.ext2_sb.s_log_block_size,
+ put_fs_long (sb->u.ext2_sb.s_blocks_count >> sb->u.ext2_sb.s_log_block_size,
&buf->f_blocks);
tmp = ext2_count_free_blocks (sb);
put_fs_long (tmp, &buf->f_bfree);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 9e6082e..b0edb54 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -785,27 +785,27 @@ int ext2_link (struct inode * oldinode, struct inode * dir,
return 0;
}
-static int subdir (struct inode * new, struct inode * old)
+static int subdir (struct inode * new_inode, struct inode * old_inode)
{
int ino;
int result;
- new->i_count ++;
+ new_inode->i_count ++;
result = 0;
for (;;) {
- if (new == old) {
+ if (new_inode == old_inode) {
result = 1;
break;
}
- if (new->i_dev != old->i_dev)
+ if (new_inode->i_dev != old_inode->i_dev)
break;
- ino = new->i_ino;
- if (ext2_lookup (new, "..", 2, &new))
+ ino = new_inode->i_ino;
+ if (ext2_lookup (new_inode, "..", 2, &new_inode))
break;
- if (new->i_ino == ino)
+ if (new_inode->i_ino == ino)
break;
}
- iput (new);
+ iput (new_inode);
return result;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 52c6d90..effbd48 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -13,9 +13,9 @@
#include <linux/fcntl.h>
#include <linux/string.h>
-extern int sys_close(int fd);
extern int fcntl_getlk(unsigned int, struct flock *);
extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
+extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
static int dupfd(unsigned int fd, unsigned int arg)
{
@@ -35,7 +35,7 @@ static int dupfd(unsigned int fd, unsigned int arg)
return arg;
}
-int sys_dup2(unsigned int oldfd, unsigned int newfd)
+extern "C" int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
if (oldfd >= NR_OPEN || !current->filp[oldfd])
return -EBADF;
@@ -58,16 +58,15 @@ int sys_dup2(unsigned int oldfd, unsigned int newfd)
return dupfd(oldfd,newfd);
}
-int sys_dup(unsigned int fildes)
+extern "C" int sys_dup(unsigned int fildes)
{
return dupfd(fildes,0);
}
-int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+extern "C" int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
- extern int sock_fcntl (struct file *, unsigned int cmd,
- unsigned long arg);
+
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
switch (cmd) {
diff --git a/fs/fifo.c b/fs/fifo.c
index 78ceb4b..2e63550 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -9,10 +9,6 @@
#include <linux/errno.h>
#include <linux/fcntl.h>
-extern struct file_operations read_pipe_fops;
-extern struct file_operations write_pipe_fops;
-extern struct file_operations rdwr_pipe_fops;
-
static int fifo_open(struct inode * inode,struct file * filp)
{
int retval = 0;
@@ -26,16 +22,12 @@ static int fifo_open(struct inode * inode,struct file * filp)
* POSIX.1 says that O_NONBLOCK means return with the FIFO
* opened, even when there is no process writing the FIFO.
*/
- filp->f_op = &read_pipe_fops;
+ filp->f_op = &connecting_pipe_fops;
if (!PIPE_READERS(*inode)++)
wake_up(&PIPE_WRITE_WAIT(*inode));
if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
PIPE_RD_OPENERS(*inode)++;
while (!PIPE_WRITERS(*inode)) {
-#if 0
- if (PIPE_HEAD(*inode) != PIPE_TAIL(*inode))
- break;
-#endif
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
break;
@@ -47,6 +39,8 @@ static int fifo_open(struct inode * inode,struct file * filp)
}
while (PIPE_WR_OPENERS(*inode))
interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
+ if (PIPE_WRITERS(*inode))
+ filp->f_op = &read_pipe_fops;
if (retval && !--PIPE_READERS(*inode))
wake_up(&PIPE_WRITE_WAIT(*inode));
break;
diff --git a/fs/file_table.c b/fs/file_table.c
index 7e5c713..e23d9da 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -46,7 +46,7 @@ void grow_files(void)
struct file * file;
int i;
- page = get_free_page(GFP_KERNEL);
+ page = get_free_page(GFP_BUFFER);
if (!page)
return;
file = (struct file *) page;
diff --git a/fs/inode.c b/fs/inode.c
index 75883cf..1c0f8b1 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -88,19 +88,16 @@ void grow_inodes(void)
struct inode * inode;
int i;
- page = get_free_page(GFP_KERNEL);
+ page = get_free_page(GFP_BUFFER);
if (!page)
return;
inode = (struct inode *) page;
- for (i=0; i < (PAGE_SIZE / sizeof(struct inode)); i++, inode++)
- {
- if (!first_inode)
- {
+ for (i=0; i < (PAGE_SIZE / sizeof(struct inode)); i++, inode++) {
+ if (!first_inode) {
inode->i_next = inode;
inode->i_prev = inode;
first_inode = inode;
- }
- else
+ } else
insert_inode_free(inode);
}
nr_inodes += i;
@@ -151,9 +148,9 @@ void clear_inode(struct inode * inode)
struct wait_queue * wait;
wait_on_inode(inode);
- wait = ((volatile struct inode *) inode)->i_wait;
remove_inode_hash(inode);
remove_inode_free(inode);
+ wait = ((volatile struct inode *) inode)->i_wait;
if (inode->i_count)
nr_free_inodes++;
memset(inode,0,sizeof(*inode));
@@ -163,10 +160,13 @@ void clear_inode(struct inode * inode)
int fs_may_mount(dev_t dev)
{
- struct inode * inode;
+ struct inode * inode, * next;
int i;
- for (inode = first_inode, i=0; i<nr_inodes; i++, inode=inode->i_next) {
+ next = first_inode;
+ for (i = nr_inodes ; i > 0 ; i--) {
+ inode = next;
+ next = inode->i_next; /* clear_inode() changes the queues.. */
if (inode->i_dev != dev)
continue;
if (inode->i_count || inode->i_dirt || inode->i_lock)
@@ -181,12 +181,13 @@ int fs_may_umount(dev_t dev, struct inode * mount_root)
struct inode * inode;
int i;
- for (inode = first_inode, i=0; i<nr_inodes; i++, inode=inode->i_next) {
- if (inode->i_dev==dev && inode->i_count)
- if (inode == mount_root && inode->i_count == 1)
- continue;
- else
- return 0;
+ inode = first_inode;
+ for (i=0 ; i < nr_inodes ; i++, inode = inode->i_next) {
+ if (inode->i_dev != dev || !inode->i_count)
+ continue;
+ if (inode == mount_root && inode->i_count == 1)
+ continue;
+ return 0;
}
return 1;
}
@@ -266,20 +267,20 @@ int bmap(struct inode * inode, int block)
void invalidate_inodes(dev_t dev)
{
+ struct inode * inode, * next;
int i;
- struct inode * inode;
- inode = first_inode;
- for(i = 0; i < nr_inodes*2; i++, inode = inode->i_next) {
- wait_on_inode(inode);
- if (inode->i_dev == dev) {
- if (inode->i_count) {
- printk("VFS: inode busy on removed device %d/%d\n",
- MAJOR(dev), MINOR(dev));
- continue;
- }
- clear_inode(inode);
+ next = first_inode;
+ for(i = nr_inodes ; i > 0 ; i--) {
+ inode = next;
+ next = inode->i_next; /* clear_inode() changes the queues.. */
+ if (inode->i_dev != dev)
+ continue;
+ if (inode->i_count || inode->i_dirt || inode->i_lock) {
+ printk("VFS: inode busy on removed device %d/%d\n", MAJOR(dev), MINOR(dev));
+ continue;
}
+ clear_inode(inode);
}
}
@@ -385,8 +386,7 @@ repeat:
inode->i_count = 1;
inode->i_nlink = 1;
nr_free_inodes--;
- if (nr_free_inodes < 0)
- {
+ if (nr_free_inodes < 0) {
printk ("VFS: get_empty_inode: bad free inode count.\n");
nr_free_inodes = 0;
}
@@ -396,20 +396,22 @@ repeat:
struct inode * get_pipe_inode(void)
{
struct inode * inode;
+ extern struct inode_operations pipe_inode_operations;
if (!(inode = get_empty_inode()))
return NULL;
if (!(PIPE_BASE(*inode) = (char *) get_free_page(GFP_USER))) {
- inode->i_count = 0;
+ iput(inode);
return NULL;
}
+ inode->i_op = &pipe_inode_operations;
inode->i_count = 2; /* sum of readers/writers */
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
inode->i_pipe = 1;
- inode->i_mode |= S_IFIFO;
+ inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -422,8 +424,8 @@ struct inode * iget(struct super_block * sb,int nr)
if (!sb)
panic("VFS: iget with sb==NULL");
-repeat:
empty = get_empty_inode();
+repeat:
inode = *(hash(sb->s_dev,nr));
while (inode) {
if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
@@ -440,7 +442,7 @@ repeat:
int i;
for (i = 0 ; i<NR_SUPER ; i++)
- if (super_block[i].s_covered==inode)
+ if (super_blocks[i].s_covered==inode)
break;
if (i >= NR_SUPER) {
printk("VFS: Mounted inode hasn't got sb\n");
@@ -449,7 +451,7 @@ repeat:
return inode;
}
iput(inode);
- if (!(inode = super_block[i].s_mounted))
+ if (!(inode = super_blocks[i].s_mounted))
printk("VFS: Mounted device %d/%d has no rootinode\n",
MAJOR(inode->i_dev), MINOR(inode->i_dev));
else {
diff --git a/fs/ioctl.c b/fs/ioctl.c
index e97140e..c54c453 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -54,7 +54,7 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
}
-int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+extern "C" int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
int on;
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index fd906db..66b24e9 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -67,7 +67,7 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
char c = 0;
int inode_number;
struct buffer_head * bh;
- char * cpnt = 0;
+ void * cpnt = NULL;
unsigned int old_offset;
int dlen, rrflag;
char * dpnt;
@@ -76,9 +76,9 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
- offset = filp->f_pos & (BLOCK_SIZE - 1);
- block = isofs_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
- if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE)))
+ offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode) - 1);
+ block = isofs_bmap(inode,(filp->f_pos)>>ISOFS_BUFFER_BITS(inode));
+ if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
return 0;
while (filp->f_pos < inode->i_size) {
@@ -86,7 +86,7 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
printk("Block, offset: %x %x %x\n",block, offset, filp->f_pos);
#endif
de = (struct iso_directory_record *) (offset + bh->b_data);
- inode_number = (block << BLOCK_SIZE_BITS)+(offset & (BLOCK_SIZE - 1));
+ inode_number = (block << ISOFS_BUFFER_BITS(inode))+(offset & (ISOFS_BUFFER_SIZE(inode) - 1));
/* If the length byte is zero, we should move on to the next CDROM sector.
If we are at the end of the directory, we kick out of the while loop. */
@@ -95,8 +95,8 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
brelse(bh);
offset = 0;
filp->f_pos =(filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))+ISOFS_BLOCK_SIZE;
- block = isofs_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
- if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE)))
+ block = isofs_bmap(inode,(filp->f_pos)>>ISOFS_BUFFER_BITS(inode));
+ if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
return 0;
continue;
}
@@ -108,16 +108,17 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
old_offset = offset;
offset += *((unsigned char*) de);
filp->f_pos += *((unsigned char*) de);
- if (offset >= BLOCK_SIZE) {
+
+ if (offset >= ISOFS_BUFFER_SIZE(inode)) {
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, BLOCK_SIZE);
+ memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
de = (struct iso_directory_record *) (old_offset + cpnt);
brelse(bh);
- offset = filp->f_pos & (BLOCK_SIZE - 1);
- block = isofs_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
- if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE)))
+ offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode) - 1);
+ block = isofs_bmap(inode,(filp->f_pos)>> ISOFS_BUFFER_BITS(inode));
+ if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
return 0;
- memcpy(cpnt+BLOCK_SIZE, bh->b_data, BLOCK_SIZE);
+ memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
}
/* Handle the case of the '.' directory */
@@ -137,7 +138,7 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
put_fs_byte('.',dirent->d_name+1);
i = 2;
dpnt = "..";
- if((inode->i_sb->u.isofs_sb.s_firstdatazone << BLOCK_SIZE_BITS) != inode->i_ino)
+ if((inode->i_sb->u.isofs_sb.s_firstdatazone << ISOFS_BUFFER_BITS(inode)) != inode->i_ino)
inode_number = inode->u.isofs_i.i_backlink;
else
inode_number = inode->i_ino;
@@ -166,7 +167,7 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
if (rrflag == -1) { /* This is a rock ridge reloc dir */
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
- cpnt = 0;
+ cpnt = NULL;
};
continue;
};
@@ -204,7 +205,7 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
if (rrflag) kfree(dpnt);
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
- cpnt = 0;
+ cpnt = NULL;
};
if (i) {
@@ -218,7 +219,8 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
/* We go here for any condition we cannot handle. We also drop through
to here at the end of the directory. */
out:
- if (cpnt) kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
+ if (cpnt)
+ kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
brelse(bh);
return 0;
}
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index 223e7d0..c20aef2 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -42,6 +42,7 @@ static struct file_operations isofs_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
+ generic_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
NULL /* fsync */
@@ -93,10 +94,10 @@ static void isofs_determine_filetype(struct inode * inode)
unsigned char * pnt;
block = isofs_bmap(inode,0);
- if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE))) {
- pnt = (char*) bh->b_data;
+ if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode)))) {
+ pnt = (unsigned char *) bh->b_data;
result = ISOFS_FILE_TEXT_M;
- for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE ? inode->i_size : ISOFS_BUFFER_SIZE);
+ for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE(inode) ? inode->i_size : ISOFS_BUFFER_SIZE(inode));
i++,pnt++){
if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;};
if(*pnt >= 0x20 || *pnt == 0x1a) continue;
@@ -139,9 +140,9 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf,
if (left <= 0)
return 0;
read = 0;
- block = filp->f_pos >> ISOFS_BUFFER_BITS;
- offset = filp->f_pos & (ISOFS_BUFFER_SIZE-1);
- blocks = (left + offset + ISOFS_BUFFER_SIZE - 1) / ISOFS_BUFFER_SIZE;
+ block = filp->f_pos >> ISOFS_BUFFER_BITS(inode);
+ offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode)-1);
+ blocks = (left + offset + ISOFS_BUFFER_SIZE(inode) - 1) / ISOFS_BUFFER_SIZE(inode);
bhb = bhe = buflist;
ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
@@ -163,7 +164,7 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf,
while (blocks) {
int uptodate;
--blocks;
- *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE);
+ *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode));
uptodate = 1;
if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0;
@@ -189,7 +190,7 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf,
if (block >= max_block) break;
if(bhrequest == NBUF) break; /* Block full */
--ra_blocks;
- *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE);
+ *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode));
if (*bhb && !(*bhb)->b_uptodate) {
if((*bhb)->b_blocknr != nextblock) {
@@ -220,10 +221,10 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf,
}
}
- if (left < ISOFS_BUFFER_SIZE - offset)
+ if (left < ISOFS_BUFFER_SIZE(inode) - offset)
chars = left;
else
- chars = ISOFS_BUFFER_SIZE - offset;
+ chars = ISOFS_BUFFER_SIZE(inode) - offset;
filp->f_pos += chars;
left -= chars;
read += chars;
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 8baa2fb..23310cd 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -51,34 +51,35 @@ static struct super_operations isofs_sops = {
-static int parse_options(char *options,char *map,char *conversion, char * rock, char * cruft)
+static int parse_options(char *options,char *map,char *conversion, char * rock, char * cruft, unsigned int * blocksize)
{
- char *this,*value;
+ char *this_char,*value;
*map = 'n';
*rock = 'y';
*cruft = 'n';
*conversion = 'a';
+ *blocksize = 1024;
if (!options) return 1;
- for (this = strtok(options,","); this; this = strtok(NULL,",")) {
- if (strncmp(this,"norock",6) == 0) {
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if (strncmp(this_char,"norock",6) == 0) {
*rock = 'n';
continue;
};
- if (strncmp(this,"cruft",5) == 0) {
+ if (strncmp(this_char,"cruft",5) == 0) {
*cruft = 'y';
continue;
};
- if ((value = strchr(this,'=')) != NULL)
+ if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
- if (!strcmp(this,"map") && value) {
+ if (!strcmp(this_char,"map") && value) {
if (value[0] && !value[1] && strchr("on",*value))
*map = *value;
else if (!strcmp(value,"off")) *map = 'o';
else if (!strcmp(value,"normal")) *map = 'n';
else return 0;
}
- else if (!strcmp(this,"conv") && value) {
+ else if (!strcmp(this_char,"conv") && value) {
if (value[0] && !value[1] && strchr("bta",*value))
*conversion = *value;
else if (!strcmp(value,"binary")) *conversion = 'b';
@@ -87,6 +88,19 @@ static int parse_options(char *options,char *map,char *conversion, char * rock,
else if (!strcmp(value,"auto")) *conversion = 'a';
else return 0;
}
+ else if (!strcmp(this_char,"block") && value) {
+ char * vpnt = value;
+ unsigned int ivalue;
+ ivalue = 0;
+ while(*vpnt){
+ if(*vpnt < '0' || *vpnt > '9') break;
+ ivalue = ivalue * 10 + (*vpnt - '0');
+ vpnt++;
+ };
+ if (*vpnt) return 0;
+ if (ivalue != 1024 && ivalue != 2048) return 0;
+ *blocksize = ivalue;
+ }
else return 0;
}
return 1;
@@ -97,6 +111,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
{
struct buffer_head *bh;
int iso_blknum;
+ unsigned int blocksize, blocksize_bits;
int high_sierra;
int dev=s->s_dev;
struct iso_volume_descriptor *vdp;
@@ -109,17 +124,27 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
char map, conversion, rock, cruft;
- if (!parse_options((char *) data,&map,&conversion, &rock, &cruft)) {
+ if (!parse_options((char *) data,&map,&conversion, &rock, &cruft, &blocksize)) {
s->s_dev = 0;
return NULL;
}
+ blocksize_bits = 0;
+ {
+ int i = blocksize;
+ while (i != 1){
+ blocksize_bits++;
+ i >>=1;
+ };
+ };
+ set_blocksize(dev, blocksize);
+
lock_super(s);
s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
- if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-ISOFS_BUFFER_BITS), ISOFS_BUFFER_SIZE))) {
+ if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), blocksize))) {
s->s_dev=0;
printk("isofs_read_super: bread failed, dev 0x%x iso_blknum %d\n",
dev, iso_blknum);
@@ -188,7 +213,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */
s->u.isofs_sb.s_firstdatazone = isonum_733( rootp->extent) <<
- (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS);
+ (ISOFS_BLOCK_BITS - blocksize_bits);
s->s_magic = ISOFS_SUPER_MAGIC;
/* The CDROM is read-only, has no nodes (devices) on it, and since
@@ -219,7 +244,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_rock = (rock == 'y' ? 1 : 0);
s->u.isofs_sb.s_conversion = conversion;
s->u.isofs_sb.s_cruft = cruft;
- s->s_blocksize = ISOFS_BUFFER_SIZE;
+ s->s_blocksize = blocksize;
+ s->s_blocksize_bits = blocksize_bits;
s->s_mounted = iget(s, isonum_733 (rootp->extent) << ISOFS_BLOCK_BITS);
unlock_super(s);
@@ -267,32 +293,33 @@ int isofs_bmap(struct inode * inode,int block)
void isofs_read_inode(struct inode * inode)
{
struct buffer_head * bh;
- unsigned char * pnt, *cpnt = 0;
+ unsigned char *pnt = NULL;
+ void *cpnt = NULL;
struct iso_directory_record * raw_inode;
int high_sierra;
int block;
int i;
-
- block = inode->i_ino >> ISOFS_BUFFER_BITS;
- if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE)))
+
+ block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
+ if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode))))
panic("unable to read i-node block");
- pnt = ((char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE - 1));
+ pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
raw_inode = ((struct iso_directory_record *) pnt);
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
- if ((inode->i_ino & (ISOFS_BUFFER_SIZE - 1)) + *pnt > ISOFS_BUFFER_SIZE){
+
+ if ((inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1)) + *pnt > ISOFS_BUFFER_SIZE(inode)){
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE);
+ memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
brelse(bh);
- if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE)))
+ if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE(inode))))
panic("unable to read i-node block");
- memcpy(cpnt+ISOFS_BUFFER_SIZE, bh->b_data, ISOFS_BUFFER_SIZE);
- pnt = ((char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE - 1));
+ memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
+ pnt = ((unsigned char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
raw_inode = ((struct iso_directory_record *) pnt);
};
-
inode->i_mode = 0444; /* Everybody gets to read the file. */
inode->i_nlink = 1;
@@ -374,9 +401,9 @@ void isofs_read_inode(struct inode * inode)
iso_date(raw_inode->date, high_sierra);
inode->u.isofs_i.i_first_extent = isonum_733 (raw_inode->extent) <<
- (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS);
+ (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(inode));
- inode->u.isofs_i.i_backlink = -1; /* Will be used for previous directory */
+ inode->u.isofs_i.i_backlink = 0xffffffff; /* Will be used for previous directory */
switch (inode->i_sb->u.isofs_sb.s_conversion){
case 'a':
inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN; /* File type */
@@ -406,7 +433,7 @@ void isofs_read_inode(struct inode * inode)
if (cpnt) {
kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS);
- cpnt = 0;
+ cpnt = NULL;
};
inode->i_op = NULL;
@@ -447,14 +474,14 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
unsigned int block,offset;
int parent_dir, inode_number;
int old_offset;
- char * cpnt = 0;
+ void * cpnt = NULL;
int result;
struct buffer_head * bh;
struct iso_directory_record * de;
offset = 0;
- block = extent << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS);
- if (!(bh = bread(parent->i_dev, block, ISOFS_BUFFER_SIZE))) return 0;
+ block = extent << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(parent));
+ if (!(bh = bread(parent->i_dev, block, ISOFS_BUFFER_SIZE(parent)))) return 0;
while (1 == 1) {
de = (struct iso_directory_record *) (offset + bh->b_data);
@@ -467,7 +494,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
offset += *((unsigned char*) de);
- if (offset >= ISOFS_BUFFER_SIZE)
+ if (offset >= ISOFS_BUFFER_SIZE(parent))
{
printk(".. Directory not in first block of directory.\n");
brelse(bh);
@@ -491,13 +518,13 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
result = -1;
offset = 0;
- block = parent_dir << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS);
- if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE)))
+ block = parent_dir << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(parent));
+ if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
return 0;
while (1==1) {
de = (struct iso_directory_record *) (offset + bh->b_data);
- inode_number = (block << ISOFS_BUFFER_BITS)+(offset & (ISOFS_BUFFER_SIZE - 1));
+ inode_number = (block << ISOFS_BUFFER_BITS(parent))+(offset & (ISOFS_BUFFER_SIZE(parent) - 1));
/* If the length byte is zero, we should move on to the next CDROM sector.
If we are at the end of the directory, we kick out of the while loop. */
@@ -508,7 +535,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
offset = 0;
block++;
if(block & 1) return -1;
- if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE)))
+ if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
return -1;
continue;
}
@@ -519,18 +546,19 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
old_offset = offset;
offset += *((unsigned char*) de);
- if (offset >= ISOFS_BUFFER_SIZE)
+
+ if (offset >= ISOFS_BUFFER_SIZE(parent))
{
cpnt = kmalloc(1<<ISOFS_BLOCK_BITS,GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE);
+ memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(parent));
de = (struct iso_directory_record *) (old_offset + cpnt);
brelse(bh);
- offset -= ISOFS_BUFFER_SIZE;
+ offset -= ISOFS_BUFFER_SIZE(parent);
block++;
if((block & 1) == 0) return -1;
- if (!(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE)))
+ if (!(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
return -1;
- memcpy(cpnt+ISOFS_BUFFER_SIZE, bh->b_data, ISOFS_BUFFER_SIZE);
+ memcpy(cpnt+ISOFS_BUFFER_SIZE(parent), bh->b_data, ISOFS_BUFFER_SIZE(parent));
}
if (find_rock_ridge_relocation(de, parent) == extent){
@@ -540,7 +568,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
- cpnt = 0;
+ cpnt = NULL;
};
}
/* We go here for any condition we cannot handle. We also drop through
@@ -549,7 +577,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
out:
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
- cpnt = 0;
+ cpnt = NULL;
};
brelse(bh);
#ifdef DEBUG
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 4ba4262..ca00791 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -66,7 +66,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
{
unsigned int block,i, f_pos, offset, inode_number;
struct buffer_head * bh;
- char * cpnt = 0;
+ void * cpnt = NULL;
unsigned int old_offset;
unsigned int backlink;
int dlen, rrflag, match;
@@ -81,14 +81,15 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
f_pos = 0;
- offset = f_pos & (ISOFS_BUFFER_SIZE - 1);
- block = isofs_bmap(dir,f_pos >> ISOFS_BUFFER_BITS);
- if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE))) return NULL;
+ offset = f_pos & (ISOFS_BUFFER_SIZE(dir) - 1);
+ block = isofs_bmap(dir,f_pos >> ISOFS_BUFFER_BITS(dir));
+
+ if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE(dir)))) return NULL;
while (f_pos < dir->i_size) {
de = (struct iso_directory_record *) (offset + bh->b_data);
backlink = dir->i_ino;
- inode_number = (block << ISOFS_BUFFER_BITS)+(offset & (ISOFS_BUFFER_SIZE - 1));
+ inode_number = (block << ISOFS_BUFFER_BITS(dir))+(offset & (ISOFS_BUFFER_SIZE(dir) - 1));
/* If byte is zero, this is the end of file, or time to move to
the next sector. Usually 2048 byte boundaries. */
@@ -97,8 +98,8 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
brelse(bh);
offset = 0;
f_pos =(f_pos & ~(ISOFS_BLOCK_SIZE - 1))+ISOFS_BLOCK_SIZE;
- block = isofs_bmap(dir,(f_pos)>>ISOFS_BUFFER_BITS);
- if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE)))
+ block = isofs_bmap(dir,(f_pos)>>ISOFS_BUFFER_BITS(dir));
+ if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE(dir))))
return 0;
continue; /* Will kick out if past end of directory */
};
@@ -107,19 +108,19 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
offset += *((unsigned char*) de);
f_pos += *((unsigned char*) de);
+
/* Handle case where the directory entry spans two blocks. Usually
1024 byte boundaries */
-
- if (offset >= ISOFS_BUFFER_SIZE) {
+ if (offset >= ISOFS_BUFFER_SIZE(dir)) {
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE);
+ memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(dir));
de = (struct iso_directory_record *) (old_offset + cpnt);
brelse(bh);
- offset = f_pos & (ISOFS_BUFFER_SIZE - 1);
- block = isofs_bmap(dir,f_pos>>ISOFS_BUFFER_BITS);
- if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE)))
+ offset = f_pos & (ISOFS_BUFFER_SIZE(dir) - 1);
+ block = isofs_bmap(dir,f_pos>>ISOFS_BUFFER_BITS(dir));
+ if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE(dir))))
return 0;
- memcpy(cpnt+ISOFS_BUFFER_SIZE, bh->b_data, ISOFS_BUFFER_SIZE);
+ memcpy(cpnt+ISOFS_BUFFER_SIZE(dir), bh->b_data, ISOFS_BUFFER_SIZE(dir));
}
/* Handle the '.' case */
@@ -133,9 +134,9 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
if (de->name[0]==1 && de->name_len[0]==1) {
#if 0
- printk("Doing .. (%d %d)",dir->i_sb->s_firstdatazone << ISOFS_BUFFER_BITS, dir->i_ino);
+ printk("Doing .. (%d %d)",dir->i_sb->s_firstdatazone << ISOFS_BUFFER_BITS(dir), dir->i_ino);
#endif
- if((dir->i_sb->u.isofs_sb.s_firstdatazone << ISOFS_BUFFER_BITS) != dir->i_ino)
+ if((dir->i_sb->u.isofs_sb.s_firstdatazone << ISOFS_BUFFER_BITS(dir)) != dir->i_ino)
inode_number = dir->u.isofs_i.i_backlink;
else
inode_number = dir->i_ino;
@@ -166,7 +167,10 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
};
};
match = isofs_match(namelen,name,dpnt, dlen);
- if (cpnt) { kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); cpnt = 0;};
+ if (cpnt) {
+ kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
+ cpnt = NULL;
+ }
if(rrflag) kfree(dpnt);
if (match) {
@@ -241,8 +245,9 @@ int isofs_lookup(struct inode * dir,const char * name, int len,
/* We need this backlink for the .. entry */
- if (ino_back && !(*result)->i_pipe)
- (*result)->u.isofs_i.i_backlink = ino_back;
+ if (ino_back && !(*result)->i_pipe)
+ (*result)->u.isofs_i.i_backlink = ino_back;
+
iput(dir);
return 0;
}
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 7bc95c6..29932c4 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -36,7 +36,7 @@
#define CONTINUE_DECLS \
int cont_extent = 0, cont_offset = 0, cont_size = 0; \
- char * buffer = 0
+ void * buffer = 0
#define CHECK_CE \
{cont_extent = isonum_733(rr->u.CE.extent); \
@@ -55,25 +55,27 @@
int block, offset; \
struct buffer_head * bh; \
buffer = kmalloc(cont_size,GFP_KERNEL); \
- block = cont_extent << 1; \
+ block = cont_extent; \
offset = cont_offset; \
- if (offset >= 1024) block++; \
- offset &= 1023; \
- bh = bread(DEV, block, 1024); \
- if (bh) { \
+ if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \
+ block <<= 1; \
+ if (offset >= 1024) block++; \
+ offset &= 1023; \
+ }; \
+ bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
+ if(bh){ \
memcpy(buffer, bh->b_data, cont_size); \
brelse(bh); \
- chr = buffer; \
+ chr = (unsigned char *) buffer; \
len = cont_size; \
cont_extent = 0; \
cont_size = 0; \
cont_offset = 0; \
goto LABEL; \
- } \
- printk("Unable to read rock-ridge descriptor block\n"); \
+ }; \
+ printk("Unable to read rock-ridge attributes\n"); \
}}
-
/* This is the inner layer of the get filename routine, and is called
for each system area and continuation record related to the file */
@@ -143,7 +145,7 @@ int find_rock_ridge_relocation(struct iso_directory_record * de,
}
};
};
- MAYBE_CONTINUE(repeat, inode->i_dev);
+ MAYBE_CONTINUE(repeat, inode);
return retval;
out:
if(buffer) kfree(buffer);
@@ -220,7 +222,7 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
}
};
}
- MAYBE_CONTINUE(repeat,inode->i_dev);
+ MAYBE_CONTINUE(repeat,inode);
if(retname){
*name = retname;
*namlen = retnamlen;
@@ -330,8 +332,8 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
printk("RR CL (%x)\n",inode->i_ino);
#endif
inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
- (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS);
- reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent << ISOFS_BUFFER_BITS);
+ (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(inode));
+ reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent << ISOFS_BUFFER_BITS(inode));
inode->i_mode = reloc->i_mode;
inode->i_nlink = reloc->i_nlink;
inode->i_uid = reloc->i_uid;
@@ -348,7 +350,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
}
};
}
- MAYBE_CONTINUE(repeat,inode->i_dev);
+ MAYBE_CONTINUE(repeat,inode);
return 0;
out:
if(buffer) kfree(buffer);
@@ -362,14 +364,15 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
char * get_rock_ridge_symlink(struct inode * inode)
{
struct buffer_head * bh;
- unsigned char * pnt, *cpnt = 0;
+ unsigned char * pnt;
+ void * cpnt = NULL;
char * rpnt;
struct iso_directory_record * raw_inode;
CONTINUE_DECLS;
int block;
int sig;
int len;
- char * chr;
+ unsigned char * chr;
struct rock_ridge * rr;
if (!inode->i_sb->u.isofs_sb.s_rock)
@@ -377,22 +380,22 @@ char * get_rock_ridge_symlink(struct inode * inode)
rpnt = 0;
- block = inode->i_ino >> ISOFS_BUFFER_BITS;
- if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE)))
+ block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
+ if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode))))
panic("unable to read i-node block");
- pnt = ((char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE - 1));
+ pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
raw_inode = ((struct iso_directory_record *) pnt);
- if ((inode->i_ino & (ISOFS_BUFFER_SIZE - 1)) + *pnt > ISOFS_BUFFER_SIZE){
+ if ((inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1)) + *pnt > ISOFS_BUFFER_SIZE(inode)){
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE);
+ memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
brelse(bh);
- if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE)))
+ if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE(inode))))
panic("unable to read i-node block");
- memcpy(cpnt+ISOFS_BUFFER_SIZE, bh->b_data, ISOFS_BUFFER_SIZE);
- pnt = ((char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE - 1));
+ memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
+ pnt = ((unsigned char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
raw_inode = ((struct iso_directory_record *) pnt);
};
@@ -455,13 +458,14 @@ char * get_rock_ridge_symlink(struct inode * inode)
}
};
};
- MAYBE_CONTINUE(repeat,inode->i_dev);
+ MAYBE_CONTINUE(repeat,inode);
brelse(bh);
if (cpnt) {
kfree(cpnt);
- cpnt = 0;
+ cpnt = NULL;
};
+
return rpnt;
out:
if(buffer) kfree(buffer);
diff --git a/fs/locks.c b/fs/locks.c
index 7aed2cc..43dc61e 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -26,7 +26,7 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l);
static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
static int overlap(struct file_lock *fl1, struct file_lock *fl2);
static int lock_it(struct file *filp, struct file_lock *caller);
-static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *template);
+static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl);
static void free_lock(struct file_lock **fl);
static struct file_lock file_lock_table[NR_FILE_LOCKS];
@@ -398,27 +398,27 @@ next_lock:
*/
static struct file_lock *alloc_lock(struct file_lock **pos,
- struct file_lock *template)
+ struct file_lock *fl)
{
- struct file_lock *new;
+ struct file_lock *tmp;
- new = file_lock_free_list;
- if (new == NULL)
+ tmp = file_lock_free_list;
+ if (tmp == NULL)
return NULL; /* no available entry */
- if (new->fl_owner != NULL)
+ if (tmp->fl_owner != NULL)
panic("alloc_lock: broken free list\n");
/* remove from free list */
- file_lock_free_list = new->fl_next;
+ file_lock_free_list = tmp->fl_next;
- *new = *template;
+ *tmp = *fl;
- new->fl_next = *pos; /* insert into file's list */
- *pos = new;
+ tmp->fl_next = *pos; /* insert into file's list */
+ *pos = tmp;
- new->fl_owner = current; /* FIXME: needed? */
- new->fl_wait = NULL;
- return new;
+ tmp->fl_owner = current; /* FIXME: needed? */
+ tmp->fl_wait = NULL;
+ return tmp;
}
/*
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index b445288..64cfb6f 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -18,7 +18,8 @@
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
- ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
+ : \
+ :"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
#define find_first_zero(addr) ({ \
int __res; \
@@ -90,7 +91,7 @@ void minix_free_block(struct super_block * sb, int block)
printk("minix_free_block: nonexistent bitmap buffer\n");
return;
}
- if (clear_bit(bit,bh->b_data))
+ if (!clear_bit(bit,bh->b_data))
printk("free_block (%04x:%d): bit already cleared\n",sb->s_dev,block);
bh->b_dirt = 1;
return;
@@ -142,6 +143,7 @@ unsigned long minix_count_free_blocks(struct super_block *sb)
void minix_free_inode(struct inode * inode)
{
struct buffer_head * bh;
+ unsigned long ino;
if (!inode)
return;
@@ -165,14 +167,15 @@ void minix_free_inode(struct inode * inode)
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
- if (!(bh=inode->i_sb->u.minix_sb.s_imap[inode->i_ino>>13])) {
+ ino = inode->i_ino;
+ if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
- if (clear_bit(inode->i_ino&8191,bh->b_data))
- printk("free_inode: bit %d already cleared.\n",inode->i_ino);
- bh->b_dirt = 1;
clear_inode(inode);
+ if (!clear_bit(ino & 8191, bh->b_data))
+ printk("free_inode: bit %d already cleared.\n",ino);
+ bh->b_dirt = 1;
}
struct inode * minix_new_inode(const struct inode * dir)
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 75d6b4c..e8191c1 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -39,7 +39,7 @@ static struct file_operations minix_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
- NULL, /* mmap */
+ generic_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
minix_sync_file /* fsync */
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index da3b75b..717cbf6 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -67,6 +67,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
}
ms = (struct minix_super_block *) bh->b_data;
s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
s->u.minix_sb.s_ninodes = ms->s_ninodes;
s->u.minix_sb.s_nzones = ms->s_nzones;
s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks;
@@ -136,7 +137,9 @@ void minix_statfs(struct super_block *sb, struct statfs *buf)
put_fs_long(MINIX_SUPER_MAGIC, &buf->f_type);
put_fs_long(1024, &buf->f_bsize);
- put_fs_long(sb->u.minix_sb.s_nzones << sb->u.minix_sb.s_log_zone_size, &buf->f_blocks);
+ tmp = sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone;
+ tmp <<= sb->u.minix_sb.s_log_zone_size;
+ put_fs_long(tmp, &buf->f_blocks);
tmp = minix_count_free_blocks(sb);
put_fs_long(tmp, &buf->f_bfree);
put_fs_long(tmp, &buf->f_bavail);
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index c5e8285..dbc33c2 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -626,27 +626,27 @@ int minix_link(struct inode * oldinode, struct inode * dir, const char * name, i
return 0;
}
-static int subdir(struct inode * new, struct inode * old)
+static int subdir(struct inode * new_inode, struct inode * old_inode)
{
int ino;
int result;
- new->i_count++;
+ new_inode->i_count++;
result = 0;
for (;;) {
- if (new == old) {
+ if (new_inode == old_inode) {
result = 1;
break;
}
- if (new->i_dev != old->i_dev)
+ if (new_inode->i_dev != old_inode->i_dev)
break;
- ino = new->i_ino;
- if (minix_lookup(new,"..",2,&new))
+ ino = new_inode->i_ino;
+ if (minix_lookup(new_inode,"..",2,&new_inode))
break;
- if (new->i_ino == ino)
+ if (new_inode->i_ino == ino)
break;
}
- iput(new);
+ iput(new_inode);
return result;
}
diff --git a/fs/msdos/fat.c b/fs/msdos/fat.c
index a1c0fa7..b4ec8d7 100644
--- a/fs/msdos/fat.c
+++ b/fs/msdos/fat.c
@@ -15,17 +15,17 @@ static struct fat_cache *fat_cache,cache[FAT_CACHE];
/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
new_value is != -1, that FAT entry is replaced by it. */
-int fat_access(struct super_block *sb,int this,int new_value)
+int fat_access(struct super_block *sb,int nr,int new_value)
{
struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
unsigned char *p_first,*p_last;
void *data,*data2,*c_data,*c_data2;
int first,last,next,copy;
- if ((unsigned) (this-2) >= MSDOS_SB(sb)->clusters) return 0;
- if (MSDOS_SB(sb)->fat_bits == 16) first = last = this*2;
+ if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0;
+ if (MSDOS_SB(sb)->fat_bits == 16) first = last = nr*2;
else {
- first = this*3/2;
+ first = nr*3/2;
last = first+1;
}
if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
@@ -55,7 +55,7 @@ int fat_access(struct super_block *sb,int this,int new_value)
p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)];
p_last = &((unsigned char *) data2)[(first+1) &
(SECTOR_SIZE-1)];
- if (this & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
+ if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
else next = (*p_first+(*p_last << 8)) & 0xfff;
if (next >= 0xff7) next = -1;
}
@@ -64,7 +64,7 @@ int fat_access(struct super_block *sb,int this,int new_value)
((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >>
1] = CT_LE_W(new_value);
else {
- if (this & 1) {
+ if (nr & 1) {
*p_first = (*p_first & 0xf) | (new_value << 4);
*p_last = new_value >> 4;
}
@@ -220,18 +220,18 @@ void cache_inval_dev(int device)
int get_cluster(struct inode *inode,int cluster)
{
- int this,count;
+ int nr,count;
- if (!(this = MSDOS_I(inode)->i_start)) return 0;
- if (!cluster) return this;
+ if (!(nr = MSDOS_I(inode)->i_start)) return 0;
+ if (!cluster) return nr;
count = 0;
- for (cache_lookup(inode,cluster,&count,&this); count < cluster;
+ for (cache_lookup(inode,cluster,&count,&nr); count < cluster;
count++) {
- if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
- if (!this) return 0;
+ if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0;
+ if (!nr) return 0;
}
- cache_add(inode,cluster,this);
- return this;
+ cache_add(inode,cluster,nr);
+ return nr;
}
@@ -258,14 +258,14 @@ int msdos_smap(struct inode *inode,int sector)
int fat_free(struct inode *inode,int skip)
{
- int this,last;
+ int nr,last;
- if (!(this = MSDOS_I(inode)->i_start)) return 0;
+ if (!(nr = MSDOS_I(inode)->i_start)) return 0;
last = 0;
while (skip--) {
- last = this;
- if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
- if (!this) {
+ last = nr;
+ if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0;
+ if (!nr) {
printk("fat_free: skipped EOF\n");
return -EIO;
}
@@ -278,8 +278,8 @@ int fat_free(struct inode *inode,int skip)
inode->i_dirt = 1;
}
lock_fat(inode->i_sb);
- while (this != -1) {
- if (!(this = fat_access(inode->i_sb,this,0))) {
+ while (nr != -1) {
+ if (!(nr = fat_access(inode->i_sb,nr,0))) {
fs_panic(inode->i_sb,"fat_free: deleting beyond EOF");
break;
}
diff --git a/fs/msdos/file.c b/fs/msdos/file.c
index f450937..0bf8f39 100644
--- a/fs/msdos/file.c
+++ b/fs/msdos/file.c
@@ -170,7 +170,7 @@ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
}
else {
written = left = SECTOR_SIZE-offset;
- to = data+(filp->f_pos & (SECTOR_SIZE-1));
+ to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1));
if (carry) {
*to++ = '\n';
left--;
diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c
index 0ef6829..9289e4b 100644
--- a/fs/msdos/inode.c
+++ b/fs/msdos/inode.c
@@ -69,7 +69,7 @@ static struct super_operations msdos_sops = {
static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
gid_t *gid,int *umask,int *debug,int *fat,int *quiet)
{
- char *this,*value;
+ char *this_char,*value;
*check = 'n';
*conversion = 'b';
@@ -78,10 +78,10 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
*umask = current->umask;
*debug = *fat = *quiet = 0;
if (!options) return 1;
- for (this = strtok(options,","); this; this = strtok(NULL,",")) {
- if ((value = strchr(this,'=')) != NULL)
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
- if (!strcmp(this,"check") && value) {
+ if (!strcmp(this_char,"check") && value) {
if (value[0] && !value[1] && strchr("rns",*value))
*check = *value;
else if (!strcmp(value,"relaxed")) *check = 'r';
@@ -89,7 +89,7 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
else if (!strcmp(value,"strict")) *check = 's';
else return 0;
}
- else if (!strcmp(this,"conv") && value) {
+ else if (!strcmp(this_char,"conv") && value) {
if (value[0] && !value[1] && strchr("bta",*value))
*conversion = *value;
else if (!strcmp(value,"binary")) *conversion = 'b';
@@ -97,39 +97,39 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
else if (!strcmp(value,"auto")) *conversion = 'a';
else return 0;
}
- else if (!strcmp(this,"uid")) {
+ else if (!strcmp(this_char,"uid")) {
if (!value || !*value)
return 0;
*uid = simple_strtoul(value,&value,0);
if (*value)
return 0;
}
- else if (!strcmp(this,"gid")) {
+ else if (!strcmp(this_char,"gid")) {
if (!value || !*value)
return 0;
*gid = simple_strtoul(value,&value,0);
if (*value)
return 0;
}
- else if (!strcmp(this,"umask")) {
+ else if (!strcmp(this_char,"umask")) {
if (!value || !*value)
return 0;
*umask = simple_strtoul(value,&value,8);
if (*value)
return 0;
}
- else if (!strcmp(this,"debug")) {
+ else if (!strcmp(this_char,"debug")) {
if (value) return 0;
*debug = 1;
}
- else if (!strcmp(this,"fat")) {
+ else if (!strcmp(this_char,"fat")) {
if (!value || !*value)
return 0;
*fat = simple_strtoul(value,&value,0);
if (*value || (*fat != 12 && *fat != 16))
return 0;
}
- else if (!strcmp(this,"quiet")) {
+ else if (!strcmp(this_char,"quiet")) {
if (value) return 0;
*quiet = 1;
}
@@ -169,6 +169,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data,
}
b = (struct msdos_boot_sector *) bh->b_data;
s->s_blocksize = 1024; /* we cannot handle anything else yet */
+ s->s_blocksize_bits = 10; /* we cannot handle anything else yet */
/*
* The DOS3 partition size limit is *not* 32M as many people think.
@@ -260,7 +261,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data,
void msdos_statfs(struct super_block *sb,struct statfs *buf)
{
- int free,this;
+ int free,nr;
put_fs_long(sb->s_magic,&buf->f_type);
put_fs_long(MSDOS_SB(sb)->cluster_size*SECTOR_SIZE,&buf->f_bsize);
@@ -270,8 +271,8 @@ void msdos_statfs(struct super_block *sb,struct statfs *buf)
free = MSDOS_SB(sb)->free_clusters;
else {
free = 0;
- for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++)
- if (!fat_access(sb,this,-1)) free++;
+ for (nr = 2; nr < MSDOS_SB(sb)->clusters+2; nr++)
+ if (!fat_access(sb,nr,-1)) free++;
MSDOS_SB(sb)->free_clusters = free;
}
unlock_fat(sb);
@@ -305,7 +306,7 @@ void msdos_read_inode(struct inode *inode)
{
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
- int this;
+ int nr;
/* printk("read inode %d\n",inode->i_ino); */
MSDOS_I(inode)->i_busy = 0;
@@ -351,11 +352,11 @@ void msdos_read_inode(struct inode *inode)
}
#endif
inode->i_size = 0;
- if ((this = CF_LE_W(raw_entry->start)) != 0)
- while (this != -1) {
+ if ((nr = CF_LE_W(raw_entry->start)) != 0)
+ while (nr != -1) {
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
i_sb)->cluster_size;
- if (!(this = fat_access(inode->i_sb,this,-1)))
+ if (!(nr = fat_access(inode->i_sb,nr,-1)))
printk("Directory %d: bad FAT\n",
inode->i_ino);
}
diff --git a/fs/msdos/misc.c b/fs/msdos/misc.c
index 697e3be..2eb2abd 100644
--- a/fs/msdos/misc.c
+++ b/fs/msdos/misc.c
@@ -108,7 +108,7 @@ void unlock_fat(struct super_block *sb)
int msdos_add_cluster(struct inode *inode)
{
- int count,this,limit,last,current,sector;
+ int count,nr,limit,last,current,sector;
void *data;
struct buffer_head *bh;
@@ -116,13 +116,13 @@ int msdos_add_cluster(struct inode *inode)
if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
lock_fat(inode->i_sb);
limit = MSDOS_SB(inode->i_sb)->clusters;
- this = limit; /* to keep GCC happy */
+ nr = limit; /* to keep GCC happy */
for (count = 0; count < limit; count++) {
- this = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
- if (fat_access(inode->i_sb,this,-1) == 0) break;
+ nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
+ if (fat_access(inode->i_sb,nr,-1) == 0) break;
}
#ifdef DEBUG
-printk("free cluster: %d\n",this);
+printk("free cluster: %d\n",nr);
#endif
MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)->
prev_free+1) % limit;
@@ -131,13 +131,13 @@ printk("free cluster: %d\n",this);
unlock_fat(inode->i_sb);
return -ENOSPC;
}
- fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
+ fat_access(inode->i_sb,nr,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
0xff8 : 0xfff8);
if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
MSDOS_SB(inode->i_sb)->free_clusters--;
unlock_fat(inode->i_sb);
#ifdef DEBUG
-printk("set to %x\n",fat_access(inode->i_sb,this,-1));
+printk("set to %x\n",fat_access(inode->i_sb,nr,-1));
#endif
last = 0;
if ((current = MSDOS_I(inode)->i_start) != 0) {
@@ -152,9 +152,9 @@ printk("set to %x\n",fat_access(inode->i_sb,this,-1));
#ifdef DEBUG
printk("last = %d\n",last);
#endif
- if (last) fat_access(inode->i_sb,last,this);
+ if (last) fat_access(inode->i_sb,last,nr);
else {
- MSDOS_I(inode)->i_start = this;
+ MSDOS_I(inode)->i_start = nr;
inode->i_dirt = 1;
}
#ifdef DEBUG
@@ -162,7 +162,7 @@ if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
#endif
for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
current++) {
- sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
+ sector = MSDOS_SB(inode->i_sb)->data_start+(nr-2)*
MSDOS_SB(inode->i_sb)->cluster_size+current;
#ifdef DEBUG
printk("zeroing sector %d\n",sector);
@@ -455,7 +455,7 @@ static int raw_scan(struct super_block *sb,int start,char *name,int *number,
int msdos_parent_ino(struct inode *dir,int locked)
{
static int zero = 0;
- int error,current,prev,this;
+ int error,current,prev,nr;
if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
@@ -465,21 +465,21 @@ int msdos_parent_ino(struct inode *dir,int locked)
if (!locked) unlock_creation();
return current;
}
- if (!current) this = MSDOS_ROOT_INO;
+ if (!current) nr = MSDOS_ROOT_INO;
else {
if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,&zero,NULL,
NULL,NULL)) < 0) {
if (!locked) unlock_creation();
return prev;
}
- if ((error = raw_scan(dir->i_sb,prev,NULL,&current,&this,NULL,
+ if ((error = raw_scan(dir->i_sb,prev,NULL,&current,&nr,NULL,
NULL)) < 0) {
if (!locked) unlock_creation();
return error;
}
}
if (!locked) unlock_creation();
- return this;
+ return nr;
}
diff --git a/fs/namei.c b/fs/namei.c
index 6d922d1..c864777 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -360,20 +360,23 @@ int open_namei(const char * pathname, int flag, int mode,
return -EROFS;
}
}
- if ((inode->i_count > 1) && (flag & 2))
+ if ((inode->i_count > 1) && (flag & 2)) {
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ struct vm_area_struct * mpnt;
if (!*p)
continue;
if (inode == (*p)->executable) {
iput(inode);
return -ETXTBSY;
}
- for (i=0; i < (*p)->numlibraries; i++)
- if (inode == (*p)->libraries[i].library) {
- iput(inode);
- return -ETXTBSY;
- }
+ for(mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next) {
+ if (inode == mpnt->vm_inode) {
+ iput(inode);
+ return -ETXTBSY;
+ }
+ }
}
+ }
*res_inode = inode;
return 0;
}
@@ -407,7 +410,7 @@ int do_mknod(const char * filename, int mode, dev_t dev)
return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
-int sys_mknod(const char * filename, int mode, dev_t dev)
+extern "C" int sys_mknod(const char * filename, int mode, dev_t dev)
{
int error;
char * tmp;
@@ -450,7 +453,7 @@ static int do_mkdir(const char * pathname, int mode)
return dir->i_op->mkdir(dir,basename,namelen,mode);
}
-int sys_mkdir(const char * pathname, int mode)
+extern "C" int sys_mkdir(const char * pathname, int mode)
{
int error;
char * tmp;
@@ -491,7 +494,7 @@ static int do_rmdir(const char * name)
return dir->i_op->rmdir(dir,basename,namelen);
}
-int sys_rmdir(const char * pathname)
+extern "C" int sys_rmdir(const char * pathname)
{
int error;
char * tmp;
@@ -532,7 +535,7 @@ static int do_unlink(const char * name)
return dir->i_op->unlink(dir,basename,namelen);
}
-int sys_unlink(const char * pathname)
+extern "C" int sys_unlink(const char * pathname)
{
int error;
char * tmp;
@@ -573,19 +576,19 @@ static int do_symlink(const char * oldname, const char * newname)
return dir->i_op->symlink(dir,basename,namelen,oldname);
}
-int sys_symlink(const char * oldname, const char * newname)
+extern "C" int sys_symlink(const char * oldname, const char * newname)
{
int error;
- char * old, * new;
+ char * from, * to;
- error = getname(oldname,&old);
+ error = getname(oldname,&from);
if (!error) {
- error = getname(newname,&new);
+ error = getname(newname,&to);
if (!error) {
- error = do_symlink(old,new);
- putname(new);
+ error = do_symlink(from,to);
+ putname(to);
}
- putname(old);
+ putname(from);
}
return error;
}
@@ -629,19 +632,19 @@ static int do_link(struct inode * oldinode, const char * newname)
return dir->i_op->link(oldinode, dir, basename, namelen);
}
-int sys_link(const char * oldname, const char * newname)
+extern "C" int sys_link(const char * oldname, const char * newname)
{
int error;
- char * new;
+ char * to;
struct inode * oldinode;
error = namei(oldname, &oldinode);
if (error)
return error;
- error = getname(newname,&new);
+ error = getname(newname,&to);
if (!error) {
- error = do_link(oldinode,new);
- putname(new);
+ error = do_link(oldinode,to);
+ putname(to);
}
return error;
}
@@ -701,19 +704,19 @@ static int do_rename(const char * oldname, const char * newname)
new_dir, new_base, new_len);
}
-int sys_rename(const char * oldname, const char * newname)
+extern "C" int sys_rename(const char * oldname, const char * newname)
{
int error;
- char * old, * new;
+ char * from, * to;
- error = getname(oldname,&old);
+ error = getname(oldname,&from);
if (!error) {
- error = getname(newname,&new);
+ error = getname(newname,&to);
if (!error) {
- error = do_rename(old,new);
- putname(new);
+ error = do_rename(from,to);
+ putname(to);
}
- putname(old);
+ putname(from);
}
return error;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f225ce2..4f5f0c0 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -343,8 +343,8 @@ static int nfs_create(struct inode *dir, const char *name, int len, int mode,
return -ENAMETOOLONG;
}
sattr.mode = mode;
- sattr.uid = sattr.gid = sattr.size = -1;
- sattr.atime.seconds = sattr.mtime.seconds = -1;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
if ((error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
name, &sattr, &fhandle, &fattr))) {
iput(dir);
@@ -377,12 +377,12 @@ static int nfs_mknod(struct inode *dir, const char *name, int len,
return -ENAMETOOLONG;
}
sattr.mode = mode;
- sattr.uid = sattr.gid = -1;
+ sattr.uid = sattr.gid = (unsigned) -1;
if (S_ISCHR(mode) || S_ISBLK(mode))
sattr.size = rdev; /* get out your barf bag */
else
- sattr.size = -1;
- sattr.atime.seconds = sattr.mtime.seconds = -1;
+ sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
name, &sattr, &fhandle, &fattr);
if (!error)
@@ -408,8 +408,8 @@ static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode)
return -ENAMETOOLONG;
}
sattr.mode = mode;
- sattr.uid = sattr.gid = sattr.size = -1;
- sattr.atime.seconds = sattr.mtime.seconds = -1;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
name, &sattr, &fhandle, &fattr);
if (!error)
@@ -478,8 +478,8 @@ static int nfs_symlink(struct inode *dir, const char *name, int len,
return -ENAMETOOLONG;
}
sattr.mode = S_IFLNK | 0777; /* SunOS 4.1.2 crashes without this! */
- sattr.uid = sattr.gid = sattr.size = -1;
- sattr.atime.seconds = sattr.mtime.seconds = -1;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
name, symname, &sattr);
iput(dir);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 68e173f..47c46c1 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -89,6 +89,7 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
filp->f_count++;
lock_super(sb);
sb->s_blocksize = 1024; /* XXX */
+ sb->s_blocksize_bits = 10;
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_dev = dev;
sb->s_op = &nfs_sops;
@@ -200,17 +201,17 @@ int nfs_notify_change(int flags, struct inode *inode)
if (flags & NOTIFY_MODE)
sattr.mode = inode->i_mode;
else
- sattr.mode = -1;
+ sattr.mode = (unsigned) -1;
if (flags & NOTIFY_UIDGID) {
sattr.uid = inode->i_uid;
sattr.gid = inode->i_gid;
}
else
- sattr.uid = sattr.gid = -1;
+ sattr.uid = sattr.gid = (unsigned) -1;
if (flags & NOTIFY_SIZE)
sattr.size = S_ISREG(inode->i_mode) ? inode->i_size : -1;
else
- sattr.size = -1;
+ sattr.size = (unsigned) -1;
if (flags & NOTIFY_TIME) {
sattr.mtime.seconds = inode->i_mtime;
sattr.mtime.useconds = 0;
@@ -218,8 +219,8 @@ int nfs_notify_change(int flags, struct inode *inode)
sattr.atime.useconds = 0;
}
else {
- sattr.mtime.seconds = sattr.mtime.useconds = -1;
- sattr.atime.seconds = sattr.atime.useconds = -1;
+ sattr.mtime.seconds = sattr.mtime.useconds = (unsigned) -1;
+ sattr.atime.seconds = sattr.atime.useconds = (unsigned) -1;
}
error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
&sattr, &fattr);
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 7e58c0d..df5bfc4 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -102,7 +102,6 @@ static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
if (len > maxlen)
return NULL;
memcpy(data, (char *) p, len);
- data[len] = '\0';
p += (len + 3) >> 2;
return p;
}
@@ -617,7 +616,7 @@ static int *nfs_rpc_header(int *p, int procedure)
int *p1, *p2;
int i;
static int xid = 0;
- unsigned char *sys = system_utsname.nodename;
+ unsigned char *sys = (unsigned char *) system_utsname.nodename;
if (xid == 0) {
xid = CURRENT_TIME;
@@ -632,7 +631,7 @@ static int *nfs_rpc_header(int *p, int procedure)
*p++ = htonl(RPC_AUTH_UNIX);
p1 = p++;
*p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
- p = xdr_encode_string(p, sys);
+ p = xdr_encode_string(p, (char *) sys);
*p++ = htonl(current->euid);
*p++ = htonl(current->egid);
p2 = p++;
diff --git a/fs/open.c b/fs/open.c
index 421d22f..914a546 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -21,12 +21,12 @@
extern void fcntl_remove_locks(struct task_struct *, struct file *);
-int sys_ustat(int dev, struct ustat * ubuf)
+extern "C" int sys_ustat(int dev, struct ustat * ubuf)
{
return -ENOSYS;
}
-int sys_statfs(const char * path, struct statfs * buf)
+extern "C" int sys_statfs(const char * path, struct statfs * buf)
{
struct inode * inode;
int error;
@@ -46,7 +46,7 @@ int sys_statfs(const char * path, struct statfs * buf)
return 0;
}
-int sys_fstatfs(unsigned int fd, struct statfs * buf)
+extern "C" int sys_fstatfs(unsigned int fd, struct statfs * buf)
{
struct inode * inode;
struct file * file;
@@ -65,7 +65,7 @@ int sys_fstatfs(unsigned int fd, struct statfs * buf)
return 0;
}
-int sys_truncate(const char * path, unsigned int length)
+extern "C" int sys_truncate(const char * path, unsigned int length)
{
struct inode * inode;
int error;
@@ -91,7 +91,7 @@ int sys_truncate(const char * path, unsigned int length)
return error;
}
-int sys_ftruncate(unsigned int fd, unsigned int length)
+extern "C" int sys_ftruncate(unsigned int fd, unsigned int length)
{
struct inode * inode;
struct file * file;
@@ -114,7 +114,7 @@ int sys_ftruncate(unsigned int fd, unsigned int length)
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
-int sys_utime(char * filename, struct utimbuf * times)
+extern "C" int sys_utime(char * filename, struct utimbuf * times)
{
struct inode * inode;
long actime,modtime;
@@ -155,7 +155,7 @@ int sys_utime(char * filename, struct utimbuf * times)
* XXX we should use the real ids for checking _all_ components of the
* path. Now we only use them for the final compenent of the path.
*/
-int sys_access(const char * filename,int mode)
+extern "C" int sys_access(const char * filename,int mode)
{
struct inode * inode;
int res, i_mode;
@@ -189,7 +189,7 @@ int sys_access(const char * filename,int mode)
return -EACCES;
}
-int sys_chdir(const char * filename)
+extern "C" int sys_chdir(const char * filename)
{
struct inode * inode;
int error;
@@ -210,7 +210,7 @@ int sys_chdir(const char * filename)
return (0);
}
-int sys_chroot(const char * filename)
+extern "C" int sys_chroot(const char * filename)
{
struct inode * inode;
int error;
@@ -231,7 +231,7 @@ int sys_chroot(const char * filename)
return (0);
}
-int sys_fchmod(unsigned int fd, mode_t mode)
+extern "C" int sys_fchmod(unsigned int fd, mode_t mode)
{
struct inode * inode;
struct file * file;
@@ -252,7 +252,7 @@ int sys_fchmod(unsigned int fd, mode_t mode)
return notify_change(NOTIFY_MODE, inode);
}
-int sys_chmod(const char * filename, mode_t mode)
+extern "C" int sys_chmod(const char * filename, mode_t mode)
{
struct inode * inode;
int error;
@@ -278,7 +278,7 @@ int sys_chmod(const char * filename, mode_t mode)
return error;
}
-int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+extern "C" int sys_fchown(unsigned int fd, uid_t user, gid_t group)
{
struct inode * inode;
struct file * file;
@@ -305,7 +305,7 @@ int sys_fchown(unsigned int fd, uid_t user, gid_t group)
return -EPERM;
}
-int sys_chown(const char * filename, uid_t user, gid_t group)
+extern "C" int sys_chown(const char * filename, uid_t user, gid_t group)
{
struct inode * inode;
int error;
@@ -350,7 +350,7 @@ int sys_chown(const char * filename, uid_t user, gid_t group)
* for the internal routines (ie open_namei()/follow_link() etc). 00 is
* used by symlinks.
*/
-int sys_open(const char * filename,int flags,int mode)
+extern "C" int sys_open(const char * filename,int flags,int mode)
{
struct inode * inode;
struct file * f;
@@ -414,7 +414,7 @@ int sys_open(const char * filename,int flags,int mode)
return (fd);
}
-int sys_creat(const char * pathname, int mode)
+extern "C" int sys_creat(const char * pathname, int mode)
{
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
@@ -442,7 +442,7 @@ int close_fp(struct file *filp)
return 0;
}
-int sys_close(unsigned int fd)
+extern "C" int sys_close(unsigned int fd)
{
struct file * filp;
@@ -459,7 +459,7 @@ int sys_close(unsigned int fd)
* This routine simulates a hangup on the tty, to arrange that users
* are given clean terminals at login time.
*/
-int sys_vhangup(void)
+extern "C" int sys_vhangup(void)
{
struct tty_struct *tty;
diff --git a/fs/pipe.c b/fs/pipe.c
index 1c74c94..1f407f5 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -132,7 +132,52 @@ static int pipe_select(struct inode * inode, struct file * filp, int sel_type, s
select_wait(&PIPE_READ_WAIT(*inode), wait);
return 0;
case SEL_OUT:
- if (!PIPE_FULL(*inode) || !PIPE_WRITERS(*inode))
+ if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
+ return 1;
+ select_wait(&PIPE_WRITE_WAIT(*inode), wait);
+ return 0;
+ case SEL_EX:
+ if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
+ return 1;
+ select_wait(&inode->i_wait,wait);
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * The 'connect_xxx()' functions are needed for named pipes when
+ * the open() code hasn't guaranteed a connection (O_NONBLOCK),
+ * and we need to act differently until we do get a writer..
+ */
+static int connect_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ while (!PIPE_SIZE(*inode)) {
+ if (PIPE_WRITERS(*inode))
+ break;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ wake_up(& PIPE_WRITE_WAIT(*inode));
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ interruptible_sleep_on(& PIPE_READ_WAIT(*inode));
+ }
+ filp->f_op = &read_pipe_fops;
+ return pipe_read(inode,filp,buf,count);
+}
+
+static int connect_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+{
+ switch (sel_type) {
+ case SEL_IN:
+ if (!PIPE_EMPTY(*inode)) {
+ filp->f_op = &read_pipe_fops;
+ return 1;
+ }
+ select_wait(&PIPE_READ_WAIT(*inode), wait);
+ return 0;
+ case SEL_OUT:
+ if (!PIPE_FULL(*inode))
return 1;
select_wait(&PIPE_WRITE_WAIT(*inode), wait);
return 0;
@@ -170,9 +215,22 @@ static void pipe_rdwr_release(struct inode * inode, struct file * filp)
}
/*
- * The three file_operations structs are not static because they
+ * The file_operations structs are not static because they
* are also used in linux/fs/fifo.c to do operations on fifo's.
*/
+struct file_operations connecting_pipe_fops = {
+ pipe_lseek,
+ connect_read,
+ bad_pipe_rw,
+ pipe_readdir,
+ connect_select,
+ pipe_ioctl,
+ NULL, /* no mmap on pipes.. surprise */
+ NULL, /* no special open code */
+ pipe_read_release,
+ NULL
+};
+
struct file_operations read_pipe_fops = {
pipe_lseek,
pipe_read,
@@ -212,7 +270,25 @@ struct file_operations rdwr_pipe_fops = {
NULL
};
-int sys_pipe(unsigned long * fildes)
+struct inode_operations pipe_inode_operations = {
+ &rdwr_pipe_fops,
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+extern "C" int sys_pipe(unsigned long * fildes)
{
struct inode * inode;
struct file * f[2];
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 9e4f2c2..bc43cac 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -19,6 +19,10 @@
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+#ifdef CONFIG_DEBUG_MALLOC
+int get_malloc(char * buffer);
+#endif
+
static int get_loadavg(char * buffer)
{
int a, b, c;
@@ -262,13 +266,13 @@ static int get_statm(int pid, char * buffer)
return 0;
tpag = (*p)->end_code / PAGE_SIZE;
if ((*p)->state != TASK_ZOMBIE) {
- pagedir = (void *)((*p)->tss.cr3 + ((*p)->start_code >> 20));
+ pagedir = (unsigned long *)((*p)->tss.cr3 + ((*p)->start_code >> 20));
for (i = 0; i < 0x300; ++i) {
if ((ptbl = pagedir[i]) == 0) {
tpag -= 1024;
continue;
}
- buf = (void *)(ptbl & 0xfffff000);
+ buf = (unsigned long *)(ptbl & 0xfffff000);
for (pte = buf; pte < (buf + 1024); ++pte) {
if (*pte != 0) {
++size;
@@ -338,6 +342,11 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
case 12:
length = get_statm(pid, page);
break;
+#ifdef CONFIG_DEBUG_MALLOC
+ case 13:
+ length = get_malloc(page);
+ break;
+#endif
default:
free_page((unsigned long) page);
return -EBADF;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ac06664..b6df88d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -58,7 +58,7 @@ static struct proc_dir_entry base_dir[] = {
{ 5,4,"root" },
{ 6,3,"exe" },
{ 7,2,"fd" },
- { 8,3,"lib" },
+ { 8,4,"mmap" },
{ 9,7,"environ" },
{ 10,7,"cmdline" },
{ 11,4,"stat" },
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index ba4dcb7..a130e30 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -109,7 +109,12 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
return -ENOENT;
ino = (pid << 16) + 0x100 + fd;
} else {
- if (fd >= p->numlibraries)
+ int j = 0;
+ struct vm_area_struct * mpnt;
+ for (mpnt = p->mmap; mpnt; mpnt = mpnt->vm_next)
+ if (mpnt->vm_inode)
+ j++;
+ if (fd >= j)
return -ENOENT;
ino = (pid << 16) + 0x200 + fd;
}
@@ -160,9 +165,15 @@ static int proc_readfd(struct inode * inode, struct file * filp,
break;
if (!p->filp[fd] || !p->filp[fd]->f_inode)
continue;
- } else
- if (fd >= p->numlibraries)
+ } else {
+ int j = 0;
+ struct vm_area_struct * mpnt;
+ for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next)
+ if (mpnt->vm_inode)
+ j++;
+ if (fd >= j)
break;
+ }
j = 10;
i = 1;
while (fd >= j) {
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index d6c4411..cb2353f 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -46,6 +46,7 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
{
lock_super(s);
s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
s->s_magic = PROC_SUPER_MAGIC;
s->s_op = &proc_sops;
unlock_super(s);
@@ -169,8 +170,15 @@ void proc_read_inode(struct inode * inode)
return;
case 2:
ino &= 0xff;
- if (ino >= p->numlibraries)
- return;
+ {
+ int j = 0;
+ struct vm_area_struct * mpnt;
+ for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next)
+ if(mpnt->vm_inode)
+ j++;
+ if (ino >= j)
+ return;
+ }
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
inode->i_mode = S_IFLNK | 0700;
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 3ef339f..bb0e51c 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -17,7 +17,7 @@
extern unsigned long log_size;
extern struct wait_queue * log_wait;
-extern int sys_syslog(int type, char * bug, int count);
+extern "C" int sys_syslog(int type, char * bug, int count);
static int kmsg_open(struct inode * inode, struct file * file)
{
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 9f96279..95c3420 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -79,8 +79,19 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
break;
case 2:
ino &= 0xff;
- if (ino < p->numlibraries)
- inode = p->libraries[ino].library;
+ { int j = ino;
+ struct vm_area_struct * mpnt;
+ for(mpnt = p->mmap; mpnt && j >= 0;
+ mpnt = mpnt->vm_next){
+ if(mpnt->vm_inode) {
+ if(j == 0) {
+ inode = mpnt->vm_inode;
+ break;
+ };
+ j--;
+ }
+ }
+ };
}
}
if (!inode)
diff --git a/fs/proc/root.c b/fs/proc/root.c
index f1b9e7d..691f5f9 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -12,6 +12,7 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/config.h>
static int proc_readroot(struct inode *, struct file *, struct dirent *, int);
static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
@@ -59,7 +60,10 @@ static struct proc_dir_entry root_dir[] = {
{ 5,4,"kmsg" },
{ 6,7,"version" },
{ 7,4,"self" }, /* will change inode # */
- { 8,3,"net" }
+ { 8,3,"net" },
+#ifdef CONFIG_DEBUG_MALLOC
+ {13,6,"malloc" },
+#endif
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
diff --git a/fs/read_write.c b/fs/read_write.c
index 1d5d334..32a5a0e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -16,7 +16,7 @@
* Count is not yet used: but we'll probably support reading several entries
* at once in the future. Use count=1 in the library for future expansions.
*/
-int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
+extern "C" int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
{
int error;
struct file * file;
@@ -34,7 +34,7 @@ int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
return error;
}
-int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
+extern "C" int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
struct file * file;
int tmp = -1;
@@ -67,7 +67,7 @@ int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
return file->f_pos;
}
-int sys_read(unsigned int fd,char * buf,unsigned int count)
+extern "C" int sys_read(unsigned int fd,char * buf,unsigned int count)
{
int error;
struct file * file;
@@ -87,7 +87,7 @@ int sys_read(unsigned int fd,char * buf,unsigned int count)
return file->f_op->read(inode,file,buf,count);
}
-int sys_write(unsigned int fd,char * buf,unsigned int count)
+extern "C" int sys_write(unsigned int fd,char * buf,unsigned int count)
{
int error;
struct file * file;
diff --git a/fs/select.c b/fs/select.c
index ebdff95..0311289 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -193,7 +193,7 @@ __set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
* Update: ERESTARTSYS breaks at least the xview clock binary, so
* I'm trying ERESTARTNOHAND which restart only when you want to.
*/
-int sys_select( unsigned long *buffer )
+extern "C" int sys_select( unsigned long *buffer )
{
/* Perform the select(nd, in, out, ex, tv) system call. */
int i;
diff --git a/fs/stat.c b/fs/stat.c
index abdc27e..42033ae 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -55,18 +55,29 @@ static void cp_new_stat(struct inode * inode, struct new_stat * statbuf)
* this simple algorithm to get a reasonable (although not 100% accurate)
* value.
*/
+
+/*
+ * Use minix fs values for the number of direct and indirect blocks. The
+ * count is now exact for the minix fs except that it counts zero blocks.
+ * Everything is in BLOCK_SIZE'd units until the assignment to
+ * tmp.st_blksize.
+ */
+#define D_B 7
+#define I_B (BLOCK_SIZE / sizeof(unsigned short))
+
if (!inode->i_blksize) {
- blocks = (tmp.st_size + 511) / 512;
- if (blocks > 10) {
- indirect = (blocks - 11)/256+1;
- if (blocks > 10+256) {
- indirect += (blocks - 267)/(256*256)+1;
- if (blocks > 10+256+256*256)
- indirect++;
- }
+ blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ if (blocks > D_B) {
+ indirect = (blocks - D_B + I_B - 1) / I_B;
blocks += indirect;
+ if (indirect > 1) {
+ indirect = (indirect - 1 + I_B - 1) / I_B;
+ blocks += indirect;
+ if (indirect > 1)
+ blocks++;
+ }
}
- tmp.st_blocks = blocks;
+ tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
tmp.st_blksize = BLOCK_SIZE;
} else {
tmp.st_blocks = inode->i_blocks;
@@ -75,7 +86,7 @@ static void cp_new_stat(struct inode * inode, struct new_stat * statbuf)
memcpy_tofs(statbuf,&tmp,sizeof(tmp));
}
-int sys_stat(char * filename, struct old_stat * statbuf)
+extern "C" int sys_stat(char * filename, struct old_stat * statbuf)
{
struct inode * inode;
int error;
@@ -91,7 +102,7 @@ int sys_stat(char * filename, struct old_stat * statbuf)
return 0;
}
-int sys_newstat(char * filename, struct new_stat * statbuf)
+extern "C" int sys_newstat(char * filename, struct new_stat * statbuf)
{
struct inode * inode;
int error;
@@ -107,7 +118,7 @@ int sys_newstat(char * filename, struct new_stat * statbuf)
return 0;
}
-int sys_lstat(char * filename, struct old_stat * statbuf)
+extern "C" int sys_lstat(char * filename, struct old_stat * statbuf)
{
struct inode * inode;
int error;
@@ -123,7 +134,7 @@ int sys_lstat(char * filename, struct old_stat * statbuf)
return 0;
}
-int sys_newlstat(char * filename, struct new_stat * statbuf)
+extern "C" int sys_newlstat(char * filename, struct new_stat * statbuf)
{
struct inode * inode;
int error;
@@ -139,7 +150,7 @@ int sys_newlstat(char * filename, struct new_stat * statbuf)
return 0;
}
-int sys_fstat(unsigned int fd, struct old_stat * statbuf)
+extern "C" int sys_fstat(unsigned int fd, struct old_stat * statbuf)
{
struct file * f;
struct inode * inode;
@@ -154,7 +165,7 @@ int sys_fstat(unsigned int fd, struct old_stat * statbuf)
return 0;
}
-int sys_newfstat(unsigned int fd, struct new_stat * statbuf)
+extern "C" int sys_newfstat(unsigned int fd, struct new_stat * statbuf)
{
struct file * f;
struct inode * inode;
@@ -169,7 +180,7 @@ int sys_newfstat(unsigned int fd, struct new_stat * statbuf)
return 0;
}
-int sys_readlink(const char * path, char * buf, int bufsiz)
+extern "C" int sys_readlink(const char * path, char * buf, int bufsiz)
{
struct inode * inode;
int error;
diff --git a/fs/super.c b/fs/super.c
index 294d512..420d3b7 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -32,7 +32,7 @@ extern void fcntl_init_locks(void);
extern int root_mountflags;
-struct super_block super_block[NR_SUPER];
+struct super_block super_blocks[NR_SUPER];
static int do_remount_sb(struct super_block *sb, int flags);
@@ -70,7 +70,7 @@ void sync_supers(dev_t dev)
{
struct super_block * sb;
- for (sb = super_block + 0 ; sb < super_block + NR_SUPER ; sb++) {
+ for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) {
if (!sb->s_dev)
continue;
if (dev && sb->s_dev != dev)
@@ -91,13 +91,13 @@ static struct super_block * get_super(dev_t dev)
if (!dev)
return NULL;
- s = 0+super_block;
- while (s < NR_SUPER+super_block)
+ s = 0+super_blocks;
+ while (s < NR_SUPER+super_blocks)
if (s->s_dev == dev) {
wait_on_super(s);
if (s->s_dev == dev)
return s;
- s = 0+super_block;
+ s = 0+super_blocks;
} else
s++;
return NULL;
@@ -140,8 +140,8 @@ static struct super_block * read_super(dev_t dev,char *name,int flags,
MAJOR(dev), MINOR(dev), name);
return NULL;
}
- for (s = 0+super_block ;; s++) {
- if (s >= NR_SUPER+super_block)
+ for (s = 0+super_blocks ;; s++) {
+ if (s >= NR_SUPER+super_blocks)
return NULL;
if (!s->s_dev)
break;
@@ -243,7 +243,7 @@ static int do_umount(dev_t dev)
* functions, they should be faked here. -- jrs
*/
-int sys_umount(char * name)
+extern "C" int sys_umount(char * name)
{
struct inode * inode;
dev_t dev;
@@ -390,7 +390,7 @@ static int do_remount(const char *dir,int flags)
* isn't present, the flags and data info isn't used, as the syscall assumes we
* are talking to an older version that didn't understand them.
*/
-int sys_mount(char * dev_name, char * dir_name, char * type,
+extern "C" int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
{
struct file_system_type * fstype;
@@ -479,7 +479,7 @@ void mount_root(void)
struct super_block * sb;
struct inode * inode;
- memset(super_block, 0, sizeof(super_block));
+ memset(super_blocks, 0, sizeof(super_blocks));
fcntl_init_locks();
if (MAJOR(ROOT_DEV) == 2) {
printk("VFS: Insert root floppy and press ENTER");
diff --git a/fs/xiafs/bitmap.c b/fs/xiafs/bitmap.c
index 2b5f990..fceb732 100644
--- a/fs/xiafs/bitmap.c
+++ b/fs/xiafs/bitmap.c
@@ -283,7 +283,8 @@ int xiafs_new_zone(struct super_block * sb, u_long prev_addr)
void xiafs_free_inode(struct inode * inode)
{
struct buffer_head * bh;
- int tmp;
+ struct super_block * sb;
+ unsigned long ino;
if (!inode)
return;
@@ -292,16 +293,17 @@ void xiafs_free_inode(struct inode * inode)
printk("XIA-FS: bad inode (%s %d)\n", WHERE_ERR);
return;
}
- bh = get_imap_zone(inode->i_sb, inode->i_ino, NULL);
+ sb = inode->i_sb;
+ ino = inode->i_ino;
+ bh = get_imap_zone(sb, ino, NULL);
if (!bh)
return;
- tmp = inode->i_ino & (XIAFS_BITS_PER_Z(inode->i_sb)-1);
- if (clear_bit(tmp, bh->b_data))
+ clear_inode(inode);
+ if (clear_bit(ino & (XIAFS_BITS_PER_Z(sb)-1), bh->b_data))
printk("XIA-FS: bit %d (0x%x) already cleared (%s %d)\n",
- inode->i_ino, inode->i_ino, WHERE_ERR);
+ ino, ino, WHERE_ERR);
bh->b_dirt = 1;
- xiafs_unlock_super(inode->i_sb, inode->i_sb->u.xiafs_sb.s_imap_cached);
- clear_inode(inode);
+ xiafs_unlock_super(sb, sb->u.xiafs_sb.s_imap_cached);
}
struct inode * xiafs_new_inode(struct inode * dir)
diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c
index af74628..4d02217 100644
--- a/fs/xiafs/file.c
+++ b/fs/xiafs/file.c
@@ -42,7 +42,7 @@ static struct file_operations xiafs_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
- NULL, /* mmap */
+ generic_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
xiafs_sync_file /* fsync */
diff --git a/fs/xiafs/fsync.c b/fs/xiafs/fsync.c
index 0e84f54..039272f 100644
--- a/fs/xiafs/fsync.c
+++ b/fs/xiafs/fsync.c
@@ -27,7 +27,7 @@
#define blocksize (XIAFS_ZSIZE(inode->i_sb))
#define addr_per_block (XIAFS_ADDRS_PER_Z(inode->i_sb))
-static int sync_block (struct inode * inode, int * block, int wait)
+static int sync_block (struct inode * inode, unsigned long * block, int wait)
{
struct buffer_head * bh;
int tmp;
@@ -56,7 +56,7 @@ static int sync_block (struct inode * inode, int * block, int wait)
return 0;
}
-static int sync_iblock (struct inode * inode, int * iblock,
+static int sync_iblock (struct inode * inode, unsigned long * iblock,
struct buffer_head **bh, int wait)
{
int rc, tmp;
@@ -107,7 +107,7 @@ static int sync_indirect(struct inode *inode, unsigned long *iblock, int wait)
for (i = 0; i < addr_per_block; i++) {
rc = sync_block (inode,
- ((daddr_t *) ind_bh->b_data) + i,
+ ((unsigned long *) ind_bh->b_data) + i,
wait);
if (rc > 0)
break;
@@ -131,7 +131,7 @@ static int sync_dindirect(struct inode *inode, unsigned long *diblock,
for (i = 0; i < addr_per_block; i++) {
rc = sync_indirect (inode,
- ((daddr_t *) dind_bh->b_data) + i,
+ ((unsigned long *) dind_bh->b_data) + i,
wait);
if (rc > 0)
break;
diff --git a/fs/xiafs/inode.c b/fs/xiafs/inode.c
index fb3491b..2c29778 100644
--- a/fs/xiafs/inode.c
+++ b/fs/xiafs/inode.c
@@ -65,6 +65,9 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data,
dev=s->s_dev;
lock_super(s);
+
+ set_blocksize(dev, BLOCK_SIZE);
+
if (!(bh = bread(dev, 0, BLOCK_SIZE))) {
s->s_dev=0;
unlock_super(s);
@@ -83,6 +86,16 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data,
return NULL;
}
s->s_blocksize = sp->s_zone_size;
+ s->s_blocksize_bits = 10 + sp->s_zone_shift;
+ if (s->s_blocksize != BLOCK_SIZE &&
+ (s->s_blocksize == 1024 || s->s_blocksize == 2048 ||
+ s->s_blocksize == 4096)) {
+ brelse(bh);
+ set_blocksize(dev, s->s_blocksize);
+ bh = bread (dev, 0, s->s_blocksize);
+ if(!bh) return NULL;
+ sp = (struct xiafs_super_block *) (((char *)bh->b_data) + BLOCK_SIZE) ;
+ };
s->u.xiafs_sb.s_nzones = sp->s_nzones;
s->u.xiafs_sb.s_ninodes = sp->s_ninodes;
s->u.xiafs_sb.s_ndatazones = sp->s_ndatazones;
diff --git a/fs/xiafs/namei.c b/fs/xiafs/namei.c
index 9a5dfd4..2f2839f 100644
--- a/fs/xiafs/namei.c
+++ b/fs/xiafs/namei.c
@@ -667,27 +667,27 @@ int xiafs_link(struct inode * oldinode, struct inode * dir,
return 0;
}
-static int subdir(struct inode * new, struct inode * old)
+static int subdir(struct inode * new_inode, struct inode * old_inode)
{
int ino;
int result;
- new->i_count++;
+ new_inode->i_count++;
result = 0;
for (;;) {
- if (new == old) {
+ if (new_inode == old_inode) {
result = 1;
break;
}
- if (new->i_dev != old->i_dev)
+ if (new_inode->i_dev != old_inode->i_dev)
break;
- ino = new->i_ino;
- if (xiafs_lookup(new,"..",2,&new))
+ ino = new_inode->i_ino;
+ if (xiafs_lookup(new_inode,"..",2,&new_inode))
break;
- if (new->i_ino == ino)
+ if (new_inode->i_ino == ino)
break;
}
- iput(new);
+ iput(new_inode);
return result;
}
diff --git a/ibcs/emulate.c b/ibcs/emulate.c
index f8c4b1e..5c3f582 100644
--- a/ibcs/emulate.c
+++ b/ibcs/emulate.c
@@ -20,7 +20,7 @@
#include <asm/segment.h>
#include <asm/system.h>
-void iABI_emulate(struct pt_regs * regs)
+extern "C" void iABI_emulate(struct pt_regs * regs)
{
printk("lcall 7,xxx: eax = %08x\n",regs->eax);
}
diff --git a/include/asm/bitops.h b/include/asm/bitops.h
index eb075d9..f8191b9 100644
--- a/include/asm/bitops.h
+++ b/include/asm/bitops.h
@@ -6,8 +6,8 @@
#ifdef i386
/*
* These have to be done with inline assembly: that way the bit-setting
- * is guaranteed to be atomic. Both set_bit and clear_bit return 0
- * if the bit-setting went ok, != 0 if the bit already was set/cleared.
+ * is guaranteed to be atomic. All bitoperations return 0 if the bit
+ * was cleared before the operation and != 0 if it was not.
*
* bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
*/
@@ -20,22 +20,22 @@ struct __dummy { unsigned long a[100]; };
extern inline int set_bit(int nr, void * addr)
{
- unsigned char ok;
+ int oldbit;
- __asm__ __volatile__("btsl %2,%1\n\tsetb %0"
- :"=q" (ok),"=m" (ADDR)
+ __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"=m" (ADDR)
:"r" (nr));
- return ok;
+ return oldbit;
}
extern inline int clear_bit(int nr, void * addr)
{
- unsigned char ok;
+ int oldbit;
- __asm__ __volatile__("btrl %2,%1\n\tsetnb %0"
- :"=q" (ok),"=m" (ADDR)
+ __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit),"=m" (ADDR)
:"r" (nr));
- return ok;
+ return oldbit;
}
/*
@@ -44,12 +44,12 @@ extern inline int clear_bit(int nr, void * addr)
*/
extern inline int test_bit(int nr, void * addr)
{
- unsigned char ok;
+ int oldbit;
- __asm__ __volatile__("btl %2,%1\n\tsetb %0"
- :"=q" (ok)
+ __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
+ :"=r" (oldbit)
:"m" (ADDR),"r" (nr));
- return ok;
+ return oldbit;
}
#else
diff --git a/include/asm/dma.h b/include/asm/dma.h
index 741c2da..a2d4a9e 100644
--- a/include/asm/dma.h
+++ b/include/asm/dma.h
@@ -141,10 +141,10 @@ static __inline__ void disable_dma(unsigned int dmanr)
/* Clear the 'DMA Pointer Flip Flop'.
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a know state.
+ * Use this once to initialize the FF to a known state.
* After that, keep track of it. :-)
* --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disbled! ---
+ * --- only be used while interrupts are disabled! ---
*/
static __inline__ void clear_dma_ff(unsigned int dmanr)
{
diff --git a/include/asm/io.h b/include/asm/io.h
index 5059de6..b405c2d 100644
--- a/include/asm/io.h
+++ b/include/asm/io.h
@@ -24,34 +24,97 @@
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
-extern inline void outb(char value, unsigned short port)
+/* This is the more general version of outb.. */
+extern inline void __outb(unsigned char value, unsigned short port)
{
-__asm__ __volatile__ ("outb %%al,%%dx"
- ::"a" ((char) value),"d" ((unsigned short) port));
+__asm__ __volatile__ ("outb %b0,%w1"
+ : /* no outputs */
+ :"a" (value),"d" (port));
}
-extern inline unsigned int inb(unsigned short port)
+/* this is used for constant port numbers < 256.. */
+extern inline void __outbc(unsigned char value, unsigned short port)
+{
+__asm__ __volatile__ ("outb %b0,%1"
+ : /* no outputs */
+ :"a" (value),"i" (port));
+}
+
+/* general version of inb */
+extern inline unsigned int __inb(unsigned short port)
+{
+ unsigned int _v;
+__asm__ __volatile__ ("inb %w1,%b0"
+ :"=a" (_v):"d" (port),"0" (0));
+ return _v;
+}
+
+/* inb with constant port nr 0-255 */
+extern inline unsigned int __inbc(unsigned short port)
{
unsigned int _v;
-__asm__ __volatile__ ("inb %%dx,%%al"
- :"=a" (_v):"d" ((unsigned short) port),"0" (0));
+__asm__ __volatile__ ("inb %1,%b0"
+ :"=a" (_v):"i" (port),"0" (0));
return _v;
}
-extern inline void outb_p(char value, unsigned short port)
+extern inline void __outb_p(unsigned char value, unsigned short port)
+{
+__asm__ __volatile__ ("outb %b0,%w1"
+ : /* no outputs */
+ :"a" (value),"d" (port));
+ SLOW_DOWN_IO;
+}
+
+extern inline void __outbc_p(unsigned char value, unsigned short port)
{
-__asm__ __volatile__ ("outb %%al,%%dx"
- ::"a" ((char) value),"d" ((unsigned short) port));
+__asm__ __volatile__ ("outb %b0,%1"
+ : /* no outputs */
+ :"a" (value),"i" (port));
SLOW_DOWN_IO;
}
-extern inline unsigned int inb_p(unsigned short port)
+extern inline unsigned int __inb_p(unsigned short port)
{
unsigned int _v;
-__asm__ __volatile__ ("inb %%dx,%%al"
- :"=a" (_v):"d" ((unsigned short) port),"0" (0));
+__asm__ __volatile__ ("inb %w1,%b0"
+ :"=a" (_v):"d" (port),"0" (0));
SLOW_DOWN_IO;
return _v;
}
+extern inline unsigned int __inbc_p(unsigned short port)
+{
+ unsigned int _v;
+__asm__ __volatile__ ("inb %1,%b0"
+ :"=a" (_v):"i" (port),"0" (0));
+ SLOW_DOWN_IO;
+ return _v;
+}
+
+/*
+ * Note that due to the way __builtin_constant_p() works, you
+ * - can't use it inside a inlien function (it will never be true)
+ * - you don't have to worry about side effects within the __builtin..
+ */
+#define outb(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc((val),(port)) : \
+ __outb((val),(port)))
+
+#define inb(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc(port) : \
+ __inb(port))
+
+#define outb_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc_p((val),(port)) : \
+ __outb_p((val),(port)))
+
+#define inb_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc_p(port) : \
+ __inb_p(port))
+
#endif
diff --git a/include/asm/irq.h b/include/asm/irq.h
index f5cb9d0..64a7e92 100644
--- a/include/asm/irq.h
+++ b/include/asm/irq.h
@@ -117,9 +117,9 @@
#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
#define BUILD_IRQ(chip,nr,mask) \
-void IRQ_NAME(nr); \
-void FAST_IRQ_NAME(nr); \
-void BAD_IRQ_NAME(nr); \
+extern "C" void IRQ_NAME(nr); \
+extern "C" void FAST_IRQ_NAME(nr); \
+extern "C" void BAD_IRQ_NAME(nr); \
__asm__( \
"\n.align 4\n" \
"_IRQ" #nr "_interrupt:\n\t" \
@@ -136,19 +136,6 @@ __asm__( \
"cli\n\t" \
UNBLK_##chip(mask) \
"decl _intr_count\n\t" \
- "jne ret_from_sys_call\n\t" \
- "movl _bh_mask,%eax\n\t" \
- "andl _bh_active,%eax\n\t" \
- "je ret_from_sys_call\n\t" \
- "incl _intr_count\n\t" \
- "sti\n\t" \
- "bsfl %eax,%eax\n\t" \
- "btrl %eax,_bh_active\n\t" \
- "pushl %eax\n\t" \
- "call _do_bottom_half\n\t" \
- "addl $4,%esp\n\t" \
- "cli\n\t" \
- "decl _intr_count\n\t" \
"jmp ret_from_sys_call\n" \
"\n.align 4\n" \
"_fast_IRQ" #nr "_interrupt:\n\t" \
@@ -161,22 +148,6 @@ __asm__( \
"cli\n\t" \
UNBLK_##chip(mask) \
"decl _intr_count\n\t" \
- "jne 1f\n\t" \
- "movl _bh_mask,%eax\n\t" \
- "andl _bh_active,%eax\n\t" \
- "jne 2f\n" \
- "1:\t" \
- RESTORE_MOST \
- "\n.align 4\n" \
- "2:\tincl _intr_count\n\t" \
- "sti\n\t" \
- "bsfl %eax,%eax\n\t" \
- "btrl %eax,_bh_active\n\t" \
- "pushl %eax\n\t" \
- "call _do_bottom_half\n\t" \
- "addl $4,%esp\n\t" \
- "cli\n\t" \
- "decl _intr_count\n\t" \
RESTORE_MOST \
"\n\n.align 4\n" \
"_bad_IRQ" #nr "_interrupt:\n\t" \
diff --git a/include/asm/segment.h b/include/asm/segment.h
index cefbc35..5e471f9 100644
--- a/include/asm/segment.h
+++ b/include/asm/segment.h
@@ -6,6 +6,22 @@ static inline unsigned char get_fs_byte(const char * addr)
return _v;
}
+static inline unsigned char get_fs_byte(const unsigned char * addr)
+{
+ register unsigned char _v;
+
+ __asm__ ("movb %%fs:%1,%0":"=q" (_v):"m" (*addr));
+ return _v;
+}
+
+static inline unsigned short get_fs_word(const short *addr)
+{
+ unsigned short _v;
+
+ __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr));
+ return _v;
+}
+
static inline unsigned short get_fs_word(const unsigned short *addr)
{
unsigned short _v;
@@ -14,6 +30,30 @@ static inline unsigned short get_fs_word(const unsigned short *addr)
return _v;
}
+static inline unsigned long get_fs_long(const int *addr)
+{
+ unsigned long _v;
+
+ __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
+ return _v;
+}
+
+static inline unsigned long get_fs_long(const unsigned int *addr)
+{
+ unsigned long _v;
+
+ __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
+ return _v;
+}
+
+static inline unsigned long get_fs_long(const long *addr)
+{
+ unsigned long _v;
+
+ __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
+ return _v;
+}
+
static inline unsigned long get_fs_long(const unsigned long *addr)
{
unsigned long _v;
@@ -24,17 +64,42 @@ static inline unsigned long get_fs_long(const unsigned long *addr)
static inline void put_fs_byte(char val,char *addr)
{
-__asm__ ("movb %0,%%fs:%1"::"iq" (val),"m" (*addr));
+__asm__ ("movb %0,%%fs:%1": /* no outputs */ :"iq" (val),"m" (*addr));
+}
+
+static inline void put_fs_byte(char val,unsigned char *addr)
+{
+__asm__ ("movb %0,%%fs:%1": /* no outputs */ :"iq" (val),"m" (*addr));
}
static inline void put_fs_word(short val,short * addr)
{
-__asm__ ("movw %0,%%fs:%1"::"ir" (val),"m" (*addr));
+__asm__ ("movw %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
+}
+
+static inline void put_fs_word(short val,unsigned short * addr)
+{
+__asm__ ("movw %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
+}
+
+static inline void put_fs_long(unsigned long val,int * addr)
+{
+__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
+}
+
+static inline void put_fs_long(unsigned long val,unsigned int * addr)
+{
+__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
+}
+
+static inline void put_fs_long(unsigned long val,long * addr)
+{
+__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
}
static inline void put_fs_long(unsigned long val,unsigned long * addr)
{
-__asm__ ("movl %0,%%fs:%1"::"ir" (val),"m" (*addr));
+__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
}
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
@@ -52,7 +117,8 @@ __asm__("cld\n\t"
"2:\tshrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"pop %%es"
- ::"c" (n),"D" ((long) to),"S" ((long) from)
+ : /* no outputs */
+ :"c" (n),"D" ((long) to),"S" ((long) from)
:"cx","di","si");
}
@@ -67,7 +133,8 @@ __asm__("cld\n\t"
"fs ; movsw\n"
"2:\tshrl $2,%%ecx\n\t"
"rep ; fs ; movsl"
- ::"c" (n),"D" ((long) to),"S" ((long) from)
+ : /* no outputs */
+ :"c" (n),"D" ((long) to),"S" ((long) from)
:"cx","di","si");
}
@@ -80,20 +147,20 @@ __asm__("cld\n\t"
static inline unsigned long get_fs(void)
{
- unsigned short _v;
- __asm__("mov %%fs,%0":"=r" (_v):);
+ unsigned long _v;
+ __asm__("mov %%fs,%w0":"=r" (_v):"0" (0));
return _v;
}
static inline unsigned long get_ds(void)
{
- unsigned short _v;
- __asm__("mov %%ds,%0":"=r" (_v):);
+ unsigned long _v;
+ __asm__("mov %%ds,%w0":"=r" (_v):"0" (0));
return _v;
}
static inline void set_fs(unsigned long val)
{
- __asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val));
+ __asm__ __volatile__("mov %w0,%%fs": /* no output */ :"r" (val));
}
diff --git a/include/asm/system.h b/include/asm/system.h
index 53eacc9..7888381 100644
--- a/include/asm/system.h
+++ b/include/asm/system.h
@@ -16,11 +16,25 @@ __asm__ __volatile__ ("movl %%esp,%%eax\n\t" \
"mov %%ax,%%es\n\t" \
"mov %%ax,%%fs\n\t" \
"mov %%ax,%%gs" \
- ::"i" (USER_DS), "i" (USER_CS):"ax")
+ : /* no outputs */ :"i" (USER_DS), "i" (USER_CS):"ax")
+
+#define sti() __asm__ __volatile__ ("sti": : :"memory")
+#define cli() __asm__ __volatile__ ("cli": : :"memory")
+#define nop() __asm__ __volatile__ ("nop")
+
+/*
+ * Clear and set 'TS' bit respectively
+ */
+#define clts() __asm__ __volatile__ ("clts")
+#define stts() \
+__asm__ __volatile__ ( \
+ "movl %%cr0,%%eax\n\t" \
+ "orl $8,%%eax\n\t" \
+ "movl %%eax,%%cr0" \
+ : /* no outputs */ \
+ : /* no inputs */ \
+ :"ax")
-#define sti() __asm__ __volatile__ ("sti":::"memory")
-#define cli() __asm__ __volatile__ ("cli":::"memory")
-#define nop() __asm__ __volatile__ ("nop"::)
extern inline int tas(char * m)
{
@@ -31,12 +45,12 @@ extern inline int tas(char * m)
}
#define save_flags(x) \
-__asm__ __volatile__("pushfl ; popl %0":"=r" (x)::"memory")
+__asm__ __volatile__("pushfl ; popl %0":"=r" (x): /* no input */ :"memory")
#define restore_flags(x) \
-__asm__ __volatile__("pushl %0 ; popfl"::"r" (x):"memory")
+__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"r" (x):"memory")
-#define iret() __asm__ __volatile__ ("iret":::"memory")
+#define iret() __asm__ __volatile__ ("iret": : :"memory")
#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
@@ -80,11 +94,12 @@ __asm__ __volatile__ ("movw $" #limit ",%1\n\t" \
"movb $0x00,%5\n\t" \
"movb %%ah,%6\n\t" \
"rorl $16,%%eax" \
- ::"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
+ : /* no output */ \
+ :"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
"m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
)
-#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),231,"0x89")
+#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),235,"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),23,"0x82")
#endif
diff --git a/include/linux/delay.h b/include/linux/delay.h
new file mode 100644
index 0000000..92508f3
--- /dev/null
+++ b/include/linux/delay.h
@@ -0,0 +1,37 @@
+#ifndef _LINUX_DELAY_H
+#define _LINUX_DELAY_H
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines, using a pre-computed "loops_per_second" value.
+ */
+
+extern unsigned long loops_per_sec;
+
+extern __inline__ void __delay(int loops)
+{
+ __asm__("\n1:\tdecl %0\n\tjns 1b\n": :"a" (loops):"ax");
+}
+
+/*
+ * division by multiplication: you don't have to worry about
+ * loss of precision.
+ *
+ * Use only for very small delays ( < 1 msec). Should probably use a
+ * lookup table, really, as the multiplications take much too long with
+ * short delays. This is a "reasonable" implementation, though (and the
+ * first constant multiplications gets optimized away if the delay is
+ * a constant)
+ */
+extern __inline__ void udelay(unsigned long usecs)
+{
+ usecs *= 0x000010c6; /* 2**32 / 1000000 */
+ __asm__("mull %0"
+ :"=d" (usecs)
+ :"a" (usecs),"0" (loops_per_sec)
+ :"ax");
+ __delay(usecs);
+}
+
+#endif
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 4f30d57..93d458c 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -75,7 +75,7 @@
* Macro-instructions used to manage fragments
*/
#define EXT2_MIN_FRAG_SIZE 1024
-#define EXT2_MAX_FRAG_SIZE 1024
+#define EXT2_MAX_FRAG_SIZE 4096
#define EXT2_MIN_FRAG_LOG_SIZE 10
#ifdef __KERNEL__
# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
@@ -312,11 +312,9 @@ extern void ext2_truncate (struct inode *);
/* dir.c */
extern struct inode_operations ext2_dir_inode_operations;
-extern struct file_operations ext2_dir_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
-extern struct file_operations ext2_file_operations;
/* symlink.c */
extern struct inode_operations ext2_symlink_inode_operations;
diff --git a/include/linux/ext_fs.h b/include/linux/ext_fs.h
index b288492..c2380df 100644
--- a/include/linux/ext_fs.h
+++ b/include/linux/ext_fs.h
@@ -105,7 +105,4 @@ extern struct inode_operations ext_file_inode_operations;
extern struct inode_operations ext_dir_inode_operations;
extern struct inode_operations ext_symlink_inode_operations;
-extern struct file_operations ext_file_operations;
-extern struct file_operations ext_dir_operations;
-
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 6a3d930..e25ceab 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -241,6 +241,7 @@ struct file_lock {
struct super_block {
dev_t s_dev;
unsigned long s_blocksize;
+ unsigned char s_blocksize_bits;
unsigned char s_lock;
unsigned char s_rd_only;
unsigned char s_dirt;
@@ -310,6 +311,11 @@ struct file_system_type {
int requires_dev;
};
+#ifdef __KERNEL__
+
+extern "C" int sys_open(const char *, int, int);
+extern "C" int sys_close(unsigned int); /* yes, it's really unsigned */
+
extern int getname(const char * filename, char **result);
extern void putname(char * name);
@@ -325,6 +331,11 @@ extern struct inode_operations chrdev_inode_operations;
extern void init_fifo(struct inode * inode);
+extern struct file_operations connecting_pipe_fops;
+extern struct file_operations read_pipe_fops;
+extern struct file_operations write_pipe_fops;
+extern struct file_operations rdwr_pipe_fops;
+
extern struct file_system_type *get_fs_type(char *name);
extern int fs_may_mount(dev_t dev);
@@ -333,7 +344,7 @@ extern int fs_may_remount_ro(dev_t dev);
extern struct file *first_file;
extern int nr_files;
-extern struct super_block super_block[NR_SUPER];
+extern struct super_block super_blocks[NR_SUPER];
extern void grow_buffers(int size);
extern int shrink_buffers(unsigned int priority);
@@ -371,6 +382,7 @@ extern void ll_rw_block(int rw, int nr, struct buffer_head * bh[]);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern void brelse(struct buffer_head * buf);
+extern void set_blocksize(dev_t dev, int size);
extern struct buffer_head * bread(dev_t dev, int block, int size);
extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int prot);
extern struct buffer_head * breada(dev_t dev,int block,...);
@@ -386,7 +398,11 @@ extern int read_ahead[];
extern int char_write(struct inode *, struct file *, char *, int);
extern int block_write(struct inode *, struct file *, char *, int);
+extern int generic_mmap(struct inode *, struct file *, unsigned long, size_t, int, unsigned long);
+
extern int block_fsync(struct inode *, struct file *);
extern int file_fsync(struct inode *, struct file *);
+#endif /* __KERNEL__ */
+
#endif
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index bacc130..8ff890e 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -39,7 +39,7 @@ struct gendisk {
void (*init)(void); /* Initialization called before we do our thing */
struct hd_struct *part; /* partition table */
- int *sizes; /* block sizes */
+ int *sizes; /* size of device in blocks */
int nr_real; /* number of real devices */
void *real_devices; /* internal use */
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index bf98798..197c6ae 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -35,8 +35,8 @@ struct ipc_perm
#ifdef __KERNEL__
/* special shmsegs[id], msgque[id] or semary[id] values */
-#define IPC_UNUSED ((void *) -1)
-#define IPC_NOID ((void *) -2) /* being allocated/destroyed */
+#define IPC_UNUSED ((void *) -1)
+#define IPC_NOID ((void *) -2) /* being allocated/destroyed */
/*
* These are used to wrap system calls. See ipc/util.c, libipc.c
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
index 20daac3..66c0993 100644
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -136,12 +136,23 @@ extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inod
#define ISOFS_BLOCK_BITS 11
#define ISOFS_BLOCK_SIZE 2048
+#define ISOFS_BUFFER_SIZE(INODE) ((INODE)->i_sb->s_blocksize)
+#define ISOFS_BUFFER_BITS(INODE) ((INODE)->i_sb->s_blocksize_bits)
+
+#if 0
+#ifdef ISOFS_FIXED_BLOCKSIZE
/* We use these until the buffer cache supports 2048 */
#define ISOFS_BUFFER_BITS 10
#define ISOFS_BUFFER_SIZE 1024
#define ISOFS_BLOCK_NUMBER(X) (X<<1)
+#else
+#define ISOFS_BUFFER_BITS 11
+#define ISOFS_BUFFER_SIZE 2048
+#define ISOFS_BLOCK_NUMBER(X) (X)
+#endif
+#endif
#define ISOFS_SUPER_MAGIC 0x9660
#define ISOFS_FILE_UNKNOWN 0
@@ -179,9 +190,6 @@ extern struct inode_operations isofs_chrdev_inode_operations;
extern struct inode_operations isofs_blkdev_inode_operations;
extern struct inode_operations isofs_fifo_inode_operations;
-extern struct file_operations isofs_file_operations;
-extern struct file_operations isofs_dir_operations;
-
struct lookup_cache{
char lock;
unsigned long dir; /* If this matches... */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index aa507f8..c0a86d1 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -5,21 +5,47 @@
* 'kernel.h' contains some often-used function prototypes etc
*/
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
#define VERIFY_READ 0
#define VERIFY_WRITE 1
int verify_area(int type, void * addr, unsigned long count);
+extern void math_error(void);
volatile void panic(const char * str);
volatile void do_exit(long error_code);
unsigned long simple_strtoul(const char *,char **,unsigned int);
int sprintf(char * buf, const char * fmt, ...);
-int printk(const char * fmt, ...);
+
+extern "C" int printk(const char * fmt, ...);
+
+#ifdef CONFIG_DEBUG_MALLOC
+#define kmalloc(a,b) deb_kmalloc(__FILE__,__LINE__, a,b)
+#define kfree_s(a,b) deb_kfree_s(__FILE__,__LINE__,a,b)
+
+void *deb_kmalloc(const char *deb_file, unsigned short deb_line,unsigned int size, int priority);
+void deb_kfree_s (const char *deb_file, unsigned short deb_line,void * obj, int size);
+void deb_kcheck_s(const char *deb_file, unsigned short deb_line,void * obj, int size);
+
+#define kfree(a) deb_kfree_s(__FILE__,__LINE__, a,0)
+#define kcheck(a) deb_kcheck_s(__FILE__,__LINE__, a,0)
+#define kcheck_s(a,b) deb_kcheck_s(__FILE__,__LINE__, a,b)
+
+#else /* !debug */
void * kmalloc(unsigned int size, int priority);
void kfree_s(void * obj, int size);
+#define kcheck_s(a,b) 0
+
#define kfree(x) kfree_s((x), 0)
+#define kcheck(x) kcheck_s((x), 0)
+
+#endif
+
/*
* This is defined as a macro, but at some point this might become a
@@ -30,6 +56,8 @@ void kfree_s(void * obj, int size);
*/
#define suser() (current->euid == 0)
+#endif /* __KERNEL__ */
+
#define SI_LOAD_SHIFT 16
struct sysinfo {
long uptime; /* Seconds since boot */
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 01d6de9..51e2aee 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -135,7 +135,7 @@ extern inline void chg_vc_kbd_flag(struct kbd_struct * kbd, int flag)
#define NR_KEYS 112
#define NR_KEYMAPS 3
extern const int NR_TYPES;
-extern const unsigned char max_vals[];
+extern const int max_vals[];
extern unsigned short key_map[NR_KEYMAPS][NR_KEYS];
#define KT_LATIN 0 /* we depend on this being zero */
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 9bc56b1..ef59ad0 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -111,7 +111,4 @@ extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
extern struct inode_operations minix_symlink_inode_operations;
-extern struct file_operations minix_file_operations;
-extern struct file_operations minix_dir_operations;
-
#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 17923bd..a225b29 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -26,6 +26,7 @@ struct vm_area_struct {
struct task_struct * vm_task; /* VM area parameters */
unsigned long vm_start;
unsigned long vm_end;
+ unsigned short vm_page_prot;
struct vm_area_struct * vm_next; /* linked list */
struct vm_area_struct * vm_share; /* linked list */
struct inode * vm_inode;
@@ -42,9 +43,10 @@ struct vm_area_struct {
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
- void (*nopage)(struct vm_area_struct * area, unsigned long address);
+ void (*nopage)(int error_code,
+ struct vm_area_struct * area, unsigned long address);
void (*wppage)(struct vm_area_struct * area, unsigned long address);
- int (*share)(struct vm_area_struct * old, struct vm_area_struct * new, unsigned long address);
+ int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
};
extern unsigned long __bad_page(void);
@@ -57,6 +59,7 @@ extern unsigned long __zero_page(void);
extern volatile short free_page_ptr; /* used by malloc and tcp/ip. */
+extern int nr_swap_pages;
extern int nr_free_pages;
extern unsigned long free_page_list;
extern int nr_secondary_pages;
@@ -77,7 +80,8 @@ extern inline unsigned long get_free_page(int priority)
page = __get_free_page(priority);
if (page)
__asm__ __volatile__("rep ; stosl"
- ::"a" (0),"c" (1024),"D" (page)
+ : /* no outputs */ \
+ :"a" (0),"c" (1024),"D" (page)
:"di","cx");
return page;
}
@@ -91,8 +95,8 @@ extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
unsigned long address);
extern void free_page_tables(struct task_struct * tsk);
extern void clear_page_tables(struct task_struct * tsk);
-extern int copy_page_tables(struct task_struct * new);
-extern int clone_page_tables(struct task_struct * new);
+extern int copy_page_tables(struct task_struct * to);
+extern int clone_page_tables(struct task_struct * to);
extern int unmap_page_range(unsigned long from, unsigned long size);
extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask);
extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
@@ -117,13 +121,17 @@ extern void swap_in(unsigned long *table_ptr);
extern void si_swapinfo(struct sysinfo * val);
extern void rw_swap_page(int rw, unsigned long nr, char * buf);
+/* mmap.c */
+extern int do_mmap(struct file * file, unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long off);
+
#define read_swap_page(nr,buf) \
rw_swap_page(READ,(nr),(buf))
#define write_swap_page(nr,buf) \
rw_swap_page(WRITE,(nr),(buf))
#define invalidate() \
-__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3":::"ax")
+__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
extern unsigned long high_memory;
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 8531024..3e3197e 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -142,7 +142,7 @@ extern int msdos_subdirs(struct inode *dir);
/* fat.c */
-extern int fat_access(struct super_block *sb,int this,int new_value);
+extern int fat_access(struct super_block *sb,int nr,int new_value);
extern int msdos_smap(struct inode *inode,int sector);
extern int fat_free(struct inode *inode,int skip);
extern void cache_init(void);
@@ -178,12 +178,10 @@ extern int msdos_notify_change(int flags,struct inode *inode);
/* dir.c */
-extern struct file_operations msdos_dir_operations;
extern struct inode_operations msdos_dir_inode_operations;
/* file.c */
-extern struct file_operations msdos_file_operations;
extern struct inode_operations msdos_file_inode_operations;
extern struct inode_operations msdos_file_inode_operations_no_bmap;
diff --git a/include/linux/mtio.h b/include/linux/mtio.h
index a1604da..990f830 100644
--- a/include/linux/mtio.h
+++ b/include/linux/mtio.h
@@ -79,6 +79,7 @@ struct mtget {
#define MT_ISTDC3610 0x06 /* Tandberg 6310, QIC-24 */
#define MT_ISARCHIVE_VP60I 0x07 /* Archive VP60i, QIC-02 */
#define MT_ISARCHIVE_2150L 0x08 /* Archive Viper 2150L */
+#define MT_ISARCHIVE_2060L 0x09 /* Archive Viper 2060L */
#define MT_ISQIC02_ALL_FEATURES 0x0F /* Generic QIC-02 with all features */
#define MT_ISWT5099EEN24 0x11 /* Wangtek 5099-een24, 60MB, QIC-24 */
#define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */
@@ -99,6 +100,7 @@ struct mt_tape_info {
{MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \
{MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \
{MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \
+ {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \
{MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \
{MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
{MT_ISSCSI1, "Generic SCSI-1 tape"}, \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 04f5c8a..cf6473a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -12,6 +12,7 @@
#define HZ 100
#include <linux/tasks.h>
+#include <asm/system.h>
/*
* User space process size: 3GB. This is hardcoded into a few places,
@@ -75,51 +76,56 @@ extern unsigned long avenrun[]; /* Load averages */
#define NULL ((void *) 0)
#endif
-#define MAX_SHARED_LIBS 16
+#ifdef __KERNEL__
extern void sched_init(void);
extern void show_state(void);
-extern void schedule(void);
extern void trap_init(void);
extern void panic(const char * str);
-typedef int (*fn_ptr)();
+extern "C" void schedule(void);
+
+#endif /* __KERNEL__ */
+
+struct i387_hard_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct i387_soft_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long top;
+ struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */
+ unsigned char lookahead;
+ struct info *info;
+ unsigned long entry_eip;
+};
union i387_union {
- struct i387_hard_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
- } hard;
- struct i387_soft_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long top;
- struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */
- unsigned char lookahead;
- struct info *info;
- unsigned long entry_eip;
- } soft;
+ struct i387_hard_struct hard;
+ struct i387_soft_struct soft;
};
struct tss_struct {
- unsigned long back_link; /* 16 high bits zero */
+ unsigned short back_link,__blh;
unsigned long esp0;
- unsigned long ss0; /* 16 high bits zero */
+ unsigned short ss0,__ss0h;
unsigned long esp1;
- unsigned long ss1; /* 16 high bits zero */
+ unsigned short ss1,__ss1h;
unsigned long esp2;
- unsigned long ss2; /* 16 high bits zero */
+ unsigned short ss2,__ss2h;
unsigned long cr3;
unsigned long eip;
unsigned long eflags;
@@ -128,15 +134,16 @@ struct tss_struct {
unsigned long ebp;
unsigned long esi;
unsigned long edi;
- unsigned long es; /* 16 high bits zero */
- unsigned long cs; /* 16 high bits zero */
- unsigned long ss; /* 16 high bits zero */
- unsigned long ds; /* 16 high bits zero */
- unsigned long fs; /* 16 high bits zero */
- unsigned long gs; /* 16 high bits zero */
- unsigned long ldt; /* 16 high bits zero */
- unsigned long trace_bitmap; /* bits: trace 0, bitmap 16-31 */
- unsigned long io_bitmap[IO_BITMAP_SIZE];
+ unsigned short es, __esh;
+ unsigned short cs, __csh;
+ unsigned short ss, __ssh;
+ unsigned short ds, __dsh;
+ unsigned short fs, __fsh;
+ unsigned short gs, __gsh;
+ unsigned short ldt, __ldth;
+ unsigned short trace, bitmap;
+ unsigned long io_bitmap[IO_BITMAP_SIZE+1];
+ unsigned long tr;
union i387_union i387;
};
@@ -150,13 +157,15 @@ struct task_struct {
unsigned long flags; /* per process flags, defined below */
int errno;
/* various fields */
+ struct task_struct *next_task, *prev_task;
struct sigaction sigaction[32];
unsigned long saved_kernel_stack;
unsigned long kernel_stack_page;
int exit_code, exit_signal;
+ int elf_executable:1;
int dumpable:1;
int swappable:1;
- unsigned long start_code,end_code,end_data,brk,start_stack;
+ unsigned long start_code,end_code,end_data,brk,start_stack,start_mmap;
unsigned long arg_start, arg_end, env_start, env_end;
long pid,pgrp,session,leader;
int groups[NGROUPS];
@@ -195,13 +204,6 @@ struct task_struct {
struct vm_area_struct * mmap;
struct shm_desc *shm;
struct sem_undo *semun;
- struct {
- struct inode * library;
- unsigned long start;
- unsigned long length;
- unsigned long bss;
- } libraries[MAX_SHARED_LIBS];
- int numlibraries;
struct file * filp[NR_OPEN];
fd_set close_on_exec;
/* ldt for this task - not currently used */
@@ -231,9 +233,10 @@ struct task_struct {
*/
#define INIT_TASK \
/* state etc */ { 0,15,15,0,0,0,0, \
+/* schedlink */ &init_task,&init_task, \
/* signals */ {{ 0, },}, \
/* stack */ 0,0, \
-/* ec,brk... */ 0,0,0,0,0,0,0,0,0, \
+/* ec,brk... */ 0,0,0,0,0,0,0,0,0,0,0, \
/* argv.. */ 0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
/* suppl grps*/ {NOGROUP,}, \
@@ -250,21 +253,26 @@ struct task_struct {
/* vm86_info */ NULL, 0, \
/* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL, \
/* ipc */ NULL, NULL, \
-/* libraries */ { { NULL, 0, 0, 0}, }, 0, \
/* filp */ {NULL,}, \
/* cloe */ {{ 0, }}, \
{ \
/* ldt */ {0,0}, \
}, \
-/*tss*/ {0,sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
- KERNEL_DS,0,0,0,0,(long) &swapper_pg_dir,\
- 0,0,0,0,0,0,0,0, \
- 0,0,USER_DS,USER_DS,USER_DS,USER_DS,USER_DS,USER_DS, \
- _LDT(0),0x80000000,{0xffffffff}, \
- { { 0, }, } \
+/*tss*/ {0,0, \
+ sizeof(init_kernel_stack) + (long) &init_kernel_stack, KERNEL_DS, 0, \
+ 0,0,0,0,0,0, \
+ (long) &swapper_pg_dir, \
+ 0,0,0,0,0,0,0,0,0,0, \
+ USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0, \
+ _LDT(0),0, \
+ 0, 0x8000, \
+/* ioperm */ {0xffffffff, }, \
+ _TSS(0), \
+/* 387 state */ { { 0, }, } \
} \
}
+extern struct task_struct init_task;
extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
@@ -288,7 +296,7 @@ extern int in_group_p(gid_t grp);
extern int request_irq(unsigned int irq,void (*handler)(int));
extern void free_irq(unsigned int irq);
-extern int irqaction(unsigned int irq,struct sigaction * new);
+extern int irqaction(unsigned int irq,struct sigaction * sa);
/*
* Entry into gdt where to find first TSS. GDT layout:
@@ -307,8 +315,8 @@ extern int irqaction(unsigned int irq,struct sigaction * new);
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
-#define load_TR(n) __asm__("ltr %%ax"::"a" (_TSS(n)))
-#define load_ldt(n) __asm__("lldt %%ax"::"a" (_LDT(n)))
+#define load_TR(n) __asm__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
+#define load_ldt(n) __asm__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
#define store_TR(n) \
__asm__("str %%ax\n\t" \
"subl %2,%%eax\n\t" \
@@ -321,11 +329,9 @@ __asm__("str %%ax\n\t" \
* This also clears the TS-flag if the task we switched to has used
* tha math co-processor latest.
*/
-#define switch_to(n) {\
-struct {long a,b;} __tmp; \
+#define switch_to(tsk) \
__asm__("cmpl %%ecx,_current\n\t" \
"je 1f\n\t" \
- "movw %%dx,%1\n\t" \
"cli\n\t" \
"xchgl %%ecx,_current\n\t" \
"ljmp %0\n\t" \
@@ -334,10 +340,10 @@ __asm__("cmpl %%ecx,_current\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
- ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
- "d" (_TSS(n)),"c" ((long) task[n]) \
- :"cx"); \
-}
+ : /* no output */ \
+ :"m" (*(((char *)&tsk->tss.tr)-4)), \
+ "c" (tsk) \
+ :"cx")
#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)
@@ -346,10 +352,11 @@ __asm__("movw %%dx,%0\n\t" \
"rorl $16,%%edx\n\t" \
"movb %%dl,%1\n\t" \
"movb %%dh,%2" \
- ::"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7)), \
- "d" (base) \
+ : /* no output */ \
+ :"m" (*((addr)+2)), \
+ "m" (*((addr)+4)), \
+ "m" (*((addr)+7)), \
+ "d" (base) \
:"dx")
#define _set_limit(addr,limit) \
@@ -359,9 +366,10 @@ __asm__("movw %%dx,%0\n\t" \
"andb $0xf0,%%dh\n\t" \
"orb %%dh,%%dl\n\t" \
"movb %%dl,%1" \
- ::"m" (*(addr)), \
- "m" (*((addr)+6)), \
- "d" (limit) \
+ : /* no output */ \
+ :"m" (*(addr)), \
+ "m" (*((addr)+6)), \
+ "d" (limit) \
:"dx")
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
@@ -384,7 +392,8 @@ extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wa
printk("add_wait_queue (%08x): wait->next = %08x\n",pc,wait->next);
}
#endif
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
if (!*p) {
wait->next = wait;
*p = wait;
@@ -392,7 +401,7 @@ extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wa
wait->next = (*p)->next;
(*p)->next = wait;
}
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
@@ -403,7 +412,8 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
unsigned long ok = 0;
#endif
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
if ((*p == wait) &&
#ifdef DEBUG
(ok = 1) &&
@@ -422,7 +432,7 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
tmp->next = wait->next;
}
wait->next = NULL;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
#ifdef DEBUG
if (!ok) {
printk("removed wait_queue not on list.\n");
@@ -474,6 +484,8 @@ static inline unsigned long get_limit(unsigned long segment)
}
#define REMOVE_LINKS(p) \
+ (p)->next_task->prev_task = (p)->prev_task; \
+ (p)->prev_task->next_task = (p)->next_task; \
if ((p)->p_osptr) \
(p)->p_osptr->p_ysptr = (p)->p_ysptr; \
if ((p)->p_ysptr) \
@@ -482,6 +494,10 @@ static inline unsigned long get_limit(unsigned long segment)
(p)->p_pptr->p_cptr = (p)->p_osptr
#define SET_LINKS(p) \
+ (p)->next_task = &init_task; \
+ (p)->prev_task = init_task.prev_task; \
+ init_task.prev_task->next_task = (p); \
+ init_task.prev_task = (p); \
(p)->p_ysptr = NULL; \
if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \
(p)->p_osptr->p_ysptr = p; \
diff --git a/include/linux/sem.h b/include/linux/sem.h
index a996c3f..02d535f 100644
--- a/include/linux/sem.h
+++ b/include/linux/sem.h
@@ -86,7 +86,6 @@ struct seminfo {
struct sem_undo {
struct sem_undo *proc_next;
struct sem_undo *id_next;
- struct sem_undo *id_prev;
int semid;
short semadj; /* semval adjusted by exit */
ushort sem_num; /* semaphore index in array semid */
diff --git a/include/linux/string.h b/include/linux/string.h
index 8d5523b..62aa810 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -26,7 +26,8 @@ __asm__("cld\n"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
- ::"S" (src),"D" (dest):"si","di","ax","memory");
+ : /* no output */
+ :"S" (src),"D" (dest):"si","di","ax","memory");
return dest;
}
@@ -42,7 +43,8 @@ __asm__("cld\n"
"rep\n\t"
"stosb\n"
"2:"
- ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
+ : /* no output */
+ :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
return dest;
}
@@ -56,7 +58,8 @@ __asm__("cld\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
- ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
+ : /* no output */
+ :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
return dest;
}
@@ -75,7 +78,8 @@ __asm__("cld\n\t"
"jne 1b\n"
"2:\txorl %2,%2\n\t"
"stosb"
- ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
+ : /* no output */
+ :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
:"si","di","ax","cx","memory");
return dest;
}
@@ -341,7 +345,8 @@ __asm__("cld\n\t"
"je 2f\n\t"
"movsw\n"
"2:\n"
- ::"d" (n),"D" ((long) to),"S" ((long) from)
+ : /* no output */
+ :"d" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si","memory");
return (to);
}
@@ -352,14 +357,16 @@ if (dest<src)
__asm__("cld\n\t"
"rep\n\t"
"movsb"
- ::"c" (n),"S" (src),"D" (dest)
+ : /* no output */
+ :"c" (n),"S" (src),"D" (dest)
:"cx","si","di");
else
__asm__("std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
- ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
+ : /* no output */
+ :"c" (n),"S" (src+n-1),"D" (dest+n-1)
:"cx","si","di","memory");
return dest;
}
@@ -401,7 +408,8 @@ extern inline void * memset(void * s,char c,size_t count)
__asm__("cld\n\t"
"rep\n\t"
"stosb"
- ::"a" (c),"D" (s),"c" (count)
+ : /* no output */
+ :"a" (c),"D" (s),"c" (count)
:"cx","di","memory");
return s;
}
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 09fa4df..94635ee 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -4,6 +4,8 @@
#define sys_clone sys_fork
+extern "C" {
+
extern int sys_setup();
extern int sys_exit();
extern int sys_fork();
@@ -141,6 +143,8 @@ extern int sys_old_syscall();
#define sys_signal sys_old_syscall /* sys_sigaction */
#endif
+typedef int (*fn_ptr)();
+
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
@@ -165,5 +169,7 @@ sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
sys_clone, sys_setdomainname, sys_newuname};
+}
+
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/timer.h b/include/linux/timer.h
index fd3aea9..dcca17f 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -24,6 +24,8 @@
* NET_TIMER tcp/ip timeout timer
*
* COPRO_TIMER 387 timeout for buggy hardware..
+ *
+ * TAPE_QIC02_TIMER timer for QIC-02 tape driver (it's not hardcoded)
*/
#define BLANK_TIMER 0
@@ -37,6 +39,8 @@
#define SOUND_TIMER 20
#define COPRO_TIMER 21
+#define TAPE_QIC02_TIMER 22 /* hhb */
+
struct timer_struct {
unsigned long expires;
void (*fn)(void);
diff --git a/include/linux/tpqic02.h b/include/linux/tpqic02.h
new file mode 100644
index 0000000..bed2e58
--- /dev/null
+++ b/include/linux/tpqic02.h
@@ -0,0 +1,376 @@
+/* $Id: tpqic02.h,v 0.16 1993/04/19 23:15:39 root Exp root $
+ *
+ * Include file for QIC-02 driver for Linux.
+ *
+ * Copyright (c) 1992 by H. H. Bergman. All rights reserved.
+ *
+ * ******* USER CONFIG SECTION BELOW *******
+ */
+
+#ifndef _LINUX_TPQIC02_H
+#define _LINUX_TPQIC02_H
+
+#include <linux/config.h>
+
+#if CONFIG_TAPE_QIC02
+
+/* need to have TAPE_QIC02_DRIVE and TAPE_QIC02_IFC expand to something */
+#include <linux/mtio.h>
+
+
+/* make TAPE_QIC02_IFC expand to something */
+#define WANGTEK 1 /* don't know about Wangtek QIC-36 */
+#define EVEREX WANGTEK /* I heard *some* of these are identical */
+#define EVEREX_811V EVEREX /* With TEAC MT 2ST 45D */
+#define EVEREX_831V EVEREX
+#define ARCHIVE 3
+#define ARCHIVE_SC400 ARCHIVE /* rumoured to be from the pre-SMD-age */
+#define ARCHIVE_SC402 ARCHIVE /* don't know much about SC400 */
+#define ARCHIVE_SC499 ARCHIVE /* SC402 and SC499R should be identical */
+
+
+/*********** START OF USER CONFIGURABLE SECTION ************/
+
+/* Tape configuration:
+ *
+ * Tape drive configuration: (MT_IS* constants are defined in sys/mtio.h)
+ *
+ * TAPE_QIC02_DRIVE = MT_ISWT5150
+ * - Wangtek 5150, format: up to QIC-150.
+ * TAPE_QIC02_DRIVE = MT_ISQIC02_ALL_FEATURES
+ * - Enables some optional QIC commands that some drives may lack.
+ * It is provided so you can check which are supported by your drive.
+ * Refer to tpqic02.h for others.
+ *
+ * Supported interface cards: TAPE_QIC02_IFC =
+ * WANGTEK,
+ * ARCHIVE_SC402, ARCHIVE_SC499. (both same programming interface)
+ *
+ * Make sure you have the I/O ports/DMA channels
+ * and IRQ stuff configured properly!
+ * NOTE: There may be other device drivers using the same major
+ * number. This must be avoided. Check for timer.h conflicts too.
+ */
+
+#define TAPE_QIC02_DRIVE MT_ISQIC02_ALL_FEATURES /* drive type */
+/* #define TAPE_QIC02_DRIVE MT_ISWT5150 */
+#define TAPE_QIC02_IFC WANGTEK /* interface card type */
+/* #define TAPE_QIC02_IFC ARCHIVE */
+#define TAPE_QIC02_MAJOR 12 /* major device number. /dev/loop seems to use 12 as well :-( */
+#define TAPE_QIC02_PORT 0x300 /* controller port adress */
+#define TAPE_QIC02_IRQ 5 /* Muhammad, please don't use 2 here. -- Hennus */
+#define TAPE_QIC02_DMA 1 /* either 1 or 3, because 2 is used by the floppy */
+
+
+/************ END OF USER CONFIGURABLE SECTION *************/
+
+
+/* NOTE: TP_HAVE_DENS should distinguish between available densities
+ * NOTE: Drive select is not implemented -- I have only one tape streamer,
+ * so I'm unable and unmotivated to test and implement that. ;-) ;-)
+ */
+#if TAPE_QIC02_DRIVE == MT_ISWT5150
+#define TP_HAVE_DENS
+#define TP_HAVE_BSF /* nope */
+#define TP_HAVE_FSR /* nope */
+#define TP_HAVE_BSR /* nope */
+#define TP_HAVE_EOD /* most of the time */
+#define TP_HAVE_RAS1
+#define TP_HAVE_RAS2
+
+#elif TAPE_QIC02_DRIVE == MT_ISARCHIVESC499 /* Archive SC-499 QIC-36 controller */
+#define TP_HAVE_DENS /* can do set density (QIC-11 / QIC-24) */
+#define TP_HAVE_FSR /* can skip one block forwards */
+#define TP_HAVE_BSR /* can skip one block backwards */
+#define TP_HAVE_EOD /* can seek to end of recorded data */
+#define TP_HAVE_RAS1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+#elif (TAPE_QIC02_DRIVE == MT_ISARCHIVE_2060L) || (TAPE_QIC02_DRIVE == MT_ISARCHIVE_2150L)
+#define TP_HAVE_DENS /* can do set density (QIC-24 / QIC-120 / QIC-150) */
+#define TP_HAVE_FSR /* can skip one block forwards */
+#define TP_HAVE_BSR /* can skip one block backwards */
+#define TP_HAVE_EOD /* can seek to end of recorded data */
+#define TP_HAVE_TELL /* can read current block address */
+#define TP_HAVE_SEEK /* can seek to block */
+#define TP_HAVE_RAS1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+#elif TAPE_QIC02_DRIVE == MT_ISQIC02_ALL_FEATURES
+#define TP_HAVE_DENS /* can do set density */
+#define TP_HAVE_BSF /* can search filemark backwards */
+#define TP_HAVE_FSR /* can skip one block forwards */
+#define TP_HAVE_BSR /* can skip one block backwards */
+#define TP_HAVE_EOD /* can seek to end of recorded data */
+#define TP_HAVE_SEEK /* seek to block address */
+#define TP_HAVE_TELL /* tell current block address */
+#define TP_HAVE_RAS1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+
+#else
+#error No QIC-02 tape drive type defined!
+/* If your drive is not listed above, first try the 'ALL_FEATURES',
+ * to see what commands are supported, then create your own entry in
+ * the list above. You may want to mail it to me, so that I can include
+ * it in the next release.
+ */
+#endif
+
+
+/* NR_BLK_BUF is a `tuneable parameter'. If you're really low on
+ * kernel space, you could decrease it to 1, or if you got a very
+ * slow machine, you could increase it up to 128 blocks. Less kernel
+ * buffer blocks result in more context-switching.
+ */
+#define NR_BLK_BUF 20 /* max 128 blocks */
+#define TAPE_BLKSIZE 512 /* streamer tape block size (fixed) */
+#define TPQBUF_SIZE (TAPE_BLKSIZE*NR_BLK_BUF) /* buffer size */
+
+
+#define BLOCKS_BEYOND_EW 2 /* nr of blocks after Early Warning hole */
+
+#if TAPE_QIC02_IFC == WANGTEK
+ /* Wangtek interface card port locations */
+# define QIC_STAT_PORT TAPE_QIC02_PORT
+# define QIC_CTL_PORT TAPE_QIC02_PORT
+# define QIC_CMD_PORT (TAPE_QIC02_PORT+1)
+# define QIC_DATA_PORT (TAPE_QIC02_PORT+1)
+
+/* status register bits (Active LOW!) */
+# define QIC_STAT_READY 0x01
+# define QIC_STAT_EXCEPTION 0x02
+# define QIC_STAT_MASK (QIC_STAT_READY|QIC_STAT_EXCEPTION)
+
+# define QIC_STAT_RESETMASK 0x07
+# define QIC_STAT_RESETVAL (QIC_STAT_RESETMASK & ~QIC_STAT_EXCEPTION)
+
+/* controller register (QIC_CTL_PORT) bits */
+# define WT_CTL_ONLINE 0x01
+# define QIC_CTL_RESET 0x02
+# define QIC_CTL_REQUEST 0x04
+# define WT_CTL_CMDOFF 0xC0
+# if TAPE_QIC02_DMA == 3 /* dip-switches alone don't seem to cut it */
+# define WT_CTL_DMA 0x10 /* enable dma chan3 */
+# elif TAPE_QIC02_DMA == 1
+# define WT_CTL_DMA 0x08 /* enable dma chan1 or chan2 */
+# else
+# error Unsupported or incorrect DMA configuration.
+# endif
+
+#elif TAPE_QIC02_IFC == ARCHIVE
+ /* Archive interface card port locations */
+# define QIC_STAT_PORT (TAPE_QIC02_PORT+1)
+# define QIC_CTL_PORT (TAPE_QIC02_PORT+1)
+# define QIC_CMD_PORT (TAPE_QIC02_PORT)
+# define QIC_DATA_PORT (TAPE_QIC02_PORT)
+# define AR_START_DMA_PORT (TAPE_QIC02_PORT+2)
+# define AR_RESET_DMA_PORT (TAPE_QIC02_PORT+3)
+
+ /* STAT port bits */
+# define AR_STAT_IRQF 0x80 /* active high, interrupt request flag */
+# define QIC_STAT_READY 0x40 /* active low */
+# define QIC_STAT_EXCEPTION 0x20 /* active low */
+# define QIC_STAT_MASK (QIC_STAT_READY|QIC_STAT_EXCEPTION)
+# define AR_STAT_DMADONE 0x10 /* active high, DMA done */
+# define AR_STAT_DIRC 0x08 /* active high, direction */
+
+# define QIC_STAT_RESETMASK 0x70 /* check RDY,EXC,DMADONE */
+# define QIC_STAT_RESETVAL ((QIC_STAT_RESETMASK & ~AR_STAT_IRQF & ~QIC_STAT_EXCEPTION) | AR_STAT_DMADONE)
+
+ /* CTL port bits */
+# define QIC_CTL_RESET 0x80 /* drive reset */
+# define QIC_CTL_REQUEST 0x40 /* notify of new command */
+# define AR_CTL_IEN 0x20 /* interrupt enable */
+# define AR_CTL_DNIEN 0x10 /* done-interrupt enable */
+ /* Note: All of these bits are cleared automatically when writing to
+ * AR_RESET_DMA_PORT. So AR_CTL_IEN and AR_CTL_DNIEN must be
+ * reprogrammed before the write to AR_START_DMA_PORT.
+ */
+
+# if TAPE_QIC02_DMA > 3 /* channel 2 is used by the floppy driver */
+# error DMA channels other than 1 and 3 are not supported.
+# endif
+
+#else
+# error No valid interface card specified!
+#endif /* TAPE_QIC02_IFC */
+
+/* Standard QIC-02 commands -- rev F. All QIC-02 drives must support these */
+#define QCMD_SEL_1 0x01 /* select drive 1 */
+#define QCMD_SEL_2 0x02 /* select drive 2 */
+#define QCMD_SEL_3 0x04 /* select drive 3 */
+#define QCMD_SEL_4 0x08 /* select drive 4 */
+#define QCMD_REWIND 0x21 /* rewind tape*/
+#define QCMD_ERASE 0x22 /* erase tape */
+#define QCMD_RETEN 0x24 /* retension tape */
+#define QCMD_WRT_DATA 0x40 /* write data */
+#define QCMD_WRT_FM 0x60 /* write file mark */
+#define QCMD_RD_DATA 0x80 /* read data */
+#define QCMD_RD_FM 0xA0 /* read file mark (forward direction) */
+#define QCMD_RD_STAT 0xC0 /* read status */
+
+/* Other (optional/vendor unique) commands */
+ /* Density commands are only valid when TP_BOM is set! */
+#define QCMD_DENS_11 0x26 /* QIC-11 */
+#define QCMD_DENS_24 0x27 /* QIC-24: 9 track 60MB */
+#define QCMD_DENS_120 0x28 /* QIC-120: 15 track 120MB */
+#define QCMD_DENS_150 0x29 /* QIC-150: 18 track 150MB */
+#define QCMD_DENS_300 0x2A /* QIC-300/QIC-2100 */
+#define QCMD_DENS_600 0x2B /* QIC-600/QIC-2200 */
+/* don't know about QIC-1000 and QIC-1350 */
+
+#define QCMD_WRTNU_DATA 0x40 /* write data, no underruns, insert filler. */
+#define QCMD_SPACE_FWD 0x81 /* skip next block */
+#define QCMD_SPACE_BCK 0x89 /* move tape head one block back -- very useful! */
+#define QCMD_RD_FM_BCK 0xA8 /* read filemark (backwards) */
+#define QCMD_SEEK_EOD 0xA3 /* skip to EOD */
+#define QCMD_RD_STAT_X1 0xC1 /* read extended status 1 */
+#define QCMD_RD_STAT_X2 0xC4 /* read extended status 2 */
+#define QCMD_RD_STAT_X3 0xE0 /* read extended status 3 */
+#define QCMD_SELF_TST1 0xC2 /* run self test 1 (nondestructive) */
+#define QCMD_SELF_TST2 0xCA /* run self test 2 (destructive) */
+
+
+
+/* "Vendor Unique" codes */
+#if defined(MT_ISARCHIVESC499) || defined(MT_ISARCHIVE_2150L)
+# define QCMDV_TELL_BLK 0xAE /* read current block address */
+# define QCMDV_SEEK_BLK 0xAD /* seek to specific block */
+# define SEEK_BUF_SIZE 3 /* address is 3 bytes */
+#endif
+
+
+/* Optional, QFA (Quick File Access) commands.
+ * Not all drives support this, but those that do could use these commands
+ * to implement semi-non-sequential access. `mt fsf` would benefit from this.
+ * QFA divides the tape into 2 partitions, a data and a directory partition,
+ * causing some incompatibility problems wrt std QIC-02 data exchange.
+ * It would be useful to cache the directory info, but that might be tricky
+ * to do in kernel-space. [Size constraints.]
+ * Refer to QIC-02, appendix A for more information.
+ * I have no idea how other *nix variants implement QFA.
+ * I have no idea which drives support QFA and which don't.
+ */
+#define QFA_ENABLE 0x2D /* enter QFA mode, give @ BOT only */
+#define QFA_DATA 0x20 /* select data partition */
+#define QFA_DIR 0x23 /* select directory partition */
+#define QFA_RD_POS 0xCF /* read position+status bytes */
+#define QFA_SEEK_EOD 0xA1 /* seek EOD within current partition */
+#define QFA_SEEK_BLK 0xAF /* seek to a block within current partition */
+
+
+
+/* Minor device codes for tapes:
+ * |7|6|5|4|3|2|1|0|
+ * | \ | / \ | / |_____ 1=rewind on close, 0=no rewind on close
+ * | \|/ |_________ Density: 000=none, 001=QIC-11, 010=24, 011=120,
+ * | | 100=QIC-150, 101..111 reserved.
+ * | |_______________ Reserved for unit numbers.
+ * |___________________ Reserved for diagnostics during debugging.
+ */
+
+#define TP_REWCLOSE(d) ((MINOR(d)&0x01) == 1) /* rewind bit */
+ /* rewind is only done if data has been transfered */
+#define TP_DENS(dev) ((MINOR(dev) >> 1) & 0x07) /* tape density */
+#define TP_UNIT(dev) ((MINOR(dev) >> 4) & 0x07) /* unit number */
+#define TP_DIAGS(dev) (MINOR(dev) & 0x80) /* print excessive diagnostics */
+
+
+/* status codes returned by a WTS_RDSTAT call */
+struct tpstatus { /* sizeof(short)==2), LSB first */
+ unsigned short exs; /* Drive exception flags */
+ unsigned short dec; /* data error count: nr of blocks rewritten/soft read errors */
+ unsigned short urc; /* underrun count: nr of times streaming was interrupted */
+};
+#define TPSTATSIZE sizeof(struct tpstatus)
+
+
+/* defines for tpstatus.exs -- taken from 386BSD wt driver */
+#define TP_POR 0x100 /* Power on or reset occurred */
+#define TP_EOR 0x200 /* REServed for end of RECORDED media */
+#define TP_PAR 0x400 /* REServed for bus parity */
+#define TP_BOM 0x800 /* Beginning of media */
+#define TP_MBD 0x1000 /* Marginal block detected */
+#define TP_NDT 0x2000 /* No data detected */
+#define TP_ILL 0x4000 /* Illegal command */
+#define TP_ST1 0x8000 /* Status byte 1 flag */
+#define TP_FIL 0x01 /* File mark detected */
+#define TP_BNL 0x02 /* Bad block not located */
+#define TP_UDA 0x04 /* Unrecoverable data error */
+#define TP_EOM 0x08 /* End of media */
+#define TP_WRP 0x10 /* Write protected cartridge */
+#define TP_USL 0x20 /* Unselected drive */
+#define TP_CNI 0x40 /* Cartridge not in place */
+#define TP_ST0 0x80 /* Status byte 0 flag */
+
+#define REPORT_ERR0 (TP_CNI|TP_USL|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL)
+#define REPORT_ERR1 (TP_ILL|TP_NDT|TP_MBD|TP_PAR)
+
+
+#define EXC_UNKNOWN 0 /* (extra) Unknown exception code */
+#define EXC_NCART 1 /* No cartridge */
+#define EXC_NDRV 2 /* No drive */
+#define EXC_WP 3 /* Write protected */
+#define EXC_EOM 4 /* EOM */
+#define EXC_RWA 5 /* read/write abort */
+#define EXC_XBAD 6 /* read error, bad block transfered */
+#define EXC_XFILLER 7 /* read error, filler block transfered */
+#define EXC_NDT 8 /* read error, no data */
+#define EXC_NDTEOM 9 /* read error, no data & EOM */
+#define EXC_NDTBOM 10 /* read error, no data & BOM */
+#define EXC_FM 11 /* Read a filemark */
+#define EXC_ILL 12 /* Illegal command */
+#define EXC_POR 13 /* Power on/reset */
+#define EXC_MARGINAL 14 /* Marginal block detected */
+#define EXC_EOR 15 /* (extra, for SEEKEOD) End Of Recorded data reached */
+#define EXC_BOM 16 /* (extra) BOM reached */
+
+
+#define TAPE_NOTIFY_TIMEOUT 1000000
+
+/* internal function return codes */
+#define TE_OK 0 /* everything is fine */
+#define TE_EX 1 /* exception detected */
+#define TE_ERR 2 /* some error */
+#define TE_NS 3 /* can't read status */
+#define TE_TIM 4 /* timed out */
+#define TE_DEAD 5 /* tape drive doesn't respond */
+#define TE_END 6 /******** Archive hack *****/
+
+/* timeout timer values -- check these! */
+#define TIM_S (4*HZ) /* 4 seconds (normal cmds) */
+#define TIM_M (30*HZ) /* 30 seconds (write FM) */
+#define TIM_R (8*60*HZ) /* 8 minutes (retensioning) */
+#define TIM_F (2*3600*HZ) /* est. 1.2hr for full tape read/write+2 retens */
+
+#define TIMERON(t) timer_table[TAPE_QIC02_TIMER].expires = jiffies + (t); \
+ timer_active |= (1<<TAPE_QIC02_TIMER)
+#define TIMEROFF timer_active &= ~(1<<TAPE_QIC02_TIMER)
+#define TIMERCONT timer_active |= (1<<TAPE_QIC02_TIMER)
+
+
+typedef char flag;
+#define NO 0 /* NO must be 0 */
+#define YES 1 /* YES must be != 0 */
+
+
+#ifdef TDEBUG
+# define TPQDEB(s) s
+# define TPQPUTS(s) tpqputs(s)
+#else
+# define TPQDEB(s)
+# define TPQPUTS(s)
+#endif
+
+
+
+extern long tape_qic02_init(long); /* for kernel/mem.c */
+
+
+#endif /* CONFIG_TAPE_QIC02 */
+
+#endif /* _LINUX_TPQIC02_H */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5a0c5bf..f735fc9 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -346,7 +346,7 @@ extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty);
extern void wait_until_sent(struct tty_struct * tty);
extern void copy_to_cooked(struct tty_struct * tty);
-extern int tty_register_ldisc(int disc, struct tty_ldisc *new);
+extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
extern int tty_write_data(struct tty_struct *tty, char *bufp, int buflen,
diff --git a/include/linux/wait.h b/include/linux/wait.h
index b0642ec..92fb67d 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -11,12 +11,14 @@ struct wait_queue {
struct wait_queue * next;
};
+struct select_table_entry {
+ struct wait_queue wait;
+ struct wait_queue ** wait_address;
+};
+
typedef struct select_table_struct {
int nr;
- struct select_table_entry {
- struct wait_queue wait;
- struct wait_queue ** wait_address;
- } * entry;
+ struct select_table_entry * entry;
} select_table;
#define __MAX_SELECT_TABLE_ENTRIES (4096 / sizeof (struct select_table_entry))
diff --git a/include/linux/xd.h b/include/linux/xd.h
index 9c37a95..17bc3dc 100644
--- a/include/linux/xd.h
+++ b/include/linux/xd.h
@@ -99,10 +99,10 @@ typedef struct {
/* this structure defines a ROM BIOS signature */
typedef struct {
u_long offset;
- u_char *string;
+ char *string;
void (*init_controller)(u_char *address);
void (*init_drive)(u_char drive);
- u_char *name;
+ char *name;
} XD_SIGNATURE;
extern void resetup_one_dev (struct gendisk *dev,unsigned int drive);
@@ -117,7 +117,7 @@ static void do_xd_request (void);
static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
static void xd_release (struct inode *inode,struct file *file);
static int xd_reread_partitions (int dev);
-static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count);
+static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
static void xd_recalibrate (u_char drive);
static void xd_interrupt_handler (int unused);
diff --git a/include/linux/xia_fs.h b/include/linux/xia_fs.h
index ab0e2a4..47f3e3f 100644
--- a/include/linux/xia_fs.h
+++ b/include/linux/xia_fs.h
@@ -104,9 +104,6 @@ extern struct inode_operations xiafs_file_inode_operations;
extern struct inode_operations xiafs_dir_inode_operations;
extern struct inode_operations xiafs_symlink_inode_operations;
-extern struct file_operations xiafs_file_operations;
-extern struct file_operations xiafs_dir_operations;
-
#endif /* _XIA_FS_H */
diff --git a/include/linux/xia_fs_i.h b/include/linux/xia_fs_i.h
index b176771..3000a44 100644
--- a/include/linux/xia_fs_i.h
+++ b/include/linux/xia_fs_i.h
@@ -11,9 +11,9 @@
*/
struct xiafs_inode_info { /* for data zone pointers */
- daddr_t i_zone[8];
- daddr_t i_ind_zone;
- daddr_t i_dind_zone;
+ unsigned long i_zone[8];
+ unsigned long i_ind_zone;
+ unsigned long i_dind_zone;
};
#endif /* _XIA_FS_I_H */
diff --git a/init/main.c b/init/main.c
index a183127..ed00c52 100644
--- a/init/main.c
+++ b/init/main.c
@@ -20,6 +20,8 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
@@ -49,6 +51,7 @@ static inline _syscall1(int,dup,int,fd)
static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
static inline _syscall1(int,close,int,fd)
+static inline _syscall1(int,exit,int,exitcode)
static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
static inline pid_t wait(int * wait_stat)
@@ -68,8 +71,11 @@ extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct mktime * time);
-extern unsigned long simple_strtoul(const char *cp,char **endp,unsigned int
- base);
+extern unsigned long simple_strtoul(const char *,char **,unsigned int);
+
+extern void hd_setup(char *str, int *ints);
+extern void bmouse_setup(char *str, int *ints);
+extern void eth_setup(char *str, int *ints);
#ifdef CONFIG_SYSVIPC
extern void ipc_init(void);
@@ -83,7 +89,7 @@ extern unsigned long scsi_dev_init(unsigned long, unsigned long);
*/
#define PARAM empty_zero_page
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#define DRIVE_INFO (*(struct drive_info *) (PARAM+0x80))
+#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
#define RAMDISK_SIZE (*(unsigned short *) (PARAM+0x1F8))
@@ -137,8 +143,8 @@ static void time_init(void)
startup_time = kernel_mktime(&time);
}
-static unsigned long memory_start = 0; /* After mem_init, stores the */
- /* amount of free user memory */
+static unsigned long memory_start = 0; /* After mem_init, stores the */
+ /* amount of free user memory */
static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0;
@@ -151,7 +157,7 @@ static char * envp_rc[] = { "HOME=/", "TERM=console", NULL };
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", "TERM=console", NULL };
-struct drive_info { char dummy[32]; } drive_info;
+struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info;
unsigned char aux_device_present;
@@ -162,6 +168,80 @@ static char fpu_error = 0;
static char command_line[80] = { 0, };
+char *get_options(char *str, int *ints)
+{
+ char *cur = str;
+ int i=1;
+
+ while (cur && isdigit(*cur) && i <= 10) {
+ ints[i++] = simple_strtoul(cur,NULL,0);
+ if ((cur = strchr(cur,',')) != NULL)
+ cur++;
+ }
+ ints[0] = i-1;
+ return(cur);
+}
+
+struct {
+ char *str;
+ void (*setup_func)(char *, int *);
+} bootsetups[] = {
+#ifdef CONFIG_INET
+ { "ether=", eth_setup },
+#endif
+#ifdef CONFIG_BLK_DEV_HD
+ { "hd=", hd_setup },
+#endif
+#ifdef CONFIG_BUSMOUSE
+ { "bmouse=", bmouse_setup },
+#endif
+ { 0, 0 }
+};
+
+int checksetup(char *line)
+{
+ int i = 0;
+ int ints[11];
+
+ while (bootsetups[i].str) {
+ int n = strlen(bootsetups[i].str);
+ if (!strncmp(line,bootsetups[i].str,n)) {
+ bootsetups[i].setup_func(get_options(line+n,ints), ints);
+ return(0);
+ }
+ i++;
+ }
+ return(1);
+}
+
+unsigned long loops_per_sec = 1;
+
+static void calibrate_delay(void)
+{
+ int ticks;
+
+ printk("Calibrating delay loop.. ");
+ while (loops_per_sec <<= 1) {
+ ticks = jiffies;
+ __delay(loops_per_sec);
+ ticks = jiffies - ticks;
+ if (ticks >= HZ) {
+ __asm__("mull %1 ; divl %2"
+ :"=a" (loops_per_sec)
+ :"d" (HZ),
+ "r" (ticks),
+ "0" (loops_per_sec)
+ :"dx");
+ printk("ok - %d.%02d BogoMips (tm)\n",
+ loops_per_sec/500000,
+ (loops_per_sec/5000) % 100);
+ return;
+ }
+ }
+ printk("failed\n");
+}
+
+
/*
* This is a simple kernel command line parsing function: it parses
* the command line, and fills in the arguments/environment to init
@@ -176,6 +256,8 @@ static char command_line[80] = { 0, };
static void parse_options(char *line)
{
char *next;
+ char *devnames[] = { "hda", "hdb", "sda", "sdb", "sdc", "sdd", "sde", "fd", NULL };
+ int devnums[] = { 0x300, 0x340, 0x800, 0x810, 0x820, 0x830, 0x840, 0x200, 0};
int args, envs;
if (!*line)
@@ -190,25 +272,31 @@ static void parse_options(char *line)
* check for kernel options first..
*/
if (!strncmp(line,"root=",5)) {
- ROOT_DEV = simple_strtoul(line+5,NULL,16);
- continue;
- }
- if (!strcmp(line,"ro")) {
+ int n;
+ line += 5;
+ if (strncmp(line,"/dev/",5)) {
+ ROOT_DEV = simple_strtoul(line,NULL,16);
+ continue;
+ }
+ line += 5;
+ for (n = 0 ; devnames[n] ; n++) {
+ int len = strlen(devnames[n]);
+ if (!strncmp(line,devnames[n],len)) {
+ ROOT_DEV = devnums[n]+simple_strtoul(line+len,NULL,16);
+ break;
+ }
+ }
+ } else if (!strcmp(line,"ro"))
root_mountflags |= MS_RDONLY;
- continue;
- }
- if (!strcmp(line,"rw")) {
+ else if (!strcmp(line,"rw"))
root_mountflags &= ~MS_RDONLY;
- continue;
- }
- if (!strcmp(line,"no387")) {
+ else if (!strcmp(line,"no387")) {
hard_math = 0;
__asm__("movl %%cr0,%%eax\n\t"
- "andl $0xFFFFFFF9,%%eax\n\t"
- "orl $0x4,%%eax\n\t"
- "movl %%eax,%%cr0\n\t" ::: "ax");
- continue;
- }
+ "orl $0xE,%%eax\n\t"
+ "movl %%eax,%%cr0\n\t" : : : "ax");
+ } else
+ checksetup(line);
/*
* Then check if it's an environment variable or
* an option.
@@ -238,7 +326,7 @@ static void copro_timeout(void)
outb_p(0,0xf0);
}
-void start_kernel(void)
+extern "C" void start_kernel(void)
{
/*
* Interrupts are still disabled. Do necessary setups, then
@@ -294,6 +382,7 @@ void start_kernel(void)
ipc_init();
#endif
sti();
+ calibrate_delay();
/*
* check if exception 16 works correctly.. This is truly evil
* code: it disables the high 8 interrupts to make sure that
@@ -306,18 +395,18 @@ void start_kernel(void)
if (hard_math) {
unsigned short control_word;
+ printk("Checking 386/387 coupling... ");
timer_table[COPRO_TIMER].expires = jiffies+50;
timer_table[COPRO_TIMER].fn = copro_timeout;
timer_active |= 1<<COPRO_TIMER;
- printk("You have a bad 386/387 coupling.\r");
__asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
control_word &= 0xffc0;
- __asm__("fldcw %0 ; fwait"::"m" (*&control_word));
+ __asm__("fldcw %0 ; fwait": :"m" (*&control_word));
outb_p(inb_p(0x21) | (1 << 2), 0x21);
__asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
timer_active &= ~(1<<COPRO_TIMER);
if (!fpu_error)
- printk("Math coprocessor using %s error reporting.\n",
+ printk("Ok, fpu using %s error reporting.\n",
ignore_irq13?"exception 16":"irq13");
}
move_to_user_mode();
@@ -365,9 +454,9 @@ void init(void)
if (!(pid=fork())) {
close(0);
if (open("/etc/rc",O_RDONLY,0))
- _exit(1);
+ exit(1);
execve("/bin/sh",argv_rc,envp_rc);
- _exit(2);
+ exit(2);
}
if (pid>0)
while (pid != wait(&i))
@@ -383,7 +472,7 @@ void init(void)
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
- _exit(execve("/bin/sh",argv,envp));
+ exit(execve("/bin/sh",argv,envp));
}
while (1)
if (pid == wait(&i))
@@ -391,5 +480,5 @@ void init(void)
printf("\n\rchild %d died with code %04x\n\r",pid,i);
sync();
}
- _exit(0); /* NOTE! _exit, not exit() */
+ exit(0);
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 60b5dfb..2becdde 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -27,7 +27,7 @@ void msg_init (void)
int id;
for (id=0; id < MSGMNI; id++)
- msgque[id] = IPC_UNUSED;
+ msgque[id] = (struct msqid_ds *) IPC_UNUSED;
msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
msg_lock = NULL;
return;
@@ -35,7 +35,7 @@ void msg_init (void)
int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
{
- int id;
+ int id, err;
struct msqid_ds *msq;
struct ipc_perm *ipcp;
struct msg *msgh;
@@ -45,6 +45,9 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
return -EINVAL;
if (!msgp)
return -EFAULT;
+ err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
+ if (err)
+ return err;
if ((mtype = get_fs_long (&msgp->mtype)) < 1)
return -EINVAL;
id = msqid % MSGMNI;
@@ -78,7 +81,7 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
|| ipcp->seq != msqid / MSGMNI) {
- kfree (msgh);
+ kfree_s (msgh, sizeof(*msgh) + msgsz);
return -EIDRM;
}
@@ -109,17 +112,21 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
struct ipc_perm *ipcp;
struct msg *tmsg, *leastp = NULL;
struct msg *nmsg = NULL;
- int id;
+ int id, err;
if (msqid < 0 || msgsz < 0)
return -EINVAL;
+ if (!msgp || !msgp->mtext)
+ return -EFAULT;
+ err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
+ if (err)
+ return err;
+
id = msqid % MSGMNI;
msq = msgque [id];
if (msq == IPC_NOID || msq == IPC_UNUSED)
return -EINVAL;
ipcp = &msq->msg_perm;
- if (!msgp || !msgp->mtext)
- return -EFAULT;
/*
* find message of correct type.
@@ -153,7 +160,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
tmsg = tmsg->msg_next)
if (tmsg->msg_type < leastp->msg_type)
leastp = tmsg;
- if (leastp->msg_type >= - msgtyp)
+ if (leastp && leastp->msg_type <= - msgtyp)
nmsg = leastp;
}
@@ -161,7 +168,6 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
return -E2BIG;
msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
-
if (nmsg == msq->msg_first)
msq->msg_first = nmsg->msg_next;
else {
@@ -185,7 +191,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
wake_up (&msq->wwait);
put_fs_long (nmsg->msg_type, &msgp->mtype);
memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
- kfree (nmsg);
+ kfree_s (nmsg, sizeof(*nmsg) + msgsz);
return msgsz;
} else { /* did not find a message */
if (msgflg & IPC_NOWAIT)
@@ -223,7 +229,7 @@ static int newque (key_t key, int msgflg)
for (id=0; id < MSGMNI; id++)
if (msgque[id] == IPC_UNUSED) {
- msgque[id] = IPC_NOID;
+ msgque[id] = (struct msqid_ds *) IPC_NOID;
goto found;
}
return -ENOSPC;
@@ -231,7 +237,7 @@ static int newque (key_t key, int msgflg)
found:
msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
if (!msq) {
- msgque[id] = IPC_UNUSED;
+ msgque[id] = (struct msqid_ds *) IPC_UNUSED;
if (msg_lock)
wake_up (&msg_lock);
return -ENOMEM;
@@ -291,7 +297,7 @@ static void freeque (int id)
msgbytes -= msq->msg_cbytes;
if (id == max_msqid)
while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
- msgque[id] = IPC_UNUSED;
+ msgque[id] = (struct msqid_ds *) IPC_UNUSED;
used_queues--;
while (msq->rwait || msq->wwait) {
if (msq->rwait)
@@ -303,9 +309,9 @@ static void freeque (int id)
for (msgp = msq->msg_first; msgp; msgp = msgh ) {
msgh = msgp->msg_next;
msghdrs--;
- kfree ((void *) msgp);
+ kfree_s (msgp, sizeof(*msgp) + msgp->msg_ts);
}
- kfree (msq);
+ kfree_s (msq, sizeof (*msq));
}
int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
diff --git a/ipc/sem.c b/ipc/sem.c
index 62d323d..7795843 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -28,7 +28,7 @@ void sem_init (void)
sem_lock = NULL;
used_sems = used_semids = max_semid = sem_seq = 0;
for (i=0; i < SEMMNI; i++)
- semary[i] = IPC_UNUSED;
+ semary[i] = (struct semid_ds *) IPC_UNUSED;
return;
}
@@ -61,7 +61,7 @@ static int newary (key_t key, int nsems, int semflg)
return -ENOSPC;
for (id=0; id < SEMMNI; id++)
if (semary[id] == IPC_UNUSED) {
- semary[id] = IPC_NOID;
+ semary[id] = (struct semid_ds *) IPC_NOID;
goto found;
}
return -ENOSPC;
@@ -70,7 +70,7 @@ found:
used_sems += nsems;
sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);
if (!sma) {
- semary[id] = IPC_UNUSED;
+ semary[id] = (struct semid_ds *) IPC_UNUSED;
used_sems -= nsems;
if (sem_lock)
wake_up (&sem_lock);
@@ -123,6 +123,7 @@ int sys_semget (key_t key, int nsems, int semflg)
static void freeary (int id)
{
struct semid_ds *sma = semary[id];
+ struct sem_undo *un;
sma->sem_perm.seq++;
if ((int)((++sem_seq + 1) * SEMMNI) < 0)
@@ -130,8 +131,10 @@ static void freeary (int id)
used_sems -= sma->sem_nsems;
if (id == max_semid)
while (max_semid && (semary[--max_semid] == IPC_UNUSED));
- semary[id] = IPC_UNUSED;
+ semary[id] = (struct semid_ds *) IPC_UNUSED;
used_semids--;
+ for (un=sma->undo; un; un=un->id_next)
+ un->semadj = 0;
while (sma->eventz || sma->eventn) {
if (sma->eventz)
wake_up (&sma->eventz);
@@ -139,14 +142,14 @@ static void freeary (int id)
wake_up (&sma->eventn);
schedule();
}
- kfree (sma);
+ kfree_s (sma, sizeof (*sma) + sma->sem_nsems * sizeof (struct sem));
return;
}
int sys_semctl (int semid, int semnum, int cmd, void *arg)
{
int i, id, val = 0;
- struct semid_ds *sma, *buf, tbuf;
+ struct semid_ds *sma, *buf = NULL, tbuf;
struct ipc_perm *ipcp;
struct sem *curr;
struct sem_undo *un;
@@ -161,7 +164,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
case SEM_INFO:
{
struct seminfo seminfo, *tmp;
- if (!arg || ! (tmp = (struct seminfo *) get_fs_long (arg)))
+ if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg)))
return -EFAULT;
seminfo.semmni = SEMMNI;
seminfo.semmns = SEMMNS;
@@ -185,7 +188,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
}
case SEM_STAT:
- if (!arg || ! (buf = (struct semid_ds *) get_fs_long (arg)))
+ if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg)))
return -EFAULT;
i = verify_area (VERIFY_WRITE, buf, sizeof (*sma));
if (i)
@@ -228,7 +231,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
case GETNCNT: return curr->semncnt;
case GETZCNT: return curr->semzcnt;
case GETALL:
- if (!arg || ! (array = (ushort *) get_fs_long (arg)))
+ if (!arg || ! (array = (ushort *) get_fs_long((int *) arg)))
return -EFAULT;
i = verify_area (VERIFY_WRITE, array, nsems* sizeof(short));
if (i)
@@ -238,7 +241,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
case SETVAL:
if (!arg)
return -EFAULT;
- if ((val = (int) get_fs_long (arg)) > SEMVMX || val < 0)
+ if ((val = (int) get_fs_long ((int *) arg)) > SEMVMX || val < 0)
return -ERANGE;
break;
case IPC_RMID:
@@ -249,7 +252,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
}
return -EPERM;
case SETALL: /* arg is a pointer to an array of ushort */
- if (!arg || ! (array = (ushort *) get_fs_long (arg)) )
+ if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) )
return -EFAULT;
if ((i = verify_area (VERIFY_READ, array, sizeof tbuf)))
return i;
@@ -259,13 +262,13 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
return -ERANGE;
break;
case IPC_STAT:
- if (!arg || !(buf = (struct semid_ds *) get_fs_long (arg)))
+ if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg)))
return -EFAULT;
if ((i = verify_area (VERIFY_WRITE, arg, sizeof tbuf)))
return i;
break;
case IPC_SET:
- if (!arg || !(buf = (struct semid_ds *) get_fs_long (arg)))
+ if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg)))
return -EFAULT;
if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf)))
return i;
@@ -320,7 +323,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
return -EACCES;
for (i=0; i<nsems; i++)
sma->sem_base[i].semval = sem_io[i];
- for (un = sma->undo; un != NULL; un = un->id_next)
+ for (un = sma->undo; un; un = un->id_next)
un->semadj = 0;
if (sma->eventn)
wake_up (&sma->eventn);
@@ -390,9 +393,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
un->proc_next = current->semun;
current->semun = un;
un->id_next = sma->undo;
- if (sma->undo)
- sma->undo->id_prev = un;
- sma->undo = un->id_prev = un;
+ sma->undo = un;
}
}
@@ -453,34 +454,51 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
}
/*
- * add semadj values to semaphores if alowed. Silently ignore errors!
+ * add semadj values to semaphores, free undo structures.
+ * undo structures are not freed when semaphore arrays are destroyed
+ * so some of them may be out of date.
*/
void sem_exit (void)
{
- struct sem_undo *un, *tmp;
+ struct sem_undo *u, *un = NULL, **up, **unp;
struct semid_ds *sma;
struct sem *sem = NULL;
- for (un = current->semun; un; kfree(un), un = tmp) {
- un->id_prev->id_next = un->id_next;
- if (un->id_next)
- un->id_next->id_prev = un->id_prev;
- tmp = un->proc_next;
- if (!un->semadj)
+ for (up = &current->semun; (u = *up); *up = u->proc_next, kfree(u)) {
+ sma = semary[u->semid % SEMMNI];
+ if (sma == IPC_UNUSED || sma == IPC_NOID)
continue;
- sma = semary[un->semid % SEMMNI];
- if (sma == IPC_UNUSED || sma == IPC_NOID
- || sma->sem_perm.seq != un->semid / SEMMNI)
+ if (sma->sem_perm.seq != u->semid / SEMMNI)
continue;
- sem = &sma->sem_base[un->sem_num];
- if (sem->semval + un->semadj >= 0) {
- sem->semval += un->semadj;
- sem->sempid = current->pid;
- sma->sem_otime = CURRENT_TIME;
- if (un->semadj > 0 && sma->eventn)
- wake_up (&sma->eventn);
- if (!sem->semval && sma->eventz)
- wake_up (&sma->eventz);
+ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
+ if (u == un)
+ goto found;
+ }
+ printk ("sem_exit undo list error id=%d\n", u->semid);
+ break;
+found:
+ *unp = un->id_next;
+ if (!un->semadj)
+ continue;
+ while (1) {
+ if (sma->sem_perm.seq != un->semid / SEMMNI)
+ break;
+ sem = &sma->sem_base[un->sem_num];
+ if (sem->semval + un->semadj >= 0) {
+ sem->semval += un->semadj;
+ sem->sempid = current->pid;
+ sma->sem_otime = CURRENT_TIME;
+ if (un->semadj > 0 && sma->eventn)
+ wake_up (&sma->eventn);
+ if (!sem->semval && sma->eventz)
+ wake_up (&sma->eventz);
+ break;
+ }
+ if (current->signal & ~current->blocked)
+ break;
+ sem->semncnt++;
+ interruptible_sleep_on (&sma->eventn);
+ sem->semncnt--;
}
}
current->semun = NULL;
diff --git a/ipc/shm.c b/ipc/shm.c
index 00979d5..fe590a4 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -36,7 +36,7 @@ void shm_init (void)
int id;
for (id = 0; id < SHMMNI; id++)
- shm_segs[id] = IPC_UNUSED;
+ shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
shm_lock = NULL;
return;
@@ -73,7 +73,7 @@ static int newseg (key_t key, int shmflg, int size)
return -ENOSPC;
for (id=0; id < SHMMNI; id++)
if (shm_segs[id] == IPC_UNUSED) {
- shm_segs[id] = IPC_NOID;
+ shm_segs[id] = (struct shmid_ds *) IPC_NOID;
goto found;
}
return -ENOSPC;
@@ -81,7 +81,7 @@ static int newseg (key_t key, int shmflg, int size)
found:
shp = (struct shmid_ds *) kmalloc (sizeof (*shp), GFP_KERNEL);
if (!shp) {
- shm_segs[id] = IPC_UNUSED;
+ shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
if (shm_lock)
wake_up (&shm_lock);
return -ENOMEM;
@@ -89,10 +89,10 @@ found:
shp->shm_pages = (ulong *) kmalloc (numpages*sizeof(ulong),GFP_KERNEL);
if (!shp->shm_pages) {
- shm_segs[id] = IPC_UNUSED;
+ shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
if (shm_lock)
wake_up (&shm_lock);
- kfree (shp);
+ kfree_s (shp, sizeof (*shp));
return -ENOMEM;
}
@@ -165,7 +165,7 @@ static void killseg (int id)
numpages = shp->shm_npages;
if ((int)((++shm_seq + 1) * SHMMNI) < 0)
shm_seq = 0;
- shm_segs[id] = IPC_UNUSED;
+ shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
used_segs--;
if (id == max_shmid)
while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));
@@ -184,9 +184,9 @@ static void killseg (int id)
shm_swp--;
}
}
- kfree(shp->shm_pages);
+ kfree_s (shp->shm_pages, numpages * sizeof (ulong));
shm_tot -= numpages;
- kfree (shp);
+ kfree_s (shp, sizeof (*shp));
return;
}
@@ -261,7 +261,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp = shm_segs[id = shmid % SHMMNI];
if (shp == IPC_UNUSED || shp == IPC_NOID)
- return -EIDRM;
+ return -EINVAL;
ipcp = &shp->shm_perm;
if (ipcp->seq != shmid / SHMMNI)
return -EIDRM;
@@ -275,7 +275,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
ipcp->mode &= ~SHM_LOCKED;
break;
case SHM_LOCK:
-/* Alow superuser to lock segment in memory */
+/* Allow superuser to lock segment in memory */
/* Should the pages be faulted in here or leave it to user? */
/* need to determine interaction with current->swappable */
if (!suser())
@@ -434,7 +434,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if (!shmd)
return -ENOMEM;
if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) {
- kfree (shmd);
+ kfree_s (shmd, sizeof (*shmd));
return -EIDRM;
}
shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
@@ -453,7 +453,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if ((err = shm_map (shmd, shmflg & SHM_REMAP))) {
if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
killseg(id);
- kfree (shmd);
+ kfree_s (shmd, sizeof (*shmd));
return err;
}
@@ -490,7 +490,7 @@ static void detach (struct shm_desc **shmdp)
found:
unmap_page_range (shmd->start, shp->shm_segsz); /* sleeps */
- kfree(shmd);
+ kfree_s (shmd, sizeof (*shmd));
shp->shm_lpid = current->pid;
shp->shm_dtime = CURRENT_TIME;
if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
@@ -532,7 +532,7 @@ void shm_exit (void)
*/
int shm_fork (struct task_struct *p1, struct task_struct *p2)
{
- struct shm_desc *shmd, *new = NULL, *tmp;
+ struct shm_desc *shmd, *new_desc = NULL, *tmp;
struct shmid_ds *shp;
int id;
@@ -541,21 +541,21 @@ int shm_fork (struct task_struct *p1, struct task_struct *p2)
for (shmd = p1->shm; shmd; shmd = shmd->task_next) {
tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
- while (new) {
- tmp = new->task_next;
- kfree(new);
- new = tmp;
+ while (new_desc) {
+ tmp = new_desc->task_next;
+ kfree_s (new_desc, sizeof (*new_desc));
+ new_desc = tmp;
}
free_page_tables (p2);
return -ENOMEM;
}
*tmp = *shmd;
tmp->task = p2;
- tmp->task_next = new;
- new = tmp;
+ tmp->task_next = new_desc;
+ new_desc = tmp;
}
- p2->shm = new;
- for (shmd = new; shmd; shmd = shmd->task_next) {
+ p2->shm = new_desc;
+ for (shmd = new_desc; shmd; shmd = shmd->task_next) {
id = (shmd->shm_sgn >> SHM_ID_SHIFT) & 0xfff;
shp = shm_segs[id];
if (shp == IPC_UNUSED) {
diff --git a/ipc/util.c b/ipc/util.c
index bd4e881..700d137 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -12,7 +12,7 @@
#include <linux/shm.h>
void ipc_init (void);
-int sys_ipc (uint call, int first, int second, int third, void *ptr);
+extern "C" int sys_ipc (uint call, int first, int second, int third, void *ptr);
#ifdef CONFIG_SYSVIPC
@@ -63,7 +63,7 @@ int ipcperms (struct ipc_perm *ipcp, short flag)
return 0;
}
-int sys_ipc (uint call, int first, int second, int third, void *ptr)
+extern "C" int sys_ipc (uint call, int first, int second, int third, void *ptr)
{
if (call <= SEMCTL)
@@ -119,7 +119,7 @@ int sys_ipc (uint call, int first, int second, int third, void *ptr)
#else /* not CONFIG_SYSVIPC */
-int sys_ipc (uint call, int first, int second, int third, void *ptr)
+extern "C" int sys_ipc (uint call, int first, int second, int third, void *ptr)
{
return -ENOSYS;
}
diff --git a/kernel/FPU-emu/Makefile b/kernel/FPU-emu/Makefile
index 6a051f7..fb09ed9 100644
--- a/kernel/FPU-emu/Makefile
+++ b/kernel/FPU-emu/Makefile
@@ -10,7 +10,7 @@ CFLAGS := $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin
$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
.S.o:
- $(CC) $(CFLAGS) -c $<
+ $(CC) -D__ASSEMBLER__ -c $<
.s.o:
$(CC) -c $<
@@ -41,7 +41,8 @@ clean:
rm -f core *.o *.a *.s
dep:
- $(CPP) -M *.c *.S > .depend
+ $(CPP) -M *.c > .depend
+ $(CPP) -D__ASSEMBLER__ -M *.S >> .depend
proto:
cproto -e -DMAKING_PROTO *.c >fpu_proto.h
diff --git a/kernel/FPU-emu/errors.c b/kernel/FPU-emu/errors.c
index 17b958c..b933594 100644
--- a/kernel/FPU-emu/errors.c
+++ b/kernel/FPU-emu/errors.c
@@ -225,7 +225,7 @@ static struct {
0x218 in reg_round.S
*/
-void exception(int n)
+extern "C" void exception(int n)
{
int i, int_type;
@@ -306,7 +306,7 @@ void exception(int n)
/* Real operation attempted on two operands, one a NaN */
-void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
+extern "C" void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
{
FPU_REG *x;
int signalling;
@@ -368,7 +368,7 @@ void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
}
/* Invalid arith operation on Valid registers */
-void arith_invalid(FPU_REG *dest)
+extern "C" void arith_invalid(FPU_REG *dest)
{
if ( control_word & CW_Invalid )
@@ -385,7 +385,7 @@ void arith_invalid(FPU_REG *dest)
/* Divide a finite number by zero */
-void divide_by_zero(int sign, FPU_REG *dest)
+extern "C" void divide_by_zero(int sign, FPU_REG *dest)
{
if ( control_word & CW_ZeroDiv )
@@ -403,7 +403,7 @@ void divide_by_zero(int sign, FPU_REG *dest)
/* This may be called often, so keep it lean */
-void set_precision_flag_up(void)
+extern "C" void set_precision_flag_up(void)
{
if ( control_word & CW_Precision )
status_word |= (SW_Precision | SW_C1); /* The masked response */
@@ -414,7 +414,7 @@ void set_precision_flag_up(void)
/* This may be called often, so keep it lean */
-void set_precision_flag_down(void)
+extern "C" void set_precision_flag_down(void)
{
if ( control_word & CW_Precision )
{ /* The masked response */
@@ -426,7 +426,7 @@ void set_precision_flag_down(void)
}
-int denormal_operand(void)
+extern "C" int denormal_operand(void)
{
if ( control_word & CW_Denormal )
{ /* The masked response */
@@ -441,7 +441,7 @@ int denormal_operand(void)
}
-void arith_overflow(FPU_REG *dest)
+extern "C" void arith_overflow(FPU_REG *dest)
{
if ( control_word & CW_Overflow )
@@ -468,7 +468,7 @@ void arith_overflow(FPU_REG *dest)
}
-void arith_underflow(FPU_REG *dest)
+extern "C" void arith_underflow(FPU_REG *dest)
{
if ( control_word & CW_Underflow )
diff --git a/kernel/FPU-emu/fpu_emu.h b/kernel/FPU-emu/fpu_emu.h
index 43cc4bb..ed9cc06 100644
--- a/kernel/FPU-emu/fpu_emu.h
+++ b/kernel/FPU-emu/fpu_emu.h
@@ -99,31 +99,31 @@ extern FPU_REG FPU_loaded_data;
/*----- Prototypes for functions written in assembler -----*/
-/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
+/* extern "C" void reg_move(FPU_REG *a, FPU_REG *b); */
-extern void mul64(long long *a, long long *b, long long *result);
-extern void poly_div2(long long *x);
-extern void poly_div4(long long *x);
-extern void poly_div16(long long *x);
-extern void polynomial(unsigned accum[], unsigned x[],
+extern "C" void mul64(long long *a, long long *b, long long *result);
+extern "C" void poly_div2(long long *x);
+extern "C" void poly_div4(long long *x);
+extern "C" void poly_div16(long long *x);
+extern "C" void polynomial(unsigned accum[], unsigned x[],
unsigned short terms[][4], int n);
-extern void normalize(FPU_REG *x);
-extern void normalize_nuo(FPU_REG *x);
-extern void reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+extern "C" void normalize(FPU_REG *x);
+extern "C" void normalize_nuo(FPU_REG *x);
+extern "C" void reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
-extern void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+extern "C" void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
-extern void reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+extern "C" void reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
-extern void reg_u_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+extern "C" void reg_u_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
-extern void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+extern "C" void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
-extern void wm_sqrt(FPU_REG *n, unsigned int control_w);
-extern unsigned shrx(void *l, unsigned x);
-extern unsigned shrxs(void *v, unsigned x);
-extern unsigned long div_small(unsigned long long *x, unsigned long y);
-extern void round_reg(FPU_REG *arg, unsigned int extent,
+extern "C" void wm_sqrt(FPU_REG *n, unsigned int control_w);
+extern "C" unsigned shrx(void *l, unsigned x);
+extern "C" unsigned shrxs(void *v, unsigned x);
+extern "C" unsigned long div_small(unsigned long long *x, unsigned long y);
+extern "C" void round_reg(FPU_REG *arg, unsigned int extent,
unsigned int control_w);
#ifndef MAKING_PROTO
diff --git a/kernel/FPU-emu/fpu_entry.c b/kernel/FPU-emu/fpu_entry.c
index c44d5db..f67c440 100644
--- a/kernel/FPU-emu/fpu_entry.c
+++ b/kernel/FPU-emu/fpu_entry.c
@@ -140,7 +140,7 @@ char emulating=0;
#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
-void math_emulate(long arg)
+extern "C" void math_emulate(long arg)
{
unsigned char FPU_modrm;
unsigned short code;
@@ -474,7 +474,7 @@ void __math_abort(struct info * info, unsigned int signal)
FPU_EIP = FPU_ORIG_EIP;
send_sig(signal,current,1);
RE_ENTRANT_CHECK_OFF
- __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
+ __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
#ifdef PARANOID
printk("ERROR: wm-FPU-emu math_abort failed!\n");
#endif PARANOID
@@ -485,7 +485,7 @@ void __math_abort(struct info * info, unsigned int signal)
#include <linux/signal.h>
#include <linux/sched.h>
-void math_emulate(long arg)
+extern "C" void math_emulate(long arg)
{
printk("math-meulation not enabled and no coprocessor found.\n");
printk("killing %s.\n",current->comm);
diff --git a/kernel/FPU-emu/fpu_proto.h b/kernel/FPU-emu/fpu_proto.h
index ae8492d..3bc692c 100644
--- a/kernel/FPU-emu/fpu_proto.h
+++ b/kernel/FPU-emu/fpu_proto.h
@@ -1,19 +1,20 @@
/* errors.c */
extern void Un_impl(void);
extern void emu_printall(void);
-extern void exception(int n);
-extern void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
-extern void arith_invalid(FPU_REG *dest);
-extern void divide_by_zero(int sign, FPU_REG *dest);
-extern void set_precision_flag_up(void);
-extern void set_precision_flag_down(void);
-extern int denormal_operand(void);
-extern void arith_overflow(FPU_REG *dest);
-extern void arith_underflow(FPU_REG *dest);
extern void stack_overflow(void);
extern void stack_underflow(void);
extern void stack_underflow_i(int i);
extern void stack_underflow_pop(int i);
+extern "C" void exception(int n);
+extern "C" void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
+extern "C" void arith_invalid(FPU_REG *dest);
+extern "C" void divide_by_zero(int sign, FPU_REG *dest);
+extern "C" void set_precision_flag_up(void);
+extern "C" void set_precision_flag_down(void);
+extern "C" int denormal_operand(void);
+extern "C" void arith_overflow(FPU_REG *dest);
+extern "C" void arith_underflow(FPU_REG *dest);
+
/* fpu_arith.c */
extern void fadd__(void);
extern void fmul__(void);
@@ -33,6 +34,7 @@ extern void fsubrp(void);
extern void fsubp_(void);
extern void fdivrp(void);
extern void fdivp_(void);
+
/* fpu_aux.c */
extern void fclex(void);
extern void finit(void);
@@ -45,34 +47,46 @@ extern void ffree_(void);
extern void ffreep(void);
extern void fst_i_(void);
extern void fstp_i(void);
+
/* fpu_entry.c */
-extern void math_emulate(long arg);
+extern "C" void math_emulate(long arg);
extern void __math_abort(struct info *info, unsigned int signal);
+
/* fpu_etc.c */
extern void fp_etc(void);
+
/* fpu_trig.c */
extern void convert_l2reg(long *arg, FPU_REG *dest);
extern void trig_a(void);
extern void trig_b(void);
+
/* get_address.c */
extern void get_address(unsigned char FPU_modrm);
+
/* load_store.c */
extern void load_store_instr(char type);
+
/* poly_2xm1.c */
extern int poly_2xm1(FPU_REG *arg, FPU_REG *result);
+
/* poly_atan.c */
extern void poly_atan(FPU_REG *arg);
extern void poly_add_1(FPU_REG *src);
+
/* poly_l2.c */
extern void poly_l2(FPU_REG *arg, FPU_REG *result);
extern int poly_l2p1(FPU_REG *arg, FPU_REG *result);
+
/* poly_sin.c */
extern void poly_sine(FPU_REG *arg, FPU_REG *result);
+
/* poly_tan.c */
extern void poly_tan(FPU_REG *arg, FPU_REG *y_reg);
+
/* reg_add_sub.c */
extern void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w);
extern void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w);
+
/* reg_compare.c */
extern int compare(FPU_REG *b);
extern int compare_st_data(void);
@@ -82,8 +96,10 @@ extern void fcompp(void);
extern void fucom_(void);
extern void fucomp(void);
extern void fucompp(void);
+
/* reg_constant.c */
extern void fconst(void);
+
/* reg_ld_str.c */
extern void reg_load_extended(void);
extern void reg_load_double(void);
@@ -105,5 +121,6 @@ extern void frstor(void);
extern unsigned short tag_word(void);
extern char *fstenv(void);
extern void fsave(void);
+
/* reg_mul.c */
extern void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest, unsigned int control_w);
diff --git a/kernel/FPU-emu/load_store.c b/kernel/FPU-emu/load_store.c
index 2eeaa57..febe359 100644
--- a/kernel/FPU-emu/load_store.c
+++ b/kernel/FPU-emu/load_store.c
@@ -70,10 +70,12 @@ void load_store_instr(char type)
}
break;
case _null_:
- return Un_impl();
+ Un_impl();
+ return;
#ifdef PARANOID
default:
- return EXCEPTION(EX_INTERNAL);
+ EXCEPTION(EX_INTERNAL);
+ return;
#endif PARANOID
}
diff --git a/kernel/FPU-emu/reg_compare.c b/kernel/FPU-emu/reg_compare.c
index d3969b1..defbcd4 100644
--- a/kernel/FPU-emu/reg_compare.c
+++ b/kernel/FPU-emu/reg_compare.c
@@ -298,14 +298,14 @@ static int compare_u_st_st(int nr)
/*---------------------------------------------------------------------------*/
-void fcom_st()
+void fcom_st(void)
{
/* fcom st(i) */
compare_st_st(FPU_rm);
}
-void fcompst()
+void fcompst(void)
{
/* fcomp st(i) */
if ( compare_st_st(FPU_rm) )
@@ -313,11 +313,13 @@ void fcompst()
}
-void fcompp()
+void fcompp(void)
{
/* fcompp */
- if (FPU_rm != 1)
- return Un_impl();
+ if (FPU_rm != 1) {
+ Un_impl();
+ return;
+ }
if ( compare_st_st(1) )
{
pop(); FPU_st0_ptr = &st(0);
@@ -326,7 +328,7 @@ void fcompp()
}
-void fucom_()
+void fucom_(void)
{
/* fucom st(i) */
compare_u_st_st(FPU_rm);
@@ -334,7 +336,7 @@ void fucom_()
}
-void fucomp()
+void fucomp(void)
{
/* fucomp st(i) */
if ( compare_u_st_st(FPU_rm) )
@@ -342,7 +344,7 @@ void fucomp()
}
-void fucompp()
+void fucompp(void)
{
/* fucompp */
if (FPU_rm == 1)
diff --git a/kernel/FPU-emu/reg_ld_str.c b/kernel/FPU-emu/reg_ld_str.c
index 3b1d6d9..8cbef5a 100644
--- a/kernel/FPU-emu/reg_ld_str.c
+++ b/kernel/FPU-emu/reg_ld_str.c
@@ -1061,7 +1061,7 @@ int reg_store_bcd(void)
{
char *d = (char *)FPU_data_address;
FPU_REG t;
- long long ll;
+ unsigned long long ll;
unsigned char b;
int i;
unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
@@ -1082,7 +1082,7 @@ int reg_store_bcd(void)
reg_move(FPU_st0_ptr, &t);
round_to_int(&t);
- ll = *(long long *)(&t.sigl);
+ ll = *(unsigned long long *)(&t.sigl);
/* Check for overflow, by comparing with 999999999999999999 decimal. */
if ( (t.sigh > 0x0de0b6b3) ||
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index da471ba..9167318 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -1,7 +1,7 @@
#ifndef _BLK_H
#define _BLK_H
-#include <linux/fs.h>
+#include <linux/sched.h>
#include <linux/locks.h>
/*
@@ -59,18 +59,25 @@ struct sec_size {
/*
* These will have to be changed to be aware of different buffer
- * sizes etc..
+ * sizes etc.. It actually needs a major cleanup.
*/
-#define SECTOR_MASK ((1 << (BLOCK_SIZE_BITS - 9)) -1)
-#define SUBSECTOR(block) ((block) & SECTOR_MASK)
+#define SECTOR_MASK (blksize_size[MAJOR_NR] && \
+ blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] ? \
+ ((blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] >> 9) - 1) : \
+ ((BLOCK_SIZE >> 9) - 1))
+
+#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
extern struct sec_size * blk_sec[MAX_BLKDEV];
extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
extern struct request request[NR_REQUEST];
extern struct wait_queue * wait_for_request;
+extern void resetup_one_dev(struct gendisk *dev, int drive);
extern int * blk_size[MAX_BLKDEV];
+extern int * blksize_size[MAX_BLKDEV];
+
extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
extern int is_read_only(int dev);
extern void set_device_ro(int dev,int flag);
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
index 0e34b04..8890c36 100644
--- a/kernel/blk_drv/floppy.c
+++ b/kernel/blk_drv/floppy.c
@@ -120,9 +120,9 @@ static unsigned char running = 0;
/*
* The DMA channel used by the floppy controller cannot access data at
- * addresses >= 1MB
+ * addresses >= 16MB
*/
-#define LAST_DMA_ADDR (0x100000 - BLOCK_SIZE)
+#define LAST_DMA_ADDR (0x1000000 - BLOCK_SIZE)
/*
* globals used by 'result()'
@@ -427,7 +427,8 @@ int floppy_change(struct buffer_head * bh)
#define copy_buffer(from,to) \
__asm__("cld ; rep ; movsl" \
- ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
+ : \
+ :"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
:"cx","di","si")
static void setup_DMA(void)
@@ -942,8 +943,10 @@ static void floppy_ready(void)
* There should be a cleaner solution for that ...
*/
if (!reset && !recalibrate) {
- do_floppy = (current_track && current_track != NO_TRACK)
- ? shake_zero : shake_one;
+ if (current_track && current_track != NO_TRACK)
+ do_floppy = shake_zero;
+ else
+ do_floppy = shake_one;
output_byte(FD_RECALIBRATE);
output_byte(head<<2 | current_drive);
return;
@@ -1015,14 +1018,16 @@ repeat:
if (device > 3)
floppy = (device >> 2) + floppy_type;
else { /* Auto-detection */
- if ((floppy = current_type[device & 3]) == NULL) {
+ floppy = current_type[device & 3];
+ if (!floppy) {
probing = 1;
- if ((floppy = base_type[device & 3]) ==
- NULL) {
+ floppy = base_type[device & 3];
+ if (!floppy) {
request_done(0);
goto repeat;
}
- floppy += CURRENT_ERRORS & 1;
+ if (CURRENT_ERRORS & 1)
+ floppy++;
}
}
if (format_status != FORMAT_BUSY) {
@@ -1098,7 +1103,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long param)
{
int i,drive,cnt,okay;
- struct floppy_struct *this;
+ struct floppy_struct *this_floppy;
switch (cmd) {
RO_IOCTLS(inode->i_rdev,param);
@@ -1119,14 +1124,14 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
cmd = FDCLRPRM;
break;
case FDGETPRM:
- if (drive > 3) this = &floppy_type[drive >> 2];
- else if ((this = current_type[drive & 3]) == NULL)
+ if (drive > 3) this_floppy = &floppy_type[drive >> 2];
+ else if ((this_floppy = current_type[drive & 3]) == NULL)
return -ENODEV;
i = verify_area(VERIFY_WRITE,(void *) param,sizeof(struct floppy_struct));
if (i)
return i;
for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
- put_fs_byte(((char *) this)[cnt],
+ put_fs_byte(((char *) this_floppy)[cnt],
(char *) param+cnt);
return 0;
case FDFMTTRK:
@@ -1178,12 +1183,13 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
break;
case FDSETPRM:
case FDDEFPRM:
- for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
- ((char *) &user_params[drive])[cnt] =
- get_fs_byte((char *) param+cnt);
+ memcpy_fromfs(user_params+drive,
+ (void *) param,
+ sizeof(struct floppy_struct));
current_type[drive] = &user_params[drive];
floppy_sizes[drive] = user_params[drive].size >> 1;
- if (cmd == FDDEFPRM) keep_data[drive] = -1;
+ if (cmd == FDDEFPRM)
+ keep_data[drive] = -1;
else {
cli();
while (fdc_busy) sleep_on(&fdc_wait);
@@ -1192,7 +1198,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
outb_p((current_DOR & 0xfc) | drive |
(0x10 << drive),FD_DOR);
for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
- keep_data[drive] = (inb(FD_DIR) & 0x80) ? 1 : 0;
+ if (inb(FD_DIR) & 0x80)
+ keep_data[drive] = 1;
+ else
+ keep_data[drive] = 0;
outb_p(current_DOR,FD_DOR);
fdc_busy = 0;
wake_up(&fdc_wait);
diff --git a/kernel/blk_drv/genhd.c b/kernel/blk_drv/genhd.c
index c5b9293..840e858 100644
--- a/kernel/blk_drv/genhd.c
+++ b/kernel/blk_drv/genhd.c
@@ -55,7 +55,7 @@ static void extended_partition(struct gendisk *hd, int dev)
bh->b_dirt=0;
bh->b_uptodate=0;
if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
- p = 0x1BE + (void *)bh->b_data;
+ p = (struct partition *) (0x1BE + bh->b_data);
/*
* Process the first entry, which should be the real
* data partition.
@@ -110,7 +110,7 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
current_minor += 4; /* first "extra" minor */
if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
- p = 0x1BE + (void *)bh->b_data;
+ p = (struct partition *) (0x1BE + bh->b_data);
for (i=1 ; i<=4 ; minor++,i++,p++) {
if (!(hd->part[minor].nr_sects = p->nr_sects))
continue;
@@ -128,7 +128,7 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
* check for Disk Manager partition table
*/
if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
- p = 0x1BE + (void *)bh->b_data;
+ p = (struct partition *) (0x1BE + bh->b_data);
for (i = 4 ; i < 16 ; i++, current_minor++) {
p--;
if ((current_minor & mask) >= mask-2)
@@ -194,7 +194,7 @@ static void setup_dev(struct gendisk *dev)
}
/* This may be used only once, enforced by 'static int callable' */
-int sys_setup(void * BIOS)
+extern "C" int sys_setup(void * BIOS)
{
static int callable = 1;
struct gendisk *p;
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
index 8d62113..b1f547b 100644
--- a/kernel/blk_drv/hd.c
+++ b/kernel/blk_drv/hd.c
@@ -38,7 +38,6 @@
#define MAJOR_NR 3
#include "blk.h"
-extern void resetup_one_dev(struct gendisk *, unsigned int);
static int revalidate_hddisk(int, int);
static inline unsigned char CMOS_READ(unsigned char addr)
@@ -85,12 +84,13 @@ static int NR_HD = 0;
static struct hd_struct hd[MAX_HD<<6]={{0,0},};
static int hd_sizes[MAX_HD<<6] = {0, };
+static int hd_blocksizes[MAX_HD<<6] = {0, };
#define port_read(port,buf,nr) \
-__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
-__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
#if (HD_DELAY > 0)
unsigned long read_timer(void)
@@ -108,6 +108,22 @@ unsigned long read_timer(void)
}
#endif
+void hd_setup(char *str, int *ints)
+{
+ int hdind = 0;
+
+ if (ints[0] != 3)
+ return;
+ if (hd_info[0].head != 0)
+ hdind=1;
+ hd_info[hdind].head = ints[2];
+ hd_info[hdind].sect = ints[3];
+ hd_info[hdind].cyl = ints[1];
+ hd_info[hdind].wpcom = 0;
+ hd_info[hdind].lzone = ints[1];
+ hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+}
+
static int win_result(void)
{
int i=inb_p(HD_STATUS);
@@ -509,7 +525,7 @@ repeat:
static int hd_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
- struct hd_geometry *loc = (void *) arg;
+ struct hd_geometry *loc = (struct hd_geometry *) arg;
int dev, err;
if (!inode)
@@ -689,6 +705,9 @@ static void hd_geninit(void)
}
}
hd_gendisk.nr_real = NR_HD;
+
+ for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = hd_blocksizes;
}
static struct file_operations hd_fops = {
diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c
index 1691fc5..f6b3cae 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -51,7 +51,8 @@ struct blk_dev_struct blk_dev[MAX_BLKDEV] = {
};
/*
- * blk_size contains the size of all block-devices:
+ * blk_size contains the size of all block-devices in units of 1024 byte
+ * sectors:
*
* blk_size[MAJOR][MINOR]
*
@@ -59,6 +60,15 @@ struct blk_dev_struct blk_dev[MAX_BLKDEV] = {
*/
int * blk_size[MAX_BLKDEV] = { NULL, NULL, };
+/*
+ * blksize_size contains the size of all block-devices:
+ *
+ * blksize_size[MAJOR][MINOR]
+ *
+ * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
+ */
+int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
+
/* RO fail safe mechanism */
static long ro_bits[MAX_BLKDEV][8];
@@ -269,6 +279,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
struct request plug;
int plugged;
+ int correct_size;
struct blk_dev_struct * dev;
int i, j;
@@ -279,23 +290,32 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
if (nr <= 0) return;
};
+ if ((major=MAJOR(bh[0]->b_dev)) >= MAX_BLKDEV ||
+ !(blk_dev[major].request_fn)) {
+ printk("ll_rw_block: Trying to read nonexistent block-device %04x (%d)\n",bh[0]->b_dev,bh[0]->b_blocknr);
+ for (i=0;i<nr; i++)
+ if (bh[i]) bh[i]->b_dirt = bh[i]->b_uptodate = 0;
+ return;
+ }
+
for(j=0;j<nr; j++){
if(!bh[j]) continue;
- if (bh[j]->b_size != 1024) {
- printk("ll_rw_block: only 1024-char blocks implemented (%d)\n",bh[0]->b_size);
+ /* Determine correct block size for this device */
+ correct_size = BLOCK_SIZE;
+ if(blksize_size[major] && blksize_size[major][MINOR(bh[j]->b_dev)])
+ correct_size = blksize_size[major][MINOR(bh[j]->b_dev)];
+
+ if(bh[j]->b_size != correct_size) {
+
+ printk("ll_rw_block: only %d-char blocks implemented (%d)\n",
+ correct_size, bh[j]->b_size);
+
for (i=0;i<nr; i++)
if (bh[i]) bh[i]->b_dirt = bh[i]->b_uptodate = 0;
return;
}
};
- if ((major=MAJOR(bh[0]->b_dev)) >= MAX_BLKDEV ||
- !(blk_dev[major].request_fn)) {
- printk("ll_rw_block: Trying to read nonexistent block-device %04x (%d)\n",bh[0]->b_dev,bh[0]->b_blocknr);
- for (i=0;i<nr; i++)
- if (bh[i]) bh[i]->b_dirt = bh[i]->b_uptodate = 0;
- return;
- }
if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
printk("Can't write to read-only device 0x%X\n",bh[0]->b_dev);
for (i=0;i<nr; i++)
@@ -332,6 +352,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
{
int i;
+ int buffersize;
struct request * req;
unsigned int major = MAJOR(dev);
@@ -349,7 +370,9 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
return;
}
- for (i=0; i<nb; i++, buf += BLOCK_SIZE)
+ buffersize = PAGE_SIZE / nb;
+
+ for (i=0; i<nb; i++, buf += buffersize)
{
repeat:
req = request+NR_REQUEST;
@@ -364,9 +387,9 @@ repeat:
req->dev = dev;
req->cmd = rw;
req->errors = 0;
- req->sector = b[i] << 1;
- req->nr_sectors = 2;
- req->current_nr_sectors = 2;
+ req->sector = (b[i] * buffersize) >> 9;
+ req->nr_sectors = buffersize >> 9;
+ req->current_nr_sectors = buffersize >> 9;
req->buffer = buf;
req->waiting = current;
req->bh = NULL;
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
index d90c070..0bd237e 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/kernel/blk_drv/ramdisk.c
@@ -27,6 +27,7 @@
char *rd_start;
int rd_length = 0;
+static int rd_blocksizes[2] = {0, 0};
static void do_rd_request(void)
{
@@ -87,6 +88,10 @@ long rd_init(long mem_start, int length)
cp = rd_start;
for (i=0; i < length; i++)
*cp++ = '\0';
+
+ for(i=0;i<2;i++) rd_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = rd_blocksizes;
+
return(length);
}
diff --git a/kernel/blk_drv/scsi/Makefile b/kernel/blk_drv/scsi/Makefile
index 7e648e4..1b0ea8a 100644
--- a/kernel/blk_drv/scsi/Makefile
+++ b/kernel/blk_drv/scsi/Makefile
@@ -82,7 +82,7 @@ endif
CFLAGS := $(CFLAGS) "-DMAX_SCSI_HOSTS=($(SCSI_HOSTS))"
seagate.o: seagate.c
- $(CC) -Wall -I$(KERNELHDRS) -c seagate.c
+ $(CC) -Wall -I$(KERNELHDRS) -x c++ -c seagate.c
clean:
rm -f core *.o *.a *.s
diff --git a/kernel/blk_drv/scsi/aha1542.c b/kernel/blk_drv/scsi/aha1542.c
index 6919e51..4141c81 100644
--- a/kernel/blk_drv/scsi/aha1542.c
+++ b/kernel/blk_drv/scsi/aha1542.c
@@ -431,6 +431,8 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
printk("Sending command (%d %x)...",mbo, done);
#endif
+ any2scsi(mb[mbo].ccbptr, &ccb[mbo]); /* This gets trashed for some reason*/
+
memset(&ccb[mbo], 0, sizeof(struct ccb));
ccb[mbo].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */
@@ -451,7 +453,7 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
#endif
int i;
ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather*/
- SCpnt->host_scribble = scsi_malloc(512);
+ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
sgpnt = (struct scatterlist *) SCpnt->request_buffer;
cptr = (struct chain *) SCpnt->host_scribble;
if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n");
@@ -783,10 +785,11 @@ int aha1542_reset(void)
return 0;
}
-int aha1542_biosparam(int size, int dev, int* info){
- info[0] = 64;
- info[1] = 32;
- info[2] = size >> 11;
-/* if (info[2] >= 1024) info[2] = 1024; */
+int aha1542_biosparam(int size, int dev, int * ip)
+{
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = size >> 11;
+/* if (ip[2] >= 1024) ip[2] = 1024; */
return 0;
}
diff --git a/kernel/blk_drv/scsi/aha1740.c b/kernel/blk_drv/scsi/aha1740.c
index 6c1e184..b5b11ce 100644
--- a/kernel/blk_drv/scsi/aha1740.c
+++ b/kernel/blk_drv/scsi/aha1740.c
@@ -189,10 +189,10 @@ void aha1740_intr_handle(int foo)
case G2INTST_CCBRETRY:
case G2INTST_CCBERROR:
case G2INTST_CCBGOOD:
- ecbptr = (void *) ( ((ulong) inb(MBOXIN0)) +
- ((ulong) inb(MBOXIN1) <<8) +
- ((ulong) inb(MBOXIN2) <<16) +
- ((ulong) inb(MBOXIN3) <<24) );
+ ecbptr = (struct ecb *) ( ((ulong) inb(MBOXIN0)) +
+ ((ulong) inb(MBOXIN1) <<8) +
+ ((ulong) inb(MBOXIN2) <<16) +
+ ((ulong) inb(MBOXIN3) <<24) );
outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
SCtmp = ecbptr->SCpnt;
if (SCtmp->host_scribble)
@@ -314,7 +314,7 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
unsigned char * ptr;
#endif
ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/
- SCpnt->host_scribble = scsi_malloc(512);
+ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
sgpnt = (struct scatterlist *) SCpnt->request_buffer;
cptr = (struct aha1740_chain *) SCpnt->host_scribble;
if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
@@ -426,7 +426,7 @@ void aha1740_getconfig(void)
int aha1740_detect(int hostnum)
{
- memset(ecb,0,sizeof(ecb));
+ memset(&ecb, 0, sizeof(struct ecb));
DEB(printk("aha1740_detect: \n"));
for ( slot=MINEISA; slot <= MAXEISA; slot++ )
@@ -478,13 +478,13 @@ int aha1740_reset(void)
return 0;
}
-int aha1740_biosparam(int size, int dev, int* info)
+int aha1740_biosparam(int size, int dev, int* ip)
{
DEB(printk("aha1740_biosparam\n"));
- info[0] = 64;
- info[1] = 32;
- info[2] = size >> 11;
-/* if (info[2] >= 1024) info[2] = 1024; */
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = size >> 11;
+/* if (ip[2] >= 1024) ip[2] = 1024; */
return 0;
}
diff --git a/kernel/blk_drv/scsi/fdomain.c b/kernel/blk_drv/scsi/fdomain.c
index 0be2f75..958ac9e 100644
--- a/kernel/blk_drv/scsi/fdomain.c
+++ b/kernel/blk_drv/scsi/fdomain.c
@@ -1,10 +1,10 @@
-/* fdomain.c -- Future Domain TMC-1660/TMC-1680 driver
- * Created: Sun May 3 18:53:19 1992 by faith
- * Revised: Sat May 15 15:29:19 1993 by faith@cs.unc.edu
+/* fdomain.c -- Future Domain TMC-16x0 driver
+ * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
+ * Revised: Sat Jul 3 13:48:18 1993 by faith@cs.unc.edu
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993 Rickard E. Faith
*
- * $Log$
+ * $Id: fdomain.c,v 3.17 1993/07/03 14:06:31 root Exp $
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -19,14 +19,28 @@
**************************************************************************
+
DESCRIPTION:
This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
- and TMC-1650/1670 SCSI host adapters. The older boards are based on the
- TMC-1800 chip, and the driver was originally written for a TMC-1680 with
- this chip. More recently, boards are being produced with the TMC-18C50
- chip. This driver may not work with the more recent boards.
+ and TMC-1650/1670 SCSI host adapters. The 1650 and 1670 have a 25-pin
+ external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
+ high-density external connector. The 1670 and 1680 have floppy disk
+ controllers built in.
+ Future Domain's older boards are based on the TMC-1800 chip, and the
+ driver was originally written for a TMC-1680 board with the TMC-1800
+ chip. More recently, boards are being produced with the TMC-18C50 chip.
+ The latest and greatest board may not work with this driver. If you have
+ to patch this driver so that it will recognize your board's BIOS
+ signature, then the driver may fail to function after the board is
+ detected.
+
+ If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
+ your board. Please refer to the Seagate driver for more information and
+ possible support.
+
+
REFERENCES USED:
@@ -49,6 +63,7 @@
Youngdale (eric@tantalus.nrl.navy.mil), 1992.
+
NOTES ON REFERENCES:
The Maxtor manuals were free. Maxtor telephone technical support is
@@ -56,25 +71,37 @@
The Future Domain manuals were $25 and $35. They document the chip, not
the TMC-16x0 boards, so some information I had to guess at. In 1992,
- Future Domain sells DOS BIOS source for $250 and the UN*X driver source
- was $750, but these require a non-disclosure agreement, so even if I could
- afford them, they would *not* have been useful for writing this publically
- distributable driver. Future Domain technical support has provided some
- information on the phone and have sent a few useful FAXs.
+ Future Domain sold DOS BIOS source for $250 and the UN*X driver source was
+ $750, but these required a non-disclosure agreement, so even if I could
+ have afforded them, they would *not* have been useful for writing this
+ publically distributable driver. Future Domain technical support has
+ provided some information on the phone and have sent a few useful FAXs.
+ They have been much more helpful since they started to recognize that the
+ word "Linux" refers to an operating system :-).
+
ALPHA TESTERS:
There are many other alpha testers that come and go as the driver
develops. The people listed here were most helpful in times of greatest
- need. However, all of the alpha testers deserve much thanks.
+ need (mostly early on -- I've probably left out a few worthy people in
+ more recent times):
Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken
Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@dutiba.tudelft.nl),
Sakari Aaltonen (sakaria@vipunen.hit.fi), John Rice
- (rice@xanth.cs.odu.edu), and Brad Yearwood (brad@optilink.com).
+ (rice@xanth.cs.odu.edu), Brad Yearwood (brad@optilink.com), and Ray Toy
+ (toy@soho.crd.ge.com).
+
+ Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me
+ his 18C50-based card for debugging. He is the sole reason that this
+ driver works with the 18C50 chip.
+ All of the alpha testers deserve much thanks.
+
+
NOTES ON USER DEFINABLE OPTIONS:
DEBUG: This turns on the printing of various debug informaiton.
@@ -84,15 +111,6 @@
devices support parity, then you can probably get the driver to work by
turning this option off. I have no way of testing this, however.
- QUEUE: Enable "command queueing." This is supported by the higher level
- SCSI code, and allows the kernel to continue to schedule tasks while the
- SCSI request is pending. If this option is turned off, then everything
- will "freeze" during SCSI requests, and system performance will become
- unbearable. Later, this will allow multiple outstanding SCSI requests. I
- have received reports that if this option is turned off, the driver will
- no longer function correctly. I have not had time to track down this bug,
- since I hope to make the driver work for everyone with QUEUE on.
-
FIFO_COUNT: The host adapter has an 8K cache. When this many 512 byte
blocks are filled by the SCSI device, an interrupt will be raised.
Therefore, this could be as low as 0, or as high as 16. Note, however,
@@ -121,14 +139,14 @@
#include "fdomain.h"
#include <asm/system.h>
#include <linux/errno.h>
+#include <linux/string.h>
-#define VERSION "3.6" /* Change with each revision */
+#define VERSION "$Revision: 3.17 $"
/* START OF USER DEFINABLE OPTIONS */
#define DEBUG 1 /* Enable debugging output */
#define ENABLE_PARITY 1 /* Enable SCSI Parity */
-#define QUEUE 1 /* Enable command queueing */
#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */
#define DO_DETECT 0 /* Do device detection here (see scsi.c) */
#define RESELECTION 0 /* Support RESELECTION PHASE (NOT stable) */
@@ -139,8 +157,9 @@
#define EVERY_ACCESS 0 /* Write a line on every scsi access */
#define ERRORS_ONLY 1 /* Only write a line if there is an error */
#define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */
-#define DEBUG_MESSAGES 0 /* Debug MESSAGE IN PHASE */
+#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */
#define DEBUG_ABORT 1 /* Debug abort() routine */
+#define DEBUG_RESET 1 /* Debug reset() routine */
#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */
#else
#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
@@ -148,6 +167,8 @@
#define DEBUG_DETECT 0
#define DEBUG_MESSAGES 0
#define DEBUG_ABORT 0
+#define DEBUG_RESET 0
+#define DEBUG_RACE 0
#endif
/* Errors are reported on the line, so we don't need to report them again */
@@ -169,7 +190,6 @@ enum chip_type {
};
enum {
- non_queueing = 0x01,
in_arbitration = 0x02,
in_selection = 0x04,
in_other = 0x08,
@@ -183,14 +203,14 @@ enum in_port_type {
SCSI_Status = 1,
TMC_Status = 2,
FIFO_Status = 3, /* tmc18c50 only */
- Interrupt_Cond = 4, /* tmc18c50 only */
+ Interrupt_Cond = 4, /* tmc18c50 only */
LSB_ID_Code = 5,
MSB_ID_Code = 6,
Read_Loopback = 7,
SCSI_Data_NoACK = 8,
- Interrupt_Mask = 9,
- Option_Select = 10,
- Configuration = 11, /* tmc18c50 only */
+ Interrupt_Status = 9,
+ Configuration1 = 10,
+ Configuration2 = 11, /* tmc18c50 only */
Read_FIFO = 12,
FIFO_Data_Count = 14
};
@@ -199,7 +219,7 @@ enum out_port_type {
Write_SCSI_Data = 0,
SCSI_Cntl = 1,
Interrupt_Cntl = 2,
- Data_Mode_Cntl = 3,
+ SCSI_Mode_Cntl = 3,
TMC_Cntl = 4,
Memory_Cntl = 5, /* tmc18c50 only */
Write_Loopback = 7,
@@ -212,19 +232,19 @@ static int bios_major = 0;
static int bios_minor = 0;
static int interrupt_level = 0;
static int this_host = 0;
-static int can_queue = QUEUE;
static volatile int in_command = 0;
static Scsi_Cmnd *current_SC = NULL;
static enum chip_type chip = unknown;
+static int adapter_mask = 0x40;
#if DEBUG_RACE
static volatile int in_interrupt_flag = 0;
#endif
-static int Data_Mode_Cntl_port;
+static int SCSI_Mode_Cntl_port;
static int FIFO_Data_Count_port;
static int Interrupt_Cntl_port;
-static int Interrupt_Mask_port;
+static int Interrupt_Status_port;
static int Read_FIFO_port;
static int Read_SCSI_Data_port;
static int SCSI_Cntl_port;
@@ -260,15 +280,18 @@ static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
This driver works *ONLY* for Future Domain cards using the TMC-1800 chip.
This includes models TMC-1660, 1670, and 1680 *ONLY*.
- The following BIOS signatures have been tried with this driver. These
- signatures are for boards which do *NOT* work with this driver (but the
- first one should work with the Seagate driver):
+ The following BIOS signature signatures are for boards which do *NOT*
+ work with this driver (but they should work with the Seagate driver):
- FUTURE DOMAIN COPR. (C) 1986-1989 V6.0A7/28/90
- FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
- FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+ FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88
+ FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89
+ FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89
+ FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90
+ FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
+ FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+ FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92
- */
+*/
struct signature {
char *signature;
@@ -282,7 +305,11 @@ struct signature {
{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0 },
{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0 },
{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2 },
- /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE */
+
+ /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE
+ Also, fix the disk geometry code for your signature and send your
+ changes for faith@cs.unc.edu. Above all, do *NOT* change any old
+ signatures! */
};
#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
@@ -302,7 +329,7 @@ inline static unsigned short inw( unsigned short port )
inline static void outw( unsigned short value, unsigned short port )
{
__asm__ volatile ( "outw %0,%1"
- ::"a" ((unsigned short) value),
+ : :"a" ((unsigned short) value),
"d" ((unsigned short) port) );
}
@@ -311,11 +338,11 @@ inline static void outw( unsigned short value, unsigned short port )
#define insw( buf, count, port ) \
__asm__ volatile \
- ("cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" )
+ ("cld;rep;insw": :"d" (port),"D" (buf),"c" (count):"cx","di" )
#define outsw( buf, count, port ) \
__asm__ volatile \
- ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si")
+ ("cld;rep;outsw": :"d" (port),"S" (buf),"c" (count):"cx","si")
static void print_banner( void )
@@ -345,8 +372,11 @@ static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
inline static void fdomain_make_bus_idle( void )
{
outb( 0, SCSI_Cntl_port );
- outb( 0, Data_Mode_Cntl_port );
- outb( 1 | PARITY_MASK, TMC_Cntl_port );
+ outb( 0, SCSI_Mode_Cntl_port );
+ if (chip == tmc18c50)
+ outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */
+ else
+ outb( 0x01 | PARITY_MASK, TMC_Cntl_port );
}
static int fdomain_is_valid_port( int port )
@@ -380,10 +410,10 @@ static int fdomain_is_valid_port( int port )
we only detect one board here. [The one with the lowest bios_base.]
*/
- options = inb( port + Option_Select );
+ options = inb( port + Configuration1 );
#if DEBUG_DETECT
- printk( " Options = %x,", options );
+ printk( " Options = %x\n", options );
#endif
if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
@@ -408,7 +438,7 @@ static int fdomain_test_loopback( void )
int fdomain_16x0_detect( int hostnum )
{
int i, j;
- int flag;
+ int flag = 0;
struct sigaction sa;
int retcode;
#if DO_DETECT
@@ -422,7 +452,7 @@ int fdomain_16x0_detect( int hostnum )
#endif
#if DEBUG_DETECT
- printk( "SCSI: fdomain_16x0_detect()," );
+ printk( "fdomain_16x0_detect()," );
#endif
for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
@@ -446,37 +476,40 @@ int fdomain_16x0_detect( int hostnum )
return 0;
}
- /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
- Assuming the ROM is enabled (otherwise we wouldn't have been
- able to read the ROM signature :-), then the ROM sets up the
- RAM area with some magic numbers, such as a list of port
- base addresses and a list of the disk "geometry" reported to
- DOS (this geometry has nothing to do with physical geometry).
- */
+ if (bios_major == 2) {
+ /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
+ Assuming the ROM is enabled (otherwise we wouldn't have been
+ able to read the ROM signature :-), then the ROM sets up the
+ RAM area with some magic numbers, such as a list of port
+ base addresses and a list of the disk "geometry" reported to
+ DOS (this geometry has nothing to do with physical geometry).
+ */
- port_base = *((char *)bios_base + 0x1fcc)
- + (*((char *)bios_base + 0x1fcd) << 8);
+ port_base = *((char *)bios_base + 0x1fcc)
+ + (*((char *)bios_base + 0x1fcd) << 8);
#if DEBUG_DETECT
- printk( " %x,", port_base );
+ printk( " %x,", port_base );
#endif
- for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
- if (port_base == ports[i]) ++flag;
- }
+ for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
+ if (port_base == ports[i]) ++flag;
+ }
- if (flag)
- flag = fdomain_is_valid_port( port_base );
+ if (flag)
+ flag = fdomain_is_valid_port( port_base );
+ }
if (!flag) { /* Cannot get port base from BIOS RAM */
/* This is a bad sign. It usually means that someone patched the
BIOS signature list (the signatures variable) to contain a BIOS
- signature for a board *OTHER THAN* the TMC-1660/TMC-1680.
+ signature for a board *OTHER THAN* the TMC-1660/TMC-1680. It
+ also means that we don't have a Version 2.0 BIOS :-)
*/
#if DEBUG_DETECT
- printk( " RAM FAILED, " );
+ if (bios_major != 2) printk( " RAM FAILED, " );
#endif
/* Anyway, the alternative to finding the address in the RAM is
@@ -487,7 +520,7 @@ int fdomain_16x0_detect( int hostnum )
similar.
*/
- for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
+ for (i = 0; !flag && i < PORT_COUNT; i++) {
port_base = ports[i];
#if DEBUG_DETECT
printk( " %x,", port_base );
@@ -504,30 +537,26 @@ int fdomain_16x0_detect( int hostnum )
}
print_banner();
- if (chip == tmc18c50)
- printk( "Future Domain WARNING: This driver may not work with the"
- " TMC-18C50 chip!\n"
- " Send mail to faith@cs.unc.edu\n" );
-
- Data_Mode_Cntl_port = port_base + Data_Mode_Cntl;
- FIFO_Data_Count_port = port_base + FIFO_Data_Count;
- Interrupt_Cntl_port = port_base + Interrupt_Cntl;
- Interrupt_Mask_port = port_base + Interrupt_Mask;
- Read_FIFO_port = port_base + Read_FIFO;
- Read_SCSI_Data_port = port_base + Read_SCSI_Data;
- SCSI_Cntl_port = port_base + SCSI_Cntl;
- SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK;
- SCSI_Status_port = port_base + SCSI_Status;
- TMC_Cntl_port = port_base + TMC_Cntl;
- TMC_Status_port = port_base + TMC_Status;
- Write_FIFO_port = port_base + Write_FIFO;
- Write_SCSI_Data_port = port_base + Write_SCSI_Data;
+
+ SCSI_Mode_Cntl_port = port_base + SCSI_Mode_Cntl;
+ FIFO_Data_Count_port = port_base + FIFO_Data_Count;
+ Interrupt_Cntl_port = port_base + Interrupt_Cntl;
+ Interrupt_Status_port = port_base + Interrupt_Status;
+ Read_FIFO_port = port_base + Read_FIFO;
+ Read_SCSI_Data_port = port_base + Read_SCSI_Data;
+ SCSI_Cntl_port = port_base + SCSI_Cntl;
+ SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK;
+ SCSI_Status_port = port_base + SCSI_Status;
+ TMC_Cntl_port = port_base + TMC_Cntl;
+ TMC_Status_port = port_base + TMC_Status;
+ Write_FIFO_port = port_base + Write_FIFO;
+ Write_SCSI_Data_port = port_base + Write_SCSI_Data;
fdomain_16x0_reset();
if (fdomain_test_loopback()) {
#if DEBUG_DETECT
- printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
+ printk( "Future Domain: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
#endif
return 0;
}
@@ -587,11 +616,8 @@ int fdomain_16x0_detect( int hostnum )
this_host = hostnum;
- if (!QUEUE || !interrupt_level) {
- printk( "Future Domain: *NO* interrupt level selected!\n" );
- printk( " COMMAND QUEUEING DISABLED!\n" );
- can_queue = scsi_hosts[this_host].can_queue = 0;
- scsi_hosts[this_host].sg_tablesize = SG_NONE;
+ if (!interrupt_level) {
+ panic( "Future Domain: *NO* interrupt level selected!\n" );
} else {
/* Register the IRQ with the kernel */
@@ -616,39 +642,55 @@ int fdomain_16x0_detect( int hostnum )
printk( " This shouldn't happen!\n" );
printk( " Send mail to faith@cs.unc.edu\n" );
}
- printk( " COMMAND QUEUEING DISABLED!\n" );
-
- can_queue = scsi_hosts[this_host].can_queue = 0;
- scsi_hosts[this_host].sg_tablesize = SG_NONE;
+ panic( "Future Domain: Driver requires interruptions\n" );
} else {
printk( "Future Domain: IRQ %d requested from kernel\n",
interrupt_level );
}
}
+
+ if (bios_major == 3 && bios_minor >= 2) {
+ adapter_mask = 0x80;
+ scsi_hosts[this_host].this_id = 7;
+ }
return 1;
}
const char *fdomain_16x0_info(void)
{
- static char buffer[] =
- "Future Domain TMC-16x0 SCSI driver version "
- VERSION
- "\n";
+ static char buffer[80];
+ char *pt;
+
+ strcpy( buffer, "Future Domain: TMC-16x0 SCSI driver, version" );
+ if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */
+ strcat( buffer, strchr( VERSION, ':' ) + 1 );
+ pt = strrchr( buffer, '$') - 1;
+ if (!pt) /* Stripped RCS Revision string? */
+ pt = buffer + strlen( buffer ) - 1;
+ if (*pt != ' ')
+ ++pt;
+ *pt++ = '\n';
+ *pt = '\0';
+ } else { /* Assume VERSION is a number */
+ strcat( buffer, " " VERSION "\n" );
+ }
+
return buffer;
}
+#if 0
static int fdomain_arbitrate( void )
{
int status = 0;
unsigned long timeout;
#if EVERY_ACCESS
- printk( "SCSI: fdomain_arbitrate()\n" );
+ printk( "fdomain_arbitrate()\n" );
#endif
outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */
- outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */
+ outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */
outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
timeout = jiffies + 50; /* 500 mS */
@@ -664,27 +706,29 @@ static int fdomain_arbitrate( void )
printk( "Arbitration failed, status = %x\n", status );
#endif
#if ERRORS_ONLY
- printk( "SCSI (Future Domain): Arbitration failed, status = %x",
+ printk( "Future Domain: Arbitration failed, status = %x",
status );
#endif
return 1;
}
+#endif
static int fdomain_select( int target )
{
int status;
unsigned long timeout;
- /* Send our address OR'd with target address */
- outb( 0x40 | (1 << target), SCSI_Data_NoACK_port );
- if (RESELECTION && can_queue)
- outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
- else
- outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
+ if (RESELECTION) {
+ outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
+ outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port );
+ } else {
+ outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
+ outb( 1 << target, SCSI_Data_NoACK_port );
+ }
- /* Stop arbitration (also set FIFO for output and enable parity) */
- outb( 0xc0 | PARITY_MASK, TMC_Cntl_port );
+ /* Stop arbitration and enable parity */
+ outb( PARITY_MASK, TMC_Cntl_port );
timeout = jiffies + 25; /* 250mS */
while (jiffies < timeout) {
@@ -701,7 +745,7 @@ static int fdomain_select( int target )
if (!target) printk( "Selection failed\n" );
#endif
#if ERRORS_ONLY
- if (!target) printk( "SCSI (Future Domain): Selection failed" );
+ if (!target) printk( "Future Domain: Selection failed" );
#endif
return 1;
}
@@ -714,9 +758,9 @@ void my_done( int error )
fdomain_make_bus_idle();
current_SC->result = error;
if (current_SC->scsi_done) current_SC->scsi_done( current_SC );
- else panic( "SCSI (Future Domain): current_SC->scsi_done() == NULL" );
+ else panic( "Future Domain: current_SC->scsi_done() == NULL" );
} else {
- panic( "SCSI (Future Domain): my_done() called outside of command\n" );
+ panic( "Future Domain: my_done() called outside of command\n" );
}
#if DEBUG_RACE
in_interrupt_flag = 0;
@@ -735,6 +779,10 @@ void fdomain_16x0_intr( int unused )
/* We usually have one spurious interrupt after each command. Ignore it. */
if (!in_command || !current_SC) { /* Spurious interrupt */
+#if EVERY_ACCESS
+ printk( "Spurious interrupt, in_command = %d, current_SC = %x\n",
+ in_command, current_SC );
+#endif
return;
}
#if DEBUG_RACE
@@ -787,17 +835,17 @@ void fdomain_16x0_intr( int unused )
current_SC->SCp.phase = in_selection;
outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port );
-
- outb( 0x40 | (1 << current_SC->target), SCSI_Data_NoACK_port );
-
+
#if RESELECTION
outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
+ outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port );
#else
outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
+ outb( 1 << current_SC->target, SCSI_Data_NoACK_port );
#endif
- /* Stop arbitration (also set FIFO for output and enable parity) */
- outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
+ /* Stop arbitration and enable parity */
+ outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
#if DEBUG_RACE
in_interrupt_flag = 0;
#endif
@@ -816,8 +864,8 @@ void fdomain_16x0_intr( int unused )
#if EVERY_ACCESS
printk( " AltSel " );
#endif
- /* Stop arbitration (also set FIFO for output and enable parity) */
- outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
+ /* Stop arbitration and enable parity */
+ outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
}
}
current_SC->SCp.phase = in_other;
@@ -835,88 +883,18 @@ void fdomain_16x0_intr( int unused )
/* current_SC->SCp.phase == in_other: this is the body of the routine */
- switch (current_SC->cmnd[0]) {
- case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
- case 0x2e: case 0x3b: case 0xea: case 0x3f:
- while ( (data_count = 0x2000 - inw( FIFO_Data_Count_port )) > 512 ) {
-#if EVERY_ACCESS
- printk( "DC=%d, ", data_count ) ;
-#endif
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
- if (data_count > 0) {
-#if EVERY_ACCESS
- printk( "%d OUT, ", data_count );
-#endif
- if (data_count == 1) {
- outb( *current_SC->SCp.ptr++, Write_FIFO_port );
- --current_SC->SCp.this_residual;
- } else {
- data_count >>= 1;
- outsw( current_SC->SCp.ptr, data_count, Write_FIFO_port );
- current_SC->SCp.ptr += 2 * data_count;
- current_SC->SCp.this_residual -= 2 * data_count;
- }
- }
- if (!current_SC->SCp.this_residual) {
- if (current_SC->SCp.buffers_residual) {
- --current_SC->SCp.buffers_residual;
- ++current_SC->SCp.buffer;
- current_SC->SCp.ptr = current_SC->SCp.buffer->address;
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- } else
- break;
- }
- }
- break;
- default:
- if (!current_SC->SCp.have_data_in) {
- outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
- ++current_SC->SCp.have_data_in;
- } else {
- while ((data_count = inw( FIFO_Data_Count_port )) != 0) {
-#if EVERY_ACCESS
- printk( "DC=%d, ", data_count );
-#endif
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
- if (data_count) {
-#if EVERY_ACCESS
- printk( "%d IN, ", data_count );
-#endif
- if (data_count == 1) {
- *current_SC->SCp.ptr++ = inb( Read_FIFO_port );
- --current_SC->SCp.this_residual;
- } else {
- data_count >>= 1; /* Number of words */
- insw( current_SC->SCp.ptr, data_count, Read_FIFO_port );
- current_SC->SCp.ptr += 2 * data_count;
- current_SC->SCp.this_residual -= 2 * data_count;
- }
- }
- if (!current_SC->SCp.this_residual
- && current_SC->SCp.buffers_residual) {
- --current_SC->SCp.buffers_residual;
- ++current_SC->SCp.buffer;
- current_SC->SCp.ptr = current_SC->SCp.buffer->address;
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- }
- }
- }
- break;
- }
-
status = inb( SCSI_Status_port );
if (status & 0x10) { /* REQ */
switch (status & 0x0e) {
+
case 0x08: /* COMMAND OUT */
#if 0
if (!current_SC->SCp.sent_command) {
int i;
- ++current_SC->SCp.sent_command;
+ current_SC->SCp.sent_command = COMMAND_SIZE( current_SC->cmnd[0] );
for (i = 0; i < COMMAND_SIZE( current_SC->cmnd[0] ); i++) {
outb( current_SC->cmnd[i], Write_SCSI_Data_port );
@@ -935,6 +913,18 @@ void fdomain_16x0_intr( int unused )
#endif
break;
+ case 0x00: /* DATA OUT -- tmc18c50 only */
+ if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
+ current_SC->SCp.have_data_in = -1;
+ outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
+ }
+ break;
+ case 0x04: /* DATA IN -- tmc18c50 only */
+ if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
+ current_SC->SCp.have_data_in = 1;
+ outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
+ }
+ break;
case 0x0c: /* STATUS IN */
current_SC->SCp.Status = inb( Read_SCSI_Data_port );
#if EVERY_ACCESS
@@ -942,7 +932,7 @@ void fdomain_16x0_intr( int unused )
#endif
#if ERRORS_ONLY
if (current_SC->SCp.Status && current_SC->SCp.Status != 2) {
- printk( "SCSI (Future Domain): target = %d, command = %x, "
+ printk( "Future Domain: target = %d, command = %x, "
"Status = %x\n",
current_SC->target, current_SC->cmnd[0],
current_SC->SCp.Status );
@@ -977,67 +967,268 @@ void fdomain_16x0_intr( int unused )
#endif
#if DEBUG_MESSAGES || EVERY_ACCESS
if (current_SC->SCp.Message) {
- printk( "SCSI (Future Domain): Message = %x\n",
+ printk( "Future Domain: Message = %x\n",
current_SC->SCp.Message );
}
#endif
break;
}
}
-
- if (done) {
-#if EVERY_ACCESS
- printk( " ** IN DONE ** " );
-#endif
- if (current_SC->SCp.have_data_in) {
- while ((data_count = inw( FIFO_Data_Count_port )) != 0) {
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
+ if (chip == tmc1800
+ && !current_SC->SCp.have_data_in
+ && (current_SC->SCp.sent_command
+ >= COMMAND_SIZE( current_SC->cmnd[ 0 ] ))) {
+ /* We have to get the FIFO direction
+ correct, so I've made a table based
+ on the SCSI Standard of which commands
+ appear to require a DATA OUT phase.
+ */
+ /*
+ p. 94: Command for all device types
+ CHANGE DEFINITION 40 DATA OUT
+ COMPARE 39 DATA OUT
+ COPY 18 DATA OUT
+ COPY AND VERIFY 3a DATA OUT
+ INQUIRY 12
+ LOG SELECT 4c DATA OUT
+ LOG SENSE 4d
+ MODE SELECT (6) 15 DATA OUT
+ MODE SELECT (10) 55 DATA OUT
+ MODE SENSE (6) 1a
+ MODE SENSE (10) 5a
+ READ BUFFER 3c
+ RECEIVE DIAGNOSTIC RESULTS 1c
+ REQUEST SENSE 03
+ SEND DIAGNOSTIC 1d DATA OUT
+ TEST UNIT READY 00
+ WRITE BUFFER 3b DATA OUT
+
+ p.178: Commands for direct-access devices (not listed on p. 94)
+ FORMAT UNIT 04 DATA OUT
+ LOCK-UNLOCK CACHE 36
+ PRE-FETCH 34
+ PREVENT-ALLOW MEDIUM REMOVAL 1e
+ READ (6)/RECEIVE 08
+ READ (10) 3c
+ READ CAPACITY 25
+ READ DEFECT DATA (10) 37
+ READ LONG 3e
+ REASSIGN BLOCKS 07 DATA OUT
+ RELEASE 17
+ RESERVE 16 DATA OUT
+ REZERO UNIT/REWIND 01
+ SEARCH DATA EQUAL (10) 31 DATA OUT
+ SEARCH DATA HIGH (10) 30 DATA OUT
+ SEARCH DATA LOW (10) 32 DATA OUT
+ SEEK (6) 0b
+ SEEK (10) 2b
+ SET LIMITS (10) 33
+ START STOP UNIT 1b
+ SYNCHRONIZE CACHE 35
+ VERIFY (10) 2f
+ WRITE (6)/PRINT/SEND 0a DATA OUT
+ WRITE (10)/SEND 2a DATA OUT
+ WRITE AND VERIFY (10) 2e DATA OUT
+ WRITE LONG 3f DATA OUT
+ WRITE SAME 41 DATA OUT ?
+
+ p. 261: Commands for sequential-access devices (not previously listed)
+ ERASE 19
+ LOAD UNLOAD 1b
+ LOCATE 2b
+ READ BLOCK LIMITS 05
+ READ POSITION 34
+ READ REVERSE 0f
+ RECOVER BUFFERED DATA 14
+ SPACE 11
+ WRITE FILEMARKS 10 ?
+
+ p. 298: Commands for printer devices (not previously listed)
+ ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
+ SLEW AND PRINT 0b DATA OUT -- same as seek
+ STOP PRINT 1b
+ SYNCHRONIZE BUFFER 10
+
+ p. 315: Commands for processor devices (not previously listed)
+
+ p. 321: Commands for write-once devices (not previously listed)
+ MEDIUM SCAN 38
+ READ (12) a8
+ SEARCH DATA EQUAL (12) b1 DATA OUT
+ SEARCH DATA HIGH (12) b0 DATA OUT
+ SEARCH DATA LOW (12) b2 DATA OUT
+ SET LIMITS (12) b3
+ VERIFY (12) af
+ WRITE (12) aa DATA OUT
+ WRITE AND VERIFY (12) ae DATA OUT
+
+ p. 332: Commands for CD-ROM devices (not previously listed)
+ PAUSE/RESUME 4b
+ PLAY AUDIO (10) 45
+ PLAY AUDIO (12) a5
+ PLAY AUDIO MSF 47
+ PLAY TRACK RELATIVE (10) 49
+ PLAY TRACK RELATIVE (12) a9
+ READ HEADER 44
+ READ SUB-CHANNEL 42
+ READ TOC 43
+
+ p. 370: Commands for scanner devices (not previously listed)
+ GET DATA BUFFER STATUS 34
+ GET WINDOW 25
+ OBJECT POSITION 31
+ SCAN 1b
+ SET WINDOW 24 DATA OUT
+
+ p. 391: Commands for optical memory devices (not listed)
+ ERASE (10) 2c
+ ERASE (12) ac
+ MEDIUM SCAN 38 DATA OUT
+ READ DEFECT DATA (12) b7
+ READ GENERATION 29
+ READ UPDATED BLOCK 2d
+ UPDATE BLOCK 3d DATA OUT
+
+ p. 419: Commands for medium changer devices (not listed)
+ EXCHANGE MEDIUM 46
+ INITIALIZE ELEMENT STATUS 07
+ MOVE MEDIUM a5
+ POSITION TO ELEMENT 2b
+ READ ELEMENT STATUS b8
+ REQUEST VOL. ELEMENT ADDRESS b5
+ SEND VOLUME TAG b6 DATA OUT
+
+ p. 454: Commands for communications devices (not listed previously)
+ GET MESSAGE (6) 08
+ GET MESSAGE (10) 28
+ GET MESSAGE (12) a8
+ */
+
+ switch (current_SC->cmnd[0]) {
+ case CHANGE_DEFINITION: case COMPARE: case COPY:
+ case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT:
+ case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER:
+
+ case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
+ case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
+ case WRITE_6: case WRITE_10: case WRITE_VERIFY:
+ case 0x3f: case 0x41:
+
+ case 0xb1: case 0xb0: case 0xb2:
+ case 0xaa: case 0xae:
+
+ case 0x24:
+
+ case 0x38: case 0x3d:
+
+ case 0xb6:
+
+ case 0xea: /* alternate number for WRITE LONG */
+
+ current_SC->SCp.have_data_in = -1;
+ outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
+ break;
+
+ case 0x00:
+ default:
+
+ current_SC->SCp.have_data_in = 1;
+ outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
+ break;
+ }
+ }
- if (data_count) {
+ if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
+ while ( (data_count = 0x2000 - inw( FIFO_Data_Count_port )) > 512 ) {
+#if EVERY_ACCESS
+ printk( "DC=%d, ", data_count ) ;
+#endif
+ if (data_count > current_SC->SCp.this_residual)
+ data_count = current_SC->SCp.this_residual;
+ if (data_count > 0) {
#if EVERY_ACCESS
- printk( "%d IN, ", data_count );
+ printk( "%d OUT, ", data_count );
#endif
- if (data_count == 1) {
- *current_SC->SCp.ptr++ = inb( Read_FIFO_port );
- --current_SC->SCp.this_residual;
- } else {
- data_count >>= 1; /* Number of words */
- insw( current_SC->SCp.ptr, data_count, Read_FIFO_port );
- current_SC->SCp.this_residual -= 2 * data_count;
- }
+ if (data_count == 1) {
+ outb( *current_SC->SCp.ptr++, Write_FIFO_port );
+ --current_SC->SCp.this_residual;
+ } else {
+ data_count >>= 1;
+ outsw( current_SC->SCp.ptr, data_count, Write_FIFO_port );
+ current_SC->SCp.ptr += 2 * data_count;
+ current_SC->SCp.this_residual -= 2 * data_count;
}
-
- if (!current_SC->SCp.this_residual
- && current_SC->SCp.buffers_residual) {
-
+ }
+ if (!current_SC->SCp.this_residual) {
+ if (current_SC->SCp.buffers_residual) {
--current_SC->SCp.buffers_residual;
++current_SC->SCp.buffer;
current_SC->SCp.ptr = current_SC->SCp.buffer->address;
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+ } else
+ break;
+ }
+ }
+ }
+
+ if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
+ while ((data_count = inw( FIFO_Data_Count_port )) > 0) {
+#if EVERY_ACCESS
+ printk( "DC=%d, ", data_count );
+#endif
+ if (data_count > current_SC->SCp.this_residual)
+ data_count = current_SC->SCp.this_residual;
+ if (data_count) {
+#if EVERY_ACCESS
+ printk( "%d IN, ", data_count );
+#endif
+ if (data_count == 1) {
+ *current_SC->SCp.ptr++ = inb( Read_FIFO_port );
+ --current_SC->SCp.this_residual;
+ } else {
+ data_count >>= 1; /* Number of words */
+ insw( current_SC->SCp.ptr, data_count, Read_FIFO_port );
+ current_SC->SCp.ptr += 2 * data_count;
+ current_SC->SCp.this_residual -= 2 * data_count;
}
}
+ if (!current_SC->SCp.this_residual
+ && current_SC->SCp.buffers_residual) {
+ --current_SC->SCp.buffers_residual;
+ ++current_SC->SCp.buffer;
+ current_SC->SCp.ptr = current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+ }
}
+ }
+
+ if (done) {
#if EVERY_ACCESS
- printk( "AFTER DATA GET\n" );
+ printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in );
#endif
-
+
#if ERRORS_ONLY
if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
unsigned char key;
unsigned char code;
+ unsigned char qualifier;
key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
& 0x0f;
code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
+ qualifier = (unsigned char)(*((char *)current_SC->request_buffer
+ + 13));
if (!(key == UNIT_ATTENTION && (code == 0x29 || !code))
- && !(key == ILLEGAL_REQUEST && (code == 0x25 || !code)))
+ && !(key == ILLEGAL_REQUEST && (code == 0x25
+ || code == 0x24
+ || !code)))
- printk( "SCSI REQUEST SENSE: Key = %x, Code = %x\n",
- key, code );
+ printk( "Future Domain: REQUEST SENSE "
+ "Key = %x, Code = %x, Qualifier = %x\n",
+ key, code, qualifier );
}
}
#endif
@@ -1067,7 +1258,7 @@ void fdomain_16x0_intr( int unused )
int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
if (in_command) {
- panic( "SCSI (Future Domain): fdomain_16x0_queue() NOT REENTRANT!\n" );
+ panic( "Future Domain: fdomain_16x0_queue() NOT REENTRANT!\n" );
}
#if EVERY_ACCESS
printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
@@ -1091,7 +1282,7 @@ int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
} else {
- current_SC->SCp.ptr = current_SC->request_buffer;
+ current_SC->SCp.ptr = (char *)current_SC->request_buffer;
current_SC->SCp.this_residual = current_SC->request_bufflen;
current_SC->SCp.buffer = NULL;
current_SC->SCp.buffers_residual = 0;
@@ -1107,7 +1298,7 @@ int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
/* Start arbitration */
outb( 0x00, Interrupt_Cntl_port );
outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */
- outb( 0x40, SCSI_Data_NoACK_port ); /* Set our id bit */
+ outb( adapter_mask, SCSI_Data_NoACK_port ); /* Set our id bit */
++in_command;
outb( 0x20, Interrupt_Cntl_port );
outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
@@ -1117,239 +1308,78 @@ int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
int fdomain_16x0_command( Scsi_Cmnd *SCpnt )
{
- const char *cmd_pt = SCpnt->cmnd;
- const char *the_command = SCpnt->cmnd;
- unsigned char *out_buf_pt = SCpnt->request_buffer;
- unsigned char *in_buf_pt = SCpnt->request_buffer;
- unsigned char target = SCpnt->target;
- void *buff = SCpnt->request_buffer;
- int bufflen = SCpnt->request_bufflen;
- int Status = 0;
- int Message = 0;
- int status;
- int done = 0;
- unsigned long timeout;
- unsigned data_sent = 0;
- unsigned data_count;
- int have_data_in = 0;
-
- current_SC = SCpnt;
-
-#if EVERY_ACCESS
- printk( "fdomain_command(%d, %x): ", target, (unsigned char)*the_command );
-#endif
-
- if (fdomain_arbitrate()) {
-#if ERRORS_ONLY
- printk( ", target = %d, command = %x\n",
- target, (unsigned char)*the_command );
-#endif
- return DID_TIME_OUT << 16;
- }
-
- if (fdomain_select( target )) {
-#if ERRORS_ONLY
- if (!target) printk( ", target = %d, command = %x\n",
- target, (unsigned char)*the_command );
-#endif
- return DID_NO_CONNECT << 16;
- }
-
- timeout = jiffies + 500; /* 5000 mS -- For Maxtor after a RST */
- current_SC->SCp.phase = non_queueing;
-
- switch ((unsigned char)*the_command) {
- case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
- case 0x2e: case 0x3b: case 0xea: case 0x3f:
- data_count = 0x2000 - inw( FIFO_Data_Count_port );
- if (bufflen - data_sent < data_count)
- data_count = bufflen - data_sent;
- if (data_count == 1) {
- outb( *out_buf_pt++, Write_FIFO_port );
- ++data_sent;
- } else {
- data_count >>= 1;
- outsw( out_buf_pt, data_count, Write_FIFO_port );
- out_buf_pt += 2 * data_count;
- data_sent += 2 * data_count;
- }
- break;
- default:
- outb( 0x80 | PARITY_MASK, TMC_Cntl_port );
- ++have_data_in;
- break;
- }
-
- while (((status = inb( SCSI_Status_port )) & 1)
- && !done && !(current_SC->SCp.phase & aborted)
- && jiffies < timeout) {
-
- if (status & 0x10) { /* REQ */
-
- switch (status & 0x0e) {
- case 0x00: /* DATA OUT */
- data_count = 0x2000 - inw( FIFO_Data_Count_port );
- if (bufflen - data_sent < data_count)
- data_count = bufflen - data_sent;
- if (data_count == 1) {
- outb( *out_buf_pt++, Write_FIFO_port );
- ++data_sent;
- } else {
- data_count >>= 1;
- outsw( out_buf_pt, data_count, Write_FIFO_port );
- out_buf_pt += 2 * data_count;
- data_sent += 2 * data_count;
- }
- break;
- case 0x04: /* DATA IN */
- if (!have_data_in) {
- outb( 0x80 | PARITY_MASK, TMC_Cntl_port );
- ++have_data_in;
- }
- data_count = inw( FIFO_Data_Count_port );
- if (data_count == 1) {
- *in_buf_pt++ = inb( Read_FIFO_port );
- } else {
- data_count >>= 1; /* Number of words */
- insw( in_buf_pt, data_count, Read_FIFO_port );
- in_buf_pt += 2 * data_count;
- }
- break;
- case 0x08: /* COMMAND OUT */
- outb( *cmd_pt++, Write_SCSI_Data_port );
-#if EVERY_ACCESS
- printk( "%x,", (unsigned char)cmd_pt[-1] );
-#endif
- break;
- case 0x0c: /* STATUS IN */
- Status = inb( Read_SCSI_Data_port );
-#if EVERY_ACCESS
- printk( "Status = %x, ", Status );
-#endif
-#if ERRORS_ONLY
- if (Status) {
- printk( "SCSI (Future Domain): target = %d, command = %x, "
- "Status = %x\n",
- target, (unsigned char)*the_command, Status );
- }
-#endif
- break;
- case 0x0a: /* MESSAGE OUT */
- outb( 0x07, Write_SCSI_Data_port ); /* Reject */
- break;
- case 0x0e: /* MESSAGE IN */
- Message = inb( Read_SCSI_Data_port );
-#if EVERY_ACCESS
- printk( "Message = %x, ", Message );
-#endif
- if (!Message) ++done;
- if (Message == DISCONNECT) printk( "DISCONNECT\n" );
- break;
- }
- }
- }
-
- if (jiffies >= timeout) {
-#if EVERY_ACCESS
- printk( "Time out, status = %x\n", status );
-#endif
-#if ERRORS_ONLY
- printk( "SCSI (Future Domain): "
- "Time out, status = %x (target = %d, command = %x)\n",
- status, target, (unsigned char)*the_command );
-#endif
- fdomain_make_bus_idle();
- return DID_BUS_BUSY << 16;
- }
-
- if (current_SC->SCp.phase & aborted) {
-#if EVERY_ACCESS
- printk( "Aborted\n" );
-#endif
-#if ERRORS_ONLY
- printk( "SCSI (Future Domain): Aborted (command = %x)\n",
- (unsigned char)*the_command );
-#endif
- fdomain_16x0_reset();
- return DID_RESET << 16;
- }
-
- if (have_data_in) {
- while ((data_count = inw( FIFO_Data_Count_port )) != 0) {
- if (data_count == 1) {
- *in_buf_pt++ = inb( Read_FIFO_port );
- } else {
- data_count >>= 1; /* Number of words */
- insw( in_buf_pt, data_count, Read_FIFO_port );
- in_buf_pt += 2 * data_count;
- }
- }
- }
-
- fdomain_make_bus_idle();
-
-#if EVERY_ACCESS
- printk( "Retcode = %x\n",
- (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
-#endif
-#if ERRORS_ONLY
- if (*the_command == REQUEST_SENSE && !Status) {
- if ((unsigned char)(*((char *)buff + 2)) & 0x0f) {
- printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
- (unsigned char)(*((char *)buff + 2)) & 0x0f,
- (unsigned char)(*((char *)buff + 12)) );
- }
- }
-#endif
-
- return (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16);
+ panic( "Future Domain: must use interrupt-driven driver\n" );
+ return -1;
}
-int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
+void print_info( Scsi_Cmnd *SCpnt )
{
-
-#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
- printk( "SCSI (Future Domain): Abort " );
-#endif
-
-#if DEBUG_ABORT
+ unsigned int imr;
+ unsigned int irr;
+ unsigned int isr;
+
print_banner();
- switch (current_SC->SCp.phase) {
- case non_queueing: printk( "nonqueueing " ); break;
+ switch (SCpnt->SCp.phase) {
case in_arbitration: printk( "arbitration " ); break;
case in_selection: printk( "selection " ); break;
case in_other: printk( "other " ); break;
default: printk( "unknown " ); break;
}
- printk( "phase = %d, target = %d cmnd = 0x%02x pieces = %d size = %u\n",
- current_SC->SCp.phase,
- current_SC->target,
- *(unsigned char *)current_SC->cmnd,
- current_SC->use_sg,
- current_SC->request_bufflen );
+ printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+ SCpnt->SCp.phase,
+ SCpnt->target,
+ *(unsigned char *)SCpnt->cmnd,
+ SCpnt->use_sg,
+ SCpnt->request_bufflen );
+ printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
+ SCpnt->SCp.sent_command,
+ SCpnt->SCp.have_data_in,
+ SCpnt->timeout );
#if DEBUG_RACE
printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
#endif
- printk( "IMR = 0x%02x%02x\n", inb( 0x0a1 ), inb( 0x21 ) );
+
+ imr = (inb( 0x0a1 ) << 8) + inb( 0x21 );
outb( 0x0a, 0xa0 );
- printk( "IRR = 0x%02x", inb( 0xa0 ) );
+ irr = inb( 0xa0 ) << 8;
outb( 0x0a, 0x20 );
- printk( "%02x\n", inb( 0x20 ) );
+ irr += inb( 0x20 );
outb( 0x0b, 0xa0 );
- printk( "ISR = 0x%02x", inb( 0xa0 ) );
+ isr = inb( 0xa0 ) << 8;
outb( 0x0b, 0x20 );
- printk( "%02x\n", inb( 0x20 ) );
- printk( "SCSI Status = %x\n", inb( SCSI_Status_port ) );
- printk( "TMC Status = %x\n", inb( TMC_Status_port ) );
- printk( "Interrupt Mask = %x\n", inb( Interrupt_Mask_port ) );
- printk( "Option Select = %x\n", inb( port_base + Option_Select ) );
+ isr += inb( 0x20 );
+
+ printk( "IMR = 0x%04x", imr );
+ if (imr & (1 << interrupt_level))
+ printk( " (masked)" );
+ printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr );
+
+ printk( "SCSI Status = 0x%02x\n", inb( SCSI_Status_port ) );
+ printk( "TMC Status = 0x%02x", inb( TMC_Status_port ) );
+ if (inb( TMC_Status_port & 1)) printk( " (interrupt)" );
+ printk( "\n" );
+ printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) );
+ if (inb( Interrupt_Status_port ) & 0x08) printk( " (enabled)" );
+ printk( "\n" );
if (chip == tmc18c50) {
- printk( "FIFO Status = %x\n", inb( port_base + FIFO_Status ) );
- printk( "Int. Condition = %x\n", inb( port_base + Interrupt_Cond ) );
- printk( "Configuration = %x\n", inb( port_base + Configuration ) );
+ printk( "FIFO Status = 0x%02x\n", inb( port_base + FIFO_Status ) );
+ printk( "Int. Condition = 0x%02x\n",
+ inb( port_base + Interrupt_Cond ) );
}
-#else
+ printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) );
+ if (chip == tmc18c50)
+ printk( "Configuration 2 = 0x%02x\n",
+ inb( port_base + Configuration2 ) );
+}
+
+int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
+{
+
+#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
+ printk( "Future Domain: Abort " );
+#endif
+
cli();
if (!in_command) {
#if EVERY_ACCESS || ERRORS_ONLY
@@ -1363,6 +1393,12 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
#endif
}
+#if DEBUG_ABORT
+ print_info( SCpnt );
+#endif
+
+ fdomain_make_bus_idle();
+
current_SC->SCp.phase |= aborted;
current_SC->result = code ? code : DID_ABORT;
@@ -1371,25 +1407,35 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
/* Aborts are not done well. . . */
my_done( code << 16 );
-#endif
+
return 0;
}
int fdomain_16x0_reset( void )
{
+#if DEBUG_RESET
+ static int called_once = 0;
+#endif
+
#if ERRORS_ONLY
printk( "Future Domain: SCSI Bus Reset\n" );
#endif
+
+#if DEBUG_RESET
+ if (called_once) print_info( current_SC );
+ called_once = 1;
+#endif
+
outb( 1, SCSI_Cntl_port );
do_pause( 2 );
outb( 0, SCSI_Cntl_port );
do_pause( 115 );
- outb( 0, Data_Mode_Cntl_port );
+ outb( 0, SCSI_Mode_Cntl_port );
outb( PARITY_MASK, TMC_Cntl_port );
return 0;
}
-int fdomain_16x0_biosparam( int size, int dev, int *info )
+int fdomain_16x0_biosparam( int size, int dev, int *info_array )
{
int drive;
struct drive_info {
@@ -1400,6 +1446,9 @@ int fdomain_16x0_biosparam( int size, int dev, int *info )
/* NOTES:
The RAM area starts at 0x1f00 from the bios_base address.
+
+ For BIOS Version 2.0:
+
The drive parameter table seems to start at 0x1f30.
The first byte's purpose is not known.
Next is the cylinder, head, and sector information.
@@ -1420,12 +1469,34 @@ int fdomain_16x0_biosparam( int size, int dev, int *info )
The table at 0x1fcc are I/O ports addresses for the various
operations. I calculate these by hand in this driver code.
+
+ For BIOS Version 3.2:
+
+ The drive parameter table starts at 0x1f70. Each entry is
+ 0x0a bytes long. Heads are one less than we need to report.
*/
drive = MINOR(dev) / 16;
- i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
- info[0] = i->heads;
- info[1] = i->sectors;
- info[2] = i->cylinders;
+
+ if (bios_major == 2) {
+ i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
+ info_array[0] = i->heads;
+ info_array[1] = i->sectors;
+ info_array[2] = i->cylinders;
+ } else if (bios_major == 3) { /* Appears to be the same for 3.0 and 3.2 */
+ i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 );
+ info_array[0] = i->heads + 1;
+ info_array[1] = i->sectors;
+ info_array[2] = i->cylinders;
+ } else {
+ /* How the data is stored in the RAM area is very BIOS-dependent.
+ Therefore, return nothing if we are not *SURE* of the information. */
+
+ info_array[0]
+ = info_array[1]
+ = info_array[2]
+ = 0;
+ }
+
return 0;
}
diff --git a/kernel/blk_drv/scsi/fdomain.h b/kernel/blk_drv/scsi/fdomain.h
index 7c478a2..abc8a4d 100644
--- a/kernel/blk_drv/scsi/fdomain.h
+++ b/kernel/blk_drv/scsi/fdomain.h
@@ -1,32 +1,42 @@
-/* fdomain.h -- Header for Future Domain TMC-1660/TMC-1680 driver
- * Created: Sun May 3 18:47:33 1992
- * Revised: Sun Jan 10 00:54:29 1993 by root
+/* fdomain.h -- Header for Future Domain TMC-16x0 driver
+ * Created: Sun May 3 18:47:33 1992 by faith@cs.unc.edu
+ * Revised: Sun Jun 6 11:56:40 1993 by faith@cs.unc.edu
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993 Rickard E. Faith
- * This program comes with ABSOLUTELY NO WARRANTY.
*
- * $Log$
+ * $Id: fdomain.h,v 3.7 1993/06/06 15:42:16 root Exp $
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+
*/
#ifndef _FDOMAIN_H
#define _FDOMAIN_H
-int fdomain_16x0_detect( int );
-int fdomain_16x0_command( Scsi_Cmnd * );
-int fdomain_16x0_abort( Scsi_Cmnd *, int );
+int fdomain_16x0_detect( int );
+int fdomain_16x0_command( Scsi_Cmnd * );
+int fdomain_16x0_abort( Scsi_Cmnd *, int );
const char *fdomain_16x0_info( void );
-int fdomain_16x0_reset( void );
-int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
-int fdomain_16x0_biosparam( int, int, int * );
+int fdomain_16x0_reset( void );
+int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+int fdomain_16x0_biosparam( int, int, int * );
-#define FDOMAIN_16X0 { "Future Domain TMC-16x0", \
- fdomain_16x0_detect, \
- fdomain_16x0_info, \
- fdomain_16x0_command, \
- fdomain_16x0_queue, \
- fdomain_16x0_abort, \
- fdomain_16x0_reset, \
- NULL, \
- fdomain_16x0_biosparam, \
- 1, 6, 64 /* SG_NONE */, 1 ,0, 0}
+#define FDOMAIN_16X0 { "Future Domain TMC-16x0", \
+ fdomain_16x0_detect, \
+ fdomain_16x0_info, \
+ fdomain_16x0_command, \
+ fdomain_16x0_queue, \
+ fdomain_16x0_abort, \
+ fdomain_16x0_reset, \
+ NULL, \
+ fdomain_16x0_biosparam, \
+ 1, 6, 64 /* SG_NONE */, 1 ,0, 0 }
#endif
diff --git a/kernel/blk_drv/scsi/scsi.c b/kernel/blk_drv/scsi/scsi.c
index 16fd727..0fcc4ac 100644
--- a/kernel/blk_drv/scsi/scsi.c
+++ b/kernel/blk_drv/scsi/scsi.c
@@ -111,18 +111,18 @@ static struct blist blacklist[] =
{"DENON","DRD-25X","V"}, /* A cdrom that locks up when probed at lun != 0 */
{NULL, NULL, NULL}};
-static int blacklisted(char * response_data){
+static int blacklisted(unsigned char * response_data){
int i = 0;
- char * pnt;
+ unsigned char * pnt;
for(i=0; 1; i++){
if(blacklist[i].vendor == NULL) return 0;
pnt = &response_data[8];
while(*pnt && *pnt == ' ') pnt++;
- if(strncmp(blacklist[i].vendor, pnt,
+ if(memcmp(blacklist[i].vendor, pnt,
strlen(blacklist[i].vendor))) continue;
pnt = &response_data[16];
while(*pnt && *pnt == ' ') pnt++;
- if(strncmp(blacklist[i].model, pnt,
+ if(memcmp(blacklist[i].model, pnt,
strlen(blacklist[i].model))) continue;
return 1;
};
@@ -193,6 +193,7 @@ static void scan_scsis (void)
SCmd.request.dev = 0xffff; /* Mark not busy */
SCmd.use_sg = 0;
+ SCmd.old_use_sg = 0;
SCmd.transfersize = 0;
SCmd.underflow = 0;
@@ -312,9 +313,9 @@ static void scan_scsis (void)
/* These devices need this "key" to unlock the device
so we can use it */
- if(strncmp("INSITE", &scsi_result[8], 6) == 0 &&
- (strncmp("Floptical F*8I", &scsi_result[16], 16) == 0
- ||strncmp("I325VM", &scsi_result[16], 6) == 0)) {
+ if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
+ (memcmp("Floptical F*8I", &scsi_result[16], 16) == 0
+ || memcmp("I325VM", &scsi_result[16], 6) == 0)) {
printk("Unlocked floptical drive.\n");
scsi_devices[NR_SCSI_DEVICES].lockable = 0;
scsi_cmd[0] = MODE_SENSE;
@@ -447,6 +448,7 @@ Scsi_Cmnd * request_queueable (struct request * req, int index)
};
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
+ SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0;
SCpnt->underflow = 0;
return SCpnt;
@@ -520,6 +522,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
};
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
+ SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0; /* No default transfer size */
SCpnt->underflow = 0; /* Do not flag underflow conditions */
return SCpnt;
@@ -590,8 +593,6 @@ update_timeout(SCpnt, SCpnt->timeout_per_command);
static void scsi_request_sense (Scsi_Cmnd * SCpnt)
{
- int old_use_sg;
-
cli();
SCpnt->flags |= WAS_SENSE;
update_timeout(SCpnt, SENSE_TIMEOUT);
@@ -606,10 +607,9 @@ static void scsi_request_sense (Scsi_Cmnd * SCpnt)
SCpnt->request_buffer = &SCpnt->sense_buffer;
SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
- old_use_sg = SCpnt->use_sg;
SCpnt->use_sg = 0;
internal_cmnd (SCpnt);
- SCpnt->use_sg = old_use_sg;
+ SCpnt->use_sg = SCpnt->old_use_sg;
}
@@ -695,6 +695,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 10);
SCpnt->request_buffer = buffer;
SCpnt->request_bufflen = bufflen;
+ SCpnt->old_use_sg = SCpnt->use_sg;
/* Start the timer ticking. */
@@ -883,7 +884,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
exit = DRIVER_SENSE | SUGGEST_ABORT;
break;
default:
- printk ("Internal error %s %s \n", __FILE__,
+ printk ("Internal error %s %d \n", __FILE__,
__LINE__);
}
}
@@ -933,7 +934,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
break;
#endif
default:
- printk ("Internal error %s %s \n"
+ printk ("Internal error %s %d \n"
"status byte = %d \n", __FILE__,
__LINE__, status_byte(result));
@@ -1036,6 +1037,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
sizeof(SCpnt->data_cmnd));
SCpnt->request_buffer = SCpnt->buffer;
SCpnt->request_bufflen = SCpnt->bufflen;
+ SCpnt->use_sg = SCpnt->old_use_sg;
internal_cmnd (SCpnt);
};
break;
@@ -1051,6 +1053,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
host_busy[host]--; /* Indicate that we are free */
wake_up(&host_wait[host]);
SCpnt->result = result | ((exit & 0xff) << 24);
+ SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->done (SCpnt);
}
@@ -1204,12 +1207,6 @@ static void scsi_main_timeout(void)
}
/*
- These are used to keep track of things.
-*/
-
-static int time_start, time_elapsed;
-
-/*
The strategy is to cause the timer code to call scsi_times_out()
when the soonest timeout is pending.
The arguments are used when we are queueing a new command, because
@@ -1282,7 +1279,7 @@ unsigned int dma_free_sectors = 0;
unsigned int need_isa_buffer = 0;
static unsigned char * dma_malloc_buffer = NULL;
-char *scsi_malloc(unsigned int len)
+void *scsi_malloc(unsigned int len)
{
unsigned int nbits, mask;
int i, j;
@@ -1302,14 +1299,14 @@ char *scsi_malloc(unsigned int len)
#ifdef DEBUG
printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9));
#endif
- return (void*) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9));
+ return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9));
};
};
sti();
return NULL; /* Nope. No more */
}
-int scsi_free(char *obj, unsigned int len)
+int scsi_free(void *obj, unsigned int len)
{
int offset;
int page, sector, nbits, mask;
@@ -1399,8 +1396,10 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
SCpnt->index = i;
SCpnt->request.dev = -1; /* Mark not busy */
SCpnt->use_sg = 0;
+ SCpnt->old_use_sg = 0;
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
+ SCpnt->host_scribble = NULL;
host = scsi_devices[i].host_no;
if(host_queue[host])
host_queue[host]->prev = SCpnt;
@@ -1429,7 +1428,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
if(scsi_hosts[host].unchecked_isa_dma &&
memory_end > ISA_DMA_THRESHOLD &&
scsi_devices[i].type != TYPE_TAPE) {
- dma_sectors += (BLOCK_SIZE >> 9) * scsi_hosts[host].sg_tablesize *
+ dma_sectors += (PAGE_SIZE >> 9) * scsi_hosts[host].sg_tablesize *
scsi_hosts[host].cmd_per_lun;
need_isa_buffer++;
};
@@ -1445,7 +1444,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
if(memory_start & 1) memory_start++; /* Some host adapters require
buffers to be word aligned */
- dma_malloc_buffer = (char *) memory_start;
+ dma_malloc_buffer = (unsigned char *) memory_start;
memory_start += dma_sectors << 9;
memory_start = sd_init(memory_start, memory_end); /* init scsi disks */
diff --git a/kernel/blk_drv/scsi/scsi.h b/kernel/blk_drv/scsi/scsi.h
index cc0a59f..c19c3e7 100644
--- a/kernel/blk_drv/scsi/scsi.h
+++ b/kernel/blk_drv/scsi/scsi.h
@@ -316,8 +316,8 @@ struct scatterlist {
#define ISA_DMA_THRESHOLD (0x00ffffff)
-char * scsi_malloc(unsigned int);
-int scsi_free(char *, unsigned int);
+void * scsi_malloc(unsigned int);
+int scsi_free(void *, unsigned int);
extern unsigned int dma_free_sectors; /* How much room do we have left */
extern unsigned int need_isa_buffer; /* True if some devices need indirection
buffers */
@@ -352,6 +352,8 @@ typedef struct scsi_cmnd {
/* These elements define the operation we ultimately want to perform */
unsigned char data_cmnd[12];
+ unsigned short old_use_sg; /* We save use_sg here when requesting
+ sense info */
unsigned short use_sg; /* Number of pieces of scatter-gather */
unsigned short sglist_len; /* size of malloc'd scatter-gather list */
unsigned bufflen; /* Size of data buffer */
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/kernel/blk_drv/scsi/scsi_ioctl.c
index 9a7f423..1ba190e 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.c
+++ b/kernel/blk_drv/scsi/scsi_ioctl.c
@@ -32,7 +32,7 @@ static int ioctl_probe(int dev, void *buffer)
const char * string;
if ((temp = scsi_hosts[dev].present) && buffer) {
- len = get_fs_long ((int *) buffer);
+ len = get_fs_long ((unsigned long *) buffer);
string = scsi_hosts[dev].info();
slen = strlen(string);
if (len > slen)
@@ -155,8 +155,8 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
if (!buffer)
return -EINVAL;
- inlen = get_fs_long((int *) buffer);
- outlen = get_fs_long( ((int *) buffer) + 1);
+ inlen = get_fs_long((unsigned long *) buffer);
+ outlen = get_fs_long( ((unsigned long *) buffer) + 1);
cmd_in = (char *) ( ((int *)buffer) + 2);
opcode = get_fs_byte(cmd_in);
@@ -165,7 +165,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
if(needed){
needed = (needed + 511) & ~511;
if (needed > MAX_BUF) needed = MAX_BUF;
- buf = scsi_malloc(needed);
+ buf = (char *) scsi_malloc(needed);
if (!buf) return -ENOMEM;
} else
buf = NULL;
@@ -235,7 +235,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
case SCSI_IOCTL_GET_IDLUN:
verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
put_fs_long(dev->id + (dev->lun << 8) +
- (dev->host_no << 16), (long *) arg);
+ (dev->host_no << 16), (unsigned long *) arg);
return 0;
case SCSI_IOCTL_PROBE_HOST:
return ioctl_probe(dev->host_no, arg);
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.h b/kernel/blk_drv/scsi/scsi_ioctl.h
index c25ed86..c88e7c4 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.h
+++ b/kernel/blk_drv/scsi/scsi_ioctl.h
@@ -13,6 +13,8 @@
#define SCSI_REMOVAL_PREVENT 1
#define SCSI_REMOVAL_ALLOW 0
+extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+
#endif
diff --git a/kernel/blk_drv/scsi/sd.c b/kernel/blk_drv/scsi/sd.c
index afdb6e8..1ffd3c4 100644
--- a/kernel/blk_drv/scsi/sd.c
+++ b/kernel/blk_drv/scsi/sd.c
@@ -46,6 +46,7 @@ int NR_SD=0;
int MAX_SD=0;
Scsi_Disk * rscsi_disks;
static int * sd_sizes;
+static int * sd_blocksizes;
/* used to re-read partitions. */
extern void resetup_one_dev(struct gendisk *, unsigned int);
@@ -94,14 +95,7 @@ static void sd_release(struct inode * inode, struct file * file)
};
}
-static struct gendisk sd_gendisk;
-
-static void sd_geninit (void) {
- int i;
- for (i = 0; i < NR_SD; ++i)
- sd[i << 4].nr_sects = rscsi_disks[i].capacity;
- sd_gendisk.nr_real = NR_SD;
-}
+static void sd_geninit(void);
static struct file_operations sd_fops = {
NULL, /* lseek - default */
@@ -130,6 +124,13 @@ static struct gendisk sd_gendisk = {
NULL /* next */
};
+static void sd_geninit (void)
+{
+ for (int i = 0; i < NR_SD; ++i)
+ sd[i << 4].nr_sects = rscsi_disks[i].capacity;
+ sd_gendisk.nr_real = NR_SD;
+}
+
/*
rw_intr is the interrupt routine for the device driver. It will
be notified on the end of a SCSI read / write, and
@@ -393,8 +394,10 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
repeat:
- if(SCpnt->request.dev <= 0)
- return do_sd_request();
+ if(SCpnt->request.dev <= 0) {
+ do_sd_request();
+ return;
+ }
dev = MINOR(SCpnt->request.dev);
block = SCpnt->request.sector;
@@ -520,7 +523,7 @@ repeat:
if(dma_free_sectors < (bh->b_size >> 9) + 5) {
sgpnt[count].address = NULL;
} else {
- sgpnt[count].address = scsi_malloc(sgpnt[count].length);
+ sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
};
/* If we start running low on DMA buffers, we abort the scatter-gather
operation, and free all of the memory we have allocated. We want to
@@ -529,7 +532,7 @@ repeat:
if(sgpnt[count].address == NULL){ /* Out of dma memory */
printk("Warning: Running low on SCSI DMA buffers");
/* Try switching back to a non scatter-gather operation. */
- while(--count){
+ while(--count >= 0){
if(sgpnt[count].alt_address)
scsi_free(sgpnt[count].address, sgpnt[count].length);
};
@@ -553,7 +556,7 @@ repeat:
if(SCpnt->use_sg == 0){
if (((int) buff) + (this_count << 9) > ISA_DMA_THRESHOLD &&
(scsi_hosts[SCpnt->host].unchecked_isa_dma)) {
- buff = scsi_malloc(this_count << 9);
+ buff = (char *) scsi_malloc(this_count << 9);
if(buff == NULL) panic("Ran out of DMA buffers.");
if (SCpnt->request.cmd == WRITE)
memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
@@ -814,6 +817,11 @@ unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
memory_start += (MAX_SD << 4) * sizeof(int);
memset(sd_sizes, 0, (MAX_SD << 4) * sizeof(int));
+ sd_blocksizes = (int *) memory_start;
+ memory_start += (MAX_SD << 4) * sizeof(int);
+ for(i=0;i<(MAX_SD << 4);i++) sd_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = sd_blocksizes;
+
sd = (struct hd_struct *) memory_start;
memory_start += (MAX_SD << 4) * sizeof(struct hd_struct);
diff --git a/kernel/blk_drv/scsi/sd_ioctl.c b/kernel/blk_drv/scsi/sd_ioctl.c
index 4bb25e2..668ca79 100644
--- a/kernel/blk_drv/scsi/sd_ioctl.c
+++ b/kernel/blk_drv/scsi/sd_ioctl.c
@@ -8,10 +8,10 @@
#include "../blk.h"
#include "scsi.h"
+#include "scsi_ioctl.h"
#include "hosts.h"
#include "sd.h"
-extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern int revalidate_scsidisk(int, int);
int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
@@ -19,7 +19,7 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
int dev = inode->i_rdev;
int host, error;
int diskinfo[4];
- struct hd_geometry *loc = (void *) arg;
+ struct hd_geometry *loc = (struct hd_geometry *) arg;
switch (cmd) {
case HDIO_REQ: /* Return BIOS disk parameters */
diff --git a/kernel/blk_drv/scsi/seagate.c b/kernel/blk_drv/scsi/seagate.c
index c5f19e4..3728360 100644
--- a/kernel/blk_drv/scsi/seagate.c
+++ b/kernel/blk_drv/scsi/seagate.c
@@ -89,15 +89,17 @@ static unsigned char controller_type; /* set to SEAGATE for ST0x boards or FD fo
#define DATA (*(volatile unsigned char *) st0x_dr)
#ifndef OVERRIDE
-static const char * seagate_bases[] = {(char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, (char *) 0xce000, (char *) 0xce000,
- (char *) 0xdc000, (char *) 0xde000};
-typedef struct
- {
+static const char * seagate_bases[] = {
+ (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000,
+ (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000
+};
+
+typedef struct {
char *signature ;
unsigned offset;
unsigned length;
unsigned char type;
- } Signature;
+} Signature;
static const Signature signatures[] = {
#ifdef CONFIG_SCSI_SEAGATE
@@ -391,7 +393,7 @@ int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
current_target = SCpnt->target;
current_lun = SCpnt->lun;
(const void *) current_cmnd = SCpnt->cmnd;
- current_data = SCpnt->request_buffer;
+ current_data = (unsigned char *) SCpnt->request_buffer;
current_bufflen = SCpnt->request_bufflen;
SCint = SCpnt;
if(recursion_depth) {
@@ -900,7 +902,7 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
movb %%al, (%%edi);
"
#endif
-" loop 1b;" ::
+" loop 1b;" : :
/* input */
"r" (st0x_dr), "S" (data), "c" (SCint->transfersize) :
/* clobbered */
@@ -1027,7 +1029,7 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
"
#endif
-" loop 1b;" ::
+" loop 1b;" : :
/* input */
"r" (st0x_dr), "D" (data), "c" (SCint->transfersize) :
/* clobbered */
@@ -1121,8 +1123,10 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
case REQ_CMDOUT :
while (((status_read = STATUS) & STAT_BSY) &&
((status_read & REQ_MASK) == REQ_CMDOUT))
- if (status_read & STAT_REQ)
- DATA = *(unsigned char *) cmnd ++;
+ if (status_read & STAT_REQ) {
+ DATA = *(unsigned char *) cmnd;
+ cmnd = 1+(unsigned char *) cmnd;
+ }
break;
case REQ_STATIN :
@@ -1395,9 +1399,7 @@ int seagate_st0x_reset (void)
#include "sd.h"
#include "scsi_ioctl.h"
-extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
-
-int seagate_st0x_biosparam(int size, int dev, int* info) {
+int seagate_st0x_biosparam(int size, int dev, int* ip) {
unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page;
int *sizes, result, formatted_sectors, total_sectors;
int cylinders, heads, sectors;
@@ -1493,9 +1495,9 @@ printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %
if ((cylinders > 1024) || (sectors > 64))
result = -1;
else {
- info[0] = heads;
- info[1] = sectors;
- info[2] = cylinders;
+ ip[0] = heads;
+ ip[1] = sectors;
+ ip[2] = cylinders;
}
/*
diff --git a/kernel/blk_drv/scsi/seagate.h b/kernel/blk_drv/scsi/seagate.h
index b27e769..71287c4 100644
--- a/kernel/blk_drv/scsi/seagate.h
+++ b/kernel/blk_drv/scsi/seagate.h
@@ -25,11 +25,19 @@ int seagate_st0x_reset(void);
#define NULL 0
#endif
+#ifdef CONFIG_BLK_DEV_SD
#define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \
seagate_st0x_info, seagate_st0x_command, \
seagate_st0x_queue_command, seagate_st0x_abort, \
- seagate_st0x_reset, NULL, seagate_st0x_biosparam, \
+ seagate_st0x_reset, NULL, seagate_st0x_biosparam, \
1, 7, SG_ALL, 1, 0, 0}
+#else
+#define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \
+ seagate_st0x_info, seagate_st0x_command, \
+ seagate_st0x_queue_command, seagate_st0x_abort, \
+ seagate_st0x_reset, NULL, NULL, \
+ 1, 7, SG_ALL, 1, 0, 0}
+#endif /* CONFIG_BLK_DEV_SD */
#endif
diff --git a/kernel/blk_drv/scsi/sr.c b/kernel/blk_drv/scsi/sr.c
index 44d6bfc..c745d83 100644
--- a/kernel/blk_drv/scsi/sr.c
+++ b/kernel/blk_drv/scsi/sr.c
@@ -36,6 +36,8 @@ int MAX_SR=0;
Scsi_CD * scsi_CDs;
static int * sr_sizes;
+static int * sr_blocksizes;
+
static int sr_open(struct inode *, struct file *);
static void get_sectorsize(int);
@@ -352,8 +354,10 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
tries = 2;
repeat:
- if(SCpnt->request.dev <= 0)
- return do_sr_request();
+ if(SCpnt->request.dev <= 0) {
+ do_sr_request();
+ return;
+ }
dev = MINOR(SCpnt->request.dev);
block = SCpnt->request.sector;
@@ -463,12 +467,12 @@ are any multiple of 512 bytes long. */
printk("Warning - running *really* short on DMA buffers\n");
SCpnt->use_sg = 0; /* No memory left - bail out */
} else {
- buffer = (char *) sgpnt;
+ buffer = (unsigned char *) sgpnt;
count = 0;
bh = SCpnt->request.bh;
if(SCpnt->request.sector % 4) {
sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
- sgpnt[count].address = scsi_malloc(sgpnt[count].length);
+ sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete
if needed */
@@ -481,7 +485,7 @@ are any multiple of 512 bytes long. */
sgpnt[count].length = bh->b_size;
sgpnt[count].alt_address = NULL;
} else {
- sgpnt[count].address = scsi_malloc(end_rec);
+ sgpnt[count].address = (char *) scsi_malloc(end_rec);
if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
sgpnt[count].length = end_rec;
sgpnt[count].alt_address = sgpnt[count].address;
@@ -497,7 +501,7 @@ are any multiple of 512 bytes long. */
if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
sgpnt[count].address = NULL;
} else {
- sgpnt[count].address = scsi_malloc(sgpnt[count].length);
+ sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
};
/* If we start running low on DMA buffers, we abort the scatter-gather
operation, and free all of the memory we have allocated. We want to
@@ -506,7 +510,7 @@ are any multiple of 512 bytes long. */
if(sgpnt[count].address == NULL){ /* Out of dma memory */
printk("Warning: Running low on SCSI DMA buffers");
/* Try switching back to a non scatter-gather operation. */
- while(--count){
+ while(--count >= 0){
if(sgpnt[count].alt_address)
scsi_free(sgpnt[count].address, sgpnt[count].length);
};
@@ -542,19 +546,19 @@ are any multiple of 512 bytes long. */
{
this_count = ((this_count > 4 - start) ?
(4 - start) : (this_count));
- buffer = scsi_malloc(2048);
+ buffer = (unsigned char *) scsi_malloc(2048);
}
else if (this_count < 4)
{
- buffer = scsi_malloc(2048);
+ buffer = (unsigned char *) scsi_malloc(2048);
}
else
{
this_count -= this_count % 4;
- buffer = SCpnt->request.buffer;
+ buffer = (unsigned char *) SCpnt->request.buffer;
if (((int) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &
(scsi_hosts[SCpnt->host].unchecked_isa_dma))
- buffer = scsi_malloc(this_count << 9);
+ buffer = (unsigned char *) scsi_malloc(this_count << 9);
}
};
@@ -710,6 +714,11 @@ unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
memory_start += MAX_SR * sizeof(int);
memset(sr_sizes, 0, MAX_SR * sizeof(int));
+ sr_blocksizes = (int *) memory_start;
+ memory_start += MAX_SR * sizeof(int);
+ for(i=0;i<MAX_SR;i++) sr_blocksizes[i] = 2048;
+ blksize_size[MAJOR_NR] = sr_blocksizes;
+
for (i = 0; i < NR_SR; ++i)
{
get_sectorsize(i);
diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c
index 9815f5b..c8e226f 100644
--- a/kernel/blk_drv/scsi/st.c
+++ b/kernel/blk_drv/scsi/st.c
@@ -47,6 +47,7 @@
#define MAJOR_NR 9
#include "../blk.h"
#include "scsi.h"
+#include "scsi_ioctl.h"
#include "st.h"
#define MAX_RETRIES 5
@@ -144,7 +145,7 @@ static void decode_sns(int dev, char *sense_buffer)
/* Convert the result to success code */
-static int st_chk_result(int dev, int result, char *sense)
+static int st_chk_result(int dev, int result, unsigned char *sense)
{
if (!result)
return 0;
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
index 6fb5aed..35fb4e8 100644
--- a/kernel/blk_drv/scsi/ultrastor.c
+++ b/kernel/blk_drv/scsi/ultrastor.c
@@ -123,8 +123,8 @@ struct mscp {
/* The 14F uses an array of unaligned 4-byte ints for its scatter/gather list. */
typedef struct {
- Longword address;
- Longword num_bytes;
+ unsigned long address;
+ unsigned long num_bytes;
} ultrastor_sg_list;
/* This is our semaphore for mscp block availability */
@@ -341,15 +341,15 @@ static inline void build_sg_list(Scsi_Cmnd *SCpnt)
int i;
sl = (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->host_scribble = scsi_malloc(512);
+ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
if (SCpnt->host_scribble == NULL)
/* Not sure what to do here; just panic for now */
panic("US14F: Can't allocate DMA buffer for scatter-gather list!\n");
/* Save ourselves some casts; can eliminate when we don't have to look at it anymore! */
sglist = (ultrastor_sg_list *) SCpnt->host_scribble;
for (i = 0; i < SCpnt->use_sg; i++) {
- sglist[i].address = *(Longword *)&(sl[i].address);
- sglist[i].num_bytes = *(Longword *)&(sl[i].length);
+ sglist[i].address = sl[i].address;
+ sglist[i].num_bytes = sl[i].length;
transfer_length += sl[i].length;
}
mscp.number_of_sg_list = (char) SCpnt->use_sg;
@@ -491,15 +491,15 @@ int ultrastor_reset(void)
return 0;
}
-int ultrastor_biosparam(int size, int dev, int *info)
+int ultrastor_biosparam(int size, int dev, int *ip)
{
unsigned int s = config.heads * config.sectors;
- info[0] = config.heads;
- info[1] = config.sectors;
- info[2] = (size + (s - 1)) / s;
-/* if (info[2] > 1024)
- info[2] = 1024; */
+ ip[0] = config.heads;
+ ip[1] = config.sectors;
+ ip[2] = (size + (s - 1)) / s;
+/* if (ip[2] > 1024)
+ ip[2] = 1024; */
return 0;
}
diff --git a/kernel/blk_drv/scsi/wd7000.c b/kernel/blk_drv/scsi/wd7000.c
index baf8ced..88edabb 100644
--- a/kernel/blk_drv/scsi/wd7000.c
+++ b/kernel/blk_drv/scsi/wd7000.c
@@ -388,7 +388,7 @@ int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
if (SCpnt->use_sg > WD7000_SG)
panic("WD7000: requesting too many scatterblocks\n");
#endif
- SCpnt->host_scribble = scsi_malloc(WD7000_SCRIBBLE);
+ SCpnt->host_scribble = (unsigned char *) scsi_malloc(WD7000_SCRIBBLE);
sgb = (Sgb *) SCpnt->host_scribble;
if (sgb == NULL)
panic("wd7000_queuecommand: scsi_malloc() failed.\n");
@@ -597,16 +597,16 @@ int wd7000_reset(void)
}
-int wd7000_biosparam(int size, int dev, int* info)
+int wd7000_biosparam(int size, int dev, int* ip)
/*
* This is borrowed directly from aha1542.c, but my disks are organized
* this way, so I think it will work OK.
*/
{
- info[0] = 64;
- info[1] = 32;
- info[2] = (size + 2047) >> 11;
-/* if (info[2] >= 1024) info[2] = 1024; */
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = (size + 2047) >> 11;
+/* if (ip[2] >= 1024) ip[2] = 1024; */
return 0;
}
diff --git a/kernel/blk_drv/xd.c b/kernel/blk_drv/xd.c
index 1af6f82..be1105f 100644
--- a/kernel/blk_drv/xd.c
+++ b/kernel/blk_drv/xd.c
@@ -67,13 +67,13 @@ static u_char *xd_bases[] = { (u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0
static struct hd_struct xd[XD_MAXDRIVES << 6];
static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 };
+static int xd_blocksizes[XD_MAXDRIVES << 6];
static struct gendisk xd_gendisk = { MAJOR_NR,"xd",6,1 << 6,XD_MAXDRIVES,xd_geninit,xd,xd_sizes,0,(void *) xd_info,NULL };
static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,xd_ioctl,NULL,xd_open,xd_release,block_fsync };
-static struct wait_queue *xd_wait_exclusive = NULL,*xd_wait_int = NULL,*xd_wait_open = NULL;
+static struct wait_queue *xd_wait_int = NULL,*xd_wait_open = NULL;
static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
-static u_char xd_busy = 0,xd_drives = 0;
-static u_char xd_irq,xd_dma,xd_maxsectors;
+static u_char xd_drives = 0,xd_irq,xd_dma,xd_maxsectors;
static u_short xd_iobase;
/* xd_init: grab the IRQ and DMA channel and initialise the drives */
@@ -120,7 +120,7 @@ static u_char xd_detect (u_char *controller,u_char **address)
for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
- if (!memcmp((u_char *) (xd_bases[i] + xd_sigs[j].offset),xd_sigs[j].string,strlen(xd_sigs[j].string))) {
+ if (!memcmp(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
*controller = j;
*address = xd_bases[i];
found++;
@@ -144,6 +144,9 @@ static void xd_geninit (void)
}
xd_gendisk.nr_real = xd_drives;
+
+ for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = xd_blocksizes;
}
/* xd_open: open a device */
@@ -234,8 +237,6 @@ static void xd_release (struct inode *inode, struct file *file)
}
/* xd_reread_partitions: rereads the partition table from a drive */
-
-/* xd_reread_partitions: rereads the partition table from a drive */
static int xd_reread_partitions(int dev)
{
int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
@@ -262,7 +263,7 @@ static int xd_reread_partitions(int dev)
}
/* xd_readwrite: handle a read/write request */
-static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count)
+static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count)
{
u_char cmdblk[6],sense[4];
u_short track,cylinder;
@@ -285,15 +286,11 @@ static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int bloc
printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
#endif DEBUG_READWRITE
- if (xd_busy) /* get exclusive access to the controller */
- sleep_on(&xd_wait_exclusive);
- xd_busy = 1;
-
- mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,buffer,temp * 0x200);
+ mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
- switch (xd_command(cmdblk,mode,buffer,buffer,sense,XD_TIMEOUT)) {
- case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); xd_busy = 0; wake_up(&xd_wait_exclusive); return (0);
+ switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) {
+ case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); return (0);
case 2: switch ((sense[0] & 0x30) >> 4) {
case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
@@ -304,12 +301,9 @@ static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int bloc
printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
else
printk(" - no valid disk address\n");
- xd_busy = 0; wake_up(&xd_wait_exclusive);
return (0);
}
count -= temp, buffer += temp * 0x200, block += temp;
-
- xd_busy = 0; wake_up(&xd_wait_exclusive);
}
return (1);
}
diff --git a/kernel/chr_drv/Makefile b/kernel/chr_drv/Makefile
index 6d9347a..0525714 100644
--- a/kernel/chr_drv/Makefile
+++ b/kernel/chr_drv/Makefile
@@ -20,7 +20,8 @@ SUBDIRS= sound
OBJS = tty_io.o console.o keyboard.o serial.o \
tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o \
- busmouse.o psaux.o msbusmouse.o atixlmouse.o
+ busmouse.o psaux.o msbusmouse.o atixlmouse.o \
+ tpqic02.o
all: chr_drv.a subdirs
diff --git a/kernel/chr_drv/busmouse.c b/kernel/chr_drv/busmouse.c
index a3ad17b..8710e37 100644
--- a/kernel/chr_drv/busmouse.c
+++ b/kernel/chr_drv/busmouse.c
@@ -32,6 +32,13 @@
#include <asm/irq.h>
static struct mouse_status mouse;
+static int mouse_irq = MOUSE_IRQ;
+
+void bmouse_setup(char *str, int *ints)
+{
+ if (ints[0] > 0)
+ mouse_irq=ints[1];
+}
static void mouse_interrupt(int unused)
{
@@ -63,7 +70,7 @@ static void release_mouse(struct inode * inode, struct file * file)
MSE_INT_OFF();
mouse.active = 0;
mouse.ready = 0;
- free_irq(MOUSE_IRQ);
+ free_irq(mouse_irq);
}
static int open_mouse(struct inode * inode, struct file * file)
@@ -77,7 +84,7 @@ static int open_mouse(struct inode * inode, struct file * file)
mouse.dx = 0;
mouse.dy = 0;
mouse.buttons = 0x87;
- if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
+ if (request_irq(mouse_irq, mouse_interrupt)) {
mouse.active = 0;
return -EBUSY;
}
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index d93ede7..7295fe8 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -51,6 +51,22 @@
#include "vt_kern.h"
+#ifdef CONFIG_SELECTION
+#include <linux/ctype.h>
+
+/* Routines for selection control. */
+int set_selection(const int arg);
+int paste_selection(struct tty_struct *tty);
+static void clear_selection(void);
+
+/* Variables for selection control. */
+#define SEL_BUFFER_SIZE 2048
+static int sel_cons;
+static int sel_start = -1;
+static int sel_end;
+static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
+#endif /* CONFIG_SELECTION */
+
#define NPAR 16
extern void vt_init(void);
@@ -187,8 +203,6 @@ static int console_blanked = 0;
int blankinterval = 10*60*HZ;
static int screen_size = 0;
-extern void kd_mksound(int freq, int time);
-
/*
* this is what the terminal answers to a ESC-Z or csi0c query.
*/
@@ -197,6 +211,7 @@ extern void kd_mksound(int freq, int time);
static unsigned char * translations[] = {
/* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
+(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
@@ -211,6 +226,7 @@ static unsigned char * translations[] = {
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
"\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
/* vt100 graphics */
+(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
@@ -226,6 +242,7 @@ static unsigned char * translations[] = {
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
"\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
/* IBM graphics: minimal translations (CR, LF, LL, SO, SI and ESC) */
+(unsigned char *)
"\000\001\002\003\004\005\006\007\010\011\000\013\000\000\000\000"
"\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
@@ -378,7 +395,8 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
"movl _video_num_columns,%1\n\t"
"rep\n\t"
"stosw"
- ::"a" (video_erase_char),
+ : /* no output */
+ :"a" (video_erase_char),
"c" ((video_num_lines-1)*video_num_columns>>1),
"D" (video_mem_start),
"S" (origin)
@@ -390,7 +408,8 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
__asm__("cld\n\t"
"rep\n\t"
"stosw"
- ::"a" (video_erase_char),
+ : /* no output */
+ :"a" (video_erase_char),
"c" (video_num_columns),
"D" (scr_end-video_size_row)
:"cx","di");
@@ -403,7 +422,8 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
"movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
- ::"a" (video_erase_char),
+ : /* no output */
+ :"a" (video_erase_char),
"c" ((b-t-1)*video_num_columns>>1),
"D" (origin+video_size_row*t),
"S" (origin+video_size_row*(t+1))
@@ -423,7 +443,8 @@ static void scrdown(int currcons, unsigned int t, unsigned int b)
"rep\n\t"
"stosw\n\t"
"cld"
- ::"a" (video_erase_char),
+ : /* no output */
+ :"a" (video_erase_char),
"c" ((b-t-1)*video_num_columns>>1),
"D" (origin+video_size_row*b-4),
"S" (origin+video_size_row*(b-1)-4)
@@ -501,7 +522,8 @@ static void csi_J(int currcons, int vpar)
__asm__("cld\n\t"
"rep\n\t"
"stosw\n\t"
- ::"c" (count),
+ : /* no output */
+ :"c" (count),
"D" (start),"a" (video_erase_char)
:"cx","di");
need_wrap = 0;
@@ -531,7 +553,8 @@ static void csi_K(int currcons, int vpar)
__asm__("cld\n\t"
"rep\n\t"
"stosw\n\t"
- ::"c" (count),
+ : /* no output */
+ :"c" (count),
"D" (start),"a" (video_erase_char)
:"cx","di");
need_wrap = 0;
@@ -936,6 +959,12 @@ void con_write(struct tty_struct * tty)
printk("con_write: illegal tty (%d)\n", currcons);
return;
}
+#ifdef CONFIG_SELECTION
+ /* clear the selection as soon as any characters are to be written
+ out on the console holding the selection. */
+ if (!EMPTY(&tty->write_q) && currcons == sel_cons)
+ clear_selection();
+#endif /* CONFIG_SELECTION */
while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) {
if (state == ESnormal && translate[c]) {
if (need_wrap) {
@@ -1257,11 +1286,48 @@ void * memsetw(void * s,unsigned short c,int count)
__asm__("cld\n\t"
"rep\n\t"
"stosw"
- ::"a" (c),"D" (s),"c" (count)
+ : /* no output */
+ :"a" (c),"D" (s),"c" (count)
:"cx","di");
return s;
}
+void console_print(const char * b)
+{
+ int currcons = fg_console;
+ unsigned char c;
+
+ if (!printable || currcons<0 || currcons>=NR_CONSOLES)
+ return;
+ while ((c = *(b++)) != 0) {
+ if (c == 10 || c == 13 || need_wrap) {
+ if (c != 13)
+ lf(currcons);
+ cr(currcons);
+ if (c == 10 || c == 13)
+ continue;
+ }
+ *(unsigned short *) pos = (attr << 8) + c;
+ if (x == video_num_columns - 1) {
+ need_wrap = 1;
+ continue;
+ }
+ x++;
+ pos+=2;
+ }
+ set_cursor(currcons);
+ if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
+ return;
+ timer_active &= ~(1<<BLANK_TIMER);
+ if (console_blanked) {
+ timer_table[BLANK_TIMER].expires = 0;
+ timer_active |= 1<<BLANK_TIMER;
+ } else if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
+ }
+}
+
/*
* long con_init(long);
*
@@ -1279,7 +1345,6 @@ long con_init(long kmem_start)
long base;
int orig_x = ORIG_X;
int orig_y = ORIG_Y;
- void console_print(const char * b);
vc_scrmembuf = (unsigned short *) kmem_start;
video_num_columns = ORIG_VIDEO_COLS;
@@ -1466,42 +1531,6 @@ int do_screendump(int arg)
return(0);
}
-void console_print(const char * b)
-{
- int currcons = fg_console;
- unsigned char c;
-
- if (!printable || currcons<0 || currcons>=NR_CONSOLES)
- return;
- while ((c = *(b++)) != 0) {
- if (c == 10 || c == 13 || need_wrap) {
- if (c != 13)
- lf(currcons);
- cr(currcons);
- if (c == 10 || c == 13)
- continue;
- }
- *(unsigned short *) pos = (attr << 8) + c;
- if (x == video_num_columns - 1) {
- need_wrap = 1;
- continue;
- }
- x++;
- pos+=2;
- }
- set_cursor(currcons);
- if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
- return;
- timer_active &= ~(1<<BLANK_TIMER);
- if (console_blanked) {
- timer_table[BLANK_TIMER].expires = 0;
- timer_active |= 1<<BLANK_TIMER;
- } else if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
- }
-}
-
/*
* All we do is set the write and ioctl subroutines; later on maybe we'll
* dynamically allocate the console screen memory.
@@ -1514,3 +1543,199 @@ int con_open(struct tty_struct *tty, struct file * filp)
return -ENODEV;
return 0;
}
+
+#ifdef CONFIG_SELECTION
+/* set reverse video on characters s-e of console with selection. */
+static void highlight(const int currcons, const int s, const int e)
+{
+ unsigned char *p, *p1, *p2;
+
+ p1 = (unsigned char *)origin + s + 1;
+ p2 = (unsigned char *)origin + e + 1;
+ if (p1 > p2)
+ {
+ p = p1;
+ p1 = p2;
+ p2 = p;
+ }
+ for (p = p1; p <= p2; p += 2)
+ *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07);
+}
+
+/* is c in range [a-zA-Z0-9_]? */
+static inline int inword(const char c) { return (isalnum(c) || c == '_'); }
+
+/* does screen address p correspond to character at LH/RH edge of screen? */
+static inline int atedge(const int p)
+{
+ return (!(p % video_size_row) || !((p + 2) % video_size_row));
+}
+
+/* constrain v such that l <= v <= u */
+static inline short limit(const int v, const int l, const int u)
+{
+ return (v < l) ? l : ((v > u) ? u : v);
+}
+
+/* set the current selection. Invoked by ioctl(). */
+int set_selection(const int arg)
+{
+ unsigned short *args, xs, ys, xe, ye;
+ int currcons = fg_console;
+ int sel_mode, new_sel_start, new_sel_end, spc;
+ char *bp, *obp, *spos;
+ int i, ps, pe;
+ char *off = (char *)origin;
+
+ unblank_screen();
+ args = (unsigned short *)(arg + 1);
+ xs = get_fs_word(args++) - 1;
+ ys = get_fs_word(args++) - 1;
+ xe = get_fs_word(args++) - 1;
+ ye = get_fs_word(args++) - 1;
+ sel_mode = get_fs_word(args);
+
+ xs = limit(xs, 0, video_num_columns - 1);
+ ys = limit(ys, 0, video_num_lines - 1);
+ xe = limit(xe, 0, video_num_columns - 1);
+ ye = limit(ye, 0, video_num_lines - 1);
+ ps = ys * video_size_row + (xs << 1);
+ pe = ye * video_size_row + (xe << 1);
+
+ if (ps > pe) /* make sel_start <= sel_end */
+ {
+ int tmp = ps;
+ ps = pe;
+ pe = tmp;
+ }
+
+ switch (sel_mode)
+ {
+ case 0: /* character-by-character selection */
+ default:
+ new_sel_start = ps;
+ new_sel_end = pe;
+ break;
+ case 1: /* word-by-word selection */
+ spc = isspace(*(off + ps));
+ for (new_sel_start = ps; ; ps -= 2)
+ {
+ if ((spc && !isspace(*(off + ps))) ||
+ (!spc && !inword(*(off + ps))))
+ break;
+ new_sel_start = ps;
+ if (!(ps % video_size_row))
+ break;
+ }
+ spc = isspace(*(off + pe));
+ for (new_sel_end = pe; ; pe += 2)
+ {
+ if ((spc && !isspace(*(off + pe))) ||
+ (!spc && !inword(*(off + pe))))
+ break;
+ new_sel_end = pe;
+ if (!((pe + 2) % video_size_row))
+ break;
+ }
+ break;
+ case 2: /* line-by-line selection */
+ new_sel_start = ps - ps % video_size_row;
+ new_sel_end = pe + video_size_row
+ - pe % video_size_row - 2;
+ break;
+ }
+ /* select to end of line if on trailing space */
+ if (new_sel_end > new_sel_start &&
+ !atedge(new_sel_end) && isspace(*(off + new_sel_end)))
+ {
+ for (pe = new_sel_end + 2; ; pe += 2)
+ {
+ if (!isspace(*(off + pe)) || atedge(pe))
+ break;
+ }
+ if (isspace(*(off + pe)))
+ new_sel_end = pe;
+ }
+ if (sel_cons != currcons)
+ {
+ clear_selection();
+ sel_cons = currcons;
+ }
+ if (sel_start == -1) /* no current selection */
+ highlight(sel_cons, new_sel_start, new_sel_end);
+ else if (new_sel_start == sel_start)
+ {
+ if (new_sel_end == sel_end) /* no action required */
+ return 0;
+ else if (new_sel_end > sel_end) /* extend to right */
+ highlight(sel_cons, sel_end + 2, new_sel_end);
+ else /* contract from right */
+ highlight(sel_cons, new_sel_end + 2, sel_end);
+ }
+ else if (new_sel_end == sel_end)
+ {
+ if (new_sel_start < sel_start) /* extend to left */
+ highlight(sel_cons, new_sel_start, sel_start - 2);
+ else /* contract from left */
+ highlight(sel_cons, sel_start, new_sel_start - 2);
+ }
+ else /* some other case; start selection from scratch */
+ {
+ clear_selection();
+ highlight(sel_cons, new_sel_start, new_sel_end);
+ }
+ sel_start = new_sel_start;
+ sel_end = new_sel_end;
+ obp = bp = sel_buffer;
+ for (i = sel_start; i <= sel_end; i += 2)
+ {
+ spos = (char *)origin + i;
+ *bp++ = *spos;
+ if (!isspace(*spos))
+ obp = bp;
+ if (! ((i + 2) % video_size_row))
+ {
+ /* strip trailing blanks from line and add newline,
+ unless non-space at end of line. */
+ if (obp != bp)
+ {
+ bp = obp;
+ *bp++ = '\n';
+ }
+ obp = bp;
+ }
+ /* check for space, leaving room for next character, possible
+ newline, and null at end. */
+ if (bp - sel_buffer > SEL_BUFFER_SIZE - 3)
+ break;
+ }
+ *bp = '\0';
+ return 0;
+}
+
+/* insert the contents of the selection buffer into the queue of the
+ tty associated with the current console. Invoked by ioctl(). */
+int paste_selection(struct tty_struct *tty)
+{
+ char *bp = sel_buffer;
+
+ while (*bp)
+ {
+ put_tty_queue(*bp, &tty->read_q);
+ bp++;
+ }
+ TTY_READ_FLUSH(tty);
+ return 0;
+}
+
+/* remove the current selection highlight, if any, from the console holding
+ the selection. */
+static void clear_selection()
+{
+ if (sel_start != -1)
+ {
+ highlight(sel_cons, sel_start, sel_end);
+ sel_start = -1;
+ }
+}
+#endif /* CONFIG_SELECTION */
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index ffccc3c..3dabcac 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -86,7 +86,7 @@ static k_hand key_handler[] = {
};
/* maximum values each key_handler can handle */
-const u_char max_vals[] = {
+const int max_vals[] = {
255, 25, 13, 16, 4, 255, 3, 255
};
@@ -155,7 +155,8 @@ static void keyboard_interrupt(int int_pt_regs)
* code and E0 AA follows break code. We do our own book-keeping,
* so we will just ignore these.
*/
- if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa))
+ if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa ||
+ scancode == 0x36 || scancode == 0xb6))
goto end_kbd_intr;
/*
* Repeat a key only if the input buffers are empty or the
@@ -193,7 +194,7 @@ static void keyboard_interrupt(int int_pt_regs)
#if 0
printk("keyboard: scancode (%02x) not in range 00 - %2x\n", scancode, E0_BASE - 1);
#endif
- scancode = 0;
+ goto end_kbd_intr;
}
if (kbd_dead(KGD_E0)) {
@@ -204,14 +205,19 @@ static void keyboard_interrupt(int int_pt_regs)
i = -1;
break;
}
- if (i != -1)
+ if (i != -1) {
+#if 0
printk("keyboard: unknown scancode e0 %02x\n", scancode);
+#endif
+ goto end_kbd_intr;
+ }
}
key_code = key_map[shift_state][scancode];
(*key_handler[key_code >> 8])(key_code & 0xff, break_flag);
}
end_kbd_intr:
+ return;
}
static void put_queue(int ch)
@@ -281,7 +287,7 @@ static void show_ptregs(void)
printk("\n");
printk("EIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
if (pt_regs->cs & 3)
- printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
+ printk(" ESP: %04x:%08x",0xffff & pt_regs->ss,pt_regs->esp);
printk(" EFLAGS: %08x\n",pt_regs->eflags);
printk("EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n",
pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx);
@@ -427,18 +433,18 @@ unsigned int handle_diacr(unsigned int ch)
"`\340bcd\350fgh\354jklmn\362pqrst\371vwxyz{|}~", /* accent grave */
" \301BCD\311FGH\315JKLMN\323PQRST\332VWX\335Z[\\]^_"
- "`\341bcd\351fgh\355jklmn\363pqrst\372vwxyz{|}~", /* accent acute */
+ "`\341bcd\351fgh\355jklmn\363pqrst\372vwx\375z{|}~", /* accent acute */
" \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_"
"`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~", /* circumflex */
- " \303BCDEFGHIJKLMN\325PQRSTUVWXYZ[\\]^_"
+ " \303BCDEFGHIJKLM\321\325PQRSTUVWXYZ[\\]^_"
"`\343bcdefghijklm\361\365pqrstuvwxyz{|}~", /* tilde */
- " \304BCD\313FGH\316JKLMN\326PQRST\334VWXYZ[\\]^_"
+ " \304BCD\313FGH\317JKLMN\326PQRST\334VWXYZ[\\]^_"
"`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */
};
- int d = diacr;
+ int d = diacr, e;
if (diacr == -1)
return ch;
@@ -447,10 +453,13 @@ unsigned int handle_diacr(unsigned int ch)
if (ch == ' ')
return ret_diacr[d];
- if (ch < 64 || ch > 122)
- return ch;
-
- return accent_table[d][ch - 64];
+ if (ch >= 64 && ch <= 122) {
+ e = accent_table[d][ch - 64];
+ if (e != ch)
+ return e;
+ }
+ put_queue(ret_diacr[d]);
+ return ch;
}
static void do_cons(unsigned char value, char up_flag)
@@ -487,7 +496,7 @@ static void do_fn(unsigned char value, char up_flag)
return;
}
}
- if (kbd_flags & ALT_KEYS) {
+ if ((kbd_flags & ALT_KEYS) && value < 12) {
want_console = value;
return;
}
@@ -661,10 +670,10 @@ static int send_data(unsigned char data)
if (acknowledge)
return 1;
if (resend)
- goto repeat;
+ break;
}
- return 0;
-repeat:
+ if (!resend)
+ return 0;
} while (retries-- > 0);
return 0;
}
@@ -684,7 +693,7 @@ repeat:
*/
static void kbd_bh(void * unused)
{
- static unsigned char old_leds = -1;
+ static unsigned char old_leds = 0xff;
unsigned char leds = kbd_table[fg_console].flags & LED_MASK;
if (leds != old_leds) {
@@ -729,7 +738,7 @@ void hard_reset_now(void)
/* nothing */;
outb(0xfe,0x64); /* pulse reset low */
}
- __asm__("\tlidt _no_idt"::);
+ __asm__("\tlidt _no_idt");
}
}
diff --git a/kernel/chr_drv/lp.c b/kernel/chr_drv/lp.c
index 55adcfc..c74ebb7 100644
--- a/kernel/chr_drv/lp.c
+++ b/kernel/chr_drv/lp.c
@@ -46,7 +46,6 @@ static int lp_char_polled(char lpchar, int minor)
int status = 0, wait = 0;
unsigned long count = 0;
- outb_p(lpchar, LP_B(minor));
do {
status = LP_S(minor);
count ++;
@@ -64,6 +63,7 @@ static int lp_char_polled(char lpchar, int minor)
lp_max_count=count;
}
#endif
+ outb_p(lpchar, LP_B(minor));
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
while(wait != LP_WAIT(minor)) wait++;
@@ -81,12 +81,12 @@ static int lp_char_interrupt(char lpchar, int minor)
int wait = 0;
unsigned char status;
- outb_p(lpchar, LP_B(minor));
if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
|| !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
|| !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
+ outb_p(lpchar, LP_B(minor));
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
while(wait != LP_WAIT(minor)) wait++;
@@ -289,8 +289,8 @@ static int lp_open(struct inode * inode, struct file * file)
return -EBUSY;
if ((irq = LP_IRQ(minor))) {
- if (!(lp_table[minor].lp_buffer = kmalloc(LP_BUFFER_SIZE,
- GFP_KERNEL)))
+ lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
+ if (!lp_table[minor].lp_buffer)
return -ENOMEM;
sa.sa_handler = lp_interrupt;
@@ -330,6 +330,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
+ int retval = 0;
#ifdef LP_DEBUG
printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
@@ -346,15 +347,15 @@ static int lp_ioctl(struct inode *inode, struct file *file,
LP_CHAR(minor) = arg;
break;
case LPABORT:
- if(arg)
+ if (arg)
LP_F(minor) |= LP_ABORT;
- else LP_F(minor) &= ~LP_ABORT;
+ else
+ LP_F(minor) &= ~LP_ABORT;
break;
case LPWAIT:
LP_WAIT(minor) = arg;
break;
case LPSETIRQ: {
- int ret;
int oldirq;
int newirq = arg;
struct lp_struct *lp = &lp_table[minor];
@@ -367,7 +368,8 @@ static int lp_ioctl(struct inode *inode, struct file *file,
/* Allocate buffer now if we are going to need it */
if (!oldirq && newirq) {
- if (!(lp->lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL)))
+ lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
+ if (!lp->lp_buffer)
return -ENOMEM;
}
@@ -380,7 +382,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
sa.sa_flags = SA_INTERRUPT;
sa.sa_mask = 0;
sa.sa_restorer = NULL;
- if ((ret = irqaction(newirq, &sa))) {
+ if ((retval = irqaction(newirq, &sa))) {
if (oldirq) {
/* restore old irq */
irqaction(oldirq, &sa);
@@ -389,7 +391,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
lp->lp_buffer = NULL;
}
- return ret;
+ return retval;
}
}
if (oldirq && !newirq) {
@@ -402,11 +404,12 @@ static int lp_ioctl(struct inode *inode, struct file *file,
break;
}
case LPGETIRQ:
- arg = LP_IRQ(minor);
+ retval = LP_IRQ(minor);
break;
- default: arg = -EINVAL;
+ default:
+ retval = -EINVAL;
}
- return arg;
+ return retval;
}
diff --git a/kernel/chr_drv/mem.c b/kernel/chr_drv/mem.c
index 7bcfc7a..59d8910 100644
--- a/kernel/chr_drv/mem.c
+++ b/kernel/chr_drv/mem.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/mouse.h>
+#include <linux/tpqic02.h>
#include <linux/user.h>
#include <linux/a.out.h>
@@ -128,7 +129,7 @@ static int write_mem(struct inode * inode, struct file * file,char * buf, int co
static int mmap_mem(struct inode * inode, struct file * file,
unsigned long addr, size_t len, int prot, unsigned long off)
{
- if (len > high_memory || off > high_memory - len) /* avoid overflow */
+ if (off & 0xfff || off + len < off)
return -ENXIO;
if (remap_page_range(addr, off, len, prot))
@@ -239,7 +240,8 @@ static struct file_operations ram_fops = {
NULL, /* ram_ioctl */
NULL, /* ram_mmap */
NULL, /* no special open code */
- NULL /* no special release code */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
static struct file_operations mem_fops = {
@@ -251,7 +253,8 @@ static struct file_operations mem_fops = {
NULL, /* mem_ioctl */
mmap_mem,
NULL, /* no special open code */
- NULL /* no special release code */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
static struct file_operations kmem_fops = {
@@ -263,7 +266,8 @@ static struct file_operations kmem_fops = {
NULL, /* kmem_ioctl */
mmap_kmem,
NULL, /* no special open code */
- NULL /* no special release code */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
static struct file_operations null_fops = {
@@ -275,7 +279,8 @@ static struct file_operations null_fops = {
NULL, /* null_ioctl */
NULL, /* null_mmap */
NULL, /* no special open code */
- NULL /* no special release code */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
static struct file_operations port_fops = {
@@ -287,7 +292,8 @@ static struct file_operations port_fops = {
NULL, /* port_ioctl */
NULL, /* port_mmap */
NULL, /* no special open code */
- NULL /* no special release code */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
static struct file_operations zero_fops = {
@@ -311,7 +317,8 @@ static struct file_operations core_fops = {
NULL, /* zero_ioctl */
NULL, /* zero_mmap */
NULL, /* no special open code */
- NULL /* no special release code */
+ NULL, /* no special release code */
+ NULL /* fsync */
};
static int memory_open(struct inode * inode, struct file * filp)
@@ -355,7 +362,8 @@ static struct file_operations memory_fops = {
NULL, /* ioctl */
NULL, /* mmap */
memory_open, /* just a selector for the real open */
- NULL /* release */
+ NULL, /* release */
+ NULL /* fsync */
};
long chr_dev_init(long mem_start, long mem_end)
@@ -366,5 +374,8 @@ long chr_dev_init(long mem_start, long mem_end)
mem_start = lp_init(mem_start);
mem_start = mouse_init(mem_start);
mem_start = soundcard_init(mem_start);
+#if CONFIG_TAPE_QIC02
+ mem_start = tape_qic02_init(mem_start);
+#endif
return mem_start;
}
diff --git a/kernel/chr_drv/msbusmouse.c b/kernel/chr_drv/msbusmouse.c
index f2f3f83..3d9bcee 100644
--- a/kernel/chr_drv/msbusmouse.c
+++ b/kernel/chr_drv/msbusmouse.c
@@ -19,7 +19,13 @@
* really attached to the machine. Don't know what this does to
* Logitech bus mice, but all it does is read ports.
*
- * version 0.3
+ * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de)
+ * Changes: Better interrupt-handler (like in busmouse.c).
+ * Some changes to reduce code-size.
+ * Changed dectection code to use inb_p() instead of doing empty
+ * loops to delay i/o.
+ *
+ * version 0.3a
*/
#include <linux/kernel.h>
@@ -55,19 +61,19 @@ static void ms_mouse_interrupt(int unused)
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
- mouse.buttons = buttons;
- mouse.latch_buttons |= buttons;
- mouse.dx += dx;
- mouse.dy += dy;
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
+ if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
+ mouse.buttons = buttons;
+ mouse.dx += dx;
+ mouse.dy += dy;
+ mouse.ready = 1;
+ wake_up_interruptible(&mouse.wait);
+ }
}
static void release_mouse(struct inode * inode, struct file * file)
{
MS_MSE_INT_OFF();
- mouse.active = 0;
- mouse.ready = 0;
+ mouse.active = mouse.ready = 0;
free_irq(MOUSE_IRQ);
}
@@ -78,10 +84,8 @@ static int open_mouse(struct inode * inode, struct file * file)
if (mouse.active)
return -EBUSY;
mouse.active = 1;
- mouse.ready = 0;
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.buttons = mouse.latch_buttons = 0x80;
+ mouse.ready = mouse.dx = mouse.dy = 0;
+ mouse.buttons = 0x80;
if (request_irq(MOUSE_IRQ, ms_mouse_interrupt)) {
mouse.active = 0;
return -EBUSY;
@@ -105,23 +109,12 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
return -EINVAL;
if (!mouse.ready)
return -EAGAIN;
- put_fs_byte(mouse.latch_buttons | 0x80, buffer);
- if (mouse.dx < -127)
- mouse.dx = -127;
- if (mouse.dx > 127)
- mouse.dx = 127;
- put_fs_byte((char)mouse.dx, buffer + 1);
- if (mouse.dy < -127)
- mouse.dy = -127;
- if (mouse.dy > 127)
- mouse.dy = 127;
- put_fs_byte((char) -mouse.dy, buffer + 2);
+ put_fs_byte(mouse.buttons | 0x80, buffer);
+ put_fs_byte((char)(mouse.dx<-127 ? -127 : mouse.dx>127 ? 127 : mouse.dx), buffer + 1);
+ put_fs_byte((char)(mouse.dy<-127 ? 127 : mouse.dy>127 ? -127 : -mouse.dy), buffer + 2);
for (i = 3; i < count; i++)
put_fs_byte(0x00, buffer + i);
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.latch_buttons = mouse.buttons;
- mouse.ready = 0;
+ mouse.dx = mouse.dy = mouse.ready = 0;
return i;
}
@@ -147,45 +140,32 @@ struct file_operations ms_bus_mouse_fops = {
release_mouse,
};
-#define MS_DELAY 100000
-
unsigned long ms_bus_mouse_init(unsigned long kmem_start)
{
- register int mse_byte;
- int i, delay_val, msfound = 1;
+ int mse_byte, i;
- mouse.present = 0;
- mouse.active = mouse.ready = 0;
- mouse.buttons = mouse.latch_buttons = 0x80;
+ mouse.present = mouse.active = mouse.ready = 0;
+ mouse.buttons = 0x80;
mouse.dx = mouse.dy = 0;
mouse.wait = NULL;
- if (inb(MS_MSE_SIGNATURE_PORT) == 0xde) {
- for (delay_val=0; delay_val<MS_DELAY;)
- delay_val++;
+ if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
- mse_byte = inb(MS_MSE_SIGNATURE_PORT);
- for (delay_val=0; delay_val<MS_DELAY; )
- delay_val++;
+ mse_byte = inb_p(MS_MSE_SIGNATURE_PORT);
for (i = 0; i < 4; i++) {
- for (delay_val=0; delay_val<MS_DELAY;)
- delay_val++;
- if (inb(MS_MSE_SIGNATURE_PORT) == 0xde) {
- for (delay_val=0; delay_val<MS_DELAY; )
- delay_val++;
- if (inb(MS_MSE_SIGNATURE_PORT) == mse_byte)
- msfound = 0;
+ if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
+ if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
+ mouse.present = 1;
else
- msfound = 1;
+ mouse.present = 0;
} else
- msfound = 1;
+ mouse.present = 0;
}
}
- if (msfound == 1) {
+ if (mouse.present == 0) {
return kmem_start;
}
MS_MSE_INT_OFF();
- mouse.present = 1;
- printk("Microsoft Bus mouse detected and installed.\n");
+ printk("Microsoft BusMouse detected and installed.\n");
return kmem_start;
}
diff --git a/kernel/chr_drv/psaux.c b/kernel/chr_drv/psaux.c
index 7cd33c1..28d94ac 100644
--- a/kernel/chr_drv/psaux.c
+++ b/kernel/chr_drv/psaux.c
@@ -122,10 +122,11 @@ static unsigned int get_from_queue(void)
unsigned int result;
unsigned long flags;
- __asm__ __volatile__ ("pushfl ; popl %0; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
- __asm__ __volatile__ ("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
return result;
}
diff --git a/kernel/chr_drv/pty.c b/kernel/chr_drv/pty.c
index 9dca885..4cbecab 100644
--- a/kernel/chr_drv/pty.c
+++ b/kernel/chr_drv/pty.c
@@ -53,9 +53,9 @@ static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
while (!from->stopped && !EMPTY(&from->write_q)) {
if (FULL(&to->read_q)) {
- if (FULL(&to->secondary))
- break;
TTY_READ_FLUSH(to);
+ if (FULL(&to->read_q))
+ break;
continue;
}
c = get_tty_queue(&from->write_q);
@@ -64,7 +64,8 @@ static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
break;
}
TTY_READ_FLUSH(to);
- wake_up_interruptible(&from->write_q.proc_list);
+ if (!FULL(&from->write_q))
+ wake_up_interruptible(&from->write_q.proc_list);
if (from->write_data_cnt) {
set_bit(from->line, &tty_check_write);
mark_bh(TTY_BH);
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index 6034b00..b9742d1 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -437,24 +437,24 @@ static void do_softint(void *unused)
struct async_struct *info;
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
- if (!clear_bit(i, rs_event)) {
+ if (clear_bit(i, rs_event)) {
if (!info->tty)
continue;
- if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
+ if (clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
TTY_READ_FLUSH(info->tty);
}
- if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
wake_up_interruptible(&info->tty->write_q.proc_list);
}
- if (!clear_bit(RS_EVENT_HANGUP, &info->event)) {
+ if (clear_bit(RS_EVENT_HANGUP, &info->event)) {
tty_hangup(info->tty);
wake_up_interruptible(&info->open_wait);
info->flags &= ~(ASYNC_NORMAL_ACTIVE|
ASYNC_CALLOUT_ACTIVE);
}
- if (!clear_bit(RS_EVENT_BREAK, &info->event))
+ if (clear_bit(RS_EVENT_BREAK, &info->event))
handle_rs_break(info);
- if (!clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) {
+ if (clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) {
wake_up_interruptible(&info->open_wait);
}
}
@@ -880,7 +880,7 @@ static int get_serial_info(struct async_struct * info,
static int set_serial_info(struct async_struct * info,
struct serial_struct * new_info)
{
- struct serial_struct new;
+ struct serial_struct new_serial;
struct async_struct old_info;
unsigned int i,change_irq,change_port;
int retval;
@@ -888,39 +888,39 @@ static int set_serial_info(struct async_struct * info,
if (!new_info)
return -EFAULT;
- memcpy_fromfs(&new,new_info,sizeof(new));
+ memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
old_info = *info;
- change_irq = new.irq != info->irq;
- change_port = new.port != info->port;
+ change_irq = new_serial.irq != info->irq;
+ change_port = new_serial.port != info->port;
if (!suser()) {
if (change_irq || change_port ||
- (new.baud_base != info->baud_base) ||
- (new.type != info->type) ||
- (new.close_delay != info->close_delay) ||
- ((new.flags & ~ASYNC_FLAGS) !=
+ (new_serial.baud_base != info->baud_base) ||
+ (new_serial.type != info->type) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_FLAGS) !=
(info->flags & ~ASYNC_FLAGS)))
return -EPERM;
info->flags = ((info->flags & ~ASYNC_SPD_MASK) |
- (new.flags & ASYNC_SPD_MASK));
- info->custom_divisor = new.custom_divisor;
- new.port = 0; /* Prevent initialization below */
+ (new_serial.flags & ASYNC_SPD_MASK));
+ info->custom_divisor = new_serial.custom_divisor;
+ new_serial.port = 0; /* Prevent initialization below */
goto check_and_exit;
}
- if (new.irq == 2)
- new.irq = 9;
+ if (new_serial.irq == 2)
+ new_serial.irq = 9;
- if ((new.irq > 15) || (new.port > 0xffff) ||
- (new.type < PORT_UNKNOWN) || (new.type > PORT_MAX)) {
+ if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||
+ (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
return -EINVAL;
}
/* Make sure address is not already in use */
for (i = 0 ; i < NR_PORTS; i++)
if ((info != &rs_table[i]) &&
- (rs_table[i].port == new.port) && rs_table[i].type)
+ (rs_table[i].port == new_serial.port) && rs_table[i].type)
return -EADDRINUSE;
/*
@@ -928,14 +928,14 @@ static int set_serial_info(struct async_struct * info,
* interrupts. (We have to do this early, since we may get an
* error trying to do this.)
*/
- if (new.port && new.type && new.irq &&
+ if (new_serial.port && new_serial.type && new_serial.irq &&
(change_irq || !(info->flags & ASYNC_INITIALIZED))) {
- if (!IRQ_ports[new.irq]) {
+ if (!IRQ_ports[new_serial.irq]) {
sa.sa_handler = rs_interrupt;
sa.sa_flags = (SA_INTERRUPT);
sa.sa_mask = 0;
sa.sa_restorer = NULL;
- retval = irqaction(new.irq,&sa);
+ retval = irqaction(new_serial.irq,&sa);
if (retval)
return retval;
}
@@ -949,12 +949,12 @@ static int set_serial_info(struct async_struct * info,
* At this point, we start making changes.....
*/
- info->baud_base = new.baud_base;
+ info->baud_base = new_serial.baud_base;
info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new.flags & ASYNC_FLAGS));
- info->custom_divisor = new.custom_divisor;
- info->type = new.type;
- info->close_delay = new.close_delay;
+ (new_serial.flags & ASYNC_FLAGS));
+ info->custom_divisor = new_serial.custom_divisor;
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
if (change_port || change_irq) {
/*
@@ -967,8 +967,8 @@ static int set_serial_info(struct async_struct * info,
if (change_irq && info->irq && !IRQ_ports[info->irq])
free_irq(info->irq);
}
- info->irq = new.irq;
- info->port = new.port;
+ info->irq = new_serial.irq;
+ info->port = new_serial.port;
}
check_and_exit:
diff --git a/kernel/chr_drv/tpqic02.c b/kernel/chr_drv/tpqic02.c
new file mode 100644
index 0000000..c6aec05
--- /dev/null
+++ b/kernel/chr_drv/tpqic02.c
@@ -0,0 +1,2618 @@
+/* $Id: tpqic02.c,v 0.2.1.21 1993/06/18 19:04:33 root Exp root $
+ *
+ * Driver for tape drive support for Linux-i386 0.99.8.
+ *
+ * Copyright (c) 1992 by H. H. Bergman. All rights reserved.
+ * Current e-mail address: s0356514@let.rug.nl
+ * [If you are unable to reach me directly, try the TAPE mailing list
+ * channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as
+ * the first line in your message.]
+ *
+ * Distribution of this program in executable form is only allowed if
+ * all of the corresponding source files are made available through the same
+ * medium at no extra cost.
+ *
+ * I will not accept any responsibility for damage caused directly or
+ * indirectly by this program, or code derived from this program.
+ *
+ * Use this code at your own risk. Don't blame me if it destroys your data!
+ * Make sure you have a backup before you try this code.
+ *
+ * This driver was partially inspired by the 'wt' driver in the 386BSD
+ * source distribution, which carries the following copyright notice:
+ *
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * You are not allowed to change this line nor the text above.
+ *
+ * $Log: tpqic02.c,v $
+ * Revision 0.2.1.21 1993/06/18 19:04:33 root
+ * minor fixes for 0.99.10.
+ *
+ * Revision 0.2.1.20 1993/06/11 21:38:51 root
+ * Added exception code for status 0x8000 (Cypher weirdness).
+ *
+ * Revision 0.2.1.19 1993/04/19 23:13:59 root
+ * Cleanups. Changed to 0.99.8.
+ *
+ * Revision 0.2.1.18 1993/03/22 17:39:47 root
+ * Moved to 0.99.7. Added Archive MTSEEK and MTTELL support.
+ *
+ * Revision 0.2.1.17 1993/03/08 18:51:59 root
+ * Tried to `fix' write-once bug in previous release.
+ *
+ * Revision 0.2.1.16 1993/03/01 00:06:16 root
+ * Use register_chrdev() for 0.99.6.
+ *
+ * Revision 0.2.1.15 1993/02/25 00:14:25 root
+ * minor cleanups.
+ *
+ * Revision 0.2.1.14 1993/01/25 00:06:14 root
+ * Kernel udelay. Eof fixups.
+ * Removed report_ read/write dummies; have strace(1) now.
+ *
+ * Revision 0.2.1.13 1993/01/10 02:24:43 root
+ * Rewrote wait_for_ready() to use newer schedule() features.
+ * This improves performance for rewinds etc.
+ *
+ * Revision 0.2.1.12 1993/01/05 18:44:09 root
+ * Changes for 0.99.1. Fixed `restartable reads'.
+ *
+ * Revision 0.2.1.11 1992/11/28 01:19:10 root
+ * Changes to exception handling (significant).
+ * Changed returned error codes. Hopefully they're correct now.
+ * Changed declarations to please gcc-2.3.1.
+ * Patch to deal with bogus interrupts for Archive cards.
+ *
+ * Revision 0.2.1.10 1992/10/28 00:50:44 root
+ * underrun/error counter needed byte swapping.
+ *
+ * Revision 0.2.1.9 1992/10/15 17:06:01 root
+ * Removed online() stuff. Changed EOF handling.
+ *
+ * Revision 0.2.1.8 1992/10/02 22:25:48 root
+ * Removed `no_sleep' parameters (got usleep() now),
+ * cleaned up some comments.
+ *
+ * Revision 0.2.1.7 1992/09/27 01:41:55 root
+ * Changed write() to do entire user buffer in one go, rather than just
+ * a kernel-buffer sized portion each time.
+ *
+ * Revision 0.2.1.6 1992/09/21 02:15:30 root
+ * Introduced udelay() function for microsecond-delays.
+ * Trying to use get_dma_residue rather than TC flags.
+ * Patch to fill entire user buffer on reads before
+ * returning.
+ *
+ * Revision 0.2.1.5 1992/09/19 02:31:28 root
+ * Some changes based on patches by Eddy Olk to
+ * support Archive SC402/SC499R controller cards.
+ *
+ * Revision 0.2.1.4 1992/09/07 01:37:37 root
+ * Minor changes
+ *
+ * Revision 0.2.1.3 1992/08/13 00:11:02 root
+ * Added some support for Archive SC402 and SC499 cards.
+ * (Untested.)
+ *
+ * Revision 0.2.1.2 1992/08/10 02:02:36 root
+ * Changed from linux/system.h macros to asm/dma.h inline functions.
+ *
+ * Revision 0.2.1.1 1992/08/08 01:12:39 root
+ * cleaned up a bit. added stuff for selftesting.
+ * preparing for asm/dma.h instead of linux/system.h
+ *
+ * Revision 0.2 1992/08/03 20:11:30 root
+ * Changed to use new IRQ allocation. Padding now done at runtime, pads to
+ * 512 bytes. Because of this the page regs must be re-programmed every
+ * block! Added hooks for selftest commands.
+ * Moved to linux-0.97.
+ *
+ * Revision 0.1.0.5 1992/06/22 22:20:30 root
+ * moved to Linux 0.96b
+ *
+ * Revision 0.1.0.4 1992/06/18 02:00:04 root
+ * Use minor bit-7 to enable/disable printing of extra debugging info
+ * when do tape access.
+ * Added semop stuff for DMA/IRQ allocation checking. Don't think this
+ * is the right way to do it though.
+ *
+ * Revision 0.1.0.3 1992/06/01 01:57:34 root
+ * changed DRQ to DMA. added TDEBUG ifdefs to reduce output.
+ *
+ * Revision 0.1.0.2 1992/05/31 14:02:38 root
+ * changed SET_DMA_PAGE handling slightly.
+ *
+ * Revision 0.1.0.1 1992/05/27 12:12:03 root
+ * Can now use multiple files on tape (sort of).
+ * First release.
+ *
+ * Revision 0.1 1992/05/26 01:16:31 root
+ * Initial version. Copyright H. H. Bergman 1992
+ *
+ */
+
+/* After the legalese, now the important bits:
+ *
+ * This is a driver for the Wangtek 5150 tape drive with
+ * a QIC-02 controller for ISA-PC type computers.
+ * Hopefully it will work with other QIC-02 tape drives as well.
+ *
+ * Make sure your setup matches the configuration parameters.
+ * Also, be careful to avoid IO conflicts with other devices!
+ */
+
+#include <linux/config.h>
+
+/* skip this driver if not required for this configuration */
+#if CONFIG_TAPE_QIC02
+
+/*
+#define TDEBUG
+*/
+
+#define REALLY_SLOW_IO /* it sure is ... */
+
+#include <asm/dma.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/mtio.h>
+#include <linux/fcntl.h>
+#include <linux/delay.h>
+
+#include <linux/tpqic02.h>
+
+/* check existence of required configuration parameters */
+#if !defined(TAPE_QIC02_MAJOR) || !defined(TAPE_QIC02_PORT) || \
+ !defined(TAPE_QIC02_IRQ) || !defined(TAPE_QIC02_DMA)
+#error tape_qic02 configuration error
+#endif
+
+
+#define TPQIC_NAME "tpqic02"
+
+/* Linux outb() commands have (value,port) as parameters.
+ * One might expect (port,value) instead, so beware!
+ */
+
+static volatile int ctlbits = 0; /* control reg bits for tape interface */
+
+static struct wait_queue *tape_qic02_transfer = NULL; /* sync rw with interrupts */
+
+static volatile struct mtget ioctl_status; /* current generic status */
+
+static volatile struct tpstatus tperror; /* last drive status */
+
+static char rcs_revision[] = "$Revision: 0.2.1.21 $";
+static char rcs_date[] = "$Date: 1993/06/18 19:04:33 $";
+
+/* Flag bits for status and outstanding requests.
+ * (Could all be put in one bit-field-struct.)
+ * Some variables need `volatile' because they may be modified
+ * by an interrupt.
+ */
+static volatile flag status_dead = YES; /* device is legally dead until proven alive */
+static flag status_open = NO; /* in use or not */
+
+static volatile flag status_bytes_wr = NO; /* write FM at close or not */
+static volatile flag status_bytes_rd = NO; /* (rd|wr) used for rewinding */
+
+static volatile unsigned long status_cmd_pending = 0; /* cmd in progress */
+static volatile flag status_expect_int = NO; /* ready for interrupts */
+static volatile flag status_timer_on = NO; /* using time-out */
+static volatile int status_error = 0; /* int handler may detect error */
+static volatile flag status_eof_detected = NO; /* end of file */
+static volatile flag status_eom_detected = NO; /* end of recorded media */
+static volatile flag status_eot_detected = NO; /* end of tape */
+static volatile flag doing_read = NO;
+static volatile flag doing_write = NO;
+
+static volatile unsigned long dma_bytes_todo;
+static volatile unsigned long dma_bytes_done;
+static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */
+static flag need_rewind = YES;
+
+static dev_t current_tape_dev = (TAPE_QIC02_MAJOR)<<8;
+static int extra_blocks_left = BLOCKS_BEYOND_EW;
+
+
+/* return_*_eof:
+ * NO: not at EOF,
+ * YES: tell app EOF was reached (return 0).
+ *
+ * return_*_eof==YES && reported_*_eof==NO ==>
+ * return current buffer, next time(s) return EOF.
+ *
+ * return_*_eof==YES && reported_*_eof==YES ==>
+ * at EOF and application knows it, so we can
+ * move on to the next file.
+ *
+ */
+static flag return_read_eof = NO; /* set to signal app EOF was reached */
+static flag return_write_eof = NO;
+static flag reported_read_eof = NO; /* set when we've done that */
+static flag reported_write_eof = NO;
+
+
+#ifdef TP_HAVE_SEEK
+/* This is for doing `mt seek <blocknr>' */
+static char seek_addr_buf[SEEK_BUF_SIZE];
+#endif
+
+
+/* In write mode, we have to write a File Mark after the last block written,
+ * when the tape device is closed. Tape repositioning and reading in write
+ * mode is allowed as long as no actual writing has been done. After writing
+ * the File Mark, repositioning and reading are allowed again.
+ */
+static int mode_access; /* access mode: READ or WRITE */
+
+
+/* This is the actual kernel buffer where the interrupt routines read
+ * from/write to. It is needed because the DMA channels 1 and 3 cannot
+ * access the user buffers. [The kernel buffer must reside in the lower
+ * 1MBytes of system memory because of the DMA controller.]
+ * The user must ensure that a large enough buffer is passed to the
+ * kernel, in order to reduce tape repositioning.
+ *
+ * The buffer is 512 bytes larger than expected, because I want to align it
+ * at 512 bytes, to prevent problems with 64k boundaries.
+ */
+
+static volatile char tape_qic02_buf[TPQBUF_SIZE+TAPE_BLKSIZE];
+/* A really good compiler would be able to align this at 512 bytes... :-( */
+
+static unsigned long buffaddr; /* aligned physical address of buffer */
+
+
+/* This translates minor numbers to the corresponding recording format: */
+static char *format_names[] = {
+ "not set", /* for dumb drives unable to handle format selection */
+ "11", /* extinct */
+ "24",
+ "120",
+ "150",
+ "300", /* untested. */
+ "600" /* untested. */
+};
+
+
+/* `exception_list' is needed for exception status reporting.
+ * Exceptions 1..14 are defined by QIC-02 rev F.
+ * The drive status is matched sequentially to each entry,
+ * ignoring irrelevant bits, until a match is found. If no
+ * match is found, exception number 0 is used. (That should of
+ * course never happen...) The original table was based on the
+ * "Exception Status Summary" in QIC-02 rev F, but some changes
+ * were required to make it work with real-world drives.
+ *
+ * Exception 1 (CNI) is changed to also cover status 0x00e0 (mask USL),
+ * Exception 4 (EOM) is changed to also cover status 0x8288 (mask EOR),
+ * Exception 11 (FIL) is changed to also cover status 0x0089 (mask EOM).
+ * Exception 15 (EOR) is added for seek-to-end-of-data (catch EOR),
+ * Exception 16 (BOM) is added for beginning-of-media (catch BOM).
+ */
+static struct exception_list_type {
+ short mask, code;
+ char *msg;
+} exception_list[] = {
+ {0, 0,
+ "Unknown exception status code", /* extra: 0 */},
+ {~(TP_WRP|TP_USL), TP_ST0|TP_CNI,
+ /* My Wangtek 5150EQ sometimes reports a status code
+ * of 0x00e0, which is not a valid exception code, but
+ * I think it should be recognized as "NO CARTRIDGE".
+ */
+ "Cartridge not in place" /* 1 */},
+ {-1, TP_ST0|TP_CNI|TP_USL|TP_WRP,
+ "Drive not online" /* 2 */},
+ {~(TP_ST1|TP_BOM), TP_ST0|TP_WRP,
+ "Write protected cartridge" /* 3 */},
+ {~(TP_ST1|TP_EOR), TP_ST0|TP_EOM,
+ "End of media" /* 4 */},
+ {~TP_WRP, TP_ST0|TP_UDA| TP_ST1|TP_BOM,
+ "Read or Write abort. Rewind tape." /* 5 */},
+ {~TP_WRP, TP_ST0|TP_UDA,
+ "Read error. Bad block transferred." /* 6 */},
+ {~TP_WRP, TP_ST0|TP_UDA|TP_BNL,
+ "Read error. Filler block transferred." /* 7 */},
+ {~TP_WRP, TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT,
+ "Read error. No data detected." /* 8 */},
+ {~TP_WRP, TP_ST0|TP_EOM|TP_UDA|TP_BNL |TP_ST1|TP_NDT,
+ "Read error. No data detected. EOM." /* 9 */},
+ {~(TP_WRP|TP_MBD|TP_PAR|TP_EOR), TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT|TP_BOM,
+ "Read error. No data detected. BOM." /* 10 */},
+ {~(TP_WRP|TP_EOM), TP_ST0|TP_FIL,
+ /* Status 0x0089 (EOM & FM) is viewed as an FM,
+ * because it can only happen during a read.
+ * EOM is checked separately for an FM condition.
+ */
+ "File mark detected" /* 11 */},
+ {~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_ILL,
+ "Illegal command" /* 12 */},
+ {~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_POR,
+ "Reset occurred" /* 13 */},
+ {~TP_WRP, TP_ST0|TP_FIL|TP_MBD, /* NOTE: ST1 not set! */
+ "Marginal block detected" /* 14 */},
+ {~(TP_ST0|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL |TP_NDT), TP_ST1|TP_EOR,
+ /********** Is the extra TP_NDT really needed Eddy? **********/
+ "End of recorded media" /* extra: 15 */},
+ /* 15 is returned when SEEKEOD completes successfully */
+ {~(TP_WRP|TP_ST0), TP_ST1|TP_BOM,
+ "Beginning of media" /* extra: 16 */}
+#ifdef CYPHER_BUG
+ /* Perhaps the Cypher driver clears the TP_BOM bit after the
+ * status has been read? The QIC-02 specs explicitly state that
+ * the BOM bit should remain set as long as the tape is logically
+ * at the beginning of the tape.
+ */
+ ,{-1, TP_ST1,
+ "Hmm, this must be Cypher drive... Aaargh" /* extra */}
+#endif
+};
+#define NR_OF_EXC (sizeof(exception_list)/sizeof(struct exception_list_type))
+
+
+
+static void tpqputs(char *s)
+{
+ printk(TPQIC_NAME ": %s\n", s);
+} /* tpqputs */
+
+
+/* Perform byte order swapping for a 16-bit word.
+ *
+ * [FIXME] This should probably be in include/asm/
+ * ([FIXME] i486 can do this faster)
+ */
+static inline void byte_swap_w(volatile unsigned short * w)
+{
+ int t = *w;
+
+ *w = (t>>8) | ((t & 0xff)<<8);
+}
+
+
+
+/* Init control register bits on interface card.
+ * For Archive, interrupts must be enabled explicitly.
+ * Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R
+ * cards keep it active all the time.
+ */
+static void ifc_init(void)
+{
+#if TAPE_QIC02_IFC == WANGTEK
+ ctlbits = WT_CTL_ONLINE; /* online */
+ outb_p(ctlbits, QIC_CTL_PORT);
+
+#elif TAPE_QIC02_IFC == ARCHIVE
+ ctlbits = 0; /* no interrupts yet */
+ outb_p(ctlbits, QIC_CTL_PORT);
+ outb_p(0, AR_RESET_DMA_PORT); /* dummy write to reset DMA */
+#else
+# error No valid interface card specified
+#endif
+} /* ifc_init */
+
+
+static void report_exception(unsigned n)
+{
+ if (n >= NR_OF_EXC) { tpqputs("Oops -- report_exception"); n = 0; }
+ printk(TPQIC_NAME ": sense: %s\n", exception_list[n].msg);
+} /* report_exception */
+
+
+/* Try to map the drive-exception bits `s' to a predefined "exception number",
+ * by comparing the significant exception bits for each entry in the
+ * exception table (`exception_list[]').
+ * It is assumed that s!=0.
+ */
+static int decode_exception_nr(short s) /* s must be short, because of sign-extension */
+{
+ int i;
+
+ for (i=1; i<NR_OF_EXC; i++) {
+ if ((s & exception_list[i].mask)==exception_list[i].code)
+ return i;
+ }
+ tpqputs("decode_exception_nr: exception not recognized");
+ return 0;
+} /* decode_exception_nr */
+
+
+#ifdef OBSOLETE
+/* There are exactly 14 possible exceptions, as defined in QIC-02 rev F.
+ * Some are FATAL, some aren't. Currently all exceptions are treated as fatal.
+ * Especially 6 and 14 should not abort the transfer. RSN...
+ * Should probably let sense() figure out the exception number using the code
+ * below, and just report the error based on the number here, returning a code
+ * for FATAL/CONTINUABLE.
+ */
+static void report_error(int s)
+{
+ short n = -1;
+
+ if (s & TP_ST1) {
+ if (s & TP_ILL) /* 12: Illegal command. FATAL */
+ n = 12;
+ if (s & TP_POR) /* 13: Reset occurred. FATAL */
+ n = 13;
+ }
+ else if (s & TP_ST0) {
+ if (s & TP_EOR) { /* extra: 15: End of Recorded Media. CONTINUABLE */
+ n = 15;
+ /********** should set flag here **********/
+ }
+ else if (s & TP_EOM) /* 4: End Of Media. CONTINUABLE */
+ n = 4;
+ else if (s & TP_USL) /* 2: Drive not online. FATAL */
+ n = 2;
+ else if (s & TP_CNI) { /* 1: Cartridge not in place. FATAL */
+ n = 1;
+ need_rewind = YES;
+ status_eof_detected = NO;
+ status_eom_detected = NO;
+ }
+ else if (s & TP_UDA) {
+ if (s & TP_BNL) {
+ if (s & TP_NDT) {
+ if (s & TP_BOM) /* 9: Read error. No data detected & EOM. CONTINUABLE */
+ n = 9;
+ else if (s & TP_EOM) /* 10: Read error. No data detected & BOM. CONTINUABLE */
+ n = 10;
+ else /* 8: Read error. No data detected. CONTINUABLE */
+ n = 8;
+ } else { /* 7: Read error. Cannot recover block, filler substituted. CONTINUABLE */
+ tpqputs("[Bad block -- filler data transferred.]");
+ n = 7;
+ }
+ }
+ else {
+ if (s & TP_EOM) /* 5: Read or Write error. Rewind tape. FATAL */
+ n = 5;
+ else { /* 6: Read error. Bad block transferred. CONTINUABLE */
+ /* block is bad, but transfer may continue.
+ * This is why some people prefer not to
+ * use compression on backups...
+ */
+ tpqputs("[CRC failed!]");
+ n = 6;
+ }
+ }
+ }
+ else if (s & TP_FIL) {
+ if (s & TP_MBD) { /* 14: Marginal block detected. CONTINUABLE */
+ tpqputs("[Marginal block]");
+ n = 14;
+ } else /* 11: File mark detected. CONTINUABLE */
+ n = 11;
+ }
+ else if (s & TP_WRP) /* 3: Write protected cartridge. FATAL */
+ n = 3;
+ }
+ if (n >= 0)
+ sensemsg(n);
+} /* report_error */
+#endif
+
+
+/* perform appropriate action for certain exceptions */
+static void handle_exception(int exnr, int exbits)
+{
+ if (exnr==EXC_NCART) {
+ /* Cartridge was changed. Redo sense().
+ * EXC_NCART should be handled in open().
+ * It is not permitted to remove the tape while
+ * the tape driver has open files.
+ */
+ need_rewind = YES;
+ status_eof_detected = NO;
+ status_eom_detected = NO;
+ }
+ else if (exnr==EXC_XFILLER)
+ tpqputs("[Bad block -- filler data transferred.]");
+ else if (exnr==EXC_XBAD)
+ tpqputs("[CRC failed!]");
+ else if (exnr==EXC_MARGINAL) {
+ /* A marginal block behaves much like a FM.
+ * User may continue reading, if desired.
+ */
+ tpqputs("[Marginal block]");
+ doing_read = NO;
+ } else if (exnr==EXC_FM)
+ doing_read = NO;
+} /* handle_exception */
+
+
+static inline int is_exception(void)
+{
+ return (inb(QIC_STAT_PORT) & QIC_STAT_EXCEPTION) == 0;
+} /* is_exception */
+
+
+/* Reset the tape drive and controller.
+ * When reset fails, it marks the drive as dead and all
+ * requests (except reset) are to be ignored (ENXIO).
+ */
+static int tape_reset(int verbose)
+{
+ ifc_init(); /* reset interface card */
+
+ outb_p(ctlbits | QIC_CTL_RESET, QIC_CTL_PORT); /* assert reset */
+
+ /* Next, we need to wait >=25 usec. */
+ udelay(30);
+
+ /* after reset, we will be at BOT (modulo an automatic rewind) */
+ status_eof_detected = NO;
+ status_eom_detected = NO;
+ status_cmd_pending = 0;
+ need_rewind = YES;
+ doing_read = doing_write = NO;
+ ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
+
+ outb_p(ctlbits & ~QIC_CTL_RESET, QIC_CTL_PORT); /* de-assert reset */
+ status_dead = ((inb_p(QIC_STAT_PORT) & QIC_STAT_RESETMASK) != QIC_STAT_RESETVAL);
+ /* if successful, inb(STAT) returned RESETVAL */
+ if (status_dead)
+ printk(TPQIC_NAME ": reset failed!\n");
+ else if (verbose)
+ printk(TPQIC_NAME ": reset successful\n");
+
+ return (status_dead)? TE_DEAD : TE_OK;
+} /* tape_reset */
+
+
+
+/* Notify tape drive of a new command. It only waits for the
+ * command to be accepted, not for the actual command to complete.
+ *
+ * Before calling this routine, QIC_CMD_PORT must have been loaded
+ * with the command to be executed.
+ * After this routine, the exception bit must be checked.
+ * This routine is also used by rdstatus(), so in that case, any exception
+ * must be ignored (`ignore_ex' flag).
+ */
+static int notify_cmd(char cmd, short ignore_ex)
+{
+ int i;
+
+ outb_p(cmd, QIC_CMD_PORT); /* output the command */
+
+ /* wait 1 usec before asserting /REQUEST */
+ udelay(1);
+
+ if ((!ignore_ex) && is_exception()) {
+ tpqputs("*** exception detected in notify_cmd");
+ /** force a reset here **/
+ if (tape_reset(1)==TE_DEAD)
+ return TE_DEAD;
+ if (is_exception()) {
+ tpqputs("exception persists after reset.");
+ tpqputs(" ^ exception ignored.");
+ }
+ }
+
+ outb_p(ctlbits | QIC_CTL_REQUEST, QIC_CTL_PORT); /* set request bit */
+ i = TAPE_NOTIFY_TIMEOUT;
+ /* The specs say this takes about 500 usec, but there is no upper limit!
+ * If the drive were busy retensioning or something like that,
+ * it could be *much* longer!
+ */
+ while ((inb_p(QIC_STAT_PORT) & QIC_STAT_READY) && (--i>0))
+ /*skip*/; /* wait for ready */
+ if (i==0) {
+ tpqputs("timed out waiting for ready in notify_cmd");
+ status_dead = YES;
+ return TE_TIM;
+ }
+
+ outb_p(ctlbits & ~QIC_CTL_REQUEST, QIC_CTL_PORT); /* reset request bit */
+ i = TAPE_NOTIFY_TIMEOUT;
+ /* according to the specs this one should never time-out */
+ while (((inb_p(QIC_STAT_PORT) & QIC_STAT_READY) == 0) && (--i>0))
+ /*skip*/; /* wait for not ready */
+ if (i==0) {
+ tpqputs("timed out waiting for !ready in notify_cmd");
+ status_dead = YES;
+ return TE_TIM;
+ }
+ /* command accepted */
+ return TE_OK;
+} /* notify_cmd */
+
+
+
+/* Wait for a command to complete, with timeout */
+static int wait_for_ready(time_t timeout)
+{
+ int stat;
+ time_t spin_t;
+
+ /* Wait for ready or exception, without driving the loadavg up too much.
+ * In most cases, the tape drive already has READY asserted,
+ * so optimize for that case.
+ *
+ * First, busy wait a few usec:
+ */
+ spin_t = 50;
+ while (((stat = inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK) && (--spin_t>0))
+ /*SKIP*/;
+ if ((stat & QIC_STAT_READY) == 0)
+ return TE_OK; /* covers 99.99% of all calls */
+
+ /* Then use schedule() a few times */
+ spin_t = 3; /* max 0.03 sec busy waiting */
+ if (spin_t > timeout)
+ spin_t = timeout;
+ timeout -= spin_t;
+ spin_t += jiffies;
+
+ while (((stat = inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK) && (jiffies<spin_t))
+ schedule(); /* don't waste all the CPU time */
+ if ((stat & QIC_STAT_READY) == 0)
+ return TE_OK;
+
+ /* If we reach this point, we probably need to wait much longer, or
+ * an exception occurred. Either case is not very time-critical.
+ * Check the status port only a few times every second.
+ * A interval of less than 0.10 sec will not be noticed by the user,
+ * more than 0.40 sec may give noticeable delays.
+ */
+ spin_t += timeout;
+ TPQDEB({printk("wait_for_ready: additional timeout: %d\n", spin_t);})
+
+ /* not ready and no exception && timeout not expired yet */
+ while (((stat = inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK) && (jiffies<spin_t)) {
+ /* be `nice` to other processes on long operations... */
+ current->timeout = jiffies + 30; /* nap 0.30 sec between checks, */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule(); /* but could be woken up earlier by signals... */
+ }
+
+ /* don't use jiffies for this test because it may have changed by now */
+ if ((stat & QIC_STAT_MASK) == QIC_STAT_MASK) {
+ tpqputs("wait_for_ready() timed out");
+ return TE_TIM;
+ }
+
+ if ((stat & QIC_STAT_EXCEPTION) == 0) {
+ tpqputs("exception detected after waiting_for_ready");
+ return TE_EX;
+ } else {
+ return TE_OK;
+ }
+} /* wait_for_ready */
+
+
+/* Send some data to the drive */
+static int send_qic02_data(char sb[], unsigned size, int ignore_ex)
+{
+ int i, stat;
+
+ for (i=0; i<size; i++) {
+
+ stat = wait_for_ready(TIM_S);
+ if (stat != TE_OK)
+ return stat;
+
+ stat = notify_cmd(sb[i], ignore_ex);
+ if (stat != TE_OK)
+ return stat;
+ }
+ return TE_OK;
+
+} /* send_qic02_data */
+
+
+/* Send a QIC-02 command (`cmd') to the tape drive, with
+ * a time-out (`timeout').
+ * This one is also used by tp_sense(), so we must have
+ * a flag to disable exception checking (`ignore_ex').
+ *
+ * On entry, the controller is supposed to be READY.
+ */
+static int send_qic02_cmd(int cmd, time_t timeout, int ignore_ex)
+{
+ int stat;
+
+ stat = inb_p(QIC_STAT_PORT);
+ if ((stat & QIC_STAT_EXCEPTION) == 0) { /* if exception */
+ tpqputs("send_qic02_cmd: Exception!");
+ return TE_EX;
+ }
+ if (stat & QIC_STAT_READY) { /* if not ready */
+ tpqputs("send_qic02_cmd: not Ready!");
+ return TE_ERR;
+ }
+
+ /* assert(ready & !exception) */
+
+ /* Remember current command for later re-use with dma transfers.
+ * (For reading/writing multiple blocks.)
+ */
+ status_cmd_pending = cmd;
+
+ stat = notify_cmd(cmd, ignore_ex); /* tell drive new command was loaded, */
+ /* inherit exception check. */
+ if (cmd == QCMDV_SEEK_BLK) {
+ /* This one needs to send 3 more bytes, MSB first */
+ stat = send_qic02_data(seek_addr_buf, sizeof(seek_addr_buf), ignore_ex);
+ }
+ if (stat != TE_OK) {
+ tpqputs("send_qic02_cmd failed");
+ }
+ return stat;
+} /* send_qic02_cmd */
+
+
+
+/* Get drive status. Assume drive is ready or has exception set.
+ * (or will be in <1000 usec.)
+ * Extra parameters added because of 'Read Extended Status 3' command.
+ */
+static int rdstatus(char *stp, unsigned size, char qcmd)
+{
+ int s, n;
+ char *q = stp;
+
+ /* Try to busy-wait a few (700) usec, after that de-schedule.
+ *
+ * The problem is, if we don't de-schedule, performance will
+ * drop to zero when the drive is not responding and if we
+ * de-schedule immediately, we waste a lot of time because a
+ * task switch is much longer than we usually have to wait here.
+ */
+ n = 1000; /* 500 is not enough on a 486/33 */
+ while ((n>0) && ((inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK))
+ n--; /* wait for ready or exception or timeout */
+ if (n==0) {
+ /* n (above) should be chosen such that on your machine
+ * you rarely ever see the message below, and it should
+ * be small enough to give reasonable response time.]
+ */
+ tpqputs("waiting looong in rdstatus() -- drive dead?");
+ while ((inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK)
+ schedule();
+ tpqputs("finished waiting in rdstatus()");
+ }
+
+ (void) notify_cmd(qcmd, 1); /* send read status command */
+ /* ignore return code -- should always be ok, STAT may contain
+ * exception flag from previous exception which we are trying to clear.
+ */
+
+ if (TP_DIAGS(current_tape_dev))
+ printk(TPQIC_NAME ": reading status bytes: ");
+
+ for (q=stp; q<stp+size; q++)
+ {
+ do s = inb_p(QIC_STAT_PORT);
+ while ((s & QIC_STAT_MASK) == QIC_STAT_MASK); /* wait for ready or exception */
+
+ if ((s & QIC_STAT_EXCEPTION) == 0) { /* if exception */
+ tpqputs("rdstatus: exception error");
+ ioctl_status.mt_erreg = 0; /* dunno... */
+ return TE_NS; /* error, shouldn't happen... */
+ }
+
+ *q = inb_p(QIC_DATA_PORT); /* read status byte */
+
+ if (TP_DIAGS(current_tape_dev))
+ printk("[%1d]=0x%x ", q-stp, (unsigned) (*q) & 0xff);
+
+ outb_p(ctlbits | QIC_CTL_REQUEST, QIC_CTL_PORT); /* set request */
+
+ while ((inb_p(QIC_STAT_PORT) & QIC_STAT_READY) == 0); /* wait for not ready */
+
+ udelay(22); /* delay >20 usec */
+
+ outb_p(ctlbits & ~QIC_CTL_REQUEST, QIC_CTL_PORT); /* un-set request */
+
+ }
+
+ /* Specs say we should wait for READY here.
+ * My drive doesn't seem to need it here yet, but others do?
+ */
+ while (inb_p(QIC_STAT_PORT) & QIC_STAT_READY)
+ /*skip*/; /* wait for ready */
+
+ if (TP_DIAGS(current_tape_dev))
+ printk("\n");
+
+ return TE_OK;
+} /* rdstatus */
+
+
+
+/* Get standard status (6 bytes).
+ * The `.dec' and `.urc' fields are in MSB-first byte-order,
+ * so they have to be swapped first.
+ */
+static int get_status(char *stp)
+{
+ int stat = rdstatus(stp, TPSTATSIZE, QCMD_RD_STAT);
+#if defined(i386) || defined(i486)
+ byte_swap_w(&tperror.dec);
+ byte_swap_w(&tperror.urc);
+#else
+ /* should probably swap status bytes #definition */
+#endif
+ return stat;
+} /* get_status */
+
+
+#if 0
+/* This fails for my Wangtek drive */
+/* get "Extended Status Register 3" (64 bytes)
+ *
+ * If the meaning of the returned bytes were known, the MT_TYPE
+ * identifier could be used to decode them, since they are
+ * "vendor unique". :-(
+ */
+static int get_ext_status3(void)
+{
+ char vus[64]; /* vendor unique status */
+ int stat, i;
+
+ tpqputs("Attempting to read Extended Status 3...");
+ stat = rdstatus(vus, sizeof(vus), QCMD_RD_STAT_X3);
+ if (stat != TE_OK)
+ return stat;
+
+ tpqputs("Returned status bytes:");
+ for (i=0; i<sizeof(vus); i++) {
+ if ( i % 8 == 0 )
+ printk("\n" TPQIC_NAME ": %2d:");
+ printk(" %2x", vus[i] & 0xff);
+ }
+ printk("\n");
+
+ return TE_OK;
+} /* get_ext_status3 */
+#endif
+
+
+/* Read drive status and set generic status too.
+ * NOTE: Once we do a tp_sense(), read/write transfers are killed.
+ */
+static int tp_sense(int ignore)
+{
+ unsigned err = 0, exnr = 0, gs = 0;
+ static void finish_rw(int cmd);
+
+ printk(TPQIC_NAME ": tp_sense(ignore=0x%x) enter\n", ignore);
+
+ /* sense() is not allowed during a read or write cycle */
+ if (doing_write == YES)
+ tpqputs("Warning: File Mark inserted because of sense() request");
+ /* The extra test is to avoid calling finish_rw during booting */
+ if ((doing_read!=NO) || (doing_write!=NO))
+ finish_rw(QCMD_RD_STAT);
+
+ if (get_status((char *) &tperror) != TE_OK) {
+ tpqputs("tp_sense: could not read tape drive status");
+ return TE_ERR;
+ }
+
+ err = tperror.exs; /* get exception status bits */
+ if (err & (TP_ST0|TP_ST1))
+ printk(TPQIC_NAME ": tp_sense: status: %x, error count: %d, underruns: %d\n",
+ tperror.exs, tperror.dec, tperror.urc);
+ else
+ printk(TPQIC_NAME ": tp_sense: no errors at all, soft error count: %d, underruns: %d\n",
+ tperror.dec, tperror.urc);
+
+ /* Set generic status. HP-UX defines these, but some extra would
+ * be useful. Problem is to remain compatible. [Do we want to be
+ * compatible??]
+ */
+ if (err & TP_ST0) {
+ if (err & TP_CNI) /* no cartridge */
+ gs |= GMT_DR_OPEN(-1);
+ if (status_dead == NO)
+ gs |= GMT_ONLINE(-1); /* always online */
+ if (err & TP_USL) /* not online */
+ gs &= ~GMT_ONLINE(-1);
+ if (err & TP_WRP)
+ gs |= GMT_WR_PROT(-1);
+ if (err & TP_EOM) { /* end of media */
+ gs |= GMT_EOT(-1); /* not sure this is correct for writes */
+ status_eom_detected = YES;
+ /* I don't know whether drive always reports EOF at or before EOM. */
+ status_eof_detected = YES;
+ }
+ /** if (err & TP_UDA) "Unrecoverable data error" **/
+ /** if (err & TP_BNL) "Bad block not located" **/
+ if (err & TP_FIL) {
+ gs |= GMT_EOF(-1);
+ status_eof_detected = YES;
+ }
+ }
+ if (err & TP_ST1) {
+ /** if (err & TP_ILL) "Illegal command" **/
+ /** if (err & TP_NDT) "No data detected" **/
+ /** if (err & TP_MBD) "Marginal block detected" **/
+ if (err & TP_BOM)
+ gs |= GMT_BOT(-1); /* beginning of tape */
+ }
+ ioctl_status.mt_gstat = gs;
+ ioctl_status.mt_dsreg = tperror.exs; /* "drive status" */
+ ioctl_status.mt_erreg = tperror.dec; /* "sense key error" */
+
+ if (err!=0) {
+ exnr = decode_exception_nr(err);
+ handle_exception(exnr, err); /* update driver state wrt drive status */
+ report_exception(exnr);
+ }
+ err &= ~ignore; /* mask unwanted errors -- not the correct way, use exception nrs?? */
+ if (((err & TP_ST0) && (err & REPORT_ERR0)) ||
+ ((err & TP_ST1) && (err & REPORT_ERR1)))
+ return TE_ERR;
+ return TE_OK;
+} /* tp_sense */
+
+
+
+/* Wait for a wind or rewind operation to finish or
+ * to time-out. (May take very long).
+ */
+static int wait_for_rewind(time_t timeout)
+{
+ int stat;
+
+ stat = inb(QIC_STAT_PORT) & QIC_STAT_MASK;
+ printk(TPQIC_NAME ": Waiting for (re-)wind to finish: stat=0x%x\n", stat);
+
+ stat = wait_for_ready(timeout);
+
+ if (stat != TE_OK) {
+ tpqputs("(re-) winding failed\n");
+ }
+ return stat;
+} /* wait_for_rewind */
+
+
+
+/* Perform a full QIC02 command, and wait for completion,
+ * check status when done. Complain about exceptions.
+ *
+ * This function should return an OS error code when
+ * something goes wrong, 0 otherwise.
+ */
+static int ll_do_qic_cmd(int cmd, time_t timeout)
+{
+ int stat;
+
+ if (status_dead) {
+ tpqputs("Drive is dead. Do a `mt reset`.");
+ return -ENXIO; /* User should do an MTRESET. */
+ }
+
+ stat = wait_for_ready(timeout); /* wait for ready or exception */
+ if (stat == TE_EX) {
+ if (tp_sense(TP_WRP|TP_BOM|TP_EOM|TP_FIL)!=TE_OK)
+ return -EIO;
+ /* else nothing to worry about, I hope */
+ stat = TE_OK;
+ }
+ if (stat != TE_OK) {
+ printk(TPQIC_NAME ": ll_do_qic_cmd(%x, %d) failed\n", cmd, timeout);
+ return -EIO;
+ }
+
+
+#if OBSOLETE
+ /* wait for ready since it may not be active immediately after reading status */
+ while ((inb_p(QIC_STAT_PORT) & QIC_STAT_READY) != 0);
+#endif
+
+ stat = send_qic02_cmd(cmd, timeout, 0); /* (checks for exceptions) */
+
+ if (cmd==QCMD_RD_FM) {
+ status_eof_detected = NO;
+ ioctl_status.mt_fileno++;
+ /* Should update block count as well, but can't.
+ * Can do a `read address' for some drives, when MTNOP is done.
+ */
+ } else if (cmd==QCMD_WRT_FM) {
+ status_eof_detected = NO;
+ ioctl_status.mt_fileno++;
+ } else if ((cmd==QCMD_REWIND) || (cmd==QCMD_ERASE) || (cmd==QCMD_RETEN)) {
+ status_eof_detected = NO;
+ status_eom_detected = NO;
+ status_eot_detected = NO;
+ need_rewind = NO;
+ ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
+ extra_blocks_left = BLOCKS_BEYOND_EW;
+ return_write_eof = NO;
+ return_read_eof = NO;
+ reported_read_eof = NO;
+ reported_write_eof = NO;
+ }
+ /* sense() will set eof/eom as required */
+ if (stat==TE_EX) {
+ if (tp_sense(TP_WRP|TP_BOM|TP_EOM|TP_FIL)!=TE_OK) {
+ printk(TPQIC_NAME ": Exception persist in ll_do_qic_cmd[1](%x, %d)", cmd, timeout);
+ status_dead = YES;
+ return -ENXIO;
+ /* if rdstatus fails too, we're in trouble */
+ }
+ }
+ else if (stat!=TE_OK) {
+ printk(TPQIC_NAME ": ll_do_qic_cmd: send_qic02_cmd failed, stat = 0x%x\n", stat);
+ return -EIO; /*** -EIO is probably not always appropriate */
+ }
+
+
+ if (timeout == TIM_R)
+ stat = wait_for_rewind(timeout);
+ else
+ stat = wait_for_ready(timeout);
+
+ if (stat==TE_EX) {
+ if (tp_sense((cmd==QCMD_SEEK_EOD ? /*****************************/
+ TP_EOR|TP_NDT|TP_UDA|TP_BNL|TP_WRP|TP_BOM|TP_EOM|TP_FIL :
+ TP_WRP|TP_BOM|TP_EOM|TP_FIL))!=TE_OK) {
+ printk(TPQIC_NAME ": Exception persist in ll_do_qic_cmd[2](%x, %d)\n", cmd, timeout);
+ if (cmd!=QCMD_RD_FM)
+ status_dead = YES;
+ return -ENXIO;
+ /* if rdstatus fails too, we're in trouble */
+ }
+ }
+ else if (stat!=TE_OK) {
+ printk(TPQIC_NAME ": ll_do_qic_cmd %x: wait failed, stat == 0x%x\n", cmd, stat);
+ return -EIO;
+ }
+ return 0;
+} /* ll_do_qic_cmd */
+
+
+/*
+ * Problem: What to do when the user cancels a read/write operation
+ * in-progress?
+ *
+ * "Deactivating ONLINE during a READ also causes the"
+ * "tape to be rewound to BOT." Ditto for WRITEs, except
+ * a FM is written first. "The host may alternatively terminate
+ * the READ/WRITE command by issuing a RFM/WFM command."
+ *
+ * For READs:
+ * Neither option will leave the tape positioned where it was.
+ * Another (better?) solution is to terminate the READ by two
+ * subsequent sense() operations, the first to stop the current
+ * READ cycle, the second to clear the `Illegal command' exception,
+ * because the QIC-02 specs didn't anticipate this. This is
+ * delayed until actually needed, so a tar listing can be aborted
+ * by the user and continued later.
+ * If anybody has a better solution, let me know! [Also, let me
+ * know if your drive (mine is a Wangtek5150EQ) does not accept
+ * this sequence for canceling the read-cycle.]
+ *
+ * For WRITEs it's simple: Just do a WRITE_FM, leaving the tape
+ * positioned after the FM.
+ */
+
+static void terminate_read(int cmd)
+{
+ if (doing_read == YES) {
+ doing_read = NO;
+ if (cmd != QCMD_RD_FM) {
+ /* if the command is a RFM, there is no need to do this
+ * because a RFM will legally terminate the read-cycle.
+ */
+ tpqputs("terminating pending read-cycle");
+ if (tp_sense(TP_FIL|TP_EOM|TP_WRP) != TE_OK) {
+ tpqputs("finish_rw[read1]: ignore the 2 lines above");
+ if (is_exception()) {
+ if (tp_sense(TP_ILL|TP_FIL|TP_EOM|TP_WRP) != TE_OK)
+ tpqputs("finish_rw[read2]: read cycle error");
+ }
+ }
+ }
+ }
+} /* terminate_read */
+
+
+static void terminate_write(int cmd)
+{
+ int stat;
+
+ if (doing_write == YES) {
+ doing_write = NO;
+ /* Finish writing by appending a FileMark at the end. */
+ if (cmd != QCMD_WRT_FM) {
+ /* finish off write cycle */
+ stat = ll_do_qic_cmd(QCMD_WRT_FM, TIM_M);
+ if (stat != TE_OK)
+ tpqputs("Couldn't finish write cycle properly");
+ (void) tp_sense(0);
+ }
+ /* If there is an EOF token waiting to be returned to
+ * the (writing) application, discard it now.
+ * We could be at EOT, so don't reset return_write_eof.
+ */
+ reported_write_eof=YES;
+ }
+} /* terminate_write */
+
+
+/* terminate read or write cycle because of command `cmd' */
+static void finish_rw(int cmd)
+{
+ if (wait_for_ready(TIM_S) != TE_OK) {
+ tpqputs("error: drive not ready in finish_rw() !");
+ return;
+ }
+ terminate_read(cmd);
+ terminate_write(cmd);
+} /* finish_rw */
+
+
+/* Perform a QIC command through ll_do_qic_cmd().
+ * If necessary, rewind the tape first.
+ * Return an OS error code if something goes wrong, 0 if all is well.
+ */
+static int do_qic_cmd(int cmd, time_t timeout)
+{
+ int stat;
+
+
+ finish_rw(cmd);
+
+ if (need_rewind) {
+ tpqputs("Rewinding tape...");
+ stat = ll_do_qic_cmd(QCMD_REWIND, TIM_R);
+ if (stat != 0) {
+ printk(TPQIC_NAME ": rewind failed in do_qic_cmd(). stat=0x%2x", stat);
+ return stat;
+ }
+ need_rewind = NO;
+ if (cmd==QCMD_REWIND) /* don't wind beyond BOT ;-) */
+ return 0;
+ }
+
+ return ll_do_qic_cmd(cmd, timeout);
+} /* do_qic_cmd */
+
+
+/* Not all ioctls are supported for all drives. Some rely on
+ * optional QIC-02 commands. Check tpqic02.h for configuration.
+ * Some of these commands may require ONLINE to be active.
+ */
+static int do_ioctl_cmd(int cmd)
+{
+ int stat;
+
+ /* It is not permitted to read or wind the tape after bytes have
+ * been written. It is not permitted to write the tape while in
+ * read mode.
+ * We try to be kind and allow reading again after writing a FM...
+ */
+
+ switch (cmd) {
+ case MTRESET:
+ /* reset verbose */
+ return (tape_reset(1)==TE_OK)? 0 : -EIO;
+
+ case MTFSF:
+ tpqputs("MTFSF forward searching filemark");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ return do_qic_cmd(QCMD_RD_FM, TIM_F);
+
+ case MTBSF:
+#ifdef TP_HAVE_BSF
+ tpqputs("MTBSF backward searching filemark -- optional command");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ stat = do_qic_cmd(QCMD_RD_FM_BCK, TIM_F);
+#else
+ tpqputs("MTBSF not supported");
+ stat = -ENXIO;
+#endif
+ status_eom_detected = status_eof_detected = NO;
+ return stat;
+
+ case MTFSR:
+#ifdef TP_HAVE_FSR /* This is an optional QIC-02 command */
+ tpqputs("MTFSR forward space record");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ stat = do_qic_cmd(QCMD_SPACE_FWD, TIM_F);
+#else
+ /**** fake it by doing a read data block command? ******/
+ tpqputs("MTFSR not supported");
+ stat = -ENXIO;
+#endif
+ return stat;
+
+ case MTBSR:
+#ifdef TP_HAVE_BSR /* This is an optional QIC-02 command */
+ /* we need this for appending files with GNU tar!! */
+ tpqputs("MTFSR backward space record");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ stat = do_qic_cmd(QCMD_SPACE_BCK, TIM_F);
+#else
+ tpqputs("MTBSR not supported");
+ stat = -ENXIO;
+#endif
+ status_eom_detected = status_eof_detected = NO;
+ return stat;
+
+ case MTWEOF:
+ tpqputs("MTWEOF write eof mark");
+ /* Plain GNU mt(1) 2.2 uses read-only mode for writing FM. :-( */
+ if (mode_access==READ)
+ return -EACCES;
+
+ /* allow tape movement after writing FM */
+ status_bytes_rd = status_bytes_wr; /* Kludge-O-Matic */
+ status_bytes_wr = NO;
+ return do_qic_cmd(QCMD_WRT_FM, TIM_M);
+ /* not sure what to do with status_bytes when WFM should fail */
+
+ case MTREW:
+ tpqputs("MTREW rewinding tape");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ status_eom_detected = status_eof_detected = NO;
+ return do_qic_cmd(QCMD_REWIND, TIM_R);
+
+ case MTOFFL:
+ tpqputs("MTOFFL rewinding & going offline"); /*---*/
+ /******* What exactly are we supposed to do, to take it offline????
+ *****/
+ /* Doing a drive select will clear (unlock) the current drive.
+ * But that requires support for multiple drives and locking.
+ */
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ status_eom_detected = status_eof_detected = NO;
+ /**** do rewind depending on minor bits??? ***/
+ stat = do_qic_cmd(QCMD_REWIND, TIM_R);
+ return stat;
+
+ case MTNOP:
+ tpqputs("MTNOP setting status only");
+ /********** should do `read position' for drives that support it **********/
+ return (tp_sense(-1)==TE_OK)? 0 : -EIO; /**** check return codes ****/
+
+ case MTRETEN:
+ tpqputs("MTRETEN retension tape");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ status_eom_detected = status_eof_detected = NO;
+ return do_qic_cmd(QCMD_RETEN, TIM_R);
+
+ case MTBSFM:
+ /* Think think is like MTBSF, except that
+ * we shouldn't skip the FM. Tricky.
+ * Maybe use RD_FM_BCK, then do a SPACE_FWD?
+ */
+ tpqputs("MTBSFM not supported");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ return -ENXIO;
+
+ case MTFSFM:
+ /* I think this is like MTFSF, except that
+ * we shouldn't skip the FM. Tricky.
+ * Maybe use QCMD_RD_DATA until we get a TP_FIL exception?
+ * But then the FM will have been skipped...
+ * Maybe use RD_FM, then RD_FM_BCK, but not all
+ * drives will support that!
+ */
+ tpqputs("MTFSFM not supported");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ return -ENXIO;
+
+ case MTEOM:
+ /* This should leave the tape ready for appending
+ * another file to the end, such that it would append
+ * after the last FM on tape.
+ */
+ tpqputs("MTEOM search for End Of recorded Media");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+#ifdef TP_HAVE_EOD
+ /* Use faster seeking when possible.
+ * This requires the absence of data beyond the EOM.
+ */
+# if TAPE_QIC02_DRIVE == MT_ISWT5150
+ /* It seems that my drive does not always perform the
+ * SEEK_EOD correctly, unless it is preceded by a
+ * rewind command.
+ */
+# if 0
+ status_eom_detected = status_eof_detected = NO;
+# endif
+ stat = do_qic_cmd(QCMD_REWIND, TIM_R);
+ if (stat)
+ return stat;
+
+# endif
+ stat = do_qic_cmd(QCMD_SEEK_EOD, TIM_F);
+ /* After a successful seek, TP_EOR should be returned */
+#else
+ /* else just seek until the drive returns exception "No Data" */
+ stat = 0;
+ while ((stat==0) && (!status_eom_detected)) {
+ stat = do_qic_cmd(QCMD_RD_FM, TIM_F); /***** should use MTFSFM here???? ******/
+ }
+ if (tperror.exs & TP_NDT)
+ return 0;
+#endif
+ return stat;
+
+ case MTERASE:
+ tpqputs("MTERASE -- ERASE TAPE !");
+ if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
+ tpqputs("Cartridge is write-protected.");
+ return -EACCES;
+ } else {
+ time_t t = jiffies;
+ /* give user a few seconds to pull out tape */
+ while (jiffies - t < 3*HZ)
+ schedule();
+ }
+
+ /* Plain GNU mt(1) 2.2 erases a tape in O_RDONLY. :-( */
+ if (mode_access==READ)
+ return -EACCES;
+
+ /* don't bother writing filemark */
+ status_eom_detected = status_eof_detected = NO;
+ return do_qic_cmd(QCMD_ERASE, TIM_R);
+
+
+ case MTRAS1:
+#ifdef TP_HAVE_RAS1
+ tpqputs("MTRAS1: non-destructive self test");
+ stat = do_qic_cmd(QCMD_SELF_TST1, TIM_R);
+ if (stat != 0) {
+ tpqputs("RAS1 failed");
+ return stat;
+ }
+ return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */
+#else
+ tpqputs("RAS1 not supported");
+ return -ENXIO;
+#endif
+
+ case MTRAS2:
+#ifdef TP_HAVE_RAS2
+ tpqputs("MTRAS2: destructive self test");
+ stat = do_qic_cmd(QCMD_SELF_TST2, TIM_R);
+ if (stat != 0) {
+ tpqputs("RAS2 failed");
+ return stat;
+ }
+ return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */
+#else
+ tpqputs("RAS2 not supported");
+ return -ENXIO;
+#endif
+
+#ifdef TP_HAVE_SEEK
+ case MTSEEK:
+ tpqputs("MTSEEK seeking block");
+ if ((mode_access==WRITE) && status_bytes_wr)
+ return -EACCES;
+ /* NOTE: address (24 bits) is in seek_addr_buf[] */
+ return do_qic_cmd(QCMDV_SEEK_BLK, TIM_F);
+#endif
+
+ default:
+ return -ENOTTY;
+ }
+} /* do_ioctl_cmd */
+
+
+/* dma_transfer(): This routine is called for every 512 bytes to be read
+ * from/written to the tape controller. Speed is important here!
+ * (There must be enough time left for the hd controller!)
+ * When other devices use DMA they must ensure they use un-interruptible
+ * double byte accesses to the DMA controller. Floppy.c is ok.
+ * Must have interrupts disabled when this function is invoked,
+ * otherwise, the double-byte transfers to the DMA controller will not
+ * be atomic. That could lead to nasty problems when they are interrupted
+ * by other DMA interrupt-routines.
+ *
+ * This routine merely does the least possible to keep
+ * the transfers going:
+ * - set the DMA count register for the next 512 bytes
+ * - adjust the DMA address and page registers
+ * - adjust the timeout
+ * - tell the tape controller to start transferring
+ * We assume the dma address and mode are, and remain, valid.
+ */
+static inline void dma_transfer(void)
+{
+
+#if TAPE_QIC02_IFC == WANGTEK
+ outb_p(WT_CTL_ONLINE, QIC_CTL_PORT); /* back to normal */
+#elif TAPE_QIC02_IFC == ARCHIVE
+ outb_p(0, AR_RESET_DMA_PORT);
+#endif
+
+ clear_dma_ff(TAPE_QIC02_DMA);
+ set_dma_mode(TAPE_QIC02_DMA, dma_mode);
+ set_dma_addr(TAPE_QIC02_DMA, buffaddr+dma_bytes_done); /* full address */
+ set_dma_count(TAPE_QIC02_DMA, TAPE_BLKSIZE);
+
+ /* start tape DMA controller */
+#if TAPE_QIC02_IFC == WANGTEK
+ outb_p(WT_CTL_DMA | WT_CTL_ONLINE, QIC_CTL_PORT); /* trigger DMA transfer */
+#elif TAPE_QIC02_IFC == ARCHIVE
+ outb_p(AR_CTL_IEN | AR_CTL_DNIEN, QIC_CTL_PORT); /* enable interrupts again */
+ outb_p(0, AR_START_DMA_PORT); /* start DMA transfer */
+ /* In dma_end() AR_RESET_DMA_PORT is written too. */
+#endif
+
+ /* start computer DMA controller */
+ enable_dma(TAPE_QIC02_DMA);
+ /* block transfer should start now, jumping to the
+ * interrupt routine when done or an exception was detected.
+ */
+} /* dma_transfer */
+
+
+/* start_dma() sets a DMA transfer up between the tape controller and
+ * the kernel tape_qic02_buf buffer.
+ * Normally bytes_todo==dma_bytes_done at the end of a DMA transfer. If not,
+ * a filemark was read, or an attempt to write beyond the End Of Tape
+ * was made. [Or some other bad thing happened.]
+ * Must do a sense() before returning error.
+ */
+static int start_dma(short mode, unsigned long bytes_todo)
+/* assume 'bytes_todo'>0 */
+{
+ int stat;
+
+ TPQPUTS("start_dma() enter");
+ TPQDEB({printk(TPQIC_NAME ": doing_read==%d, doing_write==%d\n", doing_read, doing_write);})
+
+ dma_bytes_done = 0;
+ dma_bytes_todo = bytes_todo;
+ status_error = NO;
+ /* dma_mode!=0 indicates that the dma controller is in use */
+ dma_mode = (mode == WRITE)? DMA_MODE_WRITE : DMA_MODE_READ;
+
+ /* Only give READ/WRITE DATA command to tape drive if we haven't
+ * done that already. Otherwise the drive will rewind to the beginning
+ * of the current file on tape. Any QIC command given other than
+ * R/W FM will break the read/write transfer cycle.
+ * do_qic_cmd() will terminate doing_{read,write}
+ */
+ if ((doing_read == NO) && (doing_write == NO)) {
+ /* First, we have to clear the status -- maybe remove TP_FIL???
+ */
+
+#if 0
+ /* Next dummy get status is to make sure CNI is valid,
+ since we're only just starting a read/write it doesn't
+ matter some exceptions are cleared by reading the status;
+ we're only interested in CNI and WRP. -Eddy */
+ get_status((char *) &tperror);
+#else
+ /* TP_CNI should now be handled in open(). -Hennus */
+#endif
+
+ stat = tp_sense(((mode == WRITE)? 0 : TP_WRP) | TP_BOM | TP_FIL);
+ if (stat != TE_OK)
+ return stat;
+
+#if OBSOLETE
+ /************* not needed iff rd_status() would wait for ready!!!!!! **********/
+ if (wait_for_ready(TIM_S) != TE_OK) { /*** not sure this is needed ***/
+ tpqputs("wait_for_ready failed in start_dma");
+ return -EIO;
+ }
+#endif
+
+ /* Tell the controller the data direction */
+
+ /* r/w, timeout medium, check exceptions, sets status_cmd_pending. */
+ stat = send_qic02_cmd((mode == WRITE)? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);
+ if (stat!=TE_OK) {
+ printk(TPQIC_NAME ": start_dma: init %s failed\n",
+ (mode == WRITE)? "write" : "read");
+ (void) tp_sense(0);
+ return stat;
+ }
+
+ /* Do this last, because sense() will clear the doing_{read,write}
+ * flags, causing trouble next time around.
+ */
+ if (wait_for_ready(TIM_M) != TE_OK)
+ return -EIO;
+ switch (mode) {
+ case READ:
+ doing_read = YES;
+ break;
+ case WRITE:
+ doing_write = YES;
+ break;
+ default:
+ printk(TPQIC_NAME ": requested unknown mode %d\n", mode);
+ panic(TPQIC_NAME ": invalid mode in start_dma()");
+ }
+
+ } else if (is_exception()) {
+ /* This is for Archive drives, to handle reads with 0 bytes
+ * left for the last read request.
+ *
+ * ******** this also affects EOF/EOT handling! ************
+ */
+ tpqputs("detected exception in start_dma() while transfer in progress");
+ status_error = YES;
+ return TE_END;
+ }
+
+
+ status_expect_int = YES;
+
+ /* This assumes tape is already positioned, but these
+ * semi-'intelligent' drives are unpredictable...
+ */
+ TIMERON(TIM_M*2);
+
+ /* initiate first data block read from/write to the tape controller */
+
+ cli();
+ dma_transfer();
+ sti();
+
+ TPQPUTS("start_dma() end");
+ return TE_OK;
+} /* start_dma */
+
+
+/* This cleans up after the dma transfer has completed
+ * (or failed). If an exception occurred, a sense()
+ * must be done. If the exception was caused by a FM,
+ * sense() will set `status_eof_detected' and
+ * `status_eom_detected', as required.
+ */
+static void end_dma(unsigned long * bytes_done)
+{
+ int stat = TE_OK;
+
+ TIMEROFF;
+
+ TPQPUTS("end_dma() enter");
+
+ disable_dma(TAPE_QIC02_DMA);
+ clear_dma_ff(TAPE_QIC02_DMA);
+
+#if TAPE_QIC02_IFC == WANGTEK
+ outb_p(WT_CTL_ONLINE, QIC_CTL_PORT); /* back to normal */
+#elif TAPE_QIC02_IFC == ARCHIVE
+ outb_p(0, AR_RESET_DMA_PORT);
+#endif
+
+ stat = wait_for_ready(TIM_M);
+ if (status_error || (stat!=TE_OK)) {
+ tpqputs("DMA transfer exception");
+ stat = tp_sense((dma_mode==READ)? TP_WRP : 0);
+ /* no return here -- got to clean up first! */
+ }
+ /* take the tape controller offline */
+
+ /* finish off DMA stuff */
+
+
+ dma_mode = 0;
+ /* Note: The drive is left on-line, ready for the next
+ * data transfer.
+ * If the next command to the drive does not continue
+ * the pending cycle, it must do 2 sense()s first.
+ */
+
+ *bytes_done = dma_bytes_done;
+ status_expect_int = NO;
+ ioctl_status.mt_blkno += (dma_bytes_done / TAPE_BLKSIZE);
+
+ TPQPUTS("end_dma() exit");
+ /*** could return stat here ***/
+} /* end_dma */
+
+/*********** Below are the (public) OS-interface procedures ***********/
+
+
+/* tape_qic02_times_out() is called when a DMA transfer doesn't complete
+ * quickly enough. Usually this means there is something seriously wrong
+ * with the hardware/software, but it could just be that the controller
+ * has decided to do a long rewind, just when I didn't expect it.
+ * Just try again.
+ */
+static void tape_qic02_times_out(void)
+{
+ printk("time-out in %s driver\n", TPQIC_NAME);
+ if ((status_cmd_pending>0) || dma_mode) {
+ /* takes tooo long, shut it down */
+ status_dead = YES;
+ status_cmd_pending = 0;
+ status_timer_on = NO;
+ status_expect_int = NO;
+ status_error = YES;
+ if (dma_mode) {
+ dma_mode = 0; /* signal end to read/write routine */
+ wake_up(&tape_qic02_transfer);
+ }
+ }
+} /* tape_qic02_times_out */
+
+/*
+ * Interrupt handling:
+ *
+ * 1) Interrupt is generated iff at the end of
+ * a 512-DMA-block transfer.
+ * 2) EXCEPTION is not raised unless something
+ * is wrong or EOT/FM is detected.
+ * 3) FM EXCEPTION is set *after* the last byte has
+ * been transferred by DMA. By the time the interrupt
+ * is handled, the EXCEPTION may already be set.
+ *
+ * So,
+ * 1) On EXCEPTION, assume data has been transferred, so
+ * continue as usual, but set a flag to indicate the
+ * exception was detected.
+ * Do a sense status when the flag is found set.
+ * 2) Do not attempt to continue a transfer after an exception.
+ * [??? What about marginal blocks???????]
+ */
+
+
+/* tape_qic02_interrupt() is called when the tape controller completes
+ * a DMA transfer.
+ * We are not allowed to sleep here!
+ *
+ * Check if the transfer was successful, check if we need to transfer
+ * more. If the buffer contains enough data/is empty enough, signal the
+ * read/write() thread to copy to/from user space.
+ * When we are finished, set flags to indicate end, disable timer.
+ * NOTE: This *must* be fast!
+ */
+static void tape_qic02_interrupt(int unused)
+{
+ int stat, r, i;
+
+ TIMEROFF;
+
+ if (status_expect_int) {
+ if (TP_DIAGS(current_tape_dev))
+ printk("@");
+
+ stat = inb(QIC_STAT_PORT); /* Knock, knock */
+#if TAPE_QIC02_IFC == ARCHIVE /* "Who's there?" */
+ if (((stat & (AR_STAT_DMADONE)) == 0) &&
+ ((stat & (QIC_STAT_EXCEPTION)) != 0)) {
+ TIMERCONT;
+ return; /* "Linux with IRQ sharing" */
+ }
+#endif
+ if ((stat & QIC_STAT_EXCEPTION) == 0) { /* exception occurred */
+ /* Possible causes for an exception during a transfer:
+ * - during a write-cycle: end of tape (EW) hole detected.
+ * - during a read-cycle: filemark or EOD detected.
+ * - something went wrong
+ * So don't continue with the next block.
+ */
+ tpqputs("isr: exception on tape controller");
+ printk(" status %02x\n", stat);
+ status_error = TE_EX;
+
+ dma_bytes_done += TAPE_BLKSIZE;
+
+ dma_mode = 0; /* wake up rw() */
+ status_expect_int = NO;
+ wake_up(&tape_qic02_transfer);
+ return;
+ }
+ /* return if tape controller not ready, or
+ * if dma channel hasn't finished last byte yet.
+ */
+ r = 0;
+/* Skip next ready check for Archive controller because
+ * it may be busy reading ahead. Weird. --hhb
+ */
+#if TAPE_QIC02_IFC != ARCHIVE /* I think this is a drive-dependency, not IFC -- hhb */
+ if (stat & QIC_STAT_READY) { /* not ready */
+ tpqputs("isr: ? Tape controller not ready");
+ r = 1;
+ }
+#endif
+
+ if ( (i = get_dma_residue(TAPE_QIC02_DMA)) != 0 ) {
+ printk(TPQIC_NAME ": dma_residue == %x !!!\n", i);
+ r = 1; /* big trouble, but can't do much about it... */
+ }
+
+ if (r)
+ return;
+
+ /* finish DMA cycle */
+
+ /* no errors detected, continue */
+ dma_bytes_done += TAPE_BLKSIZE;
+ if (dma_bytes_done >= dma_bytes_todo) {
+ /* finished! Wakeup rw() */
+ dma_mode = 0;
+ status_expect_int = NO;
+ TPQPUTS("isr: dma_bytes_done");
+ wake_up(&tape_qic02_transfer);
+ } else {
+ /* start next transfer, account for track-switching time */
+ timer_table[TAPE_QIC02_TIMER].expires = jiffies + 6*HZ;
+ dma_transfer();
+ }
+ } else {
+ printk(TPQIC_NAME ": Unexpected interrupt, stat == %x\n",
+ inb(QIC_STAT_PORT));
+ }
+} /* tape_qic02_interrupt */
+
+
+static int tape_qic02_lseek(struct inode * inode, struct file * file, off_t offset, int origin)
+{
+ return -EINVAL; /* not supported */
+} /* tape_qic02_lseek */
+
+
+/* read/write routines:
+ * This code copies between a kernel buffer and a user buffer. The
+ * actual data transfer is done using DMA and interrupts. Time-outs
+ * are also used.
+ *
+ * When a filemark is read, we return '0 bytes read' and continue with the
+ * next file after that.
+ * When EOM is read, we return '0 bytes read' twice.
+ * When the EOT marker is detected on writes, '0 bytes read' should be
+ * returned twice. If user program does a MTNOP after that, 2 additional
+ * blocks may be written. ------- FIXME: Implement this correctly *************************************************
+ *
+ * Only read/writes in multiples of 512 bytes are accepted.
+ * When no bytes are available, we sleep() until they are. The controller will
+ * generate an interrupt, and we (should) get a wake_up() call.
+ *
+ * Simple buffering is used. User program should ensure that a large enough
+ * buffer is used. Usually the drive does some buffering as well (something
+ * like 4k or so).
+ *
+ * Scott S. Bertilson suggested to continue filling the user buffer, rather
+ * than waste time on a context switch, when the kernel buffer fills up.
+ */
+
+/*
+ * Problem: tar(1) doesn't always read the entire file. Sometimes the entire file
+ * has been read, but the EOF token is never returned to tar(1), simply because
+ * tar(1) knows it has already read all of the data it needs. So we must use
+ * open/release to reset the `reported_read_eof' flag. If we don't, the next read
+ * request would return the EOF flag for the previous file.
+ */
+
+static int tape_qic02_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ int error;
+ dev_t dev = inode->i_rdev;
+ unsigned short flags = filp->f_flags;
+ unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
+ int stat;
+
+ if (TP_DIAGS(current_tape_dev))
+ printk(TPQIC_NAME ": request READ, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n",
+ MINOR(dev), buf, count, filp->f_pos, flags);
+
+ if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */
+ tpqputs("Wrong block size");
+ return -EINVAL;
+ }
+
+ /* Just assume everything is ok. Controller will scream if not. */
+
+ if (status_bytes_wr) /* Once written, no more reads, 'till after WFM. */
+ return -EACCES;
+
+
+ /* Make sure buffer is safe to write into. */
+ error = verify_area(VERIFY_WRITE, buf, count);
+ if (error) {
+ printk(TPQIC_NAME ": read: verify_area(WRITE, %lx, %x) failed\n", buf, count);
+ return error;
+ }
+
+ /* This is rather ugly because it has to implement a finite state
+ * machine in order to handle the EOF situations properly.
+ */
+ while (count>=0) {
+ bytes_done = 0;
+ /* see how much fits in the kernel buffer */
+ bytes_todo = TPQBUF_SIZE;
+ if (bytes_todo>count)
+ bytes_todo = count;
+
+ /* Must ensure that user program sees exactly one EOF token (==0) */
+ if (return_read_eof==YES) {
+ printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%d\n", return_read_eof, reported_read_eof, total_bytes_done);
+
+ if (reported_read_eof==NO) {
+ /* have not yet returned EOF to user program */
+ if (total_bytes_done>0) {
+ return total_bytes_done; /* next time return EOF */
+ } else {
+ reported_read_eof = YES; /* move on next time */
+ return 0; /* return EOF */
+ }
+ } else {
+ /* Application program has already received EOF
+ * (above), now continue with next file on tape,
+ * if possible.
+ * When the FM is reached, EXCEPTION is set,
+ * causing a sense(). Subsequent read/writes will
+ * continue after the FM.
+ */
+/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/
+ if (status_eom_detected)
+ /* If EOM, nothing left to read, so keep returning EOFs.
+ *** should probably set some flag to avoid clearing
+ *** status_eom_detected through ioctls or something
+ */
+ return 0;
+ else {
+ /* just eof, there may be more files ahead... */
+ return_read_eof = NO;
+ reported_read_eof = NO;
+ status_eof_detected = NO; /* reset this too */
+ /*fall through*/
+ }
+ }
+ }
+
+/*****************************/
+ if (bytes_todo==0)
+ return total_bytes_done;
+
+ if (bytes_todo>0) {
+ /* start reading data */
+ if (is_exception()) /****************************************/
+ tpqputs("is_exception() before start_dma()!");
+/******************************************************************
+ ***** if start_dma() fails because the head is positioned 0 bytes
+ ***** before the FM, (causing EXCEPTION to be set) return_read_eof should
+ ***** be set to YES, and we should return total_bytes_done, rather than -ENXIO.
+ ***** The app should recognize this as an EOF condition.
+ ***************************************************************************/
+ stat = start_dma(READ, bytes_todo);
+ if (stat == TE_OK) {
+ /* Wait for transfer to complete, interrupt should wake us */
+ while (dma_mode != 0) {
+ sleep_on(&tape_qic02_transfer);
+ }
+ if (status_error)
+ return_read_eof = YES;
+ } else if (stat != TE_END) {
+ /* should do sense() on error here */
+#if 0
+ return -ENXIO;
+#else
+ printk("Trouble: stat==%02x\n", stat);
+ return_read_eof = YES;
+ /*************** check EOF/EOT handling!!!!!! **/
+#endif
+ }
+ end_dma(&bytes_done);
+ if (bytes_done>bytes_todo) {
+ tpqputs("read: Oops, read more bytes than requested");
+ return -EIO;
+ }
+ /* copy buffer to user-space in one go */
+ if (bytes_done>0)
+ memcpy_tofs( (void *) buf, (void *) buffaddr, bytes_done);
+#if 1
+ /* Checks Ton's patch below */
+ if ((return_read_eof == NO) && (status_eof_detected == YES)) {
+ printk(TPQIC_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof);
+ }
+#endif
+ if ((bytes_todo != bytes_done) || (status_eof_detected == YES))
+ /* EOF or EOM detected. return EOF next time. */
+ return_read_eof = YES;
+ } /* else: ignore read request for 0 bytes */
+
+ if (bytes_done>0) {
+ status_bytes_rd = YES;
+ buf += bytes_done;
+ filp->f_pos += bytes_done;
+ total_bytes_done += bytes_done;
+ count -= bytes_done;
+ }
+ }
+ tpqputs("read request for <0 bytes");
+ return -EINVAL;
+} /* tape_qic02_read */
+
+
+
+/* The drive detects near-EOT by means of the holes in the tape.
+ * When the holes are detected, there is some space left. The drive
+ * reports this as a TP_EOM exception. After clearing the exception,
+ * the drive should accept two extra blocks.
+ *
+ * It seems there are some archiver programs that would like to use the
+ * extra space for writing a continuation marker. The driver should return
+ * end-of-file to the user program on writes, when the holes are detected.
+ * If the user-program wants to use the extra space, it should use the
+ * MTNOP ioctl() to get the generic status register and may then continue
+ * writing (max 1kB). ----------- doesn't work yet...............
+ *
+ * EOF behaviour on writes:
+ * If there is enough room, write all of the data.
+ * If there is insufficient room, write as much as will fit and
+ * return the amount written. If the requested amount differs from the
+ * written amount, the application program should recognize that as the
+ * end of file. Subsequent writes will return -ENOSPC.
+ * Unless the minor bits specify a rewind-on-close, the tape will not
+ * be rewound when it is full. The user-program should do that, if desired.
+ * If the driver were to do that automatically, a user-program could be
+ * confused about the EOT/BOT condition after re-opening the tape device.
+ *
+ * Multiple volume support: Tar closes the tape device before prompting for
+ * the next tape. The user may then insert a new tape and tar will open the
+ * tape device again. The driver will detect an exception status in (No Cartridge)
+ * and force a rewind. After that tar may continue writing.
+ */
+static int tape_qic02_write(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ int error;
+ dev_t dev = inode->i_rdev;
+ unsigned short flags = filp->f_flags;
+ unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
+
+ if (TP_DIAGS(current_tape_dev))
+ printk(TPQIC_NAME ": request WRITE, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n",
+ MINOR(dev), buf, count, filp->f_pos, flags);
+
+ if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */
+ tpqputs("Wrong block size");
+ return -EINVAL;
+ }
+
+ if (mode_access==READ) {
+ tpqputs("Not in write mode");
+ return -EACCES;
+ }
+
+ /* open() does a sense() and we can assume the tape isn't changed
+ * between open() and release(), so the tperror.exs bits will still
+ * be valid.
+ */
+ if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {
+ tpqputs("Cartridge is write-protected.");
+ return -EACCES; /* don't even try when write protected */
+ }
+
+ /* Make sure buffer is safe to read from. */
+ error = verify_area(VERIFY_READ, buf, count);
+ if (error) {
+ printk(TPQIC_NAME ": write: verify_area(READ, %lx, %x) failed\n", buf, count);
+ return error;
+ }
+
+ if (doing_read == YES)
+ terminate_read(0);
+
+ while (count>=0) {
+ /* see how much fits in the kernel buffer */
+ bytes_done = 0;
+ bytes_todo = TPQBUF_SIZE;
+ if (bytes_todo>count)
+ bytes_todo = count;
+
+ if (return_write_eof == YES) {
+ /* return_write_eof should be reset on reverse tape movements. */
+
+ if (reported_write_eof==NO) {
+ if (bytes_todo>0) {
+ tpqputs("partial write");
+ /* partial write signals EOF to user program */
+ }
+ reported_write_eof = YES;
+ return total_bytes_done;
+ } else {
+ return -ENOSPC; /* return error */
+ }
+ }
+
+ /* Quit when done. */
+ if (bytes_todo==0)
+ return total_bytes_done;
+
+
+ /* copy from user to DMA buffer and initiate transfer. */
+ if (bytes_todo>0) {
+ memcpy_fromfs( (void *) buffaddr, (void *) buf, bytes_todo);
+
+/****************** similar problem with read() at FM could happen here at EOT.
+ ******************/
+
+/***** if at EOT, 0 bytes can be written. start_dma() will
+ ***** fail and write() will return ENXIO error
+ *****/
+ if (start_dma(WRITE, bytes_todo) != TE_OK) {
+ tpqputs("write: start_dma() failed");
+ /* should do sense() on error here */
+ return -ENXIO; /*********** FIXTHIS **************/
+ }
+
+ /* Wait for write to complete, interrupt should wake us. */
+ while ((status_error == 0) && (dma_mode != 0)) {
+ sleep_on(&tape_qic02_transfer);
+ }
+
+ end_dma(&bytes_done);
+ if (bytes_done>bytes_todo) {
+ tpqputs("write: Oops, wrote more bytes than requested");
+ return -EIO;
+ }
+ /* If the dma-transfer was aborted because of an exception,
+ * status_error will have been set in the interrupt handler.
+ * Then end_dma() will do a sense().
+ * If the exception was EXC_EOM, the EW-hole was encountered
+ * and two more blocks could be written. For the time being we'll
+ * just consider this to be the EOT.
+ * Otherwise, something Bad happened, such as the maximum number
+ * of block-rewrites was exceeded. [e.g. A very bad spot on tape was
+ * encountered. Normally short dropouts are compensated for by
+ * rewriting the block in error, up to 16 times. I'm not sure
+ * QIC-24 drives can do this.]
+ */
+ if (status_error) {
+ if (status_eom_detected == YES) {
+ tpqputs("write: EW detected");
+ return_write_eof = YES;
+ } else {
+ /* probably EXC_RWA */
+ tpqputs("write: dma: error in writing");
+ return -EIO;
+ }
+ }
+ if (bytes_todo != bytes_done)
+ /* EOF or EOM detected. return EOT next time. */
+ return_write_eof = YES;
+ }
+ /* else: ignore write request for 0 bytes. */
+
+ if (bytes_done>0) {
+ status_bytes_wr = YES;
+ buf += bytes_done;
+ filp->f_pos += bytes_done;
+ total_bytes_done += bytes_done;
+ count -= bytes_done;
+ }
+ }
+ tpqputs("write request for <0 bytes");
+ printk(TPQIC_NAME ": status_bytes_wr %x, buf %x, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count);
+ return -EINVAL;
+} /* tape_qic02_write */
+
+
+
+/* tape_qic02_open()
+ * We allow the device to be opened, even if it is marked 'dead' because
+ * we want to be able to reset the tape device without rebooting.
+ * Only one open tape file at a time, except when minor=255.
+ * Minor 255 is only allowed for resetting and always returns <0.
+ *
+ * The density command is only allowed when TP_BOM is set. Thus, remember
+ * the most recently used minor bits. When they are different from the
+ * remembered values, rewind the tape and set the required density.
+ * Don't rewind if the minor bits specify density 0.
+ */
+static int tape_qic02_open(struct inode * inode, struct file * filp)
+{
+ dev_t dev = inode->i_rdev;
+ unsigned short flags = filp->f_flags;
+ unsigned short dens;
+ int s;
+
+ status_open = NO;
+
+ if (TP_DIAGS(dev)) {
+ printk("tape_qic02_open: dev=%x, flags=%x ", dev, flags);
+ }
+
+ if (MINOR(dev)==255) /* special case for resetting */
+ if (suser())
+ return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
+ else
+ return -EPERM;
+
+ if (status_open==YES) {
+ return -EBUSY; /* only one at a time... */
+ }
+ status_open = YES;
+
+ status_bytes_rd = NO;
+ status_bytes_wr = NO;
+
+ return_read_eof = NO; /********????????????????*****/
+ return_write_eof = (status_eot_detected)? YES : NO;
+
+ /* Clear this in case user app close()d before reading EOF token */
+ status_eof_detected = NO;
+
+ reported_read_eof = NO;
+ reported_write_eof = NO;
+
+
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ mode_access = READ;
+ break;
+ case O_WRONLY: /* Fallthru... Strictly speaking this is not correct... */
+ case O_RDWR: /* reads are allowed as long as nothing is written */
+ mode_access = WRITE;
+ break;
+ }
+
+
+ /* This is to avoid tape-changed problems (TP_CNI exception). */
+ if (is_exception()) {
+ s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR);
+ if (s != TE_OK) {
+ status_open = NO;
+ tpqputs("open: sense() failed after exception was detected");
+ return -EIO;
+ }
+ }
+
+
+ /* not allowed to do QCMD_DENS_* unless tape is rewound */
+ if ((TP_DENS(dev)!=0) && (TP_DENS(current_tape_dev) != TP_DENS(dev))) {
+ /* force rewind if minor bits have changed,
+ * i.e. user wants to use tape in different format.
+ * [assuming single drive operation]
+ */
+ tpqputs("Density minor bits have changed. Forcing rewind.");
+ need_rewind = YES;
+ } else {
+ /* density bits still the same, but TP_DIAGS bit
+ * may have changed.
+ */
+ current_tape_dev = dev;
+ }
+
+ if (need_rewind == YES) {
+ s = do_qic_cmd(QCMD_REWIND, TIM_R);
+ if (s != 0) {
+ tpqputs("open: rewind failed");
+ status_open = NO;
+ return -EIO;
+ }
+ }
+
+
+/* Note: After a reset command, the controller will rewind the tape
+ * just before performing any tape movement operation!
+ */
+ if (status_dead) {
+ tpqputs("open: tape dead, attempting reset");
+ if (tape_reset(1)!=TE_OK) {
+ status_open = NO;
+ return -ENXIO;
+ } else {
+ status_dead = NO;
+ if (tp_sense(~(TP_ST1|TP_ILL)) != TE_OK) {
+ tpqputs("open: tp_sense() failed\n");
+ status_dead = YES; /* try reset next time */
+ status_open = NO;
+ return -EIO;
+ }
+ }
+ }
+
+ /* things should be ok, once we get here */
+
+
+ /* set density: only allowed when TP_BOM status bit is set,
+ * so we must have done a rewind by now. If not, just skip over.
+ * Only give set density command when minor bits have changed.
+ */
+ if (TP_DENS(current_tape_dev) == TP_DENS(dev) )
+ return 0;
+
+ current_tape_dev = dev;
+ need_rewind = NO;
+ dens = TP_DENS(dev);
+ if (dens < sizeof(format_names)/sizeof(char *))
+ printk(TPQIC_NAME ": format: %s%s\n", (dens!=0)? "QIC-" : "", format_names[dens]);
+ else
+ tpqputs("Wait for retensioning...");
+
+ switch (TP_DENS(dev)) {
+ case 0: /* This one's for Eddy ;-) */
+ s = 0;
+ break;
+ case 1:
+ s = do_qic_cmd(QCMD_DENS_11, TIM_S);
+ break;
+ case 2:
+ s = do_qic_cmd(QCMD_DENS_24, TIM_S);
+ break;
+ case 3:
+ s = do_qic_cmd(QCMD_DENS_120, TIM_S);
+ break;
+ case 4:
+ s = do_qic_cmd(QCMD_DENS_150, TIM_S);
+ break;
+ case 5:
+ s = do_qic_cmd(QCMD_DENS_300, TIM_S);
+ break;
+ case 6:
+ s = do_qic_cmd(QCMD_DENS_600, TIM_S);
+ break;
+ default: /* otherwise do a retension before anything else */
+ s = do_qic_cmd(QCMD_RETEN, TIM_R);
+ }
+ if (s != 0) {
+ status_open = NO; /* fail if fault occurred */
+ status_dead = YES; /* force reset */
+ current_tape_dev = 0xff80;
+ return -EIO;
+ }
+
+ return 0;
+} /* tape_qic02_open */
+
+
+static int tape_qic02_readdir(struct inode * inode, struct file * filp, struct dirent * dp, int count)
+{
+ return -ENOTDIR; /* not supported */
+} /* tape_qic02_readdir */
+
+
+static void tape_qic02_release(struct inode * inode, struct file * filp)
+{
+ dev_t dev = inode->i_rdev;
+
+ if (TP_DIAGS(dev))
+ printk("tape_qic02_release: dev=%x\n", dev);
+
+ /* Terminate any pending write cycle. Terminating the read-cycle
+ * is delayed until it is required to do so for a new command.
+ */
+ terminate_write(-1);
+
+ if (status_dead==YES)
+ tpqputs("release: device dead!?");
+
+ if (status_open==NO) {
+ tpqputs("release: device not open");
+ return;
+ }
+ /* Rewind only if minor number requires it AND
+ * read/writes have been done.
+ */
+ if ((TP_REWCLOSE(dev)) && (status_bytes_rd | status_bytes_wr)) {
+ tpqputs("release: Doing rewind...");
+ (void) do_qic_cmd(QCMD_REWIND, TIM_R);
+ }
+
+ status_open = NO;
+ return;
+} /* tape_qic02_release */
+
+
+
+/* ioctl allows user programs to rewind the tape and stuff like that */
+static int tape_qic02_ioctl(struct inode * inode, struct file * filp,
+ unsigned int iocmd, unsigned long ioarg)
+{
+ int error;
+ short i;
+ int dev_maj = MAJOR(inode->i_rdev);
+ int c;
+ struct mtop operation;
+ char *stp, *argp;
+
+#ifdef TP_HAVE_TELL
+ unsigned char blk_addr[6];
+ struct mtpos ioctl_tell;
+#endif
+
+ if (TP_DIAGS(current_tape_dev))
+ printk(TPQIC_NAME ": ioctl(%4x, %4x, %4x)\n", dev_maj, iocmd, ioarg);
+
+ if (!inode || !ioarg)
+ return -EINVAL;
+
+ /* check iocmd first */
+
+ if (dev_maj != TAPE_QIC02_MAJOR) {
+ printk(TPQIC_NAME ": Oops! Wrong device?\n");
+ /* A panic() would be appropriate here */
+ return -ENODEV;
+ }
+
+ c = iocmd & IOCCMD_MASK;
+ if (c == (MTIOCTOP & IOCCMD_MASK)) {
+
+ /* Compare expected struct size and actual struct size. This
+ * is useful to catch programs compiled with old #includes.
+ */
+ if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtop)) {
+ tpqputs("sizeof(struct mtop) does not match!");
+ return -EFAULT;
+ }
+ error = verify_area(VERIFY_READ, (char *) ioarg, sizeof(operation));
+ if (error)
+ return error;
+
+ /* copy mtop struct from user space to kernel space */
+ stp = (char *) &operation;
+ argp = (char *) ioarg;
+ for (i=0; i<sizeof(operation); i++)
+ *stp++ = get_fs_byte(argp++);
+
+ /* ---note: mt_count is signed, negative seeks must be
+ * --- translated to seeks in opposite direction!
+ * (only needed for Sun-programs, I think.)
+ */
+ /* ---note: MTFSF with count 0 should position the
+ * --- tape at the beginning of the current file.
+ */
+
+ if (TP_DIAGS(current_tape_dev))
+ printk("OP op=%4x, count=%4x\n", operation.mt_op, operation.mt_count);
+
+ if (operation.mt_count < 0)
+ tpqputs("Warning: negative mt_count ignored");
+
+ ioctl_status.mt_resid = operation.mt_count;
+ if (operation.mt_op == MTSEEK) {
+ seek_addr_buf[0] = (operation.mt_count>>16)&0xff;
+ seek_addr_buf[1] = (operation.mt_count>>8)&0xff;
+ seek_addr_buf[2] = (operation.mt_count)&0xff;
+ if (operation.mt_count>>24)
+ return -EINVAL;
+
+ if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
+ return error;
+ ioctl_status.mt_resid = 0;
+ } else {
+ while (operation.mt_count > 0) {
+ operation.mt_count--;
+ if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
+ return error;
+ ioctl_status.mt_resid = operation.mt_count;
+ }
+ }
+ return 0;
+
+ } else if (c == (MTIOCGET & IOCCMD_MASK)) {
+ if (TP_DIAGS(current_tape_dev))
+ printk("GET ");
+
+ /* compare expected struct size and actual struct size */
+ if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtget)) {
+ tpqputs("sizeof(struct mtget) does not match!");
+ return -EFAULT;
+ }
+
+ /* check for valid user address */
+ error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_status));
+ if (error)
+ return error;
+
+ /* It appears (gmt(1)) that it is normal behaviour to
+ * first set the status with MTNOP, and then to read
+ * it out with MTIOCGET
+ */
+
+ /* copy results to user space */
+ stp = (char *) &ioctl_status;
+ argp = (char *) ioarg;
+ for (i=0; i<sizeof(ioctl_status); i++)
+ put_fs_byte(*stp++, argp++);
+ return 0;
+
+#ifdef TP_HAVE_TELL
+ } else if (c == (MTIOCPOS & IOCCMD_MASK)) {
+ if (TP_DIAGS(current_tape_dev))
+ printk("POS ");
+
+ /* compare expected struct size and actual struct size */
+ if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtpos)) {
+ tpqputs("sizeof(struct mtpos) does not match!");
+ return -EFAULT;
+ }
+
+ /* check for valid user address */
+ error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_tell));
+ if (error)
+ return error;
+
+ tpqputs("MTTELL reading block address");
+ if ((doing_read==YES) || (doing_write==YES))
+ finish_rw(QCMDV_TELL_BLK);
+
+ c = rdstatus((char *) blk_addr, sizeof(blk_addr), QCMDV_TELL_BLK);
+ if (c!=TE_OK)
+ return -EIO;
+
+ ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
+
+ /* copy results to user space */
+ stp = (char *) &ioctl_tell;
+ argp = (char *) ioarg;
+ for (i=0; i<sizeof(ioctl_tell); i++)
+ put_fs_byte(*stp++, argp++);
+ return 0;
+#endif
+ } else
+ return -ENOTTY; /* Other cmds not supported. */
+} /* tape_qic02_ioctl */
+
+
+
+/* These are (most) of the interface functions: */
+static struct file_operations tape_qic02_fops = {
+ tape_qic02_lseek, /* not allowed */
+ tape_qic02_read, /* read */
+ tape_qic02_write, /* write */
+ tape_qic02_readdir, /* not allowed */
+ NULL, /* select ??? */
+ tape_qic02_ioctl, /* ioctl */
+ NULL, /* mmap not allowed */
+ tape_qic02_open, /* open */
+ tape_qic02_release, /* release */
+ NULL /* fsync */
+};
+
+
+/* Attribute `SA_INTERRUPT' makes the interrupt atomic with
+ * interrupts disabled. We could do without the atomic stuff, but
+ * then dma_transfer() would have to disable interrupts explicitly.
+ * System load is high enough as it is :-(
+ */
+static struct sigaction tape_qic02_sigaction = {
+ tape_qic02_interrupt,
+ 0,
+ SA_INTERRUPT,
+ NULL
+};
+
+
+/* align `a' at `size' bytes. `size' must be a power of 2 */
+static inline unsigned long const align_buffer(unsigned long a, unsigned size)
+{
+ if (a & (size-1)) /* if not aligned */
+ return (a | (size-1)) + 1;
+ else /* else is aligned */
+ return a;
+}
+
+
+/* init() is called from chr_dev_init() in kernel/chr_drv/mem.c */
+long tape_qic02_init(long kmem_start)
+ /* Shouldn't this be a caddr_t ? */
+{
+
+ printk(TPQIC_NAME ": IRQ %d, DMA %d, IO %xh, IFC %s, %s, %s\n",
+ TAPE_QIC02_IRQ, TAPE_QIC02_DMA, TAPE_QIC02_PORT,
+#if TAPE_QIC02_IFC == WANGTEK
+ "Wangtek",
+#elif TAPE_QIC02_IFC == ARCHIVE
+ "Archive",
+#else
+# error
+#endif
+ rcs_revision, rcs_date);
+
+ /* First perform some checks. If one of them fails,
+ * the tape driver will not be registered to the system.
+ */
+
+ /* Should do IRQ/DMA allocation in open(). Use free_irq() in release()
+ * return -EBUSY, if allocation fails in open().
+ * Make IRQ settable/readable through ioctls. DMA is trickier because
+ * some bits change for different DMA numbers. Also, this would add
+ * runtime overhead for having the dma channel number be a variable
+ * rather than a constant. Probably need to make the DMA stuff #ifdef'd
+ * to choose between hardcoded and changeable DMA channel.
+ *
+ * Also, Linux needs a more generic way to set DMA/IRQ and other stuff.
+ * Right now, this is done differently for every device. (setserial,
+ * ctrlaltdel, setdfprm, setfdthr, tunelp, ((setterm))...)
+ *
+ * #include <hint.h>
+ */
+
+ /* get IRQ */
+ if (irqaction(TAPE_QIC02_IRQ, &tape_qic02_sigaction)) {
+ printk(TPQIC_NAME ": can't allocate IRQ%d for QIC-02 tape\n",
+ TAPE_QIC02_IRQ);
+ return kmem_start;
+ }
+
+ /* After IRQ, allocate DMA channel */
+ if (request_dma(TAPE_QIC02_DMA)) {
+ printk(TPQIC_NAME ": can't allocate DMA%d for QIC-02 tape\n",
+ TAPE_QIC02_DMA);
+ free_irq(TAPE_QIC02_IRQ);
+ return kmem_start;
+ }
+
+ if (TPSTATSIZE != 6) {
+ printk(TPQIC_NAME ": internal error: tpstatus struct incorrect!\n");
+ return kmem_start;
+ }
+ if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000)) {
+ printk(TPQIC_NAME ": internal error: DMA buffer size out of range\n");
+ return kmem_start;
+ }
+
+ printk(TPQIC_NAME ": DMA buffers: %u blocks", NR_BLK_BUF);
+
+ /* Setup the page-address for the dma transfer.
+ * This assumes a one-to-one identity mapping between
+ * kernel addresses and physical memory.
+ */
+ buffaddr = align_buffer((unsigned long) &tape_qic02_buf, TAPE_BLKSIZE);
+ printk(", at address 0x%lx (0x%lx)\n", buffaddr, (unsigned long) &tape_qic02_buf);
+
+#ifndef CONFIG_MAX_16M
+ if (buffaddr+TPQBUF_SIZE>=0x1000000) {
+ printk(TPQIC_NAME ": DMA buffer *must* be in lower 16MB\n");
+ return kmem_start;
+ }
+#endif
+
+ /* If we got this far, install driver functions */
+ if (register_chrdev(TAPE_QIC02_MAJOR, TPQIC_NAME, &tape_qic02_fops)) {
+ printk(TPQIC_NAME ": Unable to get chrdev major %d\n", TAPE_QIC02_MAJOR);
+ return kmem_start;
+ }
+
+ /* prepare timer */
+ TIMEROFF;
+ timer_table[TAPE_QIC02_TIMER].expires = 0;
+ timer_table[TAPE_QIC02_TIMER].fn = tape_qic02_times_out;
+
+ if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) {
+ status_dead = YES;
+ } else {
+ if (is_exception()) {
+ tpqputs("exception detected\n");
+ (void) tp_sense(TP_WRP|TP_POR|TP_CNI);
+ }
+ }
+
+ /* initialize generic status for ioctl requests */
+
+ ioctl_status.mt_type = TAPE_QIC02_DRIVE; /* MT_IS* id nr */
+
+ ioctl_status.mt_resid = 0; /* ---residual count */
+ ioctl_status.mt_gstat = 0; /* ---generic status */
+ ioctl_status.mt_erreg = 0; /* not used */
+ ioctl_status.mt_fileno = 0; /* number of current file on tape */
+ ioctl_status.mt_blkno = 0; /* number of current (logical) block */
+
+ return kmem_start;
+} /* tape_qic02_init */
+
+
+#endif /* CONFIG_TAPE_QIC02 */
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 0551af6..a81db13 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -79,13 +79,13 @@ static int tty_select(struct inode *, struct file *, int, select_table *);
static int tty_open(struct inode *, struct file *);
static void tty_release(struct inode *, struct file *);
-int tty_register_ldisc(int disc, struct tty_ldisc *new)
+int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
{
if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;
- if (new) {
- ldiscs[disc] = *new;
+ if (new_ldisc) {
+ ldiscs[disc] = *new_ldisc;
ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
} else
memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
@@ -98,13 +98,14 @@ void put_tty_queue(char c, struct tty_queue * queue)
int head;
unsigned long flags;
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
head = (queue->head + 1) & (TTY_BUF_SIZE-1);
if (head != queue->tail) {
queue->buf[queue->head] = c;
queue->head = head;
}
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
int get_tty_queue(struct tty_queue * queue)
@@ -112,12 +113,13 @@ int get_tty_queue(struct tty_queue * queue)
int result = -1;
unsigned long flags;
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
if (queue->tail != queue->head) {
result = 0xff & queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
}
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
return result;
}
@@ -133,8 +135,9 @@ int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen)
unsigned char *p = bufp;
unsigned long flags;
int head, tail;
-
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+
+ save_flags(flags);
+ cli();
tail = tty->read_q.tail;
head = tty->read_q.head;
while ((result < buflen) && (tail!=head)) {
@@ -143,7 +146,7 @@ int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen)
result++;
}
tty->read_q.tail = tail;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
return result;
}
@@ -155,7 +158,7 @@ void tty_write_flush(struct tty_struct * tty)
if (set_bit(TTY_WRITE_BUSY,&tty->flags))
return;
tty->write(tty);
- if (clear_bit(TTY_WRITE_BUSY,&tty->flags))
+ if (!clear_bit(TTY_WRITE_BUSY,&tty->flags))
printk("tty_write_flush: bit already cleared\n");
}
@@ -166,7 +169,7 @@ void tty_read_flush(struct tty_struct * tty)
if (set_bit(TTY_READ_BUSY, &tty->flags))
return;
ldiscs[tty->disc].handler(tty);
- if (clear_bit(TTY_READ_BUSY, &tty->flags))
+ if (!clear_bit(TTY_READ_BUSY, &tty->flags))
printk("tty_read_flush: bit already cleared\n");
}
@@ -281,7 +284,7 @@ void tty_unhangup(struct file *filp)
filp->f_op = &tty_fops;
}
-inline int tty_hung_up_p(struct file * filp)
+int tty_hung_up_p(struct file * filp)
{
return ((filp->f_op == &hung_up_tty_fops) ||
(filp->f_op == &vhung_up_tty_fops));
@@ -494,7 +497,7 @@ void copy_to_cooked(struct tty_struct * tty)
save_flags(flags); cli();
if (tty->read_q.tail != tty->read_q.head) {
c = 0xff & tty->read_q.buf[tty->read_q.tail];
- special_flag = !clear_bit(tty->read_q.tail,
+ special_flag = clear_bit(tty->read_q.tail,
&tty->readq_flags);
tty->read_q.tail = (tty->read_q.tail + 1) &
(TTY_BUF_SIZE-1);
@@ -677,10 +680,10 @@ void copy_to_cooked(struct tty_struct * tty)
if (tty->write_q.proc_list && LEFT(&tty->write_q) > TTY_BUF_SIZE/2)
wake_up_interruptible(&tty->write_q.proc_list);
if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
- && !clear_bit(TTY_RQ_THROTTLED, &tty->flags))
+ && clear_bit(TTY_RQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
- && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
+ && clear_bit(TTY_SQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
}
@@ -782,7 +785,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
* now, let the low-level driver know.
*/
if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
- && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
+ && clear_bit(TTY_SQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
if (b-buf >= minimum || !current->timeout)
break;
@@ -1438,9 +1441,10 @@ int tty_write_data(struct tty_struct *tty, char *bufp, int buflen,
#define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1))
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
if (tty->write_data_cnt) {
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
return -EBUSY;
}
@@ -1457,11 +1461,11 @@ int tty_write_data(struct tty_struct *tty, char *bufp, int buflen,
tty->write_q.head = head;
if (count) {
tty->write_data_cnt = count;
- tty->write_data_ptr = p;
+ tty->write_data_ptr = (unsigned char *) p;
tty->write_data_callback = callback;
tty->write_data_arg = callarg;
}
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
tty->write(tty);
return count;
}
@@ -1487,7 +1491,7 @@ void tty_bh_routine(void * unused)
continue;
}
for (j=0, mask=0; j < 32; j++, line++, mask <<= 1) {
- if (!clear_bit(j, &tty_check_write[i])) {
+ if (clear_bit(j, &tty_check_write[i])) {
tty = tty_table[line];
if (!tty || !tty->write_data_cnt)
continue;
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index e7f071b..5557a5c 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -12,6 +12,7 @@
#include <linux/termios.h>
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
@@ -31,6 +32,11 @@ extern int session_of_pgrp(int pgrp);
extern int do_screendump(int arg);
extern int kill_pg(int pgrp, int sig, int priv);
+#ifdef CONFIG_SELECTION
+extern int set_selection(const int arg);
+extern int paste_selection(struct tty_struct *tty);
+#endif /* CONFIG_SELECTION */
+
static void flush(struct tty_queue * queue)
{
if (queue) {
@@ -211,14 +217,14 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
/* take care of the packet stuff. */
if ((tmp_termio.c_iflag & IXON) &&
- ~(tty->termios->c_iflag & IXON))
+ !(tty->termios->c_iflag & IXON))
{
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_DOSTOP;
}
- if (~(tmp_termio.c_iflag & IXON) &&
- (tty->termios->c_iflag & IXON))
+ if ((tty->termios->c_iflag & IXON) &&
+ !(tmp_termio.c_iflag & IXON))
{
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_NOSTOP;
@@ -448,6 +454,12 @@ int tty_ioctl(struct inode * inode, struct file * file,
return do_screendump(arg);
case 1:
return do_get_ps_info(arg);
+#ifdef CONFIG_SELECTION
+ case 2:
+ return set_selection(arg);
+ case 3:
+ return paste_selection(tty);
+#endif /* CONFIG_SELECTION */
default:
return -EINVAL;
}
diff --git a/kernel/chr_drv/vt.c b/kernel/chr_drv/vt.c
index d1bb6df..1e27f23 100644
--- a/kernel/chr_drv/vt.c
+++ b/kernel/chr_drv/vt.c
@@ -34,7 +34,8 @@
struct vt_cons vt_cons[NR_CONSOLES];
-extern int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern "C" int sys_ioperm(unsigned long from, unsigned long num, int on);
+
extern void change_console(unsigned int new_console);
extern void complete_change_console(unsigned int new_console);
extern int vt_waitactive(void);
@@ -138,7 +139,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
if (!i)
- put_fs_byte(KB_101, (unsigned char *) arg);
+ put_fs_byte(KB_101, (char *) arg);
return i;
case KDADDIO:
@@ -229,11 +230,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
u_char s;
verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
- if ((i = get_fs_byte(&a->kb_index)) >= NR_KEYS)
+ if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
return -EINVAL;
- if ((s = get_fs_byte(&a->kb_table)) >= NR_KEYMAPS)
+ if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS)
return -EINVAL;
- put_fs_word(key_map[s][i], &a->kb_value);
+ put_fs_word(key_map[s][i], (short *) &a->kb_value);
return 0;
}
@@ -245,9 +246,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
u_short v;
verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
- if ((i = get_fs_byte(&a->kb_index)) >= NR_KEYS)
+ if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
return -EINVAL;
- if ((s = get_fs_byte(&a->kb_table)) >= NR_KEYMAPS)
+ if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS)
return -EINVAL;
if (KTYP(v = get_fs_word(&a->kb_value)) >= NR_TYPES)
return -EINVAL;
@@ -268,7 +269,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ucval |= LED_NUM;
if (vc_kbd_flag(kbd, VC_CAPSLOCK))
ucval |= LED_CAP;
- put_fs_byte(ucval, (unsigned char *) arg);
+ put_fs_byte(ucval, (char *) arg);
return 0;
case KDSETLED:
diff --git a/kernel/chr_drv/vt_kern.h b/kernel/chr_drv/vt_kern.h
index 7df7f9f..6341140 100644
--- a/kernel/chr_drv/vt_kern.h
+++ b/kernel/chr_drv/vt_kern.h
@@ -18,4 +18,6 @@ extern struct vt_cons {
int vt_newvt;
} vt_cons[NR_CONSOLES];
+void kd_mksound(unsigned int count, unsigned int ticks);
+
#endif /* _VT_KERN_H */
diff --git a/kernel/exit.c b/kernel/exit.c
index 3e0c7fb..8882395 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -19,7 +19,6 @@
extern void shm_exit (void);
extern void sem_exit (void);
-int sys_close(int fd);
int getrusage(struct task_struct *, int, struct rusage *);
static int generate(unsigned long sig, struct task_struct * p)
@@ -273,7 +272,7 @@ int kill_proc(int pid, int sig, int priv)
* POSIX specifies that kill(-1,sig) is unspecified, but what we have
* is probably wrong. Should make it like BSD or SYSV.
*/
-int sys_kill(int pid,int sig)
+extern "C" int sys_kill(int pid,int sig)
{
struct task_struct **p = NR_TASKS + task;
int err, retval = 0, count = 0;
@@ -366,10 +365,21 @@ fake_volatile:
current->root = NULL;
iput(current->executable);
current->executable = NULL;
- for (i=0; i < current->numlibraries; i++) {
- iput(current->libraries[i].library);
- current->libraries[i].library = NULL;
- }
+ /* Release all of the old mmap stuff. */
+
+ {
+ struct vm_area_struct * mpnt, *mpnt1;
+ mpnt = current->mmap;
+ current->mmap = NULL;
+ while (mpnt) {
+ mpnt1 = mpnt->vm_next;
+ if (mpnt->vm_ops->close)
+ mpnt->vm_ops->close(mpnt);
+ kfree(mpnt);
+ mpnt = mpnt1;
+ }
+ }
+
current->state = TASK_ZOMBIE;
current->exit_code = code;
current->rss = 0;
@@ -466,12 +476,12 @@ fake_volatile:
goto fake_volatile;
}
-int sys_exit(int error_code)
+extern "C" int sys_exit(int error_code)
{
do_exit((error_code&0xff)<<8);
}
-int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
+extern "C" int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
{
int flag, retval;
struct wait_queue wait = { current, NULL };
@@ -562,7 +572,7 @@ end_wait4:
* sys_waitpid() remains for compatibility. waitpid() should be
* implemented by calling sys_wait4() from libc.a.
*/
-int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
+extern "C" int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
return sys_wait4(pid, stat_addr, options, NULL);
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 777c36b..88e769a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -18,15 +18,17 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/segment.h>
+#include <linux/ptrace.h>
#include <asm/segment.h>
#include <asm/system.h>
-extern void lcall7(void);
+extern "C" void lcall7(void);
+extern "C" void ret_from_sys_call(void) __asm__("ret_from_sys_call");
#define MAX_TASKS_PER_USER (NR_TASKS/2)
-extern int shm_fork (struct task_struct *, struct task_struct *);
+extern int shm_fork(struct task_struct *, struct task_struct *);
long last_pid=0;
static int find_empty_process(void)
@@ -46,7 +48,7 @@ repeat:
if (task[i]->pid == last_pid || task[i]->pgrp == last_pid)
goto repeat;
}
- if (this_user_tasks > MAX_TASKS_PER_USER && !suser())
+ if (this_user_tasks > MAX_TASKS_PER_USER && current->uid)
return -EAGAIN;
/* Only the super-user can fill the last available slot */
task_nr = 0;
@@ -61,62 +63,78 @@ repeat:
return -EAGAIN;
}
-static struct file * copy_fd(struct file * old)
+static struct file * copy_fd(struct file * old_file)
{
- struct file * new = get_empty_filp();
+ struct file * new_file = get_empty_filp();
int error;
- if (new) {
- memcpy(new,old,sizeof(*new));
- new->f_count = 1;
- if (new->f_inode)
- new->f_inode->i_count++;
- if (new->f_op && new->f_op->open) {
- error = new->f_op->open(new->f_inode,new);
+ if (new_file) {
+ memcpy(new_file,old_file,sizeof(struct file));
+ new_file->f_count = 1;
+ if (new_file->f_inode)
+ new_file->f_inode->i_count++;
+ if (new_file->f_op && new_file->f_op->open) {
+ error = new_file->f_op->open(new_file->f_inode,new_file);
if (error) {
- iput(new->f_inode);
- new->f_count = 0;
- new = NULL;
+ iput(new_file->f_inode);
+ new_file->f_count = 0;
+ new_file = NULL;
}
}
}
- return new;
+ return new_file;
}
-#define IS_CLONE (orig_eax == __NR_clone)
-#define copy_vm(p) ((clone_flags & COPYVM)?copy_page_tables:clone_page_tables)(p)
+int dup_mmap(struct task_struct * tsk)
+{
+ struct vm_area_struct * mpnt, **p, *tmp;
+
+ tsk->mmap = NULL;
+ p = &tsk->mmap;
+ for (mpnt = current->mmap ; mpnt ; mpnt = mpnt->vm_next) {
+ tmp = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ *tmp = *mpnt;
+ tmp->vm_task = tsk;
+ tmp->vm_next = NULL;
+ if (tmp->vm_inode)
+ tmp->vm_inode->i_count++;
+ *p = tmp;
+ p = &tmp->vm_next;
+ }
+ return 0;
+}
+
+#define IS_CLONE (regs.orig_eax == __NR_clone)
+#define copy_vm(p) ((clone_flags & COPYVM)?copy_page_tables(p):clone_page_tables(p))
/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
* also copies the data segment in it's entirety.
*/
-int sys_fork(long ebx,long ecx,long edx,
- long esi, long edi, long ebp, long eax, long ds,
- long es, long fs, long gs, long orig_eax,
- long eip,long cs,long eflags,long esp,long ss)
+extern "C" int sys_fork(struct pt_regs regs)
{
+ struct pt_regs * childregs;
struct task_struct *p;
int i,nr;
struct file *f;
unsigned long clone_flags = COPYVM | SIGCHLD;
- p = (struct task_struct *) get_free_page(GFP_KERNEL);
+ p = (struct task_struct *) __get_free_page(GFP_KERNEL);
if (!p)
- return -EAGAIN;
+ goto bad_fork;
nr = find_empty_process();
- if (nr < 0) {
- free_page((unsigned long) p);
- return nr;
- }
+ if (nr < 0)
+ goto bad_fork_free;
task[nr] = p;
*p = *current;
p->kernel_stack_page = 0;
p->state = TASK_UNINTERRUPTIBLE;
p->flags &= ~(PF_PTRACED|PF_TRACESYS);
p->pid = last_pid;
- if (p->pid > 1)
- p->swappable = 1;
+ p->swappable = 1;
p->p_pptr = p->p_opptr = current;
p->p_cptr = NULL;
SET_LINKS(p);
@@ -129,49 +147,46 @@ int sys_fork(long ebx,long ecx,long edx,
p->min_flt = p->maj_flt = 0;
p->cmin_flt = p->cmaj_flt = 0;
p->start_time = jiffies;
- p->tss.back_link = 0;
+/*
+ * set up new TSS and kernel stack
+ */
+ p->kernel_stack_page = __get_free_page(GFP_KERNEL);
+ if (!p->kernel_stack_page)
+ goto bad_fork_cleanup;
+ p->tss.es = KERNEL_DS;
+ p->tss.cs = KERNEL_CS;
+ p->tss.ss = KERNEL_DS;
+ p->tss.ds = KERNEL_DS;
+ p->tss.fs = KERNEL_DS;
+ p->tss.gs = KERNEL_DS;
p->tss.ss0 = KERNEL_DS;
- p->tss.eip = eip;
- p->tss.eflags = eflags & 0xffffcfff; /* iopl is always 0 for a new process */
- p->tss.eax = 0;
- p->tss.ecx = ecx;
- p->tss.edx = edx;
- p->tss.ebx = ebx;
- p->tss.esp = esp;
+ p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
+ p->tss.tr = _TSS(nr);
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ p->tss.esp = (unsigned long) childregs;
+ p->tss.eip = (unsigned long) ret_from_sys_call;
+ *childregs = regs;
+ childregs->eax = 0;
+ p->tss.back_link = 0;
+ p->tss.eflags = regs.eflags & 0xffffcfff; /* iopl is always 0 for a new process */
if (IS_CLONE) {
- if (ebx)
- p->tss.esp = ebx;
- clone_flags = ecx;
- if (p->tss.esp == current->tss.esp)
+ if (regs.ebx)
+ childregs->esp = regs.ebx;
+ clone_flags = regs.ecx;
+ if (childregs->esp == regs.esp)
clone_flags |= COPYVM;
}
p->exit_signal = clone_flags & CSIGNAL;
- p->tss.ebp = ebp;
- p->tss.esi = esi;
- p->tss.edi = edi;
- p->tss.es = es & 0xffff;
- p->tss.cs = cs & 0xffff;
- p->tss.ss = ss & 0xffff;
- p->tss.ds = ds & 0xffff;
- p->tss.fs = fs & 0xffff;
- p->tss.gs = gs & 0xffff;
p->tss.ldt = _LDT(nr);
- p->tss.trace_bitmap = offsetof(struct tss_struct,io_bitmap) << 16;
+ p->tss.bitmap = offsetof(struct tss_struct,io_bitmap);
set_call_gate(p->ldt+0,lcall7);
- for (i = 0; i<IO_BITMAP_SIZE ; i++)
+ for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
p->tss.io_bitmap[i] = ~0;
if (last_task_used_math == current)
- __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
- p->kernel_stack_page = get_free_page(GFP_KERNEL);
+ __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
p->semun = NULL; p->shm = NULL;
- if (!p->kernel_stack_page || copy_vm(p) || shm_fork (current, p)) {
- task[nr] = NULL;
- REMOVE_LINKS(p);
- free_page(p->kernel_stack_page);
- free_page((long) p);
- return -EAGAIN;
- }
- p->tss.esp0 = PAGE_SIZE + p->kernel_stack_page;
+ if (copy_vm(p) || shm_fork(current, p))
+ goto bad_fork_cleanup;
if (clone_flags & COPYFD) {
for (i=0; i<NR_OPEN;i++)
if ((f = p->filp[i]) != NULL)
@@ -187,12 +202,18 @@ int sys_fork(long ebx,long ecx,long edx,
current->root->i_count++;
if (current->executable)
current->executable->i_count++;
- for (i=0; i < current->numlibraries ; i++)
- if (current->libraries[i].library)
- current->libraries[i].library->i_count++;
+ dup_mmap(p);
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
p->counter = current->counter >> 1;
p->state = TASK_RUNNING; /* do this last, just in case */
return p->pid;
+bad_fork_cleanup:
+ task[nr] = NULL;
+ REMOVE_LINKS(p);
+ free_page(p->kernel_stack_page);
+bad_fork_free:
+ free_page((long) p);
+bad_fork:
+ return -EAGAIN;
}
diff --git a/kernel/info.c b/kernel/info.c
index 452afe2..cf6fa43 100644
--- a/kernel/info.c
+++ b/kernel/info.c
@@ -14,7 +14,7 @@
#include <linux/types.h>
#include <linux/mm.h>
-int sys_sysinfo(struct sysinfo *info)
+extern "C" int sys_sysinfo(struct sysinfo *info)
{
int error;
struct sysinfo val;
diff --git a/kernel/ioport.c b/kernel/ioport.c
index 0fde696..87a55b6 100644
--- a/kernel/ioport.c
+++ b/kernel/ioport.c
@@ -43,22 +43,23 @@ static void dump_io_bitmap(void)
/*
* this changes the io permissions bitmap in the current task.
*/
-int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+extern "C" int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
unsigned long froml, lindex, tnum, numl, rindex, mask;
unsigned long *iop;
+ if (from + num <= from)
+ return -EINVAL;
+ if (from + num > IO_BITMAP_SIZE*32)
+ return -EINVAL;
+ if (!suser())
+ return -EPERM;
froml = from >> 5;
lindex = from & 0x1f;
tnum = lindex + num;
numl = (tnum + 0x1f) >> 5;
rindex = tnum & 0x1f;
- if (!suser())
- return -EPERM;
- if (froml * 32 + tnum > sizeof(current->tss.io_bitmap) * 8 - 8)
- return -EINVAL;
-
#ifdef IODEBUG
printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
#endif
@@ -104,7 +105,7 @@ unsigned int *stack;
* on system-call entry - see also fork() and the signal handling
* code.
*/
-int sys_iopl(long ebx,long ecx,long edx,
+extern "C" int sys_iopl(long ebx,long ecx,long edx,
long esi, long edi, long ebp, long eax, long ds,
long es, long fs, long gs, long orig_eax,
long eip,long cs,long eflags,long esp,long ss)
diff --git a/kernel/irq.c b/kernel/irq.c
index 9d503ae..3fd8b43 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -34,10 +34,10 @@
#define CR0_NE 32
-static unsigned long intr_count=0;
static unsigned char cache_21 = 0xff;
static unsigned char cache_A1 = 0xff;
+unsigned long intr_count = 0;
unsigned long bh_active = 0;
unsigned long bh_mask = 0xFFFFFFFF;
struct bh_struct bh_base[32];
@@ -45,19 +45,29 @@ struct bh_struct bh_base[32];
/*
* do_bottom_half() runs at normal kernel priority: all interrupts
* enabled. do_bottom_half() is atomic with respect to itself: a
- * bottom_half handler need not be re-entrant. This function is
- * called only when bh_active is non-zero and when there aren't any
- * nested irq's active.
+ * bottom_half handler need not be re-entrant.
*/
-void do_bottom_half(int nr)
+extern "C" void do_bottom_half(void)
{
+ unsigned long active;
+ unsigned long mask, left;
struct bh_struct *bh;
- bh = bh_base+nr;
- if (bh->routine != NULL)
- bh->routine(bh->data);
- else
- printk ("irq.c:bad bottom half entry (%d).\n",nr);
+ bh = bh_base;
+ active = bh_active & bh_mask;
+ for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
+ if (mask & active) {
+ void (*fn)(void *);
+ bh_active &= ~mask;
+ fn = bh->routine;
+ if (!fn)
+ goto bad_bh;
+ fn(bh->data);
+ }
+ }
+ return;
+bad_bh:
+ printk ("irq.c:bad bottom half entry\n");
}
/*
@@ -146,7 +156,7 @@ static struct sigaction irq_sigaction[16] = {
* IRQ's should use this format: notably the keyboard/timer
* routines.
*/
-void do_IRQ(int irq, struct pt_regs * regs)
+extern "C" void do_IRQ(int irq, struct pt_regs * regs)
{
struct sigaction * sa = irq + irq_sigaction;
@@ -158,14 +168,14 @@ void do_IRQ(int irq, struct pt_regs * regs)
* stuff - the handler is also running with interrupts disabled unless
* it explicitly enables them later.
*/
-void do_fast_IRQ(int irq)
+extern "C" void do_fast_IRQ(int irq)
{
struct sigaction * sa = irq + irq_sigaction;
sa->sa_handler(irq);
}
-int irqaction(unsigned int irq, struct sigaction * new)
+int irqaction(unsigned int irq, struct sigaction * new_sa)
{
struct sigaction * sa;
unsigned long flags;
@@ -175,11 +185,11 @@ int irqaction(unsigned int irq, struct sigaction * new)
sa = irq + irq_sigaction;
if (sa->sa_mask)
return -EBUSY;
- if (!new->sa_handler)
+ if (!new_sa->sa_handler)
return -EINVAL;
save_flags(flags);
cli();
- *sa = *new;
+ *sa = *new_sa;
sa->sa_mask = 1;
if (sa->sa_flags & SA_INTERRUPT)
set_intr_gate(0x20+irq,fast_interrupt[irq]);
@@ -245,14 +255,17 @@ void free_irq(unsigned int irq)
* (ie as explained in the intel litterature). On a 386, you
* can't use exception 16 due to bad IBM design, so we have to
* rely on the less exact irq13.
+ *
+ * Careful.. Not only is IRQ13 unreliable, but it is also
+ * leads to races. IBM designers who came up with it should
+ * be shot.
*/
static void math_error_irq(int cpl)
{
outb(0,0xF0);
if (ignore_irq13)
return;
- send_sig(SIGFPE, last_task_used_math, 1);
- __asm__("fninit");
+ math_error();
}
static void no_action(int cpl) { }
diff --git a/kernel/itimer.c b/kernel/itimer.c
index e9d42fa..e7f507d 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -53,7 +53,7 @@ int _getitimer(int which, struct itimerval *value)
return(0);
}
-int sys_getitimer(int which, struct itimerval *value)
+extern "C" int sys_getitimer(int which, struct itimerval *value)
{
int error;
struct itimerval get_buffer;
@@ -98,7 +98,7 @@ int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
return 0;
}
-int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
+extern "C" int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
int error;
struct itimerval set_buffer, get_buffer;
diff --git a/kernel/panic.c b/kernel/panic.c
index 01b43ef..2e8bdd7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -11,10 +11,13 @@
#include <linux/kernel.h>
#include <linux/sched.h>
-void sys_sync(void); /* it's really int */
+extern "C" void sys_sync(void); /* it's really int */
volatile void panic(const char * s)
{
+ extern int log_to_console;
+
+ log_to_console = 1;
printk("Kernel panic: %s\n",s);
if (current == task[0])
printk("In swapper task - not syncing\n");
diff --git a/kernel/printk.c b/kernel/printk.c
index b3be769..f577da1 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -45,7 +45,7 @@ struct wait_queue * log_wait = NULL;
* 6 -- Disable printk's to console
* 7 -- Enable printk's to console
*/
-int sys_syslog(int type, char * buf, int len)
+extern "C" int sys_syslog(int type, char * buf, int len)
{
unsigned long i, j, count;
int do_clear = 0;
@@ -118,7 +118,7 @@ int sys_syslog(int type, char * buf, int len)
}
-int printk(const char *fmt, ...)
+extern "C" int printk(const char *fmt, ...)
{
va_list args;
int i,j;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index fbe35d5..1e70ff9 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -126,11 +126,11 @@ repeat:
page = *((unsigned long *) page);
}
if (!(page & PAGE_PRESENT)) {
- do_no_page(0,addr,tsk,0);
+ do_no_page(PAGE_RW,addr,tsk,0);
goto repeat;
}
if (!(page & PAGE_RW)) {
- do_wp_page(0,addr,tsk,0);
+ do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0);
goto repeat;
}
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
@@ -218,7 +218,7 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
return 0;
}
-int sys_ptrace(long request, long pid, long addr, long data)
+extern "C" int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -380,7 +380,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
}
}
-void syscall_trace(void)
+extern "C" void syscall_trace(void)
{
if ((current->flags & (PF_PTRACED|PF_TRACESYS))
!= (PF_PTRACED|PF_TRACESYS))
diff --git a/kernel/sched.c b/kernel/sched.c
index 79c7f5b..7c46bb0 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -11,8 +11,6 @@
* current-task
*/
-#define TIMER_IRQ 0
-
#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -24,15 +22,19 @@
#include <linux/time.h>
#include <linux/ptrace.h>
#include <linux/segment.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
+#define TIMER_IRQ 0
+
int need_resched = 0;
int hard_math = 0; /* set by boot/head.S */
int ignore_irq13 = 0; /* set if exception 16 works */
+extern int _setitimer(int, struct itimerval *, struct itimerval *);
unsigned long * prof_buffer = NULL;
unsigned long prof_len = 0;
@@ -43,10 +45,10 @@ unsigned long prof_len = 0;
extern void mem_use(void);
extern int timer_interrupt(void);
-extern int system_call(void);
+extern "C" int system_call(void);
static unsigned long init_kernel_stack[1024];
-static struct task_struct init_task = INIT_TASK;
+struct task_struct init_task = INIT_TASK;
unsigned long volatile jiffies=0;
unsigned long startup_time=0;
@@ -70,22 +72,26 @@ struct {
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
+ *
+ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
+ * Don't touch unless you *really* know how it works.
*/
-void math_state_restore(void)
+extern "C" void math_state_restore(void)
{
+ __asm__ __volatile__("clts");
if (last_task_used_math == current)
return;
timer_table[COPRO_TIMER].expires = jiffies+50;
timer_active |= 1<<COPRO_TIMER;
- if (last_task_used_math) {
- __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
- }
- __asm__("fwait");
+ if (last_task_used_math)
+ __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
+ else
+ __asm__("fnclex");
last_task_used_math = current;
if (current->used_math) {
- __asm__("frstor %0"::"m" (current->tss.i387));
+ __asm__("frstor %0": :"m" (current->tss.i387));
} else {
- __asm__("fninit"::);
+ __asm__("fninit");
current->used_math=1;
}
timer_active &= ~(1<<COPRO_TIMER);
@@ -99,50 +105,57 @@ void math_state_restore(void)
* NOTE!! Task 0 is the 'idle' task, which gets called when no other
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
* information in task[0] is never used.
+ *
+ * The "confuse_gcc" goto is used only to get better assembly code..
+ * Djikstra probably hates me.
*/
-void schedule(void)
+extern "C" void schedule(void)
{
- int i,next,c;
- struct task_struct ** p;
+ int c;
+ struct task_struct * p;
+ struct task_struct * next;
/* check alarm, wake up any interruptible tasks that have got a signal */
+ sti();
need_resched = 0;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!*p || ((*p)->state != TASK_INTERRUPTIBLE))
+ p = &init_task;
+ for (;;) {
+ if ((p = p->next_task) == &init_task)
+ goto confuse_gcc1;
+ if (p->state != TASK_INTERRUPTIBLE)
continue;
- if ((*p)->timeout && (*p)->timeout < jiffies) {
- (*p)->timeout = 0;
- (*p)->state = TASK_RUNNING;
- } else if ((*p)->signal & ~(*p)->blocked)
- (*p)->state = TASK_RUNNING;
+ if (p->signal & ~p->blocked) {
+ p->state = TASK_RUNNING;
+ continue;
+ }
+ if (p->timeout && p->timeout < jiffies) {
+ p->timeout = 0;
+ p->state = TASK_RUNNING;
+ }
}
+confuse_gcc1:
/* this is the scheduler proper: */
- while (1) {
- c = -1;
- next = 0;
- i = NR_TASKS;
- p = &task[NR_TASKS];
- while (--i) {
- if (!*--p)
- continue;
- if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
- c = (*p)->counter, next = i;
- }
- if (c)
- break;
- for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
- if (*p)
- (*p)->counter = ((*p)->counter >> 1) +
- (*p)->priority;
+ c = -1;
+ next = p = &init_task;
+ for (;;) {
+ if ((p = p->next_task) == &init_task)
+ goto confuse_gcc2;
+ if (p->state == TASK_RUNNING && p->counter > c)
+ c = p->counter, next = p;
+ }
+confuse_gcc2:
+ if (!c) {
+ p = &init_task;
+ while ((p = p->next_task) != &init_task)
+ p->counter = (p->counter >> 1) + p->priority;
}
- sti();
switch_to(next);
}
-int sys_pause(void)
+extern "C" int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
schedule();
@@ -396,55 +409,59 @@ static void do_timer(struct pt_regs * regs)
sti();
}
-int sys_alarm(long seconds)
+extern "C" int sys_alarm(long seconds)
{
- extern int _setitimer(int, struct itimerval *, struct itimerval *);
- struct itimerval new, old;
-
- new.it_interval.tv_sec = new.it_interval.tv_usec = 0;
- new.it_value.tv_sec = seconds;
- new.it_value.tv_usec = 0;
- _setitimer(ITIMER_REAL, &new, &old);
- return(old.it_value.tv_sec + (old.it_value.tv_usec / 1000000));
+ struct itimerval it_new, it_old;
+
+ it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+ it_new.it_value.tv_sec = seconds;
+ it_new.it_value.tv_usec = 0;
+ _setitimer(ITIMER_REAL, &it_new, &it_old);
+ return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000));
}
-int sys_getpid(void)
+extern "C" int sys_getpid(void)
{
return current->pid;
}
-int sys_getppid(void)
+extern "C" int sys_getppid(void)
{
return current->p_pptr->pid;
}
-int sys_getuid(void)
+extern "C" int sys_getuid(void)
{
return current->uid;
}
-int sys_geteuid(void)
+extern "C" int sys_geteuid(void)
{
return current->euid;
}
-int sys_getgid(void)
+extern "C" int sys_getgid(void)
{
return current->gid;
}
-int sys_getegid(void)
+extern "C" int sys_getegid(void)
{
return current->egid;
}
-int sys_nice(long increment)
+extern "C" int sys_nice(long increment)
{
+ int newprio;
+
if (increment < 0 && !suser())
return -EPERM;
- if (increment >= current->priority)
- increment = current->priority-1;
- current->priority -= increment;
+ newprio = current->priority - increment;
+ if (newprio < 1)
+ newprio = 1;
+ if (newprio > 35)
+ newprio = 35;
+ current->priority = newprio;
return 0;
}
@@ -457,8 +474,8 @@ static void show_task(int nr,struct task_struct * p)
p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1);
i = 0;
j = 4096;
- if (!(stack = (char *) p->kernel_stack_page)) {
- stack = (char *) init_kernel_stack;
+ if (!(stack = (unsigned char *) p->kernel_stack_page)) {
+ stack = (unsigned char *) init_kernel_stack;
j = sizeof(init_kernel_stack);
}
while (i<j && !*(stack++))
@@ -508,5 +525,6 @@ void sched_init(void)
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
- request_irq(TIMER_IRQ,(void (*)(int)) do_timer);
+ if (request_irq(TIMER_IRQ,(void (*)(int)) do_timer)!=0)
+ panic("Could not allocate timer IRQ!");
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 0e0cd15..50bc1c1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -19,14 +19,15 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
extern int core_dump(long signr,struct pt_regs * regs);
-int do_signal(unsigned long oldmask, struct pt_regs * regs);
-int sys_sgetmask(void)
+extern "C" int do_signal(unsigned long oldmask, struct pt_regs * regs);
+
+extern "C" int sys_sgetmask(void)
{
return current->blocked;
}
-int sys_ssetmask(int newmask)
+extern "C" int sys_ssetmask(int newmask)
{
int old=current->blocked;
@@ -34,7 +35,7 @@ int sys_ssetmask(int newmask)
return old;
}
-int sys_sigpending(sigset_t *set)
+extern "C" int sys_sigpending(sigset_t *set)
{
int error;
/* fill in "set" with signals pending but blocked. */
@@ -47,7 +48,7 @@ int sys_sigpending(sigset_t *set)
/*
* atomically swap in the new signal mask, and wait for a signal.
*/
-int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
+extern "C" int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
{
unsigned long mask;
struct pt_regs * regs = (struct pt_regs *) &restart;
@@ -97,7 +98,7 @@ static void check_pending(int signum)
}
}
-int sys_signal(int signum, unsigned long handler)
+extern "C" int sys_signal(int signum, unsigned long handler)
{
struct sigaction tmp;
@@ -115,23 +116,23 @@ int sys_signal(int signum, unsigned long handler)
return handler;
}
-int sys_sigaction(int signum, const struct sigaction * action,
+extern "C" int sys_sigaction(int signum, const struct sigaction * action,
struct sigaction * oldaction)
{
- struct sigaction new, *p;
+ struct sigaction new_sa, *p;
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
return -EINVAL;
p = signum - 1 + current->sigaction;
if (action) {
- memcpy_fromfs(&new, action, sizeof(struct sigaction));
- if (new.sa_flags & SA_NOMASK)
- new.sa_mask = 0;
+ memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
+ if (new_sa.sa_flags & SA_NOMASK)
+ new_sa.sa_mask = 0;
else {
- new.sa_mask |= _S(signum);
- new.sa_mask &= _BLOCKABLE;
+ new_sa.sa_mask |= _S(signum);
+ new_sa.sa_mask &= _BLOCKABLE;
}
- if (TASK_SIZE <= (unsigned long) new.sa_handler)
+ if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
return -EFAULT;
}
if (oldaction) {
@@ -139,18 +140,18 @@ int sys_sigaction(int signum, const struct sigaction * action,
memcpy_tofs(oldaction, p, sizeof(struct sigaction));
}
if (action) {
- *p = new;
+ *p = new_sa;
check_pending(signum);
}
return 0;
}
-extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+extern "C" int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
* This sets regs->esp even though we don't actually use sigstacks yet..
*/
-int sys_sigreturn(unsigned long oldmask, unsigned long eip, unsigned long esp)
+extern "C" int sys_sigreturn(unsigned long oldmask, unsigned long eip, unsigned long esp)
{
struct pt_regs * regs;
@@ -172,7 +173,7 @@ static void setup_frame(unsigned long ** fp, unsigned long eip,
unsigned long * frame;
#define __CODE ((unsigned long)(frame+24))
-#define CODE(x) ((void *) ((x)+__CODE))
+#define CODE(x) ((unsigned long *) ((x)+__CODE))
frame = *fp - 32;
verify_area(VERIFY_WRITE,frame,32*4);
/* set up the "normal" stack seen by the signal handler (iBCS2) */
@@ -225,7 +226,7 @@ static void setup_frame(unsigned long ** fp, unsigned long eip,
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(unsigned long oldmask, struct pt_regs * regs)
+extern "C" int do_signal(unsigned long oldmask, struct pt_regs * regs)
{
unsigned long mask = ~current->blocked;
unsigned long handler_signal = 0;
@@ -325,7 +326,7 @@ int do_signal(unsigned long oldmask, struct pt_regs * regs)
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
/* force a supervisor-mode page-in of the signal handler to reduce races */
- __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
+ __asm__("testb $0,%%fs:%0": :"m" (*(char *) sa_handler));
setup_frame(&frame,eip,regs,signr,sa_handler,oldmask);
eip = sa_handler;
current->blocked |= sa->sa_mask;
diff --git a/kernel/sys.c b/kernel/sys.c
index f902651..a4a5372 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -32,6 +32,7 @@ static int C_A_D = 1;
struct timezone sys_tz = { 0, 0};
extern int session_of_pgrp(int pgrp);
+extern void adjust_clock(void);
#define PZERO 15
@@ -54,7 +55,7 @@ static int proc_sel(struct task_struct *p, int which, int who)
return 0;
}
-int sys_setpriority(int which, int who, int niceval)
+extern "C" int sys_setpriority(int which, int who, int niceval)
{
struct task_struct **p;
int error = ESRCH;
@@ -84,7 +85,7 @@ int sys_setpriority(int which, int who, int niceval)
return -error;
}
-int sys_getpriority(int which, int who)
+extern "C" int sys_getpriority(int which, int who)
{
struct task_struct **p;
int max_prio = 0;
@@ -101,37 +102,37 @@ int sys_getpriority(int which, int who)
return(max_prio ? max_prio : -ESRCH);
}
-int sys_profil(void)
+extern "C" int sys_profil(void)
{
return -ENOSYS;
}
-int sys_ftime(void)
+extern "C" int sys_ftime(void)
{
return -ENOSYS;
}
-int sys_break(void)
+extern "C" int sys_break(void)
{
return -ENOSYS;
}
-int sys_stty(void)
+extern "C" int sys_stty(void)
{
return -ENOSYS;
}
-int sys_gtty(void)
+extern "C" int sys_gtty(void)
{
return -ENOSYS;
}
-int sys_prof(void)
+extern "C" int sys_prof(void)
{
return -ENOSYS;
}
-unsigned long save_v86_state(struct vm86_regs * regs)
+extern "C" unsigned long save_v86_state(struct vm86_regs * regs)
{
unsigned long stack;
@@ -167,7 +168,7 @@ static void mark_screen_rdonly(struct task_struct * tsk)
}
}
-int sys_vm86(struct vm86_struct * v86)
+extern "C" int sys_vm86(struct vm86_struct * v86)
{
struct vm86_struct info;
struct pt_regs * pt_regs = (struct pt_regs *) &v86;
@@ -198,7 +199,9 @@ int sys_vm86(struct vm86_struct * v86)
mark_screen_rdonly(current);
__asm__ __volatile__("movl %0,%%esp\n\t"
"pushl $ret_from_sys_call\n\t"
- "ret"::"g" ((long) &(info.regs)),"a" (info.regs.eax));
+ "ret"
+ : /* no outputs */
+ :"g" ((long) &(info.regs)),"a" (info.regs.eax));
return 0;
}
@@ -212,7 +215,7 @@ extern void hard_reset_now(void);
*
* reboot doesn't sync: do that yourself before calling this.
*/
-int sys_reboot(int magic, int magic_too, int flag)
+extern "C" int sys_reboot(int magic, int magic_too, int flag)
{
if (!suser())
return -EPERM;
@@ -254,7 +257,7 @@ void ctrl_alt_del(void)
* 100% compatible with BSD. A program which uses just setgid() will be
* 100% compatible with POSIX w/ Saved ID's.
*/
-int sys_setregid(gid_t rgid, gid_t egid)
+extern "C" int sys_setregid(gid_t rgid, gid_t egid)
{
int old_rgid = current->gid;
@@ -283,7 +286,7 @@ int sys_setregid(gid_t rgid, gid_t egid)
/*
* setgid() is implemeneted like SysV w/ SAVED_IDS
*/
-int sys_setgid(gid_t gid)
+extern "C" int sys_setgid(gid_t gid)
{
if (suser())
current->gid = current->egid = current->sgid = gid;
@@ -294,37 +297,37 @@ int sys_setgid(gid_t gid)
return 0;
}
-int sys_acct(void)
+extern "C" int sys_acct(void)
{
return -ENOSYS;
}
-int sys_phys(void)
+extern "C" int sys_phys(void)
{
return -ENOSYS;
}
-int sys_lock(void)
+extern "C" int sys_lock(void)
{
return -ENOSYS;
}
-int sys_mpx(void)
+extern "C" int sys_mpx(void)
{
return -ENOSYS;
}
-int sys_ulimit(void)
+extern "C" int sys_ulimit(void)
{
return -ENOSYS;
}
-int sys_old_syscall(void)
+extern "C" int sys_old_syscall(void)
{
return -ENOSYS;
}
-int sys_time(long * tloc)
+extern "C" int sys_time(long * tloc)
{
int i, error;
@@ -351,7 +354,7 @@ int sys_time(long * tloc)
* 100% compatible with BSD. A program which uses just setuid() will be
* 100% compatible with POSIX w/ Saved ID's.
*/
-int sys_setreuid(uid_t ruid, uid_t euid)
+extern "C" int sys_setreuid(uid_t ruid, uid_t euid)
{
int old_ruid = current->uid;
@@ -388,7 +391,7 @@ int sys_setreuid(uid_t ruid, uid_t euid)
* will allow a root program to temporarily drop privileges and be able to
* regain them by swapping the real and effective uid.
*/
-int sys_setuid(uid_t uid)
+extern "C" int sys_setuid(uid_t uid)
{
if (suser())
current->uid = current->euid = current->suid = uid;
@@ -399,7 +402,7 @@ int sys_setuid(uid_t uid)
return(0);
}
-int sys_stime(long * tptr)
+extern "C" int sys_stime(long * tptr)
{
if (!suser())
return -EPERM;
@@ -408,7 +411,7 @@ int sys_stime(long * tptr)
return 0;
}
-int sys_times(struct tms * tbuf)
+extern "C" int sys_times(struct tms * tbuf)
{
if (tbuf) {
int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
@@ -422,29 +425,56 @@ int sys_times(struct tms * tbuf)
return jiffies;
}
-int sys_brk(unsigned long newbrk)
+extern "C" int sys_brk(unsigned long brk)
{
+ int freepages;
unsigned long rlim;
- unsigned long oldbrk;
-
- oldbrk = current->brk;
+ unsigned long newbrk, oldbrk;
+
+ if (brk < current->end_code)
+ return current->brk;
+ newbrk = (brk + 0x00000fff) & 0xfffff000;
+ oldbrk = (current->brk + 0x00000fff) & 0xfffff000;
+ /*
+ * Always allow shrinking brk
+ */
+ if (brk <= current->brk) {
+ current->brk = brk;
+ unmap_page_range(newbrk, oldbrk-newbrk);
+ return brk;
+ }
+ /*
+ * Check against rlimit and stack..
+ */
rlim = current->rlim[RLIMIT_DATA].rlim_cur;
if (rlim >= RLIM_INFINITY)
rlim = 0xffffffff;
- if (newbrk >= current->end_code &&
- newbrk - current->end_code <= rlim &&
- newbrk < current->start_stack - 16384) {
- current->brk = newbrk;
- newbrk += 0x00000fff;
- newbrk &= 0xfffff000;
- oldbrk += 0x00000fff;
- oldbrk &= 0xfffff000;
- if (newbrk < oldbrk)
- unmap_page_range(newbrk, oldbrk-newbrk);
- else
- zeromap_page_range(oldbrk, newbrk-oldbrk, PAGE_COPY);
- }
- return current->brk;
+ if (brk - current->end_code > rlim || brk >= current->start_stack - 16384)
+ return current->brk;
+ /*
+ * stupid algorithm to decide if we have enough memory: while
+ * simple, it hopefully works in most obvious cases.. Easy to
+ * fool it, but this should catch most mistakes.
+ */
+ freepages = buffermem >> 12;
+ freepages += nr_free_pages;
+ freepages += nr_swap_pages;
+ freepages -= (high_memory - 0x100000) >> 16;
+ freepages -= (newbrk-oldbrk) >> 12;
+ if (freepages < 0)
+ return current->brk;
+#if 0
+ freepages += current->rss;
+ freepages -= oldbrk >> 12;
+ if (freepages < 0)
+ return current->brk;
+#endif
+ /*
+ * Ok, we have probably got enough memory - let it rip.
+ */
+ current->brk = brk;
+ zeromap_page_range(oldbrk, newbrk-oldbrk, PAGE_COPY);
+ return brk;
}
/*
@@ -456,7 +486,7 @@ int sys_brk(unsigned long newbrk)
* only important on a multi-user system anyway, to make sure one user
* can't send a signal to a process owned by another. -TYT, 12/12/91
*/
-int sys_setpgid(pid_t pid, pid_t pgid)
+extern "C" int sys_setpgid(pid_t pid, pid_t pgid)
{
int i;
@@ -482,12 +512,12 @@ int sys_setpgid(pid_t pid, pid_t pgid)
return -ESRCH;
}
-int sys_getpgrp(void)
+extern "C" int sys_getpgrp(void)
{
return current->pgrp;
}
-int sys_setsid(void)
+extern "C" int sys_setsid(void)
{
if (current->leader && !suser())
return -EPERM;
@@ -500,7 +530,7 @@ int sys_setsid(void)
/*
* Supplementary group ID's
*/
-int sys_getgroups(int gidsetsize, gid_t *grouplist)
+extern "C" int sys_getgroups(int gidsetsize, gid_t *grouplist)
{
int i;
@@ -509,18 +539,18 @@ int sys_getgroups(int gidsetsize, gid_t *grouplist)
if (i)
return i;
}
- for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP);
- i++, grouplist++) {
- if (gidsetsize) {
- if (i >= gidsetsize)
- return -EINVAL;
- put_fs_word(current->groups[i], (short *) grouplist);
- }
+ for (i = 0 ; (i < NGROUPS) && (current->groups[i] != NOGROUP) ; i++) {
+ if (!gidsetsize)
+ continue;
+ if (i >= gidsetsize)
+ break;
+ put_fs_word(current->groups[i], (short *) grouplist);
+ grouplist++;
}
return(i);
}
-int sys_setgroups(int gidsetsize, gid_t *grouplist)
+extern "C" int sys_setgroups(int gidsetsize, gid_t *grouplist)
{
int i;
@@ -552,7 +582,7 @@ int in_group_p(gid_t grp)
return 0;
}
-int sys_newuname(struct new_utsname * name)
+extern "C" int sys_newuname(struct new_utsname * name)
{
int error;
@@ -564,7 +594,7 @@ int sys_newuname(struct new_utsname * name)
return error;
}
-int sys_uname(struct old_utsname * name)
+extern "C" int sys_uname(struct old_utsname * name)
{
int error;
if (!name)
@@ -585,7 +615,7 @@ int sys_uname(struct old_utsname * name)
return 0;
}
-int sys_olduname(struct oldold_utsname * name)
+extern "C" int sys_olduname(struct oldold_utsname * name)
{
int error;
if (!name)
@@ -609,7 +639,7 @@ int sys_olduname(struct oldold_utsname * name)
/*
* Only sethostname; gethostname can be implemented by calling uname()
*/
-int sys_sethostname(char *name, int len)
+extern "C" int sys_sethostname(char *name, int len)
{
int i;
@@ -629,7 +659,7 @@ int sys_sethostname(char *name, int len)
* Only setdomainname; getdomainname can be implemented by calling
* uname()
*/
-int sys_setdomainname(char *name, int len)
+extern "C" int sys_setdomainname(char *name, int len)
{
int i;
@@ -645,7 +675,7 @@ int sys_setdomainname(char *name, int len)
return 0;
}
-int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
+extern "C" int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
{
int error;
@@ -661,20 +691,20 @@ int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
return 0;
}
-int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
+extern "C" int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
{
- struct rlimit new, *old;
+ struct rlimit new_rlim, *old_rlim;
if (resource >= RLIM_NLIMITS)
return -EINVAL;
- old = current->rlim + resource;
- new.rlim_cur = get_fs_long((unsigned long *) rlim);
- new.rlim_max = get_fs_long(((unsigned long *) rlim)+1);
- if (((new.rlim_cur > old->rlim_max) ||
- (new.rlim_max > old->rlim_max)) &&
+ old_rlim = current->rlim + resource;
+ new_rlim.rlim_cur = get_fs_long((unsigned long *) rlim);
+ new_rlim.rlim_max = get_fs_long(((unsigned long *) rlim)+1);
+ if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
+ (new_rlim.rlim_max > old_rlim->rlim_max)) &&
!suser())
return -EPERM;
- *old = new;
+ *old_rlim = new_rlim;
return 0;
}
@@ -730,7 +760,7 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
return 0;
}
-int sys_getrusage(int who, struct rusage *ru)
+extern "C" int sys_getrusage(int who, struct rusage *ru)
{
if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
return -EINVAL;
@@ -777,7 +807,7 @@ static inline void do_gettimeofday(struct timeval *tv)
#endif /* not __i386__ */
}
-int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+extern "C" int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
{
int error;
@@ -787,8 +817,8 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
if (error)
return error;
do_gettimeofday(&ktv);
- put_fs_long(ktv.tv_sec, &tv->tv_sec);
- put_fs_long(ktv.tv_usec, &tv->tv_usec);
+ put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
+ put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
}
if (tz) {
error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
@@ -809,10 +839,9 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
* soon as possible, so that the clock can be set right. Otherwise,
* various programs will get confused when the clock gets warped.
*/
-int sys_settimeofday(struct timeval *tv, struct timezone *tz)
+extern "C" int sys_settimeofday(struct timeval *tv, struct timezone *tz)
{
static int firsttime = 1;
- void adjust_clock(void);
if (!suser())
return -EPERM;
@@ -858,7 +887,7 @@ void adjust_clock(void)
startup_time += sys_tz.tz_minuteswest*60;
}
-int sys_umask(int mask)
+extern "C" int sys_umask(int mask)
{
int old = current->umask;
diff --git a/kernel/sys_call.S b/kernel/sys_call.S
index c74b44f..3ecd6fb 100644
--- a/kernel/sys_call.S
+++ b/kernel/sys_call.S
@@ -78,7 +78,7 @@ errno = 24
ENOSYS = 38
-.globl _system_call,_sys_execve,_lcall7
+.globl _system_call,_lcall7
.globl _device_not_available, _coprocessor_error
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
@@ -100,10 +100,10 @@ ENOSYS = 38
pushl %edx; \
pushl %ecx; \
pushl %ebx; \
- movl $KERNEL_DS,%edx; \
+ movl $(KERNEL_DS),%edx; \
mov %dx,%ds; \
mov %dx,%es; \
- movl $USER_DS,%edx; \
+ movl $(USER_DS),%edx; \
mov %dx,%fs
#define RESTORE_ALL \
@@ -139,6 +139,15 @@ _lcall7:
jmp ret_from_sys_call
.align 4
+handle_bottom_half:
+ pushfl
+ incl _intr_count
+ sti
+ call _do_bottom_half
+ popfl
+ decl _intr_count
+ jmp 9f
+.align 4
reschedule:
pushl $ret_from_sys_call
jmp _schedule
@@ -150,18 +159,17 @@ _system_call:
cmpl _NR_syscalls,%eax
jae ret_from_sys_call
movl _current,%ebx
- movl $0,errno(%ebx)
andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
- testl $0x20,flags(%ebx) # PF_TRACESYS
+ movl $0,errno(%ebx)
+ testb $0x20,flags(%ebx) # PF_TRACESYS
jne 1f
call _sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # save the return value
- movl _current,%eax
- movl errno(%eax),%edx
+ movl errno(%ebx),%edx
negl %edx
je ret_from_sys_call
movl %edx,EAX(%esp)
- orl $CF_MASK,EFLAGS(%esp) # set carry to indicate error
+ orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
jmp ret_from_sys_call
.align 4
1: call _syscall_trace
@@ -173,20 +181,25 @@ _system_call:
negl %edx
je 1f
movl %edx,EAX(%esp)
- orl $CF_MASK,EFLAGS(%esp) # set carry to indicate error
+ orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
1: call _syscall_trace
.align 4,0x90
ret_from_sys_call:
- movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
- testl $VM_MASK,%eax # different then
+ cmpl $0,_intr_count
+ jne 2f
+ movl _bh_mask,%eax
+ andl _bh_active,%eax
+ jne handle_bottom_half
+9: movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
+ testl $(VM_MASK),%eax # different then
jne 1f
- cmpw $USER_CS,CS(%esp) # was old code segment supervisor ?
+ cmpw $(USER_CS),CS(%esp) # was old code segment supervisor ?
jne 2f
- cmpw $USER_DS,OLDSS(%esp) # was stack segment user segment ?
+ cmpw $(USER_DS),OLDSS(%esp) # was stack segment user segment ?
jne 2f
-1: sti # slow interrupts get here with interrupts disabled
- orl $IF_MASK,%eax # these just try to make sure
+1: sti
+ orl $(IF_MASK),%eax # these just try to make sure
andl $~NT_MASK,%eax # the program doesn't do anything
movl %eax,EFLAGS(%esp) # stupid
cmpl $0,_need_resched
@@ -208,7 +221,7 @@ ret_from_sys_call:
signal_return:
movl %esp,%ecx
pushl %ecx
- testl $VM_MASK,EFLAGS(%ecx)
+ testl $(VM_MASK),EFLAGS(%ecx)
jne v86_signal_return
pushl %ebx
call _do_signal
@@ -227,14 +240,6 @@ v86_signal_return:
RESTORE_ALL
.align 4
-_sys_execve:
- lea (EIP+4)(%esp),%eax # don't forget about the return address.
- pushl %eax
- call _do_execve
- addl $4,%esp
- ret
-
-.align 4
_divide_error:
pushl $0 # no error code
pushl $_do_divide_error
@@ -259,10 +264,10 @@ error_code:
pushl %eax # push the error code
lea 4(%esp),%edx
pushl %edx
- movl $KERNEL_DS,%edx
+ movl $(KERNEL_DS),%edx
mov %dx,%ds
mov %dx,%es
- movl $USER_DS,%edx
+ movl $(USER_DS),%edx
mov %dx,%fs
call *%ebx
addl $8,%esp
@@ -279,7 +284,6 @@ _device_not_available:
pushl $-1 # mark this as an int
SAVE_ALL
pushl $ret_from_sys_call
- clts # clear TS so that we can use math
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je _math_state_restore
diff --git a/kernel/traps.c b/kernel/traps.c
index 3cf1697..0621668 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -41,24 +41,24 @@ __res;})
void page_exception(void);
-void divide_error(void);
-void debug(void);
-void nmi(void);
-void int3(void);
-void overflow(void);
-void bounds(void);
-void invalid_op(void);
-void device_not_available(void);
-void double_fault(void);
-void coprocessor_segment_overrun(void);
-void invalid_TSS(void);
-void segment_not_present(void);
-void stack_segment(void);
-void general_protection(void);
-void page_fault(void);
-void coprocessor_error(void);
-void reserved(void);
-void alignment_check(void);
+extern "C" void divide_error(void);
+extern "C" void debug(void);
+extern "C" void nmi(void);
+extern "C" void int3(void);
+extern "C" void overflow(void);
+extern "C" void bounds(void);
+extern "C" void invalid_op(void);
+extern "C" void device_not_available(void);
+extern "C" void double_fault(void);
+extern "C" void coprocessor_segment_overrun(void);
+extern "C" void invalid_TSS(void);
+extern "C" void segment_not_present(void);
+extern "C" void stack_segment(void);
+extern "C" void general_protection(void);
+extern "C" void page_fault(void);
+extern "C" void coprocessor_error(void);
+extern "C" void reserved(void);
+extern "C" void alignment_check(void);
/*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
{
@@ -82,31 +82,31 @@ void alignment_check(void);
do_exit(SIGSEGV);
}
-void do_double_fault(struct pt_regs * regs, long error_code)
+extern "C" void do_double_fault(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("double fault",regs,error_code);
}
-void do_general_protection(struct pt_regs * regs, long error_code)
+extern "C" void do_general_protection(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("general protection",regs,error_code);
}
-void do_alignment_check(struct pt_regs * regs, long error_code)
+extern "C" void do_alignment_check(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("alignment check",regs,error_code);
}
-void do_divide_error(struct pt_regs * regs, long error_code)
+extern "C" void do_divide_error(struct pt_regs * regs, long error_code)
{
send_sig(SIGFPE, current, 1);
die_if_kernel("divide error",regs,error_code);
}
-void do_int3(struct pt_regs * regs, long error_code)
+extern "C" void do_int3(struct pt_regs * regs, long error_code)
{
if (current->flags & PF_PTRACED)
current->blocked &= ~(1 << (SIGTRAP-1));
@@ -114,12 +114,12 @@ void do_int3(struct pt_regs * regs, long error_code)
die_if_kernel("int3",regs,error_code);
}
-void do_nmi(struct pt_regs * regs, long error_code)
+extern "C" void do_nmi(struct pt_regs * regs, long error_code)
{
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
}
-void do_debug(struct pt_regs * regs, long error_code)
+extern "C" void do_debug(struct pt_regs * regs, long error_code)
{
if (current->flags & PF_PTRACED)
current->blocked &= ~(1 << (SIGTRAP-1));
@@ -127,81 +127,96 @@ void do_debug(struct pt_regs * regs, long error_code)
die_if_kernel("debug",regs,error_code);
}
-void do_overflow(struct pt_regs * regs, long error_code)
+extern "C" void do_overflow(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("overflow",regs,error_code);
}
-void do_bounds(struct pt_regs * regs, long error_code)
+extern "C" void do_bounds(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("bounds",regs,error_code);
}
-void do_invalid_op(struct pt_regs * regs, long error_code)
+extern "C" void do_invalid_op(struct pt_regs * regs, long error_code)
{
send_sig(SIGILL, current, 1);
die_if_kernel("invalid operand",regs,error_code);
}
-void do_device_not_available(struct pt_regs * regs, long error_code)
+extern "C" void do_device_not_available(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("device not available",regs,error_code);
}
-void do_coprocessor_segment_overrun(struct pt_regs * regs, long error_code)
+extern "C" void do_coprocessor_segment_overrun(struct pt_regs * regs, long error_code)
{
send_sig(SIGFPE, last_task_used_math, 1);
die_if_kernel("coprocessor segment overrun",regs,error_code);
}
-void do_invalid_TSS(struct pt_regs * regs,long error_code)
+extern "C" void do_invalid_TSS(struct pt_regs * regs,long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("invalid TSS",regs,error_code);
}
-void do_segment_not_present(struct pt_regs * regs,long error_code)
+extern "C" void do_segment_not_present(struct pt_regs * regs,long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("segment not present",regs,error_code);
}
-void do_stack_segment(struct pt_regs * regs,long error_code)
+extern "C" void do_stack_segment(struct pt_regs * regs,long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("stack segment",regs,error_code);
}
-void do_coprocessor_error(struct pt_regs * regs, long error_code)
+/*
+ * Allow the process which triggered the interrupt to recover the error
+ * condition.
+ * - the status word is saved in the cs selector.
+ * - the tag word is saved in the operand selector.
+ * - the status word is then cleared and the tags all set to Empty.
+ *
+ * This will give sufficient information for complete recovery provided that
+ * the affected process knows or can deduce the code and data segments
+ * which were in force when the exception condition arose.
+ *
+ * Note that we play around with the 'TS' bit to hopefully get
+ * the correct behaviour even in the presense of the asynchronous
+ * IRQ13 behaviour
+ */
+void math_error(void)
{
- /*
- Allow the process which triggered the interrupt to recover the error
- condition.
- The status word is saved in the cs selector.
- The tag word is saved in the operand selector.
- The status word is then cleared and the tags all set to Empty.
- This will give sufficient information for complete recovery provided that
- the affected process knows or can deduce the code and data segments
- which were in force when the exception condition arose.
- */
- #define FPU_ENV (*(struct i387_hard_struct *)env)
- char env[28];
+ struct i387_hard_struct * env;
- ignore_irq13 = 1;
+ clts();
+ if (!last_task_used_math) {
+ __asm__("fnclex");
+ return;
+ }
+ env = &last_task_used_math->tss.i387.hard;
send_sig(SIGFPE, last_task_used_math, 1);
+ __asm__ __volatile__("fnsave %0":"=m" (*env));
+ last_task_used_math = NULL;
+ stts();
+ env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000);
+ env->fos = env->twd;
+ env->swd &= 0xffff0000;
+ env->twd = 0xffffffff;
+}
- __asm__ __volatile__("fnstenv %0; fnclex": "=m" (FPU_ENV));
- FPU_ENV.fcs = (FPU_ENV.swd & 0x0000ffff) | (FPU_ENV.fcs & 0xffff0000);
- FPU_ENV.fos = FPU_ENV.twd;
- FPU_ENV.swd &= 0xffff0000;
- FPU_ENV.twd = 0xffffffff;
- __asm__ __volatile__("fldenv %0"::"m" (FPU_ENV));
+extern "C" void do_coprocessor_error(struct pt_regs * regs, long error_code)
+{
+ ignore_irq13 = 1;
+ math_error();
}
-void do_reserved(struct pt_regs * regs, long error_code)
+extern "C" void do_reserved(struct pt_regs * regs, long error_code)
{
send_sig(SIGSEGV, current, 1);
die_if_kernel("reserved (15,17-47) error",regs,error_code);
diff --git a/lib/_exit.c b/lib/_exit.c
index b0b77e7..a46f1a2 100644
--- a/lib/_exit.c
+++ b/lib/_exit.c
@@ -11,6 +11,8 @@ volatile void _exit(int exit_code)
{
fake_volatile:
__asm__("movl %1,%%ebx\n\t"
- "int $0x80"::"a" (__NR_exit),"g" (exit_code));
+ "int $0x80"
+ : /* no outputs */
+ :"a" (__NR_exit),"g" (exit_code));
goto fake_volatile;
}
diff --git a/lib/malloc.c b/lib/malloc.c
index 925a28a..a3d8127 100644
--- a/lib/malloc.c
+++ b/lib/malloc.c
@@ -59,6 +59,8 @@
/* I've also got to make sure that kmalloc is reentrant now. */
+/* Debugging support: add file/line info, add beginning+end markers. -M.U- */
+
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
@@ -78,6 +80,28 @@ struct _bucket_dir { /* 8 bytes */
struct bucket_desc *chain;
};
+#ifdef CONFIG_DEBUG_MALLOC
+
+struct hdr_start {
+ const char *file;
+ const char *ok_file;
+ unsigned short line;
+ unsigned short ok_line;
+ unsigned short size;
+ int magic;
+};
+struct hdr_end {
+ int magic;
+};
+
+#define DEB_MAGIC_FREE 0x13579BDF /* free block */
+#define DEB_MAGIC_ALLOC 0x2468ACE0 /* allocated block */
+#define DEB_MAGIC_USED 0x147AD036 /* allocated but bad */
+#define DEB_MAGIC_FREED 0x258BE169 /* free but abused */
+
+#define DEB_MAGIC_END 0x369CF258 /* end marker */
+
+#endif
/*
* The following is the where we store a pointer to the first bucket
* descriptor for a given size.
@@ -91,7 +115,9 @@ struct _bucket_dir { /* 8 bytes */
* Note that this list *must* be kept in order.
*/
struct _bucket_dir bucket_dir[] = {
+#ifndef CONFIG_DEBUG_MALLOC /* Debug headers have too much overhead */
{ 16, (struct bucket_desc *) 0},
+#endif
{ 32, (struct bucket_desc *) 0},
{ 64, (struct bucket_desc *) 0},
{ 128, (struct bucket_desc *) 0},
@@ -137,8 +163,14 @@ static inline void init_bucket_desc(unsigned long page)
* Re-organized some code to give cleaner assembly output for easier
* verification.. LBT
*/
+#ifdef CONFIG_DEBUG_MALLOC
+void *
+deb_kmalloc(const char *deb_file, unsigned short deb_line,
+ unsigned int len, int priority)
+#else
void *
kmalloc(unsigned int len, int priority)
+#endif
{
int i;
unsigned long flags;
@@ -147,6 +179,9 @@ kmalloc(unsigned int len, int priority)
struct bucket_desc *bdesc;
void *retval;
+#ifdef CONFIG_DEBUG_MALLOC
+ len += sizeof(struct hdr_start)+sizeof(struct hdr_end);
+#endif
/*
* First we search the bucket_dir to find the right bucket change
* for this request.
@@ -173,7 +208,7 @@ kmalloc(unsigned int len, int priority)
*/
/*
- * Note that init_bucket_descriptor() does it's
+ * Note that init_bucket_descriptor() does its
* own cli() before returning, and guarantees that
* there is a bucket desc in the page.
*/
@@ -207,13 +242,27 @@ kmalloc(unsigned int len, int priority)
bdesc->page = bdesc->freeptr = (void *) page;
/* Set up the chain of free objects */
- for (i=PAGE_SIZE/bdir->size; i > 1 ; i--) {
- *((void **) page) = (void *)(page + bdir->size);
+ for (i=PAGE_SIZE/bdir->size; i > 0 ; i--) {
+#ifdef CONFIG_DEBUG_MALLOC
+ struct hdr_start *hd;
+ struct hdr_end *he;
+ hd = (struct hdr_start *) page;
+ he = (struct hdr_end *)(page+(bdir->size-sizeof(struct hdr_end)));
+ hd->magic = DEB_MAGIC_FREE;
+ hd->file = hd->ok_file = "(expand)";
+ hd->line = hd->ok_line = 0;
+ hd->size = bdir->size-sizeof(struct hdr_start)-sizeof(struct hdr_end);
+ he->magic = DEB_MAGIC_END;
+
+ memset(hd+1,0xF8,hd->size);
+
+ *((void **) (hd+1)) = (i==1) ? NULL : (void *)(page + bdir->size);
+#else
+ *((void **) page) = (i==1) ? NULL : (void *)(page + bdir->size);
+#endif
page += bdir->size;
}
- *((void **) page) = NULL;
-
/* turn interrupts back off for putting the
thing onto the chain. */
cli();
@@ -223,10 +272,58 @@ kmalloc(unsigned int len, int priority)
found_bdesc:
retval = (void *) bdesc->freeptr;
+#ifdef CONFIG_DEBUG_MALLOC
+ bdesc->freeptr = *((void **) (((char *)retval)+sizeof(struct hdr_start)));
+#else
bdesc->freeptr = *((void **) retval);
+#endif
bdesc->refcnt++;
restore_flags(flags); /* OK, we're safe again */
- memset(retval, 0xf0, bdir->size);
+#ifdef CONFIG_DEBUG_MALLOC
+ {
+ struct hdr_start *hd;
+ struct hdr_end *he;
+
+ hd = (struct hdr_start *) retval;
+ retval = hd+1;
+ len -= sizeof(struct hdr_start)+sizeof(struct hdr_end);
+ if(hd->magic != DEB_MAGIC_FREE && hd->magic != DEB_MAGIC_FREED) {
+ printk("DEB_MALLOC allocating %s block 0x%x (head 0x%x) from %s:%d, magic %x\n",
+ (hd->magic == DEB_MAGIC_ALLOC) ? "nonfree" : "trashed",
+ retval,hd,deb_file,deb_line,hd->magic);
+ return NULL;
+ }
+ if(len > hd->size || len > bdir->size-sizeof(struct hdr_start)-sizeof(struct hdr_end)) {
+ printk("DEB_MALLOC got %x:%x-byte block, wanted %x, from %s:%d, last %s:%d\n",
+ hd->size,bdir->size,len,hd->file,hd->line,deb_file,deb_line);
+ return NULL;
+ }
+ {
+ unsigned char *x = (unsigned char *) retval;
+ unsigned short pos = 4;
+ x += pos;
+ while(pos < hd->size) {
+ if(*x++ != 0xF8) {
+ printk("DEB_MALLOC used 0x%x:%x(%x) while free, from %s:%d\n",
+ retval,pos,hd->size,hd->file,hd->line);
+ return NULL;
+ }
+ pos++;
+ }
+ }
+ he = (struct hdr_end *)(((char *)retval)+hd->size);
+ if(he->magic != DEB_MAGIC_END) {
+ printk("DEB_MALLOC overran 0x%x:%d while free, from %s:%d\n",retval,hd->size,hd->file,hd->line);
+ }
+ memset(retval, 0xf0, len);
+ he = (struct hdr_end *)(((char *)retval)+len);
+ hd->file = hd->ok_file = deb_file;
+ hd->line = hd->ok_line = deb_line;
+ hd->size = len;
+ hd->magic = DEB_MAGIC_ALLOC;
+ he->magic = DEB_MAGIC_END;
+ }
+#endif
return retval;
too_large:
@@ -235,6 +332,44 @@ too_large:
return NULL;
}
+#ifdef CONFIG_DEBUG_MALLOC
+void deb_kcheck_s(const char *deb_file, unsigned short deb_line,
+ void *obj, int size)
+{
+ struct hdr_start *hd;
+ struct hdr_end *he;
+
+ if (!obj)
+ return;
+ hd = (struct hdr_start *) obj;
+ hd--;
+
+ if(hd->magic != DEB_MAGIC_ALLOC) {
+ if(hd->magic != DEB_MAGIC_USED && hd->magic != DEB_MAGIC_FREED)
+ printk("DEB_MALLOC Using %s block of 0x%x from %s:%d, by %s:%d, last %s:%d\n",
+ (hd->magic == DEB_MAGIC_FREE)?"free":"bad",obj,deb_file,deb_line,hd->file,hd->line,hd->ok_file,hd->ok_line);
+ if(hd->magic == DEB_MAGIC_FREE)
+ hd->magic = DEB_MAGIC_FREED;
+ return;
+ }
+ if(hd->size != size) {
+ if(size != 0) {
+ printk("DEB_MALLOC size for 0x%x given as %d, stored %d, from %s:%d, last %s:%d\n",
+ obj,size,hd->size,deb_file,deb_line,hd->ok_file,hd->ok_line);
+ }
+ size = hd->size;
+ }
+ he = (struct hdr_end *)(((char *)obj)+size);
+ if(he->magic != DEB_MAGIC_END) {
+ printk("DEB_MALLOC overran block 0x%x:%d, free at %s:%d\n",obj,hd->size,deb_file,deb_line);
+ hd->magic = DEB_MAGIC_USED;
+ return;
+ }
+ hd->ok_file = deb_file;
+ hd->ok_line = deb_line;
+}
+#endif
+
/*
* Here is the kfree routine. If you know the size of the object that you
* are freeing, then kfree_s() will use that information to speed up the
@@ -242,7 +377,12 @@ too_large:
*
* We will #define a macro so that "kfree(x)" is becomes "kfree_s(x, 0)"
*/
+#ifdef CONFIG_DEBUG_MALLOC
+void deb_kfree_s(const char *deb_file, unsigned short deb_line,
+ void *obj, int size)
+#else
void kfree_s(void *obj, int size)
+#endif
{
unsigned long flags;
void *page;
@@ -251,6 +391,38 @@ void kfree_s(void *obj, int size)
if (!obj)
return;
+#ifdef CONFIG_DEBUG_MALLOC
+ {
+ struct hdr_start *hd;
+ struct hdr_end *he;
+ hd = (struct hdr_start *) obj;
+ hd--;
+
+ if(hd->magic != DEB_MAGIC_ALLOC && hd->magic != DEB_MAGIC_USED) {
+ if(hd->magic != DEB_MAGIC_FREED)
+ printk("DEB_MALLOC %s free of 0x%x from %s:%d by %s:%d, last %s:%d\n",
+ (hd->magic == DEB_MAGIC_FREE)?"dup":"bad",
+ obj,deb_file,deb_line,hd->file,hd->line,hd->ok_file,hd->ok_line);
+ return;
+ }
+ if(hd->size != size) {
+ if(size != 0) {
+ if(hd->magic != DEB_MAGIC_USED)
+ printk("DEB_MALLOC size for 0x%x given as %d, stored %d, from %s:%d, last %s:%d\n",
+ obj,size,hd->size,deb_file,deb_line,hd->ok_file,hd->ok_line);
+ }
+ size = hd->size;
+ }
+ he = (struct hdr_end *)(((char *)obj)+size);
+ if(he->magic != DEB_MAGIC_END) {
+ if(hd->magic != DEB_MAGIC_USED)
+ printk("DEB_MALLOC overran block 0x%x:%d, free at %s:%d, last %s:%d\n",
+ obj,hd->size,deb_file,deb_line,hd->ok_file,hd->ok_line);
+ return;
+ }
+ size += sizeof(struct hdr_start)+sizeof(struct hdr_end);
+ }
+#endif
save_flags(flags);
/* Calculate what page this object lives in */
page = (void *) ((unsigned long) obj & 0xfffff000);
@@ -277,12 +449,37 @@ void kfree_s(void *obj, int size)
restore_flags(flags);
printk("Bad address passed to kernel kfree_s(%X, %d)\n",obj, size);
+#ifdef CONFIG_DEBUG_MALLOC
+ printk("Offending code: %s:%d\n",deb_file,deb_line);
+#else
printk("Offending eip: %08x\n",((unsigned long *) &obj)[-1]);
+#endif
return;
+
found:
/* interrupts are off here. */
- memset(obj, 0xf8, bdir->size);
+#ifdef CONFIG_DEBUG_MALLOC
+
+ {
+ struct hdr_start *hd;
+ struct hdr_end *he;
+ hd = (struct hdr_start *) obj;
+ hd--;
+
+ hd->file = deb_file;
+ hd->line = deb_line;
+ hd->magic = DEB_MAGIC_FREE;
+ hd->size = bdir->size-sizeof(struct hdr_start)-sizeof(struct hdr_end);
+ he = (struct hdr_end *)(((char *)obj)+hd->size);
+ memset(obj, 0xf8, hd->size);
+ he->magic = DEB_MAGIC_END;
+ *((void **)obj) = bdesc->freeptr;
+ obj = hd;
+ }
+#else
*((void **)obj) = bdesc->freeptr;
+#endif
+
bdesc->freeptr = obj;
bdesc->refcnt--;
if (bdesc->refcnt == 0) {
@@ -309,3 +506,40 @@ found:
restore_flags(flags);
return;
}
+
+#ifdef CONFIG_DEBUG_MALLOC
+int get_malloc(char *buffer)
+{
+ int len = 0;
+ int i;
+ unsigned long flags;
+ void *page;
+ struct _bucket_dir *bdir;
+ struct bucket_desc *bdesc;
+
+ save_flags(flags);
+ cli(); /* To avoid race conditions */
+ for (bdir = bucket_dir; bdir->size; bdir++) {
+ for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {
+ page = bdesc->page;
+ for (i=PAGE_SIZE/bdir->size; i > 0 ; i--) {
+ struct hdr_start *hd;
+ hd = (struct hdr_start *)page;
+ if(hd->magic == DEB_MAGIC_ALLOC) {
+ if(len > PAGE_SIZE-80) {
+ restore_flags(flags);
+ len += sprintf(buffer+len,"+++\n");
+ return len;
+ }
+ len += sprintf(buffer+len,"%08x:%03x %s:%d %s:%d\n",
+ (long)(page+sizeof(struct hdr_start)),hd->size,hd->file,hd->line,hd->ok_file,hd->ok_line);
+ }
+ page += bdir->size;
+ }
+ }
+ }
+
+ restore_flags(flags);
+ return len;
+}
+#endif
diff --git a/mm/memory.c b/mm/memory.c
index eb17ba6..6b31b29 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -38,11 +38,14 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
+#include <linux/mman.h>
unsigned long high_memory = 0;
extern void sound_mem_init(void);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+int nr_swap_pages = 0;
int nr_free_pages = 0;
unsigned long free_page_list = 0;
/*
@@ -55,7 +58,7 @@ int nr_secondary_pages = 0;
unsigned long secondary_page_list = 0;
#define copy_page(from,to) \
-__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
+__asm__("cld ; rep ; movsl": :"S" (from),"D" (to),"c" (1024):"cx","di","si")
unsigned short * mem_map = NULL;
@@ -128,16 +131,16 @@ void clear_page_tables(struct task_struct * tsk)
}
if (mem_map[MAP_NR(pg_dir)] > 1) {
unsigned long page;
- unsigned long * new;
+ unsigned long * new_pg;
page = get_free_page(GFP_KERNEL);
if (!page) {
oom(tsk);
return;
}
- new = (unsigned long *) page;
+ new_pg = (unsigned long *) page;
for (i = 768 ; i < 1024 ; i++)
- new[i] = page_dir[i];
+ new_pg[i] = page_dir[i];
free_page(pg_dir);
tsk->tss.cr3 = page;
return;
@@ -170,7 +173,7 @@ void free_page_tables(struct task_struct * tsk)
}
tsk->tss.cr3 = (unsigned long) swapper_pg_dir;
if (tsk == current)
- __asm__ __volatile__("movl %0,%%cr3"::"a" (tsk->tss.cr3));
+ __asm__ __volatile__("movl %0,%%cr3": :"a" (tsk->tss.cr3));
if (mem_map[MAP_NR(pg_dir)] > 1) {
free_page(pg_dir);
return;
@@ -432,13 +435,16 @@ int remap_page_range(unsigned long from, unsigned long to, unsigned long size, i
}
/*
- * i'm not sure of the second cond here. should we
- * report failure?
* the first condition should return an invalid access
* when the page is referenced. current assumptions
- * cause it to be treated as demand allocation.
+ * cause it to be treated as demand allocation in some
+ * cases.
*/
- if (!mask || to >= high_memory || !mem_map[MAP_NR(to)])
+ if (!mask)
+ *page_table++ = 0; /* not present */
+ else if (to >= high_memory)
+ *page_table++ = (to | mask);
+ else if (!mem_map[MAP_NR(to)])
*page_table++ = 0; /* not present */
else {
*page_table++ = (to | mask);
@@ -624,11 +630,14 @@ void do_wp_page(unsigned long error_code, unsigned long address,
return;
if (page & PAGE_RW)
return;
- if (!(page & PAGE_COW))
- if (user_esp && tsk == current)
+ if (!(page & PAGE_COW)) {
+ if (user_esp && tsk == current) {
send_sig(SIGSEGV, tsk, 1);
+ return;
+ }
+ }
if (mem_map[MAP_NR(page)] == 1) {
- *pg_table |= PAGE_RW;
+ *pg_table |= PAGE_RW | PAGE_DIRTY;
invalidate();
return;
}
@@ -683,6 +692,12 @@ static void get_empty_page(struct task_struct * tsk, unsigned long address)
*
* NOTE! This assumes we have checked that p != current, and that they
* share the same executable or library.
+ *
+ * We may want to fix this to allow page sharing for PIC pages at different
+ * addresses so that ELF will really perform properly. As long as the vast
+ * majority of sharable libraries load at fixed addresses this is not a
+ * big concern. Any sharing of pages between the buffer cache and the
+ * code space reduces the need for this as well. - ERY
*/
static int try_to_share(unsigned long address, struct task_struct * tsk,
struct task_struct * p, unsigned long error_code, unsigned long newpage)
@@ -740,11 +755,11 @@ static int try_to_share(unsigned long address, struct task_struct * tsk,
* We first check if it is at all feasible by checking executable->i_count.
* It should be >1 if there are other tasks sharing this inode.
*/
-static int share_page(struct task_struct * tsk, struct inode * inode,
+static int share_page(struct vm_area_struct * area, struct task_struct * tsk,
+ struct inode * inode,
unsigned long address, unsigned long error_code, unsigned long newpage)
{
struct task_struct ** p;
- int i;
if (!inode || inode->i_count < 2)
return 0;
@@ -754,11 +769,21 @@ static int share_page(struct task_struct * tsk, struct inode * inode,
if (tsk == *p)
continue;
if (inode != (*p)->executable) {
- for (i=0; i < (*p)->numlibraries; i++)
- if (inode == (*p)->libraries[i].library)
- break;
- if (i >= (*p)->numlibraries)
- continue;
+ if(!area) continue;
+ /* Now see if there is something in the VMM that
+ we can share pages with */
+ if(area){
+ struct vm_area_struct * mpnt;
+ for(mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next){
+ if(mpnt->vm_ops && mpnt->vm_ops == area->vm_ops &&
+ mpnt->vm_inode->i_ino == area->vm_inode->i_ino&&
+ mpnt->vm_inode->i_dev == area->vm_inode->i_dev){
+ if (mpnt->vm_ops->share(mpnt, area, address))
+ break;
+ };
+ };
+ if (!mpnt) continue; /* Nope. Nuthin here */
+ };
}
if (try_to_share(address,tsk,*p,error_code,newpage))
return 1;
@@ -806,8 +831,9 @@ void do_no_page(unsigned long error_code, unsigned long address,
int nr[8], prot;
unsigned long tmp;
unsigned long page;
- unsigned int block,i;
+ unsigned int block,i, j;
struct inode * inode;
+ struct vm_area_struct * mpnt;
page = get_empty_pgtable(tsk,address);
if (!page)
@@ -825,24 +851,18 @@ void do_no_page(unsigned long error_code, unsigned long address,
}
address &= 0xfffff000;
inode = NULL;
- block = 0;
+ block = 0xffffffff;
if (address < tsk->end_data) {
inode = tsk->executable;
block = 1 + address / BLOCK_SIZE;
} else {
- i = tsk->numlibraries;
- while (i-- > 0) {
- if (address < tsk->libraries[i].start)
+ for (mpnt = tsk->mmap ; mpnt ; mpnt = mpnt->vm_next) {
+ if (address < mpnt->vm_start)
continue;
- block = address - tsk->libraries[i].start;
- if (block >= tsk->libraries[i].length + tsk->libraries[i].bss)
+ if (address >= ((mpnt->vm_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
continue;
- inode = tsk->libraries[i].library;
- if (block < tsk->libraries[i].length)
- block = 1 + block / BLOCK_SIZE;
- else
- block = 0;
- break;
+ mpnt->vm_ops->nopage(error_code, mpnt, address);
+ return;
}
}
if (!inode) {
@@ -852,13 +872,14 @@ void do_no_page(unsigned long error_code, unsigned long address,
return;
if (address < tsk->brk)
return;
- if (address+8192 >= (user_esp & 0xfffff000))
+ if (address+8192 >= (user_esp & 0xfffff000) &&
+ address <= current->start_stack)
return;
send_sig(SIGSEGV,tsk,1);
return;
}
page = get_free_page(GFP_KERNEL);
- if (share_page(tsk,inode,address,error_code,page)) {
+ if (share_page(NULL, tsk,inode,address,error_code,page)) {
++tsk->min_flt;
return;
}
@@ -870,12 +891,13 @@ void do_no_page(unsigned long error_code, unsigned long address,
prot = PAGE_PRIVATE;
if (CODE_SPACE(address, tsk))
prot = PAGE_READONLY;
- if (block) {
- for (i=0 ; i<4 ; block++,i++)
- nr[i] = bmap(inode,block);
- page = bread_page(page,inode->i_dev,nr,1024,prot);
+ if (block != 0xffffffff) {
+ for (i=0, j=0; i< PAGE_SIZE ; j++, block++,i +=inode->i_sb->s_blocksize)
+ nr[j] = bmap(inode,block);
+ page = bread_page(page,inode->i_dev,nr,
+ inode->i_sb->s_blocksize,prot);
}
- if (!(error_code & PAGE_RW) && share_page(tsk,inode,address, error_code,page))
+ if (!(error_code & PAGE_RW) && share_page(NULL, tsk,inode,address, error_code,page))
return;
i = address + PAGE_SIZE - tsk->end_data;
if (i > PAGE_SIZE-1)
@@ -896,13 +918,12 @@ void do_no_page(unsigned long error_code, unsigned long address,
* and the problem, and then passes it off to one of the appropriate
* routines.
*/
-void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+extern "C" void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
unsigned long address;
unsigned long user_esp = 0;
unsigned long stack_limit;
unsigned int bit;
- extern void die_if_kernel(char *,struct pt_regs *,long);
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
@@ -953,10 +974,10 @@ unsigned long __bad_pagetable(void)
{
extern char empty_bad_page_table[PAGE_SIZE];
- __asm__ __volatile__("cld ; rep ; stosl"
- ::"a" (BAD_PAGE + PAGE_TABLE),
- "D" ((long) empty_bad_page_table),
- "c" (1024)
+ __asm__ __volatile__("cld ; rep ; stosl":
+ :"a" (BAD_PAGE + PAGE_TABLE),
+ "D" ((long) empty_bad_page_table),
+ "c" (1024)
:"di","cx");
return (unsigned long) empty_bad_page_table;
}
@@ -965,10 +986,10 @@ unsigned long __bad_page(void)
{
extern char empty_bad_page[PAGE_SIZE];
- __asm__ __volatile__("cld ; rep ; stosl"
- ::"a" (0),
- "D" ((long) empty_bad_page),
- "c" (1024)
+ __asm__ __volatile__("cld ; rep ; stosl":
+ :"a" (0),
+ "D" ((long) empty_bad_page),
+ "c" (1024)
:"di","cx");
return (unsigned long) empty_bad_page;
}
@@ -977,10 +998,10 @@ unsigned long __zero_page(void)
{
extern char empty_zero_page[PAGE_SIZE];
- __asm__ __volatile__("cld ; rep ; stosl"
- ::"a" (0),
- "D" ((long) empty_zero_page),
- "c" (1024)
+ __asm__ __volatile__("cld ; rep ; stosl":
+ :"a" (0),
+ "D" ((long) empty_zero_page),
+ "c" (1024)
:"di","cx");
return (unsigned long) empty_zero_page;
}
@@ -991,8 +1012,10 @@ void show_mem(void)
int shared = 0;
printk("Mem-info:\n");
- printk("Free pages: %6d\n",nr_free_pages);
- printk("Secondary pages: %6d\n",nr_secondary_pages);
+ printk("Free pages: %6dkB\n",nr_free_pages<<2);
+ printk("Secondary pages: %6dkB\n",nr_secondary_pages<<2);
+ printk("Free swap: %6dkB\n",nr_swap_pages<<2);
+ printk("Buffer memory: %6dkB\n",buffermem>>10);
printk("Buffer heads: %6d\n",nr_buffer_heads);
printk("Buffer blocks: %6d\n",nr_buffers);
i = high_memory >> PAGE_SHIFT;
@@ -1141,3 +1164,104 @@ void si_meminfo(struct sysinfo *val)
val->sharedram <<= PAGE_SHIFT;
return;
}
+
+
+/* This handles a generic mmap of a disk file */
+void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned long address)
+{
+ struct inode * inode = area->vm_inode;
+ unsigned int block;
+ unsigned int clear;
+ unsigned long page;
+ unsigned long tmp;
+ int nr[8];
+ int i, j;
+ int prot = area->vm_page_prot; /* prot for buffer cache.. */
+
+ address &= 0xfffff000;
+ block = address - area->vm_start + area->vm_offset;
+ block >>= inode->i_sb->s_blocksize_bits;
+
+ page = get_free_page(GFP_KERNEL);
+ if (share_page(area, area->vm_task, inode, address, error_code, page)) {
+ ++area->vm_task->min_flt;
+ return;
+ }
+
+ ++area->vm_task->maj_flt;
+ if (!page) {
+ oom(current);
+ put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+ return;
+ }
+ for (i=0, j=0; i< PAGE_SIZE ; j++, block++, i += inode->i_sb->s_blocksize)
+ nr[j] = bmap(inode,block);
+
+ /*
+ * If we don't mmap a whole page, we have to clear the end of the page,
+ * which also means that we can't share the page with the buffer cache.
+ * This is easy to handle by giving the 'bread_page()' a protection mask
+ * that contains PAGE_RW, as the cache code won't try to share then..
+ */
+ clear = 0;
+ if (address + PAGE_SIZE > area->vm_end) {
+ clear = address + PAGE_SIZE - area->vm_end;
+ prot |= PAGE_RW;
+ }
+ page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot);
+
+ if (!(error_code & PAGE_RW)) {
+ if (share_page(area, area->vm_task, inode, address, error_code, page))
+ return;
+ }
+
+ tmp = page + PAGE_SIZE;
+ while (clear--) {
+ tmp--;
+ *(char *)tmp = 0;
+ }
+ if (put_page(area->vm_task,page,address,area->vm_page_prot))
+ return;
+ free_page(page);
+ oom(current);
+}
+
+void file_mmap_free(struct vm_area_struct * area)
+{
+ if (area->vm_inode)
+ iput(area->vm_inode);
+#if 0
+ if (area->vm_inode)
+ printk("Free inode %x:%d (%d)\n",area->vm_inode->i_dev,
+ area->vm_inode->i_ino, area->vm_inode->i_count);
+#endif
+}
+
+/*
+ * Compare the contents of the mmap entries, and decide if we are allowed to
+ * share the pages
+ */
+int file_mmap_share(struct vm_area_struct * area1,
+ struct vm_area_struct * area2,
+ unsigned long address)
+{
+ if (area1->vm_inode != area2->vm_inode)
+ return 0;
+ if (area1->vm_start != area2->vm_start)
+ return 0;
+ if (area1->vm_end != area2->vm_end)
+ return 0;
+ if (area1->vm_offset != area2->vm_offset)
+ return 0;
+ if (area1->vm_page_prot != area2->vm_page_prot)
+ return 0;
+ return 1;
+}
+
+struct vm_operations_struct file_mmap = {
+ NULL, /* open */
+ file_mmap_free, /* close */
+ file_mmap_nopage, /* nopage */
+ NULL, /* wppage */
+ file_mmap_share, /* share */
+};
diff --git a/mm/mmap.c b/mm/mmap.c
index dfee9f8..ebfa63d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -34,22 +34,11 @@
#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
current->start_code + current->end_code)
-int sys_mmap(unsigned long *buffer)
+int do_mmap(struct file * file, unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long off)
{
- unsigned long base, addr;
- unsigned long len, limit, off;
- int prot, flags, mask, fd, error;
- struct file *file;
-
- addr = (unsigned long) get_fs_long(buffer); /* user address space*/
- len = (size_t) get_fs_long(buffer+1); /* nbytes of mapping */
- prot = (int) get_fs_long(buffer+2); /* protection */
- flags = (int) get_fs_long(buffer+3); /* mapping type */
- fd = (int) get_fs_long(buffer+4); /* object to map */
- off = (unsigned long) get_fs_long(buffer+5); /* offset in object */
-
- if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd]))
- return -EBADF;
+ int mask, error;
+
if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len)
return -EINVAL;
@@ -75,35 +64,33 @@ int sys_mmap(unsigned long *buffer)
/*
* obtain the address to map to. we verify (or select) it and ensure
- * that it represents a valid section of the address space. we assume
- * that if PROT_EXEC is specified this should be in the code segment.
+ * that it represents a valid section of the address space.
*/
- base = 0;
- limit = TASK_SIZE;
if (flags & MAP_FIXED) {
- /*
- * if MAP_FIXED is specified, we have to map exactly at this
- * address. it must be page aligned and not ambiguous.
- */
- if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
- (off & 0xfff))
+ if ((addr & 0xfff) || addr == 0)
return -EINVAL;
- if (addr + len > limit)
+ if (len > TASK_SIZE || addr > TASK_SIZE - len)
return -ENOMEM;
} else {
- /*
- * we're given a hint as to where to put the address.
- * that we still need to search for a range of pages which
- * are not mapped and which won't impact the stack or data
- * segment.
- * in linux, we only have a code segment and data segment.
- * since data grows up and stack grows down, we're sort of
- * stuck. placing above the data will break malloc, below
- * the stack will cause stack overflow. because of this
- * we don't allow nonspecified mappings...
- */
- return -ENOMEM;
+ struct vm_area_struct * vmm;
+
+ /* Maybe this works.. Ugly it is. */
+ addr = 0x40000000;
+ while (addr+len < 0x60000000) {
+ for (vmm = current->mmap ; vmm ; vmm = vmm->vm_next) {
+ if (addr >= vmm->vm_end)
+ continue;
+ if (addr + len <= vmm->vm_start)
+ continue;
+ addr = (vmm->vm_end + 0xfff) & 0xfffff000;
+ break;
+ }
+ if (!vmm)
+ break;
+ }
+ if (addr+len >= 0x60000000)
+ return -ENOMEM;
}
/*
@@ -117,30 +104,147 @@ int sys_mmap(unsigned long *buffer)
if (prot & (PROT_READ | PROT_EXEC))
mask |= PAGE_READONLY;
if (prot & PROT_WRITE)
- mask |= PAGE_RW;
+ if ((flags & MAP_TYPE) == MAP_PRIVATE)
+ mask |= PAGE_COW;
+ else
+ mask |= PAGE_RW;
if (!mask)
return -EINVAL;
- if ((flags & MAP_TYPE) == MAP_PRIVATE) {
- mask |= PAGE_COW;
- mask &= ~PAGE_RW;
+
+ error = file->f_op->mmap(file->f_inode, file, addr, len, mask, off);
+ if (!error)
+ return addr;
+
+ if (!current->errno)
+ current->errno = -error;
+ return -1;
+}
+
+extern "C" int sys_mmap(unsigned long *buffer)
+{
+ unsigned long fd;
+ struct file * file;
+
+ fd = get_fs_long(buffer+4);
+ if (fd >= NR_OPEN || !(file = current->filp[fd]))
+ return -EBADF;
+ return do_mmap(file, get_fs_long(buffer), get_fs_long(buffer+1),
+ get_fs_long(buffer+2), get_fs_long(buffer+3), get_fs_long(buffer+5));
+}
+
+extern "C" int sys_munmap(unsigned long addr, size_t len)
+{
+ struct vm_area_struct *mpnt, **p, *free;
+
+ if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 || addr + len > TASK_SIZE)
+ return -EINVAL;
+
+ /* This needs a bit of work - we need to figure out how to
+ deal with areas that overlap with something that we are using */
+
+ p = &current->mmap;
+ free = NULL;
+ /*
+ * Check if this memory area is ok - put it on the temporary
+ * list if so..
+ */
+ while ((mpnt = *p) != NULL) {
+ if (addr > mpnt->vm_start && addr < mpnt->vm_end)
+ goto bad_munmap;
+ if (addr+len > mpnt->vm_start && addr + len < mpnt->vm_end)
+ goto bad_munmap;
+ if (addr <= mpnt->vm_start && addr + len >= mpnt->vm_end) {
+ *p = mpnt->vm_next;
+ mpnt->vm_next = free;
+ free = mpnt;
+ continue;
+ }
+ p = &mpnt->vm_next;
}
- error = file->f_op->mmap(file->f_inode, file, base + addr, len, mask, off);
- if (error)
- return error;
- return addr;
+ /*
+ * Ok - we have the memory areas we should free on the 'free' list,
+ * so release them, and unmap the page range..
+ */
+ while (free) {
+ mpnt = free;
+ free = free->vm_next;
+ if (mpnt->vm_ops->close)
+ mpnt->vm_ops->close(mpnt);
+ kfree(mpnt);
+ }
+
+ unmap_page_range(addr, len);
+ return 0;
+bad_munmap:
+/*
+ * the arguments we got were bad: put the temporary list back into the mmap list
+ */
+ while (free) {
+ mpnt = free;
+ free = free->vm_next;
+ mpnt->vm_next = current->mmap;
+ current->mmap = mpnt;
+ }
+ return -EINVAL;
}
-int sys_munmap(unsigned long addr, size_t len)
+/* This is used for a general mmap of a disk file */
+int generic_mmap(struct inode * inode, struct file * file,
+ unsigned long addr, size_t len, int prot, unsigned long off)
{
- unsigned long base, limit;
+ struct vm_area_struct * mpnt;
+ extern struct vm_operations_struct file_mmap;
+ struct buffer_head * bh;
+
+ if (off & (inode->i_sb->s_blocksize - 1))
+ return -EINVAL;
- base = 0;
- limit = TASK_SIZE;
+ if (len > high_memory || off > high_memory - len) /* avoid overflow */
+ return -ENXIO;
- if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
- addr + len > limit)
+ if (get_limit(USER_DS) != TASK_SIZE)
return -EINVAL;
- if (unmap_page_range(base + addr, len))
- return -EAGAIN; /* should never happen */
+
+ if (!inode->i_sb || !S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (!inode->i_op || !inode->i_op->bmap) {
+ iput(inode);
+ return -ENOEXEC;
+ }
+ if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+ brelse(bh);
+
+ mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!mpnt){
+ iput(inode);
+ return -ENOMEM;
+ }
+
+ unmap_page_range(addr, len);
+ mpnt->vm_task = current;
+ mpnt->vm_start = addr;
+ mpnt->vm_end = addr + len;
+ mpnt->vm_page_prot = prot;
+ mpnt->vm_share = NULL;
+ mpnt->vm_inode = inode;
+ inode->i_count++;
+ mpnt->vm_offset = off;
+ mpnt->vm_ops = &file_mmap;
+ mpnt->vm_next = current->mmap;
+ current->mmap = mpnt;
+#if 0
+ printk("VFS: Loaded mmap at %08x - %08x\n",
+ mpnt->vm_start, mpnt->vm_end);
+#endif
return 0;
}
+
diff --git a/mm/swap.c b/mm/swap.c
index 2dc2f04..4658de6 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -38,6 +38,7 @@ static struct swap_info_struct {
unsigned int swap_device;
unsigned char * swap_map;
char * swap_lockmap;
+ int pages;
int lowest_bit;
int highest_bit;
} swap_info[MAX_SWAPFILES];
@@ -79,19 +80,21 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
if (p->swap_device) {
ll_rw_page(rw,p->swap_device,offset,buf);
} else if (p->swap_file) {
- unsigned int zones[4];
- unsigned int block = offset << 2;
- int i;
+ unsigned int zones[8];
+ unsigned int block;
+ int i, j;
- for (i = 0; i < 4; i++)
+ block = offset << (12 - p->swap_file->i_sb->s_blocksize_bits);
+
+ for (i=0, j=0; j< PAGE_SIZE ; i++, j +=p->swap_file->i_sb->s_blocksize)
if (!(zones[i] = bmap(p->swap_file,block++))) {
printk("rw_swap_page: bad swap file\n");
return;
}
- ll_rw_swap_file(rw,p->swap_file->i_dev, zones,4,buf);
+ ll_rw_swap_file(rw,p->swap_file->i_dev, zones, i,buf);
} else
printk("re_swap_page: no swap file or device\n");
- if (clear_bit(offset,p->swap_lockmap))
+ if (!clear_bit(offset,p->swap_lockmap))
printk("rw_swap_page: lock already cleared\n");
wake_up(&lock_queue);
}
@@ -109,6 +112,7 @@ unsigned int get_swap_page(void)
if (p->swap_map[offset])
continue;
p->swap_map[offset] = 1;
+ nr_swap_pages--;
if (offset == p->highest_bit)
p->highest_bit--;
p->lowest_bit = offset;
@@ -179,8 +183,9 @@ void swap_free(unsigned long entry)
if (!p->swap_map[offset])
printk("swap_free: swap-space map bad (entry %08x)\n",entry);
else
- p->swap_map[offset]--;
- if (clear_bit(offset,p->swap_lockmap))
+ if (!--p->swap_map[offset])
+ nr_swap_pages++;
+ if (!clear_bit(offset,p->swap_lockmap))
printk("swap_free: lock already cleared\n");
wake_up(&lock_queue);
}
@@ -199,8 +204,10 @@ void swap_in(unsigned long *table_ptr)
printk("No swap page in swap_in\n");
return;
}
- if (SWP_TYPE(entry) == SHM_SWP_TYPE)
- return shm_no_page ((unsigned long *) table_ptr);
+ if (SWP_TYPE(entry) == SHM_SWP_TYPE) {
+ shm_no_page ((unsigned long *) table_ptr);
+ return;
+ }
page = get_free_page(GFP_KERNEL);
if (!page) {
oom(current);
@@ -224,11 +231,8 @@ static int try_to_swap_out(unsigned long * table_ptr)
page = *table_ptr;
if (!(PAGE_PRESENT & page))
return 0;
- if (page >= high_memory) {
- printk("try_to_swap_out: bad page (%08x)\n",page);
- *table_ptr = 0;
+ if (page >= high_memory)
return 0;
- }
if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
return 0;
if (PAGE_ACCESSED & page) {
@@ -262,7 +266,7 @@ static int try_to_swap_out(unsigned long * table_ptr)
* swapping out or forgetting about. This speeds up the search when we
* actually have to swap.
*/
-int sys_idle(void)
+extern "C" int sys_idle(void)
{
need_resched = 1;
return 0;
@@ -399,8 +403,6 @@ void free_page(unsigned long addr)
printk("PC = %08x\n",*(((unsigned long *)&addr)-1));
return;
}
- printk("Trying to free nonexistent page %08x\n",addr);
- return;
}
/*
@@ -495,11 +497,8 @@ repeat:
page = *ppage;
if (!page)
continue;
- if (!(page & PAGE_PRESENT) || (page >= high_memory)) {
- printk("try_to_unuse: bad page directory (%d,%d:%08x)\n",nr,pgt,page);
- *ppage = 0;
+ if (!(page & PAGE_PRESENT) || (page >= high_memory))
continue;
- }
if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
continue;
ppage = (unsigned long *) (page & 0xfffff000);
@@ -507,13 +506,8 @@ repeat:
page = *ppage;
if (!page)
continue;
- if (page & PAGE_PRESENT) {
- if (page >= high_memory) {
- printk("try_to_unuse: bad page table (%d,%d,%d:%08x)\n",nr,pgt,pg,page);
- *ppage = 0;
- }
+ if (page & PAGE_PRESENT)
continue;
- }
if (SWP_TYPE(page) != type)
continue;
if (!tmp) {
@@ -537,7 +531,7 @@ repeat:
return 0;
}
-int sys_swapoff(const char * specialfile)
+extern "C" int sys_swapoff(const char * specialfile)
{
struct swap_info_struct * p;
struct inode * inode;
@@ -572,6 +566,7 @@ int sys_swapoff(const char * specialfile)
p->flags = SWP_WRITEOK;
return i;
}
+ nr_swap_pages -= p->pages;
iput(p->swap_file);
p->swap_file = NULL;
p->swap_device = 0;
@@ -588,7 +583,7 @@ int sys_swapoff(const char * specialfile)
*
* The swapon system call
*/
-int sys_swapon(const char * specialfile)
+extern "C" int sys_swapon(const char * specialfile)
{
struct swap_info_struct * p;
struct inode * swap_inode;
@@ -703,8 +698,10 @@ int sys_swapon(const char * specialfile)
else
tmp[i] = 128;
tmp[0] = 128;
- p->swap_map = tmp;
+ p->swap_map = (unsigned char *) tmp;
p->flags = SWP_WRITEOK;
+ p->pages = j;
+ nr_swap_pages += j;
printk("Adding Swap: %dk swap-space\n",j<<2);
return 0;
}
diff --git a/net/inet/8390.c b/net/inet/8390.c
index 2ba80b8..500227a 100644
--- a/net/inet/8390.c
+++ b/net/inet/8390.c
@@ -116,7 +116,7 @@ struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
static int
ei_open(struct device *dev)
{
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
if ( ! ei_local) {
printk("%s: Opening a non-existent physical device\n", dev->name);
@@ -140,7 +140,7 @@ static int
ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
int e8390_base = dev->base_addr;
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
int length, send_length;
int tmp_tbusy; /* we must lock dev_tint in dev.c with dev->t_busy =1 */
/* because on a slow pc a quasi endless loop can appear */
@@ -229,7 +229,7 @@ ei_start_xmit(struct sk_buff *skb, struct device *dev)
return 1;
}
dev->trans_start = jiffies;
- ei_block_output(dev, length, (void*)(skb+1), output_page);
+ ei_block_output(dev, length, (unsigned char *)(skb+1), output_page);
if (! ei_local->txing) {
NS8390_trigger_send(dev, send_length, output_page);
if (output_page == ei_local->tx_start_page)
@@ -243,7 +243,7 @@ ei_start_xmit(struct sk_buff *skb, struct device *dev)
tmp_tbusy = 1;
} else {
dev->trans_start = jiffies;
- ei_block_output(dev, length, (void*)(skb+1), ei_local->tx_start_page);
+ ei_block_output(dev, length, (unsigned char *)(skb+1), ei_local->tx_start_page);
NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
tmp_tbusy = 1;
} /* PINGPONG */
@@ -276,7 +276,7 @@ ei_interrupt(int reg_ptr)
return;
}
e8390_base = dev->base_addr;
- ei_local = dev->private;
+ ei_local = (struct ei_device *) dev->priv;
if (dev->interrupt || ei_local->irqlock) {
/* The "irqlock" check is only for testing. */
sti();
@@ -314,7 +314,7 @@ ei_interrupt(int reg_ptr)
if (interrupts & ENISR_TX) {
ei_tx_intr(dev);
} else if (interrupts & ENISR_COUNTERS) {
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
ei_local->soft_rx_errors += inb_p(e8390_base + EN0_COUNTER0);
ei_local->soft_rx_errors += inb_p(e8390_base + EN0_COUNTER1);
ei_local->missed_packets += inb_p(e8390_base + EN0_COUNTER2);
@@ -344,7 +344,7 @@ ei_tx_intr(struct device *dev)
{
int e8390_base = dev->base_addr;
int status = inb(e8390_base + EN0_TSR);
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
if ((status & ENTSR_PTX) == 0)
@@ -398,7 +398,7 @@ static void
ei_receive(struct device *dev)
{
int e8390_base = dev->base_addr;
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
int rxing_page, this_frame, next_frame, current_offset;
int boguscount = 0;
struct e8390_pkt_hdr rx_frame;
@@ -426,7 +426,7 @@ ei_receive(struct device *dev)
break; /* Done for now */
current_offset = this_frame << 8;
- ei_block_input(dev, sizeof(rx_frame), (void *)&rx_frame,
+ ei_block_input(dev, sizeof(rx_frame), (char *)&rx_frame,
current_offset);
size = rx_frame.count - sizeof(rx_frame);
@@ -478,15 +478,15 @@ ei_receive(struct device *dev)
if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
int sksize = sizeof(struct sk_buff) + size;
struct sk_buff *skb;
- skb = kmalloc(sksize, GFP_ATOMIC);
+ skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
if (skb != NULL) {
skb->lock = 0;
skb->mem_len = sksize;
skb->mem_addr = skb;
/* 'skb+1' points to the start of sk_buff data area. */
- ei_block_input(dev, size, (void *)(skb+1),
+ ei_block_input(dev, size, (char *)(skb+1),
current_offset + sizeof(rx_frame));
- if (dev_rint((void *)skb, size, IN_SKBUFF, dev)) {
+ if (dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev)) {
printk("%s: receive buffers full.\n", dev->name);
break;
}
@@ -530,7 +530,7 @@ ei_rx_overrun(struct device *dev)
{
int e8390_base = dev->base_addr;
int reset_start_time = jiffies;
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
/* We should already be stopped and in page0. Remove after testing. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
@@ -578,9 +578,9 @@ ethif_init(struct device *dev)
dev->open = &ei_open;
/* Make up a ei_local structure. */
- dev->private = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
- memset(dev->private, 0, sizeof(struct ei_device));
- ei_local = (struct ei_device *)dev->private;
+ dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct ei_device));
+ ei_local = (struct ei_device *)dev->priv;
#ifndef NO_PINGPONG
ei_local->pingpong = 1;
#endif
@@ -600,8 +600,8 @@ ethif_init(struct device *dev)
#endif
&& 1 ) {
printk("No ethernet device found.\n");
- kfree(dev->private);
- dev->private = NULL;
+ kfree(dev->priv);
+ dev->priv = NULL;
return 1; /* ENODEV or EAGAIN would be more accurate. */
}
@@ -623,9 +623,9 @@ ethdev_init(struct device *dev)
dev->rebuild_header = eth_rebuild_header;
dev->type_trans = eth_type_trans;
- if (dev->private == NULL) {
- dev->private = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
- memset(dev->private, 0, sizeof(struct ei_device));
+ if (dev->priv == NULL) {
+ dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct ei_device));
}
dev->hard_start_xmit = &ei_start_xmit;
@@ -655,7 +655,7 @@ ethdev_init(struct device *dev)
void NS8390_init(struct device *dev, int startp)
{
int e8390_base = dev->base_addr;
- struct ei_device *ei_local = dev->private;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
int i;
int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
diff --git a/net/inet/8390.h b/net/inet/8390.h
index 534b9f4..97ab1be 100644
--- a/net/inet/8390.h
+++ b/net/inet/8390.h
@@ -50,7 +50,7 @@ struct ei_device {
int rx_overrun_packets;
};
-#define ei_status (*(struct ei_device *)(dev->private))
+#define ei_status (*(struct ei_device *)(dev->priv))
/* Some generic ethernet register configurations. */
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
diff --git a/net/inet/CONFIG b/net/inet/CONFIG
index 238df51..9040714 100644
--- a/net/inet/CONFIG
+++ b/net/inet/CONFIG
@@ -14,6 +14,7 @@
# PLIP The Crynwe PL/IP driver
# SLIP The MicroWalt SLIP driver
# SL_DUMP Uses the "dump frame" debug code
+# SL_COMPRESSED Use CSLIP
# D_LINK The D-Link DE-600 Portable Ethernet Adaptor.
# D_LINK_IO The D-Link I/O address (0x378 == default)
# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == default)
@@ -28,8 +29,10 @@
CARDS = -DSLIP -DPLIP -DWD80x3 -DNE2000 -DHPLAN -DEL2 -DD_LINK
# For WD and SMC cards:
-OPTS = -DEI8390=0x280 -DEI8390_IRQ=15
-WD_OPTS = -DWD_SHMEM=0xCC000 -UFORCE_8BIT
+#OPTS = -DEI8390=0x280 -DEI8390_IRQ=15
+#WD_OPTS = -DWD_SHMEM=0xCC000 -UFORCE_8BIT
+OPTS = -DEI8390=0 -DEI8390_IRQ=0
+WD_OPTS = -DWD_SHMEM=0
# For all other cards:
#OPTS = -DEI8390=0 -DEI8390_IRQ=0
@@ -39,5 +42,5 @@ EL_OPTS = -UEL2_AUI
NE_OPTS =
HP_OPTS =
PLIP_OPTS =
-SLIP_OPTS = -DSL_DUMP
+SLIP_OPTS = -DSL_DUMP -DSL_COMPRESSED
DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
diff --git a/net/inet/Makefile b/net/inet/Makefile
index 9e984aa..7ba4fe6 100644
--- a/net/inet/Makefile
+++ b/net/inet/Makefile
@@ -19,7 +19,7 @@
OBJS = Space.o sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \
eth.o packet.o arp.o dev.o 8390.o wd.o ne.o el.o hp.o plip.o \
- slip.o d_link.o auto_irq.o ip.o raw.o icmp.o tcp.o udp.o
+ slip.o slhc.o d_link.o auto_irq.o ip.o raw.o icmp.o tcp.o udp.o
ifdef CONFIG_INET
@@ -47,7 +47,7 @@ wd.o: CONFIG wd.c Makefile
$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c wd.c -o $@
el.o: CONFIG el.c elreg.h Makefile
- $(CC) $(CPPFLAGS) $(CFLAGS) -UEL2_AUI -c el.c -o $@
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(EL_OPTS) -c el.c -o $@
ne.o: CONFIG ne.c Makefile
$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c ne.c -o $@
diff --git a/net/inet/Space.c b/net/inet/Space.c
index d7cbc05..a2ae890 100644
--- a/net/inet/Space.c
+++ b/net/inet/Space.c
@@ -202,10 +202,10 @@
extern int loopback_init(struct device *dev);
static struct device loopback_dev = {
"lo", /* Software Loopback interface */
- -1, /* recv memory end */
+ 0x0, /* recv memory end */
0x0, /* recv memory start */
- -1, /* memory end */
- 0, /* memory start */
+ 0x0, /* memory end */
+ 0x0, /* memory start */
0, /* base I/O address */
0, /* IRQ */
0, 0, 0, /* flags */
diff --git a/net/inet/arp.c b/net/inet/arp.c
index b835d8e..8c5c587 100644
--- a/net/inet/arp.c
+++ b/net/inet/arp.c
@@ -86,7 +86,7 @@ static struct {
#define ARP_MAX_TYPE (sizeof(arp_types) / sizeof(arp_types[0]))
-struct arp_table *arp_table[ARP_TABLE_SIZE] = {
+struct arp_table *arp_tables[ARP_TABLE_SIZE] = {
NULL,
};
struct sk_buff *arp_q = NULL;
@@ -262,7 +262,8 @@ arp_response(struct arphdr *arp1, struct device *dev)
int hlen;
/* Get some mem and initialize it for the return trip. */
- skb = kmalloc(sizeof(struct sk_buff) + sizeof(struct arphdr) +
+ skb = (struct sk_buff *) kmalloc(sizeof(struct sk_buff) +
+ sizeof(struct arphdr) +
(2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
dev->hard_header_len, GFP_ATOMIC);
if (skb == NULL) {
@@ -339,7 +340,7 @@ arp_lookup(unsigned long paddr)
/* Loop through the table for the desired address. */
hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
cli();
- apt = arp_table[hash];
+ apt = arp_tables[hash];
while(apt != NULL) {
if (apt->ip == paddr) {
sti();
@@ -371,7 +372,7 @@ arp_destroy(unsigned long paddr)
hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
cli();
- lapt = &arp_table[hash];
+ lapt = &arp_tables[hash];
while ((apt = *lapt) != NULL) {
if (apt->ip == paddr) {
*lapt = apt->next;
@@ -396,7 +397,7 @@ arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
DPRINTF((DBG_ARP, "%s, ", eth_print(addr)));
DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype));
- apt = kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
+ apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
if (apt == NULL) {
printk("ARP: no memory available for new ARP entry!\n");
return(NULL);
@@ -411,8 +412,8 @@ arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
memcpy(apt->ha, addr, hlen);
apt->last_used = timer_seq;
cli();
- apt->next = arp_table[hash];
- arp_table[hash] = apt;
+ apt->next = arp_tables[hash];
+ arp_tables[hash] = apt;
sti();
return(apt);
}
@@ -528,8 +529,9 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
DPRINTF((DBG_ARP, "dev=%s, ", dev->name));
DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));
- skb = kmalloc(sizeof(struct sk_buff) + sizeof(struct arphdr) +
- (2 * dev->addr_len) + (2 * 4 /* arp->plen */), GFP_ATOMIC);
+ skb = (struct sk_buff *) kmalloc(sizeof(struct sk_buff) +
+ sizeof(struct arphdr) + (2 * dev->addr_len) +
+ (2 * 4 /* arp->plen */), GFP_ATOMIC);
if (skb == NULL) {
printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
return;
@@ -722,7 +724,7 @@ arp_get_info(char *buffer)
i = 0;
for (i = 0; i < ARP_TABLE_SIZE; i++) {
cli();
- apt = arp_table[i];
+ apt = arp_tables[i];
sti();
while (apt != NULL) {
if (pos < (buffer + 4000)) {
@@ -780,7 +782,8 @@ arp_req_set(struct arpreq *req)
}
apt = arp_lookup(si->sin_addr.s_addr);
if (apt == NULL) {
- apt = arp_create(si->sin_addr.s_addr, r.arp_ha.sa_data, hlen, htype);
+ apt = arp_create(si->sin_addr.s_addr,
+ (unsigned char *) r.arp_ha.sa_data, hlen, htype);
if (apt == NULL) return(-ENOMEM);
}
diff --git a/net/inet/d_link.c b/net/inet/d_link.c
index 711f861..f8b42dd 100644
--- a/net/inet/d_link.c
+++ b/net/inet/d_link.c
@@ -508,7 +508,7 @@ d_link_interrupt(int reg_ptr)
dev->interrupt = 1;
sti(); /* Allow other interrupts. */
- localstats = (struct netstats*) dev->private;
+ localstats = (struct netstats*) dev->priv;
interrupts = d_link_read_status(dev);
@@ -613,7 +613,7 @@ d_link_rx_intr(struct device *dev)
printk("%s: Bogus packet size %d.\n", dev->name, size);
sksize = sizeof(struct sk_buff) + size;
- if ((skb = kmalloc(sksize, GFP_ATOMIC)) == NULL) {
+ if ((skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC)) == NULL) {
if (d_link_debug) {
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, sksize);
@@ -644,7 +644,7 @@ d_link_rx_intr(struct device *dev)
localstats->rx_packets++; /* count all receives */
- if(dev_rint((void *)skb, size, IN_SKBUFF, dev)) {
+ if(dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev)) {
printk("%s: receive buffers full.\n", dev->name);
return;
}
@@ -703,8 +703,8 @@ d_link_init(struct device *dev)
}
/* Initialize the device structure. */
- dev->private = kmalloc(sizeof(struct netstats), GFP_KERNEL);
- memset(dev->private, 0, sizeof(struct netstats));
+ dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct netstats));
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
diff --git a/net/inet/dev.c b/net/inet/dev.c
index 7543108..e1ec89e 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -408,7 +408,7 @@ dev_rint(unsigned char *buff, long len, int flags, struct device *dev)
if (flags & IN_SKBUFF) {
skb = (struct sk_buff *) buff;
} else {
- skb = kmalloc(sizeof(*skb) + len, GFP_ATOMIC);
+ skb = (struct sk_buff *) kmalloc(sizeof(*skb) + len, GFP_ATOMIC);
if (skb == NULL) {
printk("dev_rint: packet dropped (no memory) !\n");
dropping = 1;
@@ -543,12 +543,12 @@ inet_bh(void *tmp)
struct sk_buff *skb2;
if (ptype->copy) { /* copy if we need to */
- skb2 = kmalloc(skb->mem_len, GFP_ATOMIC);
+ skb2 = (struct sk_buff *) kmalloc(skb->mem_len, GFP_ATOMIC);
if (skb2 == NULL) continue;
memcpy(skb2, (const void *) skb, skb->mem_len);
skb2->mem_addr = skb2;
skb2->lock = 0;
- skb2->h.raw = (void *)(
+ skb2->h.raw = (unsigned char *)(
(unsigned long) skb2 +
(unsigned long) skb->h.raw -
(unsigned long) skb
@@ -599,15 +599,13 @@ dev_tint(struct device *dev)
struct sk_buff *skb;
for (i = 0; i < DEV_NUMBUFFS; i++) {
+ cli();
while (dev->buffs[i] != NULL) {
- cli();
skb = (struct sk_buff *) dev->buffs[i];
if (skb->magic != DEV_QUEUE_MAGIC) {
printk("INET: dev: skb with bad magic-%X:", skb->magic);
printk("squashing queue\n");
- cli();
dev->buffs[i] = NULL;
- sti();
continue;
}
@@ -624,7 +622,6 @@ dev_tint(struct device *dev)
) {
printk("INET: dev: *** bug bad skb->next,");
printk(", squashing queue\n");
- cli();
dev->buffs[i] = NULL;
} else {
dev->buffs[i]= skb->next;
@@ -640,8 +637,10 @@ dev_tint(struct device *dev)
/* This will send it through the process again. */
dev->queue_xmit(skb, dev, -i - 1);
if (dev->tbusy) return;
+ cli();
}
}
+ sti();
}
@@ -740,8 +739,8 @@ dev_ifsioc(void *arg, unsigned int getset)
dev->pa_addr = (*(struct sockaddr_in *)
&ifr.ifr_addr).sin_addr.s_addr;
dev->family = ifr.ifr_addr.sa_family;
- dev->pa_mask = (dev->pa_addr & get_mask(dev->pa_addr));
- dev->pa_brdaddr = dev->pa_mask | ~get_mask(dev->pa_addr);
+ dev->pa_mask = get_mask(dev->pa_addr);
+ dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
ret = 0;
break;
case SIOCGIFBRDADDR:
diff --git a/net/inet/dev.h b/net/inet/dev.h
index 454084d..2b2d242 100644
--- a/net/inet/dev.h
+++ b/net/inet/dev.h
@@ -86,7 +86,7 @@ struct device {
unsigned short type; /* interface hardware type */
unsigned long trans_start; /* ?? */
unsigned short hard_header_len; /* hardware hdr length */
- void *private; /* pointer to private data */
+ void *priv; /* pointer to private data */
/* Interface address info. */
unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
diff --git a/net/inet/eth.c b/net/inet/eth.c
index 544c6ec..94b80f1 100644
--- a/net/inet/eth.c
+++ b/net/inet/eth.c
@@ -52,6 +52,27 @@ char *eth_print(unsigned char *ptr)
return(buff);
}
+void eth_setup(char *str, int *ints)
+{
+ struct device *d = dev_base;
+
+ if (!str || !*str)
+ return;
+ while (d) {
+ if (!strcmp(str,d->name)) {
+ if (ints[0] > 0)
+ d->irq=ints[1];
+ if (ints[0] > 1)
+ d->base_addr=ints[2];
+ if (ints[0] > 2)
+ d->mem_start=ints[3];
+ if (ints[0] > 3)
+ d->mem_end=ints[4];
+ break;
+ }
+ d=d->next;
+ }
+}
/* Display the contents of the Ethernet MAC header. */
void
@@ -109,7 +130,7 @@ eth_rebuild_header(void *buff, struct device *dev)
unsigned long src, dst;
DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
- eth = buff;
+ eth = (struct ethhdr *) buff;
src = *(unsigned long *) eth->h_source;
dst = *(unsigned long *) eth->h_dest;
DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
diff --git a/net/inet/hp.c b/net/inet/hp.c
index d378dc7..a41d37f 100644
--- a/net/inet/hp.c
+++ b/net/inet/hp.c
@@ -26,14 +26,14 @@ static char *version = "hp.c:v0.99-10 5/28/93 Donald Becker (becker@super.org)\n
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
-__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
-__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
-__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
-__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+__asm__("cld;rep;outsb": :"d" (port),"S" (buf),"c" (nr):"cx","si")
#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */
#define HP_ID 0x07
diff --git a/net/inet/icmp.c b/net/inet/icmp.c
index d60c822..2c2050d 100644
--- a/net/inet/icmp.c
+++ b/net/inet/icmp.c
@@ -89,7 +89,7 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
sizeof(struct iphdr) + sizeof(struct icmphdr) +
sizeof(struct iphdr) + 8; /* amount of header to return */
- skb = kmalloc(len, GFP_ATOMIC);
+ skb = (struct sk_buff *) kmalloc(len, GFP_ATOMIC);
if (skb == NULL) return;
skb->lock = 0;
@@ -112,7 +112,7 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
}
/* Re-adjust length according to actual IP header size. */
- skb->len = offset + sizeof(struct icmphdr) + 8;
+ skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
icmph->type = type;
icmph->code = code;
@@ -120,6 +120,9 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
icmph->un.gateway = 0;
memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph,
+ sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
+
DPRINTF((DBG_ICMP, ">>\n"));
print_icmp(icmph);
@@ -235,7 +238,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
int size, offset;
size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = kmalloc(size, GFP_ATOMIC);
+ skb2 = (struct sk_buff *) kmalloc(size, GFP_ATOMIC);
if (skb2 == NULL) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
@@ -268,7 +271,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
icmphr->checksum = 0;
if (icmph->checksum) { /* Calculate Checksum */
- icmphr->checksum = ip_compute_csum((void *)icmphr, len);
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
}
/* Ship it out - free it when done */
@@ -302,7 +305,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
int size, offset;
size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = kmalloc(size, GFP_ATOMIC);
+ skb2 = (struct sk_buff *) kmalloc(size, GFP_ATOMIC);
if (skb2 == NULL) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
@@ -334,10 +337,10 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
icmphr->checksum = 0;
icmphr->un.echo.id = icmph->un.echo.id;
icmphr->un.echo.sequence = icmph->un.echo.sequence;
- memcpy((char *) (icmphr + 1), (char *) dev->pa_mask, sizeof(dev->pa_mask));
+ memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
if (icmph->checksum) { /* Calculate Checksum */
- icmphr->checksum = ip_compute_csum((void *)icmphr, len);
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
}
/* Ship it out - free it when done */
@@ -383,6 +386,7 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
/* Parse the ICMP message */
switch(icmph->type) {
+ case ICMP_TIME_EXCEEDED:
case ICMP_DEST_UNREACH:
case ICMP_SOURCE_QUENCH:
icmp_unreach(icmph, skb1);
diff --git a/net/inet/ip.c b/net/inet/ip.c
index 19daff8..66a3df1 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -38,6 +38,8 @@
#include "arp.h"
#include "icmp.h"
+extern int last_retran;
+extern void sort_send(struct sock *sk);
void
ip_print(struct iphdr *ip)
@@ -212,6 +214,12 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
if (skb->sk) skb->sk->saddr = saddr;
/* Now build the IP header. */
+
+ /* If we are using IPPROTO_RAW, then we don't need an IP header, since
+ one is being supplied to us by the user */
+
+ if(type == IPPROTO_RAW) return (tmp);
+
iph = (struct iphdr *)buff;
iph->version = 4;
iph->tos = 0;
@@ -422,7 +430,7 @@ ip_compute_csum(unsigned char * buff, int len)
/* Check the header of an incoming IP datagram. */
-static int
+int
ip_csum(struct iphdr *iph)
{
if (iph->check == 0) return(0);
@@ -514,7 +522,7 @@ ip_forward(struct sk_buff *skb, struct device *dev)
in_ntoa(raddr), dev2->name, skb->len));
if (dev2->flags & IFF_UP) {
- skb2 = kmalloc(sizeof(struct sk_buff) +
+ skb2 = (struct sk_buff *) kmalloc(sizeof(struct sk_buff) +
dev2->hard_header_len + skb->len, GFP_ATOMIC);
if (skb2 == NULL) {
printk("\nIP: No memory available for IP forward\n");
@@ -616,12 +624,12 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* and then not for the last one.
*/
if (ipprot->copy) {
- skb2 = kmalloc (skb->mem_len, GFP_ATOMIC);
+ skb2 = (struct sk_buff *) kmalloc (skb->mem_len, GFP_ATOMIC);
if (skb2 == NULL) continue;
memcpy(skb2, skb, skb->mem_len);
skb2->mem_addr = skb2;
skb2->lock = 0;
- skb2->h.raw = (void *)(
+ skb2->h.raw = (unsigned char *)(
(unsigned long)skb2 +
(unsigned long) skb->h.raw -
(unsigned long)skb);
@@ -702,8 +710,6 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
} else {
/* See if we've got a problem. */
if (sk->send_tail == NULL) {
- extern void sort_send(volatile struct sock *sk);
-
printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");
sort_send(sk);
} else {
@@ -712,7 +718,7 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
}
}
sti();
- sk->time_wait.len = sk->rtt<<1;
+ sk->time_wait.len = backoff(sk->backoff) * (2 * sk->mdev + sk->rtt);
sk->timeout = TIME_WRITE;
reset_timer ((struct timer *)&sk->time_wait);
} else {
@@ -780,8 +786,23 @@ ip_retransmit(struct sock *sk, int all)
* get through again. Once we get through, the rtt will settle
* back down reasonably quickly.
*/
- sk->rtt *= 2;
- sk->time_wait.len = sk->rtt;
+ sk->backoff++;
+ sk->time_wait.len = backoff(sk->backoff) * (2 * sk->mdev + sk->rtt);
sk->timeout = TIME_WRITE;
reset_timer((struct timer *)&sk->time_wait);
+
+}
+
+/* Backoff function - the subject of much research */
+int backoff(int n)
+{
+ /* Use binary exponential up to retry #4, and quadratic after that
+ * This yields the sequence
+ * 1, 2, 4, 8, 16, 25, 36, 49, 64, 81, 100 ...
+ */
+
+ if(n <= 4)
+ return 1 << n; /* Binary exponential back off */
+ else
+ return n * n; /* Quadratic back off */
}
diff --git a/net/inet/ip.h b/net/inet/ip.h
index 72c1251..af203cc 100644
--- a/net/inet/ip.h
+++ b/net/inet/ip.h
@@ -21,6 +21,7 @@
#include <linux/ip.h>
+extern int backoff(int n);
extern void ip_print(struct iphdr *ip);
extern int ip_ioctl(struct sock *sk, int cmd,
diff --git a/net/inet/loopback.c b/net/inet/loopback.c
index 954a65e..d370cfc 100644
--- a/net/inet/loopback.c
+++ b/net/inet/loopback.c
@@ -66,6 +66,21 @@ loopback_xmit(struct sk_buff *skb, struct device *dev)
}
dev->tbusy = 0;
+#if 1
+ __asm__("cmpl $0,_intr_count\n\t"
+ "jne 1f\n\t"
+ "movl _bh_active,%%eax\n\t"
+ "testl _bh_mask,%%eax\n\t"
+ "je 1f\n\t"
+ "incl _intr_count\n\t"
+ "call _do_bottom_half\n\t"
+ "decl _intr_count\n"
+ "1:"
+ :
+ :
+ : "ax", "dx", "cx");
+#endif
+
return(0);
}
diff --git a/net/inet/ne.c b/net/inet/ne.c
index 6a63f77..83b0575 100644
--- a/net/inet/ne.c
+++ b/net/inet/ne.c
@@ -29,14 +29,14 @@ static char *version =
/* These should be in <asm/io.h> someday, borrowed from blk_drv/hd.c. */
#define port_read(port,buf,nr) \
-__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write(port,buf,nr) \
-__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
#define port_read_b(port,buf,nr) \
-__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")
+__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_b(port,buf,nr) \
-__asm__("cld;rep;outsb"::"d" (port),"S" (buf),"c" (nr):"cx","si")
+__asm__("cld;rep;outsb": :"d" (port),"S" (buf),"c" (nr):"cx","si")
#define EN_CMD (dev->base_addr)
#define NE_BASE (dev->base_addr)
diff --git a/net/inet/packet.c b/net/inet/packet.c
index 822d314..19800d8 100644
--- a/net/inet/packet.c
+++ b/net/inet/packet.c
@@ -50,7 +50,7 @@ packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct sock *sk;
- sk = pt->data;
+ sk = (struct sock *) pt->data;
skb->dev = dev;
skb->len += dev->hard_header_len;
@@ -118,7 +118,7 @@ packet_sendto(struct sock *sk, unsigned char *from, int len,
} else
return(-EINVAL);
- skb = sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
/* This shouldn't happen, but it could. */
if (skb == NULL) {
@@ -171,7 +171,7 @@ packet_init(struct sock *sk)
{
struct packet_type *p;
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL) return(-ENOMEM);
p->func = packet_rcv;
diff --git a/net/inet/plip.c b/net/inet/plip.c
index a564d67..2522d0a 100644
--- a/net/inet/plip.c
+++ b/net/inet/plip.c
@@ -120,9 +120,9 @@ plip_init(struct device *dev)
dev->base_addr. */
/* Initialize the device structure. */
- dev->private = kmalloc(sizeof(struct netstats), GFP_KERNEL);
- memset(dev->private, 0, sizeof(struct netstats));
- localstats = (struct netstats*) dev->private;
+ dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct netstats));
+ localstats = (struct netstats*) dev->priv;
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
@@ -218,7 +218,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
}
dev->trans_start = jiffies;
- ret_val = plip_write(dev, (void*)(skb+1), skb->len);
+ ret_val = plip_write(dev, (unsigned char *)(skb+1), skb->len);
if (skb->free)
kfree_skb (skb, FREE_WRITE);
dev->tbusy = 0;
@@ -272,7 +272,7 @@ plip_interrupt(int reg_ptr)
if (plip_debug >= 4)
printk("%s: interrupt.\n", dev->name);
- localstats = (struct netstats*) dev->private;
+ localstats = (struct netstats*) dev->priv;
/* Receive the packet here. */
if (inb(dev->base_addr + PAR_STATUS) != 0xc7) {
@@ -291,7 +291,7 @@ plip_interrupt(int reg_ptr)
}
boguscount = length << 5;
sksize = sizeof(struct sk_buff) + length;
- skb = kmalloc(sksize, GFP_ATOMIC);
+ skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
if (skb == NULL) {
if (plip_debug)
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
@@ -304,7 +304,7 @@ plip_interrupt(int reg_ptr)
skb->mem_addr = skb;
{
/* 'skb+1' points to the start of sk_buff data area. */
- unsigned char *buf = (void*) (skb+1);
+ unsigned char *buf = (unsigned char *) (skb+1);
int checksum = 0;
while (length--) {
@@ -313,7 +313,7 @@ plip_interrupt(int reg_ptr)
}
if (checksum != get_byte(dev))
localstats->soft_rx_errors++;
- else if(dev_rint((void *)skb, length, IN_SKBUFF, dev)) {
+ else if(dev_rint((unsigned char *)skb, length, IN_SKBUFF, dev)) {
printk("%s: receive buffers full.\n", dev->name);
localstats->rx_errors++;
return;
diff --git a/net/inet/proc.c b/net/inet/proc.c
index 5d1dc3d..b15cbc3 100644
--- a/net/inet/proc.c
+++ b/net/inet/proc.c
@@ -25,7 +25,7 @@
#include <linux/net.h>
#include <linux/un.h>
#include <linux/in.h>
-#include <sys/param.h>
+#include <linux/param.h>
#include "inet.h"
#include "timer.h"
#include "dev.h"
diff --git a/net/inet/raw.c b/net/inet/raw.c
index c8d1324..67d2e39 100644
--- a/net/inet/raw.c
+++ b/net/inet/raw.c
@@ -57,7 +57,7 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
err, header, daddr, saddr, protocol));
if (protocol == NULL) return;
- sk = protocol->data;
+ sk = (struct sock *) protocol->data;
if (sk == NULL) return;
/* This is meaningless in raw sockets. */
@@ -98,7 +98,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
kfree_skb(skb, FREE_READ);
return(0);
}
- sk = protocol->data;
+ sk = (struct sock *) protocol->data;
if (sk == NULL) {
kfree_skb(skb, FREE_READ);
return(0);
@@ -194,8 +194,9 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
sk->inuse = 1;
skb = NULL;
while (skb == NULL) {
- skb = sk->prot->wmalloc(sk, len+sizeof(*skb) + sk->prot->max_header,
- 0, GFP_KERNEL);
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk,
+ len+sizeof(*skb) + sk->prot->max_header,
+ 0, GFP_KERNEL);
/* This shouldn't happen, but it could. */
/* FIXME: need to change this to sleep. */
if (skb == NULL) {
@@ -237,6 +238,20 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
/* verify_area(VERIFY_WRITE, from, len);*/
memcpy_fromfs ((unsigned char *)(skb+1)+tmp, from, len);
+
+ /* If we are using IPPROTO_RAW, we need to fill in the source address in
+ the IP header */
+
+ if(sk->protocol==IPPROTO_RAW) {
+ unsigned char *buff;
+ struct iphdr *iph;
+
+ buff = (unsigned char *)(skb + 1);
+ buff += tmp;
+ iph = (struct iphdr *)buff;
+ iph->saddr = sk->saddr;
+ }
+
skb->len = tmp + len;
sk->prot->queue_xmit(sk, dev, skb, 1);
release_sock(sk);
@@ -274,7 +289,7 @@ raw_init(struct sock *sk)
{
struct inet_protocol *p;
- p = kmalloc(sizeof (*p), GFP_KERNEL);
+ p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
if (p == NULL) return(-ENOMEM);
p->handler = raw_rcv;
diff --git a/net/inet/route.c b/net/inet/route.c
index cfdca28..c4b91b2 100644
--- a/net/inet/route.c
+++ b/net/inet/route.c
@@ -113,7 +113,7 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
int mask;
/* Allocate an entry. */
- rt = kmalloc(sizeof(struct rtable), GFP_ATOMIC);
+ rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
if (rt == NULL) {
DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
return;
diff --git a/net/inet/slhc.c b/net/inet/slhc.c
new file mode 100644
index 0000000..5e597f6
--- /dev/null
+++ b/net/inet/slhc.c
@@ -0,0 +1,721 @@
+/*
+ * Routines to compress and uncompress tcp packets (for transmission
+ * over low speed serial lines).
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ *
+ *
+ * modified for KA9Q Internet Software Package by
+ * Katie Stevens (dkstevens@ucdavis.edu)
+ * University of California, Davis
+ * Computing Services
+ * - 01-31-90 initial adaptation (from 1.19)
+ * PPP.05 02-15-90 [ks]
+ * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression
+ * PPP.15 09-90 [ks] improve mbuf handling
+ * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities
+ *
+ * - Feb 1991 Bill_Simpson@um.cc.umich.edu
+ * variable number of conversation slots
+ * allow zero or one slots
+ * separate routines
+ * status display
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/termios.h>
+#include <linux/in.h>
+#include <linux/fcntl.h>
+#include "inet.h"
+#include "timer.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "icmp.h"
+#include "tcp.h"
+#include "skbuff.h"
+#include "sock.h"
+#include "arp.h"
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <linux/mm.h>
+#include "slhc.h"
+
+#define DPRINT(x)
+
+int last_retran;
+
+static unsigned char *encode(unsigned char *cp,int n);
+static long decode(unsigned char **cpp);
+static unsigned char * put16(unsigned char *cp, unsigned short x);
+static unsigned short pull16(unsigned char **cpp);
+
+extern int ip_csum(struct iphdr *iph);
+
+
+/* Initialize compression data structure
+ * slots must be in range 0 to 255 (zero meaning no compression)
+ */
+struct slcompress *
+slhc_init(int rslots, int tslots)
+{
+ register short i;
+ register struct cstate *ts;
+ struct slcompress *comp;
+
+ comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
+ GFP_KERNEL);
+ if (! comp)
+ return NULL;
+
+ memset(comp, 0, sizeof(struct slcompress));
+
+ if ( rslots > 0 && rslots < 256 ) {
+ comp->rstate =
+ (struct cstate *)kmalloc(rslots * sizeof(struct cstate),
+ GFP_KERNEL);
+ if (! comp->rstate)
+ return NULL;
+ memset(comp->rstate, 0, rslots * sizeof(struct cstate));
+ comp->rslot_limit = rslots - 1;
+ }
+
+ if ( tslots > 0 && tslots < 256 ) {
+ comp->tstate =
+ (struct cstate *)kmalloc(tslots * sizeof(struct cstate),
+ GFP_KERNEL);
+ if (! comp->tstate)
+ return NULL;
+ memset(comp->tstate, 0, rslots * sizeof(struct cstate));
+ comp->tslot_limit = tslots - 1;
+ }
+
+ comp->xmit_oldest = 0;
+ comp->xmit_current = 255;
+ comp->recv_current = 255;
+ /*
+ * don't accept any packets with implicit index until we get
+ * one with an explicit index. Otherwise the uncompress code
+ * will try to use connection 255, which is almost certainly
+ * out of range
+ */
+ comp->flags |= SLF_TOSS;
+
+ if ( tslots > 0 ) {
+ ts = comp->tstate;
+ for(i = comp->tslot_limit; i > 0; --i){
+ ts[i].cs_this = i;
+ ts[i].next = &(ts[i - 1]);
+ }
+ ts[0].next = &(ts[comp->tslot_limit]);
+ ts[0].cs_this = 0;
+ }
+ return comp;
+}
+
+
+/* Free a compression data structure */
+void
+slhc_free(struct slcompress *comp)
+{
+ if ( comp == NULLSLCOMPR )
+ return;
+
+ if ( comp->rstate != NULLSLSTATE )
+ kfree( comp->rstate );
+
+ if ( comp->tstate != NULLSLSTATE )
+ kfree( comp->tstate );
+
+ kfree( comp );
+}
+
+
+/* Put a short in host order into a char array in network order */
+static unsigned char *
+put16(unsigned char *cp, unsigned short x)
+{
+ *cp++ = x >> 8;
+ *cp++ = x;
+
+ return cp;
+}
+
+
+/* Encode a number */
+unsigned char *
+encode(unsigned char *cp, int n)
+{
+ if(n >= 256 || n == 0){
+ *cp++ = 0;
+ cp = put16(cp,n);
+ } else {
+ *cp++ = n;
+ }
+ return cp;
+}
+
+/* Pull a 16-bit integer in host order from buffer in network byte order */
+static unsigned short
+pull16(unsigned char **cpp)
+{
+ short rval;
+
+ rval = *(*cpp)++;
+ rval <<= 8;
+ rval |= *(*cpp)++;
+ return rval;
+}
+
+/* Decode a number */
+long
+decode(unsigned char **cpp)
+{
+ register int x;
+
+ x = *(*cpp)++;
+ if(x == 0){
+ return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */
+ } else {
+ return x & 0xff; /* -1 if PULLCHAR returned error */
+ }
+}
+
+/*
+ * icp and isize are the original packet.
+ * ocp is a place to put a copy if necessary.
+ * cpp is initially a pointer to icp. If the copy is used,
+ * change it to ocp.
+ */
+
+int
+slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
+ unsigned char *ocp, unsigned char **cpp, int compress_cid)
+{
+ register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
+ register struct cstate *lcs = ocs;
+ register struct cstate *cs = lcs->next;
+ register unsigned long deltaS, deltaA;
+ register short changes = 0;
+ int hlen;
+ unsigned char new_seq[16];
+ register unsigned char *cp = new_seq;
+ struct iphdr *ip;
+ struct tcphdr *th, *oth;
+
+ ip = (struct iphdr *) icp;
+
+ /* Bail if this packet isn't TCP, or is an IP fragment */
+ if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
+ (ip->frag_off & 32)){
+ DPRINT(("comp: noncomp 1 %d %d %d\n", ip->protocol,
+ ntohs(ip->frag_off), ip->frag_off));
+ /* Send as regular IP */
+ if(ip->protocol != IPPROTO_TCP)
+ comp->sls_o_nontcp++;
+ else
+ comp->sls_o_tcp++;
+ return isize;
+ }
+ /* Extract TCP header */
+
+ th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
+ hlen = ip->ihl*4 + th->doff*4;
+
+ /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
+ * some other control bit is set).
+ */
+ if(th->syn || th->fin || th->rst ||
+ ! (th->ack)){
+ DPRINT(("comp: noncomp 2 %x %x %d %d %d %d\n", ip, th,
+ th->syn, th->fin, th->rst, th->ack));
+ /* TCP connection stuff; send as regular IP */
+ comp->sls_o_tcp++;
+ return isize;
+ }
+ /*
+ * Packet is compressible -- we're going to send either a
+ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way,
+ * we need to locate (or create) the connection state.
+ *
+ * States are kept in a circularly linked list with
+ * xmit_oldest pointing to the end of the list. The
+ * list is kept in lru order by moving a state to the
+ * head of the list whenever it is referenced. Since
+ * the list is short and, empirically, the connection
+ * we want is almost always near the front, we locate
+ * states via linear search. If we don't find a state
+ * for the datagram, the oldest state is (re-)used.
+ */
+ for ( ; ; ) {
+ if( ip->saddr == cs->cs_ip.saddr
+ && ip->daddr == cs->cs_ip.daddr
+ && th->source == cs->cs_tcp.source
+ && th->dest == cs->cs_tcp.dest)
+ goto found;
+
+ /* if current equal oldest, at end of list */
+ if ( cs == ocs )
+ break;
+ lcs = cs;
+ cs = cs->next;
+ comp->sls_o_searches++;
+ };
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an
+ * uncompressed packet that tells the other side what
+ * connection number we're using for this conversation.
+ *
+ * Note that since the state list is circular, the oldest
+ * state points to the newest and we only need to set
+ * xmit_oldest to update the lru linkage.
+ */
+ comp->sls_o_misses++;
+ comp->xmit_oldest = lcs->cs_this;
+ DPRINT(("comp: not found\n"));
+ goto uncompressed;
+
+found:
+ /*
+ * Found it -- move to the front on the connection list.
+ */
+ if(lcs == ocs) {
+ /* found at most recently used */
+ } else if (cs == ocs) {
+ /* found at least recently used */
+ comp->xmit_oldest = lcs->cs_this;
+ } else {
+ /* more than 2 elements */
+ lcs->next = cs->next;
+ cs->next = ocs->next;
+ ocs->next = cs;
+ }
+
+ /*
+ * Make sure that only what we expect to change changed.
+ * Check the following:
+ * IP protocol version, header length & type of service.
+ * The "Don't fragment" bit.
+ * The time-to-live field.
+ * The TCP header length.
+ * IP options, if any.
+ * TCP options, if any.
+ * If any of these things are different between the previous &
+ * current datagram, we send the current datagram `uncompressed'.
+ */
+ oth = &cs->cs_tcp;
+
+ if(last_retran
+ || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
+ || ip->tos != cs->cs_ip.tos
+ || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64)
+ || ip->ttl != cs->cs_ip.ttl
+ || th->doff != cs->cs_tcp.doff
+ || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
+ || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4 != 0))){
+ DPRINT(("comp: incompat\n"));
+ goto uncompressed;
+ }
+
+ /*
+ * Figure out which of the changing fields changed. The
+ * receiver expects changes in the order: urgent, window,
+ * ack, seq (the order minimizes the number of temporaries
+ * needed in this section of code).
+ */
+ if(th->urg){
+ deltaS = ntohs(th->urg_ptr);
+ cp = encode(cp,deltaS);
+ changes |= NEW_U;
+ } else if(th->urg_ptr != oth->urg_ptr){
+ /* argh! URG not set but urp changed -- a sensible
+ * implementation should never do this but RFC793
+ * doesn't prohibit the change so we have to deal
+ * with it. */
+ DPRINT(("comp: urg incompat\n"));
+ goto uncompressed;
+ }
+ if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
+ cp = encode(cp,deltaS);
+ changes |= NEW_W;
+ }
+ if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
+ if(deltaA > 0x0000ffff)
+ goto uncompressed;
+ cp = encode(cp,deltaA);
+ changes |= NEW_A;
+ }
+ if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
+ if(deltaS > 0x0000ffff)
+ goto uncompressed;
+ cp = encode(cp,deltaS);
+ changes |= NEW_S;
+ }
+
+ switch(changes){
+ case 0: /* Nothing changed. If this packet contains data and the
+ * last one didn't, this is probably a data packet following
+ * an ack (normal on an interactive connection) and we send
+ * it compressed. Otherwise it's probably a retransmit,
+ * retransmitted ack or window probe. Send it uncompressed
+ * in case the other side missed the compressed version.
+ */
+ if(ip->tot_len != cs->cs_ip.tot_len &&
+ ntohs(cs->cs_ip.tot_len) == hlen)
+ break;
+ DPRINT(("comp: retrans\n"));
+ goto uncompressed;
+ break;
+ case SPECIAL_I:
+ case SPECIAL_D:
+ /* actual changes match one of our special case encodings --
+ * send packet uncompressed.
+ */
+ DPRINT(("comp: special\n"));
+ goto uncompressed;
+ case NEW_S|NEW_A:
+ if(deltaS == deltaA &&
+ deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+ case NEW_S:
+ if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+ deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
+ if(deltaS != 1){
+ cp = encode(cp,deltaS);
+ changes |= NEW_I;
+ }
+ if(th->psh)
+ changes |= TCP_PUSH_BIT;
+ /* Grab the cksum before we overwrite it below. Then update our
+ * state with this packet's header.
+ */
+ deltaA = ntohs(th->check);
+ memcpy(&cs->cs_ip,ip,20);
+ memcpy(&cs->cs_tcp,th,20);
+ /* We want to use the original packet as our compressed packet.
+ * (cp - new_seq) is the number of bytes we need for compressed
+ * sequence numbers. In addition we need one byte for the change
+ * mask, one for the connection id and two for the tcp checksum.
+ * So, (cp - new_seq) + 4 bytes of header are needed.
+ */
+ deltaS = cp - new_seq;
+ if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
+ cp = ocp;
+ *cpp = ocp;
+ *cp++ = changes | NEW_C;
+ *cp++ = cs->cs_this;
+ comp->xmit_current = cs->cs_this;
+ } else {
+ cp = ocp;
+ *cpp = ocp;
+ *cp++ = changes;
+ }
+ cp = put16(cp,(short)deltaA); /* Write TCP checksum */
+/* deltaS is now the size of the change section of the compressed header */
+ DPRINT(("comp: %x %x %x %d %d\n", icp, cp, new_seq, hlen, deltaS));
+ memcpy(cp,new_seq,deltaS); /* Write list of deltas */
+ memcpy(cp+deltaS,icp+hlen,isize-hlen);
+ comp->sls_o_compressed++;
+ ocp[0] |= SL_TYPE_COMPRESSED_TCP;
+ return isize - hlen + deltaS + (cp - ocp);
+
+ /* Update connection state cs & send uncompressed packet (i.e.,
+ * a regular ip/tcp packet but with the 'conversation id' we hope
+ * to use on future compressed packets in the protocol field).
+ */
+uncompressed:
+ memcpy(&cs->cs_ip,ip,20);
+ memcpy(&cs->cs_tcp,th,20);
+ if (ip->ihl > 5)
+ memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
+ if (th->doff > 5)
+ memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
+ comp->xmit_current = cs->cs_this;
+ comp->sls_o_uncompressed++;
+ memcpy(ocp, icp, isize);
+ *cpp = ocp;
+ ocp[9] = cs->cs_this;
+ ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
+ return isize;
+}
+
+
+int
+slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
+{
+ register int changes;
+ long x;
+ register struct tcphdr *thp;
+ register struct iphdr *ip;
+ register struct cstate *cs;
+ int len, hdrlen;
+ unsigned char *cp = icp;
+
+ /* We've got a compressed packet; read the change byte */
+ comp->sls_i_compressed++;
+ if(isize < 3){
+ comp->sls_i_error++;
+ DPRINT(("uncomp: runt\n"));
+ return 0;
+ }
+ changes = *cp++;
+ if(changes & NEW_C){
+ /* Make sure the state index is in range, then grab the state.
+ * If we have a good state index, clear the 'discard' flag.
+ */
+ x = *cp++; /* Read conn index */
+ if(x < 0 || x > comp->rslot_limit)
+ goto bad;
+
+ comp->flags &=~ SLF_TOSS;
+ comp->recv_current = x;
+ } else {
+ /* this packet has an implicit state index. If we've
+ * had a line error since the last time we got an
+ * explicit state index, we have to toss the packet. */
+ if(comp->flags & SLF_TOSS){
+ comp->sls_i_tossed++;
+ DPRINT(("uncomp: toss\n"));
+ return 0;
+ }
+ }
+ cs = &comp->rstate[comp->recv_current];
+ thp = &cs->cs_tcp;
+ ip = &cs->cs_ip;
+
+ if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */
+ DPRINT(("uncomp: bad tcp chk\n"));
+ goto bad;
+ }
+ thp->check = htons(x);
+
+ thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
+/*
+ * we can use the same number for the length of the saved header and
+ * the current one, because the packet wouldn't have been sent
+ * as compressed unless the options were the same as the previous one
+ */
+
+ hdrlen = ip->ihl * 4 + thp->doff * 4;
+
+ switch(changes & SPECIALS_MASK){
+ case SPECIAL_I: /* Echoed terminal traffic */
+ {
+ register short i;
+ i = ntohs(ip->tot_len) - hdrlen;
+ thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
+ thp->seq = htonl( ntohl(thp->seq) + i);
+ }
+ break;
+
+ case SPECIAL_D: /* Unidirectional data */
+ thp->seq = htonl( ntohl(thp->seq) +
+ ntohs(ip->tot_len) - hdrlen);
+ break;
+
+ default:
+ if(changes & NEW_U){
+ thp->urg = 1;
+ if((x = decode(&cp)) == -1) {
+ DPRINT(("uncomp: bad U\n"));
+ goto bad;
+ }
+ thp->urg_ptr = htons(x);
+ } else
+ thp->urg = 0;
+ if(changes & NEW_W){
+ if((x = decode(&cp)) == -1) {
+ DPRINT(("uncomp: bad W\n"));
+ goto bad;
+ }
+ thp->window = htons( ntohs(thp->window) + x);
+ }
+ if(changes & NEW_A){
+ if((x = decode(&cp)) == -1) {
+ DPRINT(("uncomp: bad A\n"));
+ goto bad;
+ }
+ thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
+ }
+ if(changes & NEW_S){
+ if((x = decode(&cp)) == -1) {
+ DPRINT(("uncomp: bad S\n"));
+ goto bad;
+ }
+ thp->seq = htonl( ntohl(thp->seq) + x);
+ }
+ break;
+ }
+ if(changes & NEW_I){
+ if((x = decode(&cp)) == -1) {
+ DPRINT(("uncomp: bad I\n"));
+ goto bad;
+ }
+ ip->id = htons (ntohs (ip->id) + x);
+ } else
+ ip->id = htons (ntohs (ip->id) + 1);
+
+ /*
+ * At this point, cp points to the first byte of data in the
+ * packet. Put the reconstructed TCP and IP headers back on the
+ * packet. Recalculate IP checksum (but not TCP checksum).
+ */
+
+ len = isize - (cp - icp) + hdrlen;
+ ip->tot_len = htons(len);
+ ip->check = 0;
+
+ DPRINT(("uncomp: %d %d %d %d\n", cp - icp, hdrlen, isize, len));
+
+ memmove(icp + hdrlen, cp, len - hdrlen);
+
+ cp = icp;
+ memcpy(cp, ip, 20);
+ cp += 20;
+
+ if (ip->ihl > 5) {
+ memcpy(cp, cs->cs_ipopt, ((ip->ihl) - 5) * 4);
+ cp += ((ip->ihl) - 5) * 4;
+ }
+
+ memcpy(cp, thp, 20);
+ cp += 20;
+
+ if (thp->doff > 5) {
+ memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
+ cp += ((thp->doff) - 5) * 4;
+ }
+
+if (inet_debug == DBG_SLIP) printk("\runcomp: change %x len %d\n", changes, len);
+ return len;
+bad:
+ comp->sls_i_error++;
+ return slhc_toss( comp );
+}
+
+
+int
+slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
+{
+ register struct cstate *cs;
+ short ip_len;
+ struct iphdr *ip;
+ struct tcphdr *thp;
+
+ unsigned char index;
+
+ if(isize < 20) {
+ /* The packet is shorter than a legal IP header */
+ comp->sls_i_runt++;
+ return slhc_toss( comp );
+ }
+ /* Sneak a peek at the IP header's IHL field to find its length */
+ ip_len = (icp[0] & 0xf) << 2;
+ if(ip_len < 20){
+ /* The IP header length field is too small */
+ comp->sls_i_runt++;
+ return slhc_toss( comp );
+ }
+ index = icp[9];
+ icp[9] = IPPROTO_TCP;
+ ip = (struct iphdr *) icp;
+
+ if (ip_csum(ip)) {
+ /* Bad IP header checksum; discard */
+ comp->sls_i_badcheck++;
+ return slhc_toss( comp );
+ }
+ thp = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
+ if(index > comp->rslot_limit) {
+ comp->sls_i_error++;
+ return slhc_toss(comp);
+ }
+
+ /* Update local state */
+ cs = &comp->rstate[comp->recv_current = index];
+ comp->flags &=~ SLF_TOSS;
+ memcpy(&cs->cs_ip,ip,20);
+ memcpy(&cs->cs_tcp,thp,20);
+ if (ip->ihl > 5)
+ memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
+ if (thp->doff > 5)
+ memcpy(cs->cs_tcpopt, thp+1, ((thp->doff) - 5) * 4);
+ cs->cs_hsize = ip->ihl*2 + thp->doff*2;
+ /* Put headers back on packet
+ * Neither header checksum is recalculated
+ */
+ comp->sls_i_uncompressed++;
+ return isize;
+}
+
+
+int
+slhc_toss(struct slcompress *comp)
+{
+ if ( comp == NULLSLCOMPR )
+ return 0;
+
+ comp->flags |= SLF_TOSS;
+ return 0;
+}
+
+
+void slhc_i_status(struct slcompress *comp)
+{
+ if (comp != NULLSLCOMPR) {
+ printk("\t%ld Cmp, %ld Uncmp, %ld Bad, %ld Tossed\n",
+ comp->sls_i_compressed,
+ comp->sls_i_uncompressed,
+ comp->sls_i_error,
+ comp->sls_i_tossed);
+ }
+}
+
+
+void slhc_o_status(struct slcompress *comp)
+{
+ if (comp != NULLSLCOMPR) {
+ printk("\t%ld Cmp, %ld Uncmp, %ld AsIs, %ld NotTCP\n",
+ comp->sls_o_compressed,
+ comp->sls_o_uncompressed,
+ comp->sls_o_tcp,
+ comp->sls_o_nontcp);
+ printk("\t%10ld Searches, %10ld Misses\n",
+ comp->sls_o_searches,
+ comp->sls_o_misses);
+ }
+}
+
diff --git a/net/inet/slhc.h b/net/inet/slhc.h
new file mode 100644
index 0000000..0044b02
--- /dev/null
+++ b/net/inet/slhc.h
@@ -0,0 +1,187 @@
+#ifndef _SLHC_H
+#define _SLHC_H
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ *
+ *
+ * modified for KA9Q Internet Software Package by
+ * Katie Stevens (dkstevens@ucdavis.edu)
+ * University of California, Davis
+ * Computing Services
+ * - 01-31-90 initial adaptation
+ *
+ * - Feb 1991 Bill_Simpson@um.cc.umich.edu
+ * variable number of conversation slots
+ * allow zero or one slots
+ * separate routines
+ * status display
+ */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* SLIP compression masks for len/vers byte */
+#define SL_TYPE_IP 0x40
+#define SL_TYPE_UNCOMPRESSED_TCP 0x70
+#define SL_TYPE_COMPRESSED_TCP 0x80
+#define SL_TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+/*
+ * data type and sizes conversion assumptions:
+ *
+ * VJ code KA9Q style generic
+ * u_char byte_t unsigned char 8 bits
+ * u_short int16 unsigned short 16 bits
+ * u_int int16 unsigned short 16 bits
+ * u_long unsigned long unsigned long 32 bits
+ * int int32 long 32 bits
+ */
+
+typedef unsigned char byte_t;
+typedef unsigned long int32;
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ byte_t cs_this; /* connection id number (xmit) */
+ struct cstate *next; /* next in ring (xmit) */
+ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */
+ struct tcphdr cs_tcp;
+ unsigned char cs_ipopt[64];
+ unsigned char cs_tcpopt[64];
+ int cs_hsize;
+};
+#define NULLSLSTATE (struct cstate *)0
+
+/*
+ * all the state data for one serial line (we need one of these per line).
+ */
+struct slcompress {
+ struct cstate *tstate; /* transmit connection states (array)*/
+ struct cstate *rstate; /* receive connection states (array)*/
+
+ byte_t tslot_limit; /* highest transmit slot id (0-l)*/
+ byte_t rslot_limit; /* highest receive slot id (0-l)*/
+
+ byte_t xmit_oldest; /* oldest xmit in ring */
+ byte_t xmit_current; /* most recent xmit id */
+ byte_t recv_current; /* most recent rcvd id */
+
+ byte_t flags;
+#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */
+
+ int32 sls_o_nontcp; /* outbound non-TCP packets */
+ int32 sls_o_tcp; /* outbound TCP packets */
+ int32 sls_o_uncompressed; /* outbound uncompressed packets */
+ int32 sls_o_compressed; /* outbound compressed packets */
+ int32 sls_o_searches; /* searches for connection state */
+ int32 sls_o_misses; /* times couldn't find conn. state */
+
+ int32 sls_i_uncompressed; /* inbound uncompressed packets */
+ int32 sls_i_compressed; /* inbound compressed packets */
+ int32 sls_i_error; /* inbound error packets */
+ int32 sls_i_tossed; /* inbound packets tossed because of error */
+
+ int32 sls_i_runt;
+ int32 sls_i_badcheck;
+};
+#define NULLSLCOMPR (struct slcompress *)0
+
+#define __ARGS(x) x
+
+/* In slhc.c: */
+struct slcompress *slhc_init __ARGS((int rslots, int tslots));
+void slhc_free __ARGS((struct slcompress *comp));
+
+int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp,
+ int isize, unsigned char *ocp, unsigned char **cpp,
+ int compress_cid));
+int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp,
+ int isize));
+int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp,
+ int isize));
+int slhc_toss __ARGS((struct slcompress *comp));
+
+void slhc_i_status __ARGS((struct slcompress *comp));
+void slhc_o_status __ARGS((struct slcompress *comp));
+
+#endif /* _SLHC_H */
diff --git a/net/inet/slip.c b/net/inet/slip.c
index e86adbc..00ea959 100644
--- a/net/inet/slip.c
+++ b/net/inet/slip.c
@@ -36,10 +36,16 @@
#include "sock.h"
#include "arp.h"
#include "slip.h"
+#include "slhc.h"
#define SLIP_VERSION "0.7.5"
+#ifdef SL_COMPRESSED
+#define COMPRESSED_SLIP 1
+#else
+#define COMPRESSED_SLIP 0
+#endif
/* Define some IP layer stuff. Not all systems have it. */
#ifdef SL_DUMP
@@ -64,15 +70,25 @@ ip_dump(unsigned char *ptr, int len)
{
#ifdef SL_DUMP
struct iphdr *ip;
+ struct tcphdr *th;
int dlen, doff;
if (inet_debug != DBG_SLIP) return;
ip = (struct iphdr *) ptr;
+ th = (struct tcphdr *) (ptr + ip->ihl * 4);
+ printk("\r%s -> %s seq %x ack %x len %d\n",
+ in_ntoa(ip->saddr), in_ntoa(ip->daddr),
+ ntohl(th->seq), ntohl(th->ack_seq), ntohs(ip->tot_len));
+ return;
+
+ printk("\r*****\n");
+ printk("%x %d\n", ptr, len);
+ ip = (struct iphdr *) ptr;
dlen = ntohs(ip->tot_len);
doff = ((ntohs(ip->frag_off) & IPF_F_OFFSET) << 3);
- printk("\r*****\n");
+
printk("SLIP: %s->", in_ntoa(ip->saddr));
printk("%s\n", in_ntoa(ip->daddr));
printk(" len %u ihl %u ver %u ttl %u prot %u",
@@ -88,6 +104,17 @@ ip_dump(unsigned char *ptr, int len)
#endif
}
+void clh_dump(unsigned char *cp, int len)
+{
+ if (len > 60)
+ len = 60;
+ printk("%d:", len);
+ while (len > 0) {
+ printk(" %x", *cp++);
+ len--;
+ }
+ printk("\n\n");
+}
/* Initialize a SLIP control block for use. */
static void
@@ -100,10 +127,12 @@ sl_initialize(struct slip *sl, struct device *dev)
sl->line = dev->base_addr;
sl->tty = NULL;
sl->dev = dev;
+ sl->slcomp = NULL;
/* Clear all pointers. */
sl->rbuff = NULL;
sl->xbuff = NULL;
+ sl->cbuff = NULL;
sl->rhead = NULL;
sl->rend = NULL;
@@ -141,10 +170,11 @@ sl_alloc(void)
for (i = 0; i < SL_NRUNIT; i++) {
sl = &sl_ctrl[i];
if (sl->inuse == 0) {
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
sl->inuse = 1;
sl->tty = NULL;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
return(sl);
}
}
@@ -159,10 +189,11 @@ sl_free(struct slip *sl)
unsigned long flags;
if (sl->inuse) {
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
sl->inuse = 0;
sl->tty = NULL;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
}
@@ -173,28 +204,29 @@ sl_enqueue(struct slip *sl, unsigned char c)
{
unsigned long flags;
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
if (sl->rhead < sl->rend) {
*sl->rhead = c;
sl->rhead++;
sl->rcount++;
} else sl->roverrun++;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
-
/* Release 'i' bytes from a SLIP receiver buffer. */
static inline void
sl_dequeue(struct slip *sl, int i)
{
unsigned long flags;
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
if (sl->rhead > sl->rbuff) {
sl->rhead -= i;
sl->rcount -= i;
}
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
@@ -204,10 +236,11 @@ sl_lock(struct slip *sl)
{
unsigned long flags;
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
sl->sending = 1;
sl->dev->tbusy = 1;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
@@ -217,10 +250,11 @@ sl_unlock(struct slip *sl)
{
unsigned long flags;
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ save_flags(flags);
+ cli();
sl->sending = 0;
sl->dev->tbusy = 0;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ restore_flags(flags);
}
@@ -229,6 +263,42 @@ static void
sl_bump(struct slip *sl)
{
int done;
+ unsigned char c;
+ unsigned long flags;
+ int count;
+
+ count = sl->rcount;
+ if (COMPRESSED_SLIP) {
+ if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
+ /* make sure we've reserved enough space for uncompress to use */
+ save_flags(flags);
+ cli();
+ if ((sl->rhead + 80) < sl->rend) {
+ sl->rhead += 80;
+ sl->rcount += 80;
+ done = 1;
+ } else {
+ sl->roverrun++;
+ done = 0;
+ }
+ restore_flags(flags);
+ if (! done) /* not enough space available */
+ return;
+
+ if ((count = slhc_uncompress((struct slcompress *)sl->slcomp,
+ sl->rbuff, count)) <= 0 ) {
+ sl->errors++;
+ return;
+ }
+ } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
+ sl->rbuff[0] &= 0x4f;
+ if ( slhc_remember((struct slcompress *)sl->slcomp, sl->rbuff,
+ count ) <= 0 ) {
+ sl->errors++;
+ return;
+ }
+ }
+ }
DPRINTF((DBG_SLIP, "<< \"%s\" recv:\r\n", sl->dev->name));
ip_dump(sl->rbuff, sl->rcount);
@@ -237,9 +307,11 @@ sl_bump(struct slip *sl)
do {
DPRINTF((DBG_SLIP, "SLIP: packet is %d at 0x%X\n",
sl->rcount, sl->rbuff));
- done = dev_rint(sl->rbuff, sl->rcount, 0, sl->dev);
+ /* clh_dump(sl->rbuff, count); */
+ done = dev_rint(sl->rbuff, count, 0, sl->dev);
if (done == 0 || done == 1) break;
} while(1);
+
sl->rpacket++;
}
@@ -250,21 +322,26 @@ sl_next(struct slip *sl)
{
DPRINTF((DBG_SLIP, "SLIP: sl_next(0x%X) called!\n", sl));
sl_unlock(sl);
+ dev_tint(sl->dev);
}
/* Encapsulate one IP datagram and stuff into a TTY queue. */
static void
-sl_encaps(struct slip *sl, unsigned char *p, int len)
+sl_encaps(struct slip *sl, unsigned char *icp, int len)
{
- unsigned char *bp;
+ unsigned char *bp, *p;
unsigned char c;
int count;
DPRINTF((DBG_SLIP, "SLIP: sl_encaps(0x%X, %d) called\n", p, len));
DPRINTF((DBG_SLIP, ">> \"%s\" sent:\r\n", sl->dev->name));
- ip_dump(p, len);
+ ip_dump(icp, len);
+ p = icp;
+ len = slhc_compress((struct slcompress *)sl->slcomp, p, len,
+ sl->cbuff, &p, 1);
+
/*
* Send an initial END character to flush out any
* data that may have accumulated in the receiver
@@ -426,6 +503,19 @@ sl_open(struct device *dev)
sl->sending = 0;
sl->rcount = 0;
+ p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
+ if (p == NULL) {
+ DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP COMPRESS buffer!\n"));
+ return(-ENOMEM);
+ }
+ sl->cbuff = p;
+
+ sl->slcomp = slhc_init(16, 16);
+ if (sl->slcomp == NULL) {
+ DPRINTF((DBG_SLIP, "SLIP: no memory for SLCOMP!\n"));
+ return(-ENOMEM);
+ }
+
DPRINTF((DBG_SLIP, "SLIP: channel %d opened.\n", sl->line));
return(0);
}
@@ -447,6 +537,9 @@ sl_close(struct device *dev)
/* Free all SLIP frame buffers. */
kfree(sl->rbuff);
kfree(sl->xbuff);
+ kfree(sl->cbuff);
+ slhc_free(sl->slcomp);
+
sl_initialize(sl, dev);
DPRINTF((DBG_SLIP, "SLIP: channel %d closed.\n", sl->line));
@@ -495,7 +588,7 @@ slip_recv(struct tty_struct *tty)
sl->escape = 0;
break;
case END:
- if (sl->rcount > 3) sl_bump(sl);
+ if (sl->rcount > 2) sl_bump(sl);
sl_dequeue(sl, sl->rcount);
sl->rcount = 0;
sl->escape = 0;
diff --git a/net/inet/slip.h b/net/inet/slip.h
index 3bd021f..eb19031 100644
--- a/net/inet/slip.h
+++ b/net/inet/slip.h
@@ -33,10 +33,12 @@ struct slip {
int line; /* SLIP channel number */
struct tty_struct *tty; /* ptr to TTY structure */
struct device *dev; /* easy for intr handling */
+ struct slcompress *slcomp; /* for header compression */
/* These are pointers to the malloc()ed frame buffers. */
unsigned char *rbuff; /* receiver buffer */
unsigned char *xbuff; /* transmitter buffer */
+ unsigned char *cbuff; /* compression buffer */
/* These are the various pointers into the buffers. */
unsigned char *rhead; /* RECV buffer pointer (head) */
diff --git a/net/inet/sock.c b/net/inet/sock.c
index 544c4d7..a5f30b8 100644
--- a/net/inet/sock.c
+++ b/net/inet/sock.c
@@ -491,7 +491,7 @@ inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -526,7 +526,7 @@ inet_setsockopt(struct socket *sock, int level, int optname,
/* This should really pass things on to the other levels. */
if (level != SOL_SOCKET) return(-EOPNOTSUPP);
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -591,7 +591,7 @@ inet_getsockopt(struct socket *sock, int level, int optname,
/* This should really pass things on to the other levels. */
if (level != SOL_SOCKET) return(-EOPNOTSUPP);
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -654,7 +654,7 @@ inet_listen(struct socket *sock, int backlog)
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -685,7 +685,7 @@ inet_create(struct socket *sock, int protocol)
struct proto *prot;
int err;
- sk = kmalloc(sizeof(*sk), GFP_KERNEL);
+ sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
if (sk == NULL) return(-ENOMEM);
sk->num = 0;
@@ -759,6 +759,8 @@ inet_create(struct socket *sock, int protocol)
sk->fin_seq = 0;
sk->proc = 0;
sk->rtt = TCP_WRITE_TIME;
+ sk->mdev = 0;
+ sk->backoff = 0;
sk->packets_out = 0;
sk->cong_window = 1; /* start with only sending one packet at a time. */
sk->exp_growth = 1; /* if set cong_window grow exponentially every time
@@ -859,7 +861,7 @@ inet_release(struct socket *sock, struct socket *peer)
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) return(0);
DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer));
@@ -910,7 +912,7 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
struct sock *sk, *sk2;
unsigned short snum;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -935,7 +937,7 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
snum = ntohs(addr.sin_port);
DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum));
- sk = sock->data;
+ sk = (struct sock *) sock->data;
/*
* We can't just leave the socket bound wherever it is, it might
@@ -943,7 +945,7 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
* be a bug here, we will leave it if the port is not privileged.
*/
if (snum == 0) {
- if (sk->num > PROT_SOCK) return(0);
+/* if (sk->num > PROT_SOCK) return(0); */
snum = get_new_socknum(sk->prot, 0);
}
if (snum <= PROT_SOCK && !suser()) return(-EACCES);
@@ -955,13 +957,13 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
sk->prot->sock_array[snum &(SOCK_ARRAY_SIZE -1)]));
/* Make sure we are allowed to bind here. */
-outside_loop:
cli();
+outside_loop:
for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];
sk2 != NULL; sk2 = sk2->next) {
#if 1 /* should be below! */
if (sk2->num != snum) continue;
- if (sk2->saddr != sk->saddr) continue;
+/* if (sk2->saddr != sk->saddr) continue; */
#endif
if (sk2->dead) {
destroy_sock(sk2);
@@ -995,7 +997,7 @@ inet_connect(struct socket *sock, struct sockaddr * uaddr,
int err;
sock->conn = NULL;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1051,7 +1053,7 @@ inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk1, *sk2;
- sk1 = sock->data;
+ sk1 = (struct sock *) sock->data;
if (sk1 == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1080,7 +1082,7 @@ inet_accept(struct socket *sock, struct socket *newsock, int flags)
}
}
newsock->data = (void *)sk2;
- sk2->sleep = (void *)newsock->wait;
+ sk2->sleep = newsock->wait;
newsock->conn = NULL;
if (flags & O_NONBLOCK) return(0);
@@ -1124,7 +1126,7 @@ inet_getname(struct socket *sock, struct sockaddr *uaddr,
if (len < sizeof(sin)) return(-EINVAL);
sin.sin_family = AF_INET;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1152,7 +1154,7 @@ inet_read(struct socket *sock, char *ubuf, int size, int noblock)
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1165,7 +1167,7 @@ inet_read(struct socket *sock, char *ubuf, int size, int noblock)
put_sock(sk->num, sk);
sk->dummy_th.source = ntohs(sk->num);
}
- return(sk->prot->read(sk, ubuf, size, noblock,0));
+ return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock,0));
}
@@ -1175,7 +1177,7 @@ inet_recv(struct socket *sock, void *ubuf, int size, int noblock,
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1188,7 +1190,7 @@ inet_recv(struct socket *sock, void *ubuf, int size, int noblock,
put_sock(sk->num, sk);
sk->dummy_th.source = ntohs(sk->num);
}
- return(sk->prot->read(sk, ubuf, size, noblock, flags));
+ return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags));
}
@@ -1197,7 +1199,7 @@ inet_write(struct socket *sock, char *ubuf, int size, int noblock)
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1215,7 +1217,7 @@ inet_write(struct socket *sock, char *ubuf, int size, int noblock)
sk->dummy_th.source = ntohs(sk->num);
}
- return(sk->prot->write(sk, ubuf, size, noblock, 0));
+ return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, 0));
}
@@ -1225,7 +1227,7 @@ inet_send(struct socket *sock, void *ubuf, int size, int noblock,
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1243,7 +1245,7 @@ inet_send(struct socket *sock, void *ubuf, int size, int noblock,
sk->dummy_th.source = ntohs(sk->num);
}
- return(sk->prot->write(sk, ubuf, size, noblock, flags));
+ return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));
}
@@ -1253,7 +1255,7 @@ inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1273,7 +1275,7 @@ inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
sk->dummy_th.source = ntohs(sk->num);
}
- return(sk->prot->sendto(sk, ubuf, size, noblock, flags,
+ return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags,
(struct sockaddr_in *)sin, addr_len));
}
@@ -1284,7 +1286,7 @@ inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1300,7 +1302,7 @@ inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
sk->dummy_th.source = ntohs(sk->num);
}
- return(sk->prot->recvfrom(sk, ubuf, size, noblock, flags,
+ return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags,
(struct sockaddr_in*)sin, addr_len));
}
@@ -1318,7 +1320,7 @@ inet_shutdown(struct socket *sock, int how)
1->2 bit 2 snds.
2->3 */
if (how & ~SHUTDOWN_MASK) return(-EINVAL);
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1338,7 +1340,7 @@ inet_select(struct socket *sock, int sel_type, select_table *wait )
{
struct sock *sk;
- sk = sock->data;
+ sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
@@ -1359,7 +1361,7 @@ inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
DPRINTF((DBG_INET, "INET: in inet_ioctl\n"));
sk = NULL;
- if (sock && (sk = sock->data) == NULL) {
+ if (sock && (sk = (struct sock *) sock->data) == NULL) {
printk("AF_INET: Warning: sock->data = NULL: %d\n" , __LINE__);
return(0);
}
@@ -1368,13 +1370,13 @@ inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case FIOSETOWN:
case SIOCSPGRP:
if (sk)
- sk->proc = get_fs_long((void *) arg);
+ sk->proc = get_fs_long((int *) arg);
return(0);
case FIOGETOWN:
case SIOCGPGRP:
if (sk) {
verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
- put_fs_long(sk->proc,(void *)arg);
+ put_fs_long(sk->proc,(int *)arg);
}
return(0);
#if 0 /* FIXME: */
diff --git a/net/inet/sock.h b/net/inet/sock.h
index 783c0cf..c51db07 100644
--- a/net/inet/sock.h
+++ b/net/inet/sock.h
@@ -83,7 +83,9 @@ struct sock {
volatile unsigned short urg;
volatile unsigned short shutdown;
unsigned short mss;
- volatile short rtt;
+ volatile unsigned long rtt;
+ volatile unsigned long mdev;
+ volatile unsigned short backoff;
volatile short err;
unsigned char protocol;
volatile unsigned char state;
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 8c0f971..bbc9654 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -353,7 +353,7 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
release_sock(sk);
verify_area(VERIFY_WRITE,(void *) arg,
sizeof(unsigned long));
- put_fs_long(answ,(void *) arg);
+ put_fs_long(answ,(int *) arg);
return(0);
}
case TIOCOUTQ:
@@ -374,7 +374,7 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
/* This routine computes a TCP checksum. */
-static unsigned short
+unsigned short
tcp_check(struct tcphdr *th, int len,
unsigned long saddr, unsigned long daddr)
{
@@ -436,7 +436,7 @@ tcp_check(struct tcphdr *th, int len,
}
-static void
+void
tcp_send_check(struct tcphdr *th, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
@@ -498,7 +498,7 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
* We need to grab some memory, and put together an ack,
* and then put it into the queue to be sent.
*/
- buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) {
/* Force it to send an ack. */
sk->ack_backlog++;
@@ -507,6 +507,7 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
sk->time_wait.len = 10; /* got to do it quickly */
reset_timer((struct timer *)&sk->time_wait);
}
+if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
return;
}
@@ -522,6 +523,7 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
if (tmp < 0) {
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
return;
}
buff->len += tmp;
@@ -556,6 +558,8 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
t1->ack_seq = ntohl(ack);
t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
+if (inet_debug == DBG_SLIP) printk("\rtcp_ack: seq %x ack %x\n",
+ sequence, ack);
sk->prot->queue_xmit(sk, dev, buff, 1);
}
@@ -722,8 +726,9 @@ tcp_write(struct sock *sk, unsigned char *from,
if (sk->packets_out && copy < sk->mss && !(flags & MSG_OOB)) {
/* We will release the socket incase we sleep here. */
release_sock(sk);
- skb = prot->wmalloc(sk, sk->mss + 128 + prot->max_header +
- sizeof(*skb), 0, GFP_KERNEL);
+ skb = (struct sk_buff *) prot->wmalloc(sk,
+ sk->mss + 128 + prot->max_header +
+ sizeof(*skb), 0, GFP_KERNEL);
sk->inuse = 1;
sk->send_tmp = skb;
if (skb != NULL)
@@ -731,8 +736,9 @@ tcp_write(struct sock *sk, unsigned char *from,
} else {
/* We will release the socket incase we sleep here. */
release_sock(sk);
- skb = prot->wmalloc(sk, copy + prot->max_header +
- sizeof(*skb), 0, GFP_KERNEL);
+ skb = (struct sk_buff *) prot->wmalloc(sk,
+ copy + prot->max_header +
+ sizeof(*skb), 0, GFP_KERNEL);
sk->inuse = 1;
if (skb != NULL)
skb->mem_len = copy+prot->max_header + sizeof(*skb);
@@ -885,7 +891,7 @@ tcp_read_wakeup(struct sock *sk)
* We need to grab some memory, and put together an ack,
* and then put it into the queue to be sent.
*/
- buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
if (buff == NULL) {
/* Try again real soon. */
sk->timeout = TIME_WRITE;
@@ -990,7 +996,7 @@ cleanup_rbuf(struct sock *sk)
tcp_read_wakeup(sk);
} else {
/* Force it to send an ack soon. */
- if (before(jiffies + TCP_ACK_TIME, sk->time_wait.when)) {
+ if (jiffies + TCP_ACK_TIME < sk->time_wait.when) {
sk->time_wait.len = TCP_ACK_TIME;
sk->timeout = TIME_WRITE;
reset_timer((struct timer *) &sk->time_wait);
@@ -1313,7 +1319,7 @@ tcp_shutdown(struct sock *sk, int how)
prot =(struct proto *)sk->prot;
th =(struct tcphdr *)&sk->dummy_th;
release_sock(sk); /* incase the malloc sleeps. */
- buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
+ buff = (struct sk_buff *) prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
if (buff == NULL) return;
sk->inuse = 1;
@@ -1407,7 +1413,7 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
* We need to grab some memory, and put together an RST,
* and then put it into the queue to be sent.
*/
- buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
+ buff = (struct sk_buff *) prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) return;
DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
@@ -1499,7 +1505,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
* and if the listening socket is destroyed before this is taken
* off of the queue, this will take care of it.
*/
- newsk = kmalloc(sizeof(struct sock), GFP_ATOMIC);
+ newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
if (newsk == NULL) {
/* just ignore the syn. It will get retransmitted. */
kfree_skb(skb, FREE_READ);
@@ -1515,6 +1521,8 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->send_tail = NULL;
newsk->back_log = NULL;
newsk->rtt = TCP_CONNECT_TIME;
+ newsk->mdev = 0;
+ newsk->backoff = 0;
newsk->blog = 0;
newsk->intr = 0;
newsk->proc = 0;
@@ -1573,7 +1581,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
}
}
- buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
+ buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) {
sk->err = -ENOMEM;
newsk->dead = 1;
@@ -1734,7 +1742,7 @@ tcp_close(struct sock *sk, int timeout)
case TCP_SYN_RECV:
prot =(struct proto *)sk->prot;
th =(struct tcphdr *)&sk->dummy_th;
- buff = prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
+ buff = (struct sk_buff *) prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) {
/* This will force it to try again later. */
if (sk->state != TCP_CLOSE_WAIT)
@@ -1783,7 +1791,8 @@ tcp_close(struct sock *sk, int timeout)
if (sk->wfront == NULL) {
prot->queue_xmit(sk, dev, buff, 0);
} else {
- sk->time_wait.len = sk->rtt;
+ sk->time_wait.len = backoff(sk->backoff) *
+ (2 * sk->mdev + sk->rtt);
sk->timeout = TIME_WRITE;
reset_timer((struct timer *)&sk->time_wait);
buff->next = NULL;
@@ -2020,17 +2029,31 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
/* Wake up the process, it can probably write more. */
if (!sk->dead) wake_up(sk->sleep);
- cli();
-
oskb = sk->send_head;
/* Estimate the RTT. Ignore the ones right after a retransmit. */
- if (sk->retransmits == 0 && !(flag&2))
- sk->rtt += ((jiffies - oskb->when) - sk->rtt)>>2;
+ if (sk->retransmits == 0 && !(flag&2)) {
+ long abserr, rtt = jiffies - oskb->when;
+
+ if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
+ /* first ack, so nothing else to average with */
+ sk->rtt = rtt;
+ else {
+ abserr = (rtt > sk->rtt) ? rtt - sk->rtt : sk->rtt - rtt;
+ sk->rtt = (7 * sk->rtt + rtt) >> 3;
+ sk->mdev = (3 * sk->mdev + abserr) >> 2;
+ }
+ sk->backoff = 0;
+ }
+ flag |= (2|4);
+ /* no point retransmitting faster than .1 sec */
+ /* 2 minutes is max legal rtt for Internet */
+ if (sk->rtt < 10) sk->rtt = 10;
+ if (sk->rtt > 12000) sk->rtt = 12000;
- flag |= 2;
- if (sk->rtt < 1) sk->rtt = 1;
+ cli();
+ oskb = sk->send_head;
sk->send_head =(struct sk_buff *)oskb->link3;
if (sk->send_head == NULL) {
sk->send_tail = NULL;
@@ -2058,9 +2081,9 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
else arp_q =(struct sk_buff *)oskb->next;
}
}
+ sti();
oskb->magic = 0;
kfree_skb(oskb, FREE_WRITE); /* write. */
- sti();
if (!sk->dead) wake_up(sk->sleep);
} else {
break;
@@ -2088,7 +2111,8 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
} else {
if (sk->state != (unsigned char) sk->keepopen) {
sk->timeout = TIME_WRITE;
- sk->time_wait.len = sk->rtt*2;
+ sk->time_wait.len = backoff(sk->backoff) *
+ (2 * sk->mdev + sk->rtt);
reset_timer((struct timer *)&sk->time_wait);
}
if (sk->state == TCP_TIME_WAIT) {
@@ -2132,7 +2156,8 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
}
if (((!flag) || (flag&4)) && sk->send_head != NULL &&
- (sk->send_head->when + sk->rtt < jiffies)) {
+ (sk->send_head->when + backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)
+ < jiffies)) {
sk->exp_growth = 0;
ip_retransmit(sk, 0);
}
@@ -2277,7 +2302,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
if (!sk->delay_acks ||
sk->ack_backlog >= sk->max_ack_backlog ||
sk->bytes_rcv > sk->max_unacked || th->fin) {
- tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr);
+/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */
} else {
sk->ack_backlog++;
sk->time_wait.len = TCP_ACK_TIME;
@@ -2338,7 +2363,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq) {
DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk));
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_LAST_ACK;
if (!sk->dead) wake_up(sk->sleep);
@@ -2510,7 +2535,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
sk->dummy_th.dest = sin.sin_port;
release_sock(sk);
- buff=sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
if (buff == NULL) {
return(-ENOMEM);
}
@@ -2673,6 +2698,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
if (th->check && tcp_check(th, len, saddr, daddr )) {
skb->sk = NULL;
DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n"));
+if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: back checksum\n");
kfree_skb(skb, 0);
/*
* We don't release the socket because it was
@@ -2767,6 +2793,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
case TCP_FIN_WAIT2:
case TCP_TIME_WAIT:
if (!tcp_sequence(sk, th, len, opt, saddr)) {
+if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
+ tcp_send_ack(sk->send_seq, sk->acked_seq,
+ sk, th, saddr);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
@@ -2784,7 +2813,8 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
* A reset with a fin just means that
* the data was not all read.
*/
- if (!th->fin) {
+/* The comment above appears completely bogus --clh */
+/* if (!th->fin) { */
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) {
@@ -2793,7 +2823,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
- }
+/* } */
}
#if 0
if (opt && (opt->security != 0 ||
@@ -3043,7 +3073,7 @@ tcp_write_wakeup(struct sock *sk)
if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) return;
- buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
if (buff == NULL) return;
buff->lock = 0;
diff --git a/net/inet/tcp.h b/net/inet/tcp.h
index 637247e..b567e3c 100644
--- a/net/inet/tcp.h
+++ b/net/inet/tcp.h
@@ -44,10 +44,10 @@
#define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs */
#define TCP_TIMEWAIT_LEN 1000 /* how long to wait to sucessfully
* close the socket, about 60 seconds */
-#define TCP_ACK_TIME 30000 /* time to delay before sending an ACK */
+#define TCP_ACK_TIME 3000 /* time to delay before sending an ACK */
#define TCP_DONE_TIME 250 /* maximum time to wait before actually
* destroying a socket */
-#define TCP_WRITE_TIME 30000 /* initial time to wait for an ACK,
+#define TCP_WRITE_TIME 3000 /* initial time to wait for an ACK,
* after last transmit */
#define TCP_CONNECT_TIME 2000 /* time to retransmit first SYN */
#define TCP_SYN_RETRIES 5 /* number of times to retry openning a
diff --git a/net/inet/timer.c b/net/inet/timer.c
index 1b337f7..e7bc3e2 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -89,7 +89,7 @@ reset_timer(struct timer *t)
t, t->when, jiffies));
if (t == NULL) {
printk("*** reset timer NULL timer\n");
- __asm__ ("\t int $3\n"::);
+ __asm__ ("\t int $3\n");
}
if (t->running) {
DPRINTF((DBG_TMR, "t->running has value of %d, len %d\n",
@@ -109,6 +109,7 @@ reset_timer(struct timer *t)
t->len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
delete_timer(t);
+ cli();
t->when = timer_seq + t->len;
/* First see if it goes at the beginning. */
@@ -234,24 +235,34 @@ net_timer(void)
* to check for that.
*/
if (sk->send_head != NULL) {
- if (before(jiffies, sk->send_head->when +
- sk->rtt)) {
- sk->time_wait.len = sk->rtt;
+ if (jiffies < (sk->send_head->when +
+ backoff(sk->backoff) *
+ (2 * sk->mdev + sk->rtt))) {
+/* printk("timer: not yet\n"); */
+ sk->time_wait.len =
+ (sk->send_head->when +
+ backoff(sk->backoff) *
+ (2 * sk->mdev + sk->rtt)) - jiffies;
sk->timeout = TIME_WRITE;
reset_timer(&sk->time_wait);
release_sock(sk);
break;
}
+/* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq,
+ sk->retransmits, sk->packets_out, sk->cong_window); */
DPRINTF((DBG_TMR, "retransmitting.\n"));
sk->prot->retransmit(sk, 0);
-
- if (sk->retransmits > TCP_RETR1) {
+ if ((sk->state == TCP_ESTABLISHED &&
+ sk->retransmits != 0 &&
+ (sk->retransmits & 7) == 0) ||
+ (sk->state != TCP_ESTABLISHED &&
+ sk->retransmits > TCP_RETR1)) {
DPRINTF((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
arp_destroy(sk->daddr);
ip_route_check(sk->daddr);
}
-
- if (sk->retransmits > TCP_RETR2) {
+ if (sk->state != TCP_ESTABLISHED &&
+ sk->retransmits > TCP_RETR2) {
DPRINTF((DBG_TMR, "timer.c TIME_WRITE time-out 2\n"));
sk->err = ETIMEDOUT;
if (sk->state == TCP_FIN_WAIT1 ||
@@ -280,14 +291,19 @@ net_timer(void)
sk->state = TCP_CLOSE;
}
- if (sk->retransmits > TCP_RETR1) {
+ if ((sk->state == TCP_ESTABLISHED &&
+ sk->retransmits != 0 &&
+ (sk->retransmits & 7) == 0) ||
+ (sk->state != TCP_ESTABLISHED &&
+ sk->retransmits > TCP_RETR1)) {
DPRINTF((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
arp_destroy(sk->daddr);
ip_route_check(sk->daddr);
release_sock(sk);
break;
}
- if (sk->retransmits > TCP_RETR2) {
+ if (sk->state != TCP_ESTABLISHED &&
+ sk->retransmits > TCP_RETR2) {
DPRINTF((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
arp_destroy (sk->daddr);
sk->err = ETIMEDOUT;
diff --git a/net/inet/udp.c b/net/inet/udp.c
index 2344634..1ea33bd 100644
--- a/net/inet/udp.c
+++ b/net/inet/udp.c
@@ -210,7 +210,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
/* Allocate a copy of the packet. */
size = sizeof(struct sk_buff) + sk->prot->max_header + len;
- skb = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
if (skb == NULL) return(-ENOMEM);
skb->lock = 0;
@@ -327,7 +327,7 @@ udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
if (!suser()) return(-EPERM);
verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
- val = get_fs_long((void *)arg);
+ val = get_fs_long((int *)arg);
switch(val) {
case 0:
inet_debug = 0;
diff --git a/net/inet/utils.c b/net/inet/utils.c
index 96948dd..ddbebe3 100644
--- a/net/inet/utils.c
+++ b/net/inet/utils.c
@@ -87,7 +87,7 @@ dprintf(int level, char *fmt, ...)
if (level != inet_debug) return;
- buff = kmalloc(256, GFP_ATOMIC);
+ buff = (char *) kmalloc(256, GFP_ATOMIC);
if (buff != NULL) {
va_start(args, fmt);
vsprintf(buff, fmt, args);
@@ -105,7 +105,7 @@ dbg_ioctl(void *arg, int level)
if (!suser()) return(-EPERM);
verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
- val = get_fs_long((void *)arg);
+ val = get_fs_long((int *)arg);
switch(val) {
case 0: /* OFF */
inet_debug = DBG_OFF;
diff --git a/net/inet/wd.c b/net/inet/wd.c
index 5e1322b..c99af3c 100644
--- a/net/inet/wd.c
+++ b/net/inet/wd.c
@@ -348,7 +348,7 @@ wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
}
memcpy(buf, xfer_start, count);
if (ei_debug > 4) {
- unsigned short *board = xfer_start;
+ unsigned short *board = (unsigned short *) xfer_start;
printk("%s: wd8013 block_input(cnt=%d offset=%3x addr=%#x) = %2x %2x %2x...\n",
dev->name, count, ring_offset, xfer_start,
board[-1], board[0], board[1]);
@@ -368,7 +368,7 @@ wd_block_output(struct device *dev, int count, const unsigned char *buf,
int start_page)
{
unsigned char *shmem
- = (void *)dev->mem_start + ((start_page - WD_START_PG)<<8);
+ = (unsigned char *)dev->mem_start + ((start_page - WD_START_PG)<<8);
#if !defined(WD_no_mapout)
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
int reg5_val = ((dev->mem_start>>19) & 0x1f) | NIC16;
diff --git a/net/socket.c b/net/socket.c
index 2f3788d..f64c123 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -65,8 +65,6 @@ static struct proto_ops *pops[NPROTO];
static int net_debug = 0;
-extern int sys_close(int fd);
-
#ifdef SOCK_DEBUG
/* Module debugging. */
static void
@@ -374,7 +372,8 @@ sock_awaitconn(struct socket *mysock, struct socket *servsock)
wake_up(servsock->wait);
if (mysock->state != SS_CONNECTED) {
interruptible_sleep_on(mysock->wait);
- if (mysock->state != SS_CONNECTED) {
+ if (mysock->state != SS_CONNECTED &&
+ mysock->state != SS_DISCONNECTING) {
/*
* if we're not connected we could have been
* 1) interrupted, so we need to remove ourselves
@@ -807,7 +806,7 @@ sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
* we have this level of indirection. Not a lot of overhead, since more of
* the work is done via read/write/select directly.
*/
-int
+extern "C" int
sys_socketcall(int call, unsigned long *args)
{
switch(call) {
@@ -909,7 +908,7 @@ net_ioctl(unsigned int cmd, unsigned long arg)
switch(cmd) {
case DDIOCSDBG:
verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
- net_debug = get_fs_long((void *)arg);
+ net_debug = get_fs_long((int *)arg);
if (net_debug != 0 && net_debug != 1) {
net_debug = 0;
return(-EINVAL);
diff --git a/net/unix/proc.c b/net/unix/proc.c
index ac6644c..19e0ab3 100644
--- a/net/unix/proc.c
+++ b/net/unix/proc.c
@@ -27,7 +27,7 @@
#include <linux/net.h>
#include <linux/ddi.h>
#include <linux/un.h>
-#include <sys/param.h>
+#include <linux/param.h>
#include "unix.h"
@@ -63,9 +63,9 @@ int unix_get_info(char *buffer)
/*
* Check wether buffer _may_ overflow in the next loop.
* Since sockets may have very very long paths, we make
- * MAXPATHLEN+100 the minimum space left for a new line.
+ * PATH_MAX+100 the minimum space left for a new line.
*/
- if (pos > buffer+PAGE_SIZE-80-MAXPATHLEN) {
+ if (pos > buffer+PAGE_SIZE-80-PATH_MAX) {
printk("UNIX: netinfo: oops, too many sockets.\n");
return(pos - buffer);
}
diff --git a/net/unix/sock.c b/net/unix/sock.c
index c8e13b5..ddf14d6 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -88,7 +88,7 @@ dprintf(int level, char *fmt, ...)
if (level != unix_debug) return;
- buff = kmalloc(256, GFP_KERNEL);
+ buff = (char *) kmalloc(256, GFP_KERNEL);
if (buff != NULL) {
va_start(args, fmt);
vsprintf(buff, fmt, args);
@@ -178,7 +178,7 @@ unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
if (flags != 0) return(-EINVAL);
- return(unix_proto_write(sock, buff, len, nonblock));
+ return(unix_proto_write(sock, (char *) buff, len, nonblock));
}
@@ -188,7 +188,7 @@ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
if (flags != 0) return(-EINVAL);
- return(unix_proto_read(sock, buff, len, nonblock));
+ return(unix_proto_read(sock, (char *) buff, len, nonblock));
}
@@ -236,6 +236,10 @@ unix_data_alloc(void)
static inline void
unix_data_ref(struct unix_proto_data *upd)
{
+ if (!upd) {
+ dprintf(1, "UNIX: data_ref: upd = NULL\n");
+ return;
+ }
++upd->refcnt;
dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt);
}
@@ -244,6 +248,10 @@ unix_data_ref(struct unix_proto_data *upd)
static void
unix_data_deref(struct unix_proto_data *upd)
{
+ if (!upd) {
+ dprintf(1, "UNIX: data_deref: upd = NULL\n");
+ return;
+ }
if (upd->refcnt == 1) {
dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
if (upd->buf) {
@@ -558,10 +566,6 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
dprintf(1, "UNIX: read: interrupted\n");
return(-ERESTARTSYS);
}
- if (sock->state == SS_DISCONNECTING) {
- dprintf(1, "UNIX: read: disconnected\n");
- return(0);
- }
}
/*
@@ -784,7 +788,7 @@ unix_ioctl(struct inode *inode, struct file *file,
switch(cmd) {
case DDIOCSDBG:
verify_area(VERIFY_WRITE,(void *)arg, sizeof(int));
- unix_debug = get_fs_long((void *)arg);
+ unix_debug = get_fs_long((int *)arg);
if (unix_debug != 0 && unix_debug != 1) {
unix_debug = 0;
return(-EINVAL);