diff -u --recursive --new-file v1.3.100/linux/.name linux/.name
--- v1.3.100/linux/.name	Thu Jan  1 02:00:00 1970
+++ linux/.name	Sun May 12 09:03:50 1996
@@ -0,0 +1 @@
+pre-2.0
diff -u --recursive --new-file v1.3.100/linux/CREDITS linux/CREDITS
--- v1.3.100/linux/CREDITS	Sat May 11 10:42:03 1996
+++ linux/CREDITS	Sat May 11 10:43:51 1996
@@ -2,7 +2,8 @@
 	contributed to the linux project.  It is sorted by name, and
 	formatted in a format that allows for easy grepping and
 	beautification by scripts.  The fields are: name (N), email (E),
-	web-address (W), description (D) and snail-mail address (S).
+	web-address (W), PGP key ID and fingerprint (P), description (D)
+	and snail-mail address (S). 
 	Thanks,
 
 			Linus
@@ -570,6 +571,8 @@
 
 N: Michael K. Johnson
 E: johnsonm@redhat.com
+W: http://www.redhat.com/~johnsonm
+P: 1024/4536A8DD 2A EC 88 08 40 64 CE D8  DD F8 12 2B 61 43 83 15
 D: The Linux Documentation Project
 D: Kernel Hackers' Guide
 D: Procps
diff -u --recursive --new-file v1.3.100/linux/Documentation/Changes linux/Documentation/Changes
--- v1.3.100/linux/Documentation/Changes	Mon Apr 29 18:05:15 1996
+++ linux/Documentation/Changes	Sat May 11 11:49:49 1996
@@ -1,15 +1,23 @@
 This document contains a list of the latest releases of the most
 important packages for Linux as well as instructions for newcomers to
-the 1.3.x series of kernels.
+the 1.3.x series of kernels.  By glancing through it, you should be
+able to find out what you need to upgrade to successfully run the
+latest kernels.
 
-Last updated: Apr 29, 1996.
-Author: Chris Ricker (gt1355b@prism.gatech.edu), based on the original by
-Alessandro Sigala (ssigala@globalnet.it).
+   It was originally based on material from the linux-kernel mailing
+list, Jared Mauch's web page "Software Victims of the 1.3 Kernel
+Development" (http://www2.nether.net/~jared/victim.html), and Axel
+Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources,
+and was originally written and maintained by Alessandro Sigala
+(ssigala@globalnet.it).
+
+Last updated: May 10, 1996.
+Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Releases
 ****************
 
-- Kernel modules	 Stable: 1.3.57, Exp: 1.3.69f
+- Kernel modules	 Stable: 1.3.57, Exp: 1.3.69g
 - PPP daemon		 Stable: 2.2.0f
 - Dynamic linker (ld.so) 1.7.14
 - GNU CC		 2.7.2
@@ -22,66 +30,28 @@
 - SysVinit		 2.60
 - Util-linux		 2.5
 
-What you really need to upgrade
-*******************************
-
-Dynamic linker
-==============
-
-   You might upgrade the dynamic linker to the latest release, but only
-to solve some bugs.
-
-SysVinit
-========
-
-   The FIFO behavior is changed in the latest 1.3.x kernel releases.
-Upgrade to 2.60 if the older version seems broken.
-
-PPP daemon and utilities
-========================
-
-   To use the PPP protocol with the 1.3.x linux kernel, you need to
-upgrade the PPP package to version 2.2.0f.
-
-Procps utilities
-================
-
-   In the latest 1.3.x kernel releases the /proc filesystem structure
-was changed, so you need to upgrade the Procps package to version
-0.99a.  In the very latest kernels, /proc has changed again.  There's
-not yet an officially updated version of procps, so make due with
-0.99a; you might want to look for one of the patches floating around to
-update 0.99a for use with 1.3.94 and later kernels.
-
-Installation notes
-******************
-
-Kernel Modules
-==============
-
-   The current kernel modules release is 1.3.57, but you need the
-experimental release 1.3.69 to use newer binutils 2.6.0.x, because
-modules compiled with new binutils can't be loaded by modules 1.3.57.
+Upgrade notes
+*************
 
 The Linux C Library
 ===================
 
    The latest stable Linux C Library release is 5.2.18.  If you upgrade
-to this from 5.0.9 or earlier, be sure to read the `release.libc-5.2.18'
-file, since GNU make and a few other fairly important utils can be
-broken by the upgrade.
+to this from 5.0.9 or earlier, be sure to read the
+`release.libc-5.2.18' file, since GNU make and a few other fairly
+important utils can be broken by the upgrade.
 
    The current (beta) Linux C Library release is 5.3.12. In this
 release there are some important changes that may cause troubles to
 buggy programs (programs that call free() on a pointer not returned by
-malloc() work with previous libc, but not with this release) then read
-the `release.libc-5.3.9' file carefully!  In the latest libc releases a
+malloc() work with previous libc, but not with this release) so read the
+`release.libc-5.3.9' file carefully!  In the latest libc releases a
 dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU
-was defined, has been fixed.  Unfortunately, some GNU packages depend on
-this bug.  GNU make 3.xx is one of them.  To fix that you need to patch
-and recompile those programs (a patch for make is included in the file
-`release.libc-.5.3.9', and the address to obtain a precompiled binary
-is at the end of this file).
+was defined, has been fixed.  Unfortunately, some GNU packages depend
+on this bug.  GNU make 3.xx is one of them.  To fix that you need to
+patch and recompile those programs (a patch for make is included in the
+file `release.libc-.5.3.9', and the address to obtain a precompiled
+binary is at the end of this file).
 
    Also, the libc-5.3.x line has a known security hole relating to
 rlogin.  Libc-5.3.12 fixes this, so if you're going to run an
@@ -102,7 +72,9 @@
 "fcntl_setlk() called by process %d with broken flock()
   emulation\n",                        current->pid);'
 
-   in linux/fs/locks.c and recompile.
+   in linux/fs/locks.c and recompile.  If you're still running a.out,
+there's an unofficial libc-4.7.6 release out to which you can upgrade
+to fix this problem.
 
 The Termcap Library
 ===================
@@ -111,38 +83,23 @@
 read the `README' file contained into the package to get some important
 information about the `tgetent' function changes!
 
-Upgrading to 1.3.x kernel from 1.2.13
-*************************************
-
-   This section was based on material from the linux-kernel mailing
-list, Jared Mauch's web page "Software Victims of the 1.3 Kernel
-Development" (http://www2.nether.net/~jared/victim.html), and Axel
-Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources.
-
-   This section is intended primarily to help those that are new to the
-1.3.x series of Linux kernels.  In the ongoing effort to make a faster,
-better kernel and eventually achieve total world domination, several
-features of the Linux kernel have been improved.  As a result, when you
-first upgrade to 1.3.x from 1.2.13, you will also have to upgrade
-several utilities that are closely associated with the kernel and make
-use of these features.
-
-Proc filesystem
-===============
+Procps utilities
+================
 
-   Various changes in the /proc filesystem have been made, affecting
-ps, top, etc.  Running `top' or `ps -auwwx' will now give you a floating
-point exception. To fix the problem, upgrade to procps-0.99a.tar.gz,
-available at
-ftp://tsx-11.mit.edu/pub/linux/BETA/procps/procps-0.99a.tar.gz.
+   In the latest 1.3.x kernel releases the /proc file system structure
+was changed, so you need to upgrade the procps package to version
+0.99a.  In the very latest kernels, /proc has changed again.  There's
+not yet an officially updated version of procps, so make due with
+0.99a; you might want to look for one of the patches floating around to
+update 0.99a for use with 1.3.94 and later kernels.
 
-Modules
-=======
+Kernel Modules
+==============
 
    1.3.x is almost completely modularized, and kerneld is now
 incorporated into the kernel.  To take advantage of this, you'll need
 the latest version of the module support apps.  The latest non-beta is
-modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69f.tar.gz.
+modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69g.tar.gz.
 These should be available at the same place you picked up your kernel
 (ftp://ftp.cc.gatech.edu/pub/linux/kernel/) and the home page is
 http://www.pi.se/blox/modules/index.html.  Note:  If you try to load a
@@ -151,12 +108,12 @@
    `gcc2_compiled, undefined Failed to load module!  The symbols from
 kernel 1.3.foo don't match 1.3.foo'
 
-   where `foo' is a number between 1 and 89, then it's time to upgrade
-module utilities from 1.3.57 to 1.3.69f; you'll only get this error if
-you're running the latest binutils, so most people don't need to
-upgrade.
+   where `foo' is a number between 1 and 100, then it's time to upgrade
+module utilities from 1.3.57 to 1.3.69g; you'll only get this error if
+you're running the latest binutils, so most people don't need to upgrade
+past 1.3.57.
 
-   Another little tip:  you can't have both a.out *and* ELF support
+   Another little tip: you can't have both a.out *and* ELF support
 compiled as modules.  Otherwise, you get a nice Catch-22 when you try
 to run insmod to install a.out/ELF support so you can run insmod ;-).
 If you have an all-ELF system, but need a.out for the occasional
@@ -218,9 +175,9 @@
 Console
 =======
 
-   The Linux console type has changed.  If your setup is old enough that
-you have problems, you'll need to update your termcap.  To fix, add
-linux to one of the types in /etc/termcap or snoop around
+   The Linux console type has changed.  If your setup is old enough
+that you have problems, you'll need to update your termcap.  To fix,
+add linux to one of the types in /etc/termcap or snoop around
 http://www.ccil.org/~esr/ncurses.html (reputedly the latest universal
 termcap maintainer).  You may also need to update terminfo by running
 the following as root:
@@ -344,8 +301,8 @@
 ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz.
 
 Please send info about any other packages that 1.3.x "broke" or about
-any new features of 1.3.x that require extra packages for use to Chris
-Ricker (gt1355b@prism.gatech.edu).
+any new features of 1.3.x that require extra or new packages for use to
+Chris Ricker (gt1355b@prism.gatech.edu).
 
 How to know the version of the installed programs
 *************************************************
@@ -358,7 +315,7 @@
 Libc: ls -l /lib/libc.so.5
 LibC++: ls -l /usr/lib/libg++.so
 Binutils: ld -v
-dld: ldd -v and ldd -V
+ldd: ldd -v and ldd -V
 termcap: ls -l /lib/libtermcap.so.*
 modules: insmod -V
 procps: ps --version
diff -u --recursive --new-file v1.3.100/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.100/linux/Documentation/Configure.help	Sat May 11 10:42:04 1996
+++ linux/Documentation/Configure.help	Sat May 11 17:15:38 1996
@@ -623,6 +623,7 @@
   don't know what to answer at this point then answer Y. You may answer
   M for module support and later load the module when you install the
   JDK or find a interesting Java program that you can't live without.
+
 Processor type
 CONFIG_M386
   This is the processor type of your CPU. It is used for optimizing
diff -u --recursive --new-file v1.3.100/linux/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
--- v1.3.100/linux/Documentation/cdrom/cdrom-standard.tex	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/cdrom/cdrom-standard.tex	Sun May 12 08:13:07 1996
@@ -0,0 +1,837 @@
+\documentclass{article}
+\def\version{$Id: cdrom-standard.tex,v 0.4 1996/04/17 20:46:34 david Exp $}
+
+\evensidemargin=0pt
+\oddsidemargin=0pt
+\topmargin=-\headheight \advance\topmargin by -\headsep
+\textwidth=15.99cm \textheight=24.62cm % normal A4, 1'' margin
+
+\def\linux{{\sc Linux}}
+\def\cdrom{{\sc CDrom}}
+\def\cdromc{{\tt cdrom.c}}
+\def\ucdrom{{\tt ucdrom.h}}
+
+\everymath{\it} \everydisplay{\it}
+\catcode `\_=\active \def_{\_\penalty100 }
+\catcode`\<=\active \def<#1>{{\langle\hbox{\rm#1}\rangle}}
+
+\begin{document}
+\title{A \linux\ \cdrom\ standard}
+\author{David van Leeuwen\\{\normalsize\tt david@tm.tno.nl}}
+
+\maketitle
+
+\section{Introduction}
+
+\linux\ is probably the Unix-like operating system that supports the widest
+variety of hardware devices. The reasons for this are presumably
+\begin{itemize}
+\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.
+\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. 
+
+Apart from the somewhat unstructured interfacing with software, the
+actual execution of the commands is different for most of the
+different drivers: e.g., some drivers close the tray if an $open()$ call
+occurs while the tray is unloaded, others not. Some drivers lock the
+door upon opening the device, to prevent an incoherent file system,
+but others don't, to allow software ejection. Undoubtedly, the
+capabilities of the different drives vary, but even when two drives have
+the same capability the driver behavior may be different. 
+
+Personally, I think that the most important drive interfaces will be
+the IDE/ATAPI drives and of course the SCSI drives, but as prices of
+hardware drop continuously, it is not unlikely that people will have
+more than one \cdrom\ drive, possibly of mixed types.  (In December
+1994, one of the cheapest \cdrom\ drives was a Philips cm206, a
+double-speed proprietary drive. In the months that I was busy writing
+a \linux\ driver for it, proprietary drives became old-fashioned and
+IDE/ATAPI drives became standard. At the time of writing (April 1996)
+the cheapest double speed drive is IDE and at one fifth of the price
+of its predecessor. Eight speed drives are available now.)
+
+This document defines (in pre-release versions: proposes) the various
+$ioctl$s, and the way the drivers should implement this.
+
+\section{Standardizing through another software level}
+\label{cdrom.c}
+
+At the time this document is written, all drivers directly implement
+the $ioctl()$ calls through their own routines, with the danger of
+forgetting calls to $verify_area()$ and the risk of divergence in
+implementation. 
+
+For this reason, we\footnote{The writing style is such that `we' is
+used when (at least part of) the \cdrom-device driver authors support
+the idea, an `I' is used for personal opinions} propose to define
+another software-level, that separates the $ioctl()$ and $open()$
+implementation from the actual hardware implementation. We believe
+that \cdrom\ drives are specific enough (i.e., different from other
+block-devices such as floppy or hard disc drives), to define a set of
+{\em \cdrom\ device operations}, $<cdrom-device>_dops$. These are of a
+different nature than the classical block-device file operations
+$<block-device>_fops$.
+
+The extra interfacing level routines are implemented in a file
+\cdromc, and a low-level \cdrom\ driver hands over the interfacing to
+the kernel by registering the following general $struct\ file_operations$:
+$$
+\halign{$#$\ \hfil&$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+struct& file_operations\ cdrom_fops = \{\hidewidth\cr
+        &NULL,                  & lseek \cr
+        &block_read,            & read - general\ block-dev\ read \cr
+        &block_write,           & write - general block-dev write \cr
+        &NULL,                  & readdir \cr
+        &NULL,                  & select \cr
+        &cdrom_ioctl,           & ioctl \cr
+        &NULL,                  & mmap \cr
+        &cdrom_open,            & open \cr
+        &cdrom_release,         & release \cr
+        &NULL,                  & fsync \cr
+        &NULL,                  & fasync \cr
+        &cdrom_media_changed,   & media_change \cr
+        &NULL                   & revalidate \cr
+\};\cr
+}
+$$
+Every active \cdrom\ device shares this $struct$. The routines declared
+above are all implemented in \cdromc, and this is the place where the
+{\em behavior\/} of all \cdrom-devices is defined, and hence
+standardized. The implementation of the interfacing to the various
+types of hardware still is done by the various \cdrom-device drivers,
+but these routines only implement certain {\em capabilities\/} that
+are typical to \cdrom\ (removable-media) devices.
+
+Registration of the \cdrom\ device driver should now be to the general
+routines in \cdromc, not to the VFS any more. This is done though the
+call
+$$register_cdrom(int\ major, char * name, 
+  struct\ cdrom_device_ops\ device_options)
+$$
+
+The device operations structure lists the implemented routines for
+interfacing to the hardware, and some specifications of capabilities
+of the device, such as the maximum head-transfer rate.  [It is
+impossible to come up with a complete list of all capabilities of
+(future) \cdrom\ drives, as the developments in technology follow-up
+at an incredible rate. Maybe write-operation (WORM devices) will
+become very popular in the future.]  The list now is:
+$$
+\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
+\noalign{\medskip}
+  &\llap{const\ }int& capability;&  capability flags \cr
+  &int& mask;& mask of capability: disables them \cr
+  &\llap{$const\ $}float& speed;&  maximum speed for reading data \cr
+  &\llap{$const\ $}int& minors;& number of supported minor devices \cr
+  &\llap{$const\ $}int& capacity;& number of discs in jukebox \cr
+\noalign{\medskip}
+  &int& options;& options flags \cr
+  &long& mc_flags;& media-change buffer flags ($2\times16$) \cr
+\}\cr
+}
+$$ The \cdrom-driver should simply implement (some of) these
+functions, and register the functions to the global \cdrom\ driver,
+which performs interfacing with the Virtual File System and system
+$ioctl$s. The flags $capability$ specify the hardware-capabilities on
+registration of the device, the flags $mask$ can be used to mask some
+of those capabilities (for one reason or another). The value $minors$
+should be a positive value indicating the number of minor devices that
+are supported by the driver, normally~1.  (They are supposed to be
+numbered from 0 upwards). The value $capacity$ should be the number of
+discs the drive can hold simultaneously, if it is designed as a
+juke-box, or otherwise~1.
+
+Two registers contain variables local to the \cdrom\ device. The flags
+$options$ are used to specify how the general \cdrom\ routines
+should behave. These various flags registers should provide enough
+flexibility to adapt to the different user's wishes (and {\em not\/}
+the `arbitrary' wishes of the author of the low-level device driver,
+as is the case in the old scheme). The register $mc_flags$ is used to
+buffer the information from $media_changed()$ to two separate queues. 
+
+Note that most functions have fewer parameters than their
+$blkdev_fops$ counterparts. This is because very little of the
+information in the structures $inode$ and $file$ are used, the main
+parameter is the device $dev$, from which the minor-number can be
+extracted. (Most low-level \cdrom\ drivers don't even look at that value
+as only one device is supported.)
+
+The intermediate software layer that \cdromc\ forms will performs some
+additional bookkeeping. The minor number of the device is checked
+against the maximum registered in $<device>_dops$. The function
+$cdrom_ioctl()$ will verify the appropriate user-memory regions for
+read and write, and in case a location on the CD is transferred, it
+will `sanitize' the format by making requests to the low-level drivers
+in a standard format, and translating all formats between the
+user-software and low level drivers. This relieves much of the drivers
+memory checking and format checking and translation. Also, the
+necessary structures will be declared on the program stack.
+
+The implementation of the functions should be as defined in the
+following sections. Three functions {\em must\/} be implemented,
+namely $open()$, $release()$ and $open_files()$. Other functions may
+be omitted, their corresponding capability flags will be cleared upon
+registration. Generally, a function returns zero on success and
+negative on error. A function call should return only after the
+command has completed, but of course waiting for the device should not
+use processor time.
+
+\subsection{$Open(dev_t\ dev, int\ purpose)$}
+
+$Open()$ should try to open the device for a specific $purpose$, which
+can be either:
+\begin{itemize}
+\item[0] Open for data read, as is used by {\tt mount()} (2), or the
+user commands {\tt dd} or {\tt cat}.  
+\item[1] Open for $ioctl$ commanding, as is used for audio-CD playing
+programs mostly. 
+\end{itemize}
+In this routine, a static counter should be updated, reflecting the
+number of times the specific device is successfully opened (and in
+case the driver supports modules, the call $MOD_INC_USE_COUNT$
+should be performed exactly once, if successful). The return value is
+negative on error, and zero on success. The open-for-ioctl call can
+only fail if there is no hardware.
+
+Notice that any strategic code (closing tray upon $open()$, etc.)\ is
+done by the calling routine in \cdromc, so the low-level routine
+should only be concerned with proper initialization and device-use
+count.
+
+\subsection{$Release(dev_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
+device-specific actions should be taken such as spinning down the
+device. However, strategic actions such as ejection of the tray, or
+unlocking the door, should be left over to the general routine
+$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)$}
+
+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)$}
+\label{drive status}
+
+The function $drive_status$, if implemented, should provide
+information of the status of the drive (not the status of the disc,
+which may or may not be in the drive). In \ucdrom\ the possibilities
+are listed: 
+$$
+\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+CDS_NO_INFO& no information available\cr
+CDS_NO_DISC& no disc is inserted, tray is closed\cr
+CDS_TRAY_OPEN& tray is opened\cr
+CDS_DRIVE_NOT_READY& something is wrong, tray is moving?\cr
+CDS_DISC_OK& a disc is loaded and everything is fine\cr
+}
+$$
+
+\subsection{$Disc_status(dev_t\ dev)$}
+\label{disc status}
+
+As a complement to $drive_status()$, this functions can provide the
+general \cdrom-routines with information about the current disc that is
+inserted in the drive represented by $dev$. The history of development
+of the CD's use as a carrier medium for various digital information
+has lead to many different disc types, hence this function can return:
+$$
+\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+CDS_NO_INFO& no information available\cr
+CDS_NO_DISC& no disc is inserted, or tray is opened\cr
+CDS_AUDIO& Audio disc (2352 audio bytes/frame)\cr
+CDS_DATA_1& data disc, mode 1 (2048 user bytes/frame)\cr
+CDS_DATA_2& data disc, mode 2 (2336 user bytes/frame)\cr
+CDS_XA_2_1& mixed data (XA), mode 2, form 1 (2048 user bytes)\cr
+CDS_XA_2_2& mixed data (XA), mode 2, form 1 (2324  user bytes)\cr
+}
+$$
+As far as I know, \cdrom's are always of type $CDS_DATA_1$. For
+some information concerning frame layout of the various disc types, see
+a recent version of {\tt cdrom.h}. 
+
+\subsection{$Media_changed(dev\_t\ dev)$}
+
+This function is very similar to the original function in $struct\
+file_operations$. It returns 1 if the medium of the device $dev$ has
+changed since the last call, and 0 otherwise. Note that by `re-routing'
+this function through $cdrom_media_changed()$, we can implement
+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)$}
+
+This function, if implemented, should control the tray movement. (No
+other function should control this.) The parameter $position$ controls
+the desired direction of movement:
+\begin{itemize}
+\item[0] Close tray
+\item[1] Open tray
+\end{itemize}
+This function returns 0 upon success, and a non-zero value upon
+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)$}
+
+This function (and no other code) controls locking of the door, if the
+drive allows this. The value of $lock$ controls the desired locking
+state:
+\begin{itemize}
+\item[0] Unlock door, manual opening is allowed
+\item[1] Lock door, tray cannot be ejected manually
+\end{itemize}
+Return values are as for $tray_move()$.
+
+\subsection{$Select_speed(dev_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
+capability that should be standardized through a function in the
+device-operations structure. This function should select the speed at
+which data is read or audio is played back. The special value `0'
+means `auto-selection', i.e., maximum data-rate or real-time audio
+rate. If the drive doesn't have this `auto-selection' capability, the
+decision should be made on the current disc loaded and the return
+value should be positive. A negative return value indicates an
+error. (Although the audio-low-pass filters probably aren't designed
+for it, more than real-time playback of audio might be used for
+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)$}
+
+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
+disc selection. It should return the number of the selected disc on
+success, a negative value on error. Currently, none of the \linux\ 
+\cdrom\ drivers appear to support such functionality, but it defined
+here for future purpose.
+
+\subsection{$Get_last_session(dev_t\ dev, struct\ cdrom_multisession *
+ms_info)$}
+
+This function should implement the old corresponding $ioctl()$. For
+device $dev$, the start of the last session of the current disc should
+be returned in the pointer argument $ms_info$. Note that routines in \cdromc\ have sanitized this argument: its
+requested format will {\em always\/} be of the type $CDROM_LBA$
+(linear block addressing mode), whatever the calling software
+requested. But sanitization goes even further: the low-level
+implementation may return the requested information in $CDROM_MSF$
+format if it wishes so (setting the $ms_info\rightarrow addr_format$
+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)$}
+
+Some discs carry a `Media Catalog Number' (MCN), also called
+`Universal Product Code' (UPC). This number should reflect the number that
+is generally found in the bar-code on the product. Unfortunately, the
+few discs that carry such a number on the disc don't even use the same
+format. The return argument to this function is a pointer to a
+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)$}
+
+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 *
+arg)$}
+
+Some of the \cdrom-$ioctl$s defined in {\tt cdrom.h} can be
+implemented by the routines described above, and hence the function
+$cdrom_ioctl$ will use those. However, most $ioctl$s deal with
+audio-control. We have decided to leave these accessed through a
+single function, repeating the arguments $cmd$ and $arg$. Note that
+the latter is of type $void*{}$, rather than $unsigned\ long\
+int$. The routine $cdrom_ioctl()$ does do some useful things,
+though. It sanitizes the address format type to $CDROM_MSF$ (Minutes,
+Seconds, Frames) for all audio calls. It also verifies the memory
+location of $arg$, and reserves stack-memory for the argument. This
+makes implementation of the $audio_ioctl()$ much simpler than in the
+old driver scheme. For an example you may look up the function
+$cm206_audio_ioctl()$ in {\tt cm206.c} that should be updated with
+this documentation. 
+
+An unimplemented ioctl should return $-EINVAL$, but a harmless request
+(e.g., $CDROMSTART$) may be ignored by returning 0 (success). Other
+errors should be according to the standards, whatever they are. (We
+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\
+arg)$}
+
+Some $ioctl$s seem to be specific to certain \cdrom\ drives. That is,
+they are introduced to service some capabilities of certain drives. In
+fact, there are 6 different $ioctl$s for reading data, either in some
+particular kind of format, or audio data. Not many drives support
+reading audio tracks as data, I believe this is because of protection
+of copyrights of artists. Moreover, I think that if audio-tracks are
+supported, it should be done through the VFS and not via $ioctl$s. A
+problem here could be the fact that audio-frames are 2352 bytes long,
+so either the audio-file-system should ask for 75264 bytes at once
+(the least common multiple of 512 and 2352), or the drivers should
+bend their backs to cope with this incoherence (to which I would
+oppose, this code then should be standardized in \cdromc).
+
+Because there are so many $ioctl$s that seem to be introduced to
+satisfy certain drivers,\footnote{Is there software around that actually uses
+these? I 'd be interested!} any `non-standard' $ioctl$s are routed through
+the call $dev_ioctl()$. In principle, `private' $ioctl$s should be
+numbered after the device's major number, and not the general \cdrom\
+$ioctl$ number, {\tt 0x53}. Currently the non-supported $ioctl$s are:
+{\it CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, CDROMREADRAW,
+CDROMREADCOOKED, CDROMSEEK, CDROMPLAY\-BLK and CDROMREADALL}. 
+
+\subsection{\cdrom\ capabilities}
+
+Instead of just implementing some $ioctl$ calls, the interface in
+\cdromc\ supplies the possibility to indicate the {\em capabilities\/}
+of a \cdrom\ drive. This can be done by ORing any number of
+capability-constants that are defined in \ucdrom\ at the registration
+phase. Currently, the capabilities are any of:
+$$
+\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+CDC_CLOSE_TRAY& can close tray by software control\cr
+CDC_OPEN_TRAY& can open tray\cr
+CDC_LOCK& can lock and unlock the door\cr
+CDC_SELECT_SPEED& can select speed, in units of $\sim$150\,kB/s\cr
+CDC_SELECT_DISC& drive is juke-box\cr
+CDC_MULTI_SESSION& can read sessions $>\rm1$\cr
+CDC_MCN& can read Medium Catalog Number\cr
+CDC_MEDIA_CHANGED& can report if disc has changed\cr
+CDC_PLAY_AUDIO& can perform audio-functions (play, pause, etc)\cr
+}
+$$
+The capability flag is declared $const$, to prevent drivers to
+accidentally tamper with the contents. However, upon registration,
+some (claimed) capability flags may be cleared if the supporting
+function has not been implemented (see $register_cdrom()$ in
+\cdromc). 
+
+If you want to disable any of the capabilities, there is a special
+flag register $<device>_dops.mask$ that may (temporarily) disable
+certain capabilities. In the file \cdromc\ you will encounter many
+constructions of the type 
+$$\it
+if\ (cdo\rightarrow capability \mathrel\& \mathord{\sim} cdo\rightarrow mask 
+   \mathrel{\&} CDC_<capability>) \ldots
+$$
+The $mask$ could be set in the low-level driver code do disable
+certain capabilities for special brands of the device that can't
+perform the actions.  However, there is not (yet) and $ioctl$ to set
+the mask\dots The reason is that I think it is better to control the
+{\em behavior\/} rather than the {\em capabilities}.
+
+\subsection{Options}
+
+A final flag register controls the {\em behavior\/} of the \cdrom\
+drives, in order to satisfy the different users's wishes, hopefully
+independently of the ideas of the respectable author that happened to
+have made the drive's support available to the \linux\ community. The
+current behavior options are:
+$$
+\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+CDO_AUTO_CLOSE& try to close tray upon device $open()$\cr
+CDO_AUTO_EJECT& try to open tray on last device $close()$\cr
+CDO_USE_FFLAGS& use $file_pointer\rightarrow f_flags$ to indicate
+ purpose for $open()$\cr
+CDO_LOCK& try to lock door if device is opened\cr
+CDO_CHECK_TYPE& ensure disc type is data if opened for data\cr
+}
+$$
+
+The initial value of this register is $CDO_AUTO_CLOSE \mathrel|
+CDO_USE_FFLAGS \mathrel| CDO_LOCK$, reflecting my own view on user
+interface and software standards. Before you protest, there are two
+new $ioctl$s implemented in \cdromc, that allow you to control the
+behavior by software. These are:
+$$
+\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+CDROM_SET_OPTIONS& set options specified in $(int)\ arg$\cr
+CDROM_CLEAR_OPTIONS& clear options specified in $(int)\ arg$\cr
+}
+$$
+One option needs some more explanation: $CDO_USE_FFLAGS$. In the next
+section we explain what the need for this option is.
+
+\section{The need to know the purpose of opening}
+
+Traditionally, Unix devices can be used in two different `modes',
+either by reading/writing to the device file, or by issuing
+controlling commands to the device, by the device's $ioctl()$
+call. The problem with \cdrom\ drives, is that they can be used for
+two entirely different purposes. One is to mount removable
+file systems, \cdrom s, the other is to play audio CD's. Audio commands
+are implemented entirely through $ioctl$s, presumably because the
+first implementation (SUN?) has been such. In principle there is
+nothing wrong with this, but a good control of the `CD player' demands
+that the device can {\em always\/} be opened in order to give the
+$ioctl$ commands, regardless of the state the drive is in. 
+
+On the other hand, when used as a removable-media disc drive (what the
+original purpose of \cdrom s is) we would like to make sure that the
+disc drive is ready for operation upon opening the device. In the old
+scheme, some \cdrom\ drivers don't do any integrity checking, resulting
+in a number of i/o errors reported by the VFS to the kernel when an
+attempt for mounting a \cdrom\ on an empty drive occurs. This is not a
+particularly elegant way to find out that there is no \cdrom\ inserted;
+it more-or-less looks like the old IBM-PC trying to read an empty floppy
+drive for a couple of seconds, after which the system complains it
+can't read from it. Nowadays we can {\em sense\/} the existence of a
+removable medium in a drive, and we believe we should exploit that
+fact. An integrity check on opening of the device, that verifies the
+availability of a \cdrom\ and its correct type (data), would be
+desirable.
+
+These two ways of using a \cdrom\ drive, principally for data and
+secondarily for playing audio discs, have different demands for the
+behavior of the $open()$ call. Audio use simply wants to open the
+device in order to get a file handle which is needed for issuing
+$ioctl$ commands, while data use wants to open for correct and
+reliable data transfer. The only way user programs can indicate what
+their {\em purpose\/} of opening the device is, is trough the $flags$
+parameter (see {\tt open(2)}). For \cdrom\ devices, these flags aren't
+implemented (some drivers implement checking for write-related flags,
+but this is not strictly necessary if the device file has correct
+permission flags). Most option flags simply don't make sense to
+\cdrom\ devices: $O_CREAT$, $O_NOCTTY$, $O_TRUNC$, $O_APPEND$, and
+$O_SYNC$ have no meaning to a \cdrom. 
+
+We therefore propose to use the flag $O_NONBLOCK$ as an indication
+that the device is opened just for issuing $ioctl$
+commands. Strictly, the meaning of $O_NONBLOCK$ is that opening and
+subsequent calls to the device don't cause the calling process to
+wait. We could interpret this as ``don't wait until someone has been
+inserted some valid data-\cdrom.'' Thus, our proposal of the
+implementation for the $open()$ call for \cdrom s is:
+\begin{itemize}
+\item If no other flags are set than $O_RDONLY$, the device is opened
+for data transfer, and the return value will be 0 only upon successful
+initialization of the transfer. The call may even induce some actions
+on the \cdrom, such as closing the tray.  
+\item If the option flag $O_NONBLOCK$ is set, opening will always be
+successful, unless the whole device doesn't exist. The drive will take
+no actions whatsoever. 
+\end{itemize}
+
+\subsection{And what about standards?}
+
+You might hesitate to accept this proposal as is comes from the
+\linux\ community, and not from some standardizing institute. What
+about SUN, SGI, HP and all those other Unix and hardware vendors?
+Well, these companies are in the lucky position that they generally
+control both the hardware and software of their supported products,
+and are large enough to set their own standard. They do not have to
+deal with a dozen or more different, competing hardware
+configurations.\footnote{Personally, I think that SUN's approach to
+mounting \cdrom s is very good in origin: under Solaris a
+volume-daemon automatically mounts a newly inserted \cdrom\ under {\tt
+/cdrom/$<volume-name>$/}. In my opinion they should have pushed this
+further and have {\em every\/} \cdrom\ on the local area network be
+mounted at the similar location, i.e., no matter in which particular
+machine you insert a \cdrom, it will always appear at the same
+position in the directory tree, on every system. When I wanted to
+implement such a user-program for \linux, I came across the
+differences in behavior of the various drivers, and the need for an
+$ioctl$ informing about media changes.}
+
+We believe that using $O_NONBLOCK$ as indication for opening a device
+for $ioctl$ commanding only, can be easily introduced in the \linux\
+community. All the CD-player authors will have to be informed, we can
+even send in our own patches to the programs. The use of $O_NONBLOCK$
+has most likely no influence on the behavior of the CD-players on
+other operating systems than \linux. Finally, a user can always revert
+to old behavior by a call to $ioctl(file_descriptor, CDROM_CLEAR_OPTIONS,
+CDO_USE_FFLAGS)$. 
+
+\subsection{The preferred strategy of $open()$}
+
+The routines in \cdromc\ are designed in such way, that a run-time
+configuration of the behavior of \cdrom\ devices (of {\em any\/} type)
+can be carried out, by the $CDROM_SET/CLEAR_OPTIONS$ $ioctls$. Thus, various
+modes of operation can be set:
+\begin{description}
+\item[$CDO_AUTO_CLOSE \mathrel| CDO_USE_FFLAGS \mathrel| CDO_LOCK$]
+This is the default setting. (With $CDO_CHECK_TYPE$ it will be better,
+in the future.) If the device is not yet opened by any other process,
+and it is opened for data ($O_NONBLOCK$ is not set) and the tray is
+found open, an attempt to close the tray is made. Then, it is verified
+that a disc is in the drive and, if $CDO_CHECK_TYPE$ is set, that its
+type is `data mode 1.' Only if all tests are passed, the return value
+is zero. The door is locked to prevent file system corruption. If
+opened for audio ($O_NONBLOCK$ is set), no actions are taken and a
+value of 0 will be returned.
+\item[0] $Open()$ will always be successful, the option flags are
+ignored. Neither actions are undertaken, nor any integrity checks are
+made. 
+\item[$CDO_AUTO_CLOSE \mathrel| CDO_AUTO_EJECT \mathrel| CDO_LOCK$]
+This mimics the behavior of the current sbpcd-driver. The option flags
+are ignored, the tray is closed on the first open, if
+necessary. Similarly, the tray is opened on the last release, i.e., if
+a \cdrom\ is unmounted, it is automatically ejected, such that the
+user can replace it. 
+\end{description}
+We hope that these option can convince everybody (both driver
+maintainers and user program developers) to adapt to the new cdrom
+driver scheme and option flag interpretation. 
+
+\section{Description of routines in \cdromc}
+
+Only a few routines in \cdromc\ are exported to the drivers. In this
+section we will treat these, as well as the functioning of the routines
+that `take over' the interface to the kernel. The header file
+belonging to \cdromc\ is called \ucdrom, but may be included in {\tt
+cdrom.h} in the future.
+
+\subsection{$struct\ file_operations\ cdrom_fops$}
+
+The contents of this structure has been described in
+section~\ref{cdrom.c}, and this structure should be used in
+registering the block device to the kernel:
+$$
+register_blkdev(major, <name>, \&cdrom_fops);
+$$
+
+\subsection{$Int\ register_cdrom(int\ major, char * name, struct\
+cdrom_device_ops\ * cdo)$}
+
+Similar to registering $cdrom_fops$ to the kernel, the device
+operations structure, as described in section~\ref{cdrom.c}, should be
+registered to the general \cdrom\ interface:
+$$
+register_cdrom(major, <name>, \&<device>_dops);
+$$
+This function returns zero upon success, and non-zero upon failure. 
+
+\subsection{$Int\ unregister_cdrom(int\ major, char * name)$}
+
+Unregistering device $name$ with major number $major$ disconnects the
+registered device-operation routines from the \cdrom\ interface.
+This function returns zero upon success, and non-zero upon failure. 
+
+\subsection{$Int\ cdrom_open(struct\ inode * ip, struct\ file * fp)$}
+
+This function is not called directly by the low-level drivers, it is
+listed in the standard $cdrom_fops$. If the VFS opens a file, this
+function becomes active. A strategy logic is implemented in this
+routine, taking care of all capabilities and options that are set in
+the $cdrom_device_ops$ connected to the device. Then, the program flow is
+transferred to the device_dependent $open()$ call. 
+
+\subsection{$Void\ cdrom_release(struct\ inode *ip, struct\ file
+*fp)$}
+
+This function implements the reverse-logic of $cdrom_open()$, and then
+calls the device-dependent $release()$ routine.  When the use-count
+has reached 0, the allocated buffers in the are flushed by calls to
+$sync_dev(dev)$ and $invalidate_buffers(dev)$.
+
+
+\subsection{$Int\ cdrom_ioctl(struct\ inode *ip, struct\ file *fp,
+                       unsigned\ int\ cmd, unsigned\ long\ arg)$}
+\label{cdrom-ioctl}
+
+This function handles all $ioctl$ requests for \cdrom\ devices in a
+uniform way. The different calls fall into three categories: $ioctl$s
+that can be directly implemented by device operations, ones that are
+routed through the call $audio_ioctl()$, and the remaining ones, that
+are presumable device-dependent. Generally, a negative return value
+indicates an error. 
+
+\subsubsection{Directly implemented $ioctl$s}
+\label{ioctl-direct}
+
+The following `old' \cdrom-$ioctl$s are implemented by directly
+calling device-operations in $cdrom_device_ops$, if implemented and
+not masked:
+\begin{description}
+\item[CDROMMULTISESSION] Requests the last session on a \cdrom.
+\item[CDROMEJECT] Open tray. 
+\item[CDROMCLOSETRAY] Close tray.
+\item[CDROMEJECT_SW] If $arg\not=0$, set behavior to auto-close (close
+tray on first open) and auto-eject (eject on last release), otherwise
+set behavior to non-moving on $open()$ and $release()$ calls.
+\item[CDROM_GET_MCN or CDROM_GET_UPC] Get the Medium Catalog Number from a CD.
+\end{description}
+
+\subsubsection{$Ioctl$s rooted through $audio_ioctl()$}
+\label{ioctl-audio}
+
+The following set of $ioctl$s are all implemented through a call to
+the $cdrom_fops$ function $audio_ioctl()$. Memory checks and
+allocation are performed in $cdrom_ioctl()$, and also sanitization of
+address format ($CDROM_LBA$/$CDROM_MSF$) is done.
+\begin{description}
+\item[CDROMSUBCHNL] Get sub-channel data in argument $arg$ of type $struct\
+cdrom_subchnl *{}$.
+\item[CDROMREADTOCHDR] Read Table of Contents header, in $arg$ of type
+$struct\ cdrom_tochdr *{}$. 
+\item[CDROMREADTOCENTRY] Read a Table of Contents entry in $arg$ and
+specified by $arg$ of type $struct\ cdrom_tocentry *{}$.
+\item[CDROMPLAYMSF] Play audio fragment specified in Minute, Second,
+Frame format, delimited by $arg$ of type $struct\ cdrom_msf *{}$.
+\item[CDROMPLAYTRKIND] Play audio fragment in track-index format
+delimited by $arg$ of type $struct cdrom_ti *{}$.
+\item[CDROMVOLCTRL] Set volume specified by $arg$ of type $struct\
+cdrom_volctrl *{}$.
+\item[CDROMVOLREAD] Read volume into by $arg$ of type $struct\
+cdrom_volctrl *{}$.
+\item[CDROMSTART] Spin up disc.
+\item[CDROMSTOP] Stop playback of audio fragment.
+\item[CDROMPAUSE] Pause playback of audio fragment.
+\item[CDROMRESUME] Resume playing.
+\end{description}
+
+\subsubsection{New $ioctl$s in \cdromc}
+
+The following $ioctl$s have been introduced to allow user programs to
+control the behavior of individual \cdrom\ devices. New $ioctl$
+commands an be identified by their underscores in the name.
+\begin{description}
+\item[CDROM_SET_OPTIONS] Set options specified by $arg$. Returns the
+option flag register after modification. Use  $arg = \rm0$ for reading
+the current flags.
+\item[CDROM_CLEAR_OPTIONS] Clear options specified by $arg$. Returns
+  the option flag register after modification.
+\item[CDROM_SELECT_SPEED] Select head-rate speed of disc specified as
+  by $arg$. The value 0 means `auto-select', i.e., play audio discs at
+  real time and data disc at maximum speed. The value $arg$ is
+  checked against the maximum head rate of the drive found in
+  the $cdrom_dops$.
+\item[CDROM_SELECT_DISC] Select disc numbered $arg$ from a juke-box.
+  First disc is numbered 0. The number $arg$ is checked against the
+  maximum number of discs in the juke-box found in the $cdrom_dops$.
+\item[CDROM_MEDIA_CHANGED] Returns 1 if a disc has been changed since
+  the last call. Note that calls to cdrom_$media_changed$ by the VFS
+  are treated by an independent queue, so both mechanisms will detect
+  a media change once. Currently, \cdromc\ implements maximum 16 minors
+  per major device.
+\item[CDROM_DRIVE_STATUS] Returns the status of the drive by a call to
+  $drive_status()$. Return values are as defined in section~\ref{drive
+    status}. Note that this call doesn't return information on the
+  current playing activity of the drive, this can be polled through an
+  $ioctl$ call to $CDROMSUBCHNL$.
+\item[CDROM_DISC_STATUS] Returns the type of the disc currently in the
+  drive by a call to $disc_status()$. Return values are as defined in
+  section~\ref{disc status}.
+\end{description}
+
+\subsubsection{Device dependent $ioct$s}
+
+Finally, all other $ioctl$s are passed to the function $dev_ioctl()$,
+if implemented. No memory allocation or verification is carried out. 
+
+\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
+the directory tree that came with this documentation. 
+\item Include {\tt \char`\<linux/ucdrom.h>} just after {\tt cdrom.h}.
+\item change the 3rd argument of $register_blkdev$ from
+$\&<your-drive>_fops$ to $\&cdrom_fops$. 
+\item Just after that line, add a line to register to the \cdrom\
+routines: 
+$$register_cdrom(major, <name>, <your-drive>_dops);$$
+Similarly, add a call to $unregister_cdrom()$. 
+\item Copy an example of the device-operations $struct$ to your source,
+e.g., from {\tt cm206.c} $cm206_dops$, and change all entries to names
+corresponding to your driver, or names you just happen to like. If
+your driver doesn't support a certain function, make the entry
+$NULL$. At the entry $capability$ you should list all capabilities
+your drive could support, in principle. If your drive has a capability
+that is not listed, please send me a message.
+\item Implement all functions in your $<device>_dops$ structure,
+according to prototypes listed in \ucdrom, and specifications given in
+section~\ref{cdrom.c}. Most likely you have already implemented
+the code in a large part, and you may just have to adapt the prototype
+and return values. 
+\item Rename your $<device>_ioctl()$ function to $audio_ioctl$ and
+change the prototype a little. Remove entries listed in the first part
+in section~\ref{cdrom-ioctl}, if your code was OK, this are just calls
+to the routines you adapted in the previous step. 
+\item You may remove all remaining memory checking code in the
+$audio_ioctl()$ function that deal with audio commands (these are
+listed in the second part of section~\ref{cdrom-ioctl}). There is no
+need for memory allocation either, so most $case$s in the $switch$
+statement look similar to:
+$$
+case\ CDROMREADTOCENTRY\colon
+get_toc_entry\bigl((struct\ cdrom_tocentry *{})\ arg\bigr);
+$$
+\item All remaining $ioctl$ cases must be moved to a separate
+function, $<device>_ioctl$, the device-dependent $ioctl$s. Note that
+memory checking and allocation must be kept in this code!
+\item Change the prototypes of $<device>_open()$ and
+$<device>_release()$, and remove any strategic code (i.e., tray
+movement, door locking, etc.). 
+\item Try to recompile the drivers. We advice you to use modules, both
+for {\tt cdrom.o} and your driver, as debugging is much easier this
+way.
+\end{enumerate} 
+
+\section{Thanks}
+
+Thanks to all the people involved. Thanks to Thomas Quinot, Jon Tombs,
+Ken Pizzini, Eberhard M\"onkeberg and Andrew Kroll, the \linux\ 
+\cdrom\ device driver developers that were kind enough to give
+sugestions and criticisms during the writing. Finally of course, I
+want to thank Linus Torvalds for making this possible in the first
+place.
+
+\end{document}
+
diff -u --recursive --new-file v1.3.100/linux/Documentation/cdrom/cm206 linux/Documentation/cdrom/cm206
--- v1.3.100/linux/Documentation/cdrom/cm206	Fri Apr 12 15:51:43 1996
+++ linux/Documentation/cdrom/cm206	Sun May 12 08:13:07 1996
@@ -3,14 +3,20 @@
 
 				(c) 1995 David A. van Leeuwen
    
-Features as of version 0.33
+Changes since version 0.99
+--------------------------
+- Interfacing to the kernel is routed though an extra interface layer, 
+  cdrom.c. This allows runtime-configurable `bahavior' of the cdrom-drive, 
+  independent of the driver. 
+
+Features since version 0.33
 ---------------------------
 - Full audio support, that is, both  workman, workbone and cdp work
   now reasonably. Reading TOC still takes some time. xmcd has been
   reported to run successfully. 
 - Made auto-probe code a little better, i hope
 
-Features as of version 0.28
+Features since version 0.28
 ---------------------------
 - Full speed transfer rate (300 kB/s).
 - Minimum kernel memory usage for buffering (less than 3 kB).
@@ -21,12 +27,6 @@
 - Auto-probing of adapter card's base port and irq line,
   also configurable at boot time or module load time.
 
-Features still lacking
-----------------------
-- cm205ms+cm250 support. (I do have cm205ms docs now. I still have to
-  study Kai Petzke's cm205 drives to understand the workings of the
-  cm250 adapter card. Don't bet on me, write a driver yourself!)
-
 
 Decide how you are going to use the driver. There are two
 options:
@@ -66,9 +66,16 @@
 ----------------------------
 If you will only seldomly use the cd-rom driver, you can choose for
 option (b), install as a loadable module. You may have to re-compile
-the module when you upgrade the kernel to a new version. Read the file
-`README.modules' in /usr/src/linux. To install the module, you use the 
-command, as root
+the module when you upgrade the kernel to a new version. 
+
+Since version 0.96, much of the functionality has been transferred to
+a generic cdrom interface in the file cdrom.c. The module cm206.o
+depends on cdrom.o. If the latter is not compiled in in the kernel,
+you must explicitly load it before cm206.o:
+
+	 insmod /usr/src/linux/modules/cdrom.o
+
+To install the module, you use the command, as root
 
 	insmod /usr/src/linux/modules/cm206.o
 
@@ -80,16 +87,8 @@
 The order of base port and irq line don't matter; you may specify only
 one, the other will have the value of the compiled-in default.  You
 may also have to install the file-system module `iso9660.o', if you
-didn't compile that into the kernel. (If you use `tcsh' as shell, you
-might consider defining
+didn't compile that into the kernel. 
 
-	alias listinstalledmodules 'cat /proc/modules | awk \{print\$1\}'
-	complete rmmod		'p/1/`listinstalledmodules`/'
-	alias listcompiledmodules '(cd /usr/src/linux/modules; \ls -o *.o)'
-	alias insmod		'insmod /usr/src/linux/modules/\!:1 \!:2*'
-	complete insmod		'p/1/`listcompiledmodules`/'
-
-which makes typing insmod and rmmod somewhat easier.)
 
 Using the driver as part of the kernel
 --------------------------------------
@@ -103,6 +102,16 @@
 auto probing is turned off for both settings, thus setting the 
 other value to the compiled-in default.
 
+Note that you can put these parameters also in the lilo configuration file:
+
+# linux config
+image = /vmlinuz
+   root = /dev/hda1
+   label = Linux
+   append = "cm206=0x340,11"
+   read-only
+
+
 If module parameters and LILO config options don't work
 -------------------------------------------------------
 If autoprobing does not work, you can hard-wire the default values
@@ -111,7 +120,6 @@
 the defines of CM206_IRQ and CM206_BASE.
 
 
-
 Mounting the cdrom
 ------------------
 1) Make sure that there is the right device installed in /dev.
@@ -138,15 +146,14 @@
 If things don't work
 --------------------
 
-- Try to do a `tail /var/adm/messages' to find out if the driver
-  said anything about what is going wrong during the initialization.
+- Try to do a `dmesg' to find out if the driver said anything about
+  what is going wrong during the initialization.
 
 - Try to do a `dd if=/dev/cm206cd | od -tc | less' to read from the
   CD.
 
-- Look in the /proc directory to see if `cm206' shows up under
-  one of `interrupts', `ioports', `devices' or `modules' (if
-  applicable). 
+- Look in the /proc directory to see if `cm206' shows up under one of
+  `interrupts', `ioports', `devices' or `modules' (if applicable).
 
 
 DISCLAIMER 
@@ -173,5 +180,6 @@
 
     (c) 1995 David A. van Leeuwen
 
-The driver is released, like most Linux software, under the conditions 
-of the GNU general public license.
+The driver is released under the conditions of the GNU general public
+license, that can be found in the file COPYING in the root of this
+source tree.
diff -u --recursive --new-file v1.3.100/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v1.3.100/linux/Documentation/ioctl-number.txt	Tue May  7 16:22:15 1996
+++ linux/Documentation/ioctl-number.txt	Sat May 11 11:49:49 1996
@@ -1,5 +1,5 @@
 Ioctl Numbers
-6 May 1996
+10 May 1996
 Michael Chastain
 <mec@duracef.shout.net>
 
@@ -25,7 +25,7 @@
 for you.
 
 The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
-to distinguish ioctls from each other.  The third argument is a size
+to distinguish ioctls from each other.  The third argument is the size
 of the structure going into the kernel or coming out of the kernel.
 
 Some devices use their major number as the identifier; this is not
@@ -55,7 +55,6 @@
 Ioctl	Include File		Comments
 ========================================================
 0x00	linux/fs.h		only FIBMAP, FIGETBSZ
-0x00	linux/random.h		codes in 0x010800NN
 0x00	linux/mc146818rtc.h	conflict!
 0x02	linux/fd.h
 0x03	linux/hdreg.h
@@ -75,6 +74,7 @@
 'M'	linux/soundcard.h
 'P'	linux/soundcard.h
 'Q'	linux/soundcard.h
+'R'	linux/random.h
 'S'	linux/cdrom.h		conflict!
 'S'	scsi/scsi.h		conflict!
 'S'	scsi/scsi_ioctl.h	conflict!
diff -u --recursive --new-file v1.3.100/linux/Documentation/java.txt linux/Documentation/java.txt
--- v1.3.100/linux/Documentation/java.txt	Sat May 11 10:42:04 1996
+++ linux/Documentation/java.txt	Sat May 11 10:08:34 1996
@@ -51,7 +51,7 @@
 
 And then execute it:
 
-	./HellowWorld.class
+	./HelloWorld.class
 
 
 Yes, it's JUST THAT EASY! ;-)
diff -u --recursive --new-file v1.3.100/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt
--- v1.3.100/linux/Documentation/magic-number.txt	Tue May  7 16:22:15 1996
+++ linux/Documentation/magic-number.txt	Sat May 11 10:08:34 1996
@@ -21,7 +21,7 @@
 
 Please follow this discipline when you are adding future enhancements
 to the kernel!  It has saved me countless hours of debugging,
-especially in the screw cases where an array has been overrun and
+especially in the screwy cases where an array has been overrun and
 structures following the array have been overwritten.  Using this
 discipline, these cases get detected quickly and safely.
 
diff -u --recursive --new-file v1.3.100/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt
--- v1.3.100/linux/Documentation/oops-tracing.txt	Tue May  7 16:22:16 1996
+++ linux/Documentation/oops-tracing.txt	Sat May 11 10:08:34 1996
@@ -6,7 +6,7 @@
 messages ;-)
 
 Actually, there are things you can do that make this easier. I have two 
-separate approached:
+separate approaches:
 
 	gdb /usr/src/linux/vmlinux
 	gdb> disassemble <offending_function>
diff -u --recursive --new-file v1.3.100/linux/Makefile linux/Makefile
--- v1.3.100/linux/Makefile	Sat May 11 10:42:04 1996
+++ linux/Makefile	Sun May 12 08:57:56 1996
@@ -1,6 +1,6 @@
 VERSION = 1
-PATCHLEVEL = 3
-SUBLEVEL = 100
+PATCHLEVEL = 99
+SUBLEVEL = 1
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.100/linux/drivers/cdrom/Makefile linux/drivers/cdrom/Makefile
--- v1.3.100/linux/drivers/cdrom/Makefile	Tue Feb 13 10:30:25 1996
+++ linux/drivers/cdrom/Makefile	Sun May 12 08:13:07 1996
@@ -20,6 +20,16 @@
 M_OBJS   :=
 MOD_LIST_NAME := CDROM_MODULES
 
+# The following if's should be generalized (ORed) for all drivers that 
+# use the generic interface of cdrom.c 
+ifeq ($(CONFIG_CM206),y)
+L_OBJS += cdrom.o
+else
+  ifeq ($(CONFIG_CM206),m)
+  M_OBJS += cdrom.o
+  endif
+endif 
+
 ifeq ($(CONFIG_AZTCD),y)
 L_OBJS += aztcd.o
 else
diff -u --recursive --new-file v1.3.100/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v1.3.100/linux/drivers/cdrom/cdrom.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/cdrom/cdrom.c	Sun May 12 08:13:07 1996
@@ -0,0 +1,511 @@
+/* cdrom.c. Common ioctl and open routines for various Linux cdrom drivers. -*- linux-c -*-
+   Copyright (c) 1996 David van Leeuwen. 
+
+   The routines in the file should provide an interface between
+   software accessing cdroms and the various drivers that implement
+   specific hardware devices. 
+
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/fcntl.h>
+
+#include <linux/cdrom.h>
+#include <linux/ucdrom.h>
+
+#define FM_WRITE	0x2                 /* file mode write bit */
+
+#define VERSION "$Id: cdrom.c,v 0.4 1996/04/17 20:47:50 david Exp david $"
+
+/* Not-exported routines. */
+int cdrom_open(struct inode *ip, struct file *fp);
+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);
+
+struct file_operations cdrom_fops =
+{
+        NULL,                           /* lseek */
+        block_read,                     /* read - general block-dev read */
+        block_write,                    /* write - general block-dev write */
+        NULL,                           /* readdir */
+        NULL,                           /* select */
+        cdrom_ioctl,                    /* ioctl */
+        NULL,                           /* mmap */
+        cdrom_open,                     /* open */
+        cdrom_release,                  /* release */
+        NULL,                           /* fsync */
+        NULL,                           /* fasync */
+        cdrom_media_changed,            /* media_change */
+        NULL                            /* revalidate */
+};
+
+static struct cdrom_device_ops *cdromdevs[MAX_BLKDEV] = {
+	NULL,
+};
+
+/* This macro makes sure we don't have to check on cdrom_device_ops
+ * existence in the run-time routines below. Change_capability is a
+ * hack to have the capability flags defined const, while we can still
+ * change it here without gcc complaining at every line.
+ */
+
+#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
+
+/* We don't use $name$ yet, but it could be used for the /proc
+ * filesystem in the future, or for other purposes.  
+ */
+int register_cdrom(int major, char *name, struct cdrom_device_ops *cdo)
+{
+        int *change_capability = &cdo->capability; /* hack, gcc complains OK */
+	
+        if (major < 0 || major >= MAX_BLKDEV)
+                return -1;
+        if (cdo->open_files == NULL || cdo->open == NULL || 
+            cdo->release == NULL)
+                return -2;
+        ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+        ENSURE(lock_door, CDC_LOCK);
+        ENSURE(select_speed, CDC_SELECT_SPEED);
+        ENSURE(select_disc, CDC_SELECT_DISC);
+        ENSURE(get_last_session, CDC_MULTI_SESSION);
+        ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
+        ENSURE(media_changed, CDC_MEDIA_CHANGED);
+        cdromdevs[major] = cdo;
+        cdo->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
+        cdo->mc_flags = 0;
+        return 0;
+}
+#undef ENSURE
+
+int unregister_cdrom(int major, char *name)
+{
+        if (major < 0 || major >= MAX_BLKDEV)
+                return -1;
+        if (cdromdevs[major] == NULL)
+                return -2;
+        cdromdevs[major] = NULL;
+        return 0;
+}
+
+/* We need our own cdrom error types! This is a temporary solution. */
+
+#define ENOMEDIUM EAGAIN				/* no medium in removable device */
+
+/* We use the open-option O_NONBLOCK as in indicator of that the
+ * purpose of opening is only for subsequent ioctl() calls; no device
+ * integrity checks are performed.
+ *
+ * We hope that all cd-player programs will adopt this convention. It
+ * is in their own advantage: device conotrol becomes a lot easier
+ * this way.
+ */
+int open_for_data(struct cdrom_device_ops *, int);
+
+int cdrom_open(struct inode *ip, struct file *fp)
+{
+        dev_t dev = ip->i_rdev;
+        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
+        int purpose = !!(fp->f_flags & O_NONBLOCK);
+
+        if (cdo == NULL || MINOR(dev) >= cdo->minors)
+                return -ENODEV;
+        if (fp->f_mode & FM_WRITE)
+                return -EROFS;				
+        purpose = purpose || !(cdo->options & CDO_USE_FFLAGS);
+        if (cdo->open_files(dev) || purpose) 
+                return cdo->open(dev, purpose); 
+        else 
+                return open_for_data(cdo, dev);
+}
+
+int open_for_data(struct cdrom_device_ops * cdo, int dev)
+{
+        int ret;
+        if (cdo->drive_status != NULL) {
+                int ds = cdo->drive_status(dev);
+                if (ds == CDS_TRAY_OPEN) {
+                        /* can/may i close it? */
+                        if (cdo->capability & ~cdo->mask & CDC_CLOSE_TRAY &&
+                            cdo->options & CDO_AUTO_CLOSE) {
+                                if (cdo->tray_move(dev, 0))
+                                        return -EIO;
+                        } else
+                                return -ENOMEDIUM; /* can't close: too bad */
+                        ds = cdo->drive_status(dev);
+                        if (ds == CDS_NO_DISC)
+                                return -ENOMEDIUM;
+                }
+        }
+        if (cdo->disc_status != NULL) {
+                int ds = cdo->disc_status(dev);
+                if (ds == CDS_NO_DISC)
+                        return -ENOMEDIUM;
+                if (cdo->options & CDO_CHECK_TYPE &&
+                    ds != CDS_DATA_1)
+                        return -ENODATA;
+        }
+        /* all is well, we can open the device */
+        ret = cdo->open(dev, 0); /* open for data */
+        if (cdo->capability & ~cdo->mask & CDC_LOCK &&
+            cdo->options & CDO_LOCK)
+                cdo->lock_door(dev, 1);
+        return ret;
+}
+
+/* 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;
+        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
+	
+        if (cdo == NULL || MINOR(dev) >= cdo->minors)
+                return;
+        if (cdo->open_files(dev) == 1 && /* last process that closes dev */
+            cdo->options & CDO_LOCK &&  
+            cdo->capability & ~cdo->mask & CDC_LOCK) 
+                cdo->lock_door(dev, 0);
+        cdo->release(dev);
+        if (cdo->open_files(dev) == 0) { /* last process that closes dev */
+                sync_dev(dev);
+                invalidate_buffers(dev);
+                if (cdo->options & CDO_AUTO_EJECT &&
+                    cdo->capability & ~cdo->mask & CDC_OPEN_TRAY)
+                        cdo->tray_move(dev, 1);
+        }
+}
+
+/* We want to make media_changed accessible to the user through an
+ * ioctl. The main problem now is that we must double-buffer the
+ * low-level implementation, to assure that the VFS and the user both
+ * see a medium change once.
+ *
+ * For now, i've implemented only 16 minor devs (half a long), i have to
+ * think of a better solution... $Queue$ is either 0 or 1. Queue 0 is
+ * in the lower 16 bits, queue 1 in the higher 16 bits.
+ */
+
+int media_changed(dev_t dev, int queue)
+{
+        unsigned int major = MAJOR(dev);
+        unsigned int minor = MINOR(dev);
+        struct cdrom_device_ops *cdo = cdromdevs[major];
+        int ret;
+        unsigned long mask = 1 << (16 * queue + minor);
+
+        queue &= 1;
+        if (cdo == NULL || minor >= 16)
+                return -1;
+        ret = !!(cdo->mc_flags & mask); /* changed since last call? */
+        if (cdo->media_changed(dev)) {
+                cdo->mc_flags |= 0x10001 << minor; /* set bit on both queues */
+                ret |= 1;
+        }
+        cdo->mc_flags &= ~mask;         /* clear bit */
+        return ret;
+}
+
+int cdrom_media_changed(dev_t dev)
+{
+        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
+        if (cdo == NULL || MINOR(dev) >= cdo->minors)
+                return -ENODEV;
+        if (cdo->media_changed == NULL)
+                return -EINVAL;
+        return media_changed(dev, 0);
+}
+
+/* Requests to the low-level drivers will /always/ be done in the
+   following format convention: 
+
+   CDROM_LBA: all data-related requests.
+   CDROM_MSF: all audio-related requests. 
+
+   However, a low-level implementation is allowed to refuse this
+   request, and return information in its own favorite format.  
+
+   It doesn't make sense /at all/ to ask for a play_audio in LBA
+   format, or ask for multi-session info in MSF format. However, for
+   backward compatibility these format requests will be satisfied, but
+   the requests to the low-level drivers will be sanitized in the more
+   meaningful format indicated above.
+ */
+
+#undef current							/* set in sched.h */
+
+void sanitize_format(union cdrom_addr *addr,
+                     u_char * current, u_char requested)
+{
+        if (*current == requested)
+                return;                 /* nothing to be done! */
+        if (requested == CDROM_LBA) {
+                addr->lba = (int) addr->msf.frame +
+                        75 * (addr->msf.second - 2 + 60 * addr->msf.minute);
+        } else {                        /* CDROM_MSF */
+                int lba = addr->lba;
+                addr->msf.frame = lba % 75;
+                lba /= 75;
+                lba += 2;
+                addr->msf.second = lba % 60;
+                addr->msf.minute = lba / 60;
+        }
+        *current = requested;
+}
+
+/* All checking and format change makes this code really hard to read!
+ * So let's make some check and memory move macros.  These macros are
+ * a little inenficient when used both in the same piece of code, as
+ * verify_area is used twice, but who cares, as ioctl() calls
+ * shouldn't be in inner loops.
+ */
+#define GETARG(type, x) { \
+        int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
+	    if (ret) return ret; \
+	    memcpy_fromfs(&x, (type *) arg, sizeof x); }
+#define PUTARG(type, x) { \
+	    int ret=verify_area(VERIFY_WRITE, (void *) arg, sizeof x); \
+	    if (ret) return ret; \
+	    memcpy_tofs((type *) arg, &x, sizeof x); }
+
+/* Some of the cdrom ioctls are not implemented here, because these
+ * appear to be either too device-specific, or it is not clear to me
+ * what use they are. These are (number of drivers that support them
+ * in parenthesis): CDROMREADMODE1 (2+ide), CDROMREADMODE2 (2+ide),
+ * CDROMREADAUDIO (2+ide), CDROMREADRAW (2), CDROMREADCOOKED (2),
+ * CDROMSEEK (2), CDROMPLAYBLK (scsi), CDROMREADALL (1). Read-audio,
+ * OK (although i guess the record companies aren't too hapy with
+ * this, most drives therefor refuse to transport audio data).  But
+ * why are there 5 different READs defined? For now, these functions
+ * are left over to the device-specific ioctl routine,
+ * cdo->dev_ioctl. Note that as a result of this, no
+ * memory-verification is performed for these ioctls.
+ */
+int cdrom_ioctl(struct inode *ip, struct file *fp,
+                unsigned int cmd, unsigned long arg)
+{
+        dev_t dev = ip->i_rdev;
+        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
+
+        if (cdo == NULL || MINOR(dev) >= cdo->minors)
+                return -ENODEV;
+        /* the first few commands do not deal with audio capabilities, but
+           only with routines in cdrom device operations. */
+        switch (cmd) {
+                /* maybe we should order cases after statistics of use? */
+
+        case CDROMMULTISESSION: 
+        {
+                struct cdrom_multisession ms_info;
+                u_char requested_format;
+                if (!(cdo->capability & CDC_MULTI_SESSION))
+                        return -EINVAL;
+                GETARG(struct cdrom_multisession, ms_info);
+                requested_format = ms_info.addr_format;
+                ms_info.addr_format = CDROM_LBA;
+                cdo->get_last_session(dev, &ms_info);
+                sanitize_format(&ms_info.addr, &ms_info.addr_format, 
+                                requested_format);
+                PUTARG(struct cdrom_multisession, ms_info);
+                return 0;
+        }
+                
+        case CDROMEJECT:
+                if (cdo->open_files(dev) == 1 && 
+                    cdo->capability & ~cdo->mask & CDC_OPEN_TRAY)
+                        return cdo->tray_move(dev, 1);
+                else
+                        return -EINVAL;
+		
+        case CDROMCLOSETRAY:
+                if (cdo->open_files(dev) == 1 && 
+                    cdo->capability & ~cdo->mask & CDC_CLOSE_TRAY)
+                        return cdo->tray_move(dev, 0);
+                else
+                        return -EINVAL;
+                
+        case CDROMEJECT_SW:
+                cdo->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
+                if (arg)
+                        cdo->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
+                return 0;
+
+        case CDROM_MEDIA_CHANGED:
+                if (cdo->capability & ~cdo->mask & CDC_MEDIA_CHANGED)
+                        return media_changed(dev, 1);
+                else
+                        return -EINVAL;
+                
+        case CDROM_SET_OPTIONS:
+                cdo->options |= (int) arg;
+                return cdo->options;
+		
+        case CDROM_CLEAR_OPTIONS:
+                cdo->options &= ~(int) arg;
+                return cdo->options;
+                
+        case CDROM_SELECT_SPEED:
+                if (0 <= arg && arg < (int) (cdo->speed + 0.5) &&
+                    cdo->capability & ~cdo->mask & CDC_SELECT_SPEED)
+                        return cdo->select_speed(dev, arg);
+                else
+                        return -EINVAL;
+                
+        case CDROM_SELECT_DISC:
+                if (0 <= arg && arg <= cdo->capacity &&
+                    cdo->capability & ~cdo->mask & CDC_SELECT_DISC)
+                        return cdo->select_disc(dev, arg);
+                else
+                        return -EINVAL;
+		
+/* The following function is implemented, although very few audio
+ * discs give Universal Product Code information, which should just be
+ * the Medium Catalog Number on the box.  Note, that the way the code
+ * is written on the CD is /not/ uniform across all discs!
+ */
+        case CDROM_GET_MCN: {
+                struct cdrom_mcn mcn;
+                if (!(cdo->capability & CDC_MCN))
+                        return -EINVAL;
+                if (!cdo->get_mcn(dev, &mcn)) {
+                        PUTARG(struct cdrom_mcn, mcn);
+                        return 0;
+                }
+                return -EINVAL;
+        }
+                
+        case CDROM_DRIVE_STATUS:
+                if (cdo->drive_status == NULL)
+			return -EINVAL;
+		else
+			return cdo->drive_status(dev);
+		
+        case CDROM_DISC_STATUS:
+		if (cdo->disc_status == NULL)
+			return -EINVAL;
+		else
+			return cdo->disc_status(dev);
+		
+/* The following is not implemented, because there are too many
+ * different data type. We could support /1/ raw mode, that is large
+ * enough to hold everything.
+ */
+		
+#if 0
+        case CDROMREADMODE1: {
+                struct cdrom_msf msf;
+                char buf[CD_FRAMESIZE];
+                GETARG(struct cdrom_msf, msf);
+                if (!cdo->read_audio(dev, cmd, &msf, &buf)) {
+                        PUTARG(char *, buf);
+                        return 0;
+                }
+                return -EINVAL;
+        }
+#endif
+	} /* switch */
+	
+/* Now all the audio-ioctls follow, they are all routed through the
+   same call audio_ioctl(). */
+
+	if (cdo->capability & CDC_PLAY_AUDIO)
+		switch (cmd) {
+                case CDROMSUBCHNL: 
+                {
+                        struct cdrom_subchnl q;
+                        u_char requested, back;
+                        GETARG(struct cdrom_subchnl, q);
+                        requested = q.cdsc_format;
+                        q.cdsc_format = CDROM_MSF;
+                        if (!cdo->audio_ioctl(dev, cmd, &q)) {
+                                back = q.cdsc_format; /* local copy */
+                                sanitize_format(&q.cdsc_absaddr, &back, requested);
+                                sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
+                                PUTARG(struct cdrom_subchnl, q);
+                                return 0;
+                        } else
+                                return -EINVAL;
+                }
+                case CDROMREADTOCHDR: {
+                        struct cdrom_tochdr header;
+                        GETARG(struct cdrom_tochdr, header);
+                        if (!cdo->audio_ioctl(dev, cmd, &header)) {
+                                PUTARG(struct cdrom_tochdr, header);
+                                return 0;
+                        } else
+                                return -EINVAL;
+                }
+                case CDROMREADTOCENTRY: {
+                        struct cdrom_tocentry entry;
+                        u_char requested_format;
+                        GETARG(struct cdrom_tocentry, entry);
+                        requested_format = entry.cdte_format;
+                        /* make interface to low-level uniform */
+                        entry.cdte_format = CDROM_MSF; 
+                        if (!(cdo->audio_ioctl(dev, cmd, &entry))) {
+                                sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format);
+                                PUTARG(struct cdrom_tocentry, entry);
+                                return 0;
+                        } else
+                                return -EINVAL;
+                }
+                case CDROMPLAYMSF: {
+                        struct cdrom_msf msf;
+                        GETARG(struct cdrom_mdf, msf);
+                        return cdo->audio_ioctl(dev, cmd, &msf);
+                }
+                case CDROMPLAYTRKIND: {
+                        struct cdrom_ti track_index;
+                        GETARG(struct cdrom_ti, track_index);
+                        return cdo->audio_ioctl(dev, cmd, &track_index);
+                }
+                case CDROMVOLCTRL: {
+                        struct cdrom_volctrl volume;
+                        GETARG(struct cdrom_volctl, volume);
+                        return cdo->audio_ioctl(dev, cmd, &volume);
+                }
+                case CDROMVOLREAD: {
+                        struct cdrom_volctrl volume;
+                        if (!cdo->audio_ioctl(dev, cmd, &volume)) {
+                                PUTARG(struct cdrom_volctl, volume);
+                                return 0;
+                        }
+                        return -EINVAL;
+                }
+                case CDROMSTART:
+                case CDROMSTOP:
+                case CDROMPAUSE:
+                case CDROMRESUME:
+			return cdo->audio_ioctl(dev, cmd, NULL);
+		} /* switch */
+
+	if (cdo->dev_ioctl != NULL)     /* device specific ioctls? */
+		return cdo->dev_ioctl(dev, cmd, arg);
+	return -EINVAL;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	printk(KERN_INFO "Module inserted " VERSION "\n");
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	printk(KERN_INFO "Module cdrom removed\n");
+}
+
+#endif
+/*
+ * Local variables:
+ * comment-column: 40
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux-obj/include -Wall -Wstrict-prototypes -O2 -m486 -c cdrom.c -o cdrom.o"
+ * End:
+ */
diff -u --recursive --new-file v1.3.100/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- v1.3.100/linux/drivers/cdrom/cm206.c	Fri Apr 12 15:51:51 1996
+++ linux/drivers/cdrom/cm206.c	Sun May 12 08:13:07 1996
@@ -1,5 +1,5 @@
 /* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card.
-   Copyright (c) 1995 David van Leeuwen.
+   Copyright (c) 1995, 1996 David van Leeuwen.
    
      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
@@ -54,11 +54,30 @@
  10 jun 1995: 0.33 Workman still behaves funny, but you should be
               able to eject and substitute another disc.
 
- An adaption of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg
+ An adaptation of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg
 
- 18 jul 1996: 0.34 Patch by Heiko Eissfeldt included, mainly considering 
+ 18 jul 1995: 0.34 Patch by Heiko Eissfeldt included, mainly considering 
               verify_area's in the ioctls. Some bugs introduced by 
 	      EM considering the base port and irq fixed. 
+
+ 18 dec 1995: 0.35 Add some code for error checking... no luck...
+
+ We jump to reach our goal: version 1.0 in the next stable linux kernel.
+
+ 19 mar 1996: 0.95 Different implementation of CDROM_GET_UPC, on
+	      request of Thomas Quinot. 
+ 25 mar 1996: 0.96 Interpretation of opening with O_WRONLY or O_RDWR:
+	      open only for ioctl operation, e.g., for operation of
+	      tray etc.
+ 4 apr 1996:  0.97 First implementation of layer between VFS and cdrom
+              driver, a generic interface. Much of the functionality
+	      of cm206_open() and cm206_ioctl() is transferred to a
+	      new file cdrom.c and its header ucdrom.h. 
+
+	      Upgrade to Linux kernel 1.3.78. 
+
+ 11 apr 1996  0.98 Upgrade to Linux kernel 1.3.85
+              More uniformization stuff.
  * 
  * Parts of the code are based upon lmscd.c written by Kai Petzke,
  * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin
@@ -73,13 +92,13 @@
  * with `cm206' in it, as this stuff is too series-dependent. 
  * 
  * Currently, my limited knowledge is based on:
- * - The Linux Kernel Hacker's guide, v. 0.5 , by Michael J. Johnson
+ * - The Linux Kernel Hacker's guide, v. 0.5, by Michael J. Johnson
  * - Linux Kernel Programmierung, by Michael Beck and others
  * - Philips/LMS cm206 and cm226 product specification
  * - Philips/LMS cm260 product specification
  *
  *                       David van Leeuwen, david@tm.tno.nl.  */
-#define VERSION "0.34"
+#define VERSION "$Id: cm206.c,v 0.99 1996/04/14 20:26:26 david Exp $"
 
 #include <linux/module.h>	
 
@@ -94,10 +113,18 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 
+#include <linux/ucdrom.h>
+
 #include <asm/io.h>
 
 #define MAJOR_NR CM206_CDROM_MAJOR
 #include <linux/blk.h>
+
+#undef DEBUG
+#define STATISTICS		/* record times and frequencies of events */
+#undef AUTO_PROBE_MODULE
+#define USE_INSW
+
 #include <linux/cm206.h>
 
 /* This variable defines whether or not to probe for adapter base port 
@@ -109,11 +136,6 @@
 static int cm206_base = CM206_BASE;
 static int cm206_irq = CM206_IRQ; 
 
-#undef DEBUG
-#undef DEBUG_SECTORS
-#define STATISTICS
-#undef AUTO_PROBE_MODULE
-
 #define POLLOOP 10000
 #define READ_AHEAD 1		/* defines private buffer, waste! */
 #define BACK_AHEAD 1		/* defines adapter-read ahead */
@@ -121,13 +143,16 @@
 #define UART_TIMEOUT (5*HZ/100)
 #define DSB_TIMEOUT (7*HZ)	/* time for the slowest command to finish */
 
+#define LINUX_BLOCK_SIZE 512	/* WHERE is this defined? */
 #define RAW_SECTOR_SIZE 2352	/* ok, is also defined in cdrom.h */
 #define ISO_SECTOR_SIZE 2048
+#define BLOCKS_ISO (ISO_SECTOR_SIZE/LINUX_BLOCK_SIZE) /* 4 */
+#define CD_SYNC_HEAD 16		/* CD_SYNC + CD_HEAD */
 
 #ifdef STATISTICS		/* keep track of errors in counters */
-#include <linux/stats206.h>
-#define stats(i) ++cd->stats[st_ ## i]; \
-                 cd->last_stat[st_ ## i] = cd->stat_counter++;
+#define stats(i) { ++cd->stats[st_ ## i]; \
+		     cd->last_stat[st_ ## i] = cd->stat_counter++; \
+		 }
 #else
 #define stats(i) (void) 0
 #endif
@@ -141,7 +166,7 @@
 typedef unsigned char uch;	/* 8-bits */
 typedef unsigned short ush;	/* 16-bits */
 
-struct toc_struct{
+struct toc_struct{		/* private copy of Table of Contents */
   uch track, fsm[3], q0;
 };
 
@@ -174,6 +199,7 @@
   struct toc_struct toc[101];	/* The whole table of contents + lead-out */
   uch q[10];			/* Last read q-channel info */
   uch audio_status[5];		/* last read position on pause */
+  uch media_changed;		/* record if media changed */
 };
 
 #define DISC_STATUS cd->disc_status[0]
@@ -182,7 +208,7 @@
 #define PAUSED cd->audio_status[0] /* misuse this memory byte! */
 #define PLAY_TO cd->toc[0]	/* toc[0] records end-time in play */
 
-static struct cm206_struct * cd;
+static struct cm206_struct * cd; /* the main memory structure */
 
 /* First, we define some polling functions. These are actually
    only being used in the initialization. */
@@ -221,62 +247,64 @@
    as there seems so reason for this to happen.
 */
 
-static void cm206_interrupt(int sig, void *dev_id, struct pt_regs * regs) /* you rang? */
+static void cm206_interrupt(int sig, void *dev_id, struct pt_regs * regs) 
+/* you rang? */
 {
   volatile ush fool;
-    cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error,
-					 crc_error, sync_error, toc_ready 
-					 interrupts */
-    cd->intr_ls = inw(r_line_status); /* resets overrun bit */
-    /* receive buffer full? */
-    if (cd->intr_ls & ls_receive_buffer_full) {	
-      cd->intr_ur = inb(r_uart_receive); /* get order right! */
-      cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */
-      if (!cd->background && cd->uart) wake_up_interruptible(&cd->uart);
-    }
-    /* data ready in fifo? */
-    else if (cd->intr_ds & ds_data_ready) { 
-      if (cd->background) ++cd->adapter_last;
-      if ((cd->wait_back || !cd->background) && cd->data) 
-	  wake_up_interruptible(&cd->data);
-      stats(data_ready);
-    }
-    /* ready to issue a write command? */
-    else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) {
-      outw(dc_normal | (inw(r_data_status) & 0x7f), r_data_control);
-      outw(cd->command, r_uart_transmit);
-      cd->command=0;
-      if (!cd->background) wake_up_interruptible(&cd->uart);
-    }
-    /* now treat errors (at least, identify them for debugging) */
-    else if (cd->intr_ds & ds_fifo_overflow) {
-      debug(("Fifo overflow at sectors 0x%x\n", cd->sector_first));
-      fool = inw(r_fifo_output_buffer);	/* de-assert the interrupt */
-      cd->fifo_overflowed=1;	/* signal one word less should be read */
-      stats(fifo_overflow);
-    }
-    else if (cd->intr_ds & ds_data_error) {
-      debug(("Data error at sector 0x%x\n", cd->sector_first));
-      stats(data_error);
-    }
-    else if (cd->intr_ds & ds_crc_error) {
-      debug(("CRC error at sector 0x%x\n", cd->sector_first));
-      stats(crc_error);
-    }
-    else if (cd->intr_ds & ds_sync_error) {
-      debug(("Sync at sector 0x%x\n", cd->sector_first));
-      stats(sync_error);
-    }
-    else if (cd->intr_ds & ds_toc_ready) {
-				/* do something appropriate */
-    }
-    /* couldn't see why this interrupt, maybe due to init */
-    else {			
-      outw(dc_normal | READ_AHEAD, r_data_control);
-      stats(lost_intr);
-    }
+  cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error,
+				       crc_error, sync_error, toc_ready 
+				       interrupts */
+  cd->intr_ls = inw(r_line_status); /* resets overrun bit */
+  if (cd->intr_ls & ls_attention) stats(attention);
+  /* receive buffer full? */
+  if (cd->intr_ls & ls_receive_buffer_full) {	
+    cd->intr_ur = inb(r_uart_receive); /* get order right! */
+    cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */
+    if (!cd->background && cd->uart) wake_up_interruptible(&cd->uart);
+  }
+  /* data ready in fifo? */
+  else if (cd->intr_ds & ds_data_ready) { 
+    if (cd->background) ++cd->adapter_last;
+    if ((cd->wait_back || !cd->background) && cd->data) 
+      wake_up_interruptible(&cd->data);
+    stats(data_ready);
+  }
+  /* ready to issue a write command? */
+  else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) {
+    outw(dc_normal | (inw(r_data_status) & 0x7f), r_data_control);
+    outw(cd->command, r_uart_transmit);
+    cd->command=0;
+    if (!cd->background) wake_up_interruptible(&cd->uart);
+  }
+  /* now treat errors (at least, identify them for debugging) */
+  else if (cd->intr_ds & ds_fifo_overflow) {
+    debug(("Fifo overflow at sectors 0x%x\n", cd->sector_first));
+    fool = inw(r_fifo_output_buffer);	/* de-assert the interrupt */
+    cd->fifo_overflowed=1;	/* signal one word less should be read */
+    stats(fifo_overflow);
+  }
+  else if (cd->intr_ds & ds_data_error) {
+    debug(("Data error at sector 0x%x\n", cd->sector_first));
+    stats(data_error);
+  }
+  else if (cd->intr_ds & ds_crc_error) {
+    debug(("CRC error at sector 0x%x\n", cd->sector_first));
+    stats(crc_error);
+  }
+  else if (cd->intr_ds & ds_sync_error) {
+    debug(("Sync at sector 0x%x\n", cd->sector_first));
+    stats(sync_error);
+  }
+  else if (cd->intr_ds & ds_toc_ready) {
+    /* do something appropiate */
+  }
+  /* couldn't see why this interrupt, maybe due to init */
+  else {			
+    outw(dc_normal | READ_AHEAD, r_data_control);
+    stats(lost_intr);
+  }
   if (cd->background && (cd->adapter_last-cd->adapter_first == cd->max_sectors
-      || cd->fifo_overflowed))
+			 || cd->fifo_overflowed))
     mark_bh(CM206_BH);	/* issue a stop read command */
   stats(interrupt);
 }
@@ -446,6 +474,20 @@
   return 0;
 }
 
+#ifdef USE_INSW
+#define transport_data insw
+#else
+/* this routine implements insw(,,). There was a time i had the
+   impression that there would be any difference in error-behaviour. */
+void transport_data(int port, ush * dest, int count) 
+{
+  int i;
+  ush * d;
+  for (i=0, d=dest; i<count; i++, d++) 
+    *d = inw(port);
+}
+#endif
+
 int read_sector(int start)
 {
   if (cd->background) {
@@ -462,7 +504,8 @@
     stop_read();
     return -3;		
   }
-  insw(r_fifo_output_buffer, cd->sector, READ_AHEAD*RAW_SECTOR_SIZE/2);
+  transport_data(r_fifo_output_buffer, cd->sector, 
+		 READ_AHEAD*RAW_SECTOR_SIZE/2);
   if (read_background(start+READ_AHEAD,1)) stats(read_background);
   cd->sector_first = start; cd->sector_last = start+READ_AHEAD;
   stats(read_restarted);
@@ -514,12 +557,18 @@
   }
 }
 
+/* This command clears the dsb_possible_media_change flag, so we must 
+ * retain it.
+ */
 void get_drive_status(void)
 {
   uch status[2];
   type_1_command(c_drive_status, 2, status); /* this might be done faster */
   cd->dsb=status[0];
   cd->cc=status[1];
+  cd->media_changed |= 
+    !!(cd->dsb & (dsb_possible_media_change | 
+		  dsb_drive_not_ready | dsb_tray_not_closed));
 }
 
 void get_disc_status(void)
@@ -529,55 +578,30 @@
   }
 }
 
-static int cm206_open(struct inode *ip, struct file *fp)
+/* The new open. The real opeining strategy is defined in cdrom.c. */
+
+static int cm206_open(dev_t dev, int purpose) 
 {
-  if (!cd->openfiles) {
+  if (!cd->openfiles) {		/* reset only first time */
     cd->background=0;
     reset_cm260();
     cd->adapter_last = -1;	/* invalidate adapter memory */
     cd->sector_last = -1;
-    get_drive_status();
-    if (cd->dsb & dsb_tray_not_closed) {
-      int i=0;
-      type_0_command(c_close_tray, 1);
-      while (i++<10 && cd->dsb & dsb_drive_not_ready) {
-	cm206_delay(100);
-	get_drive_status();
-      }
-    }
-    if (cd->dsb & (dsb_not_useful)) return -EIO;
-    if (!(cd->dsb & dsb_disc_present)) return -ENODATA;
-    if (cd->dsb & dsb_possible_media_change) {
-      memset(cd->toc, 0, sizeof(cd->toc));
-      memset(cd->audio_status, 0, sizeof(cd->audio_status));
-    }
-    get_disc_status();
-    type_0_command(c_lock_tray,1);
-    if (!(cd->dsb & dsb_tray_locked)) {
-      debug(("Couldn't lock tray\n"));
-    }
-#if 0
-    if (!(DISC_STATUS & cds_all_audio))
-      read_background(16,0);	/* do something useful */
-#endif
   }
   ++cd->openfiles; MOD_INC_USE_COUNT;
   stats(open);
   return 0;
 }
 
-static void cm206_release(struct inode *ip, struct file *fp)
+static void cm206_release(dev_t dev)
 {
   if (cd->openfiles==1) {
     if (cd->background) {
       cd->background=0;
       stop_read();
     }
-    type_0_command(c_unlock_tray,1);
     cd->sector_last = -1;	/* Make our internal buffer invalid */
-    FIRST_TRACK = 0;	/* No valid disc status */
-    sync_dev(ip -> i_rdev);	/* These two lines are stolen */
-    invalidate_buffers(ip -> i_rdev);
+    FIRST_TRACK = 0;		/* No valid disc status */
   }
   --cd->openfiles; MOD_DEC_USE_COUNT;
 }
@@ -587,7 +611,7 @@
 void empty_buffer(int sectors) 
 {
   while (sectors>=0) {
-    insw(r_fifo_output_buffer, cd->sector + cd->fifo_overflowed, 
+    transport_data(r_fifo_output_buffer, cd->sector + cd->fifo_overflowed, 
 	 RAW_SECTOR_SIZE/2 - cd->fifo_overflowed);
     --sectors;
     ++cd->adapter_first;	/* update the current adapter sector */
@@ -598,7 +622,7 @@
   cd->sector_last=cd->adapter_first; /* update the buffer sector */
 }
 
-/* try_adapter. This function determines of the requested sector is is
+/* try_adapter. This function determines if the requested sector is is
    in adapter memory, or will appear there soon. Returns 0 upon
    success */
 int try_adapter(int sector)
@@ -648,18 +672,18 @@
     }
     error=0;
     for (i=0; i<CURRENT->nr_sectors; i++) {
-      cd_sec_no = (CURRENT->sector+i)/4; /* 4 times 512 bytes */
-      quarter = (CURRENT->sector+i) % 4; 
-      dest = CURRENT->buffer + i*512;
+      cd_sec_no = (CURRENT->sector+i)/BLOCKS_ISO; /* 4 times 512 bytes */
+      quarter = (CURRENT->sector+i) % BLOCKS_ISO; 
+      dest = CURRENT->buffer + i*LINUX_BLOCK_SIZE;
       /* is already in buffer memory? */
       if (cd->sector_first <= cd_sec_no && cd_sec_no < cd->sector_last) {
-	source = ((uch *) cd->sector) + 16 + 
-	  quarter*512 + (cd_sec_no-cd->sector_first)*RAW_SECTOR_SIZE;
- 	memcpy(dest, source, 512); 
+	source = ((uch *) cd->sector) + 16 + quarter*LINUX_BLOCK_SIZE 
+	  + (cd_sec_no-cd->sector_first)*RAW_SECTOR_SIZE;
+ 	memcpy(dest, source, LINUX_BLOCK_SIZE); 
       }
       else if (!try_adapter(cd_sec_no) || !read_sector(cd_sec_no)) {
-	source =  ((uch *) cd->sector)+16+quarter*512;
-	memcpy(dest, source, 512); 
+	source =  ((uch *) cd->sector)+16+quarter*LINUX_BLOCK_SIZE;
+	memcpy(dest, source, LINUX_BLOCK_SIZE); 
       }
       else {
 	error=1;
@@ -669,27 +693,6 @@
   }
 }
 
-int get_multi_session_info(struct cdrom_multisession * mssp)
-{
-  if (!FIRST_TRACK) get_disc_status();
-  if (mssp) {
-    if (DISC_STATUS & cds_multi_session) { /* multi-session */
-      if (mssp->addr_format == CDROM_LBA)
-      	mssp->addr.lba = fsm2lba(&cd->disc_status[3]);
-      else {
-      	mssp->addr.msf.frame = cd->disc_status[3];
-      	mssp->addr.msf.second = cd->disc_status[4];
-      	mssp->addr.msf.minute = cd->disc_status[5];
-      }
-      mssp->xa_flag = 1;
-    } else {
-      mssp->xa_flag = 0;
-    }
-    return 1;
-  }
-  return 0;
-}
-
 /* Audio support. I've tried very hard, but the cm206 drive doesn't 
    seem to have a get_toc (table-of-contents) function, while i'm
    pretty sure it must read the toc upon disc insertion. Therefore
@@ -753,11 +756,6 @@
       cd->toc[ct].track=q[1];	/* lead out still 0xaa */
       fsm(l, cd->toc[ct].fsm);
       cd->toc[ct].q0 = q[0];	/* contains adr and ctrl info */
-/*
-      if (ct==LAST_TRACK+1) 
-	printk("Leadout %x %x %x %x %d %d %d \n", q[1], q[3], q[4], q[5],
-	       q[7], q[8], q[9]);
-*/
       if (ct==track) return l;
     }
     old_lba=lba;
@@ -782,6 +780,7 @@
   if (!cd->toc[track].track) get_toc_lba(track);
 }
 
+/* return 0 upon success */
 int read_toc_header(struct cdrom_tochdr * hp)
 {
   if (!FIRST_TRACK) get_disc_status();
@@ -792,9 +791,9 @@
     cd->toc[1].track=1;		/* fill in first track position */
     for (i=0; i<3; i++) cd->toc[1].fsm[i] = cd->disc_status[3+i];
     update_toc_entry(LAST_TRACK+1);		/* find most entries */
-    return 1;
+    return 0;
   }
-  return 0;
+  return -1;
 }  
 
 void play_from_to_msf(struct cdrom_msf* msfp)
@@ -859,120 +858,54 @@
   else if (PAUSED) 
     qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED;
   else qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS;
-  return 1;
+  return 0;
 }
 
+void invalidate_toc(void)
+{
+  memset(cd->toc, 0, sizeof(cd->toc));
+  memset(cd->disc_status, 0, sizeof(cd->disc_status));
+}
+
+/* cdrom.c guarantees that cdte_format == CDROM_MSF */
 void get_toc_entry(struct cdrom_tocentry * ep)
 {
   uch track = normalize_track(ep->cdte_track);
   update_toc_entry(track);
-  if (ep->cdte_format == CDROM_MSF) {
-    ep->cdte_addr.msf.frame = cd->toc[track].fsm[0];
-    ep->cdte_addr.msf.second = cd->toc[track].fsm[1];
-    ep->cdte_addr.msf.minute = cd->toc[track].fsm[2];
-  } 
-  else ep->cdte_addr.lba = fsm2lba(cd->toc[track].fsm);
+  ep->cdte_addr.msf.frame = cd->toc[track].fsm[0];
+  ep->cdte_addr.msf.second = cd->toc[track].fsm[1];
+  ep->cdte_addr.msf.minute = cd->toc[track].fsm[2];
   ep->cdte_adr = cd->toc[track].q0 & 0xf; 
   ep->cdte_ctrl = cd->toc[track].q0 >> 4;
   ep->cdte_datamode=0;
 }
-  
-/* Ioctl. I have made the statistics accessible through an ioctl
-   call. The constant is defined in cm206.h, it shouldn't clash with
-   the standard Linux ioctls. Multisession info is gathered at
-   run-time, this may turn out to be slow. */
 
-static int cm206_ioctl(struct inode * inode, struct file * file, 
-		       unsigned int cmd, unsigned long arg)
+/* Audio ioctl.  Ioctl commands connected to audio are in such an
+ * idiosyncratic i/o format, that we leave these untouched. Return 0
+ * upon success. Memory checking has been done by cdrom_ioctl(), the
+ * calling function, as well as LBA/MSF sanatization.
+*/
+int cm206_audio_ioctl(dev_t dev, unsigned int cmd, void * arg)
 {
   switch (cmd) {
-#ifdef STATISTICS
-  case CM206CTL_GET_STAT:
-    if (arg >= NR_STATS) return -EINVAL;
-    else return cd->stats[arg];
-  case CM206CTL_GET_LAST_STAT:
-    if (arg >= NR_STATS) return -EINVAL;
-    else return cd->last_stat[arg];
-#endif    
-  case CDROMMULTISESSION: {
-    struct cdrom_multisession ms_info;
-    int st;
-    stats(ioctl_multisession);
-
-    st=verify_area(VERIFY_WRITE, (void *) arg, 
-		   sizeof(struct cdrom_multisession));
-    if (st) return (st);
-    memcpy_fromfs(&ms_info, (struct cdrom_multisession *) arg,
-		  sizeof(struct cdrom_multisession));
-    get_multi_session_info(&ms_info);
-    memcpy_tofs((struct cdrom_multisession *) arg, &ms_info, 
-		  sizeof(struct cdrom_multisession));
-    return 0;
-  }
-  case CDROMRESET:		/* If needed, it's probably too late anyway */
-    stop_read();
-    reset_cm260();
-    outw(dc_normal | dc_break | READ_AHEAD, r_data_control);
-    udelay(1000);		/* 750 musec minimum */
-    outw(dc_normal | READ_AHEAD, r_data_control);
-    cd->sector_last = -1;	/* flag no data buffered */
-    cd->adapter_last = -1;    
-    return 0;
-  }
-
-  get_drive_status();
-  if (cd->dsb & (dsb_drive_not_ready | dsb_tray_not_closed) )
-    return -EAGAIN; 
-
-  switch (cmd) {
-  case CDROMREADTOCHDR: {
-    struct cdrom_tochdr header;
-    int st;
-
-    st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(header));
-    if (st) return (st);
-    if (read_toc_header(&header)) {
-      memcpy_tofs((struct cdrom_tochdr *) arg, &header, sizeof(header));
-      return 0;
-    }
-    else return -ENODATA;
-  }
-  case CDROMREADTOCENTRY: {	
-    struct cdrom_tocentry entry;
-    int st;
-
-    st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry));
-    if (st) return (st);
-    memcpy_fromfs(&entry, (struct cdrom_tocentry *) arg, sizeof entry);
-    get_toc_entry(&entry);
-    memcpy_tofs((struct cdrom_tocentry *) arg, &entry, sizeof entry);
+  case CDROMREADTOCHDR: 
+    return read_toc_header((struct cdrom_tochdr *) arg);
+  case CDROMREADTOCENTRY: 	
+    get_toc_entry((struct cdrom_tocentry *) arg);
     return 0;
-  }
-  case CDROMPLAYMSF: {
-    struct cdrom_msf msf;
-    int st;
-
-    st=verify_area(VERIFY_READ, (void *) arg, sizeof(msf));
-    if (st) return (st);
-    memcpy_fromfs(&msf, (struct cdrom_mdf *) arg, sizeof msf);
-    play_from_to_msf(&msf);
+  case CDROMPLAYMSF: 
+    play_from_to_msf((struct cdrom_msf *) arg);
     return 0;
-  }
-  case CDROMPLAYTRKIND: {
-    struct cdrom_ti track_index;
-    int st;
-
-    st=verify_area(VERIFY_READ, (void *) arg, sizeof(track_index));
-    if (st) return (st);
-    memcpy_fromfs(&track_index, (struct cdrom_ti *) arg, sizeof(track_index));
-    play_from_to_track(track_index.cdti_trk0, track_index.cdti_trk1);
+  case CDROMPLAYTRKIND:		/* admittedly, not particulary beautiful */
+    play_from_to_track(((struct cdrom_ti *)arg)->cdti_trk0, 
+		       ((struct cdrom_ti *)arg)->cdti_trk1);
     return 0;
-  }
   case CDROMSTOP: 
     PAUSED=0;
     if (cd->dsb & dsb_play_in_progress) return type_0_command(c_stop, 1);
-    return 0;
+    else return 0;
   case CDROMPAUSE: 
+    get_drive_status();
     if (cd->dsb & dsb_play_in_progress) {
       type_0_command(c_stop, 1);
       type_1_command(c_audio_status, 5, cd->audio_status);
@@ -983,62 +916,181 @@
     if (PAUSED) play_from_to_track(0,0);
     PAUSED=0;
     return 0;
-  case CDROMEJECT:
-    PAUSED=0;
-    if (cd->openfiles == 1) {	/* Must do an open before an eject! */
-      type_0_command(c_open_tray,1);
-      memset(cd->toc, 0, sizeof(cd->toc));
-      memset(cd->disc_status, 0, sizeof(cd->disc_status));
-      return 0;
-    }
-    else return -EBUSY;
   case CDROMSTART:
   case CDROMVOLCTRL:
     return 0;
-  case CDROMSUBCHNL: {
-    struct cdrom_subchnl q;
-    int st;
-
-    st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(q));
-    if (st) return (st);
-    memcpy_fromfs(&q, (struct cdrom_subchnl *) arg, sizeof q);
-    if (get_current_q(&q)) {
-      memcpy_tofs((struct cdrom_subchnl *) arg, &q, sizeof q);
-      return 0;
-    }
-    else return -cmd;
-  }
-  case CDROM_GET_UPC: {
-    uch upc[10];
-    int st;
-
-    st=verify_area(VERIFY_WRITE, (void *) arg, 8);
-    if (st) return (st);
-    if (type_1_command(c_read_upc, 10, upc)) return -EIO;
-    memcpy_tofs((uch *) arg, &upc[1], 8);
-    return 0;
-  } 
+  case CDROMSUBCHNL: 
+    return get_current_q((struct cdrom_subchnl *)arg);
+  default:
+    return -EINVAL;
+  }
+}
+
+/* Ioctl. These ioctls are specific to the cm206 driver. I have made
+   some driver statistics accessible through ioctl calls.
+ */
+
+static int cm206_ioctl(dev_t dev, unsigned int cmd, unsigned long arg)
+{
+  switch (cmd) {
+#ifdef STATISTICS
+  case CM206CTL_GET_STAT:
+    if (arg >= NR_STATS) return -EINVAL;
+    else return cd->stats[arg];
+  case CM206CTL_GET_LAST_STAT:
+    if (arg >= NR_STATS) return -EINVAL;
+    else return cd->last_stat[arg];
+#endif    
   default:
     debug(("Unknown ioctl call 0x%x\n", cmd));
     return -EINVAL;
   }
 }     
 
-/* from lmscd.c */
-static struct file_operations cm206_fops = {
-	NULL,			/* lseek */
-	block_read,		/* read - general block-dev read */
-	block_write,		/* write - general block-dev write */
-	NULL,			/* readdir */
-	NULL,			/* select */
-	cm206_ioctl,		/* ioctl */
-	NULL,			/* mmap */
-	cm206_open,		/* open */
-	cm206_release,		/* release */
-	NULL,			/* fsync */
-	NULL,			/* fasync */
-	NULL,			/* media_change */
-	NULL			/* revalidate */
+int cm206_media_changed(dev_t dev) 
+{
+  if (cd != NULL) {
+    int r;
+    get_drive_status();		/* ensure cd->media_changed OK */
+    r = cd->media_changed;
+    cd->media_changed = 0;	/* clear bit */
+    return r;
+  }
+  else return -EIO;
+}
+
+/* The new generic cdrom support. Routines should be consice, most of
+   the logic should be in cdrom.c */
+
+/* returns number of times device is in use */
+int cm206_open_files(dev_t dev)	
+{
+  if (cd) return cd->openfiles;
+  return -1;
+}
+
+/* controls tray movement */
+int cm206_tray_move(dev_t dev, int position) 
+{
+  if (position) {		/* 1: eject */
+    type_0_command(c_open_tray,1);
+    invalidate_toc();
+  } 
+  else type_0_command(c_close_tray, 1);	/* 0: close */
+  return 0;
+}
+
+/* gives current state of the drive */
+int cm206_drive_status(dev_t dev)
+{
+  get_drive_status();
+  if (cd->dsb & dsb_tray_not_closed) return CDS_TRAY_OPEN;
+  if (!(cd->dsb & dsb_disc_present)) return CDS_NO_DISC; 
+  if (cd->dsb & dsb_drive_not_ready) return CDS_DRIVE_NOT_READY;
+  return CDS_DISC_OK;
+}
+ 
+/* gives current state of disc in drive */
+int cm206_disc_status(dev_t dev)
+{
+  uch xa;
+  get_drive_status();
+  if ((cd->dsb & dsb_not_useful) | !(cd->dsb & dsb_disc_present))
+    return CDS_NO_DISC;
+  get_disc_status();
+  if (DISC_STATUS & cds_all_audio) return CDS_AUDIO;
+  xa = DISC_STATUS >> 4;
+  switch (xa) {
+  case 0: return CDS_DATA_1;	/* can we detect CDS_DATA_2? */
+  case 1: return CDS_XA_2_1;	/* untested */
+  case 2: return CDS_XA_2_2;
+  }
+  return 0;
+}
+
+/* locks or unlocks door lock==1: lock; return 0 upon success */
+int cm206_lock_door(dev_t dev, int lock)
+{
+  uch command = (lock) ? c_lock_tray : c_unlock_tray;
+  type_0_command(command, 1);	/* wait and get dsb */
+  /* the logic calculates the success, 0 means successful */
+  return lock ^ ((cd->dsb & dsb_tray_locked) != 0);
+}
+  
+/* 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) 
+{
+  if (!FIRST_TRACK) get_disc_status();
+  if (mssp != NULL) {
+    if (DISC_STATUS & cds_multi_session) { /* multi-session */
+      mssp->addr.msf.frame = cd->disc_status[3];
+      mssp->addr.msf.second = cd->disc_status[4];
+      mssp->addr.msf.minute = cd->disc_status[5];
+      mssp->addr_format = CDROM_MSF;
+      mssp->xa_flag = 1;
+    } else {
+      mssp->xa_flag = 0;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+int cm206_get_upc(dev_t dev, struct cdrom_mcn * mcn)
+{
+  uch upc[10];
+  char * ret = mcn->medium_catalog_number;
+  int i;
+  
+  if (type_1_command(c_read_upc, 10, upc)) return -EIO;
+  for (i=0; i<13; i++) {
+    int w=i/2+1, r=i%2;
+    if (r) ret[i] = 0x30 | (upc[w] & 0x0f);
+    else ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f);
+  }
+  ret[13] = '\0';
+  return 0;
+} 
+
+int cm206_reset(dev_t dev)
+{
+  stop_read();
+  reset_cm260();
+  outw(dc_normal | dc_break | READ_AHEAD, r_data_control);
+  udelay(1000);			/* 750 musec minimum */
+  outw(dc_normal | READ_AHEAD, r_data_control);
+  cd->sector_last = -1;		/* flag no data buffered */
+  cd->adapter_last = -1;    
+  invalidate_toc();
+  return 0;
+}
+
+static struct cdrom_device_ops cm206_dops = {
+  cm206_open,			/* open */
+  cm206_release,		/* release */
+  cm206_open_files,		/* number of open_files */
+  cm206_drive_status,		/* drive status */
+  cm206_disc_status,		/* disc status */
+  cm206_media_changed,		/* media changed */
+  cm206_tray_move,		/* tray move */
+  cm206_lock_door,		/* lock door */
+  NULL,				/* select speed */
+  NULL,				/* select disc */
+  cm206_get_last_session,	/* get last session */
+  cm206_get_upc,		/* get universal product code */
+  cm206_reset,			/* hard reset */
+  cm206_audio_ioctl,		/* audio ioctl */
+  cm206_ioctl,			/* device-specific ioctl */
+  CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION |
+    CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */
+  0,				/* mask flags */
+  2.0,				/* maximum speed */
+  1,				/* number of minor devices */
+  1,				/* number of discs */
+  0,				/* options, ignored */
+  0				/* mc_flags, ignored */
 };
 
 /* This routine gets called during init if thing go wrong, can be used
@@ -1047,8 +1099,12 @@
 {
   switch (level) {
   case 4: 
+    if (unregister_cdrom(MAJOR_NR, "cm206")) {
+      printk("Can't unregister cdrom cm206\n");
+      return;
+    }
     if (unregister_blkdev(MAJOR_NR, "cm206")) {
-      printk("Can't unregister cm206\n");
+      printk("Can't unregister major cm206\n");
       return;
     }
   case 3: 
@@ -1074,25 +1130,16 @@
 int probe_base_port(int base)
 {
   int b=0x300, e=0x370;		/* this is the range of start addresses */
-  volatile int fool;
-#if 0
-  const pattern1=0x65, pattern2=0x1a;
-#endif
+  volatile int fool, i;
 
   if (base) b=e=base;
   for (base=b; base<=e; base += 0x10) {
     if (check_region(base, 0x10)) continue;
-    fool = inw(base+2);		/* empty possibly uart_receive_buffer */
+    for (i=0; i<3; i++) 
+      fool = inw(base+2); /* empty possibly uart_receive_buffer */
     if((inw(base+6) & 0xffef) != 0x0001 || /* line_status */
        (inw(base) & 0xad00) != 0) /* data status */
       continue;
-#if 0				/* writes... dangerous... */
-    outw(dc_normal | pattern1, base+8); 
-    if ((inw(base) & 0x7f) != pattern1) continue;
-    outw(dc_normal | pattern2, base+8);
-    if ((inw(base) & 0x7f) != pattern2) continue;
-    outw(dc_normal | READ_AHEAD, base+8);
-#endif
     return(base);
   }
   return 0;
@@ -1106,7 +1153,7 @@
   sti(); 
   irqs = probe_irq_on();
   reset_cm260();		/* causes interrupt */
-  udelay(10);			/* wait for it */
+  udelay(100);			/* wait for it */
   irq = probe_irq_off(irqs);
   outw(dc_normal | READ_AHEAD, r_data_control);	/* services interrupt */
   if (nr && irq!=nr && irq>0) return 0;	/* wrong interrupt happened */
@@ -1119,7 +1166,7 @@
   uch e=0;
   long int size=sizeof(struct cm206_struct);
 
-  printk(KERN_INFO "cm206: v" VERSION);
+  printk(KERN_INFO VERSION);
   cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
   if (!cm206_base) {
     printk(" can't find adapter!\n");
@@ -1162,11 +1209,16 @@
     return -EIO;
   }
   printk(".\n");
-  if (register_blkdev(MAJOR_NR, "cm206", &cm206_fops) != 0) {
+  if (register_blkdev(MAJOR_NR, "cm206", &cdrom_fops) != 0) {
     printk("Cannot register for major %d!\n", MAJOR_NR);
     cleanup(3);
     return -EIO;
   }
+  if (register_cdrom(MAJOR_NR, "cm206", &cm206_dops) != 0) {
+    printk("Cannot register for cdrom %d!\n", MAJOR_NR);
+    cleanup(3);
+    return -EIO;
+  }    
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
   read_ahead[MAJOR_NR] = 16;	/* reads ahead what? */
   init_bh(CM206_BH, cm206_bh);
@@ -1235,3 +1287,8 @@
   }
 }
 #endif /* MODULE */
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/include/linux -Wall -Wstrict-prototypes -O2 -m486 -c cm206.c -o cm206.o"
+ * End:
+ */
diff -u --recursive --new-file v1.3.100/linux/drivers/char/random.c linux/drivers/char/random.c
--- v1.3.100/linux/drivers/char/random.c	Sat May 11 10:42:05 1996
+++ linux/drivers/char/random.c	Sat May 11 10:08:34 1996
@@ -879,8 +879,8 @@
 		HASH_TRANSFORM(tmp, r->pool);
 
 		/*
-		 * In case the hash function has some recognizeable
-		 * output pattern, we fold it half.
+		 * In case the hash function has some recognizable
+		 * output pattern, we fold it in half.
 		 */
 		cp = (char *) tmp;
 		dp = cp + (HASH_BUFFER_SIZE*sizeof(__u32)) - 1;
diff -u --recursive --new-file v1.3.100/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v1.3.100/linux/drivers/char/rtc.c	Tue May  7 16:22:25 1996
+++ linux/drivers/char/rtc.c	Sat May 11 10:08:34 1996
@@ -762,7 +762,7 @@
  * ensure you actually start getting interrupts. Probably for
  * compatibility with older/broken chipset RTC implementations.
  * We also clear out any old irq data after an ioctl() that
- * meddles the interrupt enable/disable bits.
+ * meddles with the interrupt enable/disable bits.
  */
 void mask_rtc_irq_bit(unsigned char bit)
 {
diff -u --recursive --new-file v1.3.100/linux/drivers/net/hydra.c linux/drivers/net/hydra.c
--- v1.3.100/linux/drivers/net/hydra.c	Sat May 11 10:42:05 1996
+++ linux/drivers/net/hydra.c	Sat May 11 10:08:34 1996
@@ -7,8 +7,8 @@
 /* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)       */
 
 /* This file is subject to the terms and conditions of the GNU General      */
-/* Public License.  See the file README.legal in the main directory of the  */
-/* Linux/68k distribution for more details.                                 */
+/* Public License.  See the file COPYING in the main directory of the       */
+/* Linux distribution for more details.                                     */
 
 /* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a    */
 /* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM  */
@@ -100,9 +100,9 @@
 #endif
 
 
-/* this is now coherent to the C version below, */
-/* compile the source with -D__USE_ASM__ if you */
-/* want it - it'll only be some 10% faster thou */
+/* this is now coherent with the C version below, */
+/* compile the source with -D__USE_ASM__ if you   */
+/* want it - it'll only be some 10% faster though */
 
 #if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
 
diff -u --recursive --new-file v1.3.100/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.3.100/linux/drivers/net/lance.c	Fri Apr 12 15:51:56 1996
+++ linux/drivers/net/lance.c	Sun May 12 08:24:52 1996
@@ -165,6 +165,9 @@
  *	- added support for Linux/Alpha, but removed most of it, because
  *        it worked only for the PCI chip. 
  *      - added hook for the 32bit lance driver
+ *
+ *	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
+ *	- hopefully fix above so Linux/Alpha can use ISA cards too.
  */
 
 /* Set the number of Tx and Rx buffers, using Log_2(# buffers).
@@ -298,9 +301,7 @@
 
 int lance_init(void)
 {
-#ifndef __alpha__    
 	int *port;
-#endif    
 
 	if (high_memory <= 16*1024*1024)
 		lance_need_isa_bounce_buffers = 0;
@@ -344,8 +345,6 @@
 	}
 #endif  /* defined(CONFIG_PCI) */
 
-/* On the Alpha don't look for PCnet chips on the ISA bus */
-#ifndef __alpha__
 	for (port = lance_portlist; *port; port++) {
 		int ioaddr = *port;
 
@@ -359,8 +358,6 @@
 				lance_probe1(ioaddr);
 		}
 	}
-#endif
-
 	return 0;
 }
 
@@ -376,15 +373,14 @@
 	int hp_builtin = 0;					/* HP on-board ethernet. */
 	static int did_version = 0;			/* Already printed version info. */
 
-#ifndef __alpha__
 	/* First we look for special cases.
 	   Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
 	   There are two HP versions, check the BIOS for the configuration port.
 	   This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com.
 	   */
-	if ( *((unsigned short *) 0x000f0102) == 0x5048)  {
+	if (readw(0x000f0102) == 0x5048)  {
 		static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360};
-		int hp_port = ( *((unsigned char *) 0x000f00f1) & 1)  ? 0x499 : 0x99;
+		int hp_port = (readl(0x000f00f1) & 1)  ? 0x499 : 0x99;
 		/* We can have boards other than the built-in!  Verify this is on-board. */
 		if ((inb(hp_port) & 0xc0) == 0x80
 			&& ioaddr_table[inb(hp_port) & 3] == ioaddr)
@@ -393,7 +389,6 @@
 	/* We also recognize the HP Vectra on-board here, but check below. */
 	hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00
 				&& inb(ioaddr+2) == 0x09);
-#endif
 
 	/* Reset the LANCE.	 */
 	reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */
diff -u --recursive --new-file v1.3.100/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v1.3.100/linux/fs/affs/inode.c	Tue May  7 16:22:35 1996
+++ linux/fs/affs/inode.c	Sat May 11 10:08:34 1996
@@ -308,7 +308,7 @@
 	s->u.affs_sb.s_partition_size = size;
 	s->u.affs_sb.s_reserved       = reserved;
 
-	/* Try to find root block. It's location may depend on the block size. */
+	/* Try to find root block. Its location may depend on the block size. */
 
 	s->u.affs_sb.s_hashsize = 0;
 	if (blocksize > 0) {
diff -u --recursive --new-file v1.3.100/linux/include/linux/cm206.h linux/include/linux/cm206.h
--- v1.3.100/linux/include/linux/cm206.h	Fri Apr 12 15:52:07 1996
+++ linux/include/linux/cm206.h	Sun May 12 08:13:07 1996
@@ -2,6 +2,9 @@
    Copyright (c) 1995 David van Leeuwen 
 */
 
+#ifndef LINUX_CM206_H
+#define LINUX_CM206_H
+
 /* First, the cm260 stuff */
 /* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined
    below, the values are not used unless autoprobing is turned off and 
@@ -48,11 +51,12 @@
 #define dc_mask_transmit_ready 0x100
 #define dc_flag_enable 0x80
 
+/* Define the default data control register flags here */
 #define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \
 		   dc_mask_transmit_ready)
 
 /* now some constants related to the cm206 */
-/* another drive status byte, echoed by the cm206 on most commands */
+/* another drive status byte, echoed by the cm206 on most commmands */
 
 #define dsb_error_condition 0x1
 #define dsb_play_in_progress 0x4
@@ -126,3 +130,46 @@
 
 #define CM206CTL_GET_STAT 0x2000
 #define CM206CTL_GET_LAST_STAT 0x2001
+
+/* for kernel 1.2.n */
+#if !defined(CDROM_GET_UPC)
+#define CDROM_GET_UPC 0x5311
+#define CDROMRESET 0x5312
+#endif
+
+#ifdef STATISTICS
+
+/* This is an ugly way to guarantee that the names of the statistics
+ * are the same in the code and in the diagnostics program.  */
+
+#ifdef __KERNEL__
+#define x(a) st_ ## a
+#define y enum
+#else
+#define x(a) #a
+#define y char * stats_name[] = 
+#endif
+
+y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error),
+     x(crc_error), x(sync_error), x(lost_intr), x(echo),
+     x(write_timeout), x(receive_timeout), x(read_timeout),
+     x(dsb_timeout), x(stop_0xff), x(back_read_timeout),
+     x(sector_transferred), x(read_restarted), x(read_background),
+     x(bh), x(open), x(ioctl_multisession), x(attention)
+#ifdef __KERNEL__
+     , x(last_entry)
+#endif
+ };
+
+#ifdef __KERNEL__
+#define NR_STATS st_last_entry
+#else
+#define NR_STATS (sizeof(stats_name)/sizeof(char*))
+#endif
+
+#undef y
+#undef x
+
+#endif STATISTICS
+
+#endif LINUX_CM206_H
diff -u --recursive --new-file v1.3.100/linux/include/linux/kerneld.h linux/include/linux/kerneld.h
--- v1.3.100/linux/include/linux/kerneld.h	Sat May 11 10:42:07 1996
+++ linux/include/linux/kerneld.h	Sat May 11 10:35:04 1996
@@ -12,7 +12,7 @@
 
 /*
  * Uncomment the following line for the new kerneld protocol
- * This includes the pid of the kernel level requestor into the kerneld header
+ * This includes the pid of the kernel level requester into the kerneld header
  */
 /*
 #define NEW_KERNELD_PROTOCOL
diff -u --recursive --new-file v1.3.100/linux/include/linux/stats206.h linux/include/linux/stats206.h
--- v1.3.100/linux/include/linux/stats206.h	Sat Jul  1 19:06:00 1995
+++ linux/include/linux/stats206.h	Thu Jan  1 02:00:00 1970
@@ -1,34 +0,0 @@
-/* stats206.h. Define constants to gather statistics on the cm206 behavior.
-   Copyright (c) 1995 David van Leeuwen.
-   
-   This is published under the Gnu Public Licence, read the header in 
-   the file cm206.c.
-*/
-
-/* This is an ugly way to guarantee that the names of the statistics
- * are the same in the code and in the diagnostics program.  */
-
-#ifdef __KERNEL__
-#define x(a) st_ ## a
-#define y enum
-#else
-#define x(a) #a
-#define y char * stats_name[] = 
-#endif
-
-y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error),
-     x(crc_error), x(sync_error), x(lost_intr), x(echo),
-     x(write_timeout), x(receive_timeout), x(read_timeout),
-     x(dsb_timeout), x(stop_0xff), x(back_read_timeout),
-     x(sector_transferred), x(read_restarted), x(read_background),
-     x(bh), x(open), x(ioctl_multisession)
-#ifdef __KERNEL__
-     , x(last_entry)
-#endif
- };
-
-#ifdef __KERNEL__
-#define NR_STATS st_last_entry
-#else
-#define NR_STATS sizeof(stats_name)/sizeof(char*)
-#endif
diff -u --recursive --new-file v1.3.100/linux/include/linux/ucdrom.h linux/include/linux/ucdrom.h
--- v1.3.100/linux/include/linux/ucdrom.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/ucdrom.h	Sun May 12 08:13:08 1996
@@ -0,0 +1,92 @@
+/* ucdrom.h. Uniform cdrom data structures for cdrom.c. 	-*- linux-c -*-
+   Copyright (c) 1996 David van Leeuwen. 
+ */
+
+#ifndef LINUX_UCDROM_H
+#define LINUX_UCDROM_H
+
+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 */
+/* specifications */
+	const int capability;           /* capability flags */
+	int mask;                       /* mask of capability: disables them */
+	const float speed;              /* maximum speed for reading data */
+	const int minors;               /* number of minor devs supported */
+	const int capacity;             /* number of discs in jukebox */
+/* device-related storage */
+	int options;                    /* options flags */
+	long mc_flags;                  /* media change buffer flags (2*16) */
+};
+
+/* capability flags */
+#define CDC_CLOSE_TRAY	0x1             /* caddy systems _can't_ close */
+#define CDC_OPEN_TRAY	0x2             /* but _can_ eject.  */
+#define CDC_LOCK	0x4             /* disable manual eject */
+#define CDC_SELECT_SPEED 0x8            /* programmable speed */
+#define CDC_SELECT_DISC	0x10            /* select disc from juke-box */
+#define CDC_MULTI_SESSION 0x20          /* read sessions>1 */
+#define CDC_MCN		0x40            /* Medium Catalog Number */
+#define CDC_MEDIA_CHANGED 0x80          /* media changed */
+#define CDC_PLAY_AUDIO	0x100           /* audio functions */
+
+/* drive status possibilities */
+#define CDS_NO_INFO	0               /* if not implemented */
+#define CDS_NO_DISC	1
+#define CDS_TRAY_OPEN	2
+#define CDS_DRIVE_NOT_READY	3
+#define CDS_DISC_OK	4
+
+/* disc status possibilities, other than CDS_NO_DISC */
+#define CDS_AUDIO	100
+#define CDS_DATA_1	101
+#define CDS_DATA_2	102
+#define CDS_XA_2_1	103
+#define CDS_XA_2_2	104
+
+/* User-configurable behavior options */
+#define CDO_AUTO_CLOSE	0x1             /* close tray on first open() */
+#define CDO_AUTO_EJECT	0x2             /* open tray on last release() */
+#define CDO_USE_FFLAGS	0x4             /* use O_NONBLOCK information on open */
+#define CDO_LOCK	0x8             /* lock tray on open files */
+#define CDO_CHECK_TYPE	0x10            /* check type on open for data */
+
+/* Some more ioctls to control these options */
+#define CDROM_SET_OPTIONS	0x5320
+#define CDROM_CLEAR_OPTIONS	0x5321
+#define CDROM_SELECT_SPEED	0x5322  /* head-speed */
+#define CDROM_SELECT_DISC	0x5323  /* for juke-boxes */
+#define CDROM_MEDIA_CHANGED	0x5325
+#define CDROM_DRIVE_STATUS	0x5326  /* tray position, etc. */
+#define CDROM_DISC_STATUS	0x5327  /* disc type etc. */
+
+/* Rename and old ioctl */
+#define CDROM_GET_MCN	CDROM_GET_UPC	/* medium catalog number */
+
+/* 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	/* LINUX_UCDROM_H */
+/*
+ * Local variables:
+ * comment-column: 40
+ * End:
+ */
diff -u --recursive --new-file v1.3.100/linux/include/net/tcp.h linux/include/net/tcp.h
--- v1.3.100/linux/include/net/tcp.h	Tue May  7 16:22:40 1996
+++ linux/include/net/tcp.h	Sun May 12 09:15:33 1996
@@ -211,13 +211,15 @@
 static __inline__ unsigned short tcp_select_window(struct sock *sk)
 {
 	int window = tcp_new_window(sk);
+	int oldwin = tcp_old_window(sk);
 
 	/* Don't allow a shrinking window */
-	if (window > tcp_old_window(sk)) {
+	if (window > oldwin) {
 		sk->window = window;
 		sk->lastwin_seq = sk->acked_seq;
+		oldwin = window;
 	}
-	return sk->window;
+	return oldwin;
 }
 
 /*
diff -u --recursive --new-file v1.3.100/linux/ipc/msg.c linux/ipc/msg.c
--- v1.3.100/linux/ipc/msg.c	Sat May 11 10:42:07 1996
+++ linux/ipc/msg.c	Sat May 11 10:08:34 1996
@@ -49,7 +49,7 @@
 
 /*
  * If the send queue is full, try to free any old messages.
- * These are most probably unwanted, since noone has picked them up...
+ * These are most probably unwanted, since no one has picked them up...
  */
 #define MSG_FLUSH_TIME 10 /* seconds */
 static void flush_msg(struct msqid_ds *msq)
diff -u --recursive --new-file v1.3.100/linux/net/Changes linux/net/Changes
--- v1.3.100/linux/net/Changes	Tue May  7 16:22:40 1996
+++ linux/net/Changes	Sat May 11 10:08:34 1996
@@ -437,7 +437,7 @@
 10.	Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board
 driver but that's for an internal project and its general release is still
 a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
-Mike McLagan][Friz Elfert is doing the isdn4linux kit].
+Mike McLagan][Fritz Elfert is doing the isdn4linux kit].
  
 11.	IP over SCSI.
 
diff -u --recursive --new-file v1.3.100/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.100/linux/net/ipv4/arp.c	Sat May 11 10:42:07 1996
+++ linux/net/ipv4/arp.c	Sat May 11 10:08:35 1996
@@ -788,9 +788,9 @@
 }
 
 /*
- *	Check if there are too old entries and remove them. If the ATF_PERM
- *	flag is set, they are always left in the arp cache (permanent entry).
- *      If an entry was not be confirmed  for ARP_CONFIRM_INTERVAL,
+ *	Check if there are entries that are too old and remove them. If the
+ *	ATF_PERM flag is set, they are always left in the arp cache (permanent
+ *      entries). If an entry was not confirmed for ARP_CONFIRM_INTERVAL,
  *	send point-to-point ARP request.
  *	If it will not be confirmed for ARP_CONFIRM_TIMEOUT,
  *	give it to shred by arp_expire_entry.
@@ -1390,7 +1390,7 @@
 		}
 
 		/*
-		 *	A request was already send, but no reply yet. Thus
+		 *	A request was already sent, but no reply yet. Thus
 		 *	queue the packet with the previous attempt
 		 */
 			
diff -u --recursive --new-file v1.3.100/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v1.3.100/linux/net/ipv4/tcp_input.c	Tue May  7 16:22:42 1996
+++ linux/net/ipv4/tcp_input.c	Sat May 11 11:14:11 1996
@@ -195,7 +195,7 @@
  
 extern __inline__ int tcp_sequence(struct sock *sk, u32 seq, u32 end_seq)
 {
-	u32 end_window = sk->acked_seq + sk->window;
+	u32 end_window = sk->lastwin_seq + sk->window;
 	return	/* if start is at end of window, end must be too (zero window) */
 		(seq == end_window && seq == end_seq) ||
 		/* if start is before end of window, check for interest */
