summaryrefslogtreecommitdiffstats
path: root/Documentation/cdrom/cdrom-standard.tex
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /Documentation/cdrom/cdrom-standard.tex
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'Documentation/cdrom/cdrom-standard.tex')
-rw-r--r--Documentation/cdrom/cdrom-standard.tex971
1 files changed, 971 insertions, 0 deletions
diff --git a/Documentation/cdrom/cdrom-standard.tex b/Documentation/cdrom/cdrom-standard.tex
new file mode 100644
index 000000000..ba95b97ff
--- /dev/null
+++ b/Documentation/cdrom/cdrom-standard.tex
@@ -0,0 +1,971 @@
+\documentclass{article}
+\def\version{$Id: cdrom-standard.tex,v 1.2 1996/09/22 20:18:00 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\cdromh{{\tt cdrom.h}}
+\def\ucdrom{{\tt ucdrom.h}}
+\def\fo{\sl}
+
+\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 (source code examples).
+\end{itemize}
+The vast choice and openness has lead not only to a wide support of
+hardware devices, but also to a certain divergence in behavior.
+Especially for \cdrom\ devices, the way a particular drive reacts to a
+`standard' $ioctl()$ call varies a lot from one brand to another;
+however, the \linux\ \cdrom\ driver writers kept away from wilderness
+by the practice of evolving a new driver by copying, understanding and
+changing an existing one.
+
+Since the beginning of the \cdrom, many different interfaces
+developed. Some of them had their own proprietary design (Sony,
+Mitsumi, Panasonic, Philips), other manufacturers adopted an existing
+electrical interface and changed the functionality
+(CreativeLabs/SoundBlaster, Teac, Funai) or simply adapted their
+drives to one or more of the already existing electrical interfaces
+(Aztech, Sanyo, Funai, Vertos, Longshine, Optics Storage and most of
+the `NoName' manufacturers). In cases where a new drive really
+brought his own interface or used his own command set and flow control
+scheme, either a separate driver had to be written, or an existing
+driver had to get enhanced.
+
+Nowadays, almost all new \cdrom\ types are either ATAPI/IDE or SCSI;
+it is very unlikely that any manufacturer still will create a new
+interface, and new drives for the existing proprietary interfaces are
+getting rare. But history has delivered us \cdrom\ support for many
+different interfaces.
+
+When (in the 1.3.70's) I looked at the existing interface which is
+expressed through \cdromh\ it appeared to be a rather wild set of
+commands and data formats.\footnote{I cannot recollect what kernel
+ version I looked at, then, presumably 1.2.13 and 1.3.34---the latest
+ kernel that I was indirectly involved in.} It seemed that many
+features of the interface have been added to include certain specific
+capabilities of certain drives, in an {\fo ad hoc\/} manner. More
+importantly, it appeared that 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, while
+others do 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.
+
+I decided to start a discussion on how to improve uniformity,
+addressing all \cdrom-driver developers found in the various driver
+files. The reactions encouraged me to write a uniform (compatible)
+software level \cdromc\ to which this document is the documentation.
+In the mean time, the data structure definitions in \cdromh\ had been
+cleaned up a lot---which was very helpful for the new code.
+
+\begin{quote}
+\small
+[Apparently, not all \cdrom\ developers support this initiative.
+They---mainly those who used the already existing drivers not only as
+a coding example, but also as a `user interface' reference during
+their own development---have taken care that \cdromh\ reflects a
+software interface to `user programs' which is unique between all
+drivers as much as possible; these driver writers will continue to
+refine the existing \cdromh\ where it seems necessary, and they tend
+to look if any newly requested functionality isn't already there
+before they are ready to define new structures. The {\tt sbpcd} driver
+gives an example that it is possible to let a robot arm play juke
+box---either with audio or with data CDs---and that it is possible to
+let the juke box work on even if a disk has fallen upon the floor and
+the drive door has closed without having a disk inside; without any
+new software layer or any structures which are not already present in
+\cdromh. This `other' group of \linux\ \cdrom\ driver writers
+explicitly does {\em not\/} support the idea to define an additional
+software layer between driver and user program.]\parfillskip=0pt
+\end{quote}
+
+The effort (\cdromc) of which this is the documentation is {\em not\/}
+meant to drive a wedge between two groups of driver developers, but
+rather to enable sharing of `strategic code' among drivers. The code
+should {\em not\/} be viewed as a new interface to user-level
+programs, but rather as a new interface between driver code and
+kernel.
+
+Care is taken that 100\,\% compatibility exists with the data
+structures and programmer's interface defined in \cdromh, and in order
+not to interfere with ongoing development in \cdromh, any `new' data
+structures have been put in a separate header file called \ucdrom.
+Because the data structures of \cdromh\ are fully supported, this
+documentation may also be of help to the programmers using the
+interface defined in \cdromh, but this guide is primarily written to
+help \cdrom\ driver developers adapt their code to use the `common
+\cdrom' code in \cdromc.
+
+Personally, I think that the most important hardware 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. It is
+important that these drives behave in the same way. (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 was conceived, 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. Note that we
+do not wish to alter the existing application interface defined in
+\cdromh, but rather want to re-root the hardware-implementation through
+some common code.
+
+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. The interfacing with
+\cdromc\ is implemented trough two general structures, that contain
+information about the capabilities of the driver, and the specific
+drives on which the driver operates. The structures are seperated to
+contain information about
+\begin{description}
+\item[the low-level driver] It lists the routines that actually
+ implement cdrom operations, and hence the structure is called
+ $cdrom_device_ops$. The structure is conceptually connected to the
+ major number of the device (although some drivers may have have
+ different major numbers, as is the case for the IDE driver).
+\item[the specific drive] It lists the variables informative of the
+ drive that is driven, and hence the structure is called
+ $cdrom_device_info$. The structure is conceptually connected to the
+ minor number of the device.
+\end{description}
+
+The registration is done for each drive found by the driver (and hence
+for each minor number) though the call
+$$register_cdrom(kdev_t\ dev, char * name,
+ struct\ cdrom_device_info\ <device>_info)
+$$
+This device information structure (described shortly) contains all
+information needed for the kernel to interface with the low-level
+cdrom device driver. One of the main entries of this structure is a
+pointer to the $cdrom_device_ops$ structure of the driver.
+
+This device operations structure lists the implemented routines for
+interfacing to the hardware. [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)(struct\ cdrom_device_info *, int)\cr
+ &void& (* release)(struct\ cdrom_device_info *);\cr
+ &int& (* drive_status)(struct\ cdrom_device_info *);\cr
+ &int& (* disc_status)(struct\ cdrom_device_info *);\cr
+ &int& (* media_changed)(struct\ cdrom_device_info *, int);\cr
+ &int& (* tray_move)(struct\ cdrom_device_info *, int);\cr
+ &int& (* lock_door)(struct\ cdrom_device_info *, int);\cr
+ &int& (* select_speed)(struct\ cdrom_device_info *, int);\cr
+ &int& (* select_disc)(struct\ cdrom_device_info *, int);\cr
+ &int& (* get_last_session) (struct\ cdrom_device_info *, struct\ cdrom_multisession *{});\cr
+ &int& (* get_mcn)(struct\ cdrom_device_info *, struct\ cdrom_mcn *{});\cr
+ &int& (* reset)(struct\ cdrom_device_info *);\cr
+ &int& (* audio_ioctl)(struct\ cdrom_device_info *, unsigned\ int, void *{});\cr
+ &int& (* dev_ioctl)(struct\ cdrom_device_info *, unsigned\ int, unsigned\ long);\cr
+\noalign{\medskip}
+ &\llap{const\ }int& capability;& capability flags \cr
+ &int& n_minors;& number of supported minor devices \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 value $n_minors$ should be a positive
+value indicating the number of minor devices that are supported by the
+driver, normally~1. Although these two variables are `informative'
+rather than `operational,' they are included in $cdrom_device_ops$
+because they describe the cabability of the {\em driver\/} rather than
+the {\em drive}. Nomenclature has always been difficult in computer
+programming.
+
+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.) This will be available through $dev$
+in $cdrom_device_info$ described below.
+
+The drive-specific, minor-like information that is registered to
+\cdromc, contains the following fields:
+$$
+\halign{$#$\ \hfil&$#$\ \hfil&\hbox to 10em{$#$\hss}&
+ $/*$ \rm# $*/$\hfil\cr
+struct& cdrom_device_info\ \{ \hidewidth\cr
+ & \llap{$const\ $}struct\ cdrom_device_ops *& ops;& device operations for this major\cr
+ & struct\ cdrom_device_info *& next;& next device_info for this major\cr
+ & void *& handle;& driver-dependent data\cr
+\noalign{\medskip}
+ & \llap{$const\ $}kdev_t& dev;& device number (incorporates minor)/\cr
+ & int& mask;& mask of capability: disables them \cr
+ &\llap{$const\ $}int& speed;& maximum speed for reading data \cr
+ &\llap{$const\ $}int& n_discs;& number of discs in jukebox \cr
+\noalign{\medskip}
+ &int& options : 30;& options flags \cr
+ &long& mc_flags : 2;& media-change buffer flags \cr
+ & int& use_count;& number of times devices is opened\cr
+\}\cr
+}$$
+
+With this $struct$, a linked list of minor devices registrered with
+the same low-level driver is built, though the field $next$. The
+device number, the device operations struct and specifications of
+properties of the drive are stored in this structure.
+
+The flags $mask$ can be used to mask out some of the capabilities
+listed in $ops\to capability$, if a specific drive doesn't support a
+feature of the driver. The value $speed$ specifies the maximum
+head-rate of the drive, measured in units of normal audio speed
+(176\,kB/sec raw data or 150\,kB/sec filesystem data). The value
+$n_discs$ should reflect the number of discs the drive can hold
+simultaneously, if it is designed as a juke-box, or otherwise~1.
+The parameters are declared $const$ because they describe properties
+of the drive, which don't change after registration.
+
+A few registers contain variables local to the \cdrom\ drive. 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.
+Other data that is specific to minor drive, can be accessed through
+$handle$, which can point to a data structure specific to the
+low-level driver. The fields $use_count$, $next$, $options$ and
+$mc_flags$ need not be initialized.
+
+The intermediate software layer that \cdromc\ forms will performs some
+additional bookkeeping. The use count of the device (the number of
+processes that have the device opened) is registered in $use_count$.
+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. Two functions {\em must\/} be implemented, namely
+$open()$ and $release()$. 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(struct\ cdrom_device_info * cdi, 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 case the driver supports modules, the call $MOD_INC_USE_COUNT$
+should be performed exactly once, if the $open()$ was 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(struct\ cdrom_device_info * cdi)$}
+
+In case of module support, 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{$Drive_status(struct\ cdrom_device_info * cdi)$}
+\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
+}
+$$
+%For a juke-box, the second argument $drive_nr$ specifies information
+%is requested for another than the default disc ($drive_nr=0$),
+%possibly only a subset of the return values can be returned.
+
+\subsection{$Disc_status(struct\ cdrom_device_info * cdi)$}
+\label{disc status}
+
+As a complement to $drive_status()$, this function can provide the
+general \cdrom-routines with information about the current disc that
+is inserted in the drive represented by $cdi\to 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(struct\ cdrom_device_info * cdi, int disc_nr)$}
+
+This function is very similar to the original function in $struct\
+file_operations$. It returns 1 if the medium of the device $cdi\to
+dev$ has changed since the last call, and 0 otherwise. The parameter
+$disc_nr$ identifies a specific slot in a juke-box, it should be
+ignored for single-disc drives. 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(struct\ cdrom_device_info * cdi, 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(struct\ cdrom_device_info * cdi, 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(struct\ cdrom_device_info * cdi, 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(struct\ cdrom_device_info * cdi, int\ number)$}
+
+If the drive can store multiple discs (a juke-box) this function
+should perform disc selection. It should return the number of the
+selected disc on success, a negative value on error. Currently, only
+the IDE-cd driver supports such functionality.
+
+\subsection{$Get_last_session(struct\ cdrom_device_info * cdi, struct\
+ cdrom_multisession * ms_info)$}
+
+This function should implement the old corresponding $ioctl()$. For
+device $cdi->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(struct\ cdrom_device_info * cdi, 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(struct\ cdrom_device_info * cdi)$}
+
+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(struct\ cdrom_device_info * cdi, 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(struct\ cdrom_device_info * cdi, 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 be
+opposed). Once this question is resolved, this code 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 from
+accidentally tampering with the contents. The capability fags actually
+inform \cdromc\ on what the driver is capable of. If the drive found
+by the driver does not have the capability, is can be masked out by
+the $cdrom_device_info$ variable $mask$. For instance, the SCSI cdrom
+driver has implemeted the code for loading and ejecting cdrom's, and
+hence its corresponding flags in $capability$ will be set. But a SCSI
+cdrom drive might be a caddy system, which can't load the tray, and
+hence for this drive the $cdrom_device_info$ struct will have set
+the $CDC_CLOSE_TRAY$ bit in $mask$.
+
+In the file \cdromc\ you will encounter many constructions of the type
+$$\it
+if\ (cdo\rightarrow capability \mathrel\& \mathord{\sim} cdi\rightarrow mask
+ \mathrel{\&} CDC_<capability>) \ldots
+$$
+There is no $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 different users' wishes, hopefully
+independently of the ideas of the respective author who 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 through 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$ to indicate
+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
+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 it 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$ to indicate that a device is being opened
+for $ioctl$ commands 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 a 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(kdev_t\ dev, char * name, struct\
+cdrom_device_info\ * cdi)$}
+
+Similar to registering $cdrom_fops$ to the kernel, the device
+operations and information structures, as described in
+section~\ref{cdrom.c}, should be registered to the general \cdrom\
+interface:
+$$
+register_cdrom(dev, <name>, \&<device>_info);
+$$
+This function returns zero upon success, and non-zero upon
+failure. The structure $<device>_info$ should have a pointer the
+driver's $<device>_dops$, as in
+$$
+\vbox{\halign{&$#$\hfil\cr
+struct\ &cdrom_device_info\ <device>_info = \{\cr
+& <device>_dops;\cr
+&\ldots\cr
+\}\cr
+}}$$
+Note that a drivers has one static structure, $<device>_dops$, while
+it has as many structures $<device>_info$ as there are minor devices
+active. $Register_cdrom()$ builds a linked list from these.
+
+\subsection{$Int\ unregister_cdrom(struct\ cdrom_device_info * cdi)$}
+
+Unregistering device $cdi$ with minor number $MINOR(cdi\to dev)$
+removes the minor device from the list. If it was the last minor for
+the driver, this 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 can be identified by the underscores in their names.
+\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}
+
+\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, these 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 deals 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 Scott Snyder and Gerd
+Knorr, who were the first to implement this interface for SCSI and
+IDE-CD drivers and added many ideas for extension of the data
+structures relative to kernel~2.0. Further thanks to Thomas Quinot,
+Jon Tombs, Ken Pizzini, Eberhard M\"onkeberg and Andrew Kroll, the
+\linux\ \cdrom\ device driver developers who were kind enough to give
+suggestions and criticisms during the writing. Finally of course, I
+want to thank Linus Torvalds for making this possible in the first
+place.
+
+\vfill
+$\version$
+\eject
+\end{document}
+