]> git.neil.brown.name Git - history.git/commitdiff
Import pre2.0.13 pre2.0.13
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:11:06 +0000 (15:11 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:11:06 +0000 (15:11 -0500)
81 files changed:
Documentation/00-INDEX [new file with mode: 0644]
Documentation/Changes
Documentation/Configure.help
Documentation/cdrom/00-INDEX [new file with mode: 0644]
Documentation/cdrom/mcdx
Documentation/filesystems/00-INDEX [new file with mode: 0644]
Documentation/isdn/00-INDEX [new file with mode: 0644]
Documentation/modules.txt
Documentation/networking/00-INDEX [new file with mode: 0644]
Documentation/networking/Configurable [new file with mode: 0644]
Documentation/smp.tex
Documentation/watchdog.txt
Makefile
README
arch/i386/defconfig
arch/i386/kernel/irq.c
drivers/block/Config.in
drivers/block/ide.c
drivers/block/xd.c
drivers/cdrom/mcdx.c
drivers/cdrom/sbpcd.c
drivers/char/ChangeLog
drivers/char/Config.in
drivers/char/baycom.c
drivers/char/pty.c
drivers/char/random.c
drivers/char/selection.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/char/vesa_blank.c
drivers/net/lance.c
drivers/net/smc-ultra.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/Config.in
drivers/scsi/README.BusLogic
drivers/scsi/in2000.readme
drivers/scsi/qlogicisp.c
drivers/scsi/scsi.h
fs/Config.in
fs/file_table.c
fs/nfs/rpcsock.c
fs/read_write.c
fs/smbfs/dir.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/ioctl.c
fs/smbfs/mmap.c
fs/smbfs/proc.c
fs/smbfs/sock.c
include/asm-i386/resource.h
include/linux/baycom.h
include/linux/interrupt.h
include/linux/mcdx.h
include/linux/netdevice.h
include/linux/random.h
include/linux/rpcsock.h
include/linux/sbpcd.h
include/linux/smb.h
include/linux/smb_fs_i.h
include/linux/smb_mount.h
include/linux/uio.h
include/net/ip_masq.h
include/net/sock.h
kernel/sys.c
mm/mmap.c
mm/vmscan.c
net/Config.in
net/core/dev.c
net/core/skbuff.c
net/ipv4/Config.in
net/ipv4/arp.c
net/ipv4/ip_forward.c
net/ipv4/ip_input.c
net/ipv4/ip_masq.c
net/ipv4/ip_output.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/netsyms.c
net/socket.c
scripts/tkgen.c

diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
new file mode 100644 (file)
index 0000000..1a6fb3b
--- /dev/null
@@ -0,0 +1,69 @@
+This is a brief list of all the files in ./linux/Documentation and what
+they contain. If you add a documentation file, please list it here in 
+alphabetical order as well. Note that subdirectories have their own
+index files too.
+                                                        Thanks -- Paul.
+
+00-INDEX
+       - this file.
+BUG-HUNTING
+       - brute force method of doing binary search of patches to find bug.
+Changes
+       - list of changes that break older software packages.
+CodingStyle
+       - how the boss likes the C code in the kernel to look.
+Configure.help
+       - text file that is used for help when you run "make config"
+SMP.txt
+       - notes, and "To Fix" list for multi-processor Linux. (see smp.tex)
+cdrom/
+       - directory with information on the CD-ROM drivers that Linux has.
+devices.tex
+       - TeX source listing of all the nodes in /dev/ with major minor #'s
+devices.txt
+       - plain ASCII listing of all the nodes in /dev/ with major minor #'s
+digiboard.txt
+       - info on the Digiboard PC/X{i,e,eve} multiport boards.
+filesystems/
+       - directory with info on the various filesystems that Linux supports.
+ide.txt
+       - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS)
+initrd.txt
+       - how to use the RAM disk as an initial/temporary root filesystem.
+ioctl-number.txt
+       - how to implement and register device/driver ioctl calls.
+isdn/
+       - directory with info on the linux ISDN support, and supported cards.
+java.txt
+       - info on the in-kernel binary support for Java(tm)
+locks.txt
+       - info on file locking implementations, flock() vs. fcntl(), etc.
+magic-number.txt
+       - list of magic numbers used to mark/protect kernel data structures.
+mandatory.txt
+       - info on the linux implementation of Sys V mandatory file locking.
+modules.txt
+       - short guide on how to make kernel parts into loadable modules
+networking/
+       - directory with info on various linux networking aspects.
+nfsroot.txt
+       - short guide on setting up a diskless box with NFS root filesystem
+oops-tracing.txt
+       - how to decode those nasty internal kernel error dump messages.
+ramdisk.txt
+       - short guide on how to set up and use the RAM disk.
+riscom8.txt
+       - notes on using the RISCom/8 multi-port serial driver.
+rtc.txt
+       - notes on how to use the Real Time Clock (aka CMOS clock) driver.
+scsi.txt
+       - short blurb on using SCSI support as a module.
+smp.tex
+       - TeX document describing implementation of Multiprocessor Linux
+svga.txt
+       - short guide on selecting video modes at boot via VGA BIOS.
+unicode.txt
+       - info on the Unicode character/font mapping used in Linux.
+watchdog.txt
+       - how to auto-reboot Linux if it has "fallen and can't get up". ;-)
+
index dc82670f24305c8a0d38713da971c950cd59796b..139be9610e033879ae6daf72cfd77570a868081f 100644 (file)
@@ -18,7 +18,7 @@ and was originally written and maintained by Alessandro Sigala
 Taylor.  Check out http://www.cviog.uga.edu/LinuxBleed.html if you
 prefer a HTML-ized shopping list.
 
-Last updated: June 1, 1996.
+Last updated: June 5, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Releases
@@ -34,7 +34,7 @@ Current Releases
 - Termcap               2.0.8
 - Procps                0.99a
 - Gpm                   1.09
-- sysvinit              2.62
+- SysVinit              2.62
 - Util-linux            2.5
 
 Upgrade notes
@@ -55,6 +55,21 @@ distributions like Caldera).  If you're running one of these, edit
 /etc/sysconfig/network-scripts/ifup-lo, changing the line `route add
 -net $(IPADDR)' to `route add -net 127.0.0.0' and you should be fine.
 
+Booting Changes
+===============
+
+   The boot stuff in 1.3.x (for arch/i386) has been enhanced so that it
+now can load bigger kernels (bzImage) and that the loaders now can load
+an initial ramdisk (initrd). For initrd see Documentation/initrd.txt.
+For building bigger kernels use one of the following make targets:
+bzImage, bzlilo, bzdisk (equivalent to make targets zImage, zlilo, and
+zdisk respectively).  If you want or need to use the new features
+you'll need to upgrade your bootloaders.  Lilo can be found at
+ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz.  LOADLIN is at
+ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz.  If
+you're using more unusual loaders like SysLinux or etherboot, the
+latest versions are 1.3 and 2.0, respectively.
+
 The Linux C Library
 ===================
 
@@ -154,8 +169,8 @@ PPP driver
 latest stable release is 2.2.0f and is available at
 ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz.
 
-Named pipes
-===========
+Named pipes (SysVinit)
+======================
 
    Linux's handling of named pipes changed (it now does it The Right Way
 instead of the SunOS way ;-).  This broke some programs that depended
@@ -164,9 +179,7 @@ or earlier, you will probably get a weird error on shutdown in which
 your computer shuts down fine but "INIT: error reading initrequest" or
 words to that effect scroll across your screen hundreds of times.  To
 fix, upgrade to
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.62.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/sources/sbin/sysvinit-2.62.tar.gz
-ftp://ftp.cistron.nl/pub/people/miquels/software/sysvinit-2.62.tar.gz.
+ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.62.tar.gz.
 
    If you're trying to run NCSA httpd, you have to set pre-spawning of
 daemons to zero, as it incorrectly assumes SunOS behavior.  I recommend
@@ -187,6 +200,17 @@ with the Hylafax distribution and change the line
 changing them to read-write) will fix any program that is broken
 because of this change.
 
+File Locking (Sendmail)
+=======================
+
+   As of pre2.0.6 (aka 1.99.6), mixed-style file locking is no longer
+allowed.  For example, a file cannot be simultaneously locked with
+`flock' (BSD-style) and `lockf' (SYSV-style).  Among the programs this
+has impacted are older sendmails.  If you get a message that sendmail
+cannot lock aliases.dir (or other files), you'll need to upgrade to at
+least 8.7.x.  The latest sendmail is at
+ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.7.5.tar.gz.
+
 Uugetty
 =======
 
@@ -299,7 +323,7 @@ Tcsh
 ====
 
    If tcsh acts funny, get the source from
-ftp://tesla.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in
+ftp://anise.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in
 config_f.h before recompiling tcsh.  Binaries can be found in
 ftp://sunsite.unc.edu/pub/Linux/system/Shells/ and a corrected one will
 probably wind up there eventually.
@@ -351,6 +375,20 @@ This will compile just fine after you copy its mntent.h over to
 /usr/include/mntent.h.  I've uploaded this to sunsite as
 ftp://sunsite.unc.edu/pub/Linux/system/Admin/quotas-1.51-tar.gz
 
+Process Accounting
+==================
+
+   Process accounting support has also been integrated into the new
+kernels. To use this feature, you'll need to get
+ftp://iguana.hut.fi/pub/linux/Kernel/process_accounting/acct_1.3.73.tar.gz.
+
+Bdflush
+=======
+
+   Bdflush has also been integrated into the new kernels, so those of
+you using it on older systems no longer need to hunt for the patches to
+implement it once you upgrade to 1.3.x.
+
 APM support
 ===========
 
@@ -368,7 +406,9 @@ ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz
 
    For a version of Dosemu that works (well, at least as well as DOS
 ever works ;-), get
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz.
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.19.tgz.
+Be sure to follow the instructions in README.newkernels about patching
+your include files, or it will not compile.
 
 Mtools and Fdutils
 ==================
@@ -500,7 +540,7 @@ ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.09.tar.gz
 SysVinit utilities
 ==================
 
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.60.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.62.tar.gz
 
 Util-linux
 ==========
index 4057ca90bfeb4ece5f2c8c46f3e8699eb8d56bc5..955622de7aee2d460becdd989575c0180de75003 100644 (file)
@@ -1250,7 +1250,7 @@ CONFIG_SCSI_ADVANSYS
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-Adaptec AHA152X support
+Adaptec AHA152X/2825 support
 CONFIG_SCSI_AHA152X
   This is support for a SCSI host adaptor. It is explained in section
   3.3 of the SCSI-HOWTO, available via ftp (user: anonymous) at
@@ -2992,6 +2992,16 @@ CONFIG_SMB_FS
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt. Most people say N, however.
 
+SMB long filename support (EXPERIMENTAL)
+CONFIG_SMB_LONG
+  SMBFS was designed to support long filenames using the LanManager
+  2.0 protocol. I had to find out that the support for long filenames
+  sometimes causes problems, which can even result in kernel OOPSes. I
+  did not yet find out what the problem is, but hopefully I will find
+  this bug eventually. As many people seem to run long filenames with
+  no problems, I leave this support in the kernel as an option. The
+  careful among you should say N here.
+
 NCP filesystem support (to mount NetWare volumes)
 CONFIG_NCP_FS
   NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
diff --git a/Documentation/cdrom/00-INDEX b/Documentation/cdrom/00-INDEX
new file mode 100644 (file)
index 0000000..a113106
--- /dev/null
@@ -0,0 +1,29 @@
+00-INDEX
+       - this file (info on CD-ROMs and Linux)
+aztcd
+       - info on Aztech/Orchid/Okano/Wearnes/Conrad/CyCDROM driver.
+cdrom-standard.tex
+       - LaTeX document on standardizing the CD-ROM programming interface.
+cdu31a
+       - info on the Sony CDU31A/CDU33A CD-ROM driver.
+cm206
+       - info on the Philips/LMS cm206/cm260 CD-ROM driver.
+gscd
+       - info on the Goldstar R420 CD-ROM driver.
+ide-cd
+       - info on setting up and using ATAPI (aka IDE) CD-ROMs.
+isp16
+       - info on the CD-ROM interface on ISP16, MAD16 or Mozart sound card.
+mcd
+       - info on limitations of standard Mitsumi CD-ROM driver.
+mcdx
+       - info on improved Mitsumi CD-ROM driver.
+optcd
+       - info on the Optics Storage 8000 AT CD-ROM driver
+sbpcd
+       - info on the SoundBlaster Pro CD-ROM interface driver.
+sjcd
+       - info on the SANYO CDR-H94A CD-ROM interface driver.
+sonycd535
+       - info on the Sony CDU-535 (and 531) CD-ROM driver.
+
index 52a42fd5ca716df872f05ae9f9afb549ad1a8678..fd2c37321a975c2d3497b77aecbd7005df3f306f 100644 (file)
@@ -1,46 +1,44 @@
-This actually is an `improved' driver for the Mitsumi CD-ROM drives. 
+This is a first attempt to create an `improved' driver for the Mitsumi drives.
+It is able to "live together" with mcd.c, if you have at least two Mitsumi
+drives: each driver can use his own drive.
 
-We are using the major device number 20 for it. So, you have to do
+To allow this "coexistence" as long as mcdx.c is not a superset of mcd.c,
+this driver has to use its own device files. We use MAJOR 20 for it. So,
+you have to do
 
-~# mknod /dev/mcdx0 b 20 0
-~# mknod /dev/mcdx1 b 20 1
+ # mknod /dev/mcdx0 b 20 0
+ # mknod /dev/mcdx1 b 20 1
 
 and so on, one entry for each drive to support, once.
 
-If you are using the driver as a module, you can specify the ports and IRQs
-like:
+If you are using the driver as a module, you can specify your ports and IRQs
+like
 
- # insmod mcdx.o mcdx=0x300,11
+ # insmod mcdx.o mcdx=0x300,11,0x304,5
 
-and so on ("address,IRQ" pairs). When You intend to use more then one
-drive, it's necessary to edit the mcdx.h file found in
-/usr/src/linux/include/linux. Instead of providing the values on the
-command line, You can "hardwire" them all in mcdx.h. The command line
-values take precedence over the values in mcdx.h. 
-
-WARNING: BE CAREFUL TO SUPPLY THE CORRECT VALUES OTHERWISE THE WHOLE SYSTEM
-WILL HANG DURING BOOT-UP OR LOADING OF THE DRIVER!!!
+and so on ("address,IRQ" pairs).
+This will override the configuration in mcdx.h.
 
 This driver:
 
-       o       Handles XA and multi session CDs as well as ordinary CDs.
-       o       Supports up to 5 drives (of course, you'll need free 
-               IRQs, i/o ports and slots).
-       o       Uses *much* less kernel memory than the standard mcd driver.
-       o       Plays audio like the `old' driver.
+    o   handles XA (and hopefully) multi session CDs as well as
+        ordinary CDs;
+    o   supports up to 5 drives (of course, you'll need free 
+        IRQs, i/o ports and slots);
+    o   uses much less kernel memory than the standard mcd driver
+        (no extra driver internal buffers!).
+        o   plays audio (like the `old' driver, I hope)
 
 This version doesn't support yet:
 
-       o       Shared IRQs, due to the fact that otherwise it wouldn't be
-               possible to distinguish the drives issuing the interrupt in the 
-               corresponding handling routine.
+    o   shared IRQs (but it seems to be possible - I've successfully
+                connected two drives to the same irq.  So it's `only' a 
+                problem of the driver.)
 
 This driver never will:
 
-       o       Read digital audio (i.e. copy directly), due to missing
-               hardware features. 
-       o       Do DMA transfers. This is simply far less efficient with such 
-               a slow device. Further, the SoundBlaster interfaces doesn't
-               support it, so it's not worth the effort.
+    o   Read digital audio (i.e. copy directly), due to missing
+        hardware features. 
+
 
-1996/05/20 Marcin Dalecki <dalecki@namu03.gwdg.de>
+heiko@lotte.sax.de
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
new file mode 100644 (file)
index 0000000..edb8c52
--- /dev/null
@@ -0,0 +1,16 @@
+00-INDEX
+       - this file (info on some of the filesystems supported by linux).
+affs.txt
+       - info and mount options for the Amiga Fast File System.
+hpfs.txt
+       - info and mount options for the OS/2 HPFS.
+ncpfs.txt
+       - info on Novell Netware(tm) filesystem using NCP protocol.
+smbfs.txt
+       - info on using filesystems with the SMB protocol (Win 3.11, Win NT)
+sysv-fs.txt
+       - info on the SystemV/Coherent filesystem.
+umsdos.txt
+       - info on the umsdos extensions to the msdos filesystem.
+vfat.txt
+       - info on using the VFAT filesystem used in Win NT and Win 95
diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX
new file mode 100644 (file)
index 0000000..b707c34
--- /dev/null
@@ -0,0 +1,21 @@
+00-INDEX
+       - this file (info on ISDN implementation for Linux)
+CREDITS
+       - list of the kind folks that brought you this stuff.
+INTERFACE
+       - description of Linklevel and Hardwarelevel ISDN interface.
+README
+       - general info on what you need and what to do for Linux ISDN.
+README.audio
+       - info for running audio over ISDN.
+README.icn
+       - info on the ICN-ISDN-card and its driver.
+README.pcbit
+       - info on the PCBIT-D ISDN adapter and driver.
+README.syncppp
+       - info on running Sync PPP over ISDN.
+README.teles
+       - info on driver for Teles compatible ISDN cards.
+syncPPP.FAQ
+       - frequently asked questions about running PPP over ISDN.
+
index 8f48fed0a401cff2db7bcba076e9f923955baa57..12593dcb74d655ed8f51e5b5c1149586c0e17e36 100644 (file)
@@ -6,8 +6,15 @@ and use modules.
 In this kernel you also have a possibility to create modules that are
 less dependent on the kernel version.  This option can be selected
 during "make config", by enabling CONFIG_MODVERSIONS.
-Note: If you enable CONFIG_MODVERSIONS, you will need some utilities
-      from the latest module support package: "modules-1.1.8*.tar.gz"!
+
+Note: You should ensure that the modules-X.Y.Z.tar.gz you are using
+is the most up to date one for this kernel. The "X.Y.Z" will reflect
+the kernel version at the time of the release of the modules package.
+Some older modules packages aren't aware of some of the newer modular
+features that the kernel now supports. (If you are unsure, you can 
+usually find out what the current release of the modules-X.Y.Z.tar.gz
+package is by looking up the URL listed for "Bjorn Ekwall" in the 
+file ./linux/CREDITS)
 
 Anyway, your first step is to compile the kernel, as explained in the
 file README.  It generally goes like:
@@ -38,12 +45,8 @@ The set of modules is rapidly increasing, but so far these are known:
        Most low-level SCSI drivers: (i.e. aha1542, in2000)
        All SCSI high-level drivers: disk, tape, cdrom, generic.
 
-       Some ethernet drivers:
-               plip, slip, dummy,
-               de600, de620
-               3c501, 3c509
-               eexpress, depca,
-               ewrk3, apricot
+       Most ethernet drivers: (too many to list, please see the file
+                               ./Documentation/networking/net-modules.txt)
 
        Most CDROM drivers:
                aztcd:     Aztech,Orchid,Okano,Wearnes
@@ -80,14 +83,12 @@ Now, after you have made all modules, you can also do:
 
 This will copy all newly made modules into subdirectories under
 "/lib/modules/kernel_release/", where "kernel_release" is something
-like 1.1.83, or whatever the current kernel version is...
+like 2.0.1, or whatever the current kernel version is...
 
 
 Nifty features:
 
-If you have installed the utilities from "modules-1.1.8*.tar.gz",
-you will have access to two new utilities: "modprobe" and "depmod"
-
+You have access to two utilities: "modprobe" and "depmod".
 Using the modprobe utility, you can load any module like this:
 
        /sbin/modprobe module
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
new file mode 100644 (file)
index 0000000..f5182b1
--- /dev/null
@@ -0,0 +1,31 @@
+00-INDEX
+       - this file
+3c505.txt
+       - information on the 3Com EtherLink Plus (3c505) driver.
+Configurable
+       - info on some of the configurable network parameters
+alias.txt
+       - info on using alias network devices 
+arcnet-hardware.txt
+       - tons of info on arcnet, hubs, arcnet card jumper settings, etc.
+arcnet.txt
+       - info on the using the arcnet driver itself.
+ax25.txt
+       - info on using AX.25 and NET/ROM code for Linux
+framerelay.txt
+       - info on using Frame Relay/Data Link Connection Identifier (DLCI).
+ncsa-telnet
+       - notes on how NCSA telnet (DOS) breaks with MTU discovery enabled.
+net-modules.txt
+       - info and "insmod" parameters for all network driver modules.
+ppp.txt
+       - info on what software you should use to run PPP.
+tcp.txt
+       - short blurb on how TCP output takes place.
+tulip.txt
+       - info on using DEC 21040/21041/21140 based PCI ethernet cards.
+vortex.txt
+       - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards.
+z8530drv.txt
+       - info about Linux driver for Z8530 based HDLC cards for AX.25
+
diff --git a/Documentation/networking/Configurable b/Documentation/networking/Configurable
new file mode 100644 (file)
index 0000000..48be78b
--- /dev/null
@@ -0,0 +1,33 @@
+
+There are a few network parameters that can be tuned to better match
+the kernel to your system hardware and intended usage. The defaults
+are usually a good choice for 99% of the people 99% of the time, but
+you should be aware they do exist and can be changed.
+
+The current list of parameters can be found in the file:
+
+       ./linux/net/TUNABLE
+
+Some of these are accessible via the sysctl interface, and many more are
+scheduled to be added in this way. For example, some parameters related 
+to Address Resolution Protocol (ARP) are very easily viewed and altered.
+
+       # cat /proc/sys/net/ipv4/arp_timeout
+       6000
+       # echo 7000 > /proc/sys/net/ipv4/arp_timeout
+       # cat /proc/sys/net/ipv4/arp_timeout
+       7000
+
+Others are already accessible via the related user space programs.
+For example, MAX_WINDOW has a default of 32k which is a good choice for
+modern hardware, but if you have a slow (8 bit) ethercard and/or a slow
+machine, then this will be far too big for the card to keep up with fast 
+Tx'ing machines on the same net, resulting in overruns and receive errors.
+A value of about 4k would be more appropriate, which can be set via:
+
+       # route add -net 192.168.3.0 window 4096
+
+The remainder of these can only be presently changed by altering a #define
+in the related header file. This means an edit and recompile cycle.
+
+                                               Paul Gortmaker 06/96
index cfb30b43da9d75e11c989c1709173b980973a1f9..ea582088c34df9936de1db7085e3f24eecdd5266 100644 (file)
@@ -67,7 +67,7 @@ effectively atomic with respect to other processes and greatly simplifies
 many operation. Secondly interrupts may pre-empt a kernel running process, 
 but will always return to that process. A process in kernel mode may 
 disable interrupts on the processor and guarantee such an interruption will 
-not occur. The final guarantee is that an interrupt will not bne pre-empted 
+not occur. The final guarantee is that an interrupt will not be pre-empted 
 by a kernel task. That is interrupts will run to completion or be 
 pre-empted by other interrupts only.
 
index 3769112452810d7c860b66339a00c4bb397046f3..940313a9448b4e46d8e20f24b4bbe6ef20e35565 100644 (file)
@@ -25,8 +25,9 @@ degrees farenheit. Each read returns a single byte giving the temperature.
 
 The third interface logs kernel messages on additional alert events.
 
-At the moment only the software watchdog is available in the standard
-kernel.
+Both software and hardware watchdog drivers are available in the standard
+kernel. If you are using the software watchdog, you probably also want
+to use "panic=60" as a boot argument as well.
 
 Features
 --------
index bfce14d5a0f63ca5ee9c18283ca8d6e823896a71..bba28043fe0e2dac9d8019e1cbfb9dcdfbec6f06 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 12
+SUBLEVEL = 13
 
 ARCH = i386
 
diff --git a/README b/README
index 3e7ba582551694e03a968bfa6e755dd07d839b61..28be1c7350ef41f7df4b46f3761d751896b6ffca 100644 (file)
--- a/README
+++ b/README
@@ -35,8 +35,9 @@ DOCUMENTATION:
    system: there are much better sources available.
 
  - There are various readme's in the kernel Documentation/ subdirectory:
-   these are mainly used for kernel developers and some very kernel-specific
-   installation notes for some drivers for example.
+   these typically contain kernel-specific installation notes for some 
+   drivers for example. See ./Documentation/00-INDEX for a list of what
+   is contained in each file.
 
 INSTALLING the kernel:
 
@@ -105,7 +106,7 @@ CONFIGURING the kernel:
        - having unnecessary drivers will make the kernel bigger, and can
          under some circumstances lead to problems: probing for a
          nonexistent controller card may confuse your other controllers
-       - compiling the kernel with "-m486" for a number of 486-specific
+       - compiling the kernel with "Processor type" set higher than 386
          will result in a kernel that does NOT work on a 386.  The
          kernel will detect this on bootup, and give up.
        - A kernel with math-emulation compiled in will still use the
@@ -183,7 +184,10 @@ COMPILING the kernel:
 
 IF SOMETHING GOES WRONG:
 
- - if you have problems that seem to be due to kernel bugs, please mail
+ - if you have problems that seem to be due to kernel bugs, please check
+   the file MAINTAINERS to see if there is a particualr person associated
+   with the part of the kernel that you are having trouble with. If there
+   isn't anyone listed there, then the second best thing is to 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
@@ -210,7 +214,8 @@ IF SOMETHING GOES WRONG:
    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)
+   the above example it's due to a bad kernel pointer). More information
+   on making sense of the dump is in Documentation/oops-tracing.txt
 
  - You can use the "ksymoops" program to make sense of the dump.  Find
    the C++ sources under the scripts/ directory to avoid having to do
index b64e0a678c38e9e7d02e251473c3187df153dbee..e6ede18d75675ebc8b2ef620a7da2c4743b079e2 100644 (file)
@@ -37,7 +37,7 @@ CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
 
 #
-# Please see drivers/block/README.ide for help/info on IDE drives
+# Please see Documentation/ide.txt for help/info on IDE drives
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDECD=y
index 27ca35e39a7880aaae4d1667dff57f4e03773bd2..ba14e946ba771b878fec48c6eacf5bb5c45e10e4 100644 (file)
@@ -343,6 +343,7 @@ int get_smp_prof_list(char *buf) {
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
        struct irqaction * action = *(irq + irq_action);
+       int do_random = 0;
 
 #ifdef __SMP__
        if(smp_threads_ready && active_kernel_processor!=smp_processor_id())
@@ -354,11 +355,12 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
        int_count[smp_processor_id()][irq]++;
 #endif
        while (action) {
-               if (action->flags & SA_SAMPLE_RANDOM)
-                       add_interrupt_randomness(irq);
+               do_random |= action->flags;
                action->handler(irq, action->dev_id, regs);
                action = action->next;
        }
+       if (do_random & SA_SAMPLE_RANDOM)
+               add_interrupt_randomness(irq);
 }
 
 /*
@@ -369,6 +371,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 asmlinkage void do_fast_IRQ(int irq)
 {
        struct irqaction * action = *(irq + irq_action);
+       int do_random = 0;
+       
 #ifdef __SMP__
        /* IRQ 13 is allowed - that's a flush tlb */
        if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
@@ -380,9 +384,12 @@ asmlinkage void do_fast_IRQ(int irq)
        int_count[smp_processor_id()][irq]++;
 #endif
        while (action) {
+               do_random |= action->flags;
                action->handler(irq, action->dev_id, NULL);
                action = action->next;
        }
+       if (do_random & SA_SAMPLE_RANDOM)
+               add_interrupt_randomness(irq);
 }
 
 int setup_x86_irq(int irq, struct irqaction * new)
index 24ebfe260c15ea344e9e7a5ccf33737747c2c957..fb673fbfd2bba8f636c2463f6d5c31bd8024e353 100644 (file)
@@ -6,7 +6,7 @@ comment 'Floppy, IDE, and other block devices'
 
 tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
 bool 'Enhanced IDE/MFM/RLL disk/cdrom/tape support' CONFIG_BLK_DEV_IDE
-comment 'Please see drivers/block/README.ide for help/info on IDE drives'
+comment 'Please see Documentation/ide.txt for help/info on IDE drives'
 if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then
   bool 'Old harddisk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
 else
@@ -25,7 +25,9 @@ else
     bool '      ALI M1439/M1445 support' CONFIG_BLK_DEV_ALI14XX
     bool '      DTC-2278        support' CONFIG_BLK_DEV_DTC2278
     bool '      Holtek HT6560B  support' CONFIG_BLK_DEV_HT6560B
-    bool '      PROMISE DC4030  support (ALPHA)' CONFIG_BLK_DEV_PROMISE
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool '      PROMISE DC4030  support (EXPERIMENTAL)' CONFIG_BLK_DEV_PROMISE
+    fi
     bool '      QDI QD6580      support' CONFIG_BLK_DEV_QD6580
     bool '      UMC 8672        support' CONFIG_BLK_DEV_UMC8672
   fi
index b3ea7ada81e3370bb437b05c0ebc445dac5850fa..01497f1304330c3b2c5fdcbcadb2d9ddc9976409 100644 (file)
@@ -3114,7 +3114,7 @@ static int init_irq (ide_hwif_t *hwif)
         * Allocate the irq, if not already obtained for another hwif
         */
        if (!match || match->irq != hwif->irq) {
-               if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name, hwgroup)) {
+               if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT, hwif->name, hwgroup)) {
                        if (!match)
                                kfree(hwgroup);
                        restore_flags(flags);
index 455a26bcf71e88d30c714c52e71531f7151dcd37..efe8df595bb810028f67deb6d35122e8bcbf3dd5 100644 (file)
@@ -22,7 +22,7 @@
  *
  */
 
-
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
index 3481b2b95d50ab4b68bb259e07123668395e547a..78a0a3fc0291b7d1e144bf81b86b55b5992aff93 100644 (file)
@@ -1,13 +1,20 @@
 /*
  * The Mitsumi CDROM interface
+ * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
+ * VERSION: 2.14(hs)
  *
- * (H) Hackright 1996 by Marcin Dalecki <dalecki@namu03.gwdg.de>
- * 
- * Based on previous work (as of version 1.9) done by:
- * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
+ * ... anyway, I'm back again, thanks to Marcin, he adopted 
+ * large portions of my code (at least the parts containing
+ * my main thoughts ...)
+ *
+ ****************** H E L P *********************************
+ * If you ever plan to update your CD ROM drive and perhaps
+ * want to sell or simply give away your Mitsumi FX-001[DS] 
+ * -- Please --
+ * mail me (heiko@lotte.sax.de).  When my last drive goes 
+ * ballistic no more driver support will be available from me!
+ *************************************************************
  *
- * VERSION: 2.5
- * 
  * 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)
  *  Jon Tombs, Bjorn Ekwall (module support)
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
- *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
- *  Andreas Kies (testing the mysterious hangups)
+ *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
+ *  Heiko Eissfeld (VERIFY_READ/WRITE)
+ *  Marcin Dalecki (improved performance, shortened code)
  *  ... somebody forgotten?
- * 
- * 2.1  1996/04/29 Marcin Dalecki <dalecki@namu03.gwdg.de>
- *      Far too many bugfixes/changes to mention them all separately.
- * 2.2  1996/05/06 Marcin Dalecki <dalecki@namu03.gwdg.de>
- *      Mostly fixes to some silly bugs in the previous release :-).
- *      (Hi Michael Thimm! Thank's for lending me Your's double speed drive.)
- * 2.3  1996/05/15 Marcin Dalecki <dalecki@namu03.gwdg.de>
- *      Fixed stereo support. 
- * 2.5  1996/05/19 Marcin Dalecki <dalecki@namu03.gwdg.de>
- *      Overall performance increased by a factor of 1.25 :-).
- *      I hope Heiko doesn't mind the Hackright change, but there isn't much of
- *      code left from his version 1.9 anymore. 
- *      Start speedup for Work(Man|Bone).
- *
- * NOTE:
- *      There will be probably a 3.0 adhering to the new generic non ATAPI
- *      CDROM interface in the unforeseen future.
+ *  
  */
-#define VERSION "2.5"
+
+
+#if RCS
+static const char *mcdx_c_version
+               = "$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $";
+#endif
 
 #include <linux/version.h>
 #include <linux/module.h>
 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
 #include <linux/blk.h>
 
-/* 
- * for compatible parameter passing with "insmod" 
- */
-#define        mcdx_drive_map mcdx
+/* for compatible parameter passing with "insmod" */ 
+#define        mcdx_drive_map mcdx    
 #include <linux/mcdx.h>
 
-#define REQUEST_SIZE   400
+#ifndef HZ 
+#error HZ not defined
+#endif
 
-enum drivemodes {
-       TOC, DATA, RAW, COOKED
-};
+#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
 
-#define        MODE0           0x00
-#define MODE1          0x01
-#define MODE2          0x02
+#if !MCDX_QUIET
+#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
+#else
+#define xinfo(fmt, args...) { ; }
+#endif
 
-#define DOOR_LOCK      0x01
-#define DOOR_UNLOCK    0x00
+#if MCDX_DEBUG
+#define xtrace(lvl, fmt, args...) \
+               { if (lvl > 0) \
+                       { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
+#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmg, ## args)
+#else
+#define xtrace(lvl, fmt, args...) { ; }
+#define xdebug(fmt, args...) { ; }
+#endif
 
-/*
- * Structs used to gather info reported by the drive.
- */
+/* CONSTANTS *******************************************************/
+
+/* Following are the number of sectors we _request_ from the drive
+   every time an access outside the already requested range is done.
+   The _direct_ size is the number of sectors we're allowed to skip
+   directly (perfoming a read instead of requesting the new sector
+   needed */
+const int REQUEST_SIZE = 800;  /* should be less then 255 * 4 */
+const int DIRECT_SIZE = 400;   /* should be less then REQUEST_SIZE */
+
+const unsigned long ACLOSE_INHIBIT = 800;  /* 1/100 s of autoclose inhibit */
+
+enum drivemodes { TOC, DATA, RAW, COOKED };
+enum datamodes { MODE0, MODE1, MODE2 };
+enum resetmodes { SOFT, HARD };
 
+const int SINGLE = 0x01;               /* single speed drive (FX001S, LU) */
+const int DOUBLE = 0x02;               /* double speed drive (FX001D, ..? */
+const int DOOR   = 0x04;               /* door locking capability */
+const int MULTI  = 0x08;               /* multi session capability */
+
+const unsigned char READ1X = 0xc0;
+const unsigned char READ2X = 0xc1;
+
+
+/* DECLARATIONS ****************************************************/ 
 struct s_subqcode {
-       u_char adr:4;
-       u_char ctrl:4;
-       u_char tno;
-       u_char index;
+       unsigned char control;
+       unsigned char tno;
+       unsigned char index;
        struct cdrom_msf0 tt;
-       u_char dummy;           /* padding for matching the returned struct */
        struct cdrom_msf0 dt;
 };
 
+struct s_diskinfo {
+       unsigned int n_first;
+       unsigned int n_last;
+       struct cdrom_msf0 msf_leadout;
+       struct cdrom_msf0 msf_first;
+};
+       
 struct s_multi {
        unsigned char multi;
        struct cdrom_msf0 msf_last;
 };
 
-struct s_play {
-       struct cdrom_msf0 start;
-       struct cdrom_msf0 stop;
+struct s_version {
+       unsigned char code;
+       unsigned char ver;
 };
 
-/* 
- * Per drive/controller stuff.
- */
-struct s_drive_stuff {
-       struct wait_queue *busyq;
-
-       /* flags */
-       u_char used:1;          /* locks on open, we allow only
-                                  exclusive usage of the drive */
-       u_char introk:1;        /* status of last irq operation */
-       u_char busy:1;          /* drive performs an operation */
-       u_char eject_sw:1;      /* 1 - eject on last close (default 0) */
-       u_char autoclose:1;     /* 1 - close the door on open (default 1) */
-       u_char xxx:1;           /* set if changed, reset while open */
-       u_char xa:1;            /* 1 if xa disk */
-       u_char audio:1;         /* 1 if audio disk */
-       u_char eom:1;           /* end of media reached during read request */
-
-       /* drives capabilities */
-       u_char door:1;          /* can close/lock tray */
-       u_char multi_cap:1;     /* multi-session capable */
-       u_char double_speed:1;  /* double speed drive */
+/* Per drive/controller stuff **************************************/
 
+struct s_drive_stuff {
+       /* waitquenes */
+    struct wait_queue *busyq;
+    struct wait_queue *lockq;
+    struct wait_queue *sleepq;
+
+       /* flags */
+    volatile int introk;       /* status of last irq operation */
+    volatile int busy;         /* drive performs an operation */
+    volatile int lock;         /* exclusive usage */
+    int eject_sw;           /* 1 - eject on last close (default 0) */
+    int autoclose;          /* 1 - close the door on open (default 1) */
+    
        /* cd infos */
-       u_int first;
-       u_int last;
-       struct cdrom_msf0 msf_leadout;
+       struct s_diskinfo di;
        struct s_multi multi;
-
-       struct s_subqcode *toc; /* first entry of the toc array */
-       struct s_play resume;   /* where to resume after pause */
-
-       int audiostatus;
+       struct s_subqcode* toc; /* first enty of the toc array */
+       struct s_subqcode start;
+    struct s_subqcode stop;
+       int xa;                                 /* 1 if xa disk */
+       int audio;                              /* 1 if audio disk */
+       int audiostatus;                        
 
        /* `buffer' control */
-       u_char valid:1;
-       int pending;
-       int border;             /* the last sector in sequence we will read,
-                                  without reissuing a read command */
-
-       u_int base;             /* base for all registers of the drive */
-       int irq;                /* irq used by this drive */
-       int lastsector;         /* last accessible block */
+    volatile int valid;                        /* pending, ..., values are valid */
+    volatile int pending;              /* next sector to be read */
+    volatile int low_border;   /* first sector not to be skipped direct */
+    volatile int high_border; /* first sector `out of area' */
+#ifdef AK2
+    volatile int int_err;
+#endif /* AK2 */
+
+       /* adds and odds */
+       void* wreg_data;        /* w data */
+       void* wreg_reset;       /* w hardware reset */
+       void* wreg_hcon;        /* w hardware conf */
+       void* wreg_chn;         /* w channel */
+       void* rreg_data;        /* r data */
+       void* rreg_status;      /* r status */
+
+    int irq;                   /* irq used by this drive */
+    int minor;                 /* minor number of this drive */
+    int present;           /* drive present and its capabilities */
+    unsigned char readcmd;     /* read cmd depends on single/double speed */
+    unsigned char playcmd;  /* play should always be single speed */
+    unsigned int xxx;      /* set if changed, reset while open */
+    unsigned int yyy;      /* set if changed, reset by media_changed */
+    unsigned long ejected;  /* time we called the eject function */
+    int users;                         /* keeps track of open/close */
+    int lastsector;                    /* last block accessible */
+    int status;                                /* last operation's error / status */
+       int readerrs;                   /* # of blocks read w/o error */
 };
 
-/*
- * Macros for accessing interface registers
- */
-#define DATA_REG       (stuffp->base)
-#define RESET_REG      (stuffp->base+1)
-#define STAT_REG       (stuffp->base+1)
-#define CHAN_REG       (stuffp->base+3)
 
-/*      
- * Access to elements of the mcdx_drive_map members 
- */
-#define PORT   0
-#define IRQ    1
+/* Prototypes ******************************************************/ 
 
-/* 
- * declared in blk.h 
- */
+/*     The following prototypes are already declared elsewhere.  They are
+       repeated here to show what's going on.  And to sense, if they're
+       changed elsewhere. */
+
+/* declared in blk.h */
 int mcdx_init(void);
 void do_mcdx_request(void);
+int check_mcdx_media_change(kdev_t);
 
-/* 
- * already declared in init/main 
- */
+/* already declared in init/main */
 void mcdx_setup(char *, int *);
 
-/*      
- * Indirect exported functions. These functions are exported by their
- * addresses, such as mcdx_open and mcdx_close in the 
- * structure fops. 
- */
-
-/* 
- * ???  exported by the mcdx_sigaction struct 
- */
-static void mcdx_intr(int, void *, struct pt_regs *);
-
-/* 
- * exported by file_ops 
- */
-static int mcdx_open(struct inode *, struct file *);
-static void mcdx_close(struct inode *, struct file *);
-static int mcdx_ioctl(struct inode *, struct file *,
-                     unsigned int, unsigned long);
-static int mcdx_media_change(kdev_t);
-
-static int mcdx_blksize_size[MCDX_NDRIVES];
+/*     Indirect exported functions. These functions are exported by their
+       addresses, such as mcdx_open and mcdx_close in the 
+       structure fops. */
+
+/* ???  exported by the mcdx_sigaction struct */
+static void mcdx_intr(int, void *, struct pt_regs*);
+
+/* exported by file_ops */
+static int mcdx_open(struct inode*, struct file*);
+static void mcdx_close(struct inode*, struct file*);
+static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
+
+/* misc internal support functions */
+static void log2msf(unsigned int, struct cdrom_msf0*);
+static unsigned int msf2log(const struct cdrom_msf0*);
+static unsigned int uint2bcd(unsigned int);
+static unsigned int bcd2uint(unsigned char);
+static char *port(int*);
+static int irq(int*);
+static void mcdx_delay(struct s_drive_stuff*, long jifs);
+static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
+static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
+
+static int mcdx_config(struct s_drive_stuff*, int);
+static int mcdx_closedoor(struct s_drive_stuff*, int);
+static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
+static int mcdx_lockdoor(struct s_drive_stuff*, int, int);
+static int mcdx_stop(struct s_drive_stuff*, int);
+static int mcdx_hold(struct s_drive_stuff*, int);
+static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
+static int mcdx_eject(struct s_drive_stuff*, int);
+static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
+static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
+static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
+static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
+static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
+static int mcdx_getstatus(struct s_drive_stuff*, int);
+static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
+static int mcdx_talk(struct s_drive_stuff*, 
+               const unsigned char* cmd, size_t, 
+        void *buffer, size_t size, 
+        unsigned int timeout, int);
+static int mcdx_readtoc(struct s_drive_stuff*);
+static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
+static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
+static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
+
+/* static variables ************************************************/
+
+static int mcdx_blocksizes[MCDX_NDRIVES];
 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
-static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
-static struct s_drive_stuff *mcdx_irq_map[16] =
-{0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0};
+static struct s_drive_stuffmcdx_stuffp[MCDX_NDRIVES];
+static struct s_drive_stuffmcdx_irq_map[16] =
+               {0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0};
 
-static struct file_operations mcdx_fops =
-{
+static struct file_operations mcdx_fops = {
        NULL,                   /* lseek - use kernel default */
        block_read,             /* read - general block-dev read */
-       block_write,            /* write - general block-dev write */
+       block_write,    /* write - general block-dev write */
        NULL,                   /* no readdir */
        NULL,                   /* no select */
        mcdx_ioctl,             /* ioctl() */
@@ -223,1118 +284,1647 @@ static struct file_operations mcdx_fops =
        mcdx_open,              /* open() */
        mcdx_close,             /* close() */
        NULL,                   /* fsync */
-       NULL,                   /* fasync */
-       mcdx_media_change,      /* media_change */
-       NULL                    /* revalidate */
+       NULL,                     /* fasync */
+       check_mcdx_media_change,  /* media_change */
+       NULL                      /* revalidate */
 };
 
-/*     
- * Misc number converters 
- */
+/* KERNEL INTERFACE FUNCTIONS **************************************/ 
 
-static unsigned int bcd2uint(unsigned int c)
-{
-       return (c >> 4) * 10 + (c & 0x0f);
-}
+static int 
+mcdx_ioctl(
+       struct inode* ip, struct file* fp, 
+       unsigned int cmd, unsigned long arg)
+{ 
+       struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
 
-static unsigned int uint2bcd(unsigned int ival)
-{
-       return ((ival / 10) << 4) | (ival % 10);
-}
+       if (!stuffp->present) return -ENXIO;
+       if (!ip) return -EINVAL;
 
-static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
-{
-       return bcd2uint(pmsf->frame)
-           + bcd2uint(pmsf->second) * 75
-           + bcd2uint(pmsf->minute) * 4500
-           - CD_BLOCK_OFFSET;
-}
+       switch (cmd) {
+               case CDROMSTART: {
+                       xtrace(IOCTL, "ioctl() START\n");
+                       return 0;
+               }
 
-/*
- * Low level hardware related functions.
- */
+               case CDROMSTOP: {
+                       xtrace(IOCTL, "ioctl() STOP\n");
+            stuffp->audiostatus = CDROM_AUDIO_INVALID;
+                       if (-1 == mcdx_stop(stuffp, 1))
+                               return -EIO;
+                       return 0;
+               }
 
-/*
- * Return drives status in case of success, -1 otherwise.
- *
- * First we try to get the status information quickly.
- * Then we sleep repeatedly for about 10 usecs, before we finally reach the 
- * timeout. For this reason this command must be called with the drive being 
- * locked!
- */
-static int get_status(struct s_drive_stuff *stuffp,
-                     unsigned long timeout)
-{
-       unsigned long bang = jiffies + 2;
-       timeout += jiffies;
+               case CDROMPLAYTRKIND: {
+                       int ans;
+                       struct cdrom_ti ti;
 
-       do {
-               if (!(inb(STAT_REG) & MCDX_RBIT_STEN)) {
-                       return (inb(DATA_REG) & 0xff);
-               }
-       } while (jiffies < bang);
+                       xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
+                       if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(ti))))
+                               return ans;
+                       memcpy_fromfs(&ti, (void*) arg, sizeof(ti));
+                       if ((ti.cdti_trk0 < stuffp->di.n_first)
+                                       || (ti.cdti_trk0 > stuffp->di.n_last)
+                                       || (ti.cdti_trk1 < stuffp->di.n_first))
+                               return -EINVAL;
+                       if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last;
+            xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1);
 
-       while (inb(STAT_REG) & MCDX_RBIT_STEN) {
-               if (jiffies > timeout)
-                       return -1;
-               current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + HZ / 2;
-               schedule();
-       }
-       return (inb(DATA_REG) & 0xff);
-}
+            return mcdx_playtrk(stuffp, &ti);
+        }
 
-static void release_toc(struct s_drive_stuff *stuffp)
-{
-       if (stuffp->toc) {
-               kfree(stuffp->toc);
-               stuffp->toc = 0;
-       }
-}
+        case CDROMPLAYMSF: {
+            int ans;
+            struct cdrom_msf msf;
 
-/* Send a command to the drive, wait for the result.
- * returns -1 on timeout, drive status otherwise.
- * If buffer is not zero, the result (length size) is stored there.
- * If buffer is zero the size should be the number of bytes to read
- * from the drive.  These bytes are discarded.
- */
-static int talk(struct s_drive_stuff *stuffp,
-               const unsigned char command,
-               void *pars, size_t parslen,
-               void *buffer, size_t size,
-               unsigned int timeout)
-{
-       int st;
+            xtrace(IOCTL, "ioctl() PLAYMSF\n");
 
-       stuffp->valid = 0;
-       outb(command, DATA_REG);
-       if (parslen)
-               outsb(DATA_REG, pars, parslen);
+            if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
+                && (-1 == mcdx_hold(stuffp, 1))) return -EIO;
 
-       if (-1 == (st = get_status(stuffp, timeout))) {
-               goto end_talk;
-       }
-       if (st & MCDX_RBIT_CMDERR) {
-               printk(KERN_ERR MCDX ": error in command 0x%2x\n", command);
-               st = -1;
-               goto end_talk;
-       }
-       /* audio status? */
-       if (stuffp->audiostatus == CDROM_AUDIO_INVALID) {
-               stuffp->audiostatus =
-                   (st & MCDX_RBIT_AUDIOBS) ?
-                   CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
-       } else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
-                  && !(st & MCDX_RBIT_AUDIOBS)) {
-               stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
-       }
-       /* media change? */
-       if (st & MCDX_RBIT_CHANGED)
-               stuffp->xxx = 1;
-       /* now actually get the data */
-       while (size--) {
-               if (-1 == (st = get_status(stuffp, timeout))) {
-                       break;
-               }
-               *((char *) buffer) = st;
-               buffer++;
-       }
-       /* The goto's make GCC generate better code.
-        */
-      end_talk:
-       return st;
-}
+            if ((ans = verify_area(
+                    VERIFY_READ, (void*) arg, sizeof(struct cdrom_msf)))) 
+                return ans;
 
-static int issue_command(struct s_drive_stuff *stuffp,
-                        unsigned char command,
-                        unsigned int timeout)
-{
-       return talk(stuffp, command, 0, 0, NULL, 0, timeout);
-}
+            memcpy_fromfs(&msf, (void*) arg, sizeof msf);
 
-static inline int set_command(struct s_drive_stuff *stuffp,
-                             const unsigned char command,
-                             void *pars, size_t parlen,
-                             unsigned int timeout)
-{
-       return talk(stuffp, command, pars, parlen, NULL, 0, timeout);
-}
+            msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
+            msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
+            msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
 
-static inline int get_command(struct s_drive_stuff *stuffp,
-                             const unsigned char command,
-                             void *buffer, size_t size,
-                             unsigned int timeout)
-{
-       return talk(stuffp, command, NULL, 0, buffer, size, timeout);
-}
+            msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
+            msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
+            msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
 
-static int request_subq_code(struct s_drive_stuff *stuffp,
-                            struct s_subqcode *sub)
-{
-       return get_command(stuffp, MCDX_CMD_GET_SUBQ_CODE,
-                          sub, sizeof(struct s_subqcode), 2 * HZ);
-}
+            return mcdx_playmsf(stuffp, &msf);
+        }
 
-static int request_toc_data(struct s_drive_stuff *stuffp)
-{
-       char buf[8];
-       int ans;
+        case CDROMRESUME: {
+            xtrace(IOCTL, "ioctl() RESUME\n");
+            return mcdx_playtrk(stuffp, NULL);
+        }
 
-       ans = get_command(stuffp, MCDX_CMD_GET_TOC, buf, sizeof(buf), 2 * HZ);
-       if (ans == -1) {
-               stuffp->first = 0;
-               stuffp->last = 0;
-       } else {
-               stuffp->first = bcd2uint(buf[0]);
-               stuffp->last = bcd2uint(buf[1]);
-               memcpy(&(stuffp->msf_leadout), buf + 2, 3);
-       }
-       return ans;
-}
+               case CDROMREADTOCENTRY: {
+                       struct cdrom_tocentry entry;
+                       struct s_subqcode *tp = NULL;
+                       int ans;
 
-static int set_drive_mode(struct s_drive_stuff *stuffp, enum drivemodes mode)
-{
-       char value;
-       if (-1 == get_command(stuffp, MCDX_CMD_GET_DRIVE_MODE,
-                             &value, 1, 5 * HZ))
-               return -1;
-       switch (mode) {
-       case TOC:
-               value |= 0x04;
-               break;
-       case DATA:
-               value &= ~0x04;
-               break;
-       case RAW:
-               value |= 0x40;
-               break;
-       case COOKED:
-               value &= ~0x40;
-               break;
-       default:
-               break;
-       }
-       return set_command(stuffp, MCDX_CMD_SET_DRIVE_MODE, &value, 1, 5 * HZ);
-}
+                       xtrace(IOCTL, "ioctl() READTOCENTRY\n");
 
-static int config_drive(struct s_drive_stuff *stuffp)
-{
-       unsigned char buf[2];
-       buf[0] = 0x10;          /* irq enable */
-       buf[1] = 0x05;          /* pre, err irq enable */
+            if (-1 == mcdx_readtoc(stuffp)) return -1;
 
-       if (-1 == set_command(stuffp, MCDX_CMD_CONFIG, buf,
-                             sizeof(buf), 1 * HZ))
-               return -1;
+                       if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry)))) return ans;
+                       memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
 
-       buf[0] = 0x02;          /* dma select */
-       buf[1] = 0x00;          /* no dma */
+                       if (entry.cdte_track == CDROM_LEADOUT) 
+                               tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
+                       else if (entry.cdte_track > stuffp->di.n_last 
+                                       || entry.cdte_track < stuffp->di.n_first) return -EINVAL;
+                       else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first];
 
-       return set_command(stuffp, MCDX_CMD_CONFIG, buf, sizeof(buf), 1 * HZ);
-}
+                       if (NULL == tp) xwarn("FATAL.\n"); 
 
-/*  
- * Read the toc entries from the CD.
- * Return: -1 on failure, else 0 
- */
-int read_toc(struct s_drive_stuff *stuffp)
-{
-       int trk;
-       int i;
+                       entry.cdte_adr = tp->control;
+                       entry.cdte_ctrl = tp->control >> 4;
 
-       if (stuffp->toc)
-               return 0;
-       if (-1 == issue_command(stuffp, MCDX_CMD_HOLD, 2 * HZ))
-               return -1;
-       if (-1 == set_drive_mode(stuffp, TOC))
-               return -EIO;
+                       if (entry.cdte_format == CDROM_MSF) {
+                               entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
+                               entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
+                               entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
+                       } else if (entry.cdte_format == CDROM_LBA)
+                               entry.cdte_addr.lba = msf2log(&tp->dt);
+                       else return -EINVAL;
 
-       /* All seems to be OK so far ... malloc. When this fails all bets
-        * are off anyway, so we don't check for it.
-        */
-       stuffp->toc = kmalloc(sizeof(struct s_subqcode) *
-                        (stuffp->last - stuffp->first + 1), GFP_KERNEL);
-       /* now read actually the index tracks */
-       for (trk = 0; trk < stuffp->last - stuffp->first + 1; trk++)
-               stuffp->toc[trk].index = 0;
-
-       for (i = 300; i; --i) { /* why 300? */
-               struct s_subqcode q;
-               unsigned int idx;
-
-               if (-1 == request_subq_code(stuffp, &q)) {
-                       set_drive_mode(stuffp, DATA);
-                       return -EIO;
+                       memcpy_tofs((void*) arg, &entry, sizeof(entry));
+
+                       return 0;
                }
-               idx = bcd2uint(q.index);
 
-               if (idx > 0 && idx <= stuffp->last && q.tno == 0
-                   && stuffp->toc[idx - stuffp->first].index == 0) {
-                       stuffp->toc[idx - stuffp->first] = q;
-                       trk--;
+               case CDROMSUBCHNL: {
+                       int ans;
+                       struct cdrom_subchnl sub;
+                       struct s_subqcode q;
+
+                       xtrace(IOCTL, "ioctl() SUBCHNL\n");
+
+                       if ((ans = verify_area(VERIFY_WRITE,
+                    (void*) arg, sizeof(sub)))) return ans;
+
+                       memcpy_fromfs(&sub, (void*) arg, sizeof(sub));
+
+                       if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
+
+            xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus);
+                       sub.cdsc_audiostatus = stuffp->audiostatus;
+                       sub.cdsc_adr = q.control;
+                       sub.cdsc_ctrl = q.control >> 4;
+                       sub.cdsc_trk = bcd2uint(q.tno);
+                       sub.cdsc_ind = bcd2uint(q.index);
+
+            xtrace(SUBCHNL, "trk %d, ind %d\n", 
+                    sub.cdsc_trk, sub.cdsc_ind);
+
+                       if (sub.cdsc_format == CDROM_LBA) {
+                               sub.cdsc_absaddr.lba = msf2log(&q.dt);
+                               sub.cdsc_reladdr.lba = msf2log(&q.tt);
+                xtrace(SUBCHNL, "lba: abs %d, rel %d\n",
+                    sub.cdsc_absaddr.lba,
+                    sub.cdsc_reladdr.lba);
+                       } else if (sub.cdsc_format == CDROM_MSF) {
+                               sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
+                               sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
+                               sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
+                               sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
+                               sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
+                               sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
+                xtrace(SUBCHNL,
+                        "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
+                        sub.cdsc_absaddr.msf.minute,
+                        sub.cdsc_absaddr.msf.second,
+                        sub.cdsc_absaddr.msf.frame,
+                        sub.cdsc_reladdr.msf.minute,
+                        sub.cdsc_reladdr.msf.second,
+                        sub.cdsc_reladdr.msf.frame);
+                       } else return -EINVAL;
+
+                       memcpy_tofs((void*) arg, &sub, sizeof(sub));
+
+                       return 0;
                }
-               if (trk == 0)
-                       break;
-       }
-       i = stuffp->last - stuffp->first + 1;
-       memset(&stuffp->toc[i], 0, sizeof(stuffp->toc[0]));
-       stuffp->toc[i].dt = stuffp->msf_leadout;
 
-       /* unset toc mode */
-       if (-1 == set_drive_mode(stuffp, DATA))
-               return -EIO;
+               case CDROMREADTOCHDR: {
+                       struct cdrom_tochdr toc;
+                       int ans;
+
+                       xtrace(IOCTL, "ioctl() READTOCHDR\n");
+                       if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc)))
+                               return ans;
+                       toc.cdth_trk0 = stuffp->di.n_first;
+                       toc.cdth_trk1 = stuffp->di.n_last;
+                       memcpy_tofs((void*) arg, &toc, sizeof toc);
+                       xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
+                                       stuffp->di.n_first, stuffp->di.n_last);
+                       return 0;
+               }
 
-       return 0;
+               case CDROMPAUSE: {
+                       xtrace(IOCTL, "ioctl() PAUSE\n");
+                       if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
+                       if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
+            stuffp->audiostatus = CDROM_AUDIO_PAUSED;
+                       if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
+                               return -EIO;
+                       return 0;
+               }
+
+               case CDROMMULTISESSION: {
+                       int ans;
+                       struct cdrom_multisession ms;
+                       xtrace(IOCTL, "ioctl() MULTISESSION\n");
+                       if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg, 
+                                       sizeof(struct cdrom_multisession))))
+                               return ans;
+                               
+                       memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
+                       if (ms.addr_format == CDROM_MSF) {
+                               ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute);
+                               ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second);
+                               ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame);
+                       } else if (ms.addr_format == CDROM_LBA)
+                               ms.addr.lba = msf2log(&stuffp->multi.msf_last);
+                       else
+                               return -EINVAL;
+                       ms.xa_flag = !!stuffp->multi.multi;
+
+                       memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
+                       if (ms.addr_format == CDROM_MSF) {
+                               xtrace(MS, 
+                                               "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
+                                               ms.xa_flag, 
+                                               ms.addr.msf.minute,
+                                               ms.addr.msf.second,
+                                               ms.addr.msf.frame,
+                                               stuffp->multi.msf_last.minute,
+                                               stuffp->multi.msf_last.second,
+                                               stuffp->multi.msf_last.frame);
+                       } else {
+                           xtrace(MS, 
+                                       "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
+                                       ms.xa_flag,
+                                       ms.addr.lba,
+                                       stuffp->multi.msf_last.minute,
+                                       stuffp->multi.msf_last.second,
+                                       stuffp->multi.msf_last.frame);
+                         }
+                       return 0;
+               }
+
+               case CDROMEJECT: {
+                       xtrace(IOCTL, "ioctl() EJECT\n");
+                       if (stuffp->users > 1) return -EBUSY;
+                       if (-1 == mcdx_eject(stuffp, 1)) return -EIO;
+                       return 0;
+               }
+
+        case CDROMEJECT_SW: {
+            stuffp->eject_sw = arg;
+            return 0;
+        }
+
+        case CDROMVOLCTRL: {
+            int ans;
+            struct cdrom_volctrl volctrl;
+
+            xtrace(IOCTL, "ioctl() VOLCTRL\n");
+            if ((ans = verify_area(
+                    VERIFY_READ, 
+                    (void*) arg,
+                    sizeof(volctrl))))
+                return ans;
+
+            memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
+#if 0          /* not tested! */
+                       /* adjust for the weirdness of workman (md) */
+                       /* can't test it (hs) */
+                       volctrl.channel2 = volctrl.channel1;
+                       volctrl.channel1 = volctrl.channel3 = 0x00;
+#endif
+            return mcdx_setattentuator(stuffp, &volctrl, 2);
+        }
+
+               default:
+                       xwarn("ioctl(): unknown request 0x%04x\n", cmd);
+               return -EINVAL;
+       }
 }
 
-/*
- * Return 0 on success, error value -1 otherwise.
- */
-static int play_track(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
+void do_mcdx_request()
 {
-       struct s_play times;
+    int dev;
+    struct s_drive_stuff *stuffp;
 
-       if (ti) {
-               if (-1 == read_toc(stuffp)) {
-                       stuffp->audiostatus = CDROM_AUDIO_ERROR;
-                       return -EIO;
-               }
-               times.start = stuffp->toc[ti->cdti_trk0 - stuffp->first].dt;
-               times.stop = stuffp->resume.stop =
-                   stuffp->toc[ti->cdti_trk1 - stuffp->first + 1].dt;
-       } else {
-               times = stuffp->resume;
+  again:
+
+       if (CURRENT == NULL) {
+               xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
+               return;
        }
-       if (-1 == set_command(stuffp, MCDX_CMD_PLAY,
-                             &times, sizeof(times), 5 * HZ)) {
-               printk(KERN_WARNING MCDX ": play track timeout\n");
-               stuffp->audiostatus = CDROM_AUDIO_ERROR;
-               return -EIO;
+
+       if (CURRENT->rq_status == RQ_INACTIVE) {
+               xtrace(REQUEST, "end_request(0): rq_status == RQ_INACTIVE\n");
+               return;
        }
-       stuffp->audiostatus = CDROM_AUDIO_PLAY;
 
-       return 0;
+    INIT_REQUEST;
+
+    dev = MINOR(CURRENT->rq_dev);
+    stuffp = mcdx_stuffp[dev];
+
+       if ((dev < 0) 
+               || (dev >= MCDX_NDRIVES) 
+               || !stuffp 
+               || (!stuffp->present)) {
+               xwarn("do_request(): bad device: %s\n", 
+                               kdevname(CURRENT->rq_dev));
+               xtrace(REQUEST, "end_request(0): bad device\n");
+               end_request(0); return;
+    }
+
+       if (stuffp->audio) {
+               xwarn("do_request() attempt to read from audio cd\n");
+               xtrace(REQUEST, "end_request(0): read from audio\n");
+               end_request(0); return;
+       }
+
+       xtrace(REQUEST, "do_request() (%lu + %lu)\n",
+                       CURRENT->sector, CURRENT->nr_sectors);
+
+    switch (CURRENT->cmd) {
+      case WRITE:
+         xwarn("do_request(): attempt to write to cd!!\n");
+         xtrace(REQUEST, "end_request(0): write\n");
+         end_request(0); return;
+
+      case READ:
+         stuffp->status = 0;
+         while (CURRENT->nr_sectors) {
+             int i;
+
+             i = mcdx_transfer(stuffp,
+                                 CURRENT->buffer,
+                                 CURRENT->sector,
+                                 CURRENT->nr_sectors);
+
+                 if (i == -1) {
+                         end_request(0);
+                         goto again;
+                 }
+                 CURRENT->sector += i;
+                 CURRENT->nr_sectors -= i;
+                 CURRENT->buffer += (i * 512);
+         }
+         end_request(1);
+         goto again;
+
+         xtrace(REQUEST, "end_request(1)\n");
+         end_request(1);
+         break;
+
+      default:
+         panic(MCDX "do_request: unknown command.\n");
+         break;
+    }
+
+    goto again;
 }
 
-static int lock_door(struct s_drive_stuff *stuffp, u_char lock)
+static int 
+mcdx_open(struct inode *ip, struct file *fp)
+/*  actions done on open:
+ *  1)  get the drives status 
+ *  2)  set the stuffp.readcmd if a CD is in.
+ *  (return no error if no CD is found, since ioctl() 
+ *  needs an opened device */
 {
-       if (stuffp->door)
-               return set_command(stuffp, MCDX_CMD_LOCK_DOOR,
-                                  &lock, sizeof(lock), 5 * HZ);
-       return 0;
-}
+    struct s_drive_stuff *stuffp;
 
-/* 
- * KERNEL INTERFACE FUNCTIONS
- */
+       xtrace(OPENCLOSE, "open()\n");
 
-static int mcdx_ioctl(struct inode *ip, struct file *fp,
-                     unsigned int command, unsigned long arg)
-{
-       int ans;
-       struct cdrom_ti ti;
-       struct cdrom_msf msf;
-       struct cdrom_tocentry entry;
-       struct s_subqcode *tp = NULL;
-       struct cdrom_subchnl sub;
-       struct s_subqcode q;
-       struct cdrom_tochdr toc;
-       struct cdrom_multisession ms;
-       struct cdrom_volctrl volctrl;
-       struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
+    stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
+    if (!stuffp->present) return -ENXIO;
 
-       MCDX_TRACE_IOCTL(("mcdx_ioctl():\n"));
+       /* Make the modules looking used ... (thanx bjorn).
+        * But we shouldn't forget to decrement the module counter
+        * on error return */
+       MOD_INC_USE_COUNT;
 
-       if (!stuffp)
-               return -ENXIO;
-       if (!ip)
-               return -EINVAL;
+#if 0
+       /* We don't allow multiple users of a drive.  In case of data CDs
+     * they'll be used by mounting, which ensures anyway exclusive
+        * usage. In case of audio CDs it's meaningless to try playing to
+        * different tracks at once! (md)
+        * - Hey, what about cat /dev/cdrom? Why shouldn't it called by
+        * more then one process at any time?  (hs) */
+       if (stuffp->users) {
+               MOD_DEC_USE_COUNT;
+               return -EBUSY;
+       }
+#endif
 
-       switch (command) {
-       case CDROMSTART:        /* spin up the drive */
-               MCDX_TRACE_IOCTL(("CDROMSTART\n"));
-               /* Don't think we can do this.  Even if we could,
-                * I think the drive times out and stops after a while
-                * anyway.  For now, ignore it.
-                */
-               return 0;
+    /* this is only done to test if the drive talks with us */
+    if (-1 == mcdx_getstatus(stuffp, 1)) {
+               MOD_DEC_USE_COUNT;
+               return -EIO;
+       }
 
-       case CDROMSTOP:
-               MCDX_TRACE_IOCTL(("CDROMSTOP\n"));
-               stuffp->audiostatus = CDROM_AUDIO_INVALID;
-               if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ))
+       /* close the door,
+        * This should be explained ...
+        * - If the door is open and its last close is too recent the 
+        *   autoclose wouldn't probably be what we want.
+        * - If we didn't try to close the door yet, close it and go on.
+        * - If we autoclosed the door and couldn't succeed in find a valid
+        *   CD we shouln't try autoclose any longer (until a valid CD is
+        *   in.) */
+
+       if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
+        if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) {
+                       MOD_DEC_USE_COUNT;
                        return -EIO;
-               return 0;
-
-       case CDROMPLAYTRKIND:
-               MCDX_TRACE_IOCTL(("CDROMPLAYTRKIND\n"));
-
-               if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(ti))))
-                       return ans;
-               memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
-               if (ti.cdti_trk0 < stuffp->first
-                   || ti.cdti_trk0 > stuffp->last
-                   || ti.cdti_trk1 < stuffp->first)
-                       return -EINVAL;
-               if (ti.cdti_trk1 > stuffp->last)
-                       ti.cdti_trk1 = stuffp->last;
-               return play_track(stuffp, &ti);
-
-       case CDROMPLAYMSF:
-               MCDX_TRACE_IOCTL(("CDROMPLAYMSF "));
-
-               if ((ans = verify_area(VERIFY_READ, (void *) arg,
-                                      sizeof(struct cdrom_msf))))
-                        return ans;
-               memcpy_fromfs(&msf, (void *) arg, sizeof msf);
-               msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
-               msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
-               msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
-               stuffp->resume.stop.minute =
-                   msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
-               stuffp->resume.stop.second =
-                   msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
-               stuffp->resume.stop.frame =
-                   msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
-               if (-1 == set_command(stuffp, MCDX_CMD_PLAY,
-                                     &msf, sizeof(msf), 3 * HZ)) {
-                       return -1;
                }
-               stuffp->audiostatus = CDROM_AUDIO_PLAY;
-               return 0;
+        if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
+               else {
+                       MOD_DEC_USE_COUNT;
+                       return -EIO;
+               }
+    }
+
+       /* if the media changed we will have to do a little more */
+       if (stuffp->xxx) {
 
-       case CDROMPAUSE:
-               MCDX_TRACE_IOCTL(("CDROMPAUSE\n"));
+               xtrace(OPENCLOSE, "open() media changed\n");
+        /* but wait - the time of media change will be set at the 
+         * very last of this block - it seems, some of the following
+         * talk() will detect a media change ... (I think, config()
+         * is the reason. */
 
-               if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
-                       return -EINVAL;
+        stuffp->audiostatus = CDROM_AUDIO_INVALID;
+               stuffp->readcmd = 0;
 
-               if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ))
+               /* get the multisession information */
+               xtrace(OPENCLOSE, "open() Request multisession info\n");
+               if (-1 == mcdx_requestmultidiskinfo(
+                               stuffp, &stuffp->multi, 6)) {
+                       xinfo("No multidiskinfo\n");
+                       stuffp->autoclose = 0;
+                       /*
+                       MOD_DEC_USE_COUNT;
+                       stuffp->xxx = 0;
                        return -EIO;
-               if (-1 == request_subq_code(stuffp, &q)) {
-                       stuffp->audiostatus = CDROM_AUDIO_NO_STATUS;
-                       return 0;
-               }
-               stuffp->resume.start = q.dt;
-               stuffp->audiostatus = CDROM_AUDIO_PAUSED;
-               return 0;
+                       */
+               } else {
+                       /* we succeeded, so on next open(2) we could try auto close
+                        * again */
+                       stuffp->autoclose = 1;
+               
+#if !MCDX_QUIET
+                       if (stuffp->multi.multi > 2)
+                               xinfo("open() unknown multisession value (%d)\n", 
+                                               stuffp->multi.multi);
+#endif
 
-       case CDROMRESUME:
-               MCDX_TRACE_IOCTL(("CDROMRESUME\n"));
+                       /* multisession ? */
+                       if (!stuffp->multi.multi)
+                               stuffp->multi.msf_last.second = 2;
 
-               if (stuffp->audiostatus != CDROM_AUDIO_PAUSED)
-                       return -EINVAL;
-               return play_track(stuffp, NULL);
-       case CDROMREADTOCENTRY:
-               MCDX_TRACE_IOCTL(("CDROMREADTOCENTRY\n"));
+                       xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
+                                       stuffp->multi.multi,
+                                       stuffp->multi.msf_last.minute,
+                                       stuffp->multi.msf_last.second,
+                                       stuffp->multi.msf_last.frame);
 
-               if (-1 == read_toc(stuffp))
-                       return -1;
-               if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry))))
-                       return ans;
-               memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
-
-               if (entry.cdte_track == CDROM_LEADOUT)
-                       tp = &stuffp->toc[stuffp->last - stuffp->first + 1];
-               else if (entry.cdte_track > stuffp->last
-                        || entry.cdte_track < stuffp->first)
-                       return -EINVAL;
-               else
-                       tp = &stuffp->toc[entry.cdte_track - stuffp->first];
-
-               entry.cdte_adr = tp->adr;
-               entry.cdte_ctrl = tp->ctrl;
-
-               if (entry.cdte_format == CDROM_MSF) {
-                       entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
-                       entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
-                       entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
-               } else if (entry.cdte_format == CDROM_LBA)
-                       entry.cdte_addr.lba = msf2log(&tp->dt);
-               else
-                       return -EINVAL;
-
-               if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry))))
-                       return ans;
-               memcpy_tofs((void *) arg, &entry, sizeof(entry));
+               { ; } /* got multisession information */
 
-               return 0;
+               /* request the disks table of contents (aka diskinfo) */
+               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
 
-       case CDROMSUBCHNL:
-               MCDX_TRACE_IOCTL(("CDROMSUBCHNL\n"));
+                       stuffp->lastsector = -1;
 
-               if ((ans = verify_area(VERIFY_READ,
-                                      (void *) arg, sizeof(sub))))
-                       return ans;
+               } else {
+
+                       stuffp->lastsector = (CD_FRAMESIZE / 512) 
+                                       * msf2log(&stuffp->di.msf_leadout) - 1;
+
+                       xtrace(OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
+                                       stuffp->di.n_first,
+                                       stuffp->di.msf_first.minute,
+                                       stuffp->di.msf_first.second,
+                                       stuffp->di.msf_first.frame,
+                                       msf2log(&stuffp->di.msf_first));
+                       xtrace(OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
+                                       stuffp->di.n_last,
+                                       stuffp->di.msf_leadout.minute,
+                                       stuffp->di.msf_leadout.second,
+                                       stuffp->di.msf_leadout.frame,
+                                       msf2log(&stuffp->di.msf_leadout));
+               }
 
-               memcpy_fromfs(&sub, (void *) arg, sizeof(sub));
+               if (stuffp->toc) {
+                       xtrace(MALLOC, "open() free old toc @ %p\n", stuffp->toc);
+                       kfree(stuffp->toc);
+               
+                       stuffp->toc = NULL;
+               }
 
-               if (-1 == request_subq_code(stuffp, &q))
+               xtrace(OPENCLOSE, "open() init irq generation\n");
+               if (-1 == mcdx_config(stuffp, 1)) {
+                       MOD_DEC_USE_COUNT;
                        return -EIO;
+               }
 
-               sub.cdsc_audiostatus = stuffp->audiostatus;
-               sub.cdsc_adr = q.adr;
-               sub.cdsc_ctrl = q.ctrl;
-               sub.cdsc_trk = bcd2uint(q.tno);
-               sub.cdsc_ind = bcd2uint(q.index);
-
-               if (sub.cdsc_format == CDROM_LBA) {
-                       sub.cdsc_absaddr.lba = msf2log(&q.dt);
-                       sub.cdsc_reladdr.lba = msf2log(&q.tt);
-               } else if (sub.cdsc_format == CDROM_MSF) {
-                       sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
-                       sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
-                       sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
-                       sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
-                       sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
-                       sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
-               } else
-                       return -EINVAL;
-
-               if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(sub))))
-                       return ans;
-               memcpy_tofs((void *) arg, &sub, sizeof(sub));
+#if FALLBACK
+               /* Set the read speed */
+               xwarn("AAA %x AAA\n", stuffp->readcmd);
+               if (stuffp->readerrs) stuffp->readcmd = READ1X;
+               else stuffp->readcmd = 
+                               stuffp->present | SINGLE ? READ1X : READ2X;
+               xwarn("XXX %x XXX\n", stuffp->readcmd);
+#else
+               stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X;
+#endif
 
-               return 0;
+               /* try to get the first sector, iff any ... */
+               if (stuffp->lastsector >= 0) {
+                       char buf[512];
+                       int ans;
+                       int tries;
 
-       case CDROMREADTOCHDR:
-               MCDX_TRACE_IOCTL(("CDROMREADTOCHDR\n"));
+                       stuffp->xa = 0;
+                       stuffp->audio = 0;
 
-               if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof toc)))
-                       return ans;
-               /*
-                * Make sure, we really read it!
-                */
-               release_toc(stuffp);
-               if (-1 == request_toc_data(stuffp))
-                       return -EIO;
+                       for (tries = 6; tries; tries--) {
 
-               toc.cdth_trk0 = stuffp->first;
-               toc.cdth_trk1 = stuffp->last;
-               memcpy_tofs((void *) arg, &toc, sizeof toc);
-               return 0;
+                               stuffp->introk = 1;
 
-       case CDROMMULTISESSION:
-               MCDX_TRACE_IOCTL(("CDROMMULTISESSION\n"));
-
-               if ((ans = verify_area(VERIFY_READ, (void *) arg,
-                                    sizeof(struct cdrom_multisession))))
-                        return ans;
-
-               memcpy_fromfs(&ms,
-                       (void *) arg, sizeof(struct cdrom_multisession));
-               if (ms.addr_format == CDROM_MSF) {
-                       ms.addr.msf.minute =
-                           bcd2uint(stuffp->multi.msf_last.minute);
-                       ms.addr.msf.second =
-                           bcd2uint(stuffp->multi.msf_last.second);
-                       ms.addr.msf.frame =
-                           bcd2uint(stuffp->multi.msf_last.frame);
-               } else if (ms.addr_format == CDROM_LBA)
-                       ms.addr.lba = msf2log(&stuffp->multi.msf_last);
-               else
-                       return -EINVAL;
-               ms.xa_flag = !!stuffp->multi.multi;
-
-               if ((ans = verify_area(VERIFY_WRITE, (void *) arg,
-                                    sizeof(struct cdrom_multisession))))
-                        return ans;
-
-               memcpy_tofs((void *) arg,
-                           &ms, sizeof(struct cdrom_multisession));
-               return 0;
+                               xtrace(OPENCLOSE, "open() try as %s\n",
+                                       stuffp->xa ? "XA" : "normal");
 
-       case CDROMEJECT:
-               MCDX_TRACE_IOCTL(("CDROMEJECT\n"));
-               if (stuffp->door) {
-                       if (-1 == issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ))
-                               return -EIO;
+                               /* set data mode */
+                               if (-1 == (ans = mcdx_setdatamode(stuffp, 
+                                               stuffp->xa ? MODE2 : MODE1, 1))) {
+                                       /* MOD_DEC_USE_COUNT, return -EIO; */
+                                       stuffp->xa = 0;
+                                       break;
+                               }
+
+                               if ((stuffp->audio = e_audio(ans))) break; 
+
+                               while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1))) 
+                                       ;
+
+                               if (ans == 1) break;
+                               stuffp->xa = !stuffp->xa; 
+                       }
+                       /* if (!tries) MOD_DEC_USE_COUNT, return -EIO; */
                }
-               /*
-                * Force rereading of toc next time the disk gets accessed!
-                */
-               release_toc(stuffp);
 
-               return 0;
+               /* xa disks will be read in raw mode, others not */
+               if (-1 == mcdx_setdrivemode(stuffp, 
+                               stuffp->xa ? RAW : COOKED, 1)) {
+                       MOD_DEC_USE_COUNT;
+                       return -EIO;
+               }
 
-       case CDROMEJECT_SW:
-               MCDX_TRACE_IOCTL(("CDROMEJECT_SW\n"));
+               if (stuffp->audio) {
+                       xinfo("open() audio disk found\n");
+               } else if (stuffp->lastsector >= 0) {
+                       xinfo("open() %s%s disk found\n",
+                                       stuffp->xa ? "XA / " : "",
+                                       stuffp->multi.multi ? "Multi Session" : "Single Session");
+               } 
 
-               stuffp->eject_sw = !!arg;
-               return 0;
+        /* stuffp->xxx = 0; */
+       }
 
-       case CDROMVOLCTRL:
-               MCDX_TRACE_IOCTL(("CDROMVOLCTRL\n"));
-
-               if ((ans = verify_area(VERIFY_READ,
-                                      (void *) arg,
-                                      sizeof(volctrl))))
-                       return ans;
-
-               memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
-               /* Adjust for the weirdness of workman. */
-               volctrl.channel2 = volctrl.channel1;
-               volctrl.channel1 = volctrl.channel3 = 0x00;
-               return talk(stuffp, MCDX_CMD_SET_ATTENATOR,
-                           &volctrl, sizeof(volctrl),
-                           &volctrl, sizeof(volctrl), 2 * HZ);
-
-       default:
-               printk(KERN_WARNING MCDX
-                      ": unknown ioctl request 0x%04x\n", command);
-               return -EINVAL;
+    /* lock the door if not already done */
+    if (0 == stuffp->users && (-1 == mcdx_lockdoor(stuffp, 1, 1)))  {
+               MOD_DEC_USE_COUNT;
+        return -EIO;
        }
+       } 
+
+       stuffp->xxx = 0;
+    stuffp->users++;
+    return 0;
+
 }
 
-/*   
- * This does actually the transfer from the drive.
- * Return:      -1 on timeout or other error
- */
-static int transfer_data(struct s_drive_stuff *stuffp,
-                        char *p, int sector, int nr_sectors)
+static void 
+mcdx_close(struct inode *ip, struct file *fp)
 {
-       int off;
-       int done = 0;
+    struct s_drive_stuff *stuffp;
 
-       if (!stuffp->valid || sector < stuffp->pending
-           || sector > stuffp->border) {
-               unsigned char cmd[6];
+    xtrace(OPENCLOSE, "close()\n");
 
-               stuffp->valid = 1;
-               stuffp->pending = sector & ~3;
+    stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
 
-               /* do some sanity checks */
-               if (stuffp->pending > stuffp->lastsector) {
-                       printk(KERN_ERR MCDX
-                       ": sector %d transfer from nirvana requested.\n",
-                              stuffp->pending);
-                       stuffp->eom = 1;
-                       stuffp->valid = 0;
-                       return -1;
-               }
-               if ((stuffp->border = stuffp->pending + REQUEST_SIZE)
-                   > stuffp->lastsector)
-                       stuffp->border = stuffp->lastsector;
-               {
-                       unsigned int l = (stuffp->pending / 4)
-                       + CD_BLOCK_OFFSET;
+    if (0 == --stuffp->users) {
+               sync_dev(ip->i_rdev);   /* needed for r/o device? */
 
-                       cmd[0] = uint2bcd(l / 4500), l %= 4500;         /* minute */
-                       cmd[1] = uint2bcd(l / 75);      /* second */
-                       cmd[2] = uint2bcd(l % 75);      /* frame */
-               }
+               /* invalidate_inodes(ip->i_rdev); */
+               invalidate_buffers(ip->i_rdev);
 
-               stuffp->busy = 1;
-               /*
-                * FIXME: What about the ominous frame length?!
-                */
-               cmd[5] = cmd[4] = cmd[3] = ~0;
-
-               outb(stuffp->double_speed ? MCDX_CMD_PLAY_2X : MCDX_CMD_PLAY,
-                    DATA_REG);
-               outsb(DATA_REG, cmd, 6);
-       }
-       off = sector + nr_sectors;
-       if (stuffp->border < off)
-               off = stuffp->border;
-       do {
-               /* wait for the drive become idle, but first
-                * check for possible occurred errors --- the drive
-                * seems to report them asynchronously
-                */
-               current->timeout = jiffies + 5 * HZ;
-               while (stuffp->introk && stuffp->busy
-                      && current->timeout) {
-                       interruptible_sleep_on(&stuffp->busyq);
-               }
 
-               /* test for possible errors */
-               if (current->timeout == 0 || !stuffp->introk) {
-                       if (current->timeout == 0) {
-                               printk(KERN_ERR MCDX ": transfer timeout.\n");
-                       }
-                       /*
-                        * We don't report about !stuffp->introk, since this is
-                        * already done in the interrupt routine.
-                        */
-                       stuffp->busy = 0;
-                       stuffp->valid = 0;
-                       stuffp->introk = 1;
-                       return -1;
-               }
-               /* test if it's the first sector of a block,
-                * there we have to skip some bytes as we read raw data 
-                */
-               if (stuffp->xa && (0 == (stuffp->pending & 3))) {
-                       insb(DATA_REG, p,
-                          CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE);
-               }
-               /* now actually read the data */
-               insb(DATA_REG, p, 512);
+#if !MCDX_QUIET
+               if (-1 == mcdx_lockdoor(stuffp, 0, 3))
+                               xinfo("close() Cannot unlock the door\n");
+#else
+               mcdx_lockdoor(stuffp, 0, 3);
+#endif
 
-               /* test if it's the last sector of a block,
-                * if so, we have to expect an interrupt and to skip 
-                * some data too 
-                */
-               if ((stuffp->busy = (3 == (stuffp->pending & 3)))
-                   && stuffp->xa) {
-                       int i;
-                       for (i = 0; i < CD_XA_TAIL; ++i)
-                               inb(DATA_REG);
-               }
-               if (stuffp->pending == sector) {
-                       p += 512;
-                       done++;
-                       sector++;
-               }
-       } while (++(stuffp->pending) < off);
+        /* eject if wished */
+        if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
 
-       return done;
+    }
+
+    MOD_DEC_USE_COUNT;
+    return;
 }
 
-void do_mcdx_request()
+int check_mcdx_media_change(kdev_t full_dev)
+/*     Return: 1 if media changed since last call to this function
+                       0 otherwise */
 {
-       int dev;
-       struct s_drive_stuff *stuffp;
+    struct s_drive_stuff *stuffp; 
 
-      again:
+    xinfo("check_mcdx_media_change called for device %s\n",
+         kdevname(full_dev));
 
-       if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) {
-               return;
-       }
-       stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
+       stuffp = mcdx_stuffp[MINOR(full_dev)];
+       mcdx_getstatus(stuffp, 1);
 
-       INIT_REQUEST;
-       dev = MINOR(CURRENT->rq_dev);
-       if (dev < 0 || dev >= MCDX_NDRIVES || !stuffp || stuffp->audio) {
-               end_request(0);
-               goto again;
-       }
-       switch (CURRENT->cmd) {
-       case WRITE:
-               end_request(0);
-               break;
-
-       case READ:
-               stuffp->eom = 0;        /* clear end of media flag */
-               while (CURRENT->nr_sectors) {
-                       int i;
+       if (stuffp->yyy == 0) return 0;
 
-                       i = transfer_data(stuffp, CURRENT->buffer,
-                                  CURRENT->sector, CURRENT->nr_sectors);
-                       if (i == -1) {
-                               if (stuffp->eom) {
-                                       CURRENT->sector += CURRENT->nr_sectors;
-                                       CURRENT->nr_sectors = 0;
-                               } else
-                                       break;  /* FIXME: drop down speed ??? */
-                               end_request(0);
-                               goto again;
-                       }
-                       CURRENT->sector += i;
-                       CURRENT->nr_sectors -= i;
-                       CURRENT->buffer += (i * 512);
-               }
-               end_request(1);
-               break;
-
-       default:
-               panic(MCDX "do_request: unknown command.\n");
-               break;
-       }
-
-       goto again;
+       stuffp->yyy = 0;
+       return 1;
 }
 
-/*  
- * actions done on open:
- * 1)   get the drives status 
- * 2)   handle disk changes
- */
-static int mcdx_open(struct inode *ip, struct file *fp)
+void mcdx_setup(char *str, int *pi)
 {
-       struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
-       int st = 0;
-       unsigned long bang;
+       if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
+       if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
+}
 
-       MCDX_TRACE(("mcdx_open()\n"));
+/* DIRTY PART ******************************************************/ 
 
-       if (!stuffp)
-               return -ENXIO;
+static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
+/* This routine is used for sleeping.
+ * A jifs value <0 means NO sleeping,
+ *              =0 means minimal sleeping (let the kernel
+ *                 run for other processes)
+ *              >0 means at least sleep for that amount.
+ *     May be we could use a simple count loop w/ jumps to itself, but 
+ *     I wanna make this independend of cpu speed. [1 jiffie is 1/HZ] sec */
+{
+    unsigned long tout = jiffies + jifs;
+    if (jifs < 0) return;
+
+       /* If loaded during kernel boot no *_sleep_on is
+        * allowed! */
+    if (current->pid == 0) {        
+               while (jiffies < tout) {
+            current->timeout = jiffies;
+            schedule();
+        }
+    } else {  
+        current->timeout = tout;
+               xtrace(SLEEP, "*** delay: sleepq\n");
+               interruptible_sleep_on(&stuff->sleepq);
+               xtrace(SLEEP, "delay awoken\n");
+               if (current->signal & ~current->blocked) {
+                       xtrace(SLEEP, "got signal\n");
+               }
+       } 
+}
 
-       /* We don't allow multiple users of a drive. In case of data CD's they
-        * will be only used by mounting, which ensures anyway exclusive usage.
-        * In case of sound CD's it's anyway meaningless to try playing two
-        * different tracks at once! This saves us A LOT of trouble.
-        */
-       if (stuffp->used)
-               return -EBUSY;
+static void 
+mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
+{
+    struct s_drive_stuff *stuffp;
+       unsigned char b;
 
-       /* close the door, if necessary (get the door information
-        * from the hardware status register). 
-        * If we can't read the CD after an autoclose
-        * no further auto-closes will be tried 
-        */
-       if (inb(STAT_REG) & MCDX_RBIT_DOOR) {
-               if (stuffp->autoclose && (stuffp->door))
-                       issue_command(stuffp, MCDX_CMD_CLOSE_DOOR, 5 * HZ);
-               else
-                       return -EIO;
-       }
-       /*
-        * Check if a disk is in.
-        */
-       bang = jiffies + 5 * HZ;
-       while (jiffies < bang) {
-               st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 1 * HZ);
-               if (st != -1 && (st & MCDX_RBIT_DISKSET))
-                       break;
-               current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + 1 * HZ;
-               schedule();
-       }
-       if (st == -1 || (st & MCDX_RBIT_DISKSET) == 0) {
-               printk(KERN_INFO MCDX ": no disk in drive\n");
-               return -EIO;
-       }
-       /* if the media changed we will have to do a little more 
-        * FIXME: after removing of the mcdx_requestmultisession() it is showed
-        * that the logics of this may be broken.
-        */
-       if (stuffp->xxx) {
-               /* but wait - the time of media change will be set at the 
-                * very last of this block.
-                */
+    stuffp = mcdx_irq_map[irq];
 
-               stuffp->audiostatus = CDROM_AUDIO_INVALID;
-               stuffp->autoclose = 1;
+    if (stuffp == NULL ) {
+               xwarn("mcdx: no device for intr %d\n", irq);
+               return;
+    }
 
-               /* get the multisession information */
+#ifdef AK2
+       if ( !stuffp->busy && stuffp->pending )
+               stuffp->int_err = 1;
 
-               if (stuffp->multi_cap) {
-                       int i = 6;      /* number of retries */
+#endif /* AK2 */
+       /* get the interrupt status */
+       b = inb((unsigned int) stuffp->rreg_status);
+       stuffp->introk = ~b & MCDX_RBIT_DTEN;
 
-                       while (i--)
-                               if (-1 != get_command(stuffp, MCDX_CMD_GET_MDISK_INFO,
-                                                     &stuffp->multi,
-                                                 sizeof(struct s_multi),
-                                                     2 * HZ))
-                                        break;
+       /* NOTE: We only should get interrupts if the data we 
+        * requested are ready to transfer.
+        * But the drive seems to generate ``asynchronous'' interrupts
+        * on several error conditions too.  (Despite the err int enable
+        * setting during initialisation) */
+
+       /* if not ok, read the next byte as the drives status */
+       if (!stuffp->introk) {
+               xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
+               if (~b & MCDX_RBIT_STEN) {
+                       xinfo(  "intr() irq %d    status 0x%02x\n", 
+                                       irq, inb((unsigned int) stuffp->rreg_data));
+               } else {
+                       xinfo(  "intr() irq %d ambigous hw status\n", irq);
+               }
+       } else {
+               xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
+    }
 
-                       if (!i) {
-                               stuffp->autoclose = 0;  /* don't try it again on next open */
-                               if (stuffp->door)
-                                       issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
-                               return -EIO;
-                       }
-               } else
-                       stuffp->multi.multi = 0;
+    stuffp->busy = 0;
+    wake_up_interruptible(&stuffp->busyq);
+}
 
-               if (!stuffp->multi.multi)
-                       stuffp->multi.msf_last.second = 2;
-               release_toc(stuffp);    /* force rereading */
-               if (-1 == request_toc_data(stuffp))
-                       stuffp->lastsector = -1;
-               else {
-                       stuffp->lastsector = (CD_FRAMESIZE / 512)
-                           * msf2log(&stuffp->msf_leadout) - 1;
-               }
-               if (-1 == config_drive(stuffp))
-                       return -EIO;
 
-               /* try to get the first sector, iff any ... */
-               if (stuffp->lastsector >= 0) {
-                       int tries;
+static int 
+mcdx_talk (
+               struct s_drive_stuff *stuffp, 
+               const unsigned char *cmd, size_t cmdlen,
+               void *buffer, size_t size, 
+               unsigned int timeout, int tries)
+/* Send a command to the drive, wait for the result.
+ * returns -1 on timeout, drive status otherwise
+ * If buffer is not zero, the result (length size) is stored there.
+ * If buffer is zero the size should be the number of bytes to read
+ * from the drive.  These bytes are discarded.
+ */
+{
+       int st;
+    char c;
+    int discard;
 
-                       stuffp->xa = 0;
-                       stuffp->audio = 0;
-                       for (tries = 6; tries; tries--) {
-                               char buf[512];
-                               int st;
-                               unsigned char c;
-                               stuffp->introk = 1;
+       /* Somebody wants the data read? */
+    if ((discard = (buffer == NULL))) buffer = &c;
 
-                               /* set data mode */
-                               c = stuffp->xa ? MODE2 : MODE1;
-                               st = set_command(stuffp,
-                                                MCDX_CMD_SET_DATA_MODE,
-                                                &c, sizeof(c), 5 * HZ);
-                               if (-1 == st) {
-                                       stuffp->xa = 0;
-                                       continue;
-                               } else if (st & MCDX_RBIT_AUDIOTR) {
-                                       stuffp->audio = 1;
-                                       break;
-                               }
-                               while (0 == (st = transfer_data(stuffp, buf,
-                                                               0, 1)));
-                               if (st == 1)
-                                       break;
-                               stuffp->xa = !stuffp->xa;
-                       }
-                       /* if (!tries) return -EIO; */
-               }
-               /* xa disks will be read in raw mode, others not */
-               if (-1 == set_drive_mode(stuffp, stuffp->xa ? RAW : COOKED))
-                       return -EIO;
-               stuffp->xxx = 0;
+    while (stuffp->lock) {
+               xtrace(SLEEP, "*** talk: lockq\n");
+               interruptible_sleep_on(&stuffp->lockq); 
+               xtrace(SLEEP, "talk: awoken\n");
        }
-       /* lock the door if not already done */
-       if (!stuffp->used && (-1 == lock_door(stuffp, DOOR_LOCK)))
-               return -EIO;
 
-       stuffp->used = 1;
-       MOD_INC_USE_COUNT;
-       return 0;
-}
+    stuffp->lock = 1;
 
-static void mcdx_close(struct inode *ip, struct file *fp)
-{
-       struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
+       /* An operation other then reading data destroys the
+     * data already requested and remembered in stuffp->request, ... */
+    stuffp->valid = 0; 
 
-       MCDX_TRACE(("mcdx_close()\n"));
+#if MCDX_DEBUG & TALK
+       { 
+               unsigned char i;
+               xtrace(TALK, "talk() %d / %d tries, res.size %d, command 0x%02x", 
+                               tries, timeout, size, (unsigned char) cmd[0]);
+               for (i = 1; i < cmdlen; i++) xtrace(TALK, " 0x%02x", cmd[i]);
+               xtrace(TALK, "\n");
+       }
+#endif
 
-       sync_dev(ip->i_rdev);   /* needed for r/o device? */
+    /*  give up if all tries are done (bad) or if the status
+     *  st != -1 (good) */
+       for (st = -1; st == -1 && tries; tries--) {
+
+               char *bp = (char*) buffer;
+               size_t sz = size;
+
+               outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
+        xtrace(TALK, "talk() command sent\n");
+
+        /* get the status byte */
+        if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
+            xinfo("talk() %02x timed out (status), %d tr%s left\n", 
+                    cmd[0], tries - 1, tries == 2 ? "y" : "ies");
+                continue; 
+        }
+        st = *bp;
+        sz--;
+        if (!discard) bp++;
+
+        xtrace(TALK, "talk() got status 0x%02x\n", st);
+
+        /* command error? */
+        if (e_cmderr(st)) {
+            xwarn("command error cmd = %02x %s \n", 
+                    cmd[0], cmdlen > 1 ? "..." : "");
+            st = -1;
+            continue;
+               }
 
-       /* invalidate_inodes(ip->i_rdev); */
-       invalidate_buffers(ip->i_rdev);
-       lock_door(stuffp, DOOR_UNLOCK);
+        /* audio status? */
+        if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
+            stuffp->audiostatus = 
+                    e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
+        else if (stuffp->audiostatus == CDROM_AUDIO_PLAY 
+                && e_audiobusy(st) == 0)
+            stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
+
+        /* media change? */
+        if (e_changed(st)) {
+            xinfo("talk() media changed\n");
+            stuffp->xxx = stuffp->yyy = 1;
+        }
+
+        /* now actually get the data */
+        while (sz--) {
+            if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
+                xinfo("talk() %02x timed out (data), %d tr%s left\n", 
+                        cmd[0], tries - 1, tries == 2 ? "y" : "ies");
+                st = -1; break;
+            }
+            if (!discard) bp++;
+            xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
+        }
+    }
+
+#if !MCDX_QUIET
+    if (!tries && st == -1) xinfo("talk() giving up\n");
+#endif
 
-       /* eject if wished and possible */
-       if (stuffp->eject_sw && (stuffp->door)) {
-               issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
-       }
-       stuffp->used = 0;
-       MOD_DEC_USE_COUNT;
+    stuffp->lock = 0;
+    wake_up_interruptible(&stuffp->lockq);
+
+       xtrace(TALK, "talk() done with 0x%02x\n", st);
+    return st;
 }
 
-/*      
- * Return: 1 if media changed since last call to this function, 0 otherwise.
- */
-static int mcdx_media_change(kdev_t full_dev)
+/* MODULE STUFF ***********************************************************/
+#ifdef MODULE
+
+int init_module(void)
 {
-       struct s_drive_stuff *stuffp;
+       int i;
+       int drives = 0;
 
-       MCDX_TRACE(("mcdx_media_change()\n"));
+       mcdx_init();
+       for (i = 0; i < MCDX_NDRIVES; i++)  {
+               if (mcdx_stuffp[i]) {
+               xtrace(INIT, "init_module() drive %d stuff @ %p\n",
+                               i, mcdx_stuffp[i]);
+                       drives++;
+               }
+       }
 
-       /*
-        * FIXME: probably this is unneeded or should be simplified!
-        */
-       issue_command(stuffp = mcdx_stuffp[MINOR(full_dev)],
-                     MCDX_CMD_GET_STATUS, 5 * HZ);
+    if (!drives) 
+               return -EIO;
 
-       return stuffp->xxx;
+    register_symtab(0);
+    return 0;
 }
 
-/* Interrupt handler routine.
- * This function is called, when during transfer the end of a physical 2048
- * byte block is reached.
- */
-static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
+void cleanup_module(void)
 {
-       struct s_drive_stuff *stuffp;
-       u_char b;
+    int i;
 
-       if (!(stuffp = mcdx_irq_map[irq])) {
-               return;         /* huh? */
-       }
-       /* NOTE: We only should get interrupts if data were requested.
-        * But the drive seems to generate ``asynchronous'' interrupts
-        * on several error conditions too.  (Despite the err int enable
-        * setting during initialization) 
-        */
-       b = inb(STAT_REG);
-       if (!(b & MCDX_RBIT_DTEN))
-               stuffp->introk = 1;
-       else {
-               stuffp->introk = 0;
-               if (!(b & MCDX_RBIT_STEN)) {
-                       b = inb(DATA_REG);
-                       if (stuffp->used)
-                               printk(KERN_DEBUG MCDX
-                                      ": irq %d status 0x%02x\n", irq, b);
-               } else
-                       MCDX_TRACE(("irq %d ambiguous hw status\n", irq));
-       }
-       stuffp->busy = 0;
-       wake_up_interruptible(&stuffp->busyq);
+       xinfo("cleanup_module called\n");
+       
+    for (i = 0; i < MCDX_NDRIVES; i++) {
+               struct s_drive_stuff *stuffp;
+               stuffp = mcdx_stuffp[i];
+               if (!stuffp) continue;
+               release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
+               free_irq(stuffp->irq, NULL);
+               if (stuffp->toc) {
+                       xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc);
+                       kfree(stuffp->toc);
+               }
+               xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp);
+               mcdx_stuffp[i] = NULL;
+               kfree(stuffp);
+    }
+
+    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
+        xwarn("cleanup() unregister_blkdev() failed\n");
+    } 
+#if !MCDX_QUIET
+       else xinfo("cleanup() succeeded\n");
+#endif
 }
 
-/*
- * FIXME:
- * This seems to hang badly, when the driver is loaded with inappropriate
- * port/irq settings!
- */
+#endif MODULE
+
+/* Support functions ************************************************/
+
 int mcdx_init(void)
 {
        int drive;
 
 #ifdef MODULE
-       printk(KERN_INFO "Mitsumi driver V" VERSION " for %s\n",
-              kernel_version);
+       xwarn("Version 2.14(hs) for %s\n", kernel_version);
 #else
-       printk(KERN_INFO "Mitsumi driver V" VERSION "\n");
+       xwarn("Version 2.14(hs) \n");
 #endif
-       for (drive = 0; drive < MCDX_NDRIVES; drive++) {
-               struct {
-                       u_char code;
-                       u_char version;
-               } firmware;
-               int i;
-               struct s_drive_stuff *stuffp;
-               int size;
 
-               mcdx_blksize_size[drive] = 0;
-               mcdx_stuffp[drive] = 0;
+       xwarn("$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $\n");
+
+       /* zero the pointer array */
+       for (drive = 0; drive < MCDX_NDRIVES; drive++)
+               mcdx_stuffp[drive] = NULL;
+
+       /* do the initialisation */
+       for (drive = 0; drive < MCDX_NDRIVES; drive++) { 
+               struct s_version version;
+               struct s_drive_stuff* stuffp;
+        int size;
 
-               size = sizeof(*stuffp);
+               mcdx_blocksizes[drive] = 0;
+
+        size = sizeof(*stuffp);
+               
+               xtrace(INIT, "init() try drive %d\n", drive);
+
+        xtrace(INIT, "kmalloc space for stuffpt's\n");
+               xtrace(MALLOC, "init() malloc %d bytes\n", size);
+               if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
+                       xwarn("init() malloc failed\n");
+                       break; 
+               }
 
-               if (!(stuffp = kmalloc(size, GFP_KERNEL)))
-                       break;
+               xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp);
 
                /* set default values */
                memset(stuffp, 0, sizeof(*stuffp));
-               stuffp->autoclose = 1;  /* close the door on open(2) */
+        stuffp->autoclose = 1;      /* close the door on open(2) */
 
-               stuffp->base = mcdx_drive_map[drive][PORT];
-               stuffp->irq = mcdx_drive_map[drive][IRQ];
+               stuffp->present = 0;            /* this should be 0 already */
+               stuffp->toc = NULL;                     /* this should be NULL already */
+
+               /* setup our irq and i/o addresses */
+               stuffp->irq = irq(mcdx_drive_map[drive]);
+               stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
+               stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
+               stuffp->wreg_hcon = stuffp->wreg_reset + 1;
+               stuffp->wreg_chn = stuffp->wreg_hcon + 1;
 
                /* check if i/o addresses are available */
-               if (check_region(stuffp->base, MCDX_IO_SIZE)) {
-                       printk(KERN_WARNING
-                              "Init failed. I/O ports (0x%3x..0x%3x) "
-                              "already in use.\n",
-                         stuffp->base, stuffp->base + MCDX_IO_SIZE - 1);
-                       kfree(stuffp);
-                       continue;       /* next drive */
+               if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
+            xwarn("0x%3p,%d: "
+                    "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n",
+                    stuffp->wreg_data, stuffp->irq,
+                    stuffp->wreg_data, 
+                    stuffp->wreg_data + MCDX_IO_SIZE - 1);
+                       xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
+            kfree(stuffp);
+                       xtrace(INIT, "init() continue at next drive\n");
+                       continue; /* next drive */
                }
-               /*
-                * Hardware reset.
-                */
-               outb(0, CHAN_REG);      /* no dma, no irq -> hardware */
-               outb(0, RESET_REG);     /* hw reset */
-
-               i = 10;         /* number of retries */
-               while (-1 == get_command(stuffp, MCDX_CMD_GET_FIRMWARE,
-                                   &firmware, sizeof(firmware), 2 * HZ))
-                       --i;
-               if (!i) {
+
+               xtrace(INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data);
+
+               xtrace(INIT, "init() hardware reset\n");
+               mcdx_reset(stuffp, HARD, 1);
+
+               xtrace(INIT, "init() get version\n");
+               if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
                        /* failed, next drive */
-                       printk(KERN_WARNING
-                       "%s=0x%3x,%d: Init failed. Can't get version.\n",
-                              MCDX, stuffp->base, stuffp->irq);
-                       kfree(stuffp);
+            xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
+                    MCDX,
+                    stuffp->wreg_data, stuffp->irq);
+                       xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
+            kfree(stuffp);
+                       xtrace(INIT, "init() continue at next drive\n");
                        continue;
                }
-               switch (firmware.code) {
-               case 'D':
-                       stuffp->double_speed = stuffp->door =
-                           stuffp->multi_cap = 1;
-                       break;
-               case 'F':
-                       stuffp->door = stuffp->multi_cap = 1;
-                       break;
-               case 'M':
-                       break;
-               default:
-                       kfree(stuffp);
+
+               switch (version.code) {
+               case 'D': 
+                stuffp->readcmd = READ2X; 
+                stuffp->present = DOUBLE | DOOR | MULTI; 
+                break;
+               case 'F': 
+                stuffp->readcmd = READ1X; 
+                stuffp->present = SINGLE | DOOR | MULTI;
+                break;
+               case 'M': 
+                stuffp->readcmd = READ1X;
+                stuffp->present = SINGLE;
+                break;
+               default: 
+                stuffp->present = 0; break;
                }
 
-               if (!stuffp)
-                       continue;       /* next drive */
+        stuffp->playcmd = READ1X;
+
 
-               if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops)) {
+               if (!stuffp->present) {
+            xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
+                    MCDX, stuffp->wreg_data, stuffp->irq);
                        kfree(stuffp);
-                       continue;       /* next drive */
+                       continue; /* next drive */
                }
-               /*
-                * CD-ROM's are an example of non 1024 devices
-                */
-               mcdx_blksize_size[drive] = 1024;
+
+               xtrace(INIT, "init() register blkdev\n");
+               if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops) != 0) {
+            xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
+                    MCDX,
+                    stuffp->wreg_data, stuffp->irq, MAJOR_NR);
+                       kfree(stuffp);
+                       continue; /* next drive */
+               }
+
                blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
                read_ahead[MAJOR_NR] = READ_AHEAD;
-               blksize_size[MAJOR_NR] = mcdx_blksize_size;
 
+               blksize_size[MAJOR_NR] = mcdx_blocksizes;
+
+               xtrace(INIT, "init() subscribe irq and i/o\n");
                mcdx_irq_map[stuffp->irq] = stuffp;
-               if (request_irq(stuffp->irq, mcdx_intr,
-                               SA_INTERRUPT, DEVICE_NAME, NULL)) {
+               if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, DEVICE_NAME, NULL)) {
+            xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
+                    MCDX,
+                    stuffp->wreg_data, stuffp->irq, stuffp->irq);
                        stuffp->irq = 0;
                        kfree(stuffp);
-                       continue;       /* next drive */
+                       continue;
+               }
+               request_region((unsigned int) stuffp->wreg_data, 
+                MCDX_IO_SIZE, 
+                DEVICE_NAME); 
+
+               xtrace(INIT, "init() get garbage\n");
+               {
+                       int i;
+                       mcdx_delay(stuffp, HZ/2);
+                       for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status);
                }
-               request_region(stuffp->base, MCDX_IO_SIZE, DEVICE_NAME);
 
-               /* get junk after some delay.
-                */
-               current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + HZ / 2;
-               schedule();
-               for (i = 100; i; i--)
-                       (void) inb(STAT_REG);
 
 #if WE_KNOW_WHY
-               outb(0x50, CHAN_REG);   /* irq 11 -> channel register */
+                       outb(0x50, (unsigned int) stuffp->wreg_chn);    /* irq 11 -> channel register */
 #endif
 
-               config_drive(stuffp);
+               xtrace(INIT, "init() set non dma but irq mode\n");
+               mcdx_config(stuffp, 1);
+
+               stuffp->minor = drive;
 
-               printk(KERN_INFO MCDX
-                      "%d: at 0x%3x, irq %d, type: %c, firmware: %x\n",
-                      drive, stuffp->base, stuffp->irq,
-                      firmware.code, firmware.version);
+               xwarn("(%s) installed at 0x%3p, irq %d."
+                          " (Firmware version %c %x)\n",
+                          DEVICE_NAME,
+                          stuffp->wreg_data, stuffp->irq, version.code,
+               version.ver);
                mcdx_stuffp[drive] = stuffp;
+               xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
        }
 
        return 0;
 }
 
-#ifdef MODULE
+static int 
+mcdx_transfer(struct s_drive_stuff *stuffp,
+               char *p, int sector, int nr_sectors)
+/*     This seems to do the actually transfer.  But it does more.  It
+       keeps track of errors ocurred and will (if possible) fall back
+       to single speed on error. 
+       Return: -1 on timeout or other error
+                       else status byte (as in stuff->st) */
+{
+       int ans;
 
-int init_module(void)
+       ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
+       return ans;
+#if FALLBACK
+       if (-1 == ans) stuffp->readerrs++;
+       else return ans;
+
+       if (stuffp->readerrs && stuffp->readcmd == READ1X) {
+               xwarn("XXX Alrady reading 1x -- no chance\n");
+               return -1;
+       }
+
+       xwarn("XXX Fallback to 1x\n");
+
+       stuffp->readcmd = READ1X;
+       return mcdx_transfer(stuffp, p, sector, nr_sectors);
+#endif
+       
+}
+
+
+static int mcdx_xfer(struct s_drive_stuff *stuffp,
+               char *p, int sector, int nr_sectors)
+/*     This does actually the transfer from the drive.
+       Return: -1 on timeout or other error
+                       else status byte (as in stuff->st) */
 {
-       int i;
+    int border;
+    int done = 0;
+       
+       if (stuffp->audio) {
+                       xwarn("Attempt to read from audio CD.\n");
+                       return -1;
+       }
 
-       mcdx_init();
-       for (i = 0; i < MCDX_NDRIVES; i++) {
-               if (mcdx_stuffp[i]) {
-                       register_symtab(0);
-                       return 0;
+       if (!stuffp->readcmd) {
+                       xinfo("Can't transfer from missing disk.\n");
+                       return -1;
+       }
+
+    while (stuffp->lock) {
+               interruptible_sleep_on(&stuffp->lockq);
+       }
+
+    if (stuffp->valid
+                       && (sector >= stuffp->pending)
+                       && (sector < stuffp->low_border)) {
+
+               /* All (or at least a part of the sectors requested) seems
+         * to be already requested, so we don't need to bother the
+                * drive with new requests ...
+                * Wait for the drive become idle, but first
+                * check for possible occured errors --- the drive
+                * seems to report them asynchronously */
+
+
+       border = stuffp->high_border < (border = sector + nr_sectors)
+                       ? stuffp->high_border : border;
+
+       stuffp->lock = current->pid;
+
+       do {
+
+           current->timeout = jiffies + 5 * HZ;
+           while (stuffp->busy) {
+
+                       interruptible_sleep_on(&stuffp->busyq);
+
+                       if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); }
+                       else if (current->timeout == 0) { xtrace(XFER, "timeout\n"); } 
+                       else if (current->signal & ~current->blocked) {
+                               xtrace(XFER, "signal\n"); 
+                       } else continue;
+
+                       stuffp->lock = 0;
+                       stuffp->busy = 0;
+                       stuffp->valid = 0;
+
+                       wake_up_interruptible(&stuffp->lockq);
+                       xtrace(XFER, "transfer() done (-1)\n");
+                       return -1;
+           }
+
+               /* check if we need to set the busy flag (as we
+                * expect an interrupt */
+               stuffp->busy = (3 == (stuffp->pending & 3));
+
+               /* Test if it's the first sector of a block,
+                * there we have to skip some bytes as we read raw data */
+               if (stuffp->xa && (0 == (stuffp->pending & 3))) {
+                       const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
+                       insb((unsigned int) stuffp->rreg_data, p, HEAD);
                }
+
+               /* now actually read the data */ 
+           insb((unsigned int) stuffp->rreg_data, p, 512); 
+
+               /* test if it's the last sector of a block,
+                * if so, we have to handle XA special */
+               if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
+                       char dummy[CD_XA_TAIL];
+                       insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
+               }
+
+           if (stuffp->pending == sector) {
+                       p += 512;
+                       done++;
+                       sector++;
+           }
+       } while (++(stuffp->pending) < border);
+
+       stuffp->lock = 0;
+       wake_up_interruptible(&stuffp->lockq);
+
+    } else {
+
+               /* The requested sector(s) is/are out of the 
+                * already requested range, so we have to bother the drive
+                * with a new request. */
+
+               static unsigned char cmd[] = {
+                       0,
+                       0, 0, 0,
+                       0, 0, 0
+               };
+
+               cmd[0] = stuffp->readcmd;
+
+               /* The numbers held in ->pending, ..., should be valid */
+               stuffp->valid = 1;
+               stuffp->pending = sector & ~3;
+
+               /* do some sanity checks */
+               if (stuffp->pending > stuffp->lastsector) {
+                       xwarn("transfer() sector %d from nirvana requested.\n",
+                               stuffp->pending);
+                       stuffp->status = MCDX_ST_EOM;
+                       stuffp->valid = 0;
+                       xtrace(XFER, "transfer() done (-1)\n");
+                       return -1;
+               }
+
+               if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
+                               > stuffp->lastsector + 1) {
+                       xtrace(XFER, "cut low_border\n");
+                       stuffp->low_border = stuffp->lastsector + 1;
+               }
+               if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
+                               > stuffp->lastsector + 1) {
+                       xtrace(XFER,  "cut high_border\n");
+                       stuffp->high_border = stuffp->lastsector + 1;
+               }
+
+               {       /* Convert the sector to be requested to MSF format */
+                       struct cdrom_msf0 pending;
+                       log2msf(stuffp->pending / 4, &pending);
+                       cmd[1] = pending.minute;
+                       cmd[2] = pending.second;
+                       cmd[3] = pending.frame;
+               }
+
+               cmd[6] = (unsigned char) ((stuffp->high_border - stuffp->pending) / 4);
+               xtrace(XFER, "[%2d]\n", cmd[6]);
+
+               stuffp->busy = 1;
+               /* Now really issue the request command */
+               outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
+
+    }
+#ifdef AK2
+       if ( stuffp->int_err ) {
+               stuffp->valid = 0;
+               stuffp->int_err = 0;
+               return -1;
        }
-       return -EIO;
+#endif /* AK2 */
+
+    stuffp->low_border = (stuffp->low_border += done) < stuffp->high_border
+           ? stuffp->low_border : stuffp->high_border;
+
+    return done;
 }
 
-void cleanup_module(void)
+
+/*     Access to elements of the mcdx_drive_map members */
+
+static char* port(int *ip) { return (char*) ip[0]; }
+static int irq(int *ip) { return ip[1]; }
+
+/*     Misc number converters */
+
+static unsigned int bcd2uint(unsigned char c)
+{ return (c >> 4) * 10 + (c & 0x0f); }
+
+static unsigned int uint2bcd(unsigned int ival)
+{ return ((ival / 10) << 4) | (ival % 10); }
+
+static void log2msf(unsigned int l, struct cdrom_msf0* pmsf)
 {
-       int i;
+    l += CD_BLOCK_OFFSET;
+    pmsf->minute = uint2bcd(l / 4500), l %= 4500;
+    pmsf->second = uint2bcd(l / 75);
+    pmsf->frame = uint2bcd(l % 75);
+}
 
-       unregister_blkdev(MAJOR_NR, DEVICE_NAME);
+static unsigned int msf2log(const struct cdrom_msf0* pmsf)
+{
+    return bcd2uint(pmsf->frame)
+    + bcd2uint(pmsf->second) * 75
+    + bcd2uint(pmsf->minute) * 4500
+    - CD_BLOCK_OFFSET;
+}
+       
+int mcdx_readtoc(struct s_drive_stuff* stuffp)
+/*  Read the toc entries from the CD,
+ *  Return: -1 on failure, else 0 */
+{
 
-       for (i = 0; i < MCDX_NDRIVES; i++) {
-               struct s_drive_stuff *stuffp;
-               stuffp = mcdx_stuffp[i];
-               if (!stuffp)
-                       continue;
-               release_region(stuffp->base, MCDX_IO_SIZE);
-               free_irq(stuffp->irq, NULL);
-               release_toc(stuffp);
-               mcdx_stuffp[i] = NULL;
-               kfree(stuffp);
+       if (stuffp->toc) {
+               xtrace(READTOC, "ioctl() toc already read\n");
+               return 0;
+       }
+
+       xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
+                       stuffp->di.n_last - stuffp->di.n_first + 1);
+
+    if (-1 == mcdx_hold(stuffp, 1)) return -1;
+
+       xtrace(READTOC, "ioctl() tocmode\n");
+       if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
+
+       /* all seems to be ok so far ... malloc */
+       {
+               int size;
+               size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
+
+               xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
+               stuffp->toc = kmalloc(size, GFP_KERNEL);
+               if (!stuffp->toc) {
+                       xwarn("Cannot malloc %d bytes for toc\n", size);
+                       mcdx_setdrivemode(stuffp, DATA, 1);
+                       return -EIO;
+               }
        }
-       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+
+       /* now read actually the index */
+       {
+               int trk;
+               int retries;
+
+               for (trk = 0; 
+                               trk < (stuffp->di.n_last - stuffp->di.n_first + 1); 
+                               trk++)
+                       stuffp->toc[trk].index = 0;
+
+               for (retries = 300; retries; retries--) { /* why 300? */
+                       struct s_subqcode q;
+                       unsigned int idx;
+               
+                       if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
+                               mcdx_setdrivemode(stuffp, DATA, 1);
+                               return -EIO;
+                       }
+
+                       idx = bcd2uint(q.index);
+
+                       if ((idx > 0) 
+                                       && (idx <= stuffp->di.n_last) 
+                                       && (q.tno == 0)
+                                       && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
+                               stuffp->toc[idx - stuffp->di.n_first] = q;
+                               xtrace(READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk);
+                               trk--;
+                       }
+                       if (trk == 0) break;
+               }
+               memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1], 
+                               0, sizeof(stuffp->toc[0]));
+               stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
+                               = stuffp->di.msf_leadout;
+       }
+
+       /* unset toc mode */
+       xtrace(READTOC, "ioctl() undo toc mode\n");
+       if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
+               return -EIO;
+
+#if MCDX_DEBUG && READTOC
+       { int trk;
+       for (trk = 0; 
+                       trk < (stuffp->di.n_last - stuffp->di.n_first + 2); 
+                       trk++)
+               xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
+                               "  %02x:%02x.%02x  %02x:%02x.%02x\n",
+                               trk + stuffp->di.n_first,
+                               stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
+                               stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
+                               stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame);
+       }
+#endif
+
+       return 0;
 }
 
-#else                          /* MODULE */
+static int
+mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
+{
+    unsigned char cmd[7] = {
+        0, 0, 0, 0, 0, 0, 0
+    };
 
-/*
- * This function is used by the kernel in init/main.c to provide semantics
- * for the corresponding kernel options. It's unused otherwise.
- */
-void mcdx_setup(char *str, int *pi)
+       if (!stuffp->readcmd) {
+               xinfo("Can't play from missing disk.\n");
+               return -1;
+       }
+
+    cmd[0] = stuffp->playcmd;
+    
+    cmd[1] = msf->cdmsf_min0;
+    cmd[2] = msf->cdmsf_sec0;
+    cmd[3] = msf->cdmsf_frame0;
+    cmd[4] = msf->cdmsf_min1;
+    cmd[5] = msf->cdmsf_sec1;
+    cmd[6] = msf->cdmsf_frame1;
+
+    xtrace(PLAYMSF, "ioctl(): play %x "
+            "%02x:%02x:%02x -- %02x:%02x:%02x\n",
+            cmd[0], cmd[1], cmd[2], cmd[3],
+            cmd[4], cmd[5], cmd[6]); 
+
+    outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
+
+    if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
+        xwarn("playmsf() timeout\n"); 
+        return -1;
+    }
+
+    stuffp->audiostatus = CDROM_AUDIO_PLAY;
+    return 0;
+}
+
+static int 
+mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti)
 {
-       if (pi[0] > 0)
-               mcdx_drive_map[0][0] = pi[1];
-       if (pi[0] > 1)
-               mcdx_drive_map[0][1] = pi[2];
+    struct s_subqcode* p;
+    struct cdrom_msf msf;
+
+    if (-1 == mcdx_readtoc(stuffp)) return -1;
+
+    if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
+    else p = &stuffp->start;
+
+    msf.cdmsf_min0 = p->dt.minute;
+    msf.cdmsf_sec0 = p->dt.second;
+    msf.cdmsf_frame0 = p->dt.frame;
+
+    if (ti) {
+        p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
+        stuffp->stop = *p;
+    } else p = &stuffp->stop;
+
+    msf.cdmsf_min1 = p->dt.minute;
+    msf.cdmsf_sec1 = p->dt.second;
+    msf.cdmsf_frame1 = p->dt.frame;
+
+    return mcdx_playmsf(stuffp, &msf);
+}
+
+
+/* Drive functions ************************************************/
+
+static int 
+mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
+{
+       if (stuffp->present & DOOR)
+               return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries);
+       else
+               return 0;
+}
+
+static int 
+mcdx_stop(struct s_drive_stuff *stuffp, int tries)
+{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
+
+static int
+mcdx_hold(struct s_drive_stuff *stuffp, int tries)
+{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
+
+static int
+mcdx_eject(struct s_drive_stuff *stuffp, int tries)
+{
+       if (stuffp->present & DOOR) {
+        stuffp->ejected = jiffies;
+               return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries);
+    } else return 0;
 }
-#endif                         /* MODULE */
+
+static int
+mcdx_requestsubqcode(struct s_drive_stuff *stuffp, 
+        struct s_subqcode *sub, 
+        int tries)
+{
+       char buf[11];
+       int ans;
+
+       if (-1 == (ans = mcdx_talk(
+            stuffp, "\x20", 1, buf, sizeof(buf),
+            2 * HZ, tries))) 
+        return -1;
+       sub->control = buf[1];
+       sub->tno = buf[2];
+       sub->index = buf[3];
+       sub->tt.minute = buf[4];
+       sub->tt.second = buf[5];
+       sub->tt.frame = buf[6];
+       sub->dt.minute = buf[8];
+       sub->dt.second = buf[9];
+       sub->dt.frame = buf[10];
+
+       return ans;
+}
+
+static int
+mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
+{
+       char buf[5];
+       int ans;
+
+    if (stuffp->present & MULTI) {
+               ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries);
+               multi->multi = buf[1];
+        multi->msf_last.minute = buf[2];
+        multi->msf_last.second = buf[3];
+        multi->msf_last.frame = buf[4];
+        return ans;
+    } else {
+        multi->multi = 0;
+        return 0;
+    }
+}
+
+static int 
+mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
+{
+       char buf[9];
+       int ans;
+       ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
+       if (ans == -1) {
+               info->n_first = 0;
+               info->n_last = 0;
+       } else {
+               info->n_first = bcd2uint(buf[1]);
+               info->n_last = bcd2uint(buf[2]);
+               info->msf_leadout.minute = buf[3];
+               info->msf_leadout.second = buf[4];
+               info->msf_leadout.frame = buf[5];
+               info->msf_first.minute = buf[6];
+               info->msf_first.second = buf[7];
+               info->msf_first.frame = buf[8];
+       }
+       return ans;
+}
+
+static int
+mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
+{
+       char cmd[2];
+       int ans;
+
+       xtrace(HW, "setdrivemode() %d\n", mode);
+
+       if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
+               return -1;
+
+       switch (mode) {
+         case TOC: cmd[1] |= 0x04; break;
+         case DATA: cmd[1] &= ~0x04; break;
+         case RAW: cmd[1] |= 0x40; break;
+         case COOKED: cmd[1] &= ~0x40; break;
+         default: break;
+       }
+       cmd[0] = 0x50;
+       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
+}
+
+static int
+mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
+{
+       unsigned char cmd[2] = { 0xa0 };
+       xtrace(HW, "setdatamode() %d\n", mode);
+       switch (mode) {
+         case MODE0: cmd[1] = 0x00; break;
+         case MODE1: cmd[1] = 0x01; break;
+         case MODE2: cmd[1] = 0x02; break;
+         default: return -EINVAL;
+       }
+       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
+}
+
+static int
+mcdx_config(struct s_drive_stuff *stuffp, int tries)
+{
+       char cmd[4];
+
+       xtrace(HW, "config()\n");
+
+       cmd[0] = 0x90;
+
+       cmd[1] = 0x10;          /* irq enable */
+       cmd[2] = 0x05;          /* pre, err irq enable */
+
+       if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
+               return -1;
+
+       cmd[1] = 0x02;          /* dma select */
+       cmd[2] = 0x00;          /* no dma */
+
+       return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
+}
+
+static int
+mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
+{
+       char buf[3];
+       int ans;
+
+       if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 
+                       1, buf, sizeof(buf), 2 * HZ, tries)))
+               return ans;
+
+       ver->code = buf[1];
+       ver->ver = buf[2];
+
+       return ans;
+}
+
+static int
+mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
+{ 
+       if (mode == HARD) {
+               outb(0, (unsigned int) stuffp->wreg_chn);               /* no dma, no irq -> hardware */
+               outb(0, (unsigned int) stuffp->wreg_reset);             /* hw reset */
+               return 0;
+       } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
+}
+
+static int
+mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
+{
+       char cmd[2] = { 0xfe };
+    if (stuffp->present & DOOR) {
+        cmd[1] = lock ? 0x01 : 0x00;
+        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries);
+    } else return 0;
+}
+
+static int
+mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
+{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
+
+static int
+mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
+{
+    unsigned long timeout = to + jiffies;
+    char c;
+
+    if (!buf) buf = &c;
+
+    while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
+        if (jiffies > timeout) return -1;
+        mcdx_delay(stuffp, delay);
+    }
+
+    *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
+
+    return 0;
+}
+
+static int
+mcdx_setattentuator(
+        struct s_drive_stuff* stuffp, 
+        struct cdrom_volctrl* vol, 
+        int tries)
+{
+    char cmd[5];
+    cmd[0] = 0xae;
+    cmd[1] = vol->channel0;
+    cmd[2] = 0;
+    cmd[3] = vol->channel1;
+    cmd[4] = 0;
+
+    return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
+}
+
+/* ex:set ts=4 sw=4 ai si: */
index 2838359b0416ecfd714a41e2fad757b8bb8fea54..52be38829ab4d8a67b6c11488f10d1d8bf38b4cd 100644 (file)
@@ -13,7 +13,7 @@
  *             labelled E2550UA or MK4015 or 2800F).
  */
 
-#define VERSION "v4.3 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "v4.4 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 /*   Copyright (C) 1993, 1994, 1995  Eberhard Moenkeberg <emoenke@gwdg.de>
  *
  *       reading the ToC; still trying to solve it.
  *       Removed some redundant verify_area calls (yes, Heiko Eissfeldt
  *       is visiting all the Linux CDROM drivers ;-).
+ *       
+ *  4.4  Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down"
+ *       experiments: "KLOGD_PAUSE".
+ *       Inhibited "play audio" attempts with data CDs. Provisions for a
+ *       "data-safe" handling of "mixed" (data plus audio) Cds.
  *
  *
  *  TODO
@@ -689,6 +694,9 @@ static struct {
        u_char TocEnt_number;
        u_char TocEnt_format; /* em */
        u_int TocEnt_address;
+#if SAFE_MIXED
+       char has_data;
+#endif SAFE_MIXED
        u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
        
        struct {
@@ -751,7 +759,9 @@ static void msg(int level, const char *fmt, ...)
        vsprintf(&buf[18], fmt, args);
        va_end(args);
        printk(buf);
-       sbp_sleep(55); /* else messages get lost */
+#if KLOGD_PAUSE
+       sbp_sleep(KLOGD_PAUSE); /* else messages get lost */
+#endif KLOGD_PAUSE
        return;
 }
 /*==========================================================================*/
@@ -1966,7 +1976,7 @@ static int cc_PlayAudio(int pos_audio_start,int pos_audio_end)
                else if (fam2_drive)
                {
                        drvcmd[0]=CMD2_PLAY_MSF;
-                       flags_cmd_out = f_putcmd | f_ResponseStatus;
+                       flags_cmd_out = f_putcmd | f_ResponseStatus | f_obey_p_check;
                }
                else if (famT_drive)
                {
@@ -3916,6 +3926,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                
        case CDROMPLAYMSF:
                msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
+#if SAFE_MIXED
+               if (D_S[d].has_data>1) return (-EBUSY);
+#endif SAFE_MIXED
                if (D_S[d].audio_state==audio_playing)
                {
                        i=cc_Pause_Resume(1);
@@ -3938,15 +3951,21 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
                    D_S[d].pos_audio_start,D_S[d].pos_audio_end);
                i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
-               msg(DBG_IOC,"ioctl: cc_PlayAudio returns %d\n",i);
-#if 0
-               if (i<0) return (-EIO);
-#endif 0
+               if (i<0)
+               {
+                       msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
+                       DriveReset();
+                       D_S[d].audio_state=0;
+                       return (-EIO);
+               }
                D_S[d].audio_state=audio_playing;
                return (0);
                
        case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
                msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
+#if SAFE_MIXED
+               if (D_S[d].has_data>1) return (-EBUSY);
+#endif SAFE_MIXED
                if (D_S[d].audio_state==audio_playing)
                {
                        msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
@@ -3969,9 +3988,13 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                D_S[d].pos_audio_start=D_S[d].TocBuffer[ti.cdti_trk0].address;
                D_S[d].pos_audio_end=D_S[d].TocBuffer[ti.cdti_trk1+1].address;
                i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
-#if 0
-               if (i<0) return (-EIO);
-#endif 0
+               if (i<0)
+               {
+                       msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
+                       DriveReset();
+                       D_S[d].audio_state=0;
+                       return (-EIO);
+               }
                D_S[d].audio_state=audio_playing;
                return (0);
                
@@ -4015,6 +4038,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                
        case CDROMSTOP:      /* Spin down the drive */
                msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
+#if SAFE_MIXED
+               if (D_S[d].has_data>1) return (-EBUSY);
+#endif SAFE_MIXED
                i=cc_Pause_Resume(1);
                D_S[d].audio_state=0;
                return (i);
@@ -4119,6 +4145,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                
        case CDROMREADMODE1:
                msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
+#if SAFE_MIXED
+               if (D_S[d].has_data>1) return (-EBUSY);
+#endif SAFE_MIXED
                cc_ModeSelect(CD_FRAMESIZE);
                cc_ModeSense();
                D_S[d].mode=READ_M1;
@@ -4126,6 +4155,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                
        case CDROMREADMODE2: /* not usable at the moment */
                msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
+#if SAFE_MIXED
+               if (D_S[d].has_data>1) return (-EBUSY);
+#endif SAFE_MIXED
                cc_ModeSelect(CD_FRAMESIZE_RAW1);
                cc_ModeSense();
                D_S[d].mode=READ_M2;
@@ -4165,6 +4197,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
                if (famL_drive) return (-EINVAL);
                if (famV_drive) return (-EINVAL);
                if (famT_drive) return (-EINVAL);
+#if SAFE_MIXED
+               if (D_S[d].has_data>1) return (-EBUSY);
+#endif SAFE_MIXED
                if (D_S[d].aud_buf==NULL) return (-EINVAL);
                i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
                if (i) return (i);
@@ -4488,6 +4523,9 @@ static void DO_SBPCD_REQUEST(void)
                sbp_sleep(0);
                if (sbp_data() != 0)
                {
+#if SAFE_MIXED
+                       D_S[d].has_data=2; /* is really a data disk */
+#endif SAFE_MIXED
                        end_request(1);
                        goto request_loop;
                }
@@ -4959,7 +4997,15 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
                i=DiskInfo();
                if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n");
                if ((D_S[d].ored_ctl_adr&0x40)==0)
+               {               
                        msg(DBG_INF,"CD contains no data tracks.\n");
+#if SAFE_MIXED
+                       D_S[d].has_data=0;
+#endif SAFE_MIXED
+               }
+#if SAFE_MIXED
+               else if (D_S[d].has_data<1) D_S[d].has_data=1;
+#endif SAFE_MIXED
        }
        if (!st_spinning) cc_SpinUp();
        return (0);
@@ -4979,11 +5025,6 @@ static void sbpcd_release(struct inode * ip, struct file * file)
                return;
        }
        switch_drive(i);
-       
-       D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;
-       sync_dev(ip->i_rdev);                   /* nonsense if read only device? */
-       invalidate_buffers(ip->i_rdev);
-       
        /*
         * try to keep an "open" counter here and unlock the door if 1->0.
         */
@@ -4994,11 +5035,17 @@ static void sbpcd_release(struct inode * ip, struct file * file)
        {
                if (--D_S[d].open_count<=0) 
                {
+                       D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;
+                       sync_dev(ip->i_rdev); /* nonsense if read only device? */
+                       invalidate_buffers(ip->i_rdev);
                        i=UnLockDoor();
                        if (D_S[d].audio_state!=audio_playing)
                                if (D_S[d].f_eject) cc_SpinDown();
                        D_S[d].diskstate_flags &= ~cd_size_bit;
                        D_S[d].open_count=0; 
+#if SAFE_MIXED
+                       D_S[d].has_data=0;
+#endif SAFE_MIXED
                }
        }
 }
@@ -5327,6 +5374,9 @@ int SBPCD_INIT(void)
        {
                if (D_S[j].drv_id==-1) continue;
                switch_drive(j);
+#if SAFE_MIXED
+               D_S[j].has_data=0;
+#endif SAFE_MIXED
                /*
                 * allocate memory for the frame buffers
                 */
index addeaa453c05fb59a196e15de875971a60db13e9..aebe369293595e6638f2ae5e68f8ad9219f74186 100644 (file)
@@ -1,3 +1,52 @@
+Wed Jun  5 18:52:04 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * tty_io.c (do_tty_hangup): 
+       * pty.c (pty_close): When closing a pty, make sure packet mode is
+               cleared.
+
+Sun May 26 09:33:52 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * vesa_blank.c (set_vesa_blanking): Add missing verify_area() call.
+
+       * selection.c (set_selection): Add missing verify_area() call.
+
+       * tty_io.c (tty_ioctl): Add missing verify_area() calls.
+
+       * serial.c (rs_ioctl): Add missing verify_area() calls.
+               (rs_init): Allow initialization of serial driver
+               configuration from a module.
+
+       * random.c (extract_entropy): Add missing verify_area call.
+               Don't limit number of characters returned to
+               32,768. Extract entropy is now no longer a inlined
+               function.
+
+               (random_read): Check return value in case extract_entropy
+               returns an error.
+
+               (secure_tcp_sequence_number): New function which returns a
+               secure TCP sequence number.  This is needed to prevent some
+               nasty TCP hijacking attacks.
+       
+               (init_std_data): Initialize using gettimeofday() instead of
+               struct timveal xtime.
+
+               (fast_add_entropy_word, add_entropy_word): Rename the
+               inline function add_entropy_word() to
+               fast_add_entropy_word().  Make add_entropy_word() be the
+               non-inlined function which is used in non-timing critical
+               places, in order to save space.
+
+               (initialize_benchmark, begin_benchmark, end_benchmark): New
+               functions defined when RANDOM_BENCHMARK is defined.  They
+               allow us to benchmark the speed of the
+               add_timer_randomness() call.
+
+               (int_ln, rotate_left): Add two new inline functions with
+               i386 optimized asm instructions.  This speeds up the
+               critical add_entropy_word() and add_timer_randomness()
+               functions, which are called from interrupt handlers.
+
 Tue May  7 22:51:11 1996    <tytso@rsts-11.mit.edu>
 
        * random.c (add_timer_randomness): Limit the amount randomness
@@ -15,7 +64,6 @@ Tue May  7 22:51:11 1996    <tytso@rsts-11.mit.edu>
                old ioctl values to be used for backwards compatibility
                (for a limited amount of time).
 
-
 Wed Apr 24 14:02:04 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
        * random.c (add_timer_randomness): Use 2nd derivative as well to
index 3ff878adfd38d971a9706db6951bf2e7dbad4460..d4bad619ea607a475765a5d8444310700af0ae78 100644 (file)
@@ -16,7 +16,7 @@ tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
 tristate 'Parallel printer support' CONFIG_PRINTER
 
 
-bool 'Bus Mouse Support' CONFIG_MOUSE
+bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
 if [ "$CONFIG_MOUSE" = "y" ]; then
        tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
        tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
index 534f0dd6ed65cc547d46e8e37dd23b89f8ebd30a..f604261ddc5e57305f314132812cd0457c755d6e 100644 (file)
  *                  Various resource allocation cleanups
  *   0.2  12.05.96  Changed major to allocated 51. Integrated into kernel
  *                  source tree
+ *   0.3  04.06.96  Major bug fixed (forgot to wake up after write) which
+ *                  interestingly manifested only with kernel ax25
+ *                  (the slip line discipline)
+ *                  introduced bottom half and tq_baycom
+ *                  HDLC processing now done with interrupts on
  */
 
 /*****************************************************************************/
@@ -89,7 +94,8 @@
 #include <linux/ioport.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
 #include <linux/baycom.h>
 
 /* --------------------------------------------------------------------- */
  * circuitry is usually slow.
  */
 
-#define BUFLEN_RX 16384
-#define BUFLEN_TX 16384
+#define BUFLEN_RX 8192
+#define BUFLEN_TX 8192
 
 #define NR_PORTS 4
 
 #define KISS_VERBOSE
-#undef HDLC_LOOPBACK
 
 #define BAYCOM_MAGIC 0x3105bac0
 
@@ -184,10 +189,11 @@ struct access_params {
 
 struct hdlc_state_rx {
        int rx_state;   /* 0 = sync hunt, != 0 receiving */
-       unsigned char lastbit;
        unsigned int bitstream;
-       unsigned int assembly;
-       
+       unsigned int bitbuf;
+       int numbits;
+       unsigned int shreg1, shreg2;
+
        int len;
        unsigned char *bp;
        unsigned char buffer[BAYCOM_MAXFLEN+2];    /* make room for CRC */
@@ -205,6 +211,10 @@ struct hdlc_state_tx {
        unsigned int current_byte;
        unsigned char ptt;
 
+       unsigned int bitbuf;
+       int numbits;
+       unsigned int shreg1, shreg2;
+
        int len;
        unsigned char *bp;
        unsigned char buffer[BAYCOM_MAXFLEN+2];         /* make room for CRC */
@@ -226,12 +236,13 @@ struct modem_state_par96 {
        unsigned int dcd_shreg;
        unsigned long descram;
        unsigned long scram;
-       unsigned int tx_bits;
+       unsigned char last_rxbit;
 };
 
 struct modem_state {
        unsigned char dcd;
        short arb_divider;
+       unsigned char flags;
        struct modem_state_ser12 ser12;
        struct modem_state_par96 par96;
 };
@@ -288,6 +299,10 @@ struct baycom_state {
        int opened;
        struct tty_struct *tty;
 
+#ifdef BAYCOM_USE_BH
+       struct tq_struct tq_receiver, tq_transmitter, tq_arbitrate;
+#endif /* BAYCOM_USE_BH */
+
        struct packet_buffer rx_buf;
        struct packet_buffer tx_buf;
 
@@ -316,6 +331,10 @@ struct baycom_state {
 
 struct baycom_state baycom_state[NR_PORTS];
 
+#ifdef BAYCOM_USE_BH
+DECLARE_TASK_QUEUE(tq_baycom);
+#endif /* BAYCOM_USE_BH */
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -520,16 +539,29 @@ static int store_kiss_packet(struct packet_buffer *buf, unsigned char *data,
 #ifdef BAYCOM_DEBUG
 static inline void add_bitbuffer(struct bit_buffer * buf, unsigned int bit)
 {
+       unsigned char new;
+
        if (!buf) return;
-       buf->shreg <<= 1;
+       new = buf->shreg & 1;
+       buf->shreg >>= 1;
        if (bit)
-               buf->shreg |= 1;
-       if (buf->shreg & 0x100) {
+               buf->shreg |= 0x80;
+       if (new) {
                buf->buffer[buf->wr] = buf->shreg;
                buf->wr = (buf->wr+1) % sizeof(buf->buffer);
-               buf->shreg = 1;
+               buf->shreg = 0x80;
        }
 }
+
+static inline void add_bitbuffer_word(struct bit_buffer * buf, 
+                                     unsigned int bits)
+{
+       buf->buffer[buf->wr] = bits & 0xff;
+       buf->wr = (buf->wr+1) % sizeof(buf->buffer);
+       buf->buffer[buf->wr] = (bits >> 8) & 0xff;
+       buf->wr = (buf->wr+1) % sizeof(buf->buffer);
+
+}
 #endif /* BAYCOM_DEBUG */
 
 /* ---------------------------------------------------------------------- */
@@ -553,67 +585,98 @@ static inline unsigned int tenms_to_flags(struct baycom_state *bc,
  * one bit per call
  */
 
-static void hdlc_rx_bit(struct baycom_state *bc, unsigned int bit)
+static inline int hdlc_rx_add_bytes(struct baycom_state *bc, 
+                                   unsigned int bits, int num)
 {
+       int added = 0;
+       while (bc->hdlc_rx.rx_state && num >= 8) {
+               if (bc->hdlc_rx.len >= sizeof(bc->hdlc_rx.buffer)) {
+                       bc->hdlc_rx.rx_state = 0;
+                       return 0;
+               }
+               *bc->hdlc_rx.bp++ = bits >> (32-num);
+               bc->hdlc_rx.len++;
+               num -= 8;
+               added += 8;
+       }
+       return added;
+}
+
+static inline void hdlc_rx_flag(struct baycom_state *bc)
+{
+       if (bc->hdlc_rx.len < 4) 
+               return;
+       if (!check_crc_ccitt(bc->hdlc_rx.buffer, bc->hdlc_rx.len)) 
+               return;
+               bc->stat.rx_packets++;
+       if (!store_kiss_packet(&bc->rx_buf,
+                              bc->hdlc_rx.buffer,
+                              bc->hdlc_rx.len-2))
+               bc->stat.rx_bufferoverrun++;
+}
+
+static void hdlc_rx_word(struct baycom_state *bc, unsigned int word)
+{
+       int i;
+       unsigned int mask1, mask2, mask3, mask4, mask5, mask6;
+       
        if (!bc) return;
 
-       bc->hdlc_rx.bitstream <<= 1;
-       if (bit)
-               bc->hdlc_rx.bitstream |= 1;
+       word &= 0xffff;
 #ifdef BAYCOM_DEBUG
-       add_bitbuffer(&bc->bitbuf_hdlc, bc->hdlc_rx.bitstream & 1);
+       add_bitbuffer_word(&bc->bitbuf_hdlc, word);
 #endif /* BAYCOM_DEBUG */
-       if(bc->hdlc_rx.rx_state) {
-               if ((bc->hdlc_rx.bitstream & 0x3f) != 0x3e) {
-                       /* not a stuffed bit */
-                       if (bc->hdlc_rx.bitstream & 1)
-                               bc->hdlc_rx.assembly |= 0x100;
-                       if (bc->hdlc_rx.assembly & 1) {
-                               /* store byte */
-                               if (bc->hdlc_rx.len >= sizeof(bc->hdlc_rx.buffer)) {
-                                       bc->hdlc_rx.rx_state = 0;
-                               } else {
-                                       *bc->hdlc_rx.bp++ = bc->hdlc_rx.assembly>>1;
-                                       bc->hdlc_rx.len++;
-                                       bc->hdlc_rx.assembly = 0x80;
-                               }
-                       } else {
-                               bc->hdlc_rx.assembly >>= 1;
-                       }
-               }
-               if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7e) {
-                       if (bc->hdlc_rx.len >= 4) {
-                               if (check_crc_ccitt(bc->hdlc_rx.buffer,bc->hdlc_rx.len)) {
-                                       bc->stat.rx_packets++;
-                                       if (!store_kiss_packet(&bc->rx_buf,bc->hdlc_rx.buffer,bc->hdlc_rx.len-2))
-                                               bc->stat.rx_bufferoverrun++;
-                               }
+               bc->hdlc_rx.bitstream >>= 16;
+       bc->hdlc_rx.bitstream |= word << 16;
+       bc->hdlc_rx.bitbuf >>= 16;
+       bc->hdlc_rx.bitbuf |= word << 16;
+       bc->hdlc_rx.numbits += 16;
+       for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00,
+           mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; 
+           i >= 0; 
+           i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, 
+           mask5 <<= 1, mask6 = (mask6 << 1) | 1) {
+               if ((bc->hdlc_rx.bitstream & mask1) == mask1)
+                       bc->hdlc_rx.rx_state = 0; /* abort received */
+               else if ((bc->hdlc_rx.bitstream & mask2) == mask3) {
+                       /* flag received */
+                       if (bc->hdlc_rx.rx_state) {
+                               hdlc_rx_add_bytes(bc, bc->hdlc_rx.bitbuf << 
+                                                 (8 + i), bc->hdlc_rx.numbits
+                                                 - 8 - i);
+                               hdlc_rx_flag(bc);
                        }
                        bc->hdlc_rx.len = 0;
                        bc->hdlc_rx.bp = bc->hdlc_rx.buffer;
-                       bc->hdlc_rx.assembly = 0x80;
-               }
-               if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7f)
-                       bc->hdlc_rx.rx_state = 0;
-       } else {
-               if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7e) {
-                       bc->hdlc_rx.len = 0;
-                       bc->hdlc_rx.bp = bc->hdlc_rx.buffer;
-                       bc->hdlc_rx.assembly = 0x80;
                        bc->hdlc_rx.rx_state = 1;
+                       bc->hdlc_rx.numbits = i;
+               } else if ((bc->hdlc_rx.bitstream & mask4) == mask5) {
+                       /* stuffed bit */
+                       bc->hdlc_rx.numbits--;
+                       bc->hdlc_rx.bitbuf = (bc->hdlc_rx.bitbuf & (~mask6)) |
+                               ((bc->hdlc_rx.bitbuf & mask6) << 1);
                }
        }
+       bc->hdlc_rx.numbits -= hdlc_rx_add_bytes(bc, bc->hdlc_rx.bitbuf,
+                                                bc->hdlc_rx.numbits);
 }
 
 /* ---------------------------------------------------------------------- */
 
-static unsigned char hdlc_tx_bit(struct baycom_state *bc)
+static unsigned int hdlc_tx_word(struct baycom_state *bc)
 {
-       unsigned char bit;
+       unsigned int mask1, mask2, mask3;
+       int i;
 
        if (!bc || !bc->hdlc_tx.ptt)
                return 0;
-       for(;;) {
+       for (;;) {
+               if (bc->hdlc_tx.numbits >= 16) {
+                       unsigned int ret = bc->hdlc_tx.bitbuf & 0xffff;
+                       bc->hdlc_tx.bitbuf >>= 16;
+                       bc->hdlc_tx.numbits -= 16;
+                       return ret;
+               }
                switch (bc->hdlc_tx.tx_state) {
                default:
                        bc->hdlc_tx.ptt = 0;
@@ -621,80 +684,68 @@ static unsigned char hdlc_tx_bit(struct baycom_state *bc)
                        return 0;
                case 0:
                case 1:
-                       if (bc->hdlc_tx.current_byte > 1) {
-                               /*
-                                * return bit 
-                                */
-                               bit = bc->hdlc_tx.current_byte & 1;
-                               bc->hdlc_tx.current_byte >>= 1;
-                               return bit;
-                       }
-                       /*
-                        * get new bit 
-                        */
                        if (bc->hdlc_tx.numflags) {
                                bc->hdlc_tx.numflags--;
-                               bc->hdlc_tx.current_byte = 0x17e;
-                       } else {
-                               if (bc->hdlc_tx.tx_state == 1) {
-                                       bc->hdlc_tx.ptt = 0;
-                                       return 0;
-                               }
-                               get_packet(&bc->tx_buf, &bc->hdlc_tx.bp,
-                                          &bc->hdlc_tx.len);
-                               if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) {
-                                       bc->hdlc_tx.tx_state = 1;
-                                       bc->hdlc_tx.current_byte = 0;
-                                       bc->hdlc_tx.numflags = tenms_to_flags
-                                               (bc, bc->ch_params.tx_tail);
-                               } else if (bc->hdlc_tx.len >= BAYCOM_MAXFLEN) {
-                                       bc->hdlc_tx.tx_state = 0;
-                                       bc->hdlc_tx.current_byte = 0;
-                                       bc->hdlc_tx.numflags = 1;
-                                       ack_packet(&bc->tx_buf);
-                               } else {
-                                       memcpy(bc->hdlc_tx.buffer,
-                                              bc->hdlc_tx.bp, 
-                                              bc->hdlc_tx.len);
-                                       ack_packet(&bc->tx_buf);
-                                       bc->hdlc_tx.bp = bc->hdlc_tx.buffer;
-                                       append_crc_ccitt(bc->hdlc_tx.buffer,
-                                                        bc->hdlc_tx.len);
-                                       /* the appended CRC */
-                                       bc->hdlc_tx.len += 2; 
-                                       bc->hdlc_tx.tx_state = 2;
-                                       bc->hdlc_tx.current_byte = 0;
-                                       bc->hdlc_tx.bitstream = 0;
-                                       bc->stat.tx_packets++;
-                               }
+                               bc->hdlc_tx.bitbuf |= 
+                                       0x7e7e << bc->hdlc_tx.numbits;
+                               bc->hdlc_tx.numbits += 16;
+                               break;
                        }
-                       break;
-               case 2:
-                       if ((bc->hdlc_tx.bitstream & 0x1f) == 0x1f) {
-                               /*
-                                * bit stuffing
-                                */
-                               bc->hdlc_tx.bitstream <<= 1;
+                       if (bc->hdlc_tx.tx_state == 1) {
+                               bc->hdlc_tx.ptt = 0;
                                return 0;
                        }
-                       if (bc->hdlc_tx.current_byte > 1) {
-                               /*
-                                * return bit 
-                                */
-                               bc->hdlc_tx.bitstream <<= 1;
-                               bit = bc->hdlc_tx.current_byte & 1;
-                               bc->hdlc_tx.bitstream |= bit;
-                               bc->hdlc_tx.current_byte >>= 1;
-                               return bit;
+                       get_packet(&bc->tx_buf, &bc->hdlc_tx.bp,
+                                  &bc->hdlc_tx.len);
+                       if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) {
+                               bc->hdlc_tx.tx_state = 1;
+                               bc->hdlc_tx.numflags = tenms_to_flags
+                                       (bc, bc->ch_params.tx_tail);
+                               break;
+                       }
+                       if (bc->hdlc_tx.len >= BAYCOM_MAXFLEN) {
+                               bc->hdlc_tx.tx_state = 0;
+                               bc->hdlc_tx.numflags = 1;
+                               ack_packet(&bc->tx_buf);
+                               break;
                        }
+                       memcpy(bc->hdlc_tx.buffer, bc->hdlc_tx.bp, 
+                              bc->hdlc_tx.len);
+                       ack_packet(&bc->tx_buf);
+                       bc->hdlc_tx.bp = bc->hdlc_tx.buffer;
+                       append_crc_ccitt(bc->hdlc_tx.buffer, bc->hdlc_tx.len);
+                       /* the appended CRC */
+                       bc->hdlc_tx.len += 2; 
+                       bc->hdlc_tx.tx_state = 2;
+                       bc->hdlc_tx.bitstream = 0;
+                       bc->stat.tx_packets++;
+                       break;
+               case 2:
                        if (!bc->hdlc_tx.len) {
                                bc->hdlc_tx.tx_state = 0;
-                               bc->hdlc_tx.current_byte = 0;
                                bc->hdlc_tx.numflags = 1;
-                       } else {
-                               bc->hdlc_tx.len--;
-                               bc->hdlc_tx.current_byte = 0x100 | 
-                                       (*bc->hdlc_tx.bp++);
+                               break;
+                       }
+                       bc->hdlc_tx.len--;
+                       bc->hdlc_tx.bitbuf |= *bc->hdlc_tx.bp <<
+                               bc->hdlc_tx.numbits;
+                       bc->hdlc_tx.bitstream >>= 8;
+                       bc->hdlc_tx.bitstream |= (*bc->hdlc_tx.bp++) << 16;
+                       mask1 = 0x1f000;
+                       mask2 = 0x10000;
+                       mask3 = 0xffffffff >> (31-bc->hdlc_tx.numbits);
+                       bc->hdlc_tx.numbits += 8;
+                       for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, 
+                           mask3 = (mask3 << 1) | 1) {
+                               if ((bc->hdlc_tx.bitstream & mask1) != mask1) 
+                                       continue;
+                               bc->hdlc_tx.bitstream &= ~mask2;
+                               bc->hdlc_tx.bitbuf = 
+                                       (bc->hdlc_tx.bitbuf & mask3) |
+                                               ((bc->hdlc_tx.bitbuf & 
+                                                (~mask3)) << 1);
+                               bc->hdlc_tx.numbits++;
+                               mask3 = (mask3 << 1) | 1;
                        }
                        break;
                }
@@ -720,7 +771,7 @@ static inline void tx_arbitrate(struct baycom_state *bc)
        
        if (!bc || bc->hdlc_tx.ptt || bc->modem.dcd)
                return;
-       get_packet(&bc->tx_buf,&bp,&len);
+       get_packet(&bc->tx_buf, &bp, &len);
        if (!bp || !len)
                return;
        
@@ -845,18 +896,34 @@ static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                 * since this may take quite long
                 */
                outb(0x0e | (bc->modem.ser12.tx_bit ? 1 : 0), MCR(bc->iobase));
-               if (bc->calibrate > 0) {
-                       bc->modem.ser12.tx_bit = !bc->modem.ser12.tx_bit;
-                       bc->calibrate--;
-                       return;
-               }
+               if (bc->hdlc_tx.shreg1 <= 1) {
+                       if (bc->calibrate > 0) {
+                               bc->hdlc_tx.shreg1 = 0x10000;
+                               bc->calibrate--;
+                       } else {
+#ifdef BAYCOM_USE_BH
+                               bc->hdlc_tx.shreg1 = bc->hdlc_tx.shreg2;
+                               bc->hdlc_tx.shreg2 = 0;
+                               queue_task_irq_off(&bc->tq_transmitter, 
+                                                  &tq_baycom);
+                               mark_bh(BAYCOM_BH);
 #ifdef HDLC_LOOPBACK
-               hdlc_rx_bit(bc, bc->modem.ser12.tx_bit == 
-                           bc->modem.ser12.last_rxbit);
-               bc->modem.ser12.last_rxbit = bc->modem.ser12.tx_bit;
+                               bc->hdlc_rx.shreg2 = bc->hdlc_tx.shreg1;
+                               queue_task_irq_off(&bc->tq_receiver, 
+                                                  &tq_baycom);
 #endif /* HDLC_LOOPBACK */
-               if (!hdlc_tx_bit(bc))
+#else /* BAYCOM_USE_BH */
+                               bc->hdlc_tx.shreg1 = hdlc_tx_word(bc) 
+                                       | 0x10000;
+#ifdef HDLC_LOOPBACK
+                               hdlc_rx_word(bc, bc->hdlc_tx.shreg1);
+#endif /* HDLC_LOOPBACK */
+#endif /* BAYCOM_USE_BH */
+                       }       
+               }
+               if (!(bc->hdlc_tx.shreg1 & 1))
                        bc->modem.ser12.tx_bit = !bc->modem.ser12.tx_bit;
+               bc->hdlc_tx.shreg1 >>= 1;
                return;
        }
        /*
@@ -928,8 +995,10 @@ static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                ser12_set_divisor(bc, 4);
                                break;
                        }
-                       hdlc_rx_bit(bc, bc->modem.ser12.last_sample == 
-                           bc->modem.ser12.last_rxbit);
+                       bc->hdlc_rx.shreg1 >>= 1;
+                       if (bc->modem.ser12.last_sample == 
+                           bc->modem.ser12.last_rxbit)
+                               bc->hdlc_rx.shreg1 |= 0x10000;
                        bc->modem.ser12.last_rxbit = 
                                bc->modem.ser12.last_sample;
                }
@@ -965,15 +1034,32 @@ static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                ser12_set_divisor(bc, 6);
                                break;
                        }
-                       hdlc_rx_bit(bc, bc->modem.ser12.last_sample == 
-                           bc->modem.ser12.last_rxbit);
+                       bc->hdlc_rx.shreg1 >>= 1;
+                       if (bc->modem.ser12.last_sample == 
+                           bc->modem.ser12.last_rxbit)
+                               bc->hdlc_rx.shreg1 |= 0x10000;
                        bc->modem.ser12.last_rxbit = 
                                bc->modem.ser12.last_sample;
                }
                bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
        }
+       if (bc->hdlc_rx.shreg1 & 1) {
+#ifdef BAYCOM_USE_BH
+               bc->hdlc_rx.shreg2 = (bc->hdlc_rx.shreg1 >> 1) | 0x10000;
+               queue_task_irq_off(&bc->tq_receiver, &tq_baycom);
+               mark_bh(BAYCOM_BH);
+#else /* BAYCOM_USE_BH */
+               hdlc_rx_word(bc, bc->hdlc_rx.shreg1 >> 1);
+#endif /* BAYCOM_USE_BH */
+               bc->hdlc_rx.shreg1 = 0x10000;
+       }
        if (--bc->modem.arb_divider <= 0) {
+#ifdef BAYCOM_USE_BH
+               queue_task_irq_off(&bc->tq_arbitrate, &tq_baycom);
+               mark_bh(BAYCOM_BH);
+#else /* BAYCOM_USE_BH */
                tx_arbitrate(bc);
+#endif /* BAYCOM_USE_BH */
                bc->modem.arb_divider = bc->ch_params.slottime * 
                        SER12_ARB_DIVIDER(bc);
        }
@@ -1126,7 +1212,7 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        register struct baycom_state *bc = (struct baycom_state *)dev_id;
        int i;
-       unsigned int data, mask, mask2;
+       unsigned int data, rawdata, mask, mask2;
        
        if (!bc || bc->magic != BAYCOM_MAGIC)
                return;
@@ -1144,12 +1230,12 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                 * transmitter, since this may take quite long
                 * do the differential encoder and the scrambler on the fly
                 */
-               data = bc->modem.par96.tx_bits;
-               for(i = 0; i < PAR96_BURSTBITS; i++, data <<= 1) {
+               data = bc->hdlc_tx.shreg1;
+               for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) {
                        unsigned char val = PAR97_POWER;
                        bc->modem.par96.scram = ((bc->modem.par96.scram << 1) |
                                                 (bc->modem.par96.scram & 1));
-                       if (!(data & 0x8000))
+                       if (!(data & 1))
                                bc->modem.par96.scram ^= 1;
                        if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1))
                                bc->modem.par96.scram ^= 
@@ -1160,26 +1246,31 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        outb(val | PAR96_BURST, LPT_DATA(bc->iobase));
                }
                if (bc->calibrate > 0) {
-                       bc->modem.par96.tx_bits = 0;
+                       bc->hdlc_tx.shreg1 = 0x10000;
                        bc->calibrate--;
-                       return;
-               }
+               } else {
+#ifdef BAYCOM_USE_BH
+                       bc->hdlc_tx.shreg1 = bc->hdlc_tx.shreg2;
+                       bc->hdlc_tx.shreg2 = 0;
+                       queue_task_irq_off(&bc->tq_transmitter, &tq_baycom);
+                       mark_bh(BAYCOM_BH);
 #ifdef HDLC_LOOPBACK
-               for(mask = 0x8000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1)
-                       hdlc_rx_bit(bc, bc->modem.par96.tx_bits & mask);
+                       bc->hdlc_rx.shreg2 = bc->hdlc_tx.shreg1;
+                       queue_task_irq_off(&bc->tq_receiver, &tq_baycom);
 #endif /* HDLC_LOOPBACK */
-               bc->modem.par96.tx_bits = 0;
-               for(i = 0; i < PAR96_BURSTBITS; i++) {
-                       bc->modem.par96.tx_bits <<= 1;
-                       if (hdlc_tx_bit(bc))
-                               bc->modem.par96.tx_bits |= 1;
+#else /* BAYCOM_USE_BH */
+                       bc->hdlc_tx.shreg1 = hdlc_tx_word(bc);
+#ifdef HDLC_LOOPBACK
+                       hdlc_rx_word(bc, bc->hdlc_tx.shreg1);
+#endif /* HDLC_LOOPBACK */
+#endif /* BAYCOM_USE_BH */
                }
                return;
        }
        /*
         * do receiver; differential decode and descramble on the fly
         */
-       for(data = i = 0; i < PAR96_BURSTBITS; i++) {
+       for(rawdata = data = i = 0; i < PAR96_BURSTBITS; i++) {
                unsigned int descx;
                bc->modem.par96.descram = (bc->modem.par96.descram << 1);
                if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT)
@@ -1190,19 +1281,31 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                outb(PAR97_POWER | PAR96_PTT, LPT_DATA(bc->iobase));
                descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^
                          (descx >> PAR96_DESCRAM_TAPSH2));
-               data <<= 1;
-               data |= !(descx & 1);
+               if (descx & 1)
+                       bc->modem.par96.last_rxbit = 
+                               !bc->modem.par96.last_rxbit;
+               data >>= 1;
+               if (bc->modem.par96.last_rxbit)
+                       data |= 0x8000;
+               rawdata <<= 1;
+               rawdata |= !(descx & 1);
                outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, 
                     LPT_DATA(bc->iobase));
        }
-       for(mask = 0x8000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1)
-               hdlc_rx_bit(bc, data & mask);
+#ifdef BAYCOM_USE_BH
+       bc->hdlc_rx.shreg2 = bc->hdlc_rx.shreg1;
+       bc->hdlc_rx.shreg1 = data | 0x10000;
+       queue_task_irq_off(&bc->tq_receiver, &tq_baycom);
+       mark_bh(BAYCOM_BH);
+#else /* BAYCOM_USE_BH */
+       hdlc_rx_word(bc, data);
+#endif /* BAYCOM_USE_BH */
        /*
         * do DCD algorithm
         */
        if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
                bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg << 16)
-                       | data;
+                       | rawdata;
                /* search for flags and set the dcd counter appropriately */
                for(mask = 0x7f8000, mask2 = 0x3f0000, i = 0; 
                    i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1)
@@ -1223,7 +1326,12 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase)) & PAR96_DCD);
        }
        if (--bc->modem.arb_divider <= 0) {
+#ifdef BAYCOM_USE_BH
+               queue_task_irq_off(&bc->tq_arbitrate, &tq_baycom);
+               mark_bh(BAYCOM_BH);
+#else /* BAYCOM_USE_BH */
                tx_arbitrate(bc);
+#endif /* BAYCOM_USE_BH */
                bc->modem.arb_divider = bc->ch_params.slottime * 6;
        }
 }
@@ -1318,6 +1426,58 @@ static void par96_on_close(struct baycom_state *bc)
        free_irq(bc->irq, bc);  
 }
 
+/* --------------------------------------------------------------------- */
+/*
+ * ===================== Bottom half (soft interrupt) ====================
+ */
+
+#ifdef BAYCOM_USE_BH
+static void bh_receiver(void *private)
+{
+       struct baycom_state *bc = (struct baycom_state *)private;
+       unsigned int temp;
+
+       if (!bc || bc->magic != BAYCOM_MAGIC)
+               return;
+       if (!bc->hdlc_rx.shreg2)
+               return;
+       temp = bc->hdlc_rx.shreg2;
+       bc->hdlc_rx.shreg2 = 0;
+       hdlc_rx_word(bc, temp);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void bh_transmitter(void *private)
+{
+       struct baycom_state *bc = (struct baycom_state *)private;
+
+       if (!bc || bc->magic != BAYCOM_MAGIC)
+               return;
+       if (bc->hdlc_tx.shreg2)
+               return;
+       bc->hdlc_tx.shreg2 = hdlc_tx_word(bc) | 0x10000;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void bh_arbitrate(void *private)
+{
+       struct baycom_state *bc = (struct baycom_state *)private;
+
+       if (!bc || bc->magic != BAYCOM_MAGIC)
+               return;
+       tx_arbitrate(bc);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void baycom_bottom_half(void)
+{
+       run_task_queue(&tq_baycom);
+}
+#endif /* BAYCOM_USE_BH */
+
 /* --------------------------------------------------------------------- */
 /*
  * ===================== TTY interface routines ==========================
@@ -1369,7 +1529,7 @@ static void baycom_put_fend(struct baycom_state *bc)
                        break;
                bc->ch_params.ppersist = bc->kiss_decode.pkt_buf[1];
 #ifdef KISS_VERBOSE
-               printk("KERN_INFO baycom: p-persistence = %u\n", 
+               printk(KERN_INFO "baycom: p-persistence = %u\n", 
                       bc->ch_params.ppersist);
 #endif /* KISS_VERBOSE */
                break;
@@ -1379,7 +1539,7 @@ static void baycom_put_fend(struct baycom_state *bc)
                        break;
                bc->ch_params.slottime = bc->kiss_decode.pkt_buf[1];
 #ifdef KISS_VERBOSE
-               printk("baycom: slottime = %ums\n", 
+               printk(KERN_INFO "baycom: slottime = %ums\n", 
                       bc->ch_params.slottime * 10);
 #endif /* KISS_VERBOSE */
                break;
@@ -1477,6 +1637,10 @@ static int baycom_write(struct tty_struct * tty, int from_user,
                for(c = count, bp = buf; c > 0; c--,bp++)
                        baycom_put_char(tty, *bp);
        }
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+               tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+       wake_up_interruptible(&tty->write_wait);
        return count;
 }
 
@@ -1513,10 +1677,10 @@ static int baycom_chars_in_buffer(struct tty_struct *tty)
                return 0;
        if (baycom_paranoia_check(bc = tty->driver_data, "chars_in_buffer"))
                return 0;
-               
-       cnt = bc->rx_buf.wr - bc->rx_buf.rd;
+
+       cnt = bc->tx_buf.wr - bc->tx_buf.rd;
        if (cnt < 0)
-               cnt += bc->rx_buf.buflen;
+               cnt += bc->tx_buf.buflen;
                
        return cnt;
 }
@@ -1669,7 +1833,7 @@ static int baycom_ioctl(struct tty_struct *tty, struct file * file,
                
        case BAYCOMCTL_CALIBRATE:
                bc->calibrate = arg * ((bc->modem_type == BAYCOM_MODEM_PAR96) ?
-                                      600 : 1200);
+                                      600 : 75);
                return 0;
 
        case BAYCOMCTL_GETPARAMS:
@@ -1917,16 +2081,28 @@ static void init_channel(struct baycom_state *bc)
 
 #ifdef BAYCOM_DEBUG
        bc->bitbuf_channel.rd = bc->bitbuf_channel.wr = 0;
-       bc->bitbuf_channel.shreg = 1;
+       bc->bitbuf_channel.shreg = 0x80;
 
        bc->bitbuf_hdlc.rd = bc->bitbuf_hdlc.wr = 0;
-       bc->bitbuf_hdlc.shreg = 1;
+       bc->bitbuf_hdlc.shreg = 0x80;
 #endif /* BAYCOM_DEBUG */
 
        bc->kiss_decode.dec_state = bc->kiss_decode.escaped = 
        bc->kiss_decode.wr = 0;
 
        bc->ch_params = dflt_ch_params;
+
+#ifdef BAYCOM_USE_BH
+       bc->tq_receiver.next = bc->tq_transmitter.next =
+               bc->tq_arbitrate.next = NULL;
+       bc->tq_receiver.sync = bc->tq_transmitter.sync =
+               bc->tq_arbitrate.sync = 0;
+       bc->tq_receiver.data = bc->tq_transmitter.data =
+               bc->tq_arbitrate.data = bc;
+       bc->tq_receiver.routine = bh_receiver;
+       bc->tq_transmitter.routine = bh_transmitter;
+       bc->tq_arbitrate.routine = bh_arbitrate;
+#endif /* BAYCOM_USE_BH */
 }
 
 static void init_datastructs(void)
@@ -1962,6 +2138,12 @@ int baycom_init(void) {
         * initialize the data structures
         */
        init_datastructs();
+       /*
+        * initialize bottom half handler
+        */
+#ifdef BAYCOM_USE_BH
+       init_bh(BAYCOM_BH, baycom_bottom_half);
+#endif /* BAYCOM_USE_BH */
        /*
         * register the driver as tty driver
         */
@@ -2080,7 +2262,7 @@ int init_module(void)
        if (i)
                return i;
 
-       printk(KERN_INFO "baycom: version 0.2; "
+       printk(KERN_INFO "baycom: version 0.3; "
               "(C) 1996 by Thomas Sailer HB9JNX, sailer@ife.ee.ethz.ch\n");
 
        return 0;
@@ -2092,10 +2274,6 @@ void cleanup_module(void)
 {
        int i;
 
-#if 0
-       if (MOD_IN_USE)
-               printk(KERN_INFO "baycom: device busy, remove delayed\n");
-#endif
        printk(KERN_INFO "baycom: cleanup_module called\n");
 
        if (tty_unregister_driver(&baycom_driver))
index b004a33652a983b3b31ed8f9ddcaaa4eea24d613..5d464d966d39df71d0f5436f946b6eb8f93e23ba 100644 (file)
@@ -74,8 +74,10 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
        }
        wake_up_interruptible(&tty->read_wait);
        wake_up_interruptible(&tty->write_wait);
+       tty->packet = 0;
        if (!tty->link)
                return;
+       tty->link->packet = 0;
        wake_up_interruptible(&tty->link->read_wait);
        wake_up_interruptible(&tty->link->write_wait);
        set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
index 7bc96506b0001c3951abb40c0cb122d9970f2e2d..0b189bbd2e7ae7317d590f84391fdd65244b560a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * random.c -- A strong random number generator
  *
- * Version 0.98, last modified 7-May-96
+ * Version 1.00, last modified 26-May-96
  * 
  * Copyright Theodore Ts'o, 1994, 1995, 1996.  All rights reserved.
  *
  * Eastlake, Steve Crocker, and Jeff Schiller.
  */
 
-#include <linux/sched.h>
 #include <linux/utsname.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 /*
  * Configuration information
  */
+#undef RANDOM_BENCHMARK
+#undef BENCHMARK_NOINT
 
 /*
  * The pool is stirred with a primitive polynomial of degree 128
@@ -288,6 +289,29 @@ struct random_bucket {
        __u32 *pool;
 };
 
+#ifdef RANDOM_BENCHMARK
+/* For benchmarking only */
+struct random_benchmark {
+       unsigned long long      start_time;
+       int                     times;          /* # of samples */
+       unsigned long           min;
+       unsigned long           max;
+       unsigned long           accum;          /* accumulator for average */
+       const char              *descr;
+       int                     unit;
+       unsigned long           flags;
+};
+
+#define BENCHMARK_INTERVAL 500
+
+static void initialize_benchmark(struct random_benchmark *bench,
+                                const char *descr, int unit);
+static void begin_benchmark(struct random_benchmark *bench);
+static void end_benchmark(struct random_benchmark *bench);
+
+struct random_benchmark timer_benchmark;
+#endif
+
 /* There is one of these per entropy source */
 struct timer_rand_state {
        unsigned long   last_time;
@@ -315,12 +339,73 @@ static int random_write(struct inode * inode, struct file * file,
 static int random_ioctl(struct inode * inode, struct file * file,
                        unsigned int cmd, unsigned long arg);
 
-static inline void add_entropy_word(struct random_bucket *r,
+static inline void fast_add_entropy_word(struct random_bucket *r,
+                                        const __u32 input);
+
+static void add_entropy_word(struct random_bucket *r,
                                    const __u32 input);
 
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
+
+/*
+ * Unfortunately, while the GCC optimizer for the i386 understands how
+ * to opimize a static rotate left of x bits, it doesn't know how to
+ * deal with a variable rotate of x bits.  So we use a bit of asm magic.
+ */
+#if (!defined (__i386__))
+extern inline __u32 rotate_left(int i, __u32 word)
+{
+       __u32 nbits = 0;
+       
+       return (word << i) | (word >> (32 - i));
+       
+}
+#else
+extern inline __u32 rotate_left(int i, __u32 word)
+{
+       __asm__("roll %%cl,%0"
+               :"=r" (word)
+               :"0" (word),"c" (i));
+       return word;
+}
+#endif
+
+/*
+ * More asm magic....
+ * 
+ * For entropy estimation, we need to do an integral base 2
+ * logarithm.  By default, use an open-coded C version, although we do
+ * have a version which takes advantage of the Intel's x86's "bsr"
+ * instruction.
+ */
+#if (!defined (__i386__))
+static inline __u32 int_ln(__u32 word)
+{
+       __u32 nbits = 0;
+       
+       while (1) {
+               word >>= 1;
+               if (!word)
+                       break;
+               nbits++;
+       }
+       return nbits;
+}
+#else
+static inline __u32 int_ln(__u32 word)
+{
+       __asm__("bsrl %1,%0\n\t"
+               "jnz 1f\n\t"
+               "movl $0,%0\n"
+               "1:"
+               :"=r" (word)
+               :"r" (word));
+       return word;
+}
+#endif
+
        
 /*
  * Initialize the random pool with standard stuff.
@@ -331,9 +416,11 @@ static void init_std_data(struct random_bucket *r)
 {
        __u32 word, *p;
        int i;
-       
-       add_entropy_word(r, xtime.tv_sec);
-       add_entropy_word(r, xtime.tv_usec);
+       struct timeval  tv;
+
+       do_gettimeofday(&tv);
+       add_entropy_word(r, tv.tv_sec);
+       add_entropy_word(r, tv.tv_usec);
 
        for (p = (__u32 *) &system_utsname,
             i = sizeof(system_utsname) / sizeof(__u32);
@@ -364,6 +451,12 @@ void rand_initialize(void)
                irq_timer_state[i] = NULL;
        for (i = 0; i < MAX_BLKDEV; i++)
                blkdev_timer_state[i] = NULL;
+       memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state));
+       memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state));
+       memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));
+#ifdef RANDOM_BENCHMARK
+       initialize_benchmark(&timer_benchmark, "timer", 0);
+#endif
        extract_timer_state.dont_count_entropy = 1;
        random_wait = NULL;
 }
@@ -418,23 +511,25 @@ void rand_initialize_blkdev(int major, int mode)
  * scancodes, for example), the upper bits of the entropy pool don't
  * get affected. --- TYT, 10/11/95
  */
-static inline void add_entropy_word(struct random_bucket *r,
-                                   const __u32 input)
+static inline void fast_add_entropy_word(struct random_bucket *r,
+                                        const __u32 input)
 {
        unsigned i;
+       int new_rotate;
        __u32 w;
 
-       w = (input << r->input_rotate) | (input >> (32 - r->input_rotate));
+       w = rotate_left(r->input_rotate, input);
        i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1);
+       /*
+        * Normally, we add 7 bits of rotation to the pool.  At the
+        * beginning of the pool, add an extra 7 bits rotation, so
+        * that successive passes spread the input bits across the
+        * pool evenly.
+        */
+       new_rotate = r->input_rotate + 14;
        if (i)
-               r->input_rotate = (r->input_rotate + 7) & 31;
-       else
-               /*
-                * At the beginning of the pool, add an extra 7 bits
-                * rotation, so that successive passes spread the
-                * input bits across the pool evenly.
-                */
-               r->input_rotate = (r->input_rotate + 14) & 31;
+               new_rotate = r->input_rotate + 7;
+       r->input_rotate = new_rotate & 31;
 
        /* XOR in the various taps */
        w ^= r->pool[(i+TAP1)&(POOLWORDS-1)];
@@ -447,6 +542,15 @@ static inline void add_entropy_word(struct random_bucket *r,
        r->pool[i] = (w << 1) | (w >> 31);
 }
 
+/*
+ * For places where we don't need the inlined version
+ */
+static void add_entropy_word(struct random_bucket *r,
+                                   const __u32 input)
+{
+       fast_add_entropy_word(r, input);
+}
+
 /*
  * This function adds entropy to the entropy "pool" by using timing
  * delays.  It uses the timer_rand_state structure to make an estimate
@@ -463,9 +567,11 @@ static void add_timer_randomness(struct random_bucket *r,
                                 struct timer_rand_state *state, unsigned num)
 {
        int     delta, delta2, delta3;
-       unsigned        nbits;
        __u32           time;
 
+#ifdef RANDOM_BENCHMARK
+       begin_benchmark(&timer_benchmark);
+#endif
 #if defined (__i386__)
        if (x86_capability & 16) {
                unsigned long low, high;
@@ -480,15 +586,16 @@ static void add_timer_randomness(struct random_bucket *r,
        time = jiffies;
 #endif
 
-       add_entropy_word(r, (__u32) num);
-       add_entropy_word(r, time);
-
+       fast_add_entropy_word(r, (__u32) num);
+       fast_add_entropy_word(r, time);
+       
        /*
         * Calculate number of bits of randomness we probably
         * added.  We take into account the first and second order
         * deltas in order to make our estimate.
         */
-       if (!state->dont_count_entropy) {
+       if (!state->dont_count_entropy &&
+           (r->entropy_count < POOLBITS)) {
                delta = time - state->last_time;
                state->last_time = time;
                if (delta < 0) delta = -delta;
@@ -502,17 +609,10 @@ static void add_timer_randomness(struct random_bucket *r,
                if (delta3 < 0) delta3 = -delta3;
 
                delta = MIN(MIN(delta, delta2), delta3) >> 1;
-               for (nbits = 0; delta; nbits++)
-                       delta >>= 1;
-
-               /*
-                * In no case do we assume we've added more than 12
-                * bits of randomness.
-                */
-               if (nbits > 12)
-                       nbits = 12;
+               /* Limit entropy estimate to 12 bits */
+               delta &= (1 << 12) - 1;
 
-               r->entropy_count += nbits;
+               r->entropy_count += int_ln(delta);
 
                /* Prevent overflow */
                if (r->entropy_count > POOLBITS)
@@ -521,7 +621,10 @@ static void add_timer_randomness(struct random_bucket *r,
                
        /* Wake up waiting processes, if we have enough entropy. */
        if (r->entropy_count >= WAIT_INPUT_BITS)
-               wake_up_interruptible(&random_wait);    
+               wake_up_interruptible(&random_wait);
+#ifdef RANDOM_BENCHMARK
+       end_benchmark(&timer_benchmark);
+#endif
 }
 
 void add_keyboard_randomness(unsigned char scancode)
@@ -830,21 +933,24 @@ static void MD5Transform(__u32 buf[4],
  * bits of entropy are left in the pool, but it does not restrict the
  * number of bytes that are actually obtained.
  */
-static inline int extract_entropy(struct random_bucket *r, char * buf,
+static int extract_entropy(struct random_bucket *r, char * buf,
                                  int nbytes, int to_user)
 {
        int ret, i;
        __u32 tmp[HASH_BUFFER_SIZE];
        char *cp,*dp;
+
+       if (to_user) {
+               ret = verify_area(VERIFY_WRITE, (void *) buf, nbytes);
+               if (ret)
+                       return(ret);
+       }
        
        add_timer_randomness(r, &extract_timer_state, nbytes);
        
        /* Redundant, but just in case... */
        if (r->entropy_count > POOLBITS) 
                r->entropy_count = POOLBITS;
-       /* Why is this here?  Left in from Ted Ts'o.  Perhaps to limit time. */
-       if (nbytes > 32768)
-               nbytes = 32768;
 
        ret = nbytes;
        if (r->entropy_count / 8 >= nbytes)
@@ -947,6 +1053,11 @@ random_read(struct inode * inode, struct file * file, char * buf, int nbytes)
                        continue;
                }
                n = extract_entropy(&random_state, buf, n, 1);
+               if (n < 0) {
+                       if (count == 0)
+                               retval = n;
+                       break;
+               }
                count += n;
                buf += n;
                nbytes -= n;
@@ -1182,3 +1293,120 @@ struct file_operations urandom_fops = {
        NULL            /* no special release code */
 };
 
+/*
+ * TCP initial sequence number picking.  This uses the random number
+ * generator to pick an initial secret value.  This value is hashed
+ * along with the TCP endpoint information to provide a unique
+ * starting point for each pair of TCP endpoints.  This defeats
+ * attacks which rely on guessing the initial TCP sequence number.
+ * This algorithm was suggested by Steve Bellovin.
+ */
+__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
+                                __u16 sport, __u16 dport)
+{
+       static int      is_init = 0;
+       static __u32    secret[16];
+       struct timeval  tv;
+       __u32           tmp[16];
+       __u32           seq;
+
+       /*
+        * Pick a random secret the first time we open a TCP
+        * connection.
+        */
+       if (is_init == 0) {
+               get_random_bytes(&secret, sizeof(secret));
+               is_init = 1;
+       }
+
+       memcpy(tmp, secret, sizeof(tmp));
+       /*
+        * Pick a unique starting offset for each
+        * TCP connection endpoints (saddr, daddr, sport, dport)
+        */
+       tmp[8]=saddr;
+       tmp[9]=daddr;
+       tmp[10]=(sport << 16) + dport;
+       HASH_TRANSFORM(tmp, tmp);
+       
+       /*
+        *      As close as possible to RFC 793, which
+        *      suggests using a 250kHz clock.
+        *      Further reading shows this assumes 2MB/s networks.
+        *      For 10MB/s ethernet, a 1MHz clock is appropriate.
+        *      That's funny, Linux has one built in!  Use it!
+        */
+       do_gettimeofday(&tv);
+       seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000;
+#if 0
+       printk("init_seq(%lx, %lx, %d, %d) = %d\n",
+              saddr, daddr, sport, dport, seq);
+#endif
+       return (seq);
+}
+
+#ifdef RANDOM_BENCHMARK
+/*
+ * This is so we can do some benchmarking of the random driver, to see
+ * how much overhead add_timer_randomness really takes.  This only
+ * works on a Pentium, since it depends on the timer clock...
+ *
+ * Note: the results of this benchmark as of this writing (5/27/96)
+ *
+ * On a Pentium, add_timer_randomness() takes between 150 and 1000
+ * clock cycles, with an average of around 600 clock cycles.  On a 75
+ * MHz Pentium, this translates to 2 to 13 microseconds, with an
+ * average time of 8 microseconds.  This should be fast enough so we
+ * can use add_timer_randomness() even with the fastest of interrupts...
+ */
+static inline unsigned long long get_clock_cnt(void)
+{
+       unsigned long low, high;
+       __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high));
+       return (((unsigned long long) high << 31) | low); 
+}
+
+static void initialize_benchmark(struct random_benchmark *bench,
+                                const char *descr, int unit)
+{
+       bench->times = 0;
+       bench->accum = 0;
+       bench->max = 0;
+       bench->min = 1 << 31;
+       bench->descr = descr;
+       bench->unit = unit;
+}
+
+static void begin_benchmark(struct random_benchmark *bench)
+{
+#ifdef BENCHMARK_NOINT
+       save_flags(bench->flags); cli();
+#endif
+       bench->start_time = get_clock_cnt();
+}
+
+static void end_benchmark(struct random_benchmark *bench)
+{
+       unsigned long ticks;
+       
+       ticks = (unsigned long) (get_clock_cnt() - bench->start_time);
+#ifdef BENCHMARK_NOINT
+       restore_flags(bench->flags);
+#endif
+       if (ticks < bench->min)
+               bench->min = ticks;
+       if (ticks > bench->max)
+               bench->max = ticks;
+       bench->accum += ticks;
+       bench->times++;
+       if (bench->times == BENCHMARK_INTERVAL) {
+               printk("Random benchmark: %s %d: %lu min, %lu avg, "
+                      "%lu max\n", bench->descr, bench->unit, bench->min,
+                      bench->accum / BENCHMARK_INTERVAL, bench->max);
+               bench->times = 0;
+               bench->accum = 0;
+               bench->max = 0;
+               bench->min = 1 << 31;
+       }
+}      
+#endif /* RANDOM_BENCHMARK */
index dbdd283efd2635a524f1e697e41ca6f15b5ef58d..c47a9963edfdbfd97a38df98e88be2fcda9b3159 100644 (file)
@@ -123,6 +123,10 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
 
          args = (unsigned short *)(arg + 1);
          if (user) {
+                 int err;
+                 err = verify_area(VERIFY_READ, args, sizeof(short) * 5);
+                 if (err)
+                       return err;
                  xs = get_user(args++) - 1;
                  ys = get_user(args++) - 1;
                  xe = get_user(args++) - 1;
index 5904112db6ed581176d9809d4c7df2ceaeef8bb5..fb50693fc56c2d46822bb9da83d874c9a82e24ed 100644 (file)
@@ -49,7 +49,7 @@
 #include <asm/bitops.h>
 
 static char *serial_name = "Serial driver";
-static char *serial_version = "4.12";
+static char *serial_version = "4.13";
 
 DECLARE_TASK_QUEUE(tq_serial);
 
@@ -90,6 +90,13 @@ static int serial_refcount;
 
 #define _INLINE_ inline
   
+#ifdef MODULE
+static int io[PORT_MAX] = { 0, };
+static int irq[PORT_MAX]  = { 0, };
+static int type[PORT_MAX]  = { 0, };
+static int flags[PORT_MAX]  = { 0, };
+#endif
+
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
  kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
@@ -1944,6 +1951,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                                    (unsigned long *) arg);
                        return 0;
                case TIOCSSOFTCAR:
+                       error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
+                       if (error)
+                               return error;
                        arg = get_fs_long((unsigned long *) arg);
                        tty->termios->c_cflag =
                                ((tty->termios->c_cflag & ~CLOCAL) |
@@ -1967,6 +1977,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        return get_serial_info(info,
                                               (struct serial_struct *) arg);
                case TIOCSSERIAL:
+                       error = verify_area(VERIFY_READ, (void *) arg,
+                                               sizeof(struct serial_struct));
+                       if (error)
+                               return error;
                        return set_serial_info(info,
                                               (struct serial_struct *) arg);
                case TIOCSERCONFIG:
@@ -1991,6 +2005,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                case TIOCSERSWILD:
                        if (!suser())
                                return -EPERM;
+                       error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
+                       if (error)
+                               return error;
                        rs_wild_int_mask = get_fs_long((unsigned long *) arg);
                        if (rs_wild_int_mask < 0)
                                rs_wild_int_mask = check_wild_interrupts(0);
@@ -2013,6 +2030,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        return get_multiport_struct(info,
                                       (struct serial_multiport_struct *) arg);
                case TIOCSERSETMULTI:
+                       error = verify_area(VERIFY_READ, (void *) arg,
+                                   sizeof(struct serial_multiport_struct));
+                       if (error)
+                               return error;
                        return set_multiport_struct(info,
                                       (struct serial_multiport_struct *) arg);
                /*
@@ -2804,13 +2825,25 @@ int rs_init(void)
                        info->icount.rng = info->icount.dcd = 0;
                info->next_port = 0;
                info->prev_port = 0;
+#ifdef MODULE
+               if(irq[i])
+                       info->irq=irq[i];
+               if (io[i])
+                       info->port=io[i];
+               if (type[i])
+                       info->type = type[i];
+               if (flags[i])
+                       info->flags = flags[i];
+#endif
                if (info->irq == 2)
                        info->irq = 9;
-               if (!(info->flags & ASYNC_BOOT_AUTOCONF))
-                       continue;
-               autoconfig(info);
-               if (info->type == PORT_UNKNOWN)
-                       continue;
+               if (info->type == PORT_UNKNOWN) {
+                       if (!(info->flags & ASYNC_BOOT_AUTOCONF))
+                               continue;
+                       autoconfig(info);
+                       if (info->type == PORT_UNKNOWN)
+                               continue;
+               }
                printk(KERN_INFO "tty%02d%s at 0x%04x (irq = %d)", info->line, 
                       (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
                       info->port, info->irq);
index ca4af161f59c829e76cf80f11b929c958ef8dd43..bd1570bd3e9a1656cc5bb98be2085600b11721f7 100644 (file)
@@ -431,6 +431,9 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
        tty->session = 0;
        tty->pgrp = -1;
        tty->ctrl_status = 0;
+       tty->packet = 0;
+       if (tty->link)
+               tty->link->packet = 0;
        if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
                *tty->termios = tty->driver.init_termios;
        if (tty->driver.hangup)
@@ -1518,6 +1521,10 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                        return 0;
                case TIOCSETD:
                        retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       retval = verify_area(VERIFY_READ, (void *) arg,
+                                            sizeof (int));
                        if (retval)
                                return retval;
                        arg = get_user((int *) arg);
@@ -1558,9 +1565,15 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                         * kernel-internal variable; programs not closely
                         * related to the kernel should not use this.
                         */
+                                       retval = verify_area(VERIFY_WRITE, (void *) arg, 1);
+                                       if (retval)
+                                               return retval;
                                        put_user(shift_state,(char *) arg);
                                        return 0;
                                case 7:
+                                       retval = verify_area(VERIFY_WRITE, (void *) arg, 1);
+                                       if (retval)
+                                               return retval;
                                        put_user(mouse_reporting(),(char *) arg);
                                        return 0;
                                case 10:
index c3f4f5b3bce067a50e223f25ca410d78a0e00d4a..b4986f318aca2bc95ffe7478d9c81928a0e5dc4a 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <linux/mm.h>
 
 extern unsigned short video_port_reg, video_port_val;
 
@@ -267,7 +268,12 @@ void vesa_unblank(void)
 void set_vesa_blanking(const unsigned long arg)
 {
        unsigned char *argp = (unsigned char *)(arg + 1);
-       unsigned int mode = get_user(argp);
+       unsigned int mode;
+
+       if (verify_area(VERIFY_READ, argp, 1))
+               return;
+
+       mode = get_user(argp);
        vesa_blanking_mode = suspend_vesa_blanking_mode =
                ((mode <= VESA_POWERDOWN) ? mode : DEFAULT_VESA_BLANKING_MODE);
 }
index 6dfcbb18d2eac7c2a0e27dd33377e563d2c7f0db..42c141ddeabd8033d0bdce707b8c78c3e8591aa4 100644 (file)
@@ -165,6 +165,7 @@ tx_full and tbusy flags.
  *     - added support for Linux/Alpha, but removed most of it, because
  *        it worked only for the PCI chip. 
  *      - added hook for the 32bit lance driver
+ *      - added PCnetPCI II (79C970A) to chip table
  *
  *     Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
  *     - hopefully fix above so Linux/Alpha can use ISA cards too.
@@ -268,12 +269,15 @@ static struct lance_chip_type {
        {0x2430, "PCnet32",                                     /* 79C965 PCnet for VL bus. */
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
                        LANCE_HAS_MISSED_FRAME},
+        {0x2621, "PCnet/PCI-II 79C970A",        /* 79C970A PCInetPCI II. */
+                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
+                        LANCE_HAS_MISSED_FRAME},
        {0x0,    "PCnet (unknown)",
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
                        LANCE_HAS_MISSED_FRAME},
 };
 
-enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, LANCE_UNKNOWN=5};
+enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6};
 
 /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
 static unsigned char pci_irq_line = 0;
@@ -437,7 +441,7 @@ void lance_probe1(int ioaddr)
 
 #ifdef CONFIG_LANCE32
         /* look if it's a PCI or VLB chip */
-        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB) {
+        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
            extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
            
            lance32_probe1 (dev, chipname, pci_irq_line);
index 7ff1e2705e09c303ea458387e85b9ac84d7d4c9c..5b3968580303d2ce65f94344b2ae711f9143de62 100644 (file)
 
        Paul Gortmaker  : multiple card support for module users.
        Donald Becker   : 4/17/96 PIO support, minor potential problems avoided.
+       Donald Becker   : 6/6/96 correctly set auto-wrap bit.
 */
 
 static const char *version =
-       "smc-ultra.c:v1.99 4/17/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+       "smc-ultra.c:v2.00 6/6/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 
 #include <linux/module.h>
@@ -256,9 +257,10 @@ ultra_open(struct device *dev)
 
        outb(0x00, ioaddr);     /* Disable shared memory for safety. */
        outb(0x80, ioaddr + 5);
-       if (ei_status.block_input == &ultra_pio_input)
+       if (ei_status.block_input == &ultra_pio_input) {
                outb(0x11, ioaddr + 6);         /* Enable interrupts and PIO. */
-       else
+               outb(0x01, ioaddr + 0x19);      /* Enable ring read auto-wrap. */
+       } else
                outb(0x01, ioaddr + 6);         /* Enable interrupts and memory. */
        /* Set the early receive warning level in window 0 high enough not
           to receive ERW interrupts. */
index e86cd8e6cbd7914bd866d4c279765b8600fe8b89..ce408e7081ee96f07ea816391cd50c90fa0b51d8 100644 (file)
@@ -24,8 +24,8 @@
 */
 
 
-#define BusLogic_DriverVersion         "2.0.3"
-#define BusLogic_DriverDate            "17 May 1996"
+#define BusLogic_DriverVersion         "2.0.4"
+#define BusLogic_DriverDate            "5 June 1996"
 
 
 #include <linux/module.h>
@@ -100,7 +100,7 @@ static BusLogic_HostAdapter_T
   which BusLogic Host Adapters may potentially be found.
 */
 
-static unsigned short
+static unsigned int
   BusLogic_IO_StandardAddresses[] =
     { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0 };
 
@@ -112,19 +112,18 @@ static unsigned short
   standard BusLogic I/O Addresses.
 */
 
-static unsigned short
+static unsigned int
   BusLogic_IO_AddressProbeList[BusLogic_IO_MaxProbeAddresses+1] =   { 0 };
 
 
 /*
   BusLogic_IRQ_UsageCount stores a count of the number of Host Adapters using
   a given IRQ Channel, which is necessary to support PCI, EISA, or MCA shared
-  interrupts.  Only IRQ Channels 9, 10, 11, 12, 14, and 15 are supported by
-  BusLogic Host Adapters.
+  interrupts.
 */
 
-static short
-  BusLogic_IRQ_UsageCount[7] =         { 0 };
+static int
+  BusLogic_IRQ_UsageCount[NR_IRQS] =   { 0 };
 
 
 /*
@@ -319,7 +318,7 @@ static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter)
 
 static BusLogic_CCB_T *BusLogic_AllocateCCB(BusLogic_HostAdapter_T *HostAdapter)
 {
-  static unsigned int SerialNumber = 0;
+  static unsigned long SerialNumber = 0;
   BusLogic_CCB_T *CCB;
   int Allocated;
   CCB = HostAdapter->Free_CCBs;
@@ -406,8 +405,7 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
   unsigned char *ParameterPointer = (unsigned char *) ParameterData;
   unsigned char *ReplyPointer = (unsigned char *) ReplyData;
   unsigned char StatusRegister = 0, InterruptRegister;
-  long TimeoutCounter;
-  int ReplyBytes = 0;
+  int ReplyBytes = 0, TimeoutCounter;
   /*
     Clear out the Reply Data if provided.
   */
@@ -591,7 +589,7 @@ static void BusLogic_InitializeAddressProbeList(void)
   */
   if (pcibios_present())
     {
-      unsigned short BusDeviceFunction[BusLogic_IO_MaxProbeAddresses];
+      unsigned int BusDeviceFunction[BusLogic_IO_MaxProbeAddresses];
       unsigned short Index = 0, VendorID, DeviceID;
       boolean NonIncreasingScanningOrder = false;
       unsigned char Bus, DeviceFunction;
@@ -668,7 +666,7 @@ static void BusLogic_InitializeAddressProbeList(void)
                  for (j = 0; j < Bound; j++)
                    if (BusDeviceFunction[j] > BusDeviceFunction[j+1])
                      {
-                       unsigned short Temp;
+                       unsigned int Temp;
                        Temp = BusDeviceFunction[j];
                        BusDeviceFunction[j] = BusDeviceFunction[j+1];
                        BusDeviceFunction[j+1] = Temp;
@@ -765,7 +763,7 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
                                             *HostAdapter)
 {
   boolean TraceHardReset = (BusLogic_GlobalOptions & BusLogic_TraceHardReset);
-  long TimeoutCounter = loops_per_sec >> 2;
+  int TimeoutCounter = loops_per_sec >> 2;
   unsigned char StatusRegister = 0;
   /*
     Issue a Hard Reset Command to the Host Adapter.  The Host Adapter should
@@ -957,18 +955,6 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
                       sizeof(FirmwareVersion3rdDigit))
       != sizeof(FirmwareVersion3rdDigit))
     return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT");
-  /*
-    Issue the Inquire Firmware Version Letter command.
-  */
-  FirmwareVersionLetter = '\0';
-  if (BoardID.FirmwareVersion1stDigit > '3' ||
-      (BoardID.FirmwareVersion1stDigit == '3' &&
-       BoardID.FirmwareVersion2ndDigit >= '3'))
-    if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter,
-                        NULL, 0, &FirmwareVersionLetter,
-                        sizeof(FirmwareVersionLetter))
-       != sizeof(FirmwareVersionLetter))
-      return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER");
   /*
     BusLogic Host Adapters can be identified by their model number and
     the major version number of their firmware as follows:
@@ -984,11 +970,54 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
                  BT-542B/742A (revision G and below)
     0.xx       AMI FastDisk VLB/EISA BusLogic Clone Host Adapter
   */
+  /*
+    Save the Model Name and Board Name in the Host Adapter structure.
+  */
+  TargetPointer = HostAdapter->ModelName;
+  *TargetPointer++ = 'B';
+  *TargetPointer++ = 'T';
+  *TargetPointer++ = '-';
+  for (i = 0; i < sizeof(BoardModelNumber); i++)
+    {
+      Character = BoardModelNumber[i];
+      if (Character == ' ' || Character == '\0') break;
+      *TargetPointer++ = Character;
+    }
+  *TargetPointer++ = '\0';
+  strcpy(HostAdapter->BoardName, "BusLogic ");
+  strcat(HostAdapter->BoardName, HostAdapter->ModelName);
+  strcpy(HostAdapter->InterruptLabel, HostAdapter->BoardName);
+  /*
+    Save the Firmware Version in the Host Adapter structure.
+  */
+  TargetPointer = HostAdapter->FirmwareVersion;
+  *TargetPointer++ = BoardID.FirmwareVersion1stDigit;
+  *TargetPointer++ = '.';
+  *TargetPointer++ = BoardID.FirmwareVersion2ndDigit;
+  if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0')
+    *TargetPointer++ = FirmwareVersion3rdDigit;
+  *TargetPointer = '\0';
+  /*
+    Issue the Inquire Firmware Version Letter command.
+  */
+  if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0)
+    {
+      if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter,
+                          NULL, 0, &FirmwareVersionLetter,
+                          sizeof(FirmwareVersionLetter))
+         != sizeof(FirmwareVersionLetter))
+       return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER");
+      if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0')
+       *TargetPointer++ = FirmwareVersionLetter;
+      *TargetPointer = '\0';
+    }
   /*
     Issue the Inquire Generic I/O Port Information command to read the
-    termination information from "W" Series Host Adapters.
+    IRQ Channel from all PCI Host Adapters, and the Termination Information
+    from "W" Series Host Adapters.
   */
-  if (BoardID.FirmwareVersion1stDigit == '5')
+  if (HostAdapter->ModelName[3] == '9' &&
+      strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0)
     {
       if (BusLogic_Command(HostAdapter,
                           BusLogic_InquireGenericIOPortInformation,
@@ -997,10 +1026,15 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
          != sizeof(GenericIOPortInformation))
        return BusLogic_Failure(HostAdapter,
                                "INQUIRE GENERIC I/O PORT INFORMATION");
+      /*
+       Save the IRQ Channel in the Host Adapter structure.
+      */
+      HostAdapter->IRQ_Channel = GenericIOPortInformation.PCIAssignedIRQChannel;
       /*
        Save the Termination Information in the Host Adapter structure.
       */
-      if (GenericIOPortInformation.Valid)
+      if (HostAdapter->FirmwareVersion[0] == '5' &&
+         GenericIOPortInformation.Valid)
        {
          HostAdapter->TerminationInfoValid = true;
          HostAdapter->LowByteTerminated =
@@ -1010,10 +1044,10 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
        }
     }
   /*
-    Issue the Fetch Host Adapter Local RAM command to read the termination
-    information from the AutoSCSI area of "C" Series Host Adapters.
+    Issue the Fetch Host Adapter Local RAM command to read the Termination
+    Information from the AutoSCSI area of "C" Series Host Adapters.
   */
-  if (BoardID.FirmwareVersion1stDigit == '4')
+  if (HostAdapter->FirmwareVersion[0] == '4')
     {
       FetchHostAdapterLocalRAMRequest.ByteOffset =
        BusLogic_AutoSCSI_BaseOffset + 15;
@@ -1033,58 +1067,23 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
       HostAdapter->HighByteTerminated = AutoSCSIByte15.HighByteTerminated;
     }
   /*
-    Save the Model Name and Board Name in the Host Adapter structure.
+    Determine the IRQ Channel and save it in the Host Adapter structure.
   */
-  TargetPointer = HostAdapter->ModelName;
-  *TargetPointer++ = 'B';
-  *TargetPointer++ = 'T';
-  *TargetPointer++ = '-';
-  for (i = 0; i < sizeof(BoardModelNumber); i++)
+  if (HostAdapter->IRQ_Channel == 0)
     {
-      Character = BoardModelNumber[i];
-      if (Character == ' ' || Character == '\0') break;
-      *TargetPointer++ = Character;
+      if (Configuration.IRQ_Channel9)
+       HostAdapter->IRQ_Channel = 9;
+      else if (Configuration.IRQ_Channel10)
+       HostAdapter->IRQ_Channel = 10;
+      else if (Configuration.IRQ_Channel11)
+       HostAdapter->IRQ_Channel = 11;
+      else if (Configuration.IRQ_Channel12)
+       HostAdapter->IRQ_Channel = 12;
+      else if (Configuration.IRQ_Channel14)
+       HostAdapter->IRQ_Channel = 14;
+      else if (Configuration.IRQ_Channel15)
+       HostAdapter->IRQ_Channel = 15;
     }
-  *TargetPointer++ = '\0';
-  strcpy(HostAdapter->BoardName, "BusLogic ");
-  strcat(HostAdapter->BoardName, HostAdapter->ModelName);
-  strcpy(HostAdapter->InterruptLabel, HostAdapter->BoardName);
-  /*
-    Save the Firmware Version in the Host Adapter structure.
-  */
-  TargetPointer = HostAdapter->FirmwareVersion;
-  *TargetPointer++ = BoardID.FirmwareVersion1stDigit;
-  *TargetPointer++ = '.';
-  *TargetPointer++ = BoardID.FirmwareVersion2ndDigit;
-  if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0')
-    *TargetPointer++ = FirmwareVersion3rdDigit;
-  if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0')
-    *TargetPointer++ = FirmwareVersionLetter;
-  *TargetPointer++ = '\0';
-  /*
-    Determine the IRQ Channel and save it in the Host Adapter structure.
-  */
-  if (Configuration.IRQ_Channel9)
-    HostAdapter->IRQ_Channel = 9;
-  else if (Configuration.IRQ_Channel10)
-    HostAdapter->IRQ_Channel = 10;
-  else if (Configuration.IRQ_Channel11)
-    HostAdapter->IRQ_Channel = 11;
-  else if (Configuration.IRQ_Channel12)
-    HostAdapter->IRQ_Channel = 12;
-  else if (Configuration.IRQ_Channel14)
-    HostAdapter->IRQ_Channel = 14;
-  else if (Configuration.IRQ_Channel15)
-    HostAdapter->IRQ_Channel = 15;
-  /*
-    Determine the DMA Channel and save it in the Host Adapter structure.
-  */
-  if (Configuration.DMA_Channel5)
-    HostAdapter->DMA_Channel = 5;
-  else if (Configuration.DMA_Channel6)
-    HostAdapter->DMA_Channel = 6;
-  else if (Configuration.DMA_Channel7)
-    HostAdapter->DMA_Channel = 7;
   /*
     Save the Host Adapter SCSI ID in the Host Adapter structure.
   */
@@ -1098,28 +1097,30 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   HostAdapter->ParityChecking = SetupInformation.ParityCheckEnabled;
   /*
     Determine the Bus Type and save it in the Host Adapter structure,
-    overriding the DMA Channel if it is inappropriate for the bus type.
+    and determine and save the DMA Channel for ISA Host Adapters.
   */
   switch (HostAdapter->ModelName[3])
     {
     case '4':
       HostAdapter->BusType = BusLogic_VESA_Bus;
-      HostAdapter->DMA_Channel = 0;
       break;
     case '5':
       HostAdapter->BusType = BusLogic_ISA_Bus;
+      if (Configuration.DMA_Channel5)
+       HostAdapter->DMA_Channel = 5;
+      else if (Configuration.DMA_Channel6)
+       HostAdapter->DMA_Channel = 6;
+      else if (Configuration.DMA_Channel7)
+       HostAdapter->DMA_Channel = 7;
       break;
     case '6':
       HostAdapter->BusType = BusLogic_MCA_Bus;
-      HostAdapter->DMA_Channel = 0;
       break;
     case '7':
       HostAdapter->BusType = BusLogic_EISA_Bus;
-      HostAdapter->DMA_Channel = 0;
       break;
     case '9':
       HostAdapter->BusType = BusLogic_PCI_Bus;
-      HostAdapter->DMA_Channel = 0;
       break;
     }
   /*
@@ -1341,7 +1342,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
     printk("%d, ", HostAdapter->DMA_Channel);
   else printk("None, ");
   if (HostAdapter->BIOS_Address > 0)
-    printk("BIOS Address: 0x%lX, ", HostAdapter->BIOS_Address);
+    printk("BIOS Address: 0x%X, ", HostAdapter->BIOS_Address);
   else printk("BIOS Address: None, ");
   printk("Host Adapter SCSI ID: %d\n", HostAdapter->SCSI_ID);
   printk("scsi%d:   Scatter/Gather Limit: %d of %d segments, "
@@ -1432,13 +1433,13 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
     Acquire exclusive or shared access to the IRQ Channel.  A usage count is
     maintained so that PCI, EISA, or MCA shared interrupts can be supported.
   */
-  if (BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]++ == 0)
+  if (BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel]++ == 0)
     {
       if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
                      SA_INTERRUPT | SA_SHIRQ,
                      HostAdapter->InterruptLabel, NULL) < 0)
        {
-         BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]--;
+         BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel]--;
          printk("scsi%d: UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
                 HostAdapter->HostNumber, HostAdapter->IRQ_Channel);
          return false;
@@ -1498,7 +1499,7 @@ static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter)
     Release exclusive or shared access to the IRQ Channel.
   */
   if (HostAdapter->IRQ_ChannelAcquired)
-    if (--BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9] == 0)
+    if (--BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel] == 0)
       free_irq(HostAdapter->IRQ_Channel, NULL);
   /*
     Release exclusive access to the DMA Channel.
@@ -1601,7 +1602,8 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
     Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes.
   */
   ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
-  ExtendedMailboxRequest.BaseMailboxAddress = HostAdapter->FirstOutgoingMailbox;
+  ExtendedMailboxRequest.BaseMailboxAddress =
+    Virtual_to_Bus(HostAdapter->FirstOutgoingMailbox);
   if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox,
                       &ExtendedMailboxRequest,
                       sizeof(ExtendedMailboxRequest), NULL, 0) < 0)
@@ -1858,12 +1860,14 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
        else UntaggedDeviceCount++;
       }
   if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0)
-    TaggedQueueDepth =
-      1 + ((HostAdapter->TotalQueueDepth
-           - UntaggedDeviceCount * UntaggedQueueDepth)
-          / TaggedDeviceCount);
-  if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
-    TaggedQueueDepth = BusLogic_MaxTaggedQueueDepth;
+    {
+      TaggedQueueDepth =
+       1 + ((HostAdapter->TotalQueueDepth
+             - UntaggedDeviceCount * UntaggedQueueDepth)
+            / TaggedDeviceCount);
+      if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth)
+       TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth;
+    }
   for (Device = DeviceList; Device != NULL; Device = Device->next)
     if (Device->host == Host)
       {
@@ -2180,7 +2184,8 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
                      NextIncomingMailbox->CompletionCode) !=
                     BusLogic_IncomingMailboxFree)
                {
-                 BusLogic_CCB_T *CCB = NextIncomingMailbox->CCB;
+                 BusLogic_CCB_T *CCB =
+                   (BusLogic_CCB_T *) Bus_to_Virtual(NextIncomingMailbox->CCB);
                  if (MailboxCompletionCode != BusLogic_AbortedCommandNotFound)
                    if (CCB->Status == BusLogic_CCB_Active ||
                        CCB->Status == BusLogic_CCB_Reset)
@@ -2211,11 +2216,11 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
                          is not marked as status Active or Reset, then there
                          is most likely a bug in the Host Adapter firmware.
                        */
-                       printk("scsi%d: Illegal CCB #%d status %d in "
+                       printk("scsi%d: Illegal CCB #%ld status %d in "
                               "Incoming Mailbox\n", HostAdapter->HostNumber,
                               CCB->SerialNumber, CCB->Status);
                      }
-                 else printk("scsi%d: Aborted CCB #%d to Target %d "
+                 else printk("scsi%d: Aborted CCB #%ld to Target %d "
                              "Not Found\n", HostAdapter->HostNumber,
                              CCB->SerialNumber, CCB->TargetID);
                  NextIncomingMailbox->CompletionCode =
@@ -2252,8 +2257,8 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
       */
       if (CCB->Opcode == BusLogic_BusDeviceReset)
        {
-         unsigned char TargetID = CCB->TargetID;
-         printk("scsi%d: Bus Device Reset CCB #%d to Target %d Completed\n",
+         int TargetID = CCB->TargetID;
+         printk("scsi%d: Bus Device Reset CCB #%ld to Target %d Completed\n",
                 HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
          HostAdapter->TotalCommandCount[TargetID] = 0;
          HostAdapter->TaggedQueuingActive[TargetID] = false;
@@ -2301,7 +2306,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
            {
            case BusLogic_IncomingMailboxFree:
            case BusLogic_AbortedCommandNotFound:
-             printk("scsi%d: CCB #%d to Target %d Impossible State\n",
+             printk("scsi%d: CCB #%ld to Target %d Impossible State\n",
                     HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
              break;
            case BusLogic_CommandCompletedWithoutError:
@@ -2309,7 +2314,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
              Command->result = DID_OK << 16;
              break;
            case BusLogic_CommandAbortedAtHostRequest:
-             printk("scsi%d: CCB #%d to Target %d Aborted\n",
+             printk("scsi%d: CCB #%ld to Target %d Aborted\n",
                     HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
              Command->result = DID_ABORT << 16;
              break;
@@ -2321,7 +2326,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
                if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout)
                  {
                    int i;
-                   printk("scsi%d: CCB #%d Target %d: Result %X "
+                   printk("scsi%d: CCB #%ld Target %d: Result %X "
                           "Host Adapter Status %02X Target Status %02X\n",
                           HostAdapter->HostNumber, CCB->SerialNumber,
                           CCB->TargetID, Command->result,
@@ -2332,7 +2337,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
                    printk("\n");
                    printk("scsi%d: Sense ", HostAdapter->HostNumber);
                    for (i = 0; i < CCB->SenseDataLength; i++)
-                     printk(" %02X", (*CCB->SenseDataPointer)[i]);
+                     printk(" %02X", Command->sense_buffer[i]);
                    printk("\n");
                  }
              break;
@@ -2388,7 +2393,7 @@ static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T
        the Host Adapter is operating asynchronously and the locking code
        does not protect against simultaneous access by the Host Adapter.
       */
-      NextOutgoingMailbox->CCB = CCB;
+      NextOutgoingMailbox->CCB = Virtual_to_Bus(CCB);
       NextOutgoingMailbox->ActionCode = ActionCode;
       BusLogic_StartMailboxCommand(HostAdapter);
       if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox)
@@ -2413,9 +2418,9 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
   unsigned char *CDB = Command->cmnd;
-  unsigned char CDB_Length = Command->cmd_len;
-  unsigned char TargetID = Command->target;
-  unsigned char LogicalUnit = Command->lun;
+  int CDB_Length = Command->cmd_len;
+  int TargetID = Command->target;
+  int LogicalUnit = Command->lun;
   void *BufferPointer = Command->request_buffer;
   int BufferLength = Command->request_bufflen;
   int SegmentCount = Command->use_sg;
@@ -2461,7 +2466,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
     {
       CCB->Opcode = BusLogic_InitiatorCCB;
       CCB->DataLength = BufferLength;
-      CCB->DataPointer = BufferPointer;
+      CCB->DataPointer = Virtual_to_Bus(BufferPointer);
     }
   else
     {
@@ -2469,13 +2474,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
       int Segment;
       CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
       CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T);
-      CCB->DataPointer = CCB->ScatterGatherList;
+      CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
       for (Segment = 0; Segment < SegmentCount; Segment++)
        {
          CCB->ScatterGatherList[Segment].SegmentByteCount =
            ScatterList[Segment].length;
          CCB->ScatterGatherList[Segment].SegmentDataPointer =
-           ScatterList[Segment].address;
+           Virtual_to_Bus(ScatterList[Segment].address);
        }
     }
   switch (CDB[0])
@@ -2515,13 +2520,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
     the Host Adapter and Target Device can establish Synchronous and Wide
     Transfer before Queue Tag messages can interfere with the Synchronous and
     Wide Negotiation message.  By waiting to enable Tagged Queuing until after
-    the first BusLogic_MaxTaggedQueueDepth commands have been sent, it is
+    the first BusLogic_PreferredQueueDepth commands have been sent, it is
     assured that after a Reset any pending commands are resent before Tagged
     Queuing is enabled and that the Tagged Queuing message will not occur while
     the partition table is being printed.
   */
   if (HostAdapter->TotalCommandCount[TargetID]++ ==
-        BusLogic_MaxTaggedQueueDepth &&
+        BusLogic_PreferredTaggedQueueDepth &&
       (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) &&
       Command->device->tagged_supported)
     {
@@ -2564,7 +2569,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
        }
     }
   memcpy(CCB->CDB, CDB, CDB_Length);
-  CCB->SenseDataPointer = (SCSI_SenseData_T *) &Command->sense_buffer;
+  CCB->SenseDataPointer = Virtual_to_Bus(&Command->sense_buffer);
   CCB->Command = Command;
   Command->scsi_done = CompletionRoutine;
   /*
@@ -2608,7 +2613,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
-  unsigned char TargetID = Command->target;
+  int TargetID = Command->target;
   BusLogic_Lock_T Lock;
   BusLogic_CCB_T *CCB;
   int Result;
@@ -2666,7 +2671,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
   if (HostAdapter->TaggedQueuingActive[TargetID] &&
       HostAdapter->FirmwareVersion[0] < '5')
     {
-      printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
+      printk("scsi%d: Unable to Abort CCB #%ld to Target %d - "
             "Abort Tag Not Supported\n", HostAdapter->HostNumber,
             CCB->SerialNumber, TargetID);
       Result = SCSI_ABORT_SNOOZE;
@@ -2674,13 +2679,13 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
   else if (BusLogic_WriteOutgoingMailbox(HostAdapter,
                                         BusLogic_MailboxAbortCommand, CCB))
     {
-      printk("scsi%d: Aborting CCB #%d to Target %d\n",
+      printk("scsi%d: Aborting CCB #%ld to Target %d\n",
             HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
       Result = SCSI_ABORT_PENDING;
     }
   else
     {
-      printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
+      printk("scsi%d: Unable to Abort CCB #%ld to Target %d - "
             "No Outgoing Mailboxes\n", HostAdapter->HostNumber,
             CCB->SerialNumber, TargetID);
       Result = SCSI_ABORT_BUSY;
@@ -2827,7 +2832,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
                                       SCSI_Command_T *Command,
                                       unsigned int ResetFlags)
 {
-  unsigned char TargetID = Command->target;
+  int TargetID = Command->target;
   BusLogic_Lock_T Lock;
   BusLogic_CCB_T *CCB;
   int Result = -1;
@@ -2913,7 +2918,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
   */
   CCB = BusLogic_AllocateCCB(HostAdapter);
   if (CCB == NULL) goto Done;
-  printk("scsi%d: Sending Bus Device Reset CCB #%d to Target %d\n",
+  printk("scsi%d: Sending Bus Device Reset CCB #%ld to Target %d\n",
         HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
   CCB->Opcode = BusLogic_BusDeviceReset;
   CCB->TargetID = TargetID;
@@ -2984,9 +2989,8 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
-  unsigned char TargetID = Command->target;
-  unsigned char ErrorRecoveryStrategy =
-    HostAdapter->ErrorRecoveryStrategy[TargetID];
+  int TargetID = Command->target;
+  int ErrorRecoveryStrategy = HostAdapter->ErrorRecoveryStrategy[TargetID];
   /*
     Disable Tagged Queuing if it is active for this Target Device and if
     it has been less than 10 minutes since the last reset occurred, or since
@@ -3255,7 +3259,8 @@ void BusLogic_Setup(char *Strings, int *Integers)
   BusLogic_CommandLineEntry_T *CommandLineEntry =
     &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++];
   static int ProbeListIndex = 0;
-  int IntegerCount = Integers[0], TargetID, i;
+  int IntegerCount = Integers[0];
+  int TargetID, i;
   CommandLineEntry->IO_Address = 0;
   CommandLineEntry->TaggedQueueDepth = 0;
   CommandLineEntry->BusSettleTime = 0;
@@ -3269,7 +3274,7 @@ void BusLogic_Setup(char *Strings, int *Integers)
     printk("BusLogic: Unexpected Command Line Integers ignored\n");
   if (IntegerCount >= 1)
     {
-      unsigned short IO_Address = Integers[1];
+      unsigned int IO_Address = Integers[1];
       if (IO_Address > 0)
        {
          for (i = 0; ; i++)
index 5d9cb3d508d38bea2ca1d712992fe6c1a085ba9f..90b87c03fbe23d6236239e01ccffc17d6fef9742 100644 (file)
@@ -119,12 +119,13 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *);
 
 
 /*
-  Define the maximum and default Queue Depth to allow for Target Devices
-  depending on whether or not they support Tagged Queuing and whether or not
-  ISA Bounce Buffers are required.
+  Define the maximum, preferred, and default Queue Depth to allow for Target
+  Devices depending on whether or not they support Tagged Queuing and whether
+  or not ISA Bounce Buffers are required.
 */
 
-#define BusLogic_MaxTaggedQueueDepth           31
+#define BusLogic_MaxTaggedQueueDepth           63
+#define BusLogic_PreferredTaggedQueueDepth     28
 #define BusLogic_TaggedQueueDepth_BB           2
 #define BusLogic_UntaggedQueueDepth            3
 
@@ -191,6 +192,13 @@ static char
 typedef unsigned char boolean;
 
 
+/*
+  Define a 32 bit bus address data type.
+*/
+
+typedef unsigned int bus_address_t;
+
+
 /*
   Define the BusLogic SCSI Host Adapter I/O Register Offsets.
 */
@@ -401,7 +409,7 @@ BusLogic_SetupInformation_T;
 typedef struct BusLogic_ExtendedMailboxRequest
 {
   unsigned char MailboxCount;                          /* Byte 0 */
-  void *BaseMailboxAddress __attribute__ ((packed));   /* Bytes 1-4 */
+  bus_address_t BaseMailboxAddress __attribute__ ((packed)); /* Bytes 1-4 */
 }
 BusLogic_ExtendedMailboxRequest_T;
 
@@ -466,7 +474,7 @@ typedef struct BusLogic_ExtendedSetupInformation
   unsigned char BIOS_Address;                          /* Byte 1 */
   unsigned short ScatterGatherLimit;                   /* Bytes 2-3 */
   unsigned char MailboxCount;                          /* Byte 4 */
-  void *BaseMailboxAddress __attribute__ ((packed));   /* Bytes 5-8 */
+  bus_address_t BaseMailboxAddress __attribute__ ((packed)); /* Bytes 5-8 */
   struct { unsigned char :6;                           /* Byte 9 Bits 0-5 */
           boolean LevelSensitiveInterrupts:1;          /* Byte 9 Bit 6 */
           unsigned char :1; } Misc;                    /* Byte 9 Bit 7 */
@@ -708,15 +716,6 @@ BusLogic_QueueTag_T;
 typedef unsigned char SCSI_CDB_T[BusLogic_CDB_MaxLength];
 
 
-/*
-  Define the SCSI Sense Data.
-*/
-
-#define BusLogic_SenseDataMaxLength            255
-
-typedef unsigned char SCSI_SenseData_T[BusLogic_SenseDataMaxLength];
-
-
 /*
   Define the Scatter/Gather Segment structure required by the Host Adapter
   Firmware Interface.
@@ -724,8 +723,8 @@ typedef unsigned char SCSI_SenseData_T[BusLogic_SenseDataMaxLength];
 
 typedef struct BusLogic_ScatterGatherSegment
 {
-  unsigned long SegmentByteCount;                      /* Bytes 0-3 */
-  void *SegmentDataPointer;                            /* Bytes 4-7 */
+  unsigned int SegmentByteCount;                       /* Bytes 0-3 */
+  bus_address_t SegmentDataPointer;                    /* Bytes 4-7 */
 }
 BusLogic_ScatterGatherSegment_T;
 
@@ -754,8 +753,8 @@ typedef struct BusLogic_CCB
   BusLogic_QueueTag_T WideModeQueueTag:2;              /* Byte 1 Bits 6-7 */
   unsigned char CDB_Length;                            /* Byte 2 */
   unsigned char SenseDataLength;                       /* Byte 3 */
-  unsigned long DataLength;                            /* Bytes 4-7 */
-  void *DataPointer;                                   /* Bytes 8-11 */
+  unsigned int DataLength;                             /* Bytes 4-7 */
+  bus_address_t DataPointer;                           /* Bytes 8-11 */
   unsigned char :8;                                    /* Byte 12 */
   unsigned char :8;                                    /* Byte 13 */
   BusLogic_HostAdapterStatus_T HostAdapterStatus:8;    /* Byte 14 */
@@ -767,8 +766,8 @@ typedef struct BusLogic_CCB
   SCSI_CDB_T CDB;                                      /* Bytes 18-29 */
   unsigned char :8;                                    /* Byte 30 */
   unsigned char :8;                                    /* Byte 31 */
-  unsigned long :32;                                   /* Bytes 32-35 */
-  SCSI_SenseData_T *SenseDataPointer;                  /* Bytes 36-39 */
+  unsigned int :32;                                    /* Bytes 32-35 */
+  bus_address_t SenseDataPointer;                      /* Bytes 36-39 */
   /*
     BusLogic Linux Driver Portion.
   */
@@ -779,7 +778,7 @@ typedef struct BusLogic_CCB
         BusLogic_CCB_Completed =   2,
         BusLogic_CCB_Reset =       3 } Status;
   BusLogic_CompletionCode_T MailboxCompletionCode;
-  unsigned int SerialNumber;
+  unsigned long SerialNumber;
   struct BusLogic_CCB *Next;
   struct BusLogic_CCB *NextAll;
   BusLogic_ScatterGatherSegment_T
@@ -794,8 +793,8 @@ BusLogic_CCB_T;
 
 typedef struct BusLogic_OutgoingMailbox
 {
-  BusLogic_CCB_T *CCB;                                 /* Bytes 0-3 */
-  unsigned long :24;                                   /* Byte 4 */
+  bus_address_t CCB;                                   /* Bytes 0-3 */
+  unsigned int :24;                                    /* Byte 4 */
   BusLogic_ActionCode_T ActionCode:8;                  /* Bytes 5-7 */
 }
 BusLogic_OutgoingMailbox_T;
@@ -807,7 +806,7 @@ BusLogic_OutgoingMailbox_T;
 
 typedef struct BusLogic_IncomingMailbox
 {
-  BusLogic_CCB_T *CCB;                                 /* Bytes 0-3 */
+  bus_address_t CCB;                                   /* Bytes 0-3 */
   BusLogic_HostAdapterStatus_T HostAdapterStatus:8;    /* Byte 4 */
   BusLogic_TargetDeviceStatus_T TargetDeviceStatus:8;  /* Byte 5 */
   unsigned char :8;                                    /* Byte 6 */
@@ -842,7 +841,7 @@ static char
 
 typedef struct BusLogic_CommandLineEntry
 {
-  unsigned short IO_Address;
+  unsigned int IO_Address;
   unsigned short TaggedQueueDepth;
   unsigned short BusSettleTime;
   unsigned short LocalOptions;
@@ -860,12 +859,12 @@ BusLogic_CommandLineEntry_T;
 typedef struct BusLogic_HostAdapter
 {
   SCSI_Host_T *SCSI_Host;
+  unsigned int IO_Address;
   unsigned char HostNumber;
   unsigned char ModelName[9];
   unsigned char FirmwareVersion[6];
   unsigned char BoardName[18];
   unsigned char InterruptLabel[62];
-  unsigned short IO_Address;
   unsigned char IRQ_Channel;
   unsigned char DMA_Channel;
   unsigned char SCSI_ID;
@@ -901,7 +900,7 @@ typedef struct BusLogic_HostAdapter
   unsigned short LocalOptions;
   unsigned short DisconnectPermitted;
   unsigned short TaggedQueuingPermitted;
-  unsigned long BIOS_Address;
+  bus_address_t BIOS_Address;
   BusLogic_InstalledDevices_T InstalledDevices;
   BusLogic_SynchronousValues_T SynchronousValues;
   BusLogic_SynchronousPeriod_T SynchronousPeriod;
@@ -1063,6 +1062,22 @@ static inline void BusLogic_Delay(int Seconds)
 }
 
 
+/*
+  Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
+  and PCI/VLB/EISA/ISA Bus Addresses.
+*/
+
+static inline bus_address_t Virtual_to_Bus(void *VirtualAddress)
+{
+  return (bus_address_t) virt_to_bus(VirtualAddress);
+}
+
+static inline void *Bus_to_Virtual(bus_address_t BusAddress)
+{
+  return (void *) bus_to_virt(BusAddress);
+}
+
+
 /*
   Define prototypes for the forward referenced BusLogic Driver
   Internal Functions.
index 3b376cab08d20830d0603b5bbeff1105acdbc615..78468da1e091a731474c75feb83efc4e1c8be7b0 100644 (file)
@@ -15,15 +15,13 @@ mainmenu_option next_comment
 comment 'SCSI low-level drivers'
 
 dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
-dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
+dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
-if [ "$CONFIG_PCI" = "y" ]; then
-  bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
-fi
+bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
 dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
index d99797e84eb2bb9dd91d4c244ee9536ce12d4992..e363b1476c69f88e29538f5a5899fb155ca2fcef 100644 (file)
@@ -1,9 +1,9 @@
                  BusLogic MultiMaster SCSI Driver for Linux
 
-                      Version 1.2.3 for Linux 1.2.13
-                      Version 2.0.3 for Linux 2.0.0
+                      Version 1.2.4 for Linux 1.2.13
+                      Version 2.0.4 for Linux 2.0.0
 
-                                 17 May 1996
+                                 5 June 1996
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -325,7 +325,7 @@ substantially impact performance.
                             INSTALLATION
 
 This distribution was prepared for Linux kernel version 1.2.13
-(BusLogic-1.2.3.tar.gz) or Linux kernel version 2.0.0 (BusLogic-2.0.3.tar.gz).
+(BusLogic-1.2.4.tar.gz) or Linux kernel version 2.0.0 (BusLogic-2.0.4.tar.gz).
 Installation in later versions will probably be successful as well, though
 BusLogic.patch may not be required.  Installation in earlier versions is not
 recommended.
@@ -335,7 +335,7 @@ replacing "/usr/src" with wherever you keep your Linux kernel source tree
 (substitute "1.2" or "2.0" for "x.y" in the tar command as appropriate):
 
   cd /usr/src
-  tar -xvzf BusLogic-x.y.3.tar.gz
+  tar -xvzf BusLogic-x.y.4.tar.gz
   mv README.* BusLogic.[ch] linux/drivers/scsi
   patch -p < BusLogic.patch        (on Linux 1.2.13 only)
   patch -p < BusLogic.elf_patch            (on Linux 1.2.13 ELF systems only)
index 80a3a7f0bcc3a3a4a0e1b7d6cc3a3dd3f476f7df..1aefc0a6b6e612f1e5c7cb0e1430470b79559437 100644 (file)
@@ -97,6 +97,48 @@ the bus ever care what it is? Is cable quality a factor here?
 Regardless, you can choose your own default through the command-
 line with the 'period' keyword.
 
+
+------------------------------------------------
+***********  DIP switch settings  **************
+------------------------------------------------
+
+   sw1-1 sw1-2    BIOS address (hex)
+   -----------------------------------------
+    off   off     C8000 - CBFF0
+    on    off     D8000 - DBFF0
+    off   on      D0000 - D3FF0
+    on    on      BIOS disabled
+
+   sw1-3 sw1-4    IO port address (hex)
+   ------------------------------------
+    off   off     220 - 22F
+    on    off     200 - 20F
+    off   on      110 - 11F
+    on    on      100 - 10F
+
+   sw1-5 sw1-6 sw1-7    Interrupt
+   ------------------------------
+    off   off   off     15
+    off   on    off     14
+    off   off   on      11
+    off   on    on      10
+    on    -     -       disabled
+
+   sw1-8 function depends on BIOS version. In earlier versions this
+   controlled synchronous data transfer support for MSDOS:
+      off = disabled
+      on  = enabled
+   In later ROMs (starting with 01.3 in April 1994) sw1-8 controls
+   the "greater than 2 disk drive" feature that first appeared in
+   MSDOS 5.0 (ignored by linux):
+      off = 2 drives maximum
+      on  = 7 drives maximum
+
+   sw1-9    Floppy controller
+   --------------------------
+    off     disabled
+    on      enabled
+
 ------------------------------------------------
 
    I should mention that Drew Eckhardt's 'Generic NCR5380' sources
index 586c02f2117a192ad47da224602e4d2fa9af93ad..875ec8e0911b1d3bced7b83e606f03d99df0c62c 100644 (file)
 #include <linux/types.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
-#include <unistd.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/delay.h>
 
 #include "sd.h"
 #include "hosts.h"
 
 #define USE_NVRAM_DEFAULTS     0
 
-/*  Set this macro to 1 if you want to create a scsi loadable module. */
-
-#define MODULE                 0
-
 /*  Macros used for debugging */
 
 #define DEBUG_ISP1020          0
@@ -1681,8 +1677,8 @@ int isp1020_return_status(struct Status_Entry *sts)
     return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
 }
 
-#if MODULE
-Scsi_Host_Template driver_template = ISP1020;
+#ifdef MODULE
+Scsi_Host_Template driver_template = QLOGICISP;
 
 #include "scsi_module.c"
 #endif /* MODULE */
index 22c361a9ea924b353271daf4e5730e0239438488..7c6fae3bcef6022c86dca6c1f88a084690c0bdca 100644 (file)
@@ -21,6 +21,8 @@
  */
 #include <scsi/scsi.h>
 
+#include <linux/random.h>
+
 
 /*
  * Some defs, in case these are not defined elsewhere.
@@ -526,6 +528,7 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
     if (req->sem != NULL) {
        up(req->sem);
     }
+    add_blkdev_randomness(MAJOR(req->rq_dev));
     
     if (SCpnt->host->block) {
        struct Scsi_Host * next;
index 770b002c6176045408152725b8c84acf0c676104..c47e539c3f76f9d84d68e3564a8527489101e2d2 100644 (file)
@@ -28,6 +28,9 @@ if [ "$CONFIG_INET" = "y" ]; then
     fi
   fi
   tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS
+  if [ "$CONFIG_SMB_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'SMB long filename support (EXPERIMENTAL)' CONFIG_SMB_LONG
+  fi
 fi
 if [ "$CONFIG_IPX" != "n" ]; then
   tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
index a1f215c733158021a8d7ef22d6e7ed6035eb75f2..00777dc8ad9d39c914e45dbc458c5731134badcf 100644 (file)
@@ -101,8 +101,15 @@ unsigned long file_table_init(unsigned long start, unsigned long end)
 struct file * get_empty_filp(void)
 {
        int i;
+       int max = max_files;
        struct file * f;
 
+       /*
+        * Reserve a few files for the super-user..
+        */
+       if (current->euid)
+               max -= 10;
+
        /* if the return is taken, we are in deep trouble */
        if (!first_file && !grow_files())
                return NULL;
@@ -117,7 +124,7 @@ struct file * get_empty_filp(void)
                                f->f_version = ++event;
                                return f;
                        }
-       } while (nr_files < max_files && grow_files());
+       } while (nr_files < max && grow_files());
 
        return NULL;
 }
index d2d215a01205bb22cd18f3d13e1c862421895767..9a7b33ec6aae2b49b65071e01f475acb0e07a3be 100644 (file)
@@ -302,7 +302,7 @@ static inline int
 rpc_send(struct rpc_sock *rsock, struct rpc_wait *slot)
 {
        struct rpc_ioreq *req = slot->w_req;
-       struct iovec    iov[MAX_IOVEC];
+       struct iovec    iov[UIO_MAXIOV];
 
        if (rsock->shutdown)
                return -EIO;
@@ -336,7 +336,7 @@ rpc_grok(struct rpc_sock *rsock)
 {
        struct rpc_wait *rovr;
        struct rpc_ioreq *req;
-       struct iovec    iov[MAX_IOVEC];
+       struct iovec    iov[UIO_MAXIOV];
        u32             xid;
        int             safe, result;
 
index d0db64f7a274b3f62aae2d5230b6c8af9cd1bc9c..181eb6946da6a1c62289d37b1ce600c2ab4d1713 100644 (file)
@@ -203,7 +203,7 @@ static int do_readv_writev(int type, struct inode * inode, struct file * file,
        const struct iovec * vector, unsigned long count)
 {
        size_t tot_len;
-       struct iovec iov[MAX_IOVEC];
+       struct iovec iov[UIO_MAXIOV];
        int retval, i;
        IO_fn_t fn;
 
@@ -213,7 +213,7 @@ static int do_readv_writev(int type, struct inode * inode, struct file * file,
         */
        if (!count)
                return 0;
-       if (count > MAX_IOVEC)
+       if (count > UIO_MAXIOV)
                return -EINVAL;
        retval = verify_area(VERIFY_READ, vector, count*sizeof(*vector));
        if (retval)
index 2c09443cc82c4c3cc612d9d43cb72b5b49918f47..1995a790a2b38bbd9bf2d945b26d0327d9baa33b 100644 (file)
@@ -937,20 +937,3 @@ smb_rename(struct inode *old_dir, const char *old_name, int old_len,
        iput(new_dir);
        return res;
 }
-       
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index 9a64f012a4c697ac9a50ae40baa619d3e1cd5f64..6321ad921ece6f54402256a8bd82e3acaf1d8af6 100644 (file)
@@ -258,20 +258,3 @@ struct inode_operations smb_file_inode_operations = {
        NULL,                   /* bmap */
        NULL                    /* truncate */
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index 7dd2e2a35b727a6dded865886886e41b20979603..e2374756d21c6dfa293ec353ae262aa20209b65c 100644 (file)
@@ -444,20 +444,3 @@ cleanup_module(void)
 }
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index 64cc621a945e2b099ade8b159c046244a0cdd989..00c32245442cd4a4c484dd5812f21e56bc56e7bb 100644 (file)
@@ -31,21 +31,3 @@ smb_ioctl (struct inode * inode, struct file * filp,
                return -EINVAL;
        }
 }
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index db97623156d35c28e16f4766613940c7983ee08f..1baec2a0ba5c8d0d8932f5fc2381ea796c495a91 100644 (file)
@@ -120,20 +120,3 @@ smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
        vma->vm_ops = &smb_file_mmap;
        return 0;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index a3627d1083ddf51373e9df7fc3ccb1156781f806..150506aee2cd4a3985b684a95701856dee2cf397 100644 (file)
@@ -5,6 +5,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/smbno.h>
 #include <linux/smb_fs.h>
@@ -1603,12 +1604,14 @@ smb_proc_reconnect(struct smb_server *server)
           { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
           { PROTOCOL_LANMAN1,"LANMAN1.0"},
 #endif
+#ifdef CONFIG_SMB_LONG
 #ifdef LANMAN2
           { PROTOCOL_LANMAN2,"LM1.2X002"},
 #endif
 #ifdef NT1
          { PROTOCOL_NT1,"NT LM 0.12"},
          { PROTOCOL_NT1,"NT LANMAN 1.0"},
+#endif
 #endif
           {-1, NULL} };
        char dev[] = "A:";
@@ -2026,20 +2029,3 @@ smb_printerr(int class, int num)
 }
 
 #endif /* DEBUG_SMB > 0 */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index c7d96d247aaf187a3c9566c2c99236b508697516..ae6b1032777dddfe8ce1093649abdb30dded292a 100644 (file)
@@ -768,20 +768,3 @@ smb_request_write_raw(struct smb_server *server,
 
        return result;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index 83940d16a5ad7adbec2ec8dd21b4c8db0d1ecc0d..3143b5bb29c9cc917ed81c089335ef522abbc7cd 100644 (file)
@@ -14,8 +14,9 @@
 #define RLIMIT_NPROC   6               /* max number of processes */
 #define RLIMIT_NOFILE  7               /* max number of open files */
 #define RLIMIT_MEMLOCK 8               /* max locked-in-memory address space */
+#define RLIMIT_AS      9               /* address space limit */
 
-#define RLIM_NLIMITS   9
+#define RLIM_NLIMITS   10
 
 #ifdef __KERNEL__
 
@@ -30,6 +31,7 @@
        { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },     \
        { NR_OPEN, NR_OPEN },                           \
        { LONG_MAX, LONG_MAX },                         \
+       { LONG_MAX, LONG_MAX },                         \
 }
 
 #endif /* __KERNEL__ */
index ea70a74da4dcf8cf857e3945fcf569e45c27d23a..fb656acfd81353643f4c6cc162528947e6e8f38b 100644 (file)
@@ -52,6 +52,11 @@ struct baycom_params {
 #define KISS_CMD_TXTAIL     4
 #define KISS_CMD_FULLDUP    5
 
+/*
+ * use bottom halves? (HDLC processing done with interrupts on or off)
+ */
+#define BAYCOM_USE_BH
+
 /*
  * modem types
  */
index 77cd07c8f672561b698c2a493900df85999b4325..d9b59b045b61e012357318ec6fdd615ed9670851 100644 (file)
@@ -33,6 +33,7 @@ enum {
        DIGI_BH,
        SERIAL_BH,
        RISCOM8_BH,
+       BAYCOM_BH,
        NET_BH,
        IMMEDIATE_BH,
        KEYBOARD_BH,
index 91d616073e03b0572753389842107ff58dc1d183..318886ca2e0780e0271cc98a55850072eb95aa3a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
- * (H) Hackright 1996 by Marcin Dalecki <dalecki@namu03.gwdg.de>
- * VERSION: 2.5
+ * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
+ * VERSION: @VERSION@
  * 
  * 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
  * You should have received a copy of the GNU General Public License
  * along with this program; see the file COPYING.  If not, write to
  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Thanks to
+ *  The Linux Community at all and ...
+ *  Martin Harris (he wrote the first Mitsumi Driver)
+ *  Eberhard Moenkeberg (he gave me much support and the initial kick)
+ *  Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they
+ *      improved the original driver)
+ *  Jon Tombs, Bjorn Ekwall (module support)
+ *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
+ *  Gerd Knorr (he lent me his PhotoCD)
+ *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
+ *  ... somebody forgotten?
+ *  Marcin Dalecki
+ *  
  */
 
-#ifndef __MCDX_H
-#define __MCDX_H
 /*
- *     PLEASE CONFIGURE THIS ACCORDING TO YOUR HARDWARE/JUMPER SETTINGS.
+ *     The following lines are for user configuration
+ *     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *     {0|1} -- 1 if you want the driver detect your drive, may crash and
+ *     needs a long time to seek.  The higher the address the longer the
+ *     seek.
  *
- *      o       MCDX_NDRIVES  :  number of used entries of the following table
- *      o       MCDX_DRIVEMAP :  table of {i/o base, irq} per controller
+ *  WARNING: AUTOPROBE doesn't work.
+ */
+#define MCDX_AUTOPROBE 0
+
+/*
+ *     Drive specific settings according to the jumpers on the controller
+ *     board(s).
+ *     o       MCDX_NDRIVES  :  number of used entries of the following table
+ *     o       MCDX_DRIVEMAP :  table of {i/o base, irq} per controller
  *
- *      NOTE: Don't even think about connecting the drive to IRQ 9(2).
- *     In the AT architecture this interrupt is used to cascade the two
- *     interrupt controllers and isn't therefore usable for anything else!
+ *     NOTE: I didn't get a drive at irq 9(2) working.  Not even alone.
  */
- /* #define I_WAS_IN_MCDX_H */
-#define MCDX_NDRIVES 1
-#define MCDX_DRIVEMAP {        {0x230, 11},    \
+#if MCDX_AUTOPROBE == 0
+       #define MCDX_NDRIVES 1
+       #define MCDX_DRIVEMAP {         \
+                       {0x300, 11},    \
                        {0x304, 05},    \
                        {0x000, 00},    \
                        {0x000, 00},    \
                        {0x000, 00},    \
-}
-               
-/* 
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NO USER INTERVENTION NEEDED BELOW
- * If You are sure that all configuration is done, please uncomment the
- * line below. 
- */
+               }
+#else
+       #error Autoprobing is not implemented yet.
+#endif
 
-#undef MCDX_DEBUG      /* This is *REALLY* only for development! */
+#ifndef MCDX_QUIET
+#define MCDX_QUIET   1
+#endif
 
-#ifdef MCDX_DEBUG
-#define MCDX_TRACE(x) printk x
-#define MCDX_TRACE_IOCTL(x) printk x
-#else
-#define MCDX_TRACE(x)
-#define MCDX_TRACE_IOCTL(x)
+#ifndef MCDX_DEBUG
+#define MCDX_DEBUG   0
 #endif
 
-/*      The name of the device */
-#define MCDX "mcdx"
+/* *** make the following line uncommented, if you're sure,
+ * *** all configuration is done */
+/* #define I_WAS_HERE */
+#define I_WAS_HERE   /* delete this line, it's for heiko only */
 
-/*
- *      Per controller 4 bytes i/o are needed. 
+/*     The name of the device */
+#define MCDX "mcdx"    
+
+/* Flags for DEBUGGING */
+#define INIT           0
+#define MALLOC                 0
+#define IOCTL          0
+#define PLAYTRK     0
+#define SUBCHNL     0
+#define TOCHDR      0
+#define MS          0
+#define PLAYMSF     0
+#define READTOC     0
+#define OPENCLOSE      0
+#define HW                 0
+#define TALK           0
+#define IRQ            0
+#define XFER           0
+#define REQUEST                0
+#define SLEEP          0
+
+/*     The following addresses are taken from the Mitsumi Reference 
+ *  and describe the possible i/o range for the controller.
  */
+#define MCDX_IO_BEGIN  ((char*) 0x300) /* first base of i/o addr */
+#define MCDX_IO_END            ((char*) 0x3fc) /* last base of i/o addr */
+
+/*     Per controller 4 bytes i/o are needed. */
 #define MCDX_IO_SIZE           4
 
-/* 
- * Masks for the status byte, returned from every command, set if
- * the description is true 
+/*
+ *     Bits
  */
+
+/* The status byte, returned from every command, set if
+ * the description is true */
 #define MCDX_RBIT_OPEN       0x80      /* door is open */
 #define MCDX_RBIT_DISKSET    0x40      /* disk set (recognised) */
 #define MCDX_RBIT_CHANGED    0x20      /* disk was changed */
 #define MCDX_RBIT_CHECK      0x10      /* disk rotates, servo is on */
-#define MCDX_RBIT_AUDIOTR    0x08      /* current track is audio */
+#define MCDX_RBIT_AUDIOTR    0x08   /* current track is audio */
 #define MCDX_RBIT_RDERR      0x04      /* read error, refer SENSE KEY */
 #define MCDX_RBIT_AUDIOBS    0x02      /* currently playing audio */
 #define MCDX_RBIT_CMDERR     0x01      /* command, param or format error */
 
-/* 
- * The I/O Register holding the h/w status of the drive,
- * can be read at i/o base + 1 
- */
+/* The I/O Register holding the h/w status of the drive,
+ * can be read at i/o base + 1 */
 #define MCDX_RBIT_DOOR       0x10      /* door is open */
 #define MCDX_RBIT_STEN       0x04      /* if 0, i/o base contains drive status */
 #define MCDX_RBIT_DTEN       0x02      /* if 0, i/o base contains data */
 
 /*
- *    The commands.
+ *     The commands.
+ */
+
+#define OPCODE 1               /* offset of opcode */
+#define MCDX_CMD_REQUEST_TOC           1, 0x10
+#define MCDX_CMD_REQUEST_STATUS                1, 0x40 
+#define MCDX_CMD_RESET                         1, 0x60
+#define MCDX_CMD_REQUEST_DRIVE_MODE    1, 0xc2
+#define MCDX_CMD_SET_INTERLEAVE                2, 0xc8, 0
+#define MCDX_CMD_DATAMODE_SET          2, 0xa0, 0
+       #define MCDX_DATAMODE1          0x01
+       #define MCDX_DATAMODE2          0x02
+#define MCDX_CMD_LOCK_DOOR             2, 0xfe, 0
+
+#define READ_AHEAD                     4       /* 8 Sectors (4K) */
+
+/*     Useful macros */
+#define e_door(x)              ((x) & MCDX_RBIT_OPEN)
+#define e_check(x)             (~(x) & MCDX_RBIT_CHECK)
+#define e_notset(x)            (~(x) & MCDX_RBIT_DISKSET)
+#define e_changed(x)   ((x) & MCDX_RBIT_CHANGED)
+#define e_audio(x)             ((x) & MCDX_RBIT_AUDIOTR)
+#define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS)
+#define e_cmderr(x)            ((x) & MCDX_RBIT_CMDERR)
+#define e_readerr(x)   ((x) & MCDX_RBIT_RDERR)
+
+/**    no drive specific */
+#define MCDX_CDBLK     2048    /* 2048 cooked data each blk */
+
+#define MCDX_DATA_TIMEOUT      (HZ/10) /* 0.1 second */
+
+/*
+ * Access to the msf array
  */
-#define MCDX_CMD_GET_TOC               0x10
-#define MCDX_CMD_GET_MDISK_INFO                0x11
-#define MCDX_CMD_GET_SUBQ_CODE         0x20
-#define MCDX_CMD_GET_STATUS            0x40
-#define MCDX_CMD_SET_DRIVE_MODE                0x50
-#define MCDX_CMD_RESET                 0x60
-#define MCDX_CMD_HOLD                  0x70
-#define MCDX_CMD_CONFIG                        0x90
-#define MCDX_CMD_SET_ATTENATOR         0xae
-#define MCDX_CMD_PLAY                  0xc0
-#define MCDX_CMD_PLAY_2X               0xc1
-#define MCDX_CMD_GET_DRIVE_MODE                0xc2
-#define MCDX_CMD_SET_INTERLEAVE                0xc8
-#define MCDX_CMD_GET_FIRMWARE          0xdc
-#define MCDX_CMD_SET_DATA_MODE         0xa0
-#define MCDX_CMD_STOP                  0xf0
-#define MCDX_CMD_EJECT                 0xf6
-#define MCDX_CMD_CLOSE_DOOR            0xf8
-#define MCDX_CMD_LOCK_DOOR             0xfe
-
-#define READ_AHEAD                     8       /* 16 Sectors (4K) */
-
-#ifndef I_WAS_IN_MCDX_H
+#define MSF_MIN                0                       /* minute */
+#define MSF_SEC                1                       /* second */
+#define MSF_FRM                2                       /* frame  */
+
+/*
+ * Errors
+ */
+#define MCDX_E         1                       /* unspec error */
+#define MCDX_ST_EOM 0x0100             /* end of media */
+#define MCDX_ST_DRV 0x00ff             /* mask to query the drive status */
+
+#ifndef I_WAS_HERE
 #warning You have not edited mcdx.h
 #warning Perhaps irq and i/o settings are wrong.
 #endif
 
-#endif         /* __MCDX_H */
+/* ex:set ts=4 sw=4: */
index cebd1a500db6c97d5376f0170096654fe0b27881..888f5f5d788488722670ca01bc8d65f29fa87e1c 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
-#include <linux/interrupt.h>
 
 /* for future expansion when we will have different priorities. */
 #define DEV_NUMBUFFS   3
@@ -205,6 +204,7 @@ struct packet_type {
 
 #ifdef __KERNEL__
 
+#include <linux/interrupt.h>
 #include <linux/notifier.h>
 
 /* Used by dev_rint */
index 4911794401d0d293710ff3c77da0d4a52e2ac937..b2706ce031b7a98f9f353831f17c79468bf5dc70 100644 (file)
@@ -53,6 +53,9 @@ extern void add_blkdev_randomness(int major);
 
 extern void get_random_bytes(void *buf, int nbytes);
 
+extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
+                                       __u16 sport, __u16 dport);
+
 #ifndef MODULE
 extern struct file_operations random_fops, urandom_fops;
 #endif
index ab159fc1201b975215cfa7797b9453c92832c1b8..9a7f5eae953f1fd1ecdd8040e1e9330208c174ed 100644 (file)
@@ -53,10 +53,10 @@ struct rpc_ioreq {
        struct rpc_wait *       rq_slot;
        struct sockaddr *       rq_addr;
        int                     rq_alen;
-       struct iovec            rq_svec[MAX_IOVEC];
+       struct iovec            rq_svec[UIO_MAXIOV];
        unsigned int            rq_snr;
        unsigned long           rq_slen;
-       struct iovec            rq_rvec[MAX_IOVEC];
+       struct iovec            rq_rvec[UIO_MAXIOV];
        unsigned int            rq_rnr;
        unsigned long           rq_rlen;
 };
index 7c8f3ab3d706c101cd2cd9642887caef710fec94..a8ee20f59328a70f9171de815ac861fa78a41ca0 100644 (file)
 
 #if DISTRIBUTION
 #define READ_AUDIO 0
+#define KLOGD_PAUSE 55
 #else
 /* max. number of audio frames to read with one     */
 /* request (allocates n* 2352 bytes kernel memory!) */
 /* runtime by use of the CDROMAUDIOBUFSIZ ioctl.    */
 #define READ_AUDIO 75
 
+/*
+ * Time to wait after giving a message.
+ * This gets important if you enable non-standard DBG_xxx flags.
+ * You will see what happens if you omit the pause or make it
+ * too short. Be warned!
+ */
+#define KLOGD_PAUSE 1
+
 /* tray control: eject tray if no disk is in (0 or 1) */
 #define JUKEBOX 1
 
 /*==========================================================================*/
 #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
 #undef  FUTURE
+#undef SAFE_MIXED
 
 #define TEST_UPC 0
 #define SPEA_TEST 0
index f85c78b678006bcb977a1c851eaa37d6eb883fcd..f54894b045473a458a4a0927071676c76456f905 100644 (file)
@@ -104,21 +104,3 @@ struct smb_dirent {
 
 #endif  /* __KERNEL__ */
 #endif  /* _LINUX_SMB_H */
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index 436f99ac2977c94f68d051f8476d7ca8e46b5195..b6e38fd180d666430aeae6f013e2653f011707cc 100644 (file)
@@ -32,20 +32,3 @@ struct smb_inode_info {
 
 #endif
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
index 9fd88bd7a38d6a45fb7061d4571efb75af7fbeb2..994475be791b92512a1e7a1b438c9a6140a50d99 100644 (file)
@@ -36,5 +36,3 @@ struct smb_mount_data {
 };
 
 #endif
-
-
index 8051b3d00573ae6156aa742b58a4e0c0bab72f8e..8027bc8d7a588b9bd2a27768d90accde004784b1 100644 (file)
@@ -12,7 +12,7 @@
 
 
 /* A word of warning: Our uio structure will clash with the C library one (which is now obsolete). Remove the C
-   library one from sys/uio.h */
+   library one from sys/uio.h if you have a very old library set */
 
 struct iovec
 {
@@ -20,6 +20,7 @@ struct iovec
        int iov_len;
 };
 
-#define MAX_IOVEC      8       /* Maximum iovec's in one operation */
+#define UIO_MAXIOV     16      /* Maximum iovec's in one operation 
+                                  16 matches BSD */
 
 #endif
index f51cc7075f4580f61db31981b36a6849bc0e2cf3..d69a3d1d2452c41d16c5502b904a2a3f38903321 100644 (file)
 #define IP_MASQ_F_NO_DPORT             0x04    /* no dport set yet */
 #define IP_MASQ_F_NO_DADDR             0x08    /* no daddr yet */
 #define IP_MASQ_F_HASHED               0x10    /* hashed entry */
-#define IP_MASQ_F_SAW_FIN              0x20    /* tcp fin pkt seen */
-#define IP_MASQ_F_SAW_RST              0x40    /* tcp rst pkt seen */
+#define IP_MASQ_F_SAW_RST              0x20    /* tcp rst pkt seen */
+#define IP_MASQ_F_SAW_FIN_IN           0x40    /* tcp fin pkt seen incoming */
+#define IP_MASQ_F_SAW_FIN_OUT          0x80    /* tcp fin pkt seen outgoing */
+#define IP_MASQ_F_SAW_FIN              (IP_MASQ_F_SAW_FIN_IN | \
+                                        IP_MASQ_F_SAW_FIN_OUT)
+                                               /* tcp fin pkts seen */
 
 #ifdef __KERNEL__
 
index c61922a686028ca5f3c90df0ad921b4d55477c8a..044f6525e2030e9d338b9091416cb2349c00a003 100644 (file)
@@ -214,7 +214,8 @@ struct sock
        __u32                   lastwin_seq;    /* sequence number when we last updated the window we offer */
        __u32                   high_seq;       /* sequence number when we did current fast retransmit */
        volatile unsigned long  ato;            /* ack timeout */
-       volatile unsigned long  lrcvtime;       /* jiffies at last rcv */
+       volatile unsigned long  lrcvtime;       /* jiffies at last data rcv */
+       volatile unsigned long  idletime;       /* jiffies at last rcv */
        unsigned short          bytes_rcv;
 /*
  *     mss is min(mtu, max_window) 
@@ -391,7 +392,7 @@ struct proto
 #define SOCK_DESTROY_TIME (10*HZ)
 
 /*
- *     Sockets 0-1023 can't be bound too unless you are superuser 
+ *     Sockets 0-1023 can't be bound to unless you are superuser 
  */
  
 #define PROT_SOCK      1024
index a6821332fa92d2be46d481cb4501fd0b41af91b1..ba295172cad1f5427d956c8137e85bd28528cc28 100644 (file)
@@ -18,8 +18,6 @@
 #include <linux/stat.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/swap.h>
 #include <linux/fcntl.h>
 #include <linux/acct.h>
 #include <linux/tty.h>
@@ -550,70 +548,6 @@ asmlinkage long sys_times(struct tms * tbuf)
        return jiffies;
 }
 
-asmlinkage unsigned long sys_brk(unsigned long brk)
-{
-       int freepages;
-       unsigned long rlim;
-       unsigned long newbrk, oldbrk;
-
-       if (brk < current->mm->end_code)
-               return current->mm->brk;
-       newbrk = PAGE_ALIGN(brk);
-       oldbrk = PAGE_ALIGN(current->mm->brk);
-       if (oldbrk == newbrk)
-               return current->mm->brk = brk;
-
-       /*
-        * Always allow shrinking brk
-        */
-       if (brk <= current->mm->brk) {
-               current->mm->brk = brk;
-               do_munmap(newbrk, oldbrk-newbrk);
-               return brk;
-       }
-       /*
-        * Check against rlimit and stack..
-        */
-       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
-       if (rlim >= RLIM_INFINITY)
-               rlim = ~0;
-       if (brk - current->mm->end_code > rlim)
-               return current->mm->brk;
-       /*
-        * Check against existing mmap mappings.
-        */
-       if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
-               return current->mm->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 >> PAGE_SHIFT;
-       freepages += page_cache_size;
-       freepages >>= 1;
-       freepages += nr_free_pages;
-       freepages += nr_swap_pages;
-       freepages -= MAP_NR(high_memory) >> 4;
-       freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
-       if (freepages < 0)
-               return current->mm->brk;
-#if 0
-       freepages += current->mm->rss;
-       freepages -= oldbrk >> 12;
-       if (freepages < 0)
-               return current->mm->brk;
-#endif
-       /*
-        * Ok, we have probably got enough memory - let it rip.
-        */
-       current->mm->brk = brk;
-       do_mmap(NULL, oldbrk, newbrk-oldbrk,
-               PROT_READ|PROT_WRITE|PROT_EXEC,
-               MAP_FIXED|MAP_PRIVATE, 0);
-       return brk;
-}
-
 /*
  * This needs some heavy checking ...
  * I just haven't the stomach for it. I also don't fully
index 047d1c3d14dab0325d6af38ce190e8fa340afe5f..a46a3cc06a1148a4a66a46cf42c4f6644bdf04db 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -12,6 +12,8 @@
 #include <linux/mman.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -39,6 +41,78 @@ pgprot_t protection_map[16] = {
        __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
 };
 
+/*
+ * Check that a process has enough memory to allocate a
+ * new virtual mapping.
+ */
+static inline int vm_enough_memory(long pages)
+{
+       /*
+        * 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.
+        */
+       long freepages;
+       freepages = buffermem >> PAGE_SHIFT;
+       freepages += page_cache_size;
+       freepages >>= 1;
+       freepages += nr_free_pages;
+       freepages += nr_swap_pages;
+       freepages -= MAP_NR(high_memory) >> 4;
+       return freepages > pages;
+}
+
+asmlinkage unsigned long sys_brk(unsigned long brk)
+{
+       unsigned long rlim;
+       unsigned long newbrk, oldbrk;
+
+       if (brk < current->mm->end_code)
+               return current->mm->brk;
+       newbrk = PAGE_ALIGN(brk);
+       oldbrk = PAGE_ALIGN(current->mm->brk);
+       if (oldbrk == newbrk)
+               return current->mm->brk = brk;
+
+       /*
+        * Always allow shrinking brk
+        */
+       if (brk <= current->mm->brk) {
+               current->mm->brk = brk;
+               do_munmap(newbrk, oldbrk-newbrk);
+               return brk;
+       }
+       /*
+        * Check against rlimit and stack..
+        */
+       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+       if (rlim >= RLIM_INFINITY)
+               rlim = ~0;
+       if (brk - current->mm->end_code > rlim)
+               return current->mm->brk;
+
+       /*
+        * Check against existing mmap mappings.
+        */
+       if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
+               return current->mm->brk;
+
+       /*
+        * Check if we have enough memory..
+        */
+       if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
+               return current->mm->brk;
+
+       /*
+        * Ok, looks good - let it rip.
+        */
+       current->mm->brk = brk;
+       do_mmap(NULL, oldbrk, newbrk-oldbrk,
+               PROT_READ|PROT_WRITE|PROT_EXEC,
+               MAP_FIXED|MAP_PRIVATE, 0);
+       return brk;
+}
+
 /*
  * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
  * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
@@ -179,6 +253,14 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
 
        do_munmap(addr, len);   /* Clear old maps */
 
+       /* Private writable mapping? Check memory availability.. */
+       if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
+               if (!vm_enough_memory(len >> PAGE_SHIFT)) {
+                       kfree(vma);
+                       return -ENOMEM;
+               }
+       }
+
        if (file) {
                int error = file->f_op->mmap(file->f_inode, file, vma);
        
index 67c7e9fe3eab7c79d64e5909f1be7562487a7151..3815a172d6fac8e52e34dda6e4273bbdca13713a 100644 (file)
@@ -334,7 +334,12 @@ int try_to_free_page(int priority, int dma, int wait)
 {
        static int state = 0;
        int i=6;
+       int stop;
 
+       /* we don't try as hard if we're not waiting.. */
+       stop = 3;
+       if (wait)
+               stop = 0;
        switch (state) {
                do {
                case 0:
@@ -349,7 +354,8 @@ int try_to_free_page(int priority, int dma, int wait)
                        if (swap_out(i, dma, wait))
                                return 1;
                        state = 0;
-               } while (i--);
+               i--;
+               } while ((i - stop) >= 0);
        }
        return 0;
 }
index bc6e936e20107bf772173c5ceac371e7ed26a5b9..8f8705f70bcfb1c88d07f8d1087506fc3954d3c3 100644 (file)
@@ -20,9 +20,9 @@ if [ "$CONFIG_AX25" = "y" ]; then
   bool 'AX.25 over Ethernet' CONFIG_BPQETHER
   bool 'Amateur Radio NET/ROM' CONFIG_NETROM
 fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
-fi
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#  bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
+#fi
 bool 'Kernel/User network link driver' CONFIG_NETLINK
 if [ "$CONFIG_NETLINK" = "y" ]; then
   bool 'Routing messages' CONFIG_RTNETLINK
index ae27303b4baf8c372d41c78124b59db85e3c4993..93f9e900fe0e4c6fb36b1e599101bfc6c69bfb43 100644 (file)
@@ -413,14 +413,8 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
                                dev_kfree_skb(skb, FREE_WRITE);
                                return;
                        }
-                       cli();
-                       skb_device_unlock(skb);         /* Buffer is on the device queue and can be freed safely */
-                       __skb_queue_tail(list, skb);
-                       skb = __skb_dequeue(list);
-                       skb_device_lock(skb);           /* New buffer needs locking down */
-                       restore_flags(flags);
                }
-               
+
                /* copy outgoing packets to any sniffer packet handlers */
                if (dev_nit) {
                        struct packet_type *ptype;
@@ -442,6 +436,15 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
                                }
                        }
                }
+
+               if (skb_queue_len(list)) {
+                       cli();
+                       skb_device_unlock(skb);         /* Buffer is on the device queue and can be freed safely */
+                       __skb_queue_tail(list, skb);
+                       skb = __skb_dequeue(list);
+                       skb_device_lock(skb);           /* New buffer needs locking down */
+                       restore_flags(flags);
+               }
        }
        if (dev->hard_start_xmit(skb, dev) == 0) {
                /*
index f01fe57b67b7c5f186b5b1ebbf345377ca17b581..6af7c270a298a8afcf5c33825c102946da9928d7 100644 (file)
@@ -283,7 +283,6 @@ void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
 
 void __skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
 {
-       unsigned long flags;
        struct sk_buff *list = (struct sk_buff *)list_;
 
        if (newsk->next || newsk->prev)
@@ -308,7 +307,7 @@ void __skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
 
 struct sk_buff *skb_dequeue(struct sk_buff_head *list_)
 {
-       long flags;
+       unsigned long flags;
        struct sk_buff *result;
        struct sk_buff *list = (struct sk_buff *)list_;
 
index 03ec7ec9d452fe918e1e22b4f771714f1ea79279..8f48b81bb4497e4c931377c572a1ad601dc1f772 100644 (file)
@@ -9,9 +9,12 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then
     bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'IP: masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE
+      if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
+        comment 'Protocol-specific masquerading support will be built as modules.'
+      fi
       bool 'IP: transparent proxy support (EXPERIMENTAL)' CONFIG_IP_TRANSPARENT_PROXY
+      bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
     fi
-    bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
   fi
 fi
 bool 'IP: accounting' CONFIG_IP_ACCT
index 8adcb2b14c2d173fc0130d21e1dc028570b22a1d..f83034bfa914f280597cc082a8c896bcd2f3aac2 100644 (file)
@@ -2025,36 +2025,31 @@ static int arp_req_set(struct arpreq *r, struct device * dev)
 
        while ((entry = *entryp) != NULL)
        {
-               if (entry->ip == ip && entry->mask == mask && entry->dev == dev)
-                       break;
+               /* User supplied arp entries are definitive - RHP 960603 */
+
+               if (entry->ip == ip && entry->mask == mask && entry->dev == dev) {
+                       *entryp=entry->next;
+                       arp_free_entry(entry);
+                       continue;
+               }
                if ((entry->mask & mask) != mask)
-               {
-                       entry = NULL;
                        break;
-               }
                entryp = &entry->next;
        }
 
-       /*
-        *      Do we need to create a new entry?
-        */
-       
+       entry = arp_alloc_entry();
        if (entry == NULL)
        {
-               entry = arp_alloc_entry();
-               if (entry == NULL)
-               {
-                       arp_unlock();
-                       return -ENOMEM;
-               }
-               entry->ip = ip;
-               entry->dev = dev;
-               entry->mask = mask;
-               entry->flags = r->arp_flags;
-
-               entry->next = *entryp;
-               *entryp = entry;
+               arp_unlock();
+               return -ENOMEM;
        }
+       entry->ip = ip;
+       entry->dev = dev;
+       entry->mask = mask;
+       entry->flags = r->arp_flags;
+
+       entry->next = *entryp;
+       *entryp = entry;
 
        ha = r->arp_ha.sa_data;
        if (empty(ha, dev->addr_len))
index e025d831fc14c1dfcf2d06e4fc1e4bd2f73b9657..54ffe7b64a6b5da411c16ad0c35dbd54cc434003 100644 (file)
@@ -469,7 +469,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
                         *      Count mapping we shortcut
                         */
                         
-                       ip_fw_chk(iph,dev2,NULL,ip_acct_chain,IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_OUT);
+                       ip_fw_chk(iph,dev2,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT);
 #endif                 
                        
                        /*
index 20a98e65b5ac2a9c17d2ad06bd4c44dbee726035..d11c646adbdc69949d93af9f09aabc28fe5b5c79 100644 (file)
@@ -257,7 +257,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
         */
 
 #ifdef CONFIG_IP_ACCT
-       ip_fw_chk(iph,dev,NULL,ip_acct_chain,IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_IN);
+       ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
 #endif 
 
        /*
index f730828dfb66114f33ae3f6b0a344ec3e9956f0b..5505a6fd5951743e2ff827c5906ed6d39efff698 100644 (file)
@@ -14,6 +14,7 @@
  *     Juan Jose Ciarlante     :       Added NO_ADDR status flag.
  *     Nigel Metheringham      :       Added ICMP handling for demasquerade
  *     Nigel Metheringham      :       Checksum checking of masqueraded data
+ *     Nigel Metheringham      :       Better handling of timeouts of TCP conns
  *
  *     
  */
@@ -539,20 +540,29 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
                struct tcphdr *th;
                th = (struct tcphdr *)portptr;
 
+               /* Set the flags up correctly... */
+               if (th->fin)
+               {
+                       ms->flags |= IP_MASQ_F_SAW_FIN_OUT;
+               }
+
+               if (th->rst)
+               {
+                       ms->flags |= IP_MASQ_F_SAW_RST;
+               }
+
                /*
-                *      Timeout depends if FIN packet was seen
+                *      Timeout depends if FIN packet has been seen
                 *      Very short timeout if RST packet seen.
                 */
-               if (ms->flags & IP_MASQ_F_SAW_RST || th->rst)
-                {
+               if (ms->flags & IP_MASQ_F_SAW_RST)
+               {
                         timeout = 1;
-                       ms->flags |= IP_MASQ_F_SAW_RST;
-               }
-               else if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
-                {
+               }
+               else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
+               {
                         timeout = ip_masq_expire->tcp_fin_timeout;
-                       ms->flags |= IP_MASQ_F_SAW_FIN;
-               }
+               }
                else timeout = ip_masq_expire->tcp_timeout;
 
                skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
@@ -775,6 +785,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
        __u16   *portptr;
        struct ip_masq  *ms;
        unsigned short len;
+       unsigned long   timeout;
 
        switch (iph->protocol) {
        case IPPROTO_ICMP:
@@ -827,6 +838,9 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
 
         if (ms != NULL)
         {
+               /* Stop the timer ticking.... */
+               ip_masq_set_expire(ms,0);
+
                 /*
                  *     Set dport if not defined yet.
                  */
@@ -869,16 +883,13 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
 
                 /*
                  * Yug! adjust UDP/TCP and IP checksums, also update
-                * UDP timeouts since you cannot depend on traffic
-                * going through the other way to hold the timeout open.
-                * (With TCP the ACK packets hold the tunnel open).
-                * If a TCP RST is seen collapse the tunnel!
+                * timeouts.
+                * If a TCP RST is seen collapse the tunnel (by using short timeout)!
                  */
                 if (iph->protocol==IPPROTO_UDP)
                {
                         recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
-                       ip_masq_set_expire(ms, 0);
-                       ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
+                       timeout = ip_masq_expire->udp_timeout;
                }
                 else
                 {
@@ -886,16 +897,30 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
                         skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
                                                  len - sizeof(struct tcphdr), 0);
                         tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb);
-                       /* Check if TCP RST */
+
+                       /* Check if TCP FIN or RST */
                        th = (struct tcphdr *)portptr;
+                       if (th->fin)
+                       {
+                               ms->flags |= IP_MASQ_F_SAW_FIN_IN;
+                       }
                        if (th->rst)
                        {
-                               ip_masq_set_expire(ms, 0);
                                ms->flags |= IP_MASQ_F_SAW_RST;
-                               ip_masq_set_expire(ms, 1);
                        }
-
+                       
+                       /* Now set the timeouts */
+                       if (ms->flags & IP_MASQ_F_SAW_RST)
+                       {
+                               timeout = 1;
+                       }
+                       else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
+                       {
+                               timeout = ip_masq_expire->tcp_fin_timeout;
+                       }
+                       else timeout = ip_masq_expire->tcp_timeout;
                 }
+               ip_masq_set_expire(ms, timeout);
                 ip_send_check(iph);
 #ifdef DEBUG_CONFIG_IP_MASQUERADE
                 printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
index a2b1a1daf32ce32462234c3302bd327916da4650..41771042168eb037164599c6c9178ac4c144689a 100644 (file)
@@ -320,6 +320,44 @@ void ip_send_check(struct iphdr *iph)
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 }
 
+
+/*
+ *     If a sender wishes the packet to remain unfreed
+ *     we add it to his send queue. This arguably belongs
+ *     in the TCP level since nobody else uses it. BUT
+ *     remember IPng might change all the rules.
+ */
+static inline void add_to_send_queue(struct sock * sk, struct sk_buff * skb)
+{
+       unsigned long flags;
+
+       /* The socket now has more outstanding blocks */
+       sk->packets_out++;
+
+       /* Protect the list for a moment */
+       save_flags(flags);
+       cli();
+
+       if (skb->link3 != NULL)
+       {
+               NETDEBUG(printk("ip.c: link3 != NULL\n"));
+               skb->link3 = NULL;
+       }
+       if (sk->send_head == NULL)
+       {
+               sk->send_tail = skb;
+               sk->send_head = skb;
+               sk->send_next = skb;
+       }
+       else
+       {
+               sk->send_tail->link3 = skb;
+               sk->send_tail = skb;
+       }
+       restore_flags(flags);
+}
+
+
 /*
  * Queues a packet to be sent, and starts the transmitter
  * if necessary.  if free = 1 then we free the block after
@@ -332,15 +370,8 @@ void ip_send_check(struct iphdr *iph)
 void ip_queue_xmit(struct sock *sk, struct device *dev,
              struct sk_buff *skb, int free)
 {
+       unsigned int tot_len;
        struct iphdr *iph;
-/*     unsigned char *ptr;*/
-
-       /* Sanity check */
-       if (dev == NULL)
-       {
-               NETDEBUG(printk("IP: ip_queue_xmit dev = NULL\n"));
-               return;
-       }
 
        IS_SKB(skb);
 
@@ -348,7 +379,7 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
         *      Do some book-keeping in the packet for later
         */
 
-
+       skb->sk = sk;
        skb->dev = dev;
        skb->when = jiffies;
 
@@ -361,32 +392,30 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
         */
 
        iph = skb->ip_hdr;
-       iph->tot_len = htons(skb->len-(((unsigned char *)iph)-skb->data));
-
-       /*
-        *      No reassigning numbers to fragments...
-        */
-
-       if(free!=2)
-               iph->id      = htons(ip_id_count++);
-       else
-               free=1;
-
-       /* All buffers without an owner socket get freed */
-       if (sk == NULL)
-               free = 1;
+       tot_len = skb->len - (((unsigned char *)iph) - skb->data);
+       iph->tot_len = htons(tot_len);
+
+       switch (free) {
+               /* No reassigning numbers to fragments... */
+               default:
+                       free = 1;
+                       break;
+               case 0:
+                       add_to_send_queue(sk, skb);
+                       /* fall through */
+               case 1:
+                       iph->id = htons(ip_id_count++);
+       }
 
        skb->free = free;
 
+       /* Sanity check */
+       if (dev == NULL)
+               goto no_device;
+
 #ifdef CONFIG_FIREWALL
-       if(call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) {
-               /* just don't send this packet */
-               /* and free socket buffers ;) <aldem@barnet.kharkov.ua> */
-               if (free)
-                 skb->sk = sk;         /* I am not sure *this* really need, */
-               kfree_skb(skb, FREE_WRITE);     /* but *this* must be here */
-               return;
-       }
+       if (call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT)
+               goto out;
 #endif 
 
        /*
@@ -395,13 +424,8 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
         *      bits of it.
         */
 
-       if(ntohs(iph->tot_len)> dev->mtu)
-       {
-               ip_fragment(sk,skb,dev,0);
-               IS_SKB(skb);
-               kfree_skb(skb,FREE_WRITE);
-               return;
-       }
+       if (tot_len > dev->mtu)
+               goto fragment;
 
        /*
         *      Add an IP checksum
@@ -409,10 +433,6 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
 
        ip_send_check(iph);
 
-       /*
-        *      Print the frame when debugging
-        */
-
        /*
         *      More debugging. You cannot queue a packet already on a list
         *      Spot this and moan loudly.
@@ -423,58 +443,15 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
                skb_unlink(skb);
        }
 
-       /*
-        *      If a sender wishes the packet to remain unfreed
-        *      we add it to his send queue. This arguably belongs
-        *      in the TCP level since nobody else uses it. BUT
-        *      remember IPng might change all the rules.
-        */
-
-       if (!free)
-       {
-               unsigned long flags;
-               /* The socket now has more outstanding blocks */
-
-               sk->packets_out++;
-
-               /* Protect the list for a moment */
-               save_flags(flags);
-               cli();
-
-               if (skb->link3 != NULL)
-               {
-                       NETDEBUG(printk("ip.c: link3 != NULL\n"));
-                       skb->link3 = NULL;
-               }
-               if (sk->send_head == NULL)
-               {
-                       sk->send_tail = skb;
-                       sk->send_head = skb;
-                       sk->send_next = skb;
-               }
-               else
-               {
-                       sk->send_tail->link3 = skb;
-                       sk->send_tail = skb;
-               }
-               /* skb->link3 is NULL */
-
-               /* Interrupt restore */
-               restore_flags(flags);
-       }
-       else
-               /* Remember who owns the buffer */
-               skb->sk = sk;
-
        /*
         *      If the indicated interface is up and running, send the packet.
         */
         
        ip_statistics.IpOutRequests++;
 #ifdef CONFIG_IP_ACCT
-       ip_fw_chk(iph,dev,NULL,ip_acct_chain,IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_OUT);
+       ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT);
 #endif 
-       
+
 #ifdef CONFIG_IP_MULTICAST     
 
        /*
@@ -505,14 +482,12 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
                }
                /* Multicasts with ttl 0 must not go beyond the host */
                
-               if(skb->ip_hdr->ttl==0)
-               {
-                       kfree_skb(skb, FREE_READ);
-                       return;
-               }
+               if (iph->ttl==0)
+                       goto out;
        }
 #endif
-       if((dev->flags&IFF_BROADCAST) && (iph->daddr==dev->pa_brdaddr||iph->daddr==0xFFFFFFFF) && !(dev->flags&IFF_LOOPBACK))
+       if ((dev->flags & IFF_BROADCAST) && !(dev->flags & IFF_LOOPBACK)
+           && (iph->daddr==dev->pa_brdaddr || iph->daddr==0xFFFFFFFF))
                ip_loopback(dev,skb);
                
        if (dev->flags & IFF_UP)
@@ -521,24 +496,28 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
                 *      If we have an owner use its priority setting,
                 *      otherwise use NORMAL
                 */
+               int priority = SOPRI_NORMAL;
+               if (sk)
+                       priority = sk->priority;
 
-               if (sk != NULL)
-               {
-                       dev_queue_xmit(skb, dev, sk->priority);
-               }
-               else
-               {
-                       dev_queue_xmit(skb, dev, SOPRI_NORMAL);
-               }
-       }
-       else
-       {
-               if(sk)
-                       sk->err = ENETDOWN;
-               ip_statistics.IpOutDiscards++;
-               if (free)
-                       kfree_skb(skb, FREE_WRITE);
+               dev_queue_xmit(skb, dev, priority);
+               return;
        }
+       if(sk)
+               sk->err = ENETDOWN;
+       ip_statistics.IpOutDiscards++;
+out:
+       if (free)
+               kfree_skb(skb, FREE_WRITE);
+       return;
+
+no_device:
+       NETDEBUG(printk("IP: ip_queue_xmit dev = NULL\n"));
+       goto out;
+
+fragment:
+       ip_fragment(sk,skb,dev,0);
+       goto out;
 }
 
 
@@ -720,7 +699,7 @@ int ip_build_xmit(struct sock *sk,
                }
 #endif
 #ifdef CONFIG_IP_ACCT
-               ip_fw_chk(iph,dev,NULL,ip_acct_chain, IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_OUT);
+               ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT);
 #endif         
                if(dev->flags&IFF_UP)
                        dev_queue_xmit(skb,dev,sk->priority);
@@ -926,7 +905,7 @@ int ip_build_xmit(struct sock *sk,
 #endif         
 #ifdef CONFIG_IP_ACCT
                if(!offset)
-                       ip_fw_chk(iph, dev, NULL, ip_acct_chain, IP_FW_F_ACCEPT, IP_FW_MODE_ACCT_OUT);
+                       ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT);
 #endif 
                offset -= (maxfraglen-fragheaderlen);
                fraglen = maxfraglen;
index ae14060da1ba73b9c1377841d157844272c6218d..20b26eaed081aabbc3f858033317a8ced8c592bd 100644 (file)
@@ -104,6 +104,7 @@ extern __inline__ void tcp_rtt_estimator(struct sock *sk, struct sk_buff *oskb)
         */
        
        m = jiffies - oskb->when;  /* RTT */
+
        if (sk->rtt != 0) {
                if(m<=0)
                        m=1;            /* IS THIS RIGHT FOR <0 ??? */
@@ -421,6 +422,8 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        newsk->cong_count = 0;
        newsk->ssthresh = 0x7fffffff;
 
+       newsk->lrcvtime = 0;
+       newsk->idletime = 0;
        newsk->high_seq = 0;
        newsk->backoff = 0;
        newsk->blog = 0;
@@ -652,13 +655,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
        if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq)) 
                goto uninteresting_ack;
 
-       /*
-        *      If there is data set flag 1
-        */
-        
-       if (len != th->doff*4) 
-               flag |= 1;
-
        /*
         *      Have we discovered a larger window
         */
@@ -679,10 +675,8 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
        /*
         *      See if our window has been shrunk. 
         */
-       if (after(sk->window_seq, window_seq)) {
-               flag |= 4;
+       if (after(sk->window_seq, window_seq))
                tcp_window_shrunk(sk, window_seq);
-       }
 
        /*
         *      Pipe has emptied
@@ -758,7 +752,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
 
        if (sk->rcv_ack_seq == ack
                && sk->window_seq == window_seq
-               && !(flag&1)
+               && len != th->doff*4
                && before(ack, sk->sent_seq)
                && after(ack, sk->high_seq))
        {
@@ -777,9 +771,16 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                 * of what we are doing here.
                 */
                if (sk->rcv_ack_cnt == MAX_DUP_ACKS+1) {
+                       int tmp;
+
+                       /* We need to be a bit careful to preserve the
+                        * count of packets that are out in the system here.
+                        */
                        sk->ssthresh = max(sk->cong_window >> 1, 2);
                        sk->cong_window = sk->ssthresh+MAX_DUP_ACKS+1;
+                       tmp = sk->packets_out;
                        tcp_do_retransmit(sk,0);
+                       sk->packets_out = tmp;
                } else if (sk->rcv_ack_cnt > MAX_DUP_ACKS+1) {
                        sk->cong_window++;
                        /*
@@ -884,6 +885,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                if ((sk->send_head = skb->link3) == NULL)
                {
                        sk->send_tail = NULL;
+                       sk->send_next = NULL;
                        sk->retransmits = 0;
                }
 
@@ -912,10 +914,15 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                if (sk->packets_out > 0) 
                        sk->packets_out --;
 
+               /* This is really only supposed to be called when we
+                * are actually ACKing new data, which should exclude
+                * the ACK handshake on an initial SYN packet as well.
+                * Rather than introducing a new test here for this
+                * special case, we just reset the initial values for
+                * rtt immediatly after we move to the established state.
+                */
                if (!(flag&2))  /* Not retransmitting */
                        tcp_rtt_estimator(sk,skb);
-               flag |= (2|4);  /* 2 is really more like 'don't adjust the rtt 
-                                  In this case as we just set it up */
                IS_SKB(skb);
 
                /*
@@ -949,7 +956,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                /*
                 *      Add more data to the send queue.
                 */
-               flag |= 1;
                tcp_write_xmit(sk);
        }
 
@@ -1034,7 +1040,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
            && skb_queue_empty(&sk->write_queue)
            && sk->send_head == NULL) 
        {
-               flag |= 1;
                tcp_send_partial(sk);
        }
 
@@ -1055,7 +1060,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                                sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq);
                if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/) 
                {
-                       flag |= 1;
                        sk->shutdown = SHUTDOWN_MASK;
                        tcp_set_state(sk,TCP_CLOSE);
                        return 1;
@@ -1076,7 +1080,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                        sk->state_change(sk);
                if (sk->rcv_ack_seq == sk->write_seq) 
                {
-                       flag |= 1;
                        sk->shutdown |= SEND_SHUTDOWN;
                        tcp_set_state(sk, TCP_FIN_WAIT2);
                        /* If the socket is dead, then there is no
@@ -1101,7 +1104,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                        sk->state_change(sk);
                if (sk->rcv_ack_seq == sk->write_seq) 
                {
-                       flag |= 1;
                        tcp_time_wait(sk);
                }
        }
@@ -1110,7 +1112,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
         *      Final ack of a three way shake 
         */
         
-       if(sk->state==TCP_SYN_RECV)
+       if (sk->state==TCP_SYN_RECV)
        {
                tcp_set_state(sk, TCP_ESTABLISHED);
                tcp_options(sk,th);
@@ -1123,6 +1125,13 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                        sk->max_window=32;      /* Sanity check */
                        sk->mss=min(sk->max_window,sk->mtu);
                }
+               /* Reset the RTT estimator to the initial
+                * state rather than testing to avoid
+                * updating it on the ACK to the SYN packet.
+                */
+               sk->rtt = 0;
+               sk->rto = TCP_TIMEOUT_INIT;
+               sk->mdev = TCP_TIMEOUT_INIT;
        }
        
        /*
@@ -1679,7 +1688,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        struct sock *sk;
        int syn_ok=0;
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
-       int r=0;
+       int r;
 #endif
 
        /*
@@ -1763,6 +1772,11 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
         
        skb->sk=sk;
        atomic_add(skb->truesize, &sk->rmem_alloc);
+
+       /*
+        * Mark the time of the last received packet.
+        */
+       sk->idletime = jiffies;
        
        /*
         *      We should now do header prediction.
@@ -1897,6 +1911,13 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                                        sk->max_window = 32;
                                        sk->mss = min(sk->max_window, sk->mtu);
                                }
+                               /* Reset the RTT estimator to the initial
+                                * state rather than testing to avoid
+                                * updating it on the ACK to the SYN packet.
+                                */
+                               sk->rtt = 0;
+                               sk->rto = TCP_TIMEOUT_INIT;
+                               sk->mdev = TCP_TIMEOUT_INIT;
                        }
                        else
                        {
index f25d0fdbc49b365b90be27cf7508bdd1ef7827bd..0a71b4bf93a0a73862c04a84cc8fa9d96b8b6bed 100644 (file)
 
 #include <linux/config.h>
 #include <net/tcp.h>
-
+#include <linux/ip_fw.h>
+#include <linux/firewall.h>
 #include <linux/interrupt.h>
 
+
 /*
  * RFC 1122 says:
  *
@@ -145,14 +147,23 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
                }
        }
 
+       /*
+        * Jacobson recommends this in the appendix of his SIGCOMM'88 paper.
+        * The idea is to do a slow start again if we haven't been doing
+        * anything for a long time, in which case we have no reason to
+        * believe that our congestion window is still correct.
+        */
+       if (sk->send_head == 0 && (jiffies - sk->idletime) > sk->rto)
+               sk->cong_window = 1;
+
        /*
         *      Actual processing.
         */
-        
+
        tcp_statistics.TcpOutSegs++;  
        skb->seq = ntohl(th->seq);
        skb->end_seq = skb->seq + size - 4*th->doff;
-       
+
        /*
         *      We must queue if
         *
@@ -394,7 +405,7 @@ void tcp_do_retransmit(struct sock *sk, int all)
                sk->send_next = sk->send_head;
                sk->packets_out = 0;
        }
-       skb = sk->send_head;
+       skb = sk->send_next;
 
        while (skb != NULL)
        {
@@ -468,6 +479,11 @@ void tcp_do_retransmit(struct sock *sk, int all)
                                skb->sk->err_soft=ENETUNREACH;
                                skb->sk->error_report(skb->sk);
                        }
+                       /* Can't transmit this packet, no reason
+                        * to transmit the later ones, even if
+                        * the congestion window allows.
+                        */
+                       break;
                }
                else
                {
@@ -475,6 +491,17 @@ void tcp_do_retransmit(struct sock *sk, int all)
                        skb->raddr=rt->rt_gateway;
                        skb->dev=dev;
                        skb->arp=1;
+#ifdef CONFIG_FIREWALL
+                       if (call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) {
+                               /* The firewall wants us to dump the packet.
+                               * We have to check this here, because
+                               * the drop in ip_queue_xmit only catches the
+                               * first time we send it. We must drop on
+                               * every resend as well.
+                               */
+                               break;
+                       }
+#endif 
                        if (rt->rt_hh)
                        {
                                memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len);
index 7a86cf280e864dd4da09eadc4cfb987f1fba16fa..cd0b9c2ca6a1f520f50c03fb625854207e7a19d5 100644 (file)
@@ -180,6 +180,7 @@ static struct symbol_table net_syms = {
 #ifdef CONFIG_NETLINK
        X(netlink_attach),
        X(netlink_detach),
+       X(netlink_donothing),
        X(netlink_post),
 #endif /* CONFIG_NETLINK */
        
index 69c22cea11236e01e824c63e8656ad2b11b5d53e..85483f6c879a0f2d2287037a3d0fa1ee26e33e9d 100644 (file)
@@ -1113,7 +1113,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags)
        struct socket *sock;
        struct file *file;
        char address[MAX_SOCK_ADDR];
-       struct iovec iov[MAX_IOVEC];
+       struct iovec iov[UIO_MAXIOV];
        struct msghdr msg_sys;
        int err;
        int total_len;
@@ -1134,7 +1134,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags)
        memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
 
        /* do not move before msg_sys is valid */
-       if(msg_sys.msg_iovlen>MAX_IOVEC)
+       if(msg_sys.msg_iovlen>UIO_MAXIOV)
                return -EINVAL;
 
        /* This will also move the address data into kernel space */
@@ -1154,7 +1154,7 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
 {
        struct socket *sock;
        struct file *file;
-       struct iovec iov[MAX_IOVEC];
+       struct iovec iov[UIO_MAXIOV];
        struct msghdr msg_sys;
        int err;
        int total_len;
@@ -1177,7 +1177,7 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        if(err)
                return err;
        memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
-       if(msg_sys.msg_iovlen>MAX_IOVEC)
+       if(msg_sys.msg_iovlen>UIO_MAXIOV)
                return -EINVAL;
 
        /*
index eb549023d86c562c144e675e6c24752dc538550a..fc9338db39dee8b6b74822914ca319ba3c7dfa92 100644 (file)
@@ -989,9 +989,11 @@ void dump_tk_script(struct kconfig *scfg)
        case tok_dep_tristate:
        case tok_define:
        case tok_choose:
-         if(cfg->flags & GLOBAL_WRITTEN) break;
-         cfg->flags |= GLOBAL_WRITTEN;
-         printf("\tglobal %s\n", cfg->optionname);
+         if(!(cfg->flags & GLOBAL_WRITTEN))
+           {
+             cfg->flags |= GLOBAL_WRITTEN;
+             printf("\tglobal %s\n", cfg->optionname);
+           }
          /* fall through */
        case tok_make:
        case tok_comment: