diff options
Diffstat (limited to 'Documentation/cdrom/cdrom-standard.tex')
-rw-r--r-- | Documentation/cdrom/cdrom-standard.tex | 971 |
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} + |