diff -u --recursive --new-file pre2.0.2/linux/CREDITS linux/CREDITS
--- pre2.0.2/linux/CREDITS	Sun May 12 22:54:21 1996
+++ linux/CREDITS	Mon May 13 07:56:33 1996
@@ -755,7 +755,8 @@
 D: Initial implementation of VC's, pty's and select()
 
 N: James B. MacLean
-E: jmaclean@fox.nstn.ns.ca
+E: macleajb@ednet.ns.ca
+W: http://www.ednet.ns.ca/~macleajb/dosemu.html
 D: Coordinator of DOSEMU releases
 D: Program in DOSEMU
 S: PO BOX 220, HFX. CENTRAL
@@ -1007,7 +1008,7 @@
 N: Stefan Reinauer
 E: stepan@home.culture.mipt.ru
 W: http://home.culture.mipt.ru/~stepan
-D: Modulized affs and ufs. Minor fixes.
+D: Modularized affs and ufs. Minor fixes.
 S: Rebmannsweg 34h
 S: 79539 Loerrach
 S: Germany
diff -u --recursive --new-file pre2.0.2/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- pre2.0.2/linux/Documentation/Configure.help	Sun May 12 10:16:05 1996
+++ linux/Documentation/Configure.help	Mon May 13 12:15:25 1996
@@ -39,12 +39,16 @@
   testing is not yet high enough for general use. This is usually
   known as the "alpha-test" phase amongst developers. If a feature is
   currently in alpha-test, then the developers usually discourage 
-  widespread use of this feature by the general public to avoid 
-  "Why doesn't this work?" type mail messages. However, active testing
-  and and detailed bug reports from people familiar with the kernel's
-  internals are usually welcomed by the developers. Unless you intend
-  to help test and develop a feature or driver that falls into this 
-  category, you should probably say N here, which will cause this 
+  uninformed widespread use of this feature by the general public to
+  avoid "Why doesn't this work?" type mail messages. However, active
+  testing and use of these systems is welcomed. Just be aware that it
+  may not meet the normal level of reliability or it may fail to work
+  in some special cases. Detailed bug reports from people familiar with
+  the kernel internals are usually welcomed by the developers. 
+
+  Unless you intend to help test and develop a feature or driver that
+  falls into this category, or you have a situation that requires using 
+  these features you should probably say N here, which will cause this 
   configure script to present you with fewer choices. If you say Y here,
   you will be offered the choice of using features or drivers that are
   currently considered to be in the alpha-test phase.
@@ -403,7 +407,8 @@
   net is inspected by the firewall first. If you want to configure
   your Linux box as a firewall for a local network, say Y here. If
   your local network is TCP/IP based, you will have to say Y to "IP:
-  firewalling", below. Chances are that you don't want this, so say N.
+  firewalling", below. Chances are that you should use this on any
+  machine being run as a router and not on a host.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -465,7 +470,7 @@
   option to the kernel 3) passing the "mem=4M" option to the kernel
   (thereby disabling all but the first 4M of RAM) 4) disabling the
   cache from your BIOS settings 5) exchanging RAM chips 6) exchanging
-  the motherboard 7) committing suicide.
+  the motherboard.
 
 Using SRM as bootloader
 CONFIG_ALPHA_SRM
@@ -772,9 +777,9 @@
 IP: multicasting
 CONFIG_IP_MULTICAST
   This is code for addressing several networked computers at once,
-  enlarging your kernel by about 2 kB. Some versions of gated, the
-  program which constantly updates a networked computer's routing
-  tables, require that this option be compiled in. You also need
+  enlarging your kernel by about 2 kB. If you are using gated, the
+  to update your computer's routing tables and are using RIP2 or OSPF
+  you will need to have this option compiled in. You also need
   multicasting if you intend to participate in the MBONE, a high
   bandwidth network on top of the internet which carries audio and
   video broadcasts. More information about the MBONE is on the WWW at
@@ -789,28 +794,22 @@
   Some Linux network drivers use a technique called copy and checksum
   to optimize host performance. For a machine which is forwarding most
   packets to another host this is however a loss. This parameter turns
-  off copy and checksum from devices. It may also do other changes in
+  off copy and checksum from devices. It may make other changes in the
   future.
 
 IP: firewalling
 CONFIG_IP_FIREWALL
-  A firewall is a computer which protects a local network from the
-  rest of the internet: all traffic to and from computers on the local
-  net is inspected by the firewall first. If you want to configure
-  your Linux box as a firewall for a local TCP/IP based network, say Y
-  here. This will enlarge your kernel by about 2kB. You will need to
-  read the FIREWALL-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will have to use
-  the ipfw tool from the net-tools package, available via ftp (user:
-  anonymous) from
-  ftp.linux.org.uk:/pub/linux/Networking/PROGRAMS/NetTools, or
-  preferably ipfwadm from ftp.xos.nl:/pub/linux/ipfwadm/. These
-  programs allow selective blocking of internet traffic based on type,
-  origin and destination.  You need to enable IP firewalling in order
-  to be able to use IP masquerading (i.e. local computers can chat
-  with an outside host, but that outside host is made to think that it
-  is talking to the firewall box. Makes the local network completely
-  invisible). Chances are that you don't want this, so say N.
+  If you want to configure your Linux box as a firewall for a local 
+  TCP/IP based network, say Y here. This will enlarge your kernel by
+  about 2kB. You may need to read the FIREWALL-HOWTO, available via
+  ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also,
+  you will need the ipfwadm tool to allow selective blocking of internet
+  traffic based on type, origin and destination.  You need to enable IP
+  firewalling in order to be able to use IP masquerading (i.e. local 
+  computers can chat with an outside host, but that outside host is 
+  made to think that it is talking to the firewall box. Makes the local
+  network completely invisible) or to use the ip packet accounting to see
+  what is using all your network bandwidth.
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -821,13 +820,7 @@
   firewalling. The data is accessible with "cat /proc/net/ip_acct", so
   you want to say Y to the /proc filesystem below, if you say Y
   here. To specify what exactly should be recorded, you need the tool
-  ipfw from the net-tools package, available via ftp (user:
-  anonymous) from
-  ftp.linux.org.uk:/pub/Linux/Networking/PROGRAMS/NetTools.  Also, you
-  might want to have a look at the net-acct package, available via ftp
-  (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/system/Network/management. Most people
-  say N, however.
+  ipfwadm (available from ftp.xos.nl if you don't have a copy already).
 
 IP: tunneling
 CONFIG_NET_IPIP
@@ -840,8 +833,7 @@
   mobile IP facilities (which effectively are doing that). Enabling this
   option will produce two modules ( = code which can be inserted in
   and removed from the running kernel whenever you want), one
-  encapsulator and one decapsulator.  This is still alpha code, which
-  means that it need not be completely stable. You can read details in
+  encapsulator and one decapsulator. You can read details in
   drivers/net/README.tunnel. Most people can say N.
   
 IP: firewall packet logging
@@ -905,8 +897,9 @@
 CONFIG_INET_PCTCP
   If you have been having difficulties telneting to your Linux machine
   from a DOS system that uses (broken) PC/TCP networking software (all
-  versions up to OnNet 2.0), try enabling this option.  Everyone else
-  says N.
+  versions up to OnNet 2.0) over your local ethernet  try enabling this
+  option.  Everyone else says N. People having problems with NCSA telnet
+  should see the file linux/Documentation/networking/ncsa-telnet.
 
 Reverse ARP
 CONFIG_INET_RARP
@@ -939,7 +932,8 @@
   we adjust to a smaller size. This is good, so most people say
   N. However, some versions of DOS NCSA telnet (and other software)
   are broken and can only connect to your Linux machine if you say Y
-  here.
+  here. See also Documentation/networking/ncsa-telnet for the location
+  of fixed NCSA telnet clients.
 
 Disable NAGLE algorithm (normally enabled)
 CONFIG_TCP_NAGLE_OFF
@@ -957,26 +951,24 @@
   decide how to forward the frame. However, there is a feature of the
   IP protocol that allows to specify the full route for a given frame
   already at its origin. A frame with such a fully specified route is
-  called "source routed". The question now is whether we should honor
+  called "source routed". The question now is whether we should honour
   these route requests when such frames arrive, or if we should
-  drop all those frames instead. Honoring can introduce security
-  problems (and is not required by the IP specification), and hence it
-  is recommended to say Y here unless you really know what you're
-  doing.
+  drop all those frames instead. Honouring them can introduce security
+  problems (and is rarely a useful feature), and hence it is recommended
+  that you say Y here unless you really know what you're doing.
 
 IP: Allow large windows (not recommend if <16Mb of memory)
 CONFIG_SKB_LARGE
-  This option can speed up network performance. It works by increasing
-  the size of socket buffers, thereby reducing overhead but increasing
-  memory usage. Say N if you have less than 16Mb of RAM, otherwise Y.
-  Note for machines with more that 64MB of RAM: in order for the kernel 
-  to be able to use the memory above 64MB, pass the command line option
-  "mem=XXXM" (where XXX is the memory size in megabytes) to your
-  kernel. See the documentation of your boot loader (lilo or loadlin)
-  about how to pass options to the kernel. The lilo procedure is also
-  explained in the SCSI-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  You also need at least 512kB
-  of RAM cache if you have more than 64MB of RAM.
+  On high speed, long distance networks the performance limit on 
+  networking becomes the amount of data a machine can buffer until the
+  other end confirms its reception. (At 45Mbit/second there are a lot
+  of bits between New York and London ..). This option allows larger
+  amounts of data to be "in flight" at a given time. It also means a user
+  process can require a lot more memory for network buffers and thus this
+  option is best only used on machines with 16Mb of memory or higher. 
+  Unless you are using long links with end to end speeds of over 2Mbit
+  a second or   satellite links this option will make no difference to
+  performance.
 
 The IPX protocol
 CONFIG_IPX
@@ -1018,9 +1010,10 @@
 
 Appletalk DDP
 CONFIG_ATALK
-  Appletalk is the way Apple computers speak to each other on an
-  Ethernet (Apple calls it EtherTalk) network. If your linux box is
-  connected to such a network and you want to join the conversation,
+  Appletalk is the way Apple computers speak to each other on a
+  network. EtherTalk is the name used for appletalk over ethernet and
+  Localtalk is appletalk over the apple serial links. If your linux box 
+  is connected to such a network and you want to join the conversation,
   say Y. You will need to use the netatalk package so that your Linux
   box can act as a print and file server for macs as well as access
   appletalk printers. Check out
@@ -1034,6 +1027,10 @@
   want). If you want to compile it as a module, say M here and read
   Documentation/modules.txt. I hear that the GNU boycott of Apple is
   over, so even politically correct people are allowed to say Y here.
+  At the time the kernel is released the localtalk drivers are not
+  yet ready to ship. The kernel however supports localtalk and when
+  such drivers become available all you will need to do is download
+  and install the localtalk driver.
 
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
@@ -1044,24 +1041,22 @@
   use a low speed TNC (a Terminal Node Controller acts as a kind of
   modem connecting your computer's serial port to your radio's
   microphone input and speaker output) supporting the KISS protocol or
-  the much faster Ottawa PI card (to enable support for this card,
-  you'll have to answer Y to the question about ALPHA test drivers,
-  below) or the Z8530 SCC cards; the latter two require an additional
-  radio modem.  In order to use AX.25, you need to get a set of
-  supporting software tools via ftp (user: anonymous) from
-  sunacm.swan.ac.uk:/pub/misc/Linux/Radio/. A comprehensive listing of
-  all the software for Linux amateur radio users as well as
-  information about how to configure an AX.25 port is contained in the
-  HAM-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also want to check
-  out the file Documentation/networking/ax25.txt in the kernel
-  source. More information about digital amateur radio in general is
-  on the WWW at
+  the  various SCC cards that are supported by the Ottowa PI, the
+  Gracilis Packetwin and the generic Z8530 driver. 
+  At the moment there is no driver for the Baycom modem serial and parallel
+  port hacks although one is being written (see the HAM-HOWTO). The other
+  baycom cards (SCC) are supported by the Z8530 driver.
+  In order to use AX.25, you need to get a set of all the software for 
+  Linux amateur radio users as well as information about how to 
+  configure an AX.25 port is contained in the HAM-HOWTO, available via
+  ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You
+  might also want to check out the file Documentation/networking/ax25.txt
+  in the kernel source. More information about digital amateur radio
+  in general is on the WWW at  
   http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
   (To browse the WWW, you need to have access to a machine on the
   Internet that has one of the programs lynx, netscape or
-  Mosaic). AX.25 support is actively being developed, so it's best to
-  get the very latest 1.3 kernel if you intend to use this.
+  Mosaic). 
 
 Amateur Radio NET/ROM
 CONFIG_NETROM
@@ -1076,9 +1071,7 @@
   http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
   (To browse the WWW, you need to have access to a machine on the
   Internet that has one of the programs lynx, netscape or
-  Mosaic). Amateur radio support is actively being developed, so you
-  might want to get the very latest 1.3 kernel if you intend to use
-  this.
+  Mosaic). 
 
 AX.25 over Ethernet
 CONFIG_BPQETHER
@@ -1094,11 +1087,12 @@
   ethernet bridge, which means that the different ethernet segments it
   is connected to will appear as one ethernet to the
   participants. Several such bridges can work together to create even
-  larger networks of ethernets using a cool spanning tree
-  algorithm. Note that if your box acts as a bridge, it probably
-  contains several ethernet devices, but the kernel is not able to
-  recognize more than one at boot time without help; for details read
-  the Multiple-Ethernet-mini-HOWTO, available via ftp (user:
+  larger networks of ethernets using the IEEE802.1 spanning tree
+  algorithm. As this is a standard Linux bridges will interwork properly
+  with other third party bridge products. Note that if your box acts as 
+  a bridge, it probably contains several ethernet devices, but the kernel
+  is not able to recognize more than one at boot time without help; for 
+  details read the Multiple-Ethernet-mini-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The
   Bridging code is still in test. If unsure, say N.
   The bridge configuration tools are available via ftp from shadow.cabi.net.
@@ -1531,8 +1525,8 @@
 
 Dummy net driver support
 CONFIG_DUMMY
-  This is essentially a loopback device (i.e. traffic you send to this
-  device is immediately returned back to you) with a configurable IP
+  This is essentially a bit-bucket device (i.e. traffic you send to 
+  this device is consigned into oblivion) with a configurable IP
   address different from the usual 127.0.0.1. It is most commonly used
   in order to make your currently inactive SLIP address seem like a
   real address for local programs. If you use SLIP or PPP, you might
@@ -1592,6 +1586,14 @@
   RELCOM line fill and keepalive monitoring. Ideal on poor quality
   analogue lines.
 
+Six bit SLIP encapsulation
+CONFIG_SLIP_MODE_SLIP6
+  Just occasionally you may need to run IP over hostile serial networks that
+  don't pass all control characters or are only seven bit. This adds an
+  extra mode you can use with SLIP "slip6" which contains only the normal
+  ascii symbols. Its good enough, for example, to run IP over the async
+  ports of a Camtec JNT Pad.
+
 Radio network interfaces
 CONFIG_NET_RADIO
   Radio based interfaces for Linux. Both amateur radio (AX.25) and other
@@ -1651,13 +1653,10 @@
 
 WIC (Radio IP bridge)
 CONFIG_WIC
-  Don't know what this is; has something to do with the parallel
-  port. Say N and that's that. But if you want to compile it as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. :-)
+  Support for the WIC parallel port radio bridge. You'll probably want
+  to say N.
 
-Z8530 SCC kiss emulation driver for AX.2
+Z8530 SCC kiss emulation driver for AX.25
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
   and communicate with other computers.  If you want to use this, read
@@ -1765,6 +1764,10 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+Ethernet (10 or 100Mbit)
+CONFIG_NET_ETHERNET
+  Say yes if you want to select support for ethernet cards.
+
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
   This is support for lance ethernet cards on Sun workstations such as
@@ -1816,6 +1819,9 @@
   more than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  Important: There have been many reports that, with some motherboards
+  mixing an SMC Ultra and an Adaptec AHA1542 SCSI card causes corruption
+  problems with many operating systems.
 
 SMC 9194 Support
 CONFIG_SMC9194
@@ -1858,15 +1864,14 @@
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Also, consider buying a new
-  card, since the 3c501 is buggy and obsolete and the driver is
-  unsupported. This driver is also available as a module ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  card, since the 3c501 is slow and obsolete. This driver is also 
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as well
+  as Documentation/networking/net-modules.txt. If you plan to use more
+  than one network card under linux, read the 
+  Multiple-Ethernet-mini-HOWTO, available from 
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini - and don't use 3c501s.
 
 3c503 support
 CONFIG_EL2
@@ -2558,6 +2563,14 @@
   use it. Probably this is only useful for multi user systems. If
   unsure, say N.
 
+Mandatory lock support
+CONFIG_LOCK_MANDATORY
+  Mandatory locking is used by some System 5 style database applications.
+  To use this option safely you must have newer NFS daemons, new samba,
+  new netatalk, new mars-nwe and other file servers. At the time of 
+  writing none of these are available. Unless you need this feature say
+  N.
+  
 Standard (minix) fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about
diff -u --recursive --new-file pre2.0.2/linux/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
--- pre2.0.2/linux/Documentation/cdrom/cdrom-standard.tex	Sun May 12 22:54:22 1996
+++ linux/Documentation/cdrom/cdrom-standard.tex	Mon May 13 07:36:19 1996
@@ -1,5 +1,5 @@
 \documentclass{article}
-\def\version{$Id: cdrom-standard.tex,v 0.4 1996/04/17 20:46:34 david Exp $}
+\def\version{$Id: cdrom-standard.tex,v 0.5 1996/05/12 22:00:00 emoenke Exp $}
 
 \evensidemargin=0pt
 \oddsidemargin=0pt
@@ -29,26 +29,66 @@
 \item The large list of different hardware devices available for the popular
 IBM PC-architecture,
 \item The open design of the operating system, such that everybody can
-write a driver for Linux.
+write a driver for Linux (source code examples).
 \end{itemize}
 The vast choice and openness has lead not only to a wide support of
-hardware devices, but also to a certain divergence in
-behavior. Especially for \cdrom\ devices, the way a particular drive
-reacts to a `standard' $ioctl()$ call varies a lot from one brand
-to another. 
-
-Undoubtedly, this has a reason. Since the beginning of the \cdrom,
-many different interfaces developed. Most of them had proprietary
-interfaces, which means that a separate driver had to be written for
-each new type of interface. Nowadays, all new \cdrom\ types are either
-ATAPI/IDE or SCSI. But history has delivered us \cdrom\ support for
-some 10 or so different interfaces. Not all drives have the same
-capabilities, and all different interfaces use different i/o formats
-for the data. For the interfacing with the \linux\ operating system
-and software, this has lead to a rather wild set of commands and data
-formats. Presumably, every \cdrom\ device drive author has added his
-own set of ioctl commands and used a format reminiscent of the
-underlying hardware. Any structure is lost. 
+hardware devices, but also to a certain divergence in behavior. Especially
+for \cdrom\ devices, the way a particular drive reacts to a `standard'
+$ioctl()$ call varies a lot from one brand to another; until today, the
+\linux \cdrom\ driver writers kept away from wilderness by a good practice:
+to evolve a new driver by copying, understanding and changing an existing
+one.
+
+Since the beginning of the \cdrom, many different interfaces developed.
+Some of them had their own proprietary design (Sony, Mitsumi, Panasonic),
+other manufacturers adopted an existing electrical interface and changed
+the functionality (CreativeLabs/SoundBlaster, Teac, Funai) or simply adapted
+their drives to one or more of the already existing electrical interfaces
+(Aztech, Sanyo, Funai, Vertos, Longshine, Optics Storage and most of the
+`NoName' manufacturers).
+In cases where a new drive really brought his own interface or used his
+own command set and flow control scheme, either a separate driver had to
+be written, or an existing driver had to get enhanced.
+
+Nowadays, almost all new \cdrom\ types are either ATAPI/IDE or SCSI;
+it is very unlikely that any manufacturer still will create a new
+interface, and new drives for the existing proprietary interfaces are
+getting rare.
+But history has delivered us \cdrom\ support for many different interfaces.
+
+Some of the \linux\ \cdrom\ driver writers look at the existing standard
+which is expressed through <linux/cdrom.h> as to a rather wild set of
+commands and data formats and feel that any structure is lost, and from
+this point of view, this documentation shall help to achieve a common
+programming interface.
+ 
+Others - mainly those who used the already existing drivers not only as
+a coding example, but also as a `user interface' reference during their
+own development - have taken care that <linux/cdrom.h> reflects a
+software interface to `user programs' which is unique between all drivers
+as much as possible; these driver writers will continue to refine the
+existing <linux/cdrom.h> where it seems necessary, and they tend to look
+if any newly requested functionality isn't already there before they are
+ready to define new structures. The sbpcd driver gives an example that
+it is possible to let a robot arm play juke box - either with audio or
+with data CDs -, and that it is possible to let the juke box work on
+even if a disk has fallen upon the floor and the drive door has closed 
+without having a disk inside; without any new software layer or any
+structures which are not already present in <linux/cdrom.h>.
+This `other' group of \linux\ \cdrom\ driver writers explicitely does
+NOT support the idea to define an additional software layer between driver
+and user program.
+
+
+The following text reflects the opinion of the first mentioned \linux\ 
+\cdrom\ driver writer group only; the other group (not only the `silent
+majority') sees this text as a good base for a future documentation of the
+existing common \linux\ \cdrom\ programming interface, as it is stated 
+within <linux/cdrom.h>. Where <linux/cdrom.h> needs some external 
+explanation, this text can give it if the reader is aware that - at least
+at the moment - this text claims to be the proposal of something else than
+<linux/cdrom.h>.
+
 
 Apart from the somewhat unstructured interfacing with software, the
 actual execution of the commands is different for most of the
@@ -140,21 +180,21 @@
 \halign{$#$\ \hfil&$#$\ \hfil&\hbox to 10em{$#$\hss}&
   $/*$ \rm# $*/$\hfil\cr
 struct& cdrom_device_ops\ \{ \hidewidth\cr
-  &int& (* open)(dev_t, int)\cr
-  &void& (* release)(dev_t);\cr 
-  &int& (* open_files)(dev_t);  \cr
-  &int& (* drive_status)(dev_t);\cr     
-  &int& (* disc_status)(dev_t);\cr      
-  &int& (* media_changed)(dev_t);\cr 
-  &int& (* tray_move)(dev_t, int);\cr
-  &int& (* lock_door)(dev_t, int);\cr
-  &int& (* select_speed)(dev_t, int);\cr
-  &int& (* select_disc)(dev_t, int);\cr
-  &int& (* get_last_session) (dev_t, struct\ cdrom_multisession *{});\cr
-  &int& (* get_mcn)(dev_t, struct\ cdrom_mcn *{});\cr
-  &int& (* reset)(dev_t);\cr
-  &int& (* audio_ioctl)(dev_t, unsigned\ int, void *{});\cr 
-  &int& (* dev_ioctl)(dev_t, unsigned\ int, unsigned\ long);\cr
+  &int& (* open)(kdev_t, int)\cr
+  &void& (* release)(kdev_t);\cr 
+  &int& (* open_files)(kdev_t);  \cr
+  &int& (* drive_status)(kdev_t);\cr     
+  &int& (* disc_status)(kdev_t);\cr      
+  &int& (* media_changed)(kdev_t);\cr 
+  &int& (* tray_move)(kdev_t, int);\cr
+  &int& (* lock_door)(kdev_t, int);\cr
+  &int& (* select_speed)(kdev_t, int);\cr
+  &int& (* select_disc)(kdev_t, int);\cr
+  &int& (* get_last_session) (kdev_t, struct\ cdrom_multisession *{});\cr
+  &int& (* get_mcn)(kdev_t, struct\ cdrom_mcn *{});\cr
+  &int& (* reset)(kdev_t);\cr
+  &int& (* audio_ioctl)(kdev_t, unsigned\ int, void *{});\cr 
+  &int& (* dev_ioctl)(kdev_t, unsigned\ int, unsigned\ long);\cr
 \noalign{\medskip}
   &\llap{const\ }int& capability;&  capability flags \cr
   &int& mask;& mask of capability: disables them \cr
@@ -213,7 +253,7 @@
 command has completed, but of course waiting for the device should not
 use processor time.
 
-\subsection{$Open(dev_t\ dev, int\ purpose)$}
+\subsection{$Open(kdev_t\ dev, int\ purpose)$}
 
 $Open()$ should try to open the device for a specific $purpose$, which
 can be either:
@@ -235,7 +275,7 @@
 should only be concerned with proper initialization and device-use
 count.
 
-\subsection{$Release(dev_t\ dev)$}
+\subsection{$Release(kdev_t\ dev)$}
 
 The use-count of the device $dev$ should be decreased by 1, and a
 single call $MOD_DEC_USE_COUNT$ should be coded here.  Possibly other
@@ -245,14 +285,14 @@
 $cdrom_release()$. Also, the invalidation of the allocated buffers in
 the VFS is taken care of by the routine in \cdromc.
 
-\subsection{$Open_files(dev_t\ dev)$}
+\subsection{$Open_files(kdev_t\ dev)$}
 
 This function should return the internal variable use-count of the
 device $dev$. The use-count is not implemented in the routines in
 \cdromc\ itself, because there may be many minor devices connected to
 a single low-level driver.
 
-\subsection{$Drive_status(dev_t\ dev)$}
+\subsection{$Drive_status(kdev_t\ dev)$}
 \label{drive status}
 
 The function $drive_status$, if implemented, should provide
@@ -269,7 +309,7 @@
 }
 $$
 
-\subsection{$Disc_status(dev_t\ dev)$}
+\subsection{$Disc_status(kdev_t\ dev)$}
 \label{disc status}
 
 As a complement to $drive_status()$, this function can provide the
@@ -301,7 +341,7 @@
 separate queues for the VFS and a new $ioctl()$ function that can
 report device changes to software (e.g., an auto-mounting daemon). 
 
-\subsection{$Tray_move(dev_t\ dev, int\ position)$}
+\subsection{$Tray_move(kdev_t\ dev, int\ position)$}
 
 This function, if implemented, should control the tray movement. (No
 other function should control this.) The parameter $position$ controls
@@ -314,7 +354,7 @@
 error. Note that if the tray is already in the desired position, no
 action need be taken, and the return value should be 0. 
 
-\subsection{$Lock_door(dev_t\ dev, int\ lock)$}
+\subsection{$Lock_door(kdev_t\ dev, int\ lock)$}
 
 This function (and no other code) controls locking of the door, if the
 drive allows this. The value of $lock$ controls the desired locking
@@ -325,7 +365,7 @@
 \end{itemize}
 Return values are as for $tray_move()$.
 
-\subsection{$Select_speed(dev_t\ dev, int\ speed)$}
+\subsection{$Select_speed(kdev_t\ dev, int\ speed)$}
 
 Although none of the drivers has implemented this function so far,
 some drives are capable of head-speed selection, and hence this is a
@@ -341,7 +381,7 @@
 high-speed copying of audio tracks). Badly pressed \cdrom s may
 benefit from less-than-maximum head rate.
 
-\subsection{$Select_disc(dev_t\ dev, int\ number)$}
+\subsection{$Select_disc(kdev_t\ dev, int\ number)$}
 
 If the drive can store multiple discs (a juke-box), it is likely that
 a disc selection can be made by software. This function should perform
@@ -350,7 +390,7 @@
 \cdrom\ drivers appears to support such functionality, but it is defined
 here for future purposes.
 
-\subsection{$Get_last_session(dev_t\ dev, struct\ cdrom_multisession *
+\subsection{$Get_last_session(kdev_t\ dev, struct\ cdrom_multisession *
 ms_info)$}
 
 This function should implement the old corresponding $ioctl()$. For
@@ -364,7 +404,7 @@
 field appropriately, of course) and the routines in \cdromc\ will make
 the transform if necessary. The return value is 0 upon success.
 
-\subsection{$Get_mcn(dev_t\ dev, struct\ cdrom_mcn * mcn)$}
+\subsection{$Get_mcn(kdev_t\ dev, struct\ cdrom_mcn * mcn)$}
 
 Some discs carry a `Media Catalog Number' (MCN), also called
 `Universal Product Code' (UPC). This number should reflect the number that
@@ -374,14 +414,14 @@
 pre-declared memory region of type $struct\ cdrom_mcn$. The MCN is
 expected as a 13-character string, terminated by a null-character.
 
-\subsection{$Reset(dev_t dev)$}
+\subsection{$Reset(kdev_t dev)$}
 
 This call should implement hard-resetting the drive (although in
 circumstances that a hard-reset is necessary, a drive may very well
 not listen to commands anymore). Preferably, control is returned to the
 caller only after the drive has finished resetting.
 
-\subsection{$Audio_ioctl(dev_t\ dev, unsigned\ int\ cmd, void *
+\subsection{$Audio_ioctl(kdev_t\ dev, unsigned\ int\ cmd, void *
 arg)$}
 
 Some of the \cdrom-$ioctl$s defined in {\tt cdrom.h} can be
@@ -405,7 +445,7 @@
 may decide to sanitize the return value in $cdrom_ioctl()$, in order
 to guarantee a uniform interface to the audio-player software.)
 
-\subsection{$Dev_ioctl(dev_t\ dev, unsigned\ int\ cmd, unsigned\ long\
+\subsection{$Dev_ioctl(kdev_t\ dev, unsigned\ int\ cmd, unsigned\ long\
 arg)$}
 
 Some $ioctl$s seem to be specific to certain \cdrom\ drives. That is,
@@ -772,12 +812,6 @@
 
 \subsection{How to update your driver}
 
-We hope all \cdrom\ driver maintainers will understand the advantages
-of re-routing the interface to the kernel though the new routines in
-\cdromc. The following scheme should help you to update your
-driver. It should not be too much work. We hope you want to take these
-steps, in order to make the \linux\ \cdrom\ support more uniform and
-more flexible.
 \begin{enumerate}
 \item Make a backup of your current driver. 
 \item Get hold of the files \cdromc\ and \ucdrom, they should be in
diff -u --recursive --new-file pre2.0.2/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- pre2.0.2/linux/Documentation/devices.tex	Sat May 11 10:42:04 1996
+++ linux/Documentation/devices.tex	Mon May 13 07:16:49 1996
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: May 9, 1996}
+\date{Last revised: May 12, 1996}
 \maketitle
 %
 \noindent
@@ -61,9 +61,10 @@
 /pub/linux/docs/linux-standards/fsstnd}.
 
 To have a major number allocated, or a minor number in situations
-where that applies (e.g.\ busmice), please contact me.  Also, if you
-have additional information regarding any of the devices listed below,
-or if I have made a mistake, I would greatly appreciate a note.
+where that applies (e.g.\ busmice), please contact me with the
+appropriate device information.  Also, if you have additional
+information regarding any of the devices listed below, or if I have
+made a mistake, I would greatly appreciate a note.
 
 Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
 platform only.  Allocations marked (68k/Atari) apply to Linux/68k on
@@ -389,13 +390,38 @@
 
 \begin{devicelist}
 \major{ 9}{}{char }{SCSI tape devices}
-	\minor{0}{/dev/st0}{First SCSI tape}
-	\minor{1}{/dev/st1}{Second SCSI tape}
+	\minor{0}{/dev/st0}{First SCSI tape, mode 0}
+	\minor{1}{/dev/st1}{Second SCSI tape, mode 0}
 	\minordots
-	\minor{128}{/dev/nst0}{First SCSI tape, no rewind-on-close}
-	\minor{129}{/dev/nst1}{Second SCSI tape, no rewind-on-close}
+	\minor{32}{/dev/st0l}{First SCSI tape, mode 1}
+	\minor{33}{/dev/st1l}{Second SCSI tape, mode 1}
 	\minordots
-\\
+	\minor{64}{/dev/st0m}{First SCSI tape, mode 2}
+	\minor{65}{/dev/st1m}{Second SCSI tape, mode 2}
+	\minordots
+	\minor{96}{/dev/st0a}{First SCSI tape, mode 3}
+	\minor{97}{/dev/st1a}{Second SCSI tape, mode 4}
+	\minordots
+	\minor{128}{/dev/nst0}{First SCSI tape, mode 0, no rewind}
+	\minor{129}{/dev/nst1}{Second SCSI tape, mode 0, no rewind}
+	\minordots
+	\minor{160}{/dev/nst0l}{First SCSI tape, mode 1, no rewind}
+	\minor{161}{/dev/nst1l}{Second SCSI tape, mode 1, no rewind}
+	\minordots
+	\minor{192}{/dev/nst0m}{First SCSI tape, mode 2, no rewind}
+	\minor{193}{/dev/nst1m}{Second SCSI tape, mode 2, no rewind}
+	\minordots
+	\minor{224}{/dev/nst0a}{First SCSI tape, mode 3, no rewind}
+	\minor{225}{/dev/nst1a}{Second SCSI tape, mode 3, no rewind}
+	\minordots
+\end{devicelist}
+
+\noindent
+``No rewind'' refers to the omission of the default automatic rewind
+on device close.  The {\file MTREW} or {\file MTOFFL} ioctl()s can be
+used to rewind the tape regardless of the device used to access it.
+
+\begin{devicelist}
 \major{  }{}{block}{Metadisk (RAID) devices}
 	\minor{0}{/dev/md0}{First metadisk group}
 	\minor{1}{/dev/md1}{Second metadisk group}
diff -u --recursive --new-file pre2.0.2/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- pre2.0.2/linux/Documentation/devices.txt	Sat May 11 10:42:04 1996
+++ linux/Documentation/devices.txt	Mon May 13 07:16:49 1996
@@ -2,7 +2,7 @@
 
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		      Last revised: May 9, 1996
+		      Last revised: May 12, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -18,9 +18,10 @@
 tsx-11.mit.edu in the directory /pub/linux/docs/linux-standards/fsstnd.
 
 To have a major number allocated, or a minor number in situations
-where that applies (e.g. busmice), please contact me.  Also, if you
-have additional information regarding any of the devices listed below,
-or if I have made a mistake, I would greatly appreciate a note.
+where that applies (e.g. busmice), please contact me with the
+appropriate device information.  Also, if you have additional
+information regarding any of the devices listed below, or if I have
+made a mistake, I would greatly appreciate a note.
 
 Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
 platform only.  Allocations marked (68k/Atari) apply to Linux/68k on
@@ -214,12 +215,36 @@
 		partitions is 15.
 
   9 char	SCSI tape devices
-    		  0 = /dev/st0		First SCSI tape
-		  1 = /dev/st1		Second SCSI tape
+    		  0 = /dev/st0		First SCSI tape, mode 0
+		  1 = /dev/st1		Second SCSI tape, mode 0
 		      ...
-		128 = /dev/nst0		First SCSI tape, no rewind-on-close
-		129 = /dev/nst1		Second SCSI tape, no rewind-on-close
+    		 32 = /dev/st0l		First SCSI tape, mode 1
+		 33 = /dev/st1l		Second SCSI tape, mode 1
 		      ...
+    		 64 = /dev/st0m		First SCSI tape, mode 2
+		 65 = /dev/st1m		Second SCSI tape, mode 2
+		      ...
+    		 96 = /dev/st0a		First SCSI tape, mode 3
+		 97 = /dev/st1a		Second SCSI tape, mode 3
+		      ...
+		128 = /dev/nst0		First SCSI tape, mode 0, no rewind
+		129 = /dev/nst1		Second SCSI tape, mode 0, no rewind
+		      ...
+		160 = /dev/nst0l	First SCSI tape, mode 1, no rewind
+		161 = /dev/nst1l	Second SCSI tape, mode 1, no rewind
+		      ...
+		192 = /dev/nst0m	First SCSI tape, mode 2, no rewind
+		193 = /dev/nst1m	Second SCSI tape, mode 2, no rewind
+		      ...
+		224 = /dev/nst0a	First SCSI tape, mode 3, no rewind
+		225 = /dev/nst1a	Second SCSI tape, mode 3, no rewind
+		      ...
+
+		"No rewind" refers to the omission of the default
+		automatic rewind on device close.  The MTREW or MTOFFL
+		ioctl()'s can be used to rewind the tape regardless of
+		the device used to access it.
+
     block	Metadisk (RAID) devices
 		  0 = /dev/md0		First metadisk group
 		  1 = /dev/md1		Second metadisk group
diff -u --recursive --new-file pre2.0.2/linux/Documentation/java.txt linux/Documentation/java.txt
--- pre2.0.2/linux/Documentation/java.txt	Sun May 12 10:16:06 1996
+++ linux/Documentation/java.txt	Mon May 13 07:17:23 1996
@@ -1,5 +1,5 @@
-               JAVA Binary Kernel Support for Linux v1.01
-               ------------------------------------------
+               Java(tm) Binary Kernel Support for Linux v1.01
+               ----------------------------------------------
 
 Linux beats them ALL! While all other OS's are TALKING about direct
 support of Java Binaries in the OS, Linux is doing it!
@@ -14,9 +14,15 @@
 		ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO
 
 	   If you install the JDK in a location other than the suggested
-	   directory of /usr/local/java, then you will need to edit the
-	   kernel's fs/binfmt_java.c file and make the needed change to the
-	   _PATH_JAVA definition at the top of that file.
+	   directory of /usr/local/java, then you will need to tell the
+	   kernel where you put the Java interpreter.  
+           There are two ways to do this.
+           One, edit fs/binfmt_java.c file and make the needed change to 
+	   the _PATH_JAVA definition at the top of that file.  
+           Two, as root, issue the command:
+	 echo "/path/to/java/interpreter" > /proc/sys/kernel/java-interpreter
+	   (Currently, this does not work if you're using a module for
+	    Java support.)
 
 	2) You must chmod the '*.class' files you wish to execute with
 	   the execute bit. This is not normally (till now) done with
@@ -30,7 +36,6 @@
 	   as a loadable module. If a module, load it with insmod or
 	   kerneld.
 
-
 To test your new setup, enter in the following simple Java app, and name
 it "HelloWorld.java":
 
@@ -75,9 +80,15 @@
 	   with all known browsers.
 
 	2) If you install the JDK in a location other than the suggested
-	   directory of /usr/local/java, then you will need to edit the
-	   kernel's fs/binfmt_java.c file and make the needed change to the
-	   _PATH_APPLET definition at the top of that file.
+	   directory of /usr/local/java, then you will need to tell the
+	   kernel where you put the Java appletviewer.  
+           There are two ways to do this.
+           One, edit fs/binfmt_java.c file and make the needed change to 
+	   the _PATH_APPLET definition at the top of that file.  
+           Two, as root, issue the command:
+	echo "/path/to/java/appletviewer" > /proc/sys/kernel/java-appletviewer
+	   (Currently, this does not work if you're using a module for
+	    Java support.)
 
 	3) You must chmod the '*.html' files you wish to execute with
 	   the execute bit. This is not normally (till now) done with
@@ -86,6 +97,7 @@
 	4) And then execute it.
 
 
-
 Brian A. Lantz
 brian@lantz.com
+(/proc/sys/kernel/java-* support by Mike Shaver (shaver@ingenia.com))
+
diff -u --recursive --new-file pre2.0.2/linux/Documentation/svga.txt linux/Documentation/svga.txt
--- pre2.0.2/linux/Documentation/svga.txt	Mon Apr 15 12:20:16 1996
+++ linux/Documentation/svga.txt	Mon May 13 12:58:55 1996
@@ -1,4 +1,4 @@
-			Video Mode Selection Support 2.7
+			Video Mode Selection Support 2.9
 	      (c) 1995, 1996 Martin Mares, <mj@k332.feld.cvut.cz>
 --------------------------------------------------------------------------------
 
@@ -243,3 +243,4 @@
 		- Screen store/restore fixed.
 2.8 (14-Apr-96)	- Previous release was not compilable without CONFIG_VIDEO_SVGA.
 		- Better recognition of text modes during mode scan.
+2.9 (12-May-96)	- Ignored VESA modes 0x80 - 0xff (more VESA BIOS bugs!)
diff -u --recursive --new-file pre2.0.2/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt
--- pre2.0.2/linux/Documentation/watchdog.txt	Tue Mar 12 13:37:56 1996
+++ linux/Documentation/watchdog.txt	Mon May 13 07:17:23 1996
@@ -2,14 +2,14 @@
 
 		Alan Cox <alan@lxorguk.ukuu.org.uk>
 
-	    Custom Linux Driver And Program Development
+	     Custom Linux Driver And Program Development
 
 
 The following watchdog drivers are currently implemented:
 
-	IMS	WDT501-P
-	INS	WDT501-P (no fan tachometer)
-	IMS	WDT500-P
+	ICS	WDT501-P
+	ICS	WDT501-P (no fan tachometer)
+	ICS	WDT500-P
 	Software Only
 
 All four interfaces provide /dev/watchdog, which when open must be written
@@ -40,6 +40,7 @@
 Overheat           X               o                o
 
 The external event interfaces on the WDT boards are not currently supported.
+Minor numbers are however allocated for it.
 
 
 Example Watchdog Driver
@@ -65,11 +66,17 @@
 }
 
 
-> People keep asking about the WDT watchdog timer hardware: The phone contacts
-> for Industrial Computer Source are:
-> 
-> US: 619 677 0898 (sales)  0895 (general)
-> UK: 01243 533900
-> France (1) 69.18.74.30
-> 
-> and please mention Linux when enquiring.
+Contact Information
+
+People keep asking about the WDT watchdog timer hardware: The phone contacts
+for Industrial Computer Source are:
+ 
+US: 619 677 0877 (sales)  0895 (fax)
+UK: 01243 533900
+France (1) 69.18.74.30
+
+Industrial Computer Source 
+9950 Barnes Canyon Road 
+San Diego, CA     
+
+and please mention Linux when enquiring.
diff -u --recursive --new-file pre2.0.2/linux/Makefile linux/Makefile
--- pre2.0.2/linux/Makefile	Sun May 12 22:54:22 1996
+++ linux/Makefile	Mon May 13 13:21:39 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 2
+SUBLEVEL = 3
 
 ARCH = i386
 
diff -u --recursive --new-file pre2.0.2/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- pre2.0.2/linux/arch/alpha/defconfig	Sat May 11 10:42:04 1996
+++ linux/arch/alpha/defconfig	Mon May 13 13:28:14 1996
@@ -69,7 +69,6 @@
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
 # CONFIG_NO_PATH_MTU_DISCOVERY is not set
-# CONFIG_TCP_NAGLE_OFF is not set
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 
@@ -164,6 +163,7 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_LOCK_MANDATORY is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -u --recursive --new-file pre2.0.2/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- pre2.0.2/linux/arch/i386/boot/video.S	Mon Apr 15 12:20:17 1996
+++ linux/arch/i386/boot/video.S	Mon May 13 12:58:55 1996
@@ -1,5 +1,5 @@
 !
-!	Display adapter & video mode setup, version 2.8 (14-Apr-96)
+!	Display adapter & video mode setup, version 2.9 (12-May-96)
 !
 !	Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
 !	Based on the original setup.S code (C) Linus Torvalds
@@ -879,8 +879,8 @@
 	jz	vesar
 	cmp	ax,#0x0080	! Check validity of mode ID
 	jc	vesa2
-	or	ah,ah		! Valid ID's are 0x0000-0x007f
-	jz	vesae		! and 0x0100-0x07ff.
+	or	ah,ah		! Valid ID's are 0x0000-0x007f and 0x0100-0x07ff
+	jz	vesan		! [Certain BIOSes errorneously report 0x80-0xff]
 	cmp	ax,#0x0800
 	jnc	vesae
 vesa2:	push	cx
diff -u --recursive --new-file pre2.0.2/linux/arch/i386/config.in linux/arch/i386/config.in
--- pre2.0.2/linux/arch/i386/config.in	Sat May 11 10:42:04 1996
+++ linux/arch/i386/config.in	Mon May 13 07:17:23 1996
@@ -33,7 +33,9 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+fi
 bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
 
 choice 'Processor type' \
diff -u --recursive --new-file pre2.0.2/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- pre2.0.2/linux/arch/i386/defconfig	Sat May 11 10:42:04 1996
+++ linux/arch/i386/defconfig	Mon May 13 13:00:32 1996
@@ -24,7 +24,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_JAVA is not set
 CONFIG_KERNEL_ELF=y
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
@@ -69,7 +68,6 @@
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
 # CONFIG_NO_PATH_MTU_DISCOVERY is not set
-# CONFIG_TCP_NAGLE_OFF is not set
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 
@@ -124,6 +122,7 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_LOCK_MANDATORY is not set
 CONFIG_MINIX_FS=y
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -u --recursive --new-file pre2.0.2/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- pre2.0.2/linux/arch/i386/kernel/smp.c	Tue May  7 16:22:17 1996
+++ linux/arch/i386/kernel/smp.c	Mon May 13 07:17:23 1996
@@ -534,8 +534,10 @@
  
 void smp_callin(void)
 {
+	extern void calibrate_delay(void);
 	int cpuid=GET_APIC_ID(apic_read(APIC_ID));
 	unsigned long l;
+	
 	/*
 	 *	Activate our APIC
 	 */
diff -u --recursive --new-file pre2.0.2/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- pre2.0.2/linux/drivers/block/genhd.c	Sat Apr 27 15:19:50 1996
+++ linux/drivers/block/genhd.c	Mon May 13 07:36:19 1996
@@ -213,7 +213,7 @@
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See extended_partition() for more information.
  */
-static void bsd_disklabel_partition(struct gendisk *hd, int dev)
+static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev)
 {
 	struct buffer_head *bh;
 	struct bsd_disklabel *l;
@@ -470,7 +470,7 @@
 
 #ifdef CONFIG_SUN_PARTITION
 
-static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
+static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
 	int i, csum;
 	unsigned short *ush;
@@ -512,13 +512,15 @@
 				 : (__u32)(x))
 
 	if(!(bh = bread(dev, 0, 1024))) {
-		printk("Dev %d: unable to read partition table\n", dev);
+		printk("Dev %s: unable to read partition table\n",
+		       kdevname(dev));
 		return -1;
 	}
 	label = (struct sun_disklabel *) bh->b_data;
 	p = label->partitions;
 	if (label->magic != SUN_LABEL_MAGIC && label->magic != SUN_LABEL_MAGIC_SWAPPED) {
-		printk("Dev %d Sun disklabel: bad magic %04x\n", dev, label->magic);
+		printk("Dev %s Sun disklabel: bad magic %04x\n",
+		       kdevname(dev), label->magic);
 		brelse(bh);
 		return 0;
 	}
@@ -528,7 +530,8 @@
 	for(csum = 0; ush >= ((unsigned short *) label);)
 		csum ^= *ush--;
 	if(csum) {
-		printk("Dev %d Sun disklabel: Csum bad, label corrupted\n", dev);
+		printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
+		       kdevname(dev));
 		brelse(bh);
 		return 0;
 	}
diff -u --recursive --new-file pre2.0.2/linux/drivers/block/linear.c linux/drivers/block/linear.c
--- pre2.0.2/linux/drivers/block/linear.c	Sun Apr 21 19:22:02 1996
+++ linux/drivers/block/linear.c	Mon May 13 07:36:19 1996
@@ -128,7 +128,8 @@
     tmp_dev=hash->dev0;
     
   if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset)
-    printk ("Block %ld out of bounds on dev %04x size %d offset %d\n", block, tmp_dev->dev, tmp_dev->size, tmp_dev->offset);
+    printk ("Block %ld out of bounds on dev %s size %d offset %d\n",
+	    block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset);
   
   *rdev=tmp_dev->dev;
   *rsector=(block-(tmp_dev->offset)) << 1;
diff -u --recursive --new-file pre2.0.2/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- pre2.0.2/linux/drivers/cdrom/cdrom.c	Sun May 12 22:54:22 1996
+++ linux/drivers/cdrom/cdrom.c	Mon May 13 07:39:35 1996
@@ -28,7 +28,7 @@
 void cdrom_release(struct inode *ip, struct file *fp);
 int cdrom_ioctl(struct inode *ip, struct file *fp,
 				unsigned int cmd, unsigned long arg);
-int cdrom_media_changed(dev_t dev);
+int cdrom_media_changed(kdev_t dev);
 
 struct file_operations cdrom_fops =
 {
@@ -107,11 +107,11 @@
  * is in their own interest: device control becomes a lot easier
  * this way.
  */
-int open_for_data(struct cdrom_device_ops *, int);
+int open_for_data(struct cdrom_device_ops *, kdev_t);
 
 int cdrom_open(struct inode *ip, struct file *fp)
 {
-        dev_t dev = ip->i_rdev;
+	kdev_t dev = ip->i_rdev;
         struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
         int purpose = !!(fp->f_flags & O_NONBLOCK);
 
@@ -126,7 +126,7 @@
                 return open_for_data(cdo, dev);
 }
 
-int open_for_data(struct cdrom_device_ops * cdo, int dev)
+int open_for_data(struct cdrom_device_ops * cdo, kdev_t dev)
 {
         int ret;
         if (cdo->drive_status != NULL) {
@@ -163,7 +163,7 @@
 /* Admittedly, the logic below could be performed in a nicer way. */
 void cdrom_release(struct inode *ip, struct file *fp)
 {
-        dev_t dev = ip->i_rdev;
+        kdev_t dev = ip->i_rdev;
         struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
 	
         if (cdo == NULL || MINOR(dev) >= cdo->minors)
@@ -192,7 +192,7 @@
  * in the lower 16 bits, queue 1 in the higher 16 bits.
  */
 
-int media_changed(dev_t dev, int queue)
+int media_changed(kdev_t dev, int queue)
 {
         unsigned int major = MAJOR(dev);
         unsigned int minor = MINOR(dev);
@@ -212,7 +212,7 @@
         return ret;
 }
 
-int cdrom_media_changed(dev_t dev)
+int cdrom_media_changed(kdev_t dev)
 {
         struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
         if (cdo == NULL || MINOR(dev) >= cdo->minors)
@@ -290,7 +290,7 @@
 int cdrom_ioctl(struct inode *ip, struct file *fp,
                 unsigned int cmd, unsigned long arg)
 {
-        dev_t dev = ip->i_rdev;
+        kdev_t dev = ip->i_rdev;
         struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
 
         if (cdo == NULL || MINOR(dev) >= cdo->minors)
diff -u --recursive --new-file pre2.0.2/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- pre2.0.2/linux/drivers/cdrom/cm206.c	Sun May 12 22:54:22 1996
+++ linux/drivers/cdrom/cm206.c	Mon May 13 07:40:53 1996
@@ -580,7 +580,7 @@
 
 /* The new open. The real opening strategy is defined in cdrom.c. */
 
-static int cm206_open(dev_t dev, int purpose) 
+static int cm206_open(kdev_t dev, int purpose) 
 {
   if (!cd->openfiles) {		/* reset only first time */
     cd->background=0;
@@ -593,7 +593,7 @@
   return 0;
 }
 
-static void cm206_release(dev_t dev)
+static void cm206_release(kdev_t dev)
 {
   if (cd->openfiles==1) {
     if (cd->background) {
@@ -885,7 +885,7 @@
  * upon success. Memory checking has been done by cdrom_ioctl(), the
  * calling function, as well as LBA/MSF sanitization.
 */
-int cm206_audio_ioctl(dev_t dev, unsigned int cmd, void * arg)
+int cm206_audio_ioctl(kdev_t dev, unsigned int cmd, void * arg)
 {
   switch (cmd) {
   case CDROMREADTOCHDR: 
@@ -930,7 +930,7 @@
    some driver statistics accessible through ioctl calls.
  */
 
-static int cm206_ioctl(dev_t dev, unsigned int cmd, unsigned long arg)
+static int cm206_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
 {
   switch (cmd) {
 #ifdef STATISTICS
@@ -947,7 +947,7 @@
   }
 }     
 
-int cm206_media_changed(dev_t dev) 
+int cm206_media_changed(kdev_t dev) 
 {
   if (cd != NULL) {
     int r;
@@ -963,14 +963,14 @@
    the logic should be in cdrom.c */
 
 /* returns number of times device is in use */
-int cm206_open_files(dev_t dev)	
+int cm206_open_files(kdev_t dev)	
 {
   if (cd) return cd->openfiles;
   return -1;
 }
 
 /* controls tray movement */
-int cm206_tray_move(dev_t dev, int position) 
+int cm206_tray_move(kdev_t dev, int position) 
 {
   if (position) {		/* 1: eject */
     type_0_command(c_open_tray,1);
@@ -981,7 +981,7 @@
 }
 
 /* gives current state of the drive */
-int cm206_drive_status(dev_t dev)
+int cm206_drive_status(kdev_t dev)
 {
   get_drive_status();
   if (cd->dsb & dsb_tray_not_closed) return CDS_TRAY_OPEN;
@@ -991,7 +991,7 @@
 }
  
 /* gives current state of disc in drive */
-int cm206_disc_status(dev_t dev)
+int cm206_disc_status(kdev_t dev)
 {
   uch xa;
   get_drive_status();
@@ -1009,7 +1009,7 @@
 }
 
 /* locks or unlocks door lock==1: lock; return 0 upon success */
-int cm206_lock_door(dev_t dev, int lock)
+int cm206_lock_door(kdev_t dev, int lock)
 {
   uch command = (lock) ? c_lock_tray : c_unlock_tray;
   type_0_command(command, 1);	/* wait and get dsb */
@@ -1020,7 +1020,7 @@
 /* Although a session start should be in LBA format, we return it in 
    MSF format because it is slightly easier, and the new generic ioctl
    will take care of the necessary conversion. */
-int cm206_get_last_session(dev_t dev, struct cdrom_multisession * mssp) 
+int cm206_get_last_session(kdev_t dev, struct cdrom_multisession * mssp) 
 {
   if (!FIRST_TRACK) get_disc_status();
   if (mssp != NULL) {
@@ -1038,7 +1038,7 @@
   return 0;
 }
 
-int cm206_get_upc(dev_t dev, struct cdrom_mcn * mcn)
+int cm206_get_upc(kdev_t dev, struct cdrom_mcn * mcn)
 {
   uch upc[10];
   char * ret = mcn->medium_catalog_number;
@@ -1054,7 +1054,7 @@
   return 0;
 } 
 
-int cm206_reset(dev_t dev)
+int cm206_reset(kdev_t dev)
 {
   stop_read();
   reset_cm260();
diff -u --recursive --new-file pre2.0.2/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- pre2.0.2/linux/drivers/cdrom/mcdx.c	Fri Apr 12 15:51:51 1996
+++ linux/drivers/cdrom/mcdx.c	Mon May 13 12:44:08 1996
@@ -1,16 +1,7 @@
 /*
  * The Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.9
- *
- ****************** 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, Please --
- * mail me (heiko@lotte.sax.de).  When my last drive goes 
- * ballistic no more driver support will be available from me !!!
- *************************************************************
- *
+ * VERSION: 2.2
  * 
  * 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
@@ -38,14 +29,14 @@
  *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
  *  Andreas Kies (testing the mysterious hang up's)
  *  ... 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.)
  */
-
-
-#if RCS
-static const char *mcdx_c_version
-		= "mcdx.c,v 1.2 1996/03/22 01:14:59 heiko Exp";
-#endif
+#define VERSION "2.2"
 
 #include <linux/version.h>
 #include <linux/module.h>
@@ -63,202 +54,152 @@
 #include <asm/io.h>
 #include <asm/segment.h>
 
-
 #include <linux/major.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>
 
-#ifndef HZ 
-#error HZ not defined
-#endif
-
-/* CONSTANTS *******************************************************/
+#define REQUEST_SIZE	200
+#define DIRECT_SIZE	200
 
-const int REQUEST_SIZE = 200;
-const int DIRECT_SIZE = 200;
-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_msf {
-	unsigned char minute;
-	unsigned char second;
-	unsigned char frame;
+enum drivemodes {
+	TOC, DATA, RAW, COOKED
 };
 
+#define	MODE0 		0x00
+#define MODE1 		0x01
+#define MODE2 		0x02
+
+#define DOOR_LOCK 	0x01
+#define DOOR_UNLOCK 	0x00
+
+/*
+ * Structs used to gather info reported by the drive.
+ */
+
 struct s_subqcode {
-	unsigned char control;
-	unsigned char tno;
-	unsigned char index;
-	struct s_msf tt;
-	struct s_msf dt;
+	u_char adr:4;
+	u_char ctrl:4;
+	u_char tno;
+	u_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 s_msf msf_leadout;
-	struct s_msf msf_first;
-};
-	
 struct s_multi {
 	unsigned char multi;
-	struct s_msf msf_last;
+	struct cdrom_msf0 msf_last;
 };
 
-struct s_version {
-	unsigned char code;
-	unsigned char ver;
+struct s_play {
+	struct cdrom_msf0 start;
+	struct cdrom_msf0 stop;
 };
 
-/* Per drive/controller stuff **************************************/
+/* 
+ * Per drive/controller stuff.
+ */
 
 struct s_drive_stuff {
-	/* waitqueues */
-    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) */
-    
+	struct wait_queue *busyq;
+	
+	/* flags */
+	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;	/* multisession capable */
+	u_char double_speed:1;	/* double speed drive */
+
 	/* cd infos */
-	struct s_diskinfo di;
+	unsigned int n_first;
+	unsigned int n_last;
+	struct cdrom_msf0 msf_leadout;
 	struct s_multi multi;
-	struct s_subqcode* toc;	/* first entry 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;			
+
+	struct s_subqcode *toc;	/* first entry of the toc array */
+	struct s_play resume;	/* where to resume after pause */
+
+	int audiostatus;
 
 	/* `buffer' control */
-    volatile int valid;
-    volatile int pending;
-    volatile int off_direct;
-    volatile int off_requested;
-
-	/* 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 */
+	unsigned int valid:1;
+	int pending;
+	int off_direct;
+	int off_requested;
+
+	int irq;		/* irq used by this drive */
+	unsigned int base;	/* base for all registers of the drive */
+	int users;		/* keeps track of open/close */
+	int lastsector;		/* last accessible blocks */
 };
 
+/*
+ * Macros for accessing interface registers
+ */
 
-/* Prototypes ******************************************************/ 
-
-/*	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. */
+#define DATA_REG	(stuffp->base)
+#define RESET_REG	(stuffp->base+1)
+#define STAT_REG	(stuffp->base+1)
+#define CHAN_REG	(stuffp->base+3)
 
-/* declared in blk.h */
+/* 
+ * 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);
-
-/* misc internal support functions */
-static void log2msf(unsigned int, struct s_msf*);
-static unsigned int msf2log(const struct s_msf*);
-static unsigned int uint2bcd(unsigned int);
-static unsigned int bcd2uint(unsigned char);
-#if MCDX_DEBUG
-static void TRACE((int level, const char* fmt, ...));
-#endif
-static void warn(const char* fmt, ...);
-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);
+/*      
+ * 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 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_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 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() */
@@ -266,1591 +207,1191 @@
 	mcdx_open,		/* open() */
 	mcdx_close,		/* close() */
 	NULL,			/* fsync */
-	NULL,                   /* fasync */
-	check_mcdx_media_change, /* media_change */
-	NULL                    /* revalidate */
+	NULL,			/* fasync */
+	mcdx_media_change,	/* media_change */
+	NULL			/* revalidate */
 };
 
-/* KERNEL INTERFACE FUNCTIONS **************************************/ 
+/*     
+ * Misc number converters 
+ */
 
-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 bcd2uint(unsigned char c)
+{
+	return (c >> 4) * 10 + (c & 0x0f);
+}
 
-	if (!stuffp->present) return -ENXIO;
-	if (!ip) return -EINVAL;
+static unsigned int uint2bcd(unsigned int ival)
+{
+	return ((ival / 10) << 4) | (ival % 10);
+}
 
-	switch (cmd) {
-		case CDROMSTART: {
-			TRACE((IOCTL, "ioctl() START\n"));
-			return 0;
-		}
+static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
+{
+	return bcd2uint(pmsf->frame)
+	    + bcd2uint(pmsf->second) * 75
+	    + bcd2uint(pmsf->minute) * 4500
+	    - CD_BLOCK_OFFSET;
+}
 
-		case CDROMSTOP: {
-			TRACE((IOCTL, "ioctl() STOP\n"));
-            stuffp->audiostatus = CDROM_AUDIO_INVALID;
-			if (-1 == mcdx_stop(stuffp, 1))
-				return -EIO;
-			return 0;
-		}
+/*      
+ * Access to elements of the mcdx_drive_map members 
+ */
+static inline unsigned int port(int *ip)
+{
+	return (unsigned int) ip[0];
+}
 
-		case CDROMPLAYTRKIND: {
-			int ans;
-			struct cdrom_ti ti;
+static inline int irq(int *ip)
+{
+	return ip[1];
+}
 
-			TRACE((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;
-            TRACE((PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
-
-            return mcdx_playtrk(stuffp, &ti);
-        }
-
-        case CDROMPLAYMSF: {
-            int ans;
-            struct cdrom_msf msf;
-
-            TRACE((IOCTL, "ioctl() PLAYMSF\n"));
-
-            if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
-                && (-1 == mcdx_hold(stuffp, 1))) return -EIO;
-
-            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);
-
-            msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
-            msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
-            msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
-
-            return mcdx_playmsf(stuffp, &msf);
-        }
-
-        case CDROMRESUME: {
-            TRACE((IOCTL, "ioctl() RESUME\n"));
-            return mcdx_playtrk(stuffp, NULL);
-        }
-
-		case CDROMREADTOCENTRY: {
-			struct cdrom_tocentry entry;
-			struct s_subqcode *tp = NULL;
-			int ans;
 
-			TRACE((IOCTL, "ioctl() READTOCENTRY\n"));
+/*
+ * Low level hardware related functions.
+ */
+
+/*
+ * 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, befor we finally reach the 
+ * timeout. For this reason this command must be called with the drive beeing 
+ * locked!
+ */
+static int get_status(struct s_drive_stuff *stuffp,
+		      unsigned long timeout)
+{
+	unsigned long bang = jiffies + 2;
+	timeout += jiffies;
 
-            if (-1 == mcdx_readtoc(stuffp)) return -1;
+	do {
+		if (!(inb(STAT_REG) & MCDX_RBIT_STEN)) {
+			return (inb(DATA_REG) & 0xff);
+		}
+	} while (jiffies < bang);
 
-			if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry)))) return ans;
-			memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
+	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);
+}
 
-			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];
-
-			if (NULL == tp) WARN(("FATAL.\n"));
-
-			entry.cdte_adr = tp->control;
-			entry.cdte_ctrl = tp->control >> 4;
-
-			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;
+/* 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;
 
-			if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(entry)))) return ans;
-			memcpy_tofs((void*) arg, &entry, sizeof(entry));
+	while (stuffp->busy) {
+		interruptible_sleep_on(&stuffp->busyq);
+	}
+	stuffp->busy = 1;
+	stuffp->valid = 0;
+	outb(command, DATA_REG);
+	if (parslen)
+		outsb(DATA_REG, pars, parslen);
 
-			return 0;
+	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;
+		if (stuffp->toc) {
+			kfree(stuffp->toc);
+			stuffp->toc = 0;
+		}
+	}
+	/* now actually get the data */
+	while (size--) {
+		if (-1 == (st = get_status(stuffp, timeout))) {
+			break;
 		}
+		*((char *) buffer) = st;
+		buffer++;
+	}
 
-		case CDROMSUBCHNL: {
-			int ans;
-			struct cdrom_subchnl sub;
-			struct s_subqcode q;
+      end_talk:
+	stuffp->busy = 0;
+	wake_up_interruptible(&stuffp->busyq);
 
-			TRACE((IOCTL, "ioctl() SUBCHNL\n"));
+	return st;
+}
 
-			if ((ans = verify_area(VERIFY_READ, 
-                    (void*) arg, sizeof(sub)))) 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(&sub, (void*) arg, sizeof(sub));
-
-			if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
-
-            TRACE((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);
-
-            TRACE((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);
-                TRACE((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);
-                TRACE((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;
-
-			if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(sub))))
-				return ans;
-			memcpy_tofs((void*) arg, &sub, sizeof(sub));
+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);
+}
 
-			return 0;
-		}
+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);
+}
 
-		case CDROMREADTOCHDR: {
-			struct cdrom_tochdr toc;
-			int ans;
+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);
+}
 
-			TRACE((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);
-			TRACE((TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
-					stuffp->di.n_first, stuffp->di.n_last));
-			return 0;
-		}
+static int request_toc_data(struct s_drive_stuff *stuffp)
+{
+	char buf[8];
+	int ans;
 
-		case CDROMPAUSE: {
-			TRACE((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;
-		}
+	ans = get_command(stuffp, MCDX_CMD_GET_TOC, buf, sizeof(buf), 2 * HZ);
+	if (ans == -1) {
+		stuffp->n_first = 0;
+		stuffp->n_last = 0;
+	} else {
+		stuffp->n_first = bcd2uint(buf[0]);
+		stuffp->n_last = bcd2uint(buf[1]);
+		memcpy(&(stuffp->msf_leadout), buf + 2, 3);
+	}
+	return ans;
+}
 
-		case CDROMMULTISESSION: {
-			int ans;
-			struct cdrom_multisession ms;
-			TRACE((IOCTL, "ioctl() MULTISESSION\n"));
-			if (0 != (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 (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
-					sizeof(struct cdrom_multisession))))
-				return ans;
-
-			memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
-			if (ms.addr_format == CDROM_MSF) 
-				TRACE((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
-			  {
-			    TRACE((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;
-		}
+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);
+}
 
-		case CDROMEJECT: {
-			TRACE((IOCTL, "ioctl() EJECT\n"));
-			if (stuffp->users > 1) return -EBUSY;
-			if (-1 == mcdx_eject(stuffp, 1)) return -EIO;
-			return 0;
-		}
+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 */
 
-        case CDROMEJECT_SW: {
-            stuffp->eject_sw = arg;
-            return 0;
-        }
-
-        case CDROMVOLCTRL: {
-            int ans;
-            struct cdrom_volctrl volctrl;
-
-            TRACE((IOCTL, "ioctl() VOLCTRL\n"));
-            if ((ans = verify_area(
-                    VERIFY_READ, 
-                    (void*) arg,
-                    sizeof(volctrl))))
-                return ans;
-
-            memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
-            return mcdx_setattentuator(stuffp, &volctrl, 1);
-        }
+	if (-1 == set_command(stuffp, MCDX_CMD_CONFIG, buf,
+			      sizeof(buf), 1 * HZ))
+		return -1;
 
-		default:
-			WARN(("ioctl(): unknown request 0x%04x\n", cmd));
-	    	return -EINVAL;
-	}
+	buf[0] = 0x02;		/* dma select */
+	buf[1] = 0x00;		/* no dma */
+
+	return set_command(stuffp, MCDX_CMD_CONFIG, buf, sizeof(buf), 1 * HZ);
 }
 
-void do_mcdx_request()
+/*  
+ * Read the toc entries from the CD.
+ * Return: -1 on failure, else 0 
+ */
+int read_toc(struct s_drive_stuff *stuffp)
 {
-    int dev;
-    struct s_drive_stuff *stuffp;
+	int trk;
+	int retries;
+
+	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;
 
-  again:
+	/* all seems to be ok so far ... malloc */
+	stuffp->toc = kmalloc(sizeof(struct s_subqcode) *
+		     (stuffp->n_last - stuffp->n_first + 2), GFP_KERNEL);
+	if (!stuffp->toc) {
+		printk(KERN_ERR MCDX ": malloc for toc failed\n");
+		set_drive_mode(stuffp, DATA);
+		return -EIO;
+	}
+	/* now read actually the index tarcks */
+	for (trk = 0;
+	     trk < (stuffp->n_last - stuffp->n_first + 1);
+	     trk++)
+		stuffp->toc[trk].index = 0;
+
+	for (retries = 300; retries; retries--) {	/* why 300? */
+		struct s_subqcode q;
+		unsigned int idx;
 
-	TRACE((REQUEST, "do_request()\n"));
+		if (-1 == request_subq_code(stuffp, &q)) {
+			set_drive_mode(stuffp, DATA);
+			return -EIO;
+		}
+		idx = bcd2uint(q.index);
 
-	if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE))  {
-		TRACE((REQUEST, "do_request() done\n"));
-		return;
+		if ((idx > 0)
+		    && (idx <= stuffp->n_last)
+		    && (q.tno == 0)
+		    && (stuffp->toc[idx - stuffp->n_first].index == 0)) {
+			stuffp->toc[idx - stuffp->n_first] = q;
+			trk--;
+		}
+		if (trk == 0)
+			break;
 	}
+	memset(&stuffp->toc[stuffp->n_last - stuffp->n_first + 1],
+	       0, sizeof(stuffp->toc[0]));
+	stuffp->toc[stuffp->n_last - stuffp->n_first + 1].dt
+	    = stuffp->msf_leadout;
 
-    stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
-	TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
+	/* unset toc mode */
+	if (-1 == set_drive_mode(stuffp, DATA))
+		return -EIO;
 
-    INIT_REQUEST;
-    dev = MINOR(CURRENT->rq_dev);
+	return 0;
+}
 
-	if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
-		WARN(("do_request(): bad device: %s\n", 
-            kdevname(CURRENT->rq_dev)));
-		end_request(0);
-		goto again;
-    }
+/*
+ * Return 0 on success, error value -1 otherwise.
+ */
+static int play_track(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
+{
+	struct s_play times;
 
-	if (stuffp->audio) {
-		WARN(("do_request() attempt to read from audio cd\n"));
-		end_request(0);
-		goto again;
+	if (ti) {
+		if (-1 == read_toc(stuffp)) {
+			stuffp->audiostatus = CDROM_AUDIO_ERROR;
+			return -EIO;
+		}
+		times.start = stuffp->toc[ti->cdti_trk0 - stuffp->n_first].dt;
+		times.stop = stuffp->resume.stop =
+		    stuffp->toc[ti->cdti_trk1 - stuffp->n_first + 1].dt;
+	} else {
+		times = stuffp->resume;
 	}
+	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;
+	}
+	stuffp->audiostatus = CDROM_AUDIO_PLAY;
 
-    switch (CURRENT->cmd) {
-      case WRITE:
-	  WARN(("do_request(): attempt to write to cd!!\n"));
-	  end_request(0);
-	  break;
-
-      case READ:
-	  stuffp->status = 0;
-	  while (CURRENT->nr_sectors) {
-	      int i;
-
-	      if (-1 == (i = mcdx_transfer(
-				      stuffp,
-				      CURRENT->buffer,
-				      CURRENT->sector,
-				      CURRENT->nr_sectors))) {
-              /*INFO(("do_request() read error\n"));*/
-			  xwarn("do_request() read error\n");
-              if (stuffp->status & MCDX_ST_EOM) {
-                  CURRENT->sector += CURRENT->nr_sectors;
-                  CURRENT->nr_sectors = 0;
-              } 
-			  invalidate_buffers(CURRENT->rq_dev);
-              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;
-}
-
-static int 
-mcdx_open(struct inode *ip, struct file *fp)
-/*  actions done on open:
- *  1)  get the drives status */
-{
-    struct s_drive_stuff *stuffp;
-
-	TRACE((OPENCLOSE, "open()\n"));
-    stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
-    if (!stuffp->present) return -ENXIO;
+	return 0;
+}
 
-    /* this is only done to test if the drive talks with us */
-    if (-1 == mcdx_getstatus(stuffp, 1)) return -EIO;
+static int lock_door(struct s_drive_stuff *stuffp, u_char lock)
+{
+	if (stuffp->door)
+		return set_command(stuffp, MCDX_CMD_LOCK_DOOR,
+				   &lock, sizeof(lock), 5 * HZ);
+	return 0;
+}				/* 
+				 * KERNEL INTERFACE FUNCTIONS
+				 */
+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)];
 
-	/* close the door, if necessary (get the door information
-    from the hardware status register). 
-    If the last eject is too recent, an autoclose wouldn't probably
-    be what we want ..., if we can't read the CD after an autoclose
-    no further autocloses will be tried */
-	if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
-        if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
-        if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
-		else return -EIO;
-    }
+	MCDX_TRACE_IOCTL(("mcdx_ioctl():\n"));
 
-	/* if the media changed we will have to do a little more */
-	if (stuffp->xxx) {
+	if (!stuffp)
+		return -ENXIO;
+	if (!ip)
+		return -EINVAL;
+
+	/*
+	 * Update disk information, when necessary.
+	 * This part will only work, when the new disk is of the same type as 
+	 * the one which was previousley there, esp. also for audio diks.
+	 * This doesn't hurt us, since otherwise the mouting/unmounting scheme 
+	 * will ensure correct operation.
+	 */
+	if (stuffp->xxx) {	/* disk changed */
+		if ((-1 == request_toc_data(stuffp)) ||
+		    (-1 == read_toc(stuffp)))
+			return -EIO;
+		stuffp->xxx = 0;
+	}
+	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;
 
-		TRACE((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. */
+	case CDROMSTOP:
+		MCDX_TRACE_IOCTL(("CDROMSTOP\n"));
+		stuffp->audiostatus = CDROM_AUDIO_INVALID;
+		if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ))
+			return -EIO;
+		return 0;
 
-        stuffp->audiostatus = CDROM_AUDIO_INVALID;
+	case CDROMPLAYTRKIND:
+		MCDX_TRACE_IOCTL(("CDROMPLAYTRKIND\n"));
 
-		/* get the multisession information */
-		TRACE((OPENCLOSE, "open() Request multisession info\n"));
-		if (-1 == mcdx_requestmultidiskinfo(
-				stuffp, &stuffp->multi, 6)) {
-			INFO(("No multidiskinfo\n"));
-			stuffp->autoclose = 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)
-				INFO(("open() unknown multisession value (%d)\n", 
-						stuffp->multi.multi));
-#endif
+		if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(ti))))
+			return ans;
+		memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
+		if ((ti.cdti_trk0 < stuffp->n_first)
+		    || (ti.cdti_trk0 > stuffp->n_last)
+		    || (ti.cdti_trk1 < stuffp->n_first))
+			return -EINVAL;
+		if (ti.cdti_trk1 > stuffp->n_last)
+			ti.cdti_trk1 = stuffp->n_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);
+		msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
+		msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
+		msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
+		stuffp->resume.stop.minute = msf.cdmsf_min1;
+		stuffp->resume.stop.second = msf.cdmsf_sec1;
+		stuffp->resume.stop.frame = 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;
 
-			/* multisession ? */
-			if (!stuffp->multi.multi)
-				stuffp->multi.msf_last.second = 2;
+	case CDROMPAUSE:
+		MCDX_TRACE_IOCTL(("CDROMPAUSE\n"));
 
-			TRACE((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 (stuffp->audiostatus != CDROM_AUDIO_PLAY)
+			return -EINVAL;
 
-		} /* got multisession information */
+		if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ))
+			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;
 
-		/* request the disks table of contents (aka diskinfo) */
-		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
+	case CDROMRESUME:
+		MCDX_TRACE_IOCTL(("CDROMRESUME\n"));
 
-			stuffp->lastsector = -1;
+		if (stuffp->audiostatus != CDROM_AUDIO_PAUSED)
+			return -EINVAL;
+		return play_track(stuffp, NULL);
+	case CDROMREADTOCENTRY:
+		MCDX_TRACE_IOCTL(("CDROMREADTOCENTRY\n"));
 
-		} else {
+		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->n_last - stuffp->n_first + 1];
+		else if (entry.cdte_track > stuffp->n_last
+			 || entry.cdte_track < stuffp->n_first)
+			return -EINVAL;
+		else
+			tp = &stuffp->toc[entry.cdte_track - stuffp->n_first];
+
+		if (NULL == tp)
+			printk(KERN_ERR MCDX ": FATAL.\n");
+
+		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));
 
-			stuffp->lastsector = (CD_FRAMESIZE / 512) 
-					* msf2log(&stuffp->di.msf_leadout) - 1;
+		return 0;
 
-			TRACE((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)));
-			TRACE((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)));
-		}
+	case CDROMSUBCHNL:
+		MCDX_TRACE_IOCTL(("CDROMSUBCHNL\n"));
 
-		if (stuffp->toc) {
-			TRACE((MALLOC, "open() free old toc @ %p\n", stuffp->toc));
-			kfree(stuffp->toc);
-		
-			stuffp->toc = NULL;
-		}
+		if ((ans = verify_area(VERIFY_READ,
+				       (void *) arg, sizeof(sub))))
+			return ans;
 
-		TRACE((OPENCLOSE, "open() init irq generation\n"));
-		if (-1 == mcdx_config(stuffp, 1)) return -EIO;
+		memcpy_fromfs(&sub, (void *) arg, sizeof(sub));
 
-#if FALLBACK
-		/* Set the read speed */
-		WARN(("AAA %x AAA\n", stuffp->readcmd));
-		if (stuffp->readerrs) stuffp->readcmd = READ1X;
-		else stuffp->readcmd = 
-				stuffp->present | SINGLE ? READ1X : READ2X;
-		WARN(("XXX %x XXX\n", stuffp->readcmd));
-#endif
+		if (-1 == request_subq_code(stuffp, &q))
+			return -EIO;
 
-		/* try to get the first sector, iff any ... */
-		if (stuffp->lastsector >= 0) {
-			char buf[512];
-			int ans;
-			int tries;
+		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));
 
-			stuffp->xa = 0;
-			stuffp->audio = 0;
+		return 0;
 
-			for (tries = 6; tries; tries--) {
+	case CDROMREADTOCHDR:
+		MCDX_TRACE_IOCTL(("CDROMREADTOCHDR\n"));
 
-				stuffp->introk = 1;
+		if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof toc)))
+			return ans;
 
-				TRACE((OPENCLOSE, "open() try as %s\n",
-					stuffp->xa ? "XA" : "normal"));
+		toc.cdth_trk0 = stuffp->n_first;
+		toc.cdth_trk1 = stuffp->n_last;
+		memcpy_tofs((void *) arg, &toc, sizeof toc);
+		return 0;
 
-				/* set data mode */
-				if (-1 == (ans = mcdx_setdatamode(stuffp, 
-						stuffp->xa ? MODE2 : MODE1, 1))) {
-					/* return -EIO; */
-					stuffp->xa = 0;
-					break;
-				}
+	case CDROMMULTISESSION:
+		MCDX_TRACE_IOCTL(("CDROMMULTISESSION\n"));
 
-				if ((stuffp->audio = e_audio(ans))) break; 
+		if (0 != (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 (0 != (ans = verify_area(VERIFY_WRITE, (void *) arg,
+				     sizeof(struct cdrom_multisession))))
+			 return ans;
 
-				while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1))) 
-					;
+		memcpy_tofs((void *) arg,
+			    &ms, sizeof(struct cdrom_multisession));
+		return 0;
 
-				if (ans == 1) break;
-				stuffp->xa = !stuffp->xa; 
-			}
-			/* if (!tries) return -EIO; */
+	case CDROMEJECT:
+		MCDX_TRACE_IOCTL(("CDROMEJECT\n"));
+		if (stuffp->users > 1)
+			return -EBUSY;
+		if (stuffp->door) {
+			if (-1 == issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ))
+				return -EIO;
 		}
+		/*
+		 * Force rereading of toc next time the disk gets accessed!
+		 */
+		if (stuffp->toc) {
+			kfree(stuffp->toc);
+			stuffp->toc = 0;
+		}
+		return 0;
 
-		/* xa disks will be read in raw mode, others not */
-		if (-1 == mcdx_setdrivemode(stuffp, 
-				stuffp->xa ? RAW : COOKED, 1))
-			return -EIO;
-
-		if (stuffp->audio) {
-			INFO(("open() audio disk found\n"));
-		} else if (stuffp->lastsector >= 0) {
-			INFO(("open() %s%s disk found\n",
-					stuffp->xa ? "XA / " : "",
-					stuffp->multi.multi ? "Multi Session" : "Single Session"));
-		} 
+	case CDROMEJECT_SW:
+		MCDX_TRACE_IOCTL(("CDROMEJECT_SW\n"));
 
-        stuffp->xxx = 0;
-	}
+		stuffp->eject_sw = !!arg;
+		return 0;
 
-    /* lock the door if not already done */
-    if (0 == stuffp->users && (-1 == mcdx_lockdoor(stuffp, 1, 1))) 
-        return -EIO;
+	case CDROMVOLCTRL:
+		MCDX_TRACE_IOCTL(("CDROMVOLCTRL\n"));
 
-    stuffp->users++;
-    MOD_INC_USE_COUNT;
-    return 0;
+		if ((ans = verify_area(VERIFY_READ,
+				       (void *) arg,
+				       sizeof(volctrl))))
+			return ans;
+
+		memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
+		/* Adjust for the wiredness of workman. */
+		volctrl.channel2 = volctrl.channel1;
+		volctrl.channel1 = volctrl.channel3 = 0xff;
+		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;
+	}
 }
 
-static void 
-mcdx_close(struct inode *ip, struct file *fp)
+/*   
+ * This does actually the transfer from the drive.
+ * Return:      -1 on timeout or other error
+ * else status byte (as in stuff->st) 
+ * FIXME: the excessive jumping throught wait queues degrades the
+ * performance significantly.
+ */
+static int transfer_data(struct s_drive_stuff *stuffp,
+			 char *p, int sector, int nr_sectors)
 {
-    struct s_drive_stuff *stuffp;
+	int off;
+	int done = 0;
 
-    TRACE((OPENCLOSE, "close()\n"));
+	if (stuffp->valid
+	    && (sector >= stuffp->pending)
+	    && (sector < stuffp->off_direct)) {
+		off = stuffp->off_requested < (off = sector + nr_sectors)
+		    ? stuffp->off_requested : off;
+
+		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);
+			}
 
-    stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
+			/* test for possible errors */
+			if (current->timeout == 0 || !stuffp->introk) {
+				if (current->timeout == 0) {
+					printk(KERN_ERR MCDX ": transfer timeout\n");
+				} else if (!stuffp->introk) {
+					printk(KERN_ERR MCDX
+					       ": error via irq in transfer reported\n");
+				}
 
-    if (0 == --stuffp->users) {
-		sync_dev(ip->i_rdev);	/* needed for r/o device? */
+				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);
 
-		/* invalidate_inodes(ip->i_rdev); */
-		invalidate_buffers(ip->i_rdev);
+			/* 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);
+	} else {
+		unsigned char cmd[6];
+		stuffp->valid = 1;
+		stuffp->pending = sector & ~3;
 
+		/* 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->off_direct = stuffp->pending + DIRECT_SIZE)
+		    > stuffp->lastsector + 1)
+			stuffp->off_direct = stuffp->lastsector + 1;
+		if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
+		    > stuffp->lastsector + 1)
+			stuffp->off_requested = stuffp->lastsector + 1;
+		{
+			unsigned int l = (stuffp->pending / 4)
+			+ CD_BLOCK_OFFSET;
 
-#if !MCDX_QUIET
-		if (-1 == mcdx_lockdoor(stuffp, 0, 3))
-				INFO(("close() Cannot unlock the door\n"));
-#else
-		mcdx_lockdoor(stuffp, 0, 3);
-#endif
+			cmd[0] = uint2bcd(l / 4500), l %= 4500;
+			/* minute */
+			cmd[1] = uint2bcd(l / 75);	/* second */
+			cmd[2] = uint2bcd(l % 75);	/* frame */
+		}
 
-        /* eject if wished */
-        if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
+		stuffp->busy = 1;
+		/*
+		 * FIXME: What about the ominous frame length?!
+		 */
+		cmd[3] = ~0;
+		cmd[4] = ~0;
+		cmd[5] = ~0;
+
+		outb(stuffp->double_speed ? MCDX_CMD_PLAY_2X : MCDX_CMD_PLAY,
+		     DATA_REG);
+		outsb(DATA_REG, cmd, 6);
+	}
 
-    }
-    MOD_DEC_USE_COUNT;
+	stuffp->off_direct =
+	    (stuffp->off_direct += done) < stuffp->off_requested
+	    ? stuffp->off_direct
+	    : stuffp->off_requested;
 
-    return;
+	return done;
 }
 
-int check_mcdx_media_change(kdev_t full_dev)
-/*	Return: 1 if media changed since last call to this function
-			0 otherwise */
+void do_mcdx_request()
 {
-    struct s_drive_stuff *stuffp; 
+	int dev;
+	struct s_drive_stuff *stuffp;
 
-    INFO(("check_mcdx_media_change called for device %s\n",
-	  kdevname(full_dev)));
+      again:
 
-	stuffp = mcdx_stuffp[MINOR(full_dev)];
-	mcdx_getstatus(stuffp, 1);
-
-	if (stuffp->yyy == 0) return 0;
+	if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) {
+		return;
+	}
+	stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
 
-	stuffp->yyy = 0;
-	return 1;
-}
+	INIT_REQUEST;
+	dev = MINOR(CURRENT->rq_dev);
 
-void mcdx_setup(char *str, int *pi)
-{
-	if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
-	if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
-}
-
-/* DIRTY PART ******************************************************/ 
+	if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp)) {
+		printk(KERN_WARNING MCDX ": bad device requested: %s\n",
+		       kdevname(CURRENT->rq_dev));
+		end_request(0);
+		goto again;
+	}
+	if (stuffp->audio) {
+		printk(KERN_WARNING MCDX ": attempt to read from audio cd\n");
+		end_request(0);
+		goto again;
+	}
+	switch (CURRENT->cmd) {
+	case WRITE:
+		printk(KERN_ERR MCDX ": attempt to write to cd!!\n");
+		end_request(0);
+		break;
 
-static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/*	This routine is used for sleeping.
-	May be we could use a simple count loop w/ jumps to itself, but 
-	I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
-{
-    unsigned long tout = jiffies + jifs;
-    if (jifs < 0) return;
+	case READ:
+		stuffp->eom = 0;	/* clear end of media flag */
+		while (CURRENT->nr_sectors) {
+			int i;
 
-    /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */
+			if (-1 == (i = transfer_data(stuffp,
+						     CURRENT->buffer,
+						     CURRENT->sector,
+						 CURRENT->nr_sectors))) {
+				if (stuffp->eom) {
+					CURRENT->sector += CURRENT->nr_sectors;
+					CURRENT->nr_sectors = 0;
+				} else {
+					/*
+					 * FIXME: TRY SOME ERROR RECOVERY HERE!
+					 */
+				}
+				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;
+	}
 
-    if (current->pid == 0) {        /* no sleep allowed */
-		while (jiffies < tout) {
-            current->timeout = jiffies;
-            schedule();
-        }
-    } else {                        /* sleeping is allowed */
-        current->timeout = tout;
-        /* current->state = TASK_INTERRUPTIBLE; */
-		/* And perhaps we should remove the while() { ... } */
-        while (current->timeout) {
-            interruptible_sleep_on(&stuff->sleepq);
-			TRACE((SLEEP, "delay: to is %d\n", current->timeout));
-        }
-    }
+	goto again;
 }
 
-static void 
-mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
+/*  
+ * actions done on open:
+ * 1)   get the drives status 
+ */
+static int mcdx_open(struct inode *ip, struct file *fp)
 {
-    struct s_drive_stuff *stuffp;
-	unsigned char b;
+	struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
+	int st = 0;
+	unsigned long bang;
 
-    stuffp = mcdx_irq_map[irq];
+	MCDX_TRACE(("mcdx_open()\n"));
 
-    if (stuffp == NULL ) {
-		xwarn("mcdx: no device for intr %d\n", irq);
-		return;
-    }
-
-	/* get the interrupt status */
-	b = inb((unsigned int) stuffp->rreg_status);
-	stuffp->introk = ~b & MCDX_RBIT_DTEN;
+	if (!stuffp)
+		return -ENXIO;
 
-	/* 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 initialisation) */
-
-	/* if not ok, read the next byte as the drives status */
-	if (!stuffp->introk) {
-		TRACE((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 ambiguous hw status\n", irq);
-		}
-	} else {
-		TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, 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 autocloses will be tried 
+	 */
+	if (inb(STAT_REG) & MCDX_RBIT_DOOR) {
+		if (stuffp->autoclose && (stuffp->door))
+			issue_command(stuffp, MCDX_CMD_CLOSE_DOOR, 10 * HZ);
+		else
+			return -EIO;
+	}
+	/*
+	 * Check if a disk is in.
+	 */ bang = jiffies + 10 * HZ;
+	while (jiffies < bang) {
+		st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 5 * 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->busy = 0;
-    wake_up_interruptible(&stuffp->busyq);
-}
+		stuffp->audiostatus = CDROM_AUDIO_INVALID;
+		stuffp->autoclose = 1;
 
+		/* get the multisession information */
 
-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;
+		if (stuffp->multi_cap) {
+			int i = 6;	/* number of retries */
+			while (i && (-1 == get_command(stuffp,
+						 MCDX_CMD_GET_MDISK_INFO,
+			&stuffp->multi, sizeof(struct s_multi), 2 * HZ)))
+				--i;
+			if (!i) {
+				stuffp->autoclose = 0;
+				/*
+				 * No multidisk info
+				 */
+			}
+		} else
+			stuffp->multi.multi = 0;
 
-    if ((discard = (buffer == NULL))) buffer = &c;
+		if (stuffp->autoclose) {
+			/* we succeeded, so on next open(2) we could try  
+			 * auto close again 
+			 */
 
-    while (stuffp->lock) {
-		interruptible_sleep_on(&stuffp->lockq); 
-		TRACE((SLEEP, "talk: lock = %d\n",
-				stuffp->lock));
-	}
-
-    stuffp->lock = 1;
-    stuffp->valid = 0;	
-
-#if MCDX_DEBUG & TALK
-	{ 
-		unsigned char i;
-		TRACE((TALK, "talk() %d / %d tries, res.size %d, command 0x%02x", 
-				tries, timeout, size, (unsigned char) cmd[0]));
-		for (i = 1; i < cmdlen; i++) printk(" 0x%02x", cmd[i]);
-		printk("\n");
-	}
-#endif
+			/* multisession ? */
+			if (!stuffp->multi.multi)
+				stuffp->multi.msf_last.second = 2;
+		}		/* got multisession information */
+		/* request the disks table of contents (aka diskinfo) */
+		if (-1 == request_toc_data(stuffp)) {
+			stuffp->lastsector = -1;
+		} else {
+			stuffp->lastsector = (CD_FRAMESIZE / 512)
+			    * msf2log(&stuffp->msf_leadout) - 1;
+		}
 
-    /*  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);
-        TRACE((TALK, "talk() command sent\n"));
-
-        /* get the status byte */
-        if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-            INFO(("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++;
-
-        TRACE((TALK, "talk() got status 0x%02x\n", st));
-
-        /* command error? */
-        if (e_cmderr(st)) {
-            WARN(("command error cmd = %02x %s \n", 
-                    cmd[0], cmdlen > 1 ? "..." : ""));
-            st = -1;
-            continue;
-		}
-
-        /* 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)) {
-            INFO(("talk() media changed\n"));
-            stuffp->xxx = stuffp->yyy = 1;
-        }
-
-        /* now actually get the data */
-        while (sz--) {
-            if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-                INFO(("talk() %02x timed out (data), %d tr%s left\n", 
-                        cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
-                st = -1; break;
-            }
-            if (!discard) bp++;
-            TRACE((TALK, "talk() got 0x%02x\n", *(bp - 1)));
-        }
-    }
+		if (stuffp->toc) {
+			kfree(stuffp->toc);
+			stuffp->toc = 0;
+		}
+		if (-1 == config_drive(stuffp))
+			return -EIO;
 
-#if !MCDX_QUIET
-    if (!tries && st == -1) INFO(("talk() giving up\n"));
-#endif
+		/* try to get the first sector, iff any ... */
+		if (stuffp->lastsector >= 0) {
+			char buf[512];
+			int ans;
+			int tries;
 
-    stuffp->lock = 0;
-    wake_up_interruptible(&stuffp->lockq);
+			stuffp->xa = 0;
+			stuffp->audio = 0;
 
-	TRACE((TALK, "talk() done with 0x%02x\n", st));
-    return st;
-}
+			for (tries = 6; tries; tries--) {
+				unsigned char c;
+				stuffp->introk = 1;
 
-/* MODULE STUFF ***********************************************************/
-#ifdef MODULE
+				/* set data mode */
+				c = stuffp->xa ? MODE2 : MODE1;
+				ans = set_command(stuffp,
+						  MCDX_CMD_SET_DATA_MODE,
+						  &c, sizeof(c), 5 * HZ);
 
-int init_module(void)
-{
-	int i;
-	int drives = 0;
+				if (-1 == ans) {
+					/* return -EIO; */
+					stuffp->xa = 0;
+					break;
+				} else if (ans & MCDX_RBIT_AUDIOTR) {
+					stuffp->audio = 1;
+					break;
+				}
+				 
+				while (0 == (ans = transfer_data(stuffp, buf,
+								 0, 1)));
 
-	mcdx_init();
-	for (i = 0; i < MCDX_NDRIVES; i++)  {
-		if (mcdx_stuffp[i]) {
-		TRACE((INIT, "init_module() drive %d stuff @ %p\n",
-				i, mcdx_stuffp[i]));
-			drives++;
+				if (ans == 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;
 	}
-
-    if (!drives) 
+	/* lock the door if not already done */
+	if (0 == stuffp->users && (-1 == lock_door(stuffp, DOOR_LOCK)))
 		return -EIO;
 
-    register_symtab(0);
-    return 0;
+	stuffp->users++;
+	MOD_INC_USE_COUNT;
+	return 0;
 }
 
-void cleanup_module(void)
+static void mcdx_close(struct inode *ip, struct file *fp)
 {
-    int i;
+	struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
 
-	INFO(("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) {
-			TRACE((MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc));
-			kfree(stuffp->toc);
+	MCDX_TRACE(("mcdx_close()\n"));
+
+	if (0 == --stuffp->users) {
+		sync_dev(ip->i_rdev);	/* needed for r/o device? */
+
+		/* invalidate_inodes(ip->i_rdev); */
+		invalidate_buffers(ip->i_rdev);
+		lock_door(stuffp, DOOR_UNLOCK);
+
+		/* eject if wished and possible */
+		if (stuffp->eject_sw && (stuffp->door)) {
+			issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
 		}
-		TRACE((MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp));
-		mcdx_stuffp[i] = NULL;
-		kfree(stuffp);
-    }
+	}
+	MOD_DEC_USE_COUNT;
 
-    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
-        WARN(("cleanup() unregister_blkdev() failed\n"));
-    } 
-#if !MCDX_QUIET
-	else INFO(("cleanup() succeeded\n"));
-#endif
+	return;
 }
 
-#endif MODULE
+/*      
+ * Return: 1 if media changed since last call to this function
+ * 0 otherwise 
+ */
+static int mcdx_media_change(kdev_t full_dev)
+{
+	struct s_drive_stuff *stuffp;
 
-/* Support functions ************************************************/
+	MCDX_TRACE(("mcdx_media_change()\n"));
 
-#if MCDX_DEBUG
-void trace(int level, const char* fmt, ...)
-{
-	char s[255];
-	va_list args;
-	if (level < 1) return;
-	va_start(args, fmt);
-	if (sizeof(s) < vsprintf(s, fmt, args))
-		printk(MCDX ":: dprintf exceeds limit!!\n");
-	else printk(MCDX ":: %s", s);
-	va_end(args);
+	/*
+	 * FIXME: propably this is unneded or should be simplified!
+	 */
+	issue_command(stuffp = mcdx_stuffp[MINOR(full_dev)],
+		      MCDX_CMD_GET_STATUS, 5 * HZ);
+
+	return stuffp->xxx;
 }
-#endif
 
-void warn(const char* fmt, ...)
+/* 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)
 {
-	char s[255];
-	va_list args;
-	va_start(args, fmt);
-	if (sizeof(s) < vsprintf(s, fmt, args))
-		printk(MCDX ":: dprintf exceeds limit!!\n");
-	else printk(MCDX ": %s", s);
-	va_end(args);
+	struct s_drive_stuff *stuffp;
+	u_char b;
+
+	if (!(stuffp = mcdx_irq_map[irq])) {
+		return;		/* hugh? */
+	}
+	
+	/* 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 initialisation) 
+	 */
+
+	/* get the interrupt status */
+	b = inb(STAT_REG);	
+	if (!(b & MCDX_RBIT_DTEN)) {
+		stuffp->introk = 1;
+	} else {
+		stuffp->introk = 0;
+		if (!(b & MCDX_RBIT_STEN)) {
+			printk(KERN_DEBUG MCDX ": irq %d status 0x%02x\n",
+			       irq, inb(DATA_REG));
+		} else {
+			MCDX_TRACE(("irq %d ambiguous hw status\n", irq));
+		}
+	}
+	stuffp->busy = 0;
+	wake_up_interruptible(&stuffp->busyq);
 }
 
+/*
+ * FIXME!
+ * This seems to hang badly, when the driver is loaded with inappriopriate
+ * port/irq settings!
+ */
 int mcdx_init(void)
 {
 	int drive;
 
 #ifdef MODULE
-	WARN(("Version 1.9 for %s\n", kernel_version));
+	printk(KERN_INFO "Mitsumi driver version " VERSION " for %s\n",
+	       kernel_version);
 #else
-	WARN(("Version 1.9\n"));
+	printk(KERN_INFO "Mitsumi driver version " VERSION "\n");
 #endif
-
-	WARN(("mcdx.c,v 1.2 1996/03/22 01:14:59 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;
+	printk("%d\n", MCDX_NDRIVES);
+	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_blocksizes[drive] = 0;
+		mcdx_stuffp[drive] = 0;
 
-        size = sizeof(*stuffp);
-		
-		TRACE((INIT, "init() try drive %d\n", drive));
+		size = sizeof(*stuffp);
 
-        TRACE((INIT, "kmalloc space for stuffpt's\n"));
-		TRACE((MALLOC, "init() malloc %d bytes\n", size));
 		if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
-			WARN(("init() malloc failed\n"));
-			break; 
+			printk(KERN_ERR MCDX
+			       ": malloc of drives data failed!\n");
+			break;
 		}
+		/* set default values */ memset(stuffp, 0, sizeof(*stuffp));
+		stuffp->autoclose = 1;	/* close the door on open(2) */
 
-		TRACE((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->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;
+		stuffp->base = port(mcdx_drive_map[drive]);
 
 		/* check if i/o addresses are available */
-		if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
-            WARN(("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));
-			TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
-            kfree(stuffp);
-			TRACE((INIT, "init() continue at next drive\n"));
-			continue; /* next drive */
+		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 */
 		}
-
-		TRACE((INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data));
-
-		TRACE((INIT, "init() hardware reset\n"));
-		mcdx_reset(stuffp, HARD, 1);
-
-		TRACE((INIT, "init() get version\n"));
-		if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
+		/*
+		 * 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) {
 			/* failed, next drive */
-            WARN(("%s=0x%3p,%d: Init failed. Can't get version.\n",
-                    MCDX,
-                    stuffp->wreg_data, stuffp->irq));
-			TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
-            kfree(stuffp);
-			TRACE((INIT, "init() continue at next drive\n"));
+			printk(KERN_WARNING
+			"%s=0x%3x,%d: Init failed. Can't get version.\n",
+			       MCDX, stuffp->base, stuffp->irq);
+			kfree(stuffp);
 			continue;
 		}
-
-		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;
-		}
-
-        stuffp->playcmd = READ1X;
-
-
-		if (!stuffp->present) {
-            WARN(("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
-                    MCDX, stuffp->wreg_data, stuffp->irq));
+		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);
-			continue; /* next drive */
 		}
 
-		TRACE((INIT, "init() register blkdev\n"));
-		if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops) != 0) {
-            WARN(("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
-                    MCDX,
-                    stuffp->wreg_data, stuffp->irq, MAJOR_NR));
+		if (!stuffp)
+			continue;	/* next drive */
+
+		if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops)) {
 			kfree(stuffp);
-			continue; /* next drive */
+			continue;	/* next drive */
 		}
-
 		blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 		read_ahead[MAJOR_NR] = READ_AHEAD;
 
 		blksize_size[MAJOR_NR] = mcdx_blocksizes;
 
-		TRACE((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)) {
-            WARN(("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
-                    MCDX,
-                    stuffp->wreg_data, stuffp->irq, stuffp->irq));
+		if (request_irq(stuffp->irq, mcdx_intr,
+				SA_INTERRUPT, DEVICE_NAME, NULL)) {
 			stuffp->irq = 0;
 			kfree(stuffp);
-			continue;
-		}
-		request_region((unsigned int) stuffp->wreg_data, 
-                MCDX_IO_SIZE, 
-                DEVICE_NAME); 
-
-		TRACE((INIT, "init() get garbage\n"));
-		{
-			int i;
-			mcdx_delay(stuffp, HZ/2);
-			for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status);
+			continue;	/* next drive */
 		}
+		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, (unsigned int) stuffp->wreg_chn);	/* irq 11 -> channel register */
+		outb(0x50, CHAN_REG);	/* irq 11 -> channel register */
 #endif
 
-		TRACE((INIT, "init() set non dma but irq mode\n"));
-		mcdx_config(stuffp, 1);
-
-		stuffp->minor = drive;
+		config_drive(stuffp);
 
-		WARN((DEVICE_NAME " installed at 0x%3p, irq %d."
-			   " (Firmware version %c %x)\n",
-			   stuffp->wreg_data, stuffp->irq, version.code,
-               version.ver));
+		printk(KERN_INFO MCDX "%d: at 0x%3x, irq %d, firmware: %c %x\n",
+		       drive, stuffp->base, stuffp->irq,
+		       firmware.code, firmware.version);
 		mcdx_stuffp[drive] = stuffp;
-		TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
 	}
 
 	return 0;
 }
 
-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 occurred 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;
-
-	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) {
-		WARN(("XXX Already reading 1x -- no chance\n"));
-		return -1;
-	}
-
-	WARN(("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 off;
-    int done = 0;
-
-	TRACE((TRANSFER, "transfer() %d sectors at sector %d\n",
-			nr_sectors, sector));
-
-	if (stuffp->audio) {
-		WARN(("attempt to read from audio cd\n"));
-		return -1;
-	}
-
-    while (stuffp->lock) {
-		interruptible_sleep_on(&stuffp->lockq);
-		TRACE((SLEEP, "xfer: lock = %d\n",
-			stuffp->lock));
-	}
-
-    if (stuffp->valid
-			&& (sector >= stuffp->pending)
-			&& (sector < stuffp->off_direct)) {
-
-
-	off = stuffp->off_requested < (off = sector + nr_sectors)
-			? stuffp->off_requested : off;
-
-	stuffp->lock = current->pid;
-
-	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);
-			TRACE((SLEEP, "request: busy = %d, timeout = %d\n",
-				stuffp->busy, current->timeout));
-		}
-
-		/* test for possible errors */
-		if (current->timeout == 0 || !stuffp->introk) {
-			if (current->timeout == 0)  {
-				WARN(("mcdx_transfer() timeout\n"));
-			} else if (!stuffp->introk) { 
-				WARN(("mcdx_transfer() error via irq reported\n"));
-			} else {
-				WARN(("mcdx_transfer() unknown failure in data request\n"));
-			}
-
-			stuffp->lock = 0;
-			stuffp->busy = 0;
-			stuffp->valid = 0;
-
-			wake_up_interruptible(&stuffp->lockq);
-			TRACE((TRANSFER, "transfer() done (-1)\n"));
-			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))) {
-			const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
-			TRACE((TRANSFER, "transfer() sector %d, skip %d header bytes\n",
-				stuffp->pending, HEAD));
-			insb((unsigned int) stuffp->rreg_data, p, HEAD);
-		}
-
-		/* now actually read the data */
-
-		TRACE((TRANSFER, "transfer() read sector %d\n", stuffp->pending));
-	    insb((unsigned int) stuffp->rreg_data, p, 512); 
-
-		/* 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) {
-			char dummy[CD_XA_TAIL];
-			TRACE((TRANSFER, "transfer() sector %d, skip %d trailer bytes\n",
-					stuffp->pending, 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) < off);
-
-	stuffp->lock = 0;
-	wake_up_interruptible(&stuffp->lockq);
-
-    } else {
-
-		static unsigned char cmd[] = {
-			0,
-			0, 0, 0,
-			0, 0, 0
-		};
-
-		cmd[0] = stuffp->readcmd;
-
-		stuffp->valid = 1;
-		stuffp->pending = sector & ~3;
-
-		/* do some sanity checks */
-		TRACE((TRANSFER, "transfer() request sector %d\n", stuffp->pending));
-		if (stuffp->pending > stuffp->lastsector) {
-			WARN(("transfer() sector %d from nirvana requested.\n",
-				stuffp->pending));
-			stuffp->status = MCDX_ST_EOM;
-			stuffp->valid = 0;
-			TRACE((TRANSFER, "transfer() done (-1)\n"));
-			return -1;
-		}
-
-		if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE)
-			> stuffp->lastsector + 1)
-			stuffp->off_direct = stuffp->lastsector + 1;
-		if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
-			> stuffp->lastsector + 1)
-			stuffp->off_requested = stuffp->lastsector + 1;
-
-		TRACE((TRANSFER, "transfer() pending %d\n", stuffp->pending));
-		TRACE((TRANSFER, "transfer() off_dir %d\n", stuffp->off_direct));
-		TRACE((TRANSFER, "transfer() off_req %d\n", stuffp->off_requested));
-
-		{
-			struct s_msf pending;
-			log2msf(stuffp->pending / 4, &pending);
-			cmd[1] = pending.minute;
-			cmd[2] = pending.second;
-			cmd[3] = pending.frame;
-		}
-
-		stuffp->busy = 1;
-		cmd[6] = (unsigned char) (stuffp->off_requested - stuffp->pending) / 4;
-
-		outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
-
-    }
-
-    stuffp->off_direct = (stuffp->off_direct += done) < stuffp->off_requested
-	    ? stuffp->off_direct : stuffp->off_requested;
-
-	TRACE((TRANSFER, "transfer() done (%d)\n", done));
-    return done;
-}
-
-
-/*	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 s_msf* pmsf)
-{
-    l += CD_BLOCK_OFFSET;
-    pmsf->minute = uint2bcd(l / 4500), l %= 4500;
-    pmsf->second = uint2bcd(l / 75);
-    pmsf->frame = uint2bcd(l % 75);
-}
+#ifdef MODULE
 
-static unsigned int msf2log(const struct s_msf* 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 */
+int init_module(void)
 {
+	int i;
 
-	if (stuffp->toc) {
-		TRACE((READTOC, "ioctl() toc already read\n"));
-		return 0;
-	}
-
-	TRACE((READTOC, "ioctl() readtoc for %d tracks\n",
-			stuffp->di.n_last - stuffp->di.n_first + 1));
-
-    if (-1 == mcdx_hold(stuffp, 1)) return -1;
-
-	TRACE((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);
-
-		TRACE((MALLOC, "ioctl() malloc %d bytes\n", size));
-		stuffp->toc = kmalloc(size, GFP_KERNEL);
-		if (!stuffp->toc) {
-			WARN(("Cannot malloc %s bytes for toc\n", size));
-			mcdx_setdrivemode(stuffp, DATA, 1);
-			return -EIO;
-		}
-	}
-
-	/* 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;
-				TRACE((READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk));
-				trk--;
-			}
-			if (trk == 0) break;
+	mcdx_init();
+	for (i = 0; i < MCDX_NDRIVES; i++) {
+		if (mcdx_stuffp[i]) {
+			register_symtab(0);
+			return 0;
 		}
-		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 */
-	TRACE((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++)
-		TRACE((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;
-}
-
-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
-    };
-
-    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;
-
-    TRACE((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)) {
-        WARN(("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)
-{
-    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;
-}
-
-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;
+	return -EIO;
 }
 
-static int
-mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
+void cleanup_module(void)
 {
-	char cmd[2];
-	int ans;
-
-	TRACE((HW, "setdrivemode() %d\n", mode));
+	int i;
 
-	if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
-		return -1;
+	unregister_blkdev(MAJOR_NR, DEVICE_NAME);
 
-	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 };
-	TRACE((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;
+	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);
+		if (stuffp->toc) {
+			kfree(stuffp->toc);
+		}
+		mcdx_stuffp[i] = NULL;
+		kfree(stuffp);
 	}
-	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];
-
-	TRACE((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;
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 }
 
-static int
-mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
+#else				/* MODULE */
 
-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)
+/*
+ * 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)
 {
-    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);
+	if (pi[0] > 0)
+		mcdx_drive_map[0][0] = pi[1];
+	if (pi[0] > 1)
+		mcdx_drive_map[0][1] = pi[2];
 }
-
-/* ex:set ts=4 sw=4: */
+#endif				/* MODULE */
diff -u --recursive --new-file pre2.0.2/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- pre2.0.2/linux/drivers/cdrom/sbpcd.c	Sat Feb 17 08:07:02 1996
+++ linux/drivers/cdrom/sbpcd.c	Mon May 13 07:02:40 1996
@@ -9,11 +9,11 @@
  *            Also for the TEAC CD-55A drive.
  *            Also for the ECS-AT "Vertos 100" drive.
  *            Not for Sanyo drives (but for the H94A, sjcd is there...).
- *            Not for any other Funai drives than the CD200 types
- *            (sometimes labelled E2550UA or MK4015 or E2880UA).
+ *            Not for any other Funai drives than the CD200 types (sometimes
+ *             labelled E2550UA or MK4015 or 2800F).
  */
 
-#define VERSION "v4.2 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "v4.3 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 /*   Copyright (C) 1993, 1994, 1995  Eberhard Moenkeberg <emoenke@gwdg.de>
  *
@@ -274,6 +274,11 @@
  *       is user-configurable (even at runtime), but to get aware of this, one
  *       needs a special mental quality: the ability to read.
  *       
+ *  4.3  CD200F does not like to receive a command while the drive is
+ *       reading the ToC; still trying to solve it.
+ *       Removed some redundant verify_area calls (yes, Heiko Eissfeldt
+ *       is visiting all the Linux CDROM drivers ;-).
+ *
  *
  *  TODO
  *
@@ -728,6 +733,12 @@
  */
 static void msg(int level, const char *fmt, ...)
 {
+#if DISTRIBUTION
+#define MSG_LEVEL KERN_NOTICE
+#else
+#define MSG_LEVEL KERN_INFO
+#endif DISTRIBUTION
+
 	char buf[256];
 	va_list args;
 	
@@ -735,7 +746,7 @@
 	
 	msgnum++;
 	if (msgnum>99) msgnum=0;
-	sprintf(buf, KERN_NOTICE "%s-%d [%02d]:  ", major_name, d, msgnum);
+	sprintf(buf, MSG_LEVEL "%s-%d [%02d]:  ", major_name, d, msgnum);
 	va_start(args, fmt);
 	vsprintf(&buf[18], fmt, args);
 	va_end(args);
@@ -1645,7 +1656,7 @@
 			drvcmd[2]=0;
 			drvcmd[3]=150;
 		}
-		flags_cmd_out=f_putcmd|f_ResponseStatus;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
 	}
 	else if (famT_drive)
 	{
@@ -3975,7 +3986,7 @@
 		
 	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
 		msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n");
-		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_tocentry));
+		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
 		if (st) return (st);
 		memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
 		i=tocentry.cdte_track;
@@ -3993,8 +4004,6 @@
 		else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
 			tocentry.cdte_addr.lba=msf2blk(D_S[d].TocBuffer[i].address);
 		else return (-EINVAL);
-		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
-		if (st) return (st);
 		memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
 		return (0);
 		
@@ -4069,8 +4078,6 @@
 					    }
 		st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
 		if (st)	return (st);
-		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
-		if (st) return (st);
 		memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
 		switch (D_S[d].audio_state)
 		{
@@ -4355,7 +4362,7 @@
 		
 	case CDROMMULTISESSION: /* tell start-of-last-session */
 		msg(DBG_IOC,"ioctl: CDROMMULTISESSION entered.\n");
-		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_multisession));
+		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
 		if (st) return (st);
 		memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
 		if (ms_info.addr_format==CDROM_MSF) /* MSF-bin requested */
@@ -4365,8 +4372,6 @@
 		else return (-EINVAL);
 		if (D_S[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */
 		else ms_info.xa_flag=0; /* invalid redirection address */
-		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
-		if (st) return (st);
 		memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
 		msg(DBG_MUL,"ioctl: CDROMMULTISESSION done (%d, %08X).\n",
 		    ms_info.xa_flag, ms_info.addr.lba);
diff -u --recursive --new-file pre2.0.2/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- pre2.0.2/linux/drivers/char/Config.in	Sun May  5 08:51:59 1996
+++ linux/drivers/char/Config.in	Mon May 13 07:17:23 1996
@@ -52,13 +52,13 @@
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
   bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
   tristate '   WDT Watchdog timer' CONFIG_WDT
-  if [ "$CONFIG_WDT" = "y" ]; then
+  if [ "$CONFIG_WDT" != "n" ]; then
      bool '       WDT501 features' CONFIG_WDT_501
      if [ "$CONFIG_WDT_501" = "y" ]; then
          bool '       Fan Tachometer' CONFIG_WDT_501_FAN
      fi
   else
-     bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+     tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   fi
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
diff -u --recursive --new-file pre2.0.2/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- pre2.0.2/linux/drivers/char/Makefile	Sat Apr 27 15:19:51 1996
+++ linux/drivers/char/Makefile	Mon May 13 07:17:23 1996
@@ -127,10 +127,14 @@
 M = y
 endif
 
-ifdef CONFIG_SOFT_WATCHDOG
-L_OBJS += softdog.o
+ifeq ($(CONFIG_SOFT_WATCHDOG),y)
 M = y
-# This is not modularized, so if configured then "misc.c" will be resident
+L_OBJS += softdog.o
+else
+  ifeq ($(CONFIG_SOFT_WATCHDOG),m)
+  M_OBJS += softdog.o
+  MM = m
+  endif   
 endif
 
 ifdef CONFIG_SUN_MOUSE
diff -u --recursive --new-file pre2.0.2/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- pre2.0.2/linux/drivers/char/keyboard.c	Sun May 12 22:54:23 1996
+++ linux/drivers/char/keyboard.c	Mon May 13 07:36:19 1996
@@ -173,7 +173,7 @@
 	for (i=0; i<0x100000; i++)
 		if ((inb_p(0x64) & 0x02) == 0)
 			return;
-	printk("Keyboard timed out\n");
+	printk(KERN_WARNING "Keyboard timed out\n");
 }
 
 static inline void send_cmd(unsigned char c)
@@ -361,7 +361,7 @@
 	  if (!(status & 0x21)) { /* neither ODS nor OBF */
 	    scancode = inb(0x60); /* read data anyway */
 #if 0
-	    printk("keyboard: status 0x%x  mask 0x%x  data 0x%x\n",
+	    printk(KERN_DEBUG "keyboard: status 0x%x  mask 0x%x  data 0x%x\n",
 		   status, kbd_read_mask, scancode);
 #endif
 	  }
@@ -383,12 +383,13 @@
 		/* strange ... */
 		reply_expected = 1;
 #if 0
-		printk("keyboard reply expected - got %02x\n", scancode);
+		printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
+		       scancode);
 #endif
 	}
 	if (scancode == 0) {
 #ifdef KBD_REPORT_ERR
-		printk("keyboard buffer overflow\n");
+		printk(KERN_INFO "keyboard buffer overflow\n");
 #endif
 		prev_scancode = 0;
 		goto end_kbd_intr;
@@ -412,7 +413,7 @@
 #ifndef KBD_IS_FOCUS_9000
 #ifdef KBD_REPORT_ERR
 		if (!raw_mode)
-		  printk("keyboard error\n");
+		  printk(KERN_DEBUG "keyboard error\n");
 #endif
 #endif
 		prev_scancode = 0;
@@ -445,7 +446,7 @@
 	      } else {
 #ifdef KBD_REPORT_UNKN
 		  if (!raw_mode)
-		    printk("keyboard: unknown e1 escape sequence\n");
+		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
 #endif
 		  prev_scancode = 0;
 		  goto end_kbd_intr;
@@ -473,7 +474,8 @@
 	      else {
 #ifdef KBD_REPORT_UNKN
 		  if (!raw_mode)
-		    printk("keyboard: unknown scancode e0 %02x\n", scancode);
+		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+			   scancode);
 #endif
 		  goto end_kbd_intr;
 	      }
@@ -494,8 +496,8 @@
 	  if (!keycode) {
 	      if (!raw_mode) {
 #ifdef KBD_REPORT_UNKN
-		  printk("keyboard: unrecognized scancode (%02x) - ignored\n"
-			 , scancode);
+		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+			 " - ignored\n", scancode);
 #endif
 	      }
 	      goto end_kbd_intr;
@@ -796,7 +798,7 @@
 
 static void do_lowercase(unsigned char value, char up_flag)
 {
-	printk("keyboard.c: do_lowercase was called - impossible\n");
+	printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n");
 }
 
 static void do_self(unsigned char value, char up_flag)
@@ -878,7 +880,7 @@
 		if (func_table[value])
 			puts_queue(func_table[value]);
 	} else
-		printk("do_fn called with value=%d\n", value);
+		printk(KERN_ERR "do_fn called with value=%d\n", value);
 }
 
 static void do_pad(unsigned char value, char up_flag)
@@ -1313,7 +1315,8 @@
 	 */
 	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
 	if (kbd_wait_for_input() != 0x55) {
-		printk("initialize_kbd: keyboard failed self test.\n");
+		printk(KERN_WARNING "initialize_kbd: "
+		       "keyboard failed self test.\n");
 		restore_flags(flags);
 		return(-1);
 	}
@@ -1325,7 +1328,8 @@
 	 */
 	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
 	if (kbd_wait_for_input() != 0x00) {
-		printk("initialize_kbd: keyboard failed self test 2.\n");
+		printk(KERN_WARNING "initialize_kbd: "
+		       "keyboard failed self test 2.\n");
 		restore_flags(flags);
 		return(-1);
 	}
@@ -1341,13 +1345,15 @@
 	 */
 	kbd_write(KBD_DATA_REG, KBD_RESET);
 	if (kbd_wait_for_input() != KBD_ACK) {
-		printk("initialize_kbd: reset kbd failed, no ACK.\n");
+		printk(KERN_WARNING "initialize_kbd: "
+		       "reset kbd failed, no ACK.\n");
 		restore_flags(flags);
 		return(-1);
 	}
 
 	if (kbd_wait_for_input() != KBD_POR) {
-		printk("initialize_kbd: reset kbd failed, not POR.\n");
+		printk(KERN_WARNING "initialize_kbd: "
+		       "reset kbd failed, not POR.\n");
 		restore_flags(flags);
 		return(-1);
 	}
@@ -1357,7 +1363,8 @@
 	 */
 	kbd_write(KBD_DATA_REG, KBD_DISABLE);
 	if (kbd_wait_for_input() != KBD_ACK) {
-		printk("initialize_kbd: disable kbd failed, no ACK.\n");
+		printk(KERN_WARNING "initialize_kbd: "
+		       "disable kbd failed, no ACK.\n");
 		restore_flags(flags);
 		return(-1);
 	}
@@ -1375,7 +1382,8 @@
 	 */
 	kbd_write(KBD_DATA_REG, KBD_ENABLE);
 	if (kbd_wait_for_input() != KBD_ACK) {
-		printk("initialize_kbd: keyboard enable failed.\n");
+		printk(KERN_WARNING "initialize_kbd: "
+		       "keyboard enable failed.\n");
 		restore_flags(flags);
 		return(-1);
 	}
diff -u --recursive --new-file pre2.0.2/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- pre2.0.2/linux/drivers/char/softdog.c	Sun Mar 31 00:13:17 1996
+++ linux/drivers/char/softdog.c	Mon May 13 07:17:23 1996
@@ -1,5 +1,5 @@
 /*
- *	SoftDog	0.02:	A Software Watchdog Device
+ *	SoftDog	0.04:	A Software Watchdog Device
  *
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
@@ -16,8 +16,15 @@
  *
  *	Software only watchdog driver. Unlike its big brother the WDT501P
  *	driver this won't always recover a failed machine.
+ *
+ *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
+ *	Modularised.
+ *	Added soft_margin; use upon insmod to change the timer delay.
+ *	NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
+ *	    minors.
  */
  
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -26,7 +33,9 @@
 #include <linux/miscdevice.h>
 
 #define WATCHDOG_MINOR	130
-#define TIMER_MARGIN	(60*HZ)		/* Allow 1 minute */
+#define TIMER_MARGIN	60		/* (secs) Default is 1 minute */
+
+static int soft_margin = TIMER_MARGIN;	/* in seconds */
 
 /*
  *	Our timer
@@ -43,8 +52,13 @@
 static void watchdog_fire(unsigned long data)
 {
 	extern void hard_reset_now(void);
+#ifdef ONLY_TESTING
+		printk(KERN_CRIT "SOFTDOG: Would Reboot.\n");
+#else
+	printk(KERN_CRIT "SOFTDOG: Initiating system reboot.\n");
 	hard_reset_now();
 	printk("WATCHDOG: Reboot didn't ?????\n");
+#endif
 }
 
 /*
@@ -55,10 +69,11 @@
 {
 	if(timer_alive)
 		return -EBUSY;
+	MOD_INC_USE_COUNT;
 	/*
 	 *	Activate timer
 	 */
-	watchdog_ticktock.expires=jiffies+TIMER_MARGIN;
+	watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
 	add_timer(&watchdog_ticktock);
 	timer_alive++;
 	return 0;
@@ -68,11 +83,13 @@
 {
 	/*
 	 *	Shut off the timer.
+	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
 	 */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	 
 	del_timer(&watchdog_ticktock);
-#endif	
+	MOD_DEC_USE_COUNT;
 	timer_alive=0;
+#endif	
 }
 
 static int softdog_write(struct inode *inode, struct file *file, const char *data, int len)
@@ -81,39 +98,50 @@
 	 *	Refresh the timer.
 	 */
 	del_timer(&watchdog_ticktock);
-	watchdog_ticktock.expires=jiffies+TIMER_MARGIN;
+	watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
 	add_timer(&watchdog_ticktock);
 	return 1;
 }
 
-/*
- *	The mouse stuff ought to be renamed misc_register etc before 1.4...
- */
- 
-void watchdog_init(void)
+static struct file_operations softdog_fops=
+{
+	NULL,		/* Seek */
+	NULL,		/* Read */
+	softdog_write,	/* Write */
+	NULL,		/* Readdir */
+	NULL,		/* Select */
+	NULL,		/* Ioctl */
+	NULL,		/* MMap */
+	softdog_open,
+	softdog_release,
+	NULL,		
+	NULL		/* Fasync */
+};
+
+static struct miscdevice softdog_miscdev=
 {
-	static struct file_operations softdog_fops=
-	{
-		NULL,		/* Seek */
-		NULL,		/* Read */
-		softdog_write,	/* Write */
-		NULL,		/* Readdir */
-		NULL,		/* Select */
-		NULL,		/* Ioctl */
-		NULL,		/* MMap */
-		softdog_open,
-		softdog_release,
-		NULL,		
-		NULL		/* Fasync */
-	};
-	static struct miscdevice softdog_mouse={
-		WATCHDOG_MINOR,
-		"softdog",
-		&softdog_fops
-	};
+	WATCHDOG_MINOR,
+	"softdog",
+	&softdog_fops
+};
 
-	misc_register(&softdog_mouse);
+void watchdog_init(void)
+{
+	misc_register(&softdog_miscdev);
 	init_timer(&watchdog_ticktock);
 	watchdog_ticktock.function=watchdog_fire;
-	printk("Software Watchdog Timer: 0.03\n");
+	printk("Software Watchdog Timer: 0.04, timer margin: %d sec\n", soft_margin);
 }	
+
+#ifdef MODULE
+int init_module(void)
+{
+	watchdog_init();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	misc_deregister(&softdog_miscdev);
+}
+#endif
diff -u --recursive --new-file pre2.0.2/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- pre2.0.2/linux/drivers/char/vt.c	Mon Apr 29 18:05:17 1996
+++ linux/drivers/char/vt.c	Mon May 13 07:36:19 1996
@@ -236,6 +236,7 @@
 		 * If the time is zero, turn off sound ourselves.
 		 */
 		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+		if ((arg & 0xffff) == 0 ) arg |= 1; /* jp: huh? */
 		count = ticks ? (1193180 / (arg & 0xffff)) : 0;
 		kd_mksound(count, ticks);
 		return 0;
@@ -700,7 +701,7 @@
 
 		if (!perm)
 			return -EPERM;
-		i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
+		i = verify_area(VERIFY_READ, (void *)vtmode, sizeof(struct vt_mode));
 		if (i)
 			return i;
 		mode = get_user(&vtmode->mode);
diff -u --recursive --new-file pre2.0.2/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- pre2.0.2/linux/drivers/isdn/isdn_tty.c	Sun Apr 21 19:22:07 1996
+++ linux/drivers/isdn/isdn_tty.c	Mon May 13 07:36:19 1996
@@ -219,7 +219,7 @@
         }
 }
 
-static inline int isdn_tty_paranoia_check(modem_info * info, dev_t device, const char *routine)
+static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
 {
 #ifdef MODEM_PARANOIA_CHECK
 	if (!info) {
diff -u --recursive --new-file pre2.0.2/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- pre2.0.2/linux/drivers/net/Config.in	Sun May  5 08:52:00 1996
+++ linux/drivers/net/Config.in	Mon May 13 07:17:23 1996
@@ -20,6 +20,7 @@
 if [ "$CONFIG_SLIP" != "n" ]; then
   bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
   bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
 fi
 bool 'Radio network interfaces' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" != "n" ]; then
diff -u --recursive --new-file pre2.0.2/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- pre2.0.2/linux/drivers/net/slip.c	Tue May  7 16:22:31 1996
+++ linux/drivers/net/slip.c	Mon May 13 07:17:23 1996
@@ -56,9 +56,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
-/* Undef this, if you don't need 6bit encapsulation code in the driver */
-#define CONFIG_SLIP_MODE_SLIP6
-
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
diff -u --recursive --new-file pre2.0.2/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- pre2.0.2/linux/drivers/scsi/ultrastor.c	Mon Mar  4 09:16:40 1996
+++ linux/drivers/scsi/ultrastor.c	Mon May 13 09:01:23 1996
@@ -951,7 +951,7 @@
     return SCSI_ABORT_SUCCESS;
 }
 
-int ultrastor_reset(Scsi_Cmnd * SCpnt)
+int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
     int flags;
     register int i;
@@ -1044,7 +1044,7 @@
 	printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
 	/* A command has been lost.  Reset and report an error
 	   for all commands.  */
-	ultrastor_reset(NULL);
+	ultrastor_reset(NULL, 0);
 	return;
     }
 #endif
diff -u --recursive --new-file pre2.0.2/linux/drivers/scsi/ultrastor.h linux/drivers/scsi/ultrastor.h
--- pre2.0.2/linux/drivers/scsi/ultrastor.h	Thu Sep 21 09:01:48 1995
+++ linux/drivers/scsi/ultrastor.h	Mon May 13 09:01:23 1996
@@ -18,7 +18,7 @@
 const char *ultrastor_info(struct Scsi_Host * shpnt);
 int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int ultrastor_abort(Scsi_Cmnd *);
-int ultrastor_reset(Scsi_Cmnd *);
+int ultrastor_reset(Scsi_Cmnd *, unsigned int);
 int ultrastor_biosparam(Disk *, kdev_t, int *);
 
 
diff -u --recursive --new-file pre2.0.2/linux/fs/Config.in linux/fs/Config.in
--- pre2.0.2/linux/fs/Config.in	Tue May  7 16:22:35 1996
+++ linux/fs/Config.in	Mon May 13 12:15:23 1996
@@ -5,6 +5,7 @@
 comment 'Filesystems'
 
 bool	 'Quota support' CONFIG_QUOTA
+bool	 'Mandatory lock support' CONFIG_LOCK_MANDATORY
 tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'Extended fs support' CONFIG_EXT_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
diff -u --recursive --new-file pre2.0.2/linux/fs/binfmt_java.c linux/fs/binfmt_java.c
--- pre2.0.2/linux/fs/binfmt_java.c	Sun May 12 22:54:24 1996
+++ linux/fs/binfmt_java.c	Mon May 13 07:17:23 1996
@@ -14,7 +14,10 @@
 
 #define _PATH_JAVA	"/usr/bin/java"
 #define _PATH_APPLET	"/usr/bin/appletviewer"
-#define _PATH_SH	"/bin/sh"
+#define _PATH_SH	"/bin/bash"
+
+char binfmt_java_interpreter[65] = _PATH_JAVA;
+char binfmt_java_appletviewer[65] = _PATH_APPLET;
 
 static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
 {
@@ -47,7 +50,7 @@
 	bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
 	bprm->argc++;
 
-	strcpy (bprm->buf, _PATH_JAVA);
+	strcpy (bprm->buf, binfmt_java_interpreter);
 	cp = bprm->buf;
 	bprm->p = copy_strings(1, &cp, bprm->page, bprm->p, 2);
 	bprm->argc++;
@@ -102,12 +105,12 @@
 	bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
 	bprm->argc++;
 
-	strcpy (bprm->buf, _PATH_APPLET);
+	strcpy (bprm->buf, binfmt_java_appletviewer);
 	cp = bprm->buf;
 	bprm->p = copy_strings(1, &cp, bprm->page, bprm->p, 2);
 	bprm->argc++;
 
-	strcpy (bprm->buf, _PATH_BSHELL);
+	strcpy (bprm->buf, _PATH_SH);
 	interp = bprm->buf;
 	if ((i_name = strrchr (bprm->buf, '/')) != NULL)
 		i_name++;
diff -u --recursive --new-file pre2.0.2/linux/fs/devices.c linux/fs/devices.c
--- pre2.0.2/linux/fs/devices.c	Fri Apr 19 10:08:01 1996
+++ linux/fs/devices.c	Mon May 13 07:36:19 1996
@@ -25,7 +25,7 @@
 /* serial module kerneld load support */
 struct tty_driver *get_tty_driver(kdev_t device);
 #define isa_tty_dev(ma)	(ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
-#define need_serial(ma,mi) (get_tty_driver(to_kdev_t(MKDEV(ma,mi))) == NULL)
+#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
 #endif
 
 struct device_struct {
diff -u --recursive --new-file pre2.0.2/linux/fs/dquot.c linux/fs/dquot.c
--- pre2.0.2/linux/fs/dquot.c	Wed Apr 17 09:06:32 1996
+++ linux/fs/dquot.c	Mon May 13 07:36:19 1996
@@ -904,7 +904,8 @@
 
 void dquot_init(void)
 {
-	printk("VFS: Diskquotas version %s initialized\r\n", __DQUOT_VERSION__);
+	printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\r\n",
+	       __DQUOT_VERSION__);
 	memset(hash_table, 0, sizeof(hash_table));
 	memset((caddr_t)&dqstats, 0, sizeof(dqstats));
 	first_dquot = NODQUOT;
diff -u --recursive --new-file pre2.0.2/linux/fs/file_table.c linux/fs/file_table.c
--- pre2.0.2/linux/fs/file_table.c	Wed Jan 10 09:27:39 1996
+++ linux/fs/file_table.c	Mon May 13 07:36:19 1996
@@ -124,7 +124,7 @@
 
 #ifdef CONFIG_QUOTA
 
-void add_dquot_ref(dev_t dev, short type)
+void add_dquot_ref(kdev_t dev, short type)
 {
 	struct file *filp;
 	int cnt;
@@ -139,7 +139,7 @@
 	}
 }
 
-void reset_dquot_ptrs(dev_t dev, short type)
+void reset_dquot_ptrs(kdev_t dev, short type)
 {
 	struct file *filp;
 	int cnt;
diff -u --recursive --new-file pre2.0.2/linux/fs/locks.c linux/fs/locks.c
--- pre2.0.2/linux/fs/locks.c	Tue May  7 16:22:36 1996
+++ linux/fs/locks.c	Mon May 13 13:02:50 1996
@@ -75,8 +75,14 @@
  *  Fixed deadlock condition for pathological code that mixes calls to
  *  flock() and fcntl().
  *  Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
+ *
+ *	BUG: MUST DISALLOW MANDATORY LOCK ON NFS/SMB/NCP FILE SYSTEM 
+ *	TO MATCH SYS5.4 SEMANTICS.
+ *
  */
 
+#include <linux/config.h>
+
 #include <linux/malloc.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -336,6 +342,7 @@
 
 int locks_mandatory_locked(struct inode *inode)
 {
+#ifdef CONFIG_LOCK_MANDATORY
 	struct file_lock *fl;
 
 	/* Search the lock list for this inode for any POSIX locks.
@@ -344,6 +351,7 @@
 		if ((fl->fl_flags & F_POSIX) && (fl->fl_owner != current))
 			return (-EAGAIN);
 	}
+#endif	
 	return (0);
 }
 
@@ -353,16 +361,19 @@
 	/* Candidates for mandatory locking have the setgid bit set
 	 * but no group execute bit -  an otherwise meaningless combination.
 	 */
+#ifdef CONFIG_LOCK_MANDATORY	 
 	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
 		return (locks_mandatory_area(read_write, inode, filp, offset,
 					     count));
+#endif					     
 	return (0);
 }
-	
+
 int locks_mandatory_area(int read_write, struct inode *inode,
 			 struct file *filp, unsigned int offset,
 			 unsigned int count)
 {
+#ifdef CONFIG_LOCK_MANDATORY	
 	struct file_lock *fl;
 
 repeat:
@@ -401,6 +412,7 @@
 			goto repeat;
 		}
 	}
+#endif
 	return (0);
 }
 
@@ -936,8 +948,8 @@
 		p += sprintf(p, "FLOCK  ADVISORY  ");
 	}
 	p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
-	p += sprintf(p, "%d %04x:%ld %ld %ld ",
-		     fl->fl_owner->pid, fl->fl_file->f_inode->i_dev,
+	p += sprintf(p, "%d %s:%ld %ld %ld ",
+		     fl->fl_owner->pid, kdevname(fl->fl_file->f_inode->i_dev),
 		     fl->fl_file->f_inode->i_ino, fl->fl_start,
 		     fl->fl_end);
 	p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n%d:%s",
diff -u --recursive --new-file pre2.0.2/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- pre2.0.2/linux/fs/ufs/ufs_inode.c	Sat Apr 27 15:19:59 1996
+++ linux/fs/ufs/ufs_inode.c	Mon May 13 07:36:19 1996
@@ -185,7 +185,7 @@
 
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
 	        /* XXX - should be ui_db[1] on little endian ufs filesystems */
-	        inode->i_rdev = ufsip->ui_db[0];
+	        inode->i_rdev = to_kdev_t(ufsip->ui_db[0]);
 	}
 
 	/* XXX - implement fast and slow symlinks */
diff -u --recursive --new-file pre2.0.2/linux/include/linux/cm206.h linux/include/linux/cm206.h
--- pre2.0.2/linux/include/linux/cm206.h	Sun May 12 10:16:07 1996
+++ linux/include/linux/cm206.h	Mon May 13 07:56:32 1996
@@ -56,7 +56,7 @@
 		   dc_mask_transmit_ready)
 
 /* now some constants related to the cm206 */
-/* another drive status byte, echoed by the cm206 on most commmands */
+/* another drive status byte, echoed by the cm206 on most commands */
 
 #define dsb_error_condition 0x1
 #define dsb_play_in_progress 0x4
diff -u --recursive --new-file pre2.0.2/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- pre2.0.2/linux/include/linux/mcdx.h	Fri Apr 12 15:52:07 1996
+++ linux/include/linux/mcdx.h	Mon May 13 12:44:25 1996
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.9
+ * VERSION: 2.2
  * 
  * 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
@@ -32,167 +32,102 @@
  *  
  */
 
+#ifndef __MCDX_H
+#define __MCDX_H
 /*
- *	The following lines are for user configuration
- *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 	PLEASE CONFIGURE THIS ACCORIDNG TO YOURS HARDWARE/JUMPER SETTINGS.
  *
- *	{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.
+ *      NOTE: I didn't get a drive at irq 9(2) working.  Not even alone.
  */
-#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: I didn't get a drive at irq 9(2) working.  Not even alone.
- */
-#if MCDX_AUTOPROBE == 0
-	#define MCDX_NDRIVES 1
-	#define MCDX_DRIVEMAP {		\
-			{0x300, 11},	\
+ /* #define I_WAS_IN_MCDX_H */
+#define MCDX_NDRIVES 1
+#define MCDX_DRIVEMAP {	{0x300, 11},	\
 			{0x304, 05},  	\
 			{0x000, 00},  	\
 			{0x000, 00},  	\
 			{0x000, 00},  	\
-	  	}
-#else
-	#error Autoprobing is not implemented yet.
-#endif
-
-#ifndef MCDX_QUIET
-#define MCDX_QUIET   1
-#endif
-
-#ifndef MCDX_DEBUG
-#define MCDX_DEBUG   0
-#endif
+}
+	  	
+/* 
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NO USER INTERVENTION NEEDED BELOW
+ * If You are shure that all configuration is done, please uncomment the
+ * line below. 
+ */
 
-/* *** make the following line uncommented, if you're sure,
- * *** all configuration is done */
-/* #define I_WAS_HERE */
-
-/*	The name of the device */
-#define MCDX "mcdx"	
-
-#if MCDX_QUIET == 1
-#define INFO(x)  
-#define xinfo(fmt, args...)
+#undef MCDX_DEBUG	/* This is *REALLY* only for developement! */
+
+#ifdef MCDX_DEBUG
+#define MCDX_TRACE(x) printk x
+#define MCDX_TRACE_IOCTL(x) printk x
 #else
-#define INFO(x) warn x
-#define xinfo(fmt, args...) _warn(fmt, ## args)
+#define MCDX_TRACE(x)
+#define MCDX_TRACE_IOCTL(x)
 #endif
 
-#define WARN(x) warn x
-#define xwarn(fmt, args...) _warn(fmt, ## args)
-#define _warn warn
-
-#if MCDX_DEBUG == 1
-#define TRACE(x) trace x
-#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 TRANSFER 	0
-#define REQUEST	 	0
-#define SLEEP		0
-#else
-#define TRACE(x)
-#endif
+/*      The name of the device */
+#define MCDX "mcdx"
 
-/*	The following addresses are taken from the Mitsumi Reference 
- *  and describe the possible i/o range for the controller.
+/*
+ *      Per controller 4 bytes i/o are needed. 
  */
-#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
 
-/*
- *	Bits
+/* 
+ * Masks for the status byte, returned from every command, set if
+ * the description is true 
  */
-
-/* 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 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			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 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 */
+#define MCDX_DATA_TIMEOUT	(HZ/10)		/* 0.1 second */
 
-#ifndef I_WAS_HERE
+#ifndef I_WAS_IN_MCDX_H
 #warning You have not edited mcdx.h
 #warning Perhaps irq and i/o settings are wrong.
 #endif
 
-/* ex:set ts=4 sw=4: */
+#endif 	/* __MCDX_H */
\ No newline at end of file
diff -u --recursive --new-file pre2.0.2/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- pre2.0.2/linux/include/linux/skbuff.h	Tue May  7 16:22:39 1996
+++ linux/include/linux/skbuff.h	Mon May 13 13:40:47 1996
@@ -110,7 +110,7 @@
 	unsigned char	*data;			/* Data head pointer				*/
 	unsigned char	*tail;			/* Tail pointer					*/
 	unsigned char 	*end;			/* End pointer					*/
-	void 		(*destructor)(struct sk_buff *this);	/* Destruct function		*/
+	void 		(*destructor)(struct sk_buff *);	/* Destruct function		*/
 };
 
 #ifdef CONFIG_SKB_LARGE
diff -u --recursive --new-file pre2.0.2/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- pre2.0.2/linux/include/linux/sysctl.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/sysctl.h	Mon May 13 07:17:23 1996
@@ -59,6 +59,8 @@
 #define KERN_REALROOTDEV 16	/* real root device to mount after initrd */
 #define KERN_NFSRNAME	17	/* NFS root name */
 #define KERN_NFSRADDRS	18	/* NFS root addresses */
+#define KERN_JAVA_INTERPRETER 19 /* path to Java(tm) interpreter */
+#define KERN_JAVA_APPLETVIEWER 20 /* path to Java(tm) appletviewer */
 
 /* CTL_VM names: */
 #define VM_SWAPCTL	1	/* struct: Set vm swapping control */
diff -u --recursive --new-file pre2.0.2/linux/include/linux/ucdrom.h linux/include/linux/ucdrom.h
--- pre2.0.2/linux/include/linux/ucdrom.h	Sun May 12 10:16:07 1996
+++ linux/include/linux/ucdrom.h	Mon May 13 07:36:19 1996
@@ -5,23 +5,24 @@
 #ifndef LINUX_UCDROM_H
 #define LINUX_UCDROM_H
 
+#ifdef __KERNEL__
 struct cdrom_device_ops {
 /* routines */
-	int (*open) (dev_t, int);
-	void (*release) (dev_t);
-	int (*open_files) (dev_t);      /* number of open files */
-	int (*drive_status) (dev_t);
-	int (*disc_status) (dev_t);
-	int (*media_changed) (dev_t);
-	int (*tray_move) (dev_t, int);
-	int (*lock_door) (dev_t, int);
-	int (*select_speed) (dev_t, int);
-	int (*select_disc) (dev_t, int);
-	int (*get_last_session) (dev_t, struct cdrom_multisession *);
-	int (*get_mcn) (dev_t, struct cdrom_mcn *);
-	int (*reset) (dev_t dev);       /* hard reset device */
-	int (*audio_ioctl) (dev_t, unsigned int, void *); /* play stuff */
-	int (*dev_ioctl) (dev_t, unsigned int, unsigned long); /* dev-specific */
+	int (*open) (kdev_t, int);
+	void (*release) (kdev_t);
+	int (*open_files) (kdev_t);      /* number of open files */
+	int (*drive_status) (kdev_t);
+	int (*disc_status) (kdev_t);
+	int (*media_changed) (kdev_t);
+	int (*tray_move) (kdev_t, int);
+	int (*lock_door) (kdev_t, int);
+	int (*select_speed) (kdev_t, int);
+	int (*select_disc) (kdev_t, int);
+	int (*get_last_session) (kdev_t, struct cdrom_multisession *);
+	int (*get_mcn) (kdev_t, struct cdrom_mcn *);
+	int (*reset) (kdev_t dev);       /* hard reset device */
+	int (*audio_ioctl) (kdev_t, unsigned int, void *); /* play stuff */
+	int (*dev_ioctl) (kdev_t, unsigned int, unsigned long); /* dev-specific */
 /* specifications */
 	const int capability;           /* capability flags */
 	int mask;                       /* mask of capability: disables them */
@@ -32,6 +33,7 @@
 	int options;                    /* options flags */
 	long mc_flags;                  /* media change buffer flags (2*16) */
 };
+#endif
 
 /* capability flags */
 #define CDC_CLOSE_TRAY	0x1             /* caddy systems _can't_ close */
@@ -74,15 +76,17 @@
 #define CDROM_DRIVE_STATUS	0x5326  /* tray position, etc. */
 #define CDROM_DISC_STATUS	0x5327  /* disc type etc. */
 
-/* Rename and old ioctl */
+/* Rename an old ioctl */
 #define CDROM_GET_MCN	CDROM_GET_UPC	/* medium catalog number */
 
+#ifdef __KERNEL__
 /* the general file operations structure: */
 extern struct file_operations cdrom_fops;
 
 extern int register_cdrom(int major, char *name,
                           struct cdrom_device_ops *cdo);
 extern int unregister_cdrom(int major, char *name);
+#endif
 
 #endif	/* LINUX_UCDROM_H */
 /*
diff -u --recursive --new-file pre2.0.2/linux/include/net/af_unix.h linux/include/net/af_unix.h
--- pre2.0.2/linux/include/net/af_unix.h	Mon Mar 25 08:58:22 1996
+++ linux/include/net/af_unix.h	Mon May 13 07:17:23 1996
@@ -1,9 +1,14 @@
+#ifndef __LINUX_NET_AFUNIX_H
+#define __LINUX_NET_AFUNIX_H
 extern void unix_proto_init(struct net_proto *pro);
 extern struct proto_ops unix_proto_ops;
 extern void unix_inflight(struct file *fp);
 extern void unix_notinflight(struct file *fp);
 typedef struct sock unix_socket;
+extern void unix_gc(void);
 
-unix_socket *unix_socket_list;
+extern unix_socket *unix_socket_list;
 
 #define UNIX_MAX_FD	8
+
+#endif
diff -u --recursive --new-file pre2.0.2/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- pre2.0.2/linux/kernel/ksyms.c	Mon Apr 29 18:05:20 1996
+++ linux/kernel/ksyms.c	Mon May 13 07:17:23 1996
@@ -74,6 +74,8 @@
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 
+extern void hard_reset_now(void);
+
 struct symbol_table symbol_table = {
 #include <linux/symtab_begin.h>
 #ifdef MODVERSIONS
@@ -292,6 +294,7 @@
 	X(simple_strtoul),
 	X(system_utsname),
 	X(sys_call_table),
+	X(hard_reset_now),
 
 	/* Signal interfaces */
 	X(send_sig),
diff -u --recursive --new-file pre2.0.2/linux/kernel/sys.c linux/kernel/sys.c
--- pre2.0.2/linux/kernel/sys.c	Sun May  5 08:52:05 1996
+++ linux/kernel/sys.c	Mon May 13 07:36:19 1996
@@ -304,7 +304,7 @@
       ac.ac_uid   = current->uid;
       ac.ac_gid   = current->gid;
       ac.ac_tty   = (current)->tty == NULL ? -1 :
-	  MKDEV(4, current->tty->device);
+	  kdev_t_to_nr(current->tty->device);
       ac.ac_flag  = 0;
       if (current->flags & PF_FORKNOEXEC)
          ac.ac_flag |= AFORK;
diff -u --recursive --new-file pre2.0.2/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- pre2.0.2/linux/kernel/sysctl.c	Fri Apr 12 15:52:10 1996
+++ linux/kernel/sysctl.c	Mon May 13 07:17:23 1996
@@ -5,6 +5,7 @@
  * Added /proc support, Dec 1995
  * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
  * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
+ * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
  */
 
 #include <linux/config.h>
@@ -97,6 +98,8 @@
 static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
 				    void *, size_t, void **);
 
+extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
+
 /* The default sysctl tables: */
 
 static ctl_table root_table[] = {
@@ -138,6 +141,12 @@
 	 0644, NULL, &proc_dostring, &sysctl_string },
 	{KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
 	 0644, NULL, &proc_dostring, &sysctl_string },
+#endif
+#ifdef CONFIG_BINFMT_JAVA
+	{KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
+	 64, 0644, NULL, &proc_dostring, &sysctl_string },
+	{KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
+	 64, 0644, NULL, &proc_dostring, &sysctl_string },
 #endif
 	{0}
 };
diff -u --recursive --new-file pre2.0.2/linux/net/README linux/net/README
--- pre2.0.2/linux/net/README	Sat Apr 27 15:20:09 1996
+++ linux/net/README	Mon May 13 07:17:23 1996
@@ -3,26 +3,26 @@
 
 Code Section		Bug Report Contact
 -------------------+-------------------------------------------
-802 [other	]	alan@cymru.net	
+802 [other	]	alan@lxorguk.ukuu.org.uk	
     [token ring	]	needs a maintainer/debugger
-appletalk		alan@cymru.net and netatalk@umich.edu
+appletalk		alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
 ax25			jsn@cs.nott.ac.uk
-core			alan@cymru.net
-ethernet		alan@cymru.net
-ipv4			alan@cymru.net
-ipx			alan@cymru.net,greg@caldera.com
+core			alan@lxorguk.ukuu.org.uk
+ethernet		alan@lxorguk.ukuu.org.uk
+ipv4			alan@lxorguk.ukuu.org.uk
+ipx			alan@lxorguk.ukuu.org.uk,greg@caldera.com
 netrom			jsn@cs.nott.ac.uk
-unix			alan@cymru.net
+unix			alan@lxorguk.ukuu.org.uk
 
 
-	If in doubt contact me <alan@cymru.net> first.
+	If in doubt contact me <alan@lxorguk.ukuu.org.uk> first.
 
 ---------------------------------------------------------------------------
 
 For commercial UK custom Linux networking projects, drivers and development
 (but not free support!) I can be contacted via
 
-	I^2IT Ltd, The Innovation Centre, University Of Wales
+	CymruNET Ltd, The Innovation Centre, University Of Wales
 		Swansea SA2 8PP.  
 	Fax: +44 1792 295811
 	Tel: +44 1792 295213
diff -u --recursive --new-file pre2.0.2/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- pre2.0.2/linux/net/appletalk/aarp.c	Fri Apr 12 15:52:10 1996
+++ linux/net/appletalk/aarp.c	Mon May 13 12:15:23 1996
@@ -794,7 +794,7 @@
 void aarp_proto_init(void)
 {
 	if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
-		printk("Unable to register AARP with SNAP.\n");
+		printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
 	init_timer(&aarp_timer);
 	aarp_timer.function=aarp_expire_timeout;
 	aarp_timer.data=0;
diff -u --recursive --new-file pre2.0.2/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- pre2.0.2/linux/net/appletalk/ddp.c	Fri Apr 12 15:52:10 1996
+++ linux/net/appletalk/ddp.c	Mon May 13 12:15:23 1996
@@ -830,7 +830,7 @@
 				limit=ntohs(nr->nr_lastnet);
 				if(limit-ntohs(nr->nr_firstnet) > 256)
 				{
-					printk("Too many routes/iface.\n");
+					printk(KERN_WARING "Too many routes/iface.\n");
 					return -EINVAL;
 				}
 				for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
@@ -2013,7 +2013,7 @@
 {
 	(void) sock_register(atalk_proto_ops.family, &atalk_proto_ops);
 	if ((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL)
-		printk("Unable to register DDP with SNAP.\n");
+		printk(KERN_CRIT "Unable to register DDP with SNAP.\n");
 	
 	ltalk_packet_type.type=htons(ETH_P_LOCALTALK);	
 	dev_add_pack(&ltalk_packet_type);
@@ -2043,7 +2043,7 @@
 		atalk_if_get_info
 	});
 
-	printk(KERN_INFO "Appletalk 0.17 for Linux NET3.034\n");
+	printk(KERN_INFO "Appletalk 0.17 for Linux NET3.035\n");
 }
 
 #ifdef MODULE
diff -u --recursive --new-file pre2.0.2/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- pre2.0.2/linux/net/ax25/af_ax25.c	Tue May  7 16:22:40 1996
+++ linux/net/ax25/af_ax25.c	Mon May 13 12:15:23 1996
@@ -636,8 +636,10 @@
 	  	case AX25_PACLEN:
 	  		if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) 
 	  			return -EINVAL;
+#if 0
 	  		if (ax25_ctl.arg > 256) /* we probably want this */
-	  			printk("ax25_ctl_ioctl: Warning --- huge paclen %d\n", (int)ax25_ctl.arg);
+	  			printk(KERN_WARNING "ax25_ctl_ioctl: Warning --- huge paclen %d\n", (int)ax25_ctl.arg);
+#endif	  			
 	  		ax25->paclen = ax25_ctl.arg;
 	  		break;
 
@@ -2413,7 +2415,7 @@
 		ax25_cs_get_info
 	});
 
-	printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.32 BETA for Linux NET3.034 (Linux 1.3.77)\n");
+	printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.32 BETA for Linux NET3.035 (Linux 2.0)\n");
 
 #ifdef CONFIG_BPQETHER
 	proc_net_register(&(struct proc_dir_entry) {
@@ -2423,7 +2425,7 @@
 		ax25_bpq_get_info
 	});
 
-	printk("G8BPQ Encapsulation of AX.25 frames enabled\n");
+	printk(KERN_INFO "G8BPQ Encapsulation of AX.25 frames enabled\n");
 #endif
 }
 
@@ -2451,7 +2453,7 @@
 		int size;
 
 		if(skb_headroom(skb) < AX25_BPQ_HEADER_LEN) {
-			printk("ax25_queue_xmit: not enough space to add BPQ Ether header\n");
+			printk(KERN_CRIT "ax25_queue_xmit: not enough space to add BPQ Ether header\n");
 			dev_kfree_skb(skb, FREE_WRITE);
 			return;
 		}
@@ -2522,7 +2524,7 @@
   			*buff++ = AX25_P_ARP;
   			break;
   		default:
-  			printk("wrong protocol type 0x%x2.2\n", type);
+  			printk(KERN_ERR "wrong protocol type 0x%x2.2\n", type);
   			*buff++ = 0;
   			break;
  	}
diff -u --recursive --new-file pre2.0.2/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- pre2.0.2/linux/net/ax25/ax25_out.c	Tue May  7 16:22:40 1996
+++ linux/net/ax25/ax25_out.c	Mon May 13 12:15:23 1996
@@ -99,7 +99,7 @@
 			 */
 			if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) {
 				restore_flags(flags);
-				printk("ax25_output: alloc_skb returned NULL\n");
+				printk(KERN_DEBUG "ax25_output: alloc_skb returned NULL\n");
 				if (skb_device_locked(skb))
 					skb_device_unlock(skb);
 				return;
@@ -268,7 +268,7 @@
 	}
 
 	if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) {
-		printk("ax25_transmit_buffer: not enough room for digi-peaters\n");
+		printk(KERN_CRIT "ax25_transmit_buffer: not enough room for digi-peaters\n");
 		skb->free = 1;
 		kfree_skb(skb, FREE_WRITE);
 		return;
diff -u --recursive --new-file pre2.0.2/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
--- pre2.0.2/linux/net/ax25/ax25_route.c	Sun May  5 08:52:05 1996
+++ linux/net/ax25/ax25_route.c	Mon May 13 12:15:23 1996
@@ -598,7 +598,7 @@
 	len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
 		
 	if (skb_headroom(skb) < len) {
-		printk("ax25_dg_build_path: not enough headroom for digis in skb\n");
+		printk(KERN_CRIT "ax25_dg_build_path: not enough headroom for digis in skb\n");
 		return;
 	}
 	
@@ -659,7 +659,7 @@
 	struct ax25_dev *ax25_dev;
 
 	if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
-		printk("ax25_dev_get_flag called with invalid device\n");
+		printk(KERN_WARNING "ax25_dev_get_flag called with invalid device\n");
 		return 1;
 	}
 
diff -u --recursive --new-file pre2.0.2/linux/net/bridge/br.c linux/net/bridge/br.c
--- pre2.0.2/linux/net/bridge/br.c	Sat Apr 27 15:20:10 1996
+++ linux/net/bridge/br.c	Mon May 13 12:15:24 1996
@@ -579,6 +579,7 @@
 {						  /* (4.8.1)	 */
 	int             port_no;
 
+	printk(KERN_INFO "Ethernet Bridge 002 for NET3.035 (Linux 2.0)\n");
 	bridge_info.designated_root = bridge_info.bridge_id;	/* (4.8.1.1)	 */
 	bridge_info.root_path_cost = Zero;
 	bridge_info.root_port = No_port;
@@ -876,7 +877,7 @@
 unsigned long flags;
 	
 	if (port_info[port_no].state == Disabled) {
-		printk("send_config_bpdu: port %i not valid\n",port_no);
+		printk(KERN_DEBUG "send_config_bpdu: port %i not valid\n",port_no);
 		return(-1);
 		}
 	if (br_stats.flags & BR_DEBUG)
@@ -887,7 +888,7 @@
 	size = sizeof(Config_bpdu) + dev->hard_header_len;
 	skb = alloc_skb(size, GFP_ATOMIC);
 	if (skb == NULL) {
-		printk("send_config_bpdu: no skb available\n");
+		printk(KERN_DEBUG "send_config_bpdu: no skb available\n");
 		return(-1);
 		}
 	skb->dev = dev;
@@ -935,7 +936,7 @@
 unsigned long flags;
 	
 	if (port_info[port_no].state == Disabled) {
-		printk("send_tcn_bpdu: port %i not valid\n",port_no);
+		printk(KERN_DEBUG "send_tcn_bpdu: port %i not valid\n",port_no);
 		return(-1);
 		}
 	if (br_stats.flags & BR_DEBUG)
@@ -943,7 +944,7 @@
 	size = sizeof(Tcn_bpdu) + dev->hard_header_len;
 	skb = alloc_skb(size, GFP_ATOMIC);
 	if (skb == NULL) {
-		printk("send_tcn_bpdu: no skb available\n");
+		printk(KERN_DEBUG "send_tcn_bpdu: no skb available\n");
 		return(-1);
 		}
 	skb->dev = dev;
@@ -1033,9 +1034,11 @@
 			}
 		}
 		break;
+#if 0
 	default:
 		printk("br_device_event: unknown event [%x]\n",
 			(unsigned int)event);
+#endif			
 	}
 	return NOTIFY_DONE;
 }
@@ -1054,7 +1057,7 @@
 		printk("br_receive_frame: ");
 	/* sanity */
 	if (!skb) {
-		printk("no skb!\n");
+		printk(KERN_CRIT "br_receive_frame: no skb!\n");
 		return(1);
 	}
 
@@ -1134,7 +1137,7 @@
 			skb_device_lock(skb);
 			return(br_forward(skb, port));
 		default:
-			printk("br_receive_frame: port [%i] unknown state [%i]\n",
+			printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
 				port, port_info[port].state);
 			return(0);	/* pass frame up stack? */
 	}
@@ -1153,7 +1156,7 @@
 	/* sanity */
 	if (!skb) 
 	{
-		printk("br_tx_frame: no skb!\n");
+		printk(KERN_CRIT "br_tx_frame: no skb!\n");
 		return(0);
 	}
 	/* check for loopback */
@@ -1208,7 +1211,7 @@
 				GFP_ATOMIC);
 
 			if (!f) {
-				printk("br_learn: unable to malloc fdb\n");
+				printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
 				return(-1);
 			}
 			f->port = port;	/* source port */
@@ -1260,7 +1263,6 @@
 int br_forward(struct sk_buff *skb, int port)	/* 3.7 */
 {
 	struct fdb *f;
-	unsigned long flags;
 	
 	/*
    	 * flood all ports with frames destined for a group
@@ -1344,7 +1346,6 @@
 {
 	int i;
 	struct sk_buff *nskb;
-	unsigned long flags;
 
 	for (i = One; i <= No_of_ports; i++) 
 	{
@@ -1411,7 +1412,7 @@
 			received_tcn_bpdu(port, bpdu);
 			break;
 		default:
-			printk("br_bpdu: received unknown bpdu, type = %i\n",
+			printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n",
 				bpdu->type);
 			/* break; */
 	}
@@ -1422,7 +1423,6 @@
 {
 	int err;
 	struct br_cf bcf;
-	int i;
 
 	switch(cmd)
 	{
@@ -1447,14 +1447,14 @@
 				case BRCMD_BRIDGE_ENABLE:
 					if (br_stats.flags & BR_UP)
 						return(-EALREADY);	
-					printk("br: enabling bridging function\n");
+					printk(KERN_DEBUG "br: enabling bridging function\n");
 					br_stats.flags |= BR_UP;	/* enable bridge */
 					start_hello_timer();
 					break;
 				case BRCMD_BRIDGE_DISABLE:
 					if (!(br_stats.flags & BR_UP))
 						return(-EALREADY);	
-					printk("br: disabling bridging function\n");
+					printk(KERN_DEBUG "br: disabling bridging function\n");
 					br_stats.flags &= ~BR_UP;	/* disable bridge */
 					stop_hello_timer();
 #if 0					
@@ -1468,7 +1468,7 @@
 						return(-EINVAL);
 					if (port_info[bcf.arg1].state != Disabled)
 						return(-EALREADY);
-					printk("br: enabling port %i\n",bcf.arg1);
+					printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
 					enable_port(bcf.arg1);
 					break;
 				case BRCMD_PORT_DISABLE:
@@ -1476,7 +1476,7 @@
 						return(-EINVAL);
 					if (port_info[bcf.arg1].state == Disabled)
 						return(-EALREADY);
-					printk("br: disabling port %i\n",bcf.arg1);
+					printk(KERN_DEBUG "br: disabling port %i\n",bcf.arg1);
 					disable_port(bcf.arg1);
 					break;
 				case BRCMD_SET_BRIDGE_PRIORITY:
diff -u --recursive --new-file pre2.0.2/linux/net/bridge/br_tree.c linux/net/bridge/br_tree.c
--- pre2.0.2/linux/net/bridge/br_tree.c	Wed Apr 10 17:02:27 1996
+++ linux/net/bridge/br_tree.c	Mon May 13 12:15:24 1996
@@ -24,7 +24,6 @@
 static int fdb_inited = 0;
 
 int addr_cmp(unsigned char *a1, unsigned char *a2);
-static void printk_avl (struct fdb * tree);
 
 /*
  * fdb_head is the AVL tree corresponding to fdb
@@ -264,7 +263,7 @@
 		struct fdb * node = *nodeplace;
 		if (node == avl_br_empty) {
 			/* what? node_to_delete not found in tree? */
-			printk("avl_remove: node to delete not found in tree\n");
+			printk(KERN_ERR "br: avl_remove: node to delete not found in tree\n");
 			return(-1);
 		}
 		*stack_ptr++ = nodeplace; stack_count++;
diff -u --recursive --new-file pre2.0.2/linux/net/core/dev.c linux/net/core/dev.c
--- pre2.0.2/linux/net/core/dev.c	Tue May  7 16:22:40 1996
+++ linux/net/core/dev.c	Mon May 13 12:15:24 1996
@@ -184,7 +184,7 @@
 			return;
 		}
 	}
-	printk("dev_remove_pack: %p not found.\n", pt);
+	printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
 }
 
 /*****************************************************************************************
@@ -360,7 +360,7 @@
 #ifdef CONFIG_NET_DEBUG
 	if (pri >= DEV_NUMBUFFS) 
 	{
-		printk("bad priority in dev_queue_xmit.\n");
+		printk(KERN_WARNING "bad priority in dev_queue_xmit.\n");
 		pri = 1;
 	}
 #endif
diff -u --recursive --new-file pre2.0.2/linux/net/core/net_alias.c linux/net/core/net_alias.c
--- pre2.0.2/linux/net/core/net_alias.c	Tue May  7 16:22:41 1996
+++ linux/net/core/net_alias.c	Mon May 13 12:15:24 1996
@@ -157,7 +157,7 @@
   if (n_at < 0)
   {
     restore_flags(flags);
-    printk("net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
+    printk(KERN_WARNING "net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
 	   nat->type);
     return -1;
   }
@@ -229,7 +229,7 @@
 static int
 net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
 {
-  printk("net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
+  printk(KERN_WARNING "net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
   dev_kfree_skb(skb, FREE_WRITE);
   return 0;
 }
@@ -363,7 +363,7 @@
     nat = nat_getbytype(family);
     if (!nat) {
 #endif
-      printk("net_alias_dev_create(%s:%d): unregistered family==%d\n",
+      printk(KERN_WARNING "net_alias_dev_create(%s:%d): unregistered family==%d\n",
              main_dev->name, slot, family);
       /* *err = -EAFNOSUPPORT; */
       *err = -EINVAL;
@@ -509,7 +509,7 @@
   {
     if (!(alias = prevdev->next->my_alias))
     {
-      printk("ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
+      printk(KERN_ERR "ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
       continue;			/* or should give up? */
     }
     if (alias->slot == slot) break;
@@ -534,10 +534,10 @@
   
   if (*aliasp != alias)
     if ((aliasp = net_alias_slow_findp(alias_info, alias)))
-      printk("net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
+      printk(KERN_WARNING "net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
     else
     {
-      printk("ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
+      printk(KERN_ERR "ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
       return NULL;		/* ENODEV */
     }
   
@@ -654,11 +654,11 @@
 	continue;
       }
       else
-	printk("net_alias_free(%s): '%s' is not my alias\n",
+	printk(KERN_ERR "net_alias_free(%s): '%s' is not my alias\n",
 	       main_dev->name, alias->name);
     }
     else
-      printk("net_alias_free(%s): found a non-alias after device!\n",
+      printk(KERN_ERR "net_alias_free(%s): found a non-alias after device!\n",
 	     main_dev->name);
     dev = dev->next;
   }
@@ -760,7 +760,7 @@
   
   if (!sa)
   {
-    printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
+    printk(KERN_ERR "ERROR: net_alias_rehash(): NULL sockaddr passed\n");
     return -1;
   }
 
@@ -770,7 +770,7 @@
 
   if ( (main_dev = alias->main_dev) == NULL )
   {
-    printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
+    printk(KERN_ERR "ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
     return -1;
   }
 
@@ -780,7 +780,7 @@
 
   if (!(alias_info=main_dev->alias_info))
   {
-    printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
+    printk(KERN_ERR "ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
     return -1;
   }
   
@@ -791,7 +791,7 @@
   o_nat = alias->nat;
   if (!o_nat)
   {
-    printk("ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
+    printk(KERN_ERR "ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
     return -1;
   }
 
@@ -806,7 +806,7 @@
     n_nat = nat_getbytype(sa->sa_family);
     if (!n_nat)
     {
-      printk("ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
+      printk(KERN_ERR "ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
       return -1;
     }
   }
@@ -832,10 +832,10 @@
   
   if(!*aliasp)
     if ((aliasp = net_alias_slow_findp(alias_info, alias)))
-      printk("net_alias_rehash(%s): bad hashing recovered\n", alias->name);
+      printk(KERN_WARNING "net_alias_rehash(%s): bad hashing recovered\n", alias->name);
     else
     {
-      printk("ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
+      printk(KERN_ERR "ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
       return -1;
     }
   
@@ -1309,7 +1309,7 @@
   unsigned long flags;
   if (!nat)
   {
-    printk("register_net_alias_type(): NULL arg\n");
+    printk(KERN_ERR "register_net_alias_type(): NULL arg\n");
     return -EINVAL;
   }
   nat->type = type;
@@ -1334,7 +1334,7 @@
   
   if (!nat)
   {
-    printk("unregister_net_alias_type(): NULL arg\n");
+    printk(KERN_ERR "unregister_net_alias_type(): NULL arg\n");
     return -EINVAL;
   }
 
@@ -1343,7 +1343,7 @@
    */
   if (nat->n_attach)
   {
-    printk("unregister_net_alias_type(): has %d attachments. failed\n",
+    printk(KERN_ERR "unregister_net_alias_type(): has %d attachments. failed\n",
 	   nat->n_attach);
     return -EINVAL;
   }
@@ -1360,7 +1360,7 @@
     }
   }
   restore_flags(flags);
-  printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
+  printk(KERN_ERR "unregister_net_alias_type(type=%d): not found!\n", nat->type);
   return -EINVAL;
 }
 
diff -u --recursive --new-file pre2.0.2/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- pre2.0.2/linux/net/core/skbuff.c	Sat Apr 27 15:20:10 1996
+++ linux/net/core/skbuff.c	Mon May 13 12:15:24 1996
@@ -69,13 +69,13 @@
 
 void show_net_buffers(void)
 {
-	printk("Networking buffers in use          : %u\n",net_skbcount);
-	printk("Network buffers locked by drivers  : %u\n",net_locked);
-	printk("Total network buffer allocations   : %u\n",net_allocs);
-	printk("Total failed network buffer allocs : %u\n",net_fails);
-	printk("Total free while locked events     : %u\n",net_free_locked);
+	printk(KERN_INFO "Networking buffers in use          : %u\n",net_skbcount);
+	printk(KERN_INFO "Network buffers locked by drivers  : %u\n",net_locked);
+	printk(KERN_INFO "Total network buffer allocations   : %u\n",net_allocs);
+	printk(KERN_INFO "Total failed network buffer allocs : %u\n",net_fails);
+	printk(KERN_INFO "Total free while locked events     : %u\n",net_free_locked);
 #ifdef CONFIG_INET
-	printk("IP fragment buffer size            : %u\n",ip_frag_mem);
+	printk(KERN_INFO "IP fragment buffer size            : %u\n",ip_frag_mem);
 #endif	
 }
 
@@ -578,7 +578,7 @@
 {
 	if (skb == NULL)
 	{
-		printk("kfree_skb: skb = NULL (from %p)\n",
+		printk(KERN_CRIT "kfree_skb: skb = NULL (from %p)\n",
 			__builtin_return_address(0));
 		return;
   	}
@@ -592,10 +592,10 @@
 		return;
   	}
   	if (skb->free == 2)
-		printk("Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n",
+		printk(KERN_WARNING "Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n",
 			__builtin_return_address(0));
 	if (skb->list)
-	 	printk("Warning: kfree_skb passed an skb still on a list (from %p).\n",
+	 	printk(KERN_WARNING "Warning: kfree_skb passed an skb still on a list (from %p).\n",
 			__builtin_return_address(0));
 
 	if(skb->destructor)
@@ -641,7 +641,7 @@
 	{
 		static int count = 0;
 		if (++count < 5) {
-			printk("alloc_skb called nonatomically from interrupt %p\n",
+			printk(KERN_ERR "alloc_skb called nonatomically from interrupt %p\n",
 				__builtin_return_address(0));
 			priority = GFP_ATOMIC;
 		}
diff -u --recursive --new-file pre2.0.2/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- pre2.0.2/linux/net/ethernet/eth.c	Tue May  7 16:22:41 1996
+++ linux/net/ethernet/eth.c	Mon May 13 12:15:24 1996
@@ -231,7 +231,7 @@
 
 	if (htype != ETH_P_IP)
 	{
-		printk("eth_header_cache_bind: %04x cache is not implemented\n", htype);
+		printk(KERN_DEBUG "eth_header_cache_bind: %04x cache is not implemented\n", htype);
 		return;
 	}
 	if (arp_bind_cache(hhp, dev, htype, daddr))
@@ -252,7 +252,7 @@
 {
 	if (hh->hh_type != ETH_P_IP)
 	{
-		printk("eth_header_cache_update: %04x cache is not implemented\n", hh->hh_type);
+		printk(KERN_DEBUG "eth_header_cache_update: %04x cache is not implemented\n", hh->hh_type);
 		return;
 	}
 	memcpy(hh->hh_data, haddr, ETH_ALEN);
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- pre2.0.2/linux/net/ipv4/Config.in	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/Config.in	Mon May 13 07:17:24 1996
@@ -30,6 +30,6 @@
 bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
 tristate 'IP: Reverse ARP' CONFIG_INET_RARP
 bool 'IP: Disable Path MTU Discovery (normally enabled)' CONFIG_NO_PATH_MTU_DISCOVERY
-bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF
+#bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF
 bool 'IP: Drop source routed frames' CONFIG_IP_NOSR
 bool 'IP: Allow large windows (not recommended if <16Mb of memory)' CONFIG_SKB_LARGE
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- pre2.0.2/linux/net/ipv4/arp.c	Sun May 12 10:16:08 1996
+++ linux/net/ipv4/arp.c	Mon May 13 12:15:24 1996
@@ -1105,7 +1105,7 @@
 	
 	if(!(entry->flags&ATF_COM))
 	{
-		printk("arp_send_q: incomplete entry for %s\n",
+		printk(KERN_ERR "arp_send_q: incomplete entry for %s\n",
 				in_ntoa(entry->ip));
 		/* Can't flush the skb, because RFC1122 says to hang on to */
 		/* at least one from any unresolved entry.  --MS */
@@ -1670,7 +1670,7 @@
 				+ dev->hard_header_len, GFP_ATOMIC);
 	if (skb == NULL)
 	{
-		printk("ARP: no memory to send an arp packet\n");
+		printk(KERN_DEBUG "ARP: no memory to send an arp packet\n");
 		return;
 	}
 	skb_reserve(skb, dev->hard_header_len);
@@ -1798,7 +1798,7 @@
 			break;
 
 		default:
-			printk("ARP: dev->type mangled!\n");
+			printk(KERN_ERR "ARP: dev->type mangled!\n");
 			kfree_skb(skb, FREE_READ);
 			return 0;
 	}
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- pre2.0.2/linux/net/ipv4/igmp.c	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/igmp.c	Mon May 13 12:15:24 1996
@@ -203,7 +203,7 @@
     im->tm_running=0;
   }
   else {
-    printk("igmp_stop_timer() called with timer not running by %p\n",__builtin_return_address(0));
+    printk(KERN_ERR "igmp_stop_timer() called with timer not running by %p\n",__builtin_return_address(0));
   }
 }
 
@@ -459,7 +459,7 @@
 	 
 	if(saddr==0)
 	{
-		printk("Broken multicast host using 0.0.0.0 heard on %s\n",
+		printk(KERN_INFO "Broken multicast host using 0.0.0.0 heard on %s\n",
 			dev->name);
 		kfree_skb(skb, FREE_READ);
 		return 0;
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/ip_alias.c linux/net/ipv4/ip_alias.c
--- pre2.0.2/linux/net/ipv4/ip_alias.c	Mon Mar 25 08:58:25 1996
+++ linux/net/ipv4/ip_alias.c	Mon May 13 12:15:24 1996
@@ -159,7 +159,7 @@
 void cleanup_module(void)
 {
 	if (ip_alias_done() != 0)
-		printk("ip_alias: can't remove module");
+		printk(KERN_INFO "ip_alias: can't remove module");
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- pre2.0.2/linux/net/ipv4/ip_forward.c	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/ip_forward.c	Mon May 13 12:15:24 1996
@@ -399,7 +399,7 @@
 					optptr[2] = srrptr+4;
 				}
 				else
-				        printk("ip_forward(): Argh! Destination lost!\n");
+				        printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");
 			}
 			if (opt->ts_needaddr) 
 			{
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- pre2.0.2/linux/net/ipv4/ip_fragment.c	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/ip_fragment.c	Mon May 13 12:15:24 1996
@@ -707,7 +707,7 @@
 
 		skb2->arp = skb->arp;
 		if(skb->free==0)
-			printk("IP fragmenter: BUG free!=1 in fragmenter\n");
+			printk(KERN_ERR "IP fragmenter: BUG free!=1 in fragmenter\n");
 		skb2->free = 1;
 		skb_put(skb2,len + hlen);
 		skb2->h.raw=(char *) skb2->data;
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- pre2.0.2/linux/net/ipv4/ipip.c	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/ipip.c	Mon May 13 12:15:24 1996
@@ -21,7 +21,6 @@
  
 #include <linux/module.h>
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -31,7 +30,6 @@
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/firewall.h>
-#include <linux/config.h>	/* For CONFIG_FIREWALL */
 
 #include <net/datalink.h>
 #include <net/sock.h>
@@ -53,9 +51,6 @@
 		__u32 daddr, unsigned short len, __u32 saddr,
                                    int redo, struct inet_protocol *protocol)
 {
-#ifdef CONFIG_FIREWALL
-	int err;
-#endif
 	/* Don't unlink in the middle of a turnaround */
 	MOD_INC_USE_COUNT;
 #ifdef TUNNEL_DEBUG
@@ -116,7 +111,7 @@
 void cleanup_module( void) 
 {
 	if ( inet_del_protocol(&ipip_protocol) < 0 )
-		printk("ipip close: can't remove protocol\n");
+		printk(KERN_INFO "ipip close: can't remove protocol\n");
 }
 
 #endif
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- pre2.0.2/linux/net/ipv4/ipmr.c	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/ipmr.c	Mon May 13 12:15:24 1996
@@ -908,7 +908,7 @@
  
 void ip_mr_init(void)
 {
-	printk("Linux IP multicast router 0.05-maybe-works 8)\n");
+	printk(KERN_INFO "Linux IP multicast router 0.05.\n");
 	register_netdevice_notifier(&ip_mr_notifier);
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- pre2.0.2/linux/net/ipv4/rarp.c	Wed Mar 27 08:19:29 1996
+++ linux/net/ipv4/rarp.c	Mon May 13 12:15:24 1996
@@ -320,7 +320,7 @@
 	ip = si->sin_addr.s_addr;
 	if (ip == 0)
 	{
-		printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n");
+		printk(KERN_DEBUG "RARP: SETRARP: requested PA is 0.0.0.0 !\n");
 		return -EINVAL;
 	}
   
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- pre2.0.2/linux/net/ipv4/tcp.c	Tue May  7 16:22:42 1996
+++ linux/net/ipv4/tcp.c	Mon May 13 12:15:24 1996
@@ -985,7 +985,7 @@
 					copy = min(sk->mss - tcp_size, seglen);
 					if (copy <= 0)
 					{
-						printk("TCP: **bug**: \"copy\" <= 0\n");
+						printk(KERN_CRIT "TCP: **bug**: \"copy\" <= 0\n");
 				  		return -EFAULT;
 					}
 					tcp_size += copy;
@@ -1023,7 +1023,7 @@
 				copy = seglen;
 			if (copy <= 0)
 			{
-				printk("TCP: **bug**: copy=%d, sk->mss=%d\n", copy, sk->mss);
+				printk(KERN_CRIT "TCP: **bug**: copy=%d, sk->mss=%d\n", copy, sk->mss);
 		  		return -EFAULT;
 			}
 
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- pre2.0.2/linux/net/ipv4/tcp_input.c	Sun May 12 10:16:08 1996
+++ linux/net/ipv4/tcp_input.c	Mon May 13 12:15:24 1996
@@ -1666,7 +1666,7 @@
 
 	if (!sk->prot) 
 	{
-		printk("IMPOSSIBLE 3\n");
+		printk(KERN_CRIT "IMPOSSIBLE 3\n");
 		return(0);
 	}
 
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- pre2.0.2/linux/net/ipv4/tcp_output.c	Tue May  7 16:22:42 1996
+++ linux/net/ipv4/tcp_output.c	Mon May 13 12:15:24 1996
@@ -120,7 +120,7 @@
 	 
 	if (size < sizeof(struct tcphdr) || size > skb->len) 
 	{
-		printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
+		printk(KERN_ERR "tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
 			skb, skb->data, th, skb->len);
 		kfree_skb(skb, FREE_WRITE);
 		return;
@@ -136,7 +136,7 @@
 		/* If it's got a syn or fin it's notionally included in the size..*/
 		if(!th->syn && !th->fin) 
 		{
-			printk("tcp_send_skb: attempt to queue a bogon.\n");
+			printk(KERN_ERR "tcp_send_skb: attempt to queue a bogon.\n");
 			kfree_skb(skb,FREE_WRITE);
 			return;
 		}
@@ -167,7 +167,7 @@
 		th->check = 0;
 		if (skb->next != NULL) 
 		{
-			printk("tcp_send_partial: next != NULL\n");
+			printk(KERN_ERR "tcp_send_partial: next != NULL\n");
 			skb_unlink(skb);
 		}
 		skb_queue_tail(&sk->write_queue, skb);
@@ -648,7 +648,7 @@
 	if (buff == NULL)
 	{
 		/* This is a disaster if it occurs */
-		printk("tcp_send_fin: Impossible malloc failure");
+		printk(KERN_CRIT "tcp_send_fin: Impossible malloc failure");
 		return;
 	}
 
@@ -713,7 +713,7 @@
   		buff->free = 0;
 		if (buff->next != NULL) 
 		{
-			printk("tcp_send_fin: next != NULL\n");
+			printk(KERN_ERR "tcp_send_fin: next != NULL\n");
 			skb_unlink(buff);
 		}
 		skb_queue_tail(&sk->write_queue, buff);
diff -u --recursive --new-file pre2.0.2/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- pre2.0.2/linux/net/ipv4/tcp_timer.c	Sat Apr 13 18:22:08 1996
+++ linux/net/ipv4/tcp_timer.c	Mon May 13 12:15:24 1996
@@ -38,7 +38,7 @@
 	if((long)when < 0)
 	{
 		when=3;
-		printk("Error: Negative timer in xmit_timer\n");
+		printk(KERN_ERR "Error: Negative timer in xmit_timer\n");
 	}
 	sk->retransmit_timer.expires=jiffies+when;
 	add_timer(&sk->retransmit_timer);
@@ -257,7 +257,7 @@
 		break;
 
 	default:
-		printk ("rexmit_timer: timer expired - reason unknown\n");
+		printk (KERN_ERR "rexmit_timer: timer expired - reason unknown\n");
 		break;
 	}
 }
diff -u --recursive --new-file pre2.0.2/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- pre2.0.2/linux/net/ipx/af_ipx.c	Tue May  7 16:22:42 1996
+++ linux/net/ipx/af_ipx.c	Mon May 13 12:15:24 1996
@@ -756,7 +756,7 @@
 		} 
 		else 
 		{
-			printk("IPX: Network number collision %lx\n\t%s %s and %s %s\n",
+			printk(KERN_WARNING "IPX: Network number collision %lx\n\t%s %s and %s %s\n",
 				htonl(ipx->ipx_source.net), 
 				ipx_device_name(i),
 				ipx_frame_name(i->if_dlink_type),
@@ -2353,13 +2353,13 @@
 	dev_add_pack(&ipx_8023_packet_type);
 	
 	if ((p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv)) == NULL)
-		printk("IPX: Unable to register with 802.2\n");
+		printk(KERN_CRIT "IPX: Unable to register with 802.2\n");
 
 	if ((p8022tr_datalink = register_8022tr_client(ipx_8022_type, ipx_rcv)) == NULL)
-		printk("IPX: Unable to register with 802.2TR\n");
+		printk(KERN_CRIT "IPX: Unable to register with 802.2TR\n");
  
 	if ((pSNAP_datalink = register_snap_client(ipx_snap_id, ipx_rcv)) == NULL)
-		printk("IPX: Unable to register with SNAP\n");
+		printk(KERN_CRIT "IPX: Unable to register with SNAP\n");
 	
 	register_netdevice_notifier(&ipx_dev_notifier);
 
@@ -2367,7 +2367,7 @@
 	proc_net_register(&ipx_if_procinfo);
 	proc_net_register(&ipx_rt_procinfo);
 		
-	printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.034\n");
+	printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.035\n");
 	printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
 }
 
diff -u --recursive --new-file pre2.0.2/linux/net/netlink.c linux/net/netlink.c
--- pre2.0.2/linux/net/netlink.c	Wed Feb  7 08:55:56 1996
+++ linux/net/netlink.c	Mon May 13 12:15:25 1996
@@ -218,7 +218,7 @@
 	int ct;
 
 	if(register_chrdev(NETLINK_MAJOR,"netlink", &netlink_fops)) {
-		printk("netlink: unable to get major %d\n", NETLINK_MAJOR);
+		printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
 		return -EIO;
 	}
 	for(ct=0;ct<MAX_LINKS;ct++)
@@ -233,7 +233,7 @@
 
 int init_module(void)
 {
-	printk("Network Kernel/User communications module 0.03\n");
+	printk(KERN_INFO "Network Kernel/User communications module 0.03\n");
 	return init_netlink();
 }
 
diff -u --recursive --new-file pre2.0.2/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- pre2.0.2/linux/net/netrom/af_netrom.c	Tue May  7 16:22:43 1996
+++ linux/net/netrom/af_netrom.c	Mon May 13 12:15:24 1996
@@ -347,7 +347,7 @@
 	  		if (nr_ctl.arg < 16 || nr_ctl.arg > 65535) 
 	  			return -EINVAL;
 	  		if (nr_ctl.arg > 236) /* we probably want this */
-	  			printk("nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
+	  			printk(KERN_WARNING "nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
 	  		sk->nr->paclen = nr_ctl.arg;
 	  		break;
 
@@ -1406,7 +1406,7 @@
 {
 	sock_register(nr_proto_ops.family, &nr_proto_ops);
 	register_netdevice_notifier(&nr_dev_notifier);
-	printk("G4KLX NET/ROM for Linux. Version 0.4 ALPHA for AX25.032 Linux 1.3.77\n");
+	printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.5 for AX25.032 Linux 2.0\n");
 
 	nr_default.quality    = NR_DEFAULT_QUAL;
 	nr_default.obs_count  = NR_DEFAULT_OBS;
diff -u --recursive --new-file pre2.0.2/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- pre2.0.2/linux/net/netrom/nr_dev.c	Fri Apr 19 10:08:03 1996
+++ linux/net/netrom/nr_dev.c	Mon May 13 12:15:24 1996
@@ -181,7 +181,7 @@
 		return 0;
 
 	if (!dev->start) {
-		printk("netrom: xmit call when iface is down\n");
+		printk(KERN_ERR "netrom: xmit call when iface is down\n");
 		return 1;
 	}
 
diff -u --recursive --new-file pre2.0.2/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- pre2.0.2/linux/net/netrom/nr_in.c	Wed Sep 27 13:07:34 1995
+++ linux/net/netrom/nr_in.c	Mon May 13 12:15:24 1996
@@ -316,7 +316,7 @@
 
 	if (sk->nr->state != NR_STATE_1 && sk->nr->state != NR_STATE_2 &&
 	    sk->nr->state != NR_STATE_3) {
-		printk("nr_process_rx_frame: frame received - state: %d\n", sk->nr->state);
+		printk(KERN_ERR "nr_process_rx_frame: frame received - state: %d\n", sk->nr->state);
 		return queued;
 	}
 
diff -u --recursive --new-file pre2.0.2/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- pre2.0.2/linux/net/netrom/nr_subr.c	Wed Feb 21 08:33:27 1996
+++ linux/net/netrom/nr_subr.c	Mon May 13 12:15:24 1996
@@ -168,7 +168,7 @@
 		case NR_INFOACK:
 			break;
 		default:
-			printk("nr_write_internal: invalid frame type %d\n", frametype);
+			printk(KERN_ERR "nr_write_internal: invalid frame type %d\n", frametype);
 			return;
 	}
 	
diff -u --recursive --new-file pre2.0.2/linux/net/socket.c linux/net/socket.c
--- pre2.0.2/linux/net/socket.c	Tue May  7 16:22:43 1996
+++ linux/net/socket.c	Mon May 13 12:15:25 1996
@@ -577,7 +577,7 @@
 
 	if (!(sock = sock_alloc())) 
 	{
-		printk("NET: sys_socket: no more sockets\n");
+		printk(KERN_WARNING "socket: no more sockets\n");
 		return(-ENOSR);	/* Was: EAGAIN, but we are out of
 				   system resources! */
 	}
@@ -754,7 +754,7 @@
 
 	if (!(newsock = sock_alloc())) 
 	{
-		printk("NET: sock_accept: no more sockets\n");
+		printk(KERN_WARNING "accept: no more sockets\n");
 		return(-ENOSR);	/* Was: EAGAIN, but we are out of system
 				   resources! */
 	}
@@ -1397,7 +1397,7 @@
 {
 	int i;
 
-	printk("Swansea University Computer Society NET3.034 for Linux 1.3.77\n");
+	printk(KERN_INFO "Swansea University Computer Society NET3.035 for Linux 2.0\n");
 
 	/*
 	 *	Initialize all address (protocol) families. 
diff -u --recursive --new-file pre2.0.2/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- pre2.0.2/linux/net/unix/af_unix.c	Tue May  7 16:22:43 1996
+++ linux/net/unix/af_unix.c	Mon May 13 12:15:23 1996
@@ -188,7 +188,7 @@
 		}
 		else
 		{
-			/* passed fds are erased where?? */
+			/* passed fds are erased in the kfree_skb hook */
 			kfree_skb(skb,FREE_WRITE);
 		}
 	}
@@ -354,7 +354,8 @@
 		skpair->protinfo.af_unix.locks--;	/* It may now die */
 	sk->protinfo.af_unix.other=NULL;		/* No pair */
 	unix_destroy_socket(sk);			/* Try to flush out this socket. Throw out buffers at least */
-	
+	unix_gc();					/* Garbage collect fds */	
+
 	/*
 	 *	FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In
 	 *	Linux we behave like files and pipes do and wait for the last dereference.
@@ -1085,7 +1086,7 @@
 		)
 		{
 			kfree(cm);
-			printk("recvmsg: Bad msg_accrights\n");
+/*			printk("recvmsg: Bad msg_accrights\n");*/
 		   	return -EINVAL;
 		}
 	}
@@ -1305,7 +1306,7 @@
 
 void unix_proto_init(struct net_proto *pro)
 {
-	printk("NET3: Unix domain sockets 0.12 for Linux NET3.033.\n");
+	printk(KERN_INFO "NET3: Unix domain sockets 0.12 for Linux NET3.035.\n");
 	sock_register(unix_proto_ops.family, &unix_proto_ops);
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&(struct proc_dir_entry) {
diff -u --recursive --new-file pre2.0.2/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- pre2.0.2/linux/net/unix/garbage.c	Fri Apr 12 15:52:13 1996
+++ linux/net/unix/garbage.c	Mon May 13 15:31:18 1996
@@ -1,14 +1,10 @@
 /*
- * NET3:	Garbage Collector For AF_UNIX sockets (STUBS)
+ * NET3:	Garbage Collector For AF_UNIX sockets
  *
  * Garbage Collector:
  *	Copyright (C) Barak A. Pearlmutter.
  *	Released under the GPL version 2 or later.
  *
- * NOTE:
- *	We don't actually call this yet. I'm finishing some tests before I
- *	enable it. The bold can add it in themselves.
- *
  * Chopped about by Alan Cox 22/3/96 to make it fit the AF_UNIX socket problem.
  * If it doesn't work blame me, it worked when Barak sent it.
  *
@@ -70,22 +66,22 @@
 
 extern inline unix_socket *unix_get_socket(struct file *filp)
 {
-	struct socket *s;
+	unix_socket * u_sock = NULL;
+	struct inode *inode = filp->f_inode;
+
 	/*
 	 *	Socket ?
 	 */
-	if(filp->f_inode->i_mode!=S_IFSOCK)
-		return NULL;
-	s=&(filp->f_inode->u.socket_i);
-	/*
-	 *	AF_UNIX ?
-	 */
-	if(s->ops!=&unix_proto_ops)
-		return NULL;
-	/*
-	 *	Got one.
-	 */
-	return s->data;	
+	if (inode && inode->i_sock) {
+		struct socket * s = &inode->u.socket_i;
+
+		/*
+		 *	AF_UNIX ?
+		 */
+		if (s->ops == &unix_proto_ops)
+			u_sock = s->data;
+	}
+	return u_sock;
 }
 
 /*
@@ -263,8 +259,15 @@
 			 *	We exist only in the passing tree of sockets
 			 *	that is no longer connected to active descriptors
 			 *	Time to die..
+			 *
+			 *	Subtle item: We will correctly sweep out the
+			 *	socket that has just been closed by the user.
+			 *	We must not close this as we are in the middle
+			 *	of its close at this moment. Skip that file
+			 *	using f_count==0 to spot it.
 			 */
-			if(s->socket && s->socket->file)
+			 
+			if(s->socket && s->socket->file && s->socket->file->f_count)
 				close_fp(s->socket->file);
 		}
 		else
