patch-pre2.0.1 linux/Documentation/cdrom/cdrom-standard.tex

Next file: linux/Documentation/cdrom/cm206
Previous file: linux/Documentation/Configure.help
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.100/linux/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
@@ -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}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this