\documentstyle{jarticle}
\def\version{$Id: cdrom-standard.tex,v 1.1 2001/01/21 05:48:43 mdk 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{\linux\ \cdrom\ 規格}
\author{David van Leeuwen 著\\{\normalsize\tt david@tm.tno.nl}\\
{\normalsize 山縣 敦 $\langle${\tt ayamagat@phys.metro-u.ac.jp}$\rangle$ 訳}}

\maketitle

\section{はじめに}

おそらく \linux\ は最も広範囲にわたる種類のハードウェア・デバイスをサ
ポートしている Unix 風オペレーティング・システムでしょう．その理由は，
\begin{itemize}
\item 広く普及した IBM PC アーキテクチャで使用できるハードウェア・デバ
イスが多い，
\item 誰もが Linux 用ドライバ(，例えばソース・コード)を書くことができ
るように，オペレーティング・システムが公開されている，
\end{itemize}
ということでしょう．
選択の幅が広く公開性があるので，多くのハードウェア・デバイスがサポート
されますが，動作において避けられない相違が生じます．特に \cdrom\ デバ
イスは，`標準の' $ioctl()$ コールに対する個々のドライブの反応の仕方が
ブランド毎に変わります; しかし \linux\ \cdrom\ ドライバの作者は，既存
ドライバのコピー，理解，変更を行って新しいドライバを発展させるという習
慣で，荒野を避けてきました．

\cdrom\ の初期のころから多くの異なったインターフェースが開発されました．
そのいくつか (Sony, Mitsumi, Panasonic, Philips) は独自の設計でした．
その他の製造業者 (CreativeLabs/SoundBlaster, Teac, Funai) は，既存のエ
レクトリカル・インターフェースを採用して機能を変更するか，(Aztech,
Sanyo, Funai, Vertos, Longshine, Optics Storage や `ノーブランド' 製造
業者のドライブは)ひとつもしくはそれ以上の既存のエレクトリカル・インター
フェースに適応しただけです．新しいドライブが本当に独自のインターフェー
スだったり，コマンド・セットやフロー制御設計を使用している場合には別々
のドライバが書かれるか既存のドライバが拡張されました．

今日ではほとんど全ての新しい \cdrom\ が ATAPI/IDE か SCSI 型です; どの
製造業者もなお新しいインターフェースを作るのはありそうになく，既存の独
自のインターフェース用の新しいドライブはまれになっています．しかし多く
の異なったインターフェースの \cdrom\ のサポートが伝えられています．

私が (バージョン 1.3.70 代に) \cdromh\ に表わされた既存のインターフェー
スを見た時，コマンドやデータ・フォーマットはやや乱れた集まりに思われま
した．\footnote{どのバージョンを見たのか思い出せませんが，おそらく 
1.2.13 と 1.3.34 です---それは間接的に熱中した最新のカーネルでした．}
インターフェースの機能の多くは {\fo ad hoc\/} なやり方で特定のドライブ
のある特別な能力を含むために加えられたようでした．より重要なのはコマン
ドの実行が実際に，異なるドライバの大部分に対して違うように見えることで
した: 例えば，トレイが開いている間に $open()$ コールがあると，あるドラ
イバはトレイを閉じ，他はそうしません．ファイル・システムに矛盾が生じな
いように，あるドライバはデバイスを開くとき蓋をロックしますが，他はソフ
トウェアでイジェクトできるようにそうしません．異なるドライブの能力が変
わるのは疑いもありませんが，ふたつのドライブが同じ能力を持つときでさえ，
ドライバの動作は異なるかも知れません．

さまざまなドライバ・ファイルで見つけられる全ての \cdrom-ドライバ開発者
に呼びかけるために，私はどのように統一性を向上させるか議論を始めようと
決心しました．統一された(互換性のある)ソフトウェア・レベルでの 
\cdromc\ を書くよう私を励ます反応がありました．これがその文書化です．
その間に \cdromh\ のデータ構造体の定義がたくさん仕上げられました---そ
れは新しいコードにとても役立ちました．
 
\begin{quote}
\small
[明らかに全ての \cdrom\ 開発者がこの発義を支持していません．全てのドラ
イバでできるかぎり唯一の `ユーザ・プログラム' のソフトウェア・インター
フェースが \cdromh\ によりもたらされることに，彼らは注目しました---主
に既存のドライバをコーディングの例として用いるだけでなく，開発中に `ユー
ザ・インターフェース' の参考にしました; これらのドライバの作者は，必要
と思われる既存の \cdromh\ を洗練させ続けるでしょうし，新しい構造体を定
義しようとする前に，ある新しい必要な機能がまだそこに存在していないか探
そうとする傾向にあります．ひとつの例が {\tt sbpcd} ドライバです．ロボッ
ト・アームで---オーディオや CD のデータを---ジューク・ボックスを再生さ
せたり，ディスクが床に落ちたりディスクが入っていないのにドライブの蓋が
閉じていてもジューク・ボックスを動作させることができます; 新しいソフト
ウェア層あるいは \cdromh\ にまだ存在しない構造体なしにです．\linux\
\cdrom\ ドライバの作者のこの `他の' グループはドライバとユーザ・プログ
ラム間のソフトウェア層を追加して定義するという考えをあからさまに支持
{\bf しません}．] \parfillskip=0pt
\end{quote}

文書化の成果 (\cdromc) にはドライバ開発者のふたつのグループ間にクサビ
を打ち込む意図は{\bf なく}，むしろドライバ間で `ストラテジック・コード' 
の共有を可能にすることにあります．このコードはユーザ・レベル・プログラ
ムの新しいインターフェースとしてでは{\bf なく}，むしろドライバ・コード
とカーネル間の新しいインターフェースとして見なされるべきです．

\cdromh\ で定義されたデータ構造体とプログラマのインターフェースに 
100\,\% の互換性があり，\cdromh\ の開発の進行を妨げるためではないこと
に注目してください．\ucdrom\ という別のヘッダ・ファイルに任意の `新し
い' データ構造体が置かれました．\ucdrom\ のデータ構造体は全てサポート
されるので，この文書はまた \cdromh\ で定義された構造体を使用するプログ
ラマに役立つかも知れません．しかしこのガイドは主にコードを \cdromc\ の 
`共通な \cdrom' コードに適応する \cdrom\ ドライバ開発者の助けになるよ
う書かれました．

最も重要なハードウェア・インターフェースは IDE/ATAPI ともちろん SCSI 
ドライブになると私は個人的に思っています．しかしハードウェアの価格が下
がり続けているので，一台以上の \cdrom\ ドライブ，おそらく混合型をお持
ちになるでしょう．これらのドライブが同じ方法で動作することが重要です．
(1994 年 12 月，最も安価な \cdrom\ ドライブのひとつは倍速の独自のドラ
イブ Philips cm206 でした．それ用の \linux\ ドライバを書くのに忙しかっ
たその月に，独自のドライブは旧式になり，IDE/ATAPI ドライブが標準となり
ました．執筆時点 (1996 年 4 月)で最も安価な倍速ドライブは IDE で，以前
の 5 分の 1 の価格です．現在は 8 倍速ドライブが入手できます．)

この文書でさまざまな $ioctl$ とそのドライバへの実装方法が定義されます．
(プレ・リリース版では提案でした．)

\section{もうひとつのソフトウェア・レベル経由の標準化}
\label{cdrom.c}

本文書執筆時点において全てのドライバは自身のルーチンで直接 $ioctl()$ 
コールを実装しています．$verify_area()$ を呼び忘れる危険や実装の相違の
恐れがあります．

そのために私たち\footnote{\cdrom-デバイス・ドライバ(，少なくともその一
部分)の作者がその考え方を支持する時に `私たち' を，個人的な意見として
は `私' を，文中で使います．}が提案するのはもうひとつのソフトウェア・
レベルを定義することです．それは実際のハードウェア実装から $ioctl()$ 
と $open()$ の実装を分離します．\cdromh\ で定義された既存のアプリケー
ション・インターフェースを変えようとは思っていないことに注意してくださ
い．むしろある共通のコードによってハードウェア実装を再定着させたいので
す．

\cdrom\ ドライブは，一組の{\bf \cdrom\ デバイス制御}
$<cdrom-device>_dops$ を定義するのに十分特別(すなわちフロッピーやハー
ド・ディスク・ドライブのような他のブロック型デバイスと異なっている)と
思っています．典型的なブロック型デバイス・ファイル制御
$<block-device>_fops$ と性質が違います．

特別なインターフェース・レベル・ルーチンは \cdromc\ ファイルに実装され
ます．低水準 \cdrom\ ドライバは以下の一般的な $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
}
$$
全ての動作中の \cdrom\ デバイスはこの{\bf 構造体}を共用します．上で宣
言されたルーチンは \cdromc\ に全て実装されます．ここで全ての \cdrom デ
バイス・ドライバの{\bf 動作}が定義され，それゆえ標準化されます．さまざ
まな型のハードウェアへのインターフェースの実装はまだ個々の \cdrom-デバ
イス・ドライバによってなされます．しかしこれらのルーチンは \cdrom\ (リ
ムーバブル・メディア) デバイスに典型的なある{\bf 能力}だけを実装します．

\cdrom\ デバイス・ドライバの登録は，もはや VFS へではなく，現在は 
\cdromc\ の一般的なルーチンになされるべきです．これは以下の呼出しでな
されます．
$$
register_cdrom(int\ major, char * name, 
  struct\ cdrom_device_ops\ device_options)
$$

デバイス制御構造体はハードウェアへのインターフェースのために実装された
ルーチンのリストです．[途方もない速さで追従する技術の発展のように，(将
来の) \cdrom\ ドライブの全ての能力の完全なリストを与えるのは不可能です．
将来はおそらく書き込み制御 (WORM デバイス) がとても普及するでしょう．] 
現在のリスト:
$$
\halign{$#$\ \hfil&$#$\ \hfil&\hbox to 10em{$#$\hss}&
  $/*$ \rm# $*/$\hfil\cr
struct& cdrom_device_ops\ \{ \hidewidth\cr
  &int& (* open)(kdev_t, int)\cr
  &void& (* release)(kdev_t);\cr 
  &int& (* open_files)(kdev_t);  \cr
  &int& (* drive_status)(kdev_t);\cr     
  &int& (* disc_status)(kdev_t);\cr      
  &int& (* media_changed)(kdev_t);\cr 
  &int& (* tray_move)(kdev_t, int);\cr
  &int& (* lock_door)(kdev_t, int);\cr
  &int& (* select_speed)(kdev_t, int);\cr
  &int& (* select_disc)(kdev_t, int);\cr
  &int& (* get_last_session) (kdev_t, struct\ cdrom_multisession *{});\cr
  &int& (* get_mcn)(kdev_t, struct\ cdrom_mcn *{});\cr
  &int& (* reset)(kdev_t);\cr
  &int& (* audio_ioctl)(kdev_t, unsigned\ int, void *{});\cr 
  &int& (* dev_ioctl)(kdev_t, unsigned\ int, unsigned\ long);\cr
\noalign{\medskip}
  &\llap{const\ }int& capability;& 能力フラグ \cr
  &int& mask;& 能力のマスク: 無効にします \cr
  &\llap{$const\ $}int& speed;& データの読み込みの最大速度 \cr
  &\llap{$const\ $}int& minors;& サポートされたマイナー・デバイス数 \cr
  &\llap{$const\ $}int& capacity;& ジュークボックス内のディスク数 \cr
\noalign{\medskip}
  &int& options;& オプション・フラグ \cr
  &long& mc_flags;& メディア-変更バッファ・フラグ ($2\times16$) \cr
\}\cr
}
$$
\cdrom-ドライバは単にこれら(のいくつか)の機能を実装すべきです．そして
グローバルな \cdrom\ ドライバへの機能を登録すべきです．それは仮想ファ
イル・システムとシステム $ioctl$ とのインターフェースをなします．
$capability$ フラグはデバイスの登録時にハードウェアの能力を指定します．
$mask$ フラグは(ひとつあるいはもうひとつの理由で)これらの能力のいくつ
かを無効にするのに使用できます．$minors$ の値はドライバのサポートする
マイナー・デバイス数を示す正値でなければなりません．通常 1 です．(それ
は 0 から昇順と仮定されます．) $capacity$ の値はドライブがジューク・ボッ
クスのように設計されているなら同時に所有するディスク数でなければなりま
せん．さもなければ 1 です．

ふたつのレジスタは \cdrom\ デバイスに局所的な変数を含みます．$options$ 
フラグは一般的な \cdrom\ ルーチンの動作の仕方を指定するのに使われます．
これらさまざまなフラグ・レジスタが異なるユーザの望みに適応するよう十分
柔軟性を与えるべきです．(旧式の設計の場合のように低水準デバイス・ドラ
イバの作者の `任意の' 望みでは{\bf ありません}．) $mc_flags$ レジスタ
は $media_changed()$ からふたつに分かれた待ち行列への情報のバッファに
使われます．

ほとんどの機能が $blkdev_fops$ に対応したパラメタの無いことに注意して
ください．これは構造体 $inode$ と $file$ でわずかな情報しか使われない
からです．主なパラメタは $dev$ デバイスです．マイナー番号はそこから引
き出すことができます．(ほとんどの低水準 \cdrom\ ドライバはデバイスがひ
とつだけサポートされているのでその値を調べません．)

\cdromc\ のなす中間のソフトウェア層はある追加のブックキーピングをなし
ます．デバイスのマイナー番号は $<device>_dops$ に登録された最大数に対
して検査されます．$cdrom_ioctl()$ 関数は読み込みと書き出しのための適当
なユーザ-メモリを照合するでしょう．CD 上の位置が転送される場合には，標
準フォーマットで低水準ドライバに要求し，ユーザ-ソフトウェアと低水準ド
ライバ間の全てのフォーマットを変換することにより，フォーマットを `衛生
的にする' でしょう．これはドライバ・メモリの照合，フォーマットの照合，
変換の多くを救援します．また必要な構造体はプログラム・スタックで宣言さ
れるでしょう．

関数の実装は以下の節で定義されるようにすべきです．$open()$，
$release()$，$open_files()$ の 3 つの関数を実装する{\bf 必要}がありま
す．他の関数は省略されてもよく，対応する能力のフラグは登録時に削除され
るでしょう．一般に，関数は成功時に 0，エラー時に負数を返します．ファン
クション・コールはコマンドが終了した後でだけ戻るべきです．しかしデバイ
スのために待つことはもちろんプロセッサ時間を使用すべきではありません．

\subsection{$Open(kdev_t\ dev, int\ purpose)$}

$open()$ は以下のどちらか特別な{\bf 目的}のためにデバイスを開こうとし
ます:
\begin{itemize}
\item[0] {\tt mount()} (2) あるいはユーザ・コマンド {\tt dd} や
{\tt cat} で使われるように，データを読み込むために開きます．
\item[1] 主にオーディオ-CD を再生するプログラムで使われるように，
$ioctl$ の実行のために開きます．
\end{itemize}
特定のデバイスを開くのに成功した回数を反映した静的なカウンタがこのルー
チンで更新されます．(ドライバがモジュールをサポートする場合，
$MOD_INC_USE_COUNT$ 呼出しは，成功したら正確に一度だけ実行されるべきで
す．) 戻り値はエラー時に負数，成功時に 0 です．ハードウェアが無いと，
open-for-ioctl コールは失敗するだけです．

($open()$ の実行時にトレイを閉じるなど)どんなストラテジック・コードも 
\cdromc\ のルーチンを呼び出してなされるべきです．ですから低水準ルーチ
ンは適当な初期化とデバイス使用回数とだけ関係すべきです．

\subsection{$Release(kdev_t\ dev)$}

$dev$ デバイスの使用回数が 1 だけ減ります．単独の $MOD_DEC_USE_COUNT$ 
呼出しがここでコードされるべきです．他のデバイスに特定な動作はおそらく
デバイスの回転を止めるようにすべきです．しかしながらトレイのイジェクト
や蓋のロックを外すような重要な動作は一般的なルーチン $cdrom_release()$ 
に残しておくべきです．また VFS におけるバッファ割当を無効にすることは 
\cdromc\ のルーチンで処理されます．

\subsection{$Open_files(kdev_t\ dev)$}

この関数は内部で変化する $dev$ デバイスの使用回数を返します．単一の低
水準ドライバに接続された多くのマイナー・デバイスがあるかも知れないので，
使用回数は \cdromc\ 自身のルーチンには実装されません．

\subsection{$Drive_status(kdev_t\ dev)$}
\label{drive status}

$drive_status$ 関数は，もし実装されるなら(ドライブにディスクがあるか無
いかという状態ではない)ドライブの状態の情報を提供します．\ucdrom\ にお
ける可能性のリスト:
$$
\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
CDS_NO_INFO& 情報が得られません\cr
CDS_NO_DISC& ディスクが挿入されていず，トレイは閉じています\cr
CDS_TRAY_OPEN& トレイが開いています\cr
CDS_DRIVE_NOT_READY& 何か誤っています，トレイが移動中かも知れません\cr
CDS_DISC_OK& ディスクが挿入され万事良好です\cr
}
$$

\subsection{$Disc_status(kdev_t\ dev)$}
\label{disc status}

$drive_status()$ を補足するために，この関数は，$dev$ で表示されるドラ
イブに挿入されている現在のディスクに関する情報をともなった一般的な 
\cdrom-ルーチンを提供できます．
$$
\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
CDS_NO_INFO& 情報が得られません\cr
CDS_NO_DISC& ディスクが挿入されていないかトレイが開いています\cr
CDS_AUDIO& オーディオ・ディスク (2352 オーディオ バイト/フレーム)\cr
CDS_DATA_1& データ・ディスク, モード 1 (2048 ユーザ バイト/フレーム)\cr
CDS_DATA_2& データ・ディスク, モード 2 (2336 ユーザ バイト/フレーム)\cr
CDS_XA_2_1& 混合データ (XA), モード 2, フォーム 1 (2048 ユーザ バイト)\cr
CDS_XA_2_2& 混合データ (XA), モード 2, フォーム 1 (2324 ユーザ バイト)\cr
}
$$
私の知る限り \cdrom\ は普通 $CDS_DATA_1$ 型です．さまざまなディスクの
型のフレーム・レイアウトを考慮したいくつかの情報に関しては最新版の
{\tt cdrom.h} を御覧ください．

\subsection{$Media_changed(dev\_t\ dev)$}

この関数は，元の $struct\ file_operations$ 関数にとてもよく似ています．
$dev$ デバイスのメディアが最後の呼出し以来変化したなら 1，さもなければ 
0 を返します．この関数を $cdrom_media_changed()$ を経由して `再定着' 
することにより，VFS とソフトウェアにデバイスの変更の報告を可能にする新
しい $ioctl()$ 関数(，例えばオート-マウント・デーモン)のために別々の待
ち行列を実装することができます．

\subsection{$Tray_move(kdev_t\ dev, int\ position)$}

この関数は実装されているならトレイの移動を制御します．(これを他の関数
で操作すべきでありません．) $position$ パラメタはお望みの以下の移動の
方向を制御します:
\begin{itemize}
\item[0] トレイを閉じます
\item[1] トレイを開けます
\end{itemize}
この関数は成功時に 0，エラー時に 0 でない値を返します．トレイがすでに
お望みの位置にありましたら，動作の必要が無く，戻り値が 0 であることに
注意してください．

\subsection{$Lock_door(kdev_t\ dev, int\ lock)$}

この(そして他のコードではない)関数は，ドライブが蓋のロックを許すならこ
れを制御します．$lock$ の値はお望みのロックの状態を制御します:
\begin{itemize}
\item[0] 蓋のロックを外し，手動で開けられます
\item[1] 蓋をロックし，トレイは手動でイジェクトできません
\end{itemize}
戻り値は $tray_move()$ に関係します．

\subsection{$Select_speed(kdev_t\ dev, int\ speed)$}

これまでどのドライバもこの関数を実装したことがありませんけれど，ヘッド
速度を選べるドライブもあります．それゆえこれはデバイス制御構造体の関数
を経由して標準化されるべき能力です．この関数はデータが読み込まれるかオー
ディオが再生される速度を選びます．特別な値 `0' は `自動選択' を意味し
ます．すなわち最大のデータ速度やリアルタイムの再生速度です．ドライブに
この `自動選択' 能力がないなら，決定は挿入された現在のディスクでなされ，
戻り値は正になります．負の戻り値はエラーを示します．(オーディオ-ロー-
パス・フィルターはおそらくそのためには設計されていませんけれど，オーディ
オのリアルタイム再生より大きい値がオーディオ・トラックの高速なコピーに
使われます．)誤ってプレスされた \cdrom\ は最大ヘッド速度より小さいこと
から利益を得るかも知れません．

\subsection{$Select_disc(kdev_t\ dev, int\ number)$}

ドライブが複数のディスクを格納できる(ジューク・ボックス)なら，ディスク
はソフトウェアで選べるのが好ましいです．この関数はディスク選択を実行し
ます．成功時に選択されたディスクの番号を，エラー時に負数を返します．現
在 \linux\ \cdrom\ ドライバはそのような機能をサポートしていないように
思われますが，将来のためにここで定義されます．

\subsection{$Get_last_session(kdev_t\ dev, struct\ cdrom_multisession *
ms_info)$}

この関数は対応する古い $ioctl()$ を実装します．$dev$ デバイスのために，
現在のディスクの最終セッションの開始がポインタ引数 $ms_info$ に返され
ます．\cdromc\ のルーチンがこの引数を衛生的にすることに注意してくださ
い: その要求されるフォーマットは呼び出すソフトウェアが何を要求しようと
も，`いつでも' (リニア・ブロック・アドレッシング・モードの)
$CDROM_LBA$ 型でしょう．しかしさらに衛生的にします: 低水準実装は，そう
望むなら(もちろん $ms_info\rightarrow addr_format$ フィールドを適切に
設定して)， $CDROM_MSF$ フォーマットに要求された情報を返すかも知れませ
ん．\cdromc\ のルーチンが，必要なら変換します．戻り値は成功時に 0 です．

\subsection{$Get_mcn(kdev_t\ dev, struct\ cdrom_mcn * mcn)$}

`メディア・カタログ番号' (MCN) または `ユニバーサル・プロダクト・コー
ド' (UPC) と呼ばれるものを持つディスクもあります．この番号は製品のバー
コードに一般に見られる番号を反映します．あいにく，ディスク上に番号のよ
うなものを持つわずかなディスクは同じフォーマットを使用しません．この関
数へ戻す引数は $struct\ cdrom_mcn$ 型のあらかじめ宣言されたメモリの範
囲へのポインタです．MCN は null 文字で終る 13 文字の文字列と期待されま
す．

\subsection{$Reset(kdev_t dev)$}

このコールはドライブのハード-リセットの実装です．(ハード-リセットが必
要な状況にあっても，最近はドライブがあまりコマンドに従わないかも知れま
せん．)むしろドライブのリセットが終了した後にだけ制御が呼出し側に戻さ
れます．

\subsection{$Audio_ioctl(kdev_t\ dev, unsigned\ int\ cmd, void *
arg)$}

{\tt cdrom.h} に定義された \cdrom-$ioctl$ のいくつかは上述したルーチン
で実装できます．それゆえ $cdrom_ioctl$ 関数はそれらを使うでしょう．し
かしながら，ほとんどの $ioctl$ はオーディオ制御を処理します．私たちは，
引数 $cmd$ と $arg$ を繰り返して，単一の関数経由でアクセスされるこれら
を残すことに決めました．後者が，$unsigned\ long\ int$ ではなく 
$void*{}$ 型であることに注意してください．けれども $cdrom_ioctl()$ ルー
チンはいくつか役に立つことをします．全てのオーディオ呼出しのために 
$CDROM_MSF$ (分，秒，フレーム) へのアドレス・フォーマット型を衛生的に
します．また，$arg$ のメモリの位置を照合し，その引数のためにスタック-
メモリを予約します．これは，旧式なドライバの設計におけるよりもはるかに
簡単に $audio_ioctl()$ を実装します．例として，この文書とともに更新さ
れるべき {\tt cm206.c} の $cm206_audio_ioctl()$ 関数を調べてもよいです．

実装されていない ioctl は $-EINVAL$ を返しますが，(例えば $CDROMSTART$ 
の)無害な要求は 0 (成功) を返して無視されるかも知れません．他のエラー
はなんであれ規格に従うべきです．(オーディオ-プレーヤー・ソフトウェアの
インターフェースの統一を保証するために，私たちは $cdrom_ioctl()$ の戻
り値を衛生的にすることを決めても構いません．)

\subsection{$Dev_ioctl(kdev_t\ dev, unsigned\ int\ cmd, unsigned\ long\
arg)$}

いくつかの $ioctl$ はある \cdrom\ ドライブに固有のようです．すなわちあ
るドライブのいくつかの能力を提供するために導入されました．実際，ある特
定の種類のフォーマット，あるいはオーディオ・データを読み込むための 6 
つの異なった $ioctl$ があります．多くのドライブはデータとしてオーディ
オ・トラックを読み込むことをサポートしていません．これはアーティストの
著作権保護のためだと私は思います．さらに，オーディオ・トラックがサポー
トされるなら，$ioctl$ でなく VFS 経由でなされるべきと私は考えます．こ
こでの問題はオーディオ-フレームが 2352 バイト長ですので，一度に( 512 
と 2352 の最小公倍数である) 75264 バイトをオーディオ-ファイル-システム
が要求するか，ドライバが(私の反対する)この矛盾を処理するために努力する
必要があります．この問題が解決すれば，このコードは \cdromc\ で標準化さ
れるでしょう．

多くの $ioctl$ があるためにあるドライバを満足するために導入されたよう
なので，\footnote{実際にこれらを使用するソフトウェアがまわりにあります
か．私は興味あります!}どの `規格にない' $ioctl$ も $dev_ioctl()$ コー
ルを経由します．原理的に `個人的な' $ioctl$ は，一般的な \cdrom\
$ioctl$ 番号 {\tt 0x53} ではなく，デバイスのメジャー番号にちなんで番号
を付けられるべきです．現在のサポートされていない $ioctl$:
{\it CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, CDROMREADRAW,
CDROMREADCOOKED, CDROMSEEK, CDROMPLAY\-BLK, CDROMREADALL}．

\subsection{\cdrom\ の能力}

いくつかの $ioctl$ コールをたんに実装する代わりに，\cdromc\ のインター
フェースは \cdrom\ ドライブの{\bf 能力}を示す可能性を与えます．これは
登録時に \ucdrom\ で定義される能力-定数の任意数の論理和をとることでな
されます．現在，能力は次のどれかです:
$$
\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
CDC_CLOSE_TRAY& ソフトウェア制御でトレイを閉じられます\cr
CDC_OPEN_TRAY& トレイを開けられます\cr
CDC_LOCK& 蓋のロックと解除ができます\cr
CDC_SELECT_SPEED& 約 150\,kB/s を単位として速度を選択できます\cr
CDC_SELECT_DISC& ドライブはジューク-ボックスです\cr
CDC_MULTI_SESSION& 複数のセッションを読み込めます\cr
CDC_MCN& メディア・カタログ番号を読み込めます\cr
CDC_MEDIA_CHANGED& ディスクが変更されたら報告できます\cr
CDC_PLAY_AUDIO& (再生，一時停止など)オーディオ機能を実行できます\cr
}
$$
能力フラグはドライバが内容を偶然に調整するのを防ぐために宣言された{\bf 
定数}です．しかしながら，登録時に，いくつかの(要求された)能力フラグは，
サポートしている関数が実装されていないなら，消去されるかも知れません．
(\cdromc\ の $register_cdrom()$ を御覧ください)

なにかの能力を無効にしたいなら，ある能力を(一時的に)無効にする特別な
$<device>_dops.mask$ フラグ・レジスタがあります．\cdromc\ ファイルで
$$
\it
if\ (cdo\rightarrow capability \mathrel\& \mathord{\sim} cdo\rightarrow mask 
   \mathrel{\&} CDC_<capability>) \ldots
$$
型のたくさんの構文に出会うでしょう．動作を実行できないデバイスの特定の
ブランドのために，ある能力を無効にする低水準ドライバ・コードで $mask$ 
は設定されます．しかしながら，mask を設定するための $ioctl$ は(まだ)あ
りません\dots その理由は，{\bf 能力}より{\bf 動作}を制御する方がよいと
私が考えるからです．

\subsection{オプション}

ドライブを偶然に \linux\ コミュニティで使用可能にした個々の作者の考え
とは願わくば独立に，異なるユーザの望みを満足させるために，最後のフラグ・
レジスタは \cdrom\ ドライブの{\bf 動作}を制御します．現在の動作のオプ
ション:
$$
\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
CDO_AUTO_CLOSE& デバイスの $open()$時にトレイを閉じようとします\cr
CDO_AUTO_EJECT& デバイスの最後の $close()$ 時にトレイを開こうとします\cr
CDO_USE_FFLAGS& $open()$ の目的を示すために $file_pointer\rightarrow
f_flags$ を使用します\cr
CDO_LOCK& デバイスが開かれたなら蓋をロックしようとします\cr
CDO_CHECK_TYPE& データのために開かれたならディスクの型がデータであるこ
とを確かめます\cr
}
$$

ユーザ・インターフェースとソフトウェアの規格における私自身の観点を反映
して，このレジスタの初期値は
$CDO_AUTO_CLOSE \mathrel| CDO_USE_FFLAGS \mathrel| CDO_LOCK$
です．抗議に先じて，動作をソフトウェアで制御するようにできる，ふたつの
新しい $ioctl$ が \cdromc\ に実装されています:
$$
\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
CDROM_SET_OPTIONS& $(int)\ arg$ で指定されたオプションに設定します\cr
CDROM_CLEAR_OPTIONS& $(int)\ arg$ で指定されたオプションを無効にします\cr
}
$$
$CDO_USE_FFLAGS$ オプションはいくらか説明が必要です．次節でこのオプショ
ンに必要なことを説明します．

\section{デバイスを開く目的を知る必要性}

伝統的に，デバイスの $ioctl()$ コールによる，デバイス・ファイルに対す
る読み込み/書き込み，あるいはコマンド制御を発する，ふたつの異なった `
モード' で Unix のデバイスは使われます．\cdrom\ ドライブにともなう問題
は，ふたつの完全に異なった目的に使われ得ることです．ひとつは \cdrom\ 
というリムーバブル・ファイル・システムをマウントすること，もうひとつは
オーディオ CD を再生することです．オーディオ・コマンドは，おそらく最初
の実装 (SUN?) がそうだったので，$ioctl$ を経由して完全に実装されていま
す．原理的にこれで悪いことは何もありません．しかし `CD プレーヤー' の
よい制御には，ドライブの状態にかかわらず $ioctl$ コマンドを与えるため
にデバイスを{\bf いつでも}開く必要があります．

一方( \cdrom\ のもともとの目的である)リムーバブル-メディア・ディスク・
ドライブのように使われる場合，ディスク・ドライブがデバイスを開く時に制
御する準備が整っているかを私たちは確かめたいのです．古い設計では，いく
つかの \cdrom\ ドライブは完全な検査をなにもしませんでした．空のドライ
ブで \cdrom\ をマウントしようとした時に，VFS によってカーネルに報告さ
れるたくさんの i/o エラーを残しました．これは \cdrom\ が挿入されていな
いことを見つけるための特に精密な方法ではありません; 多かれ少なかれ，旧
式の IBM-PC が数秒間，空のフロッピー・ドライブを読み込もうとすることに
似ています．システムがそれに不平を言った後は，それからは読み込むことが
できません．こんにち，ドライブにリムーバブル・メディアがあることは `感
知' できますし，その事実を利用すべきと私たちは信じます．\cdrom\ が利用
できることとその(データ)型が正しいことを照合する，デバイスを開くことに
関する完全な検査は望ましいことです．

これらふたつの \cdrom\ ドライブの使用法は，第一にデータ，第二にオーディ
オ・ディスクを再生するために $open()$ コールの動作に関して異なった要求
をします．オーディオの使用は $ioctl$ コマンドを発するのに必要とされる
ファイル・ハンドルを得るため，ただデバイスを開く必要があります．一方デー
タの使用は正しく信頼のおけるデータの転送のために開く必要があります．ユー
ザ・プログラムのデバイスを開く目的が何であるかを示すことができる唯一の
方法は{\bf フラグ}・パラメタを通してです．({\tt open(2)} を御覧くださ
い) \cdrom\ デバイスのためにこれらのフラグは実装されていません．(書き
込みに関係したフラグの検査を実装しているドライバもあります．しかしこれ
は，デバイス・ファイルがフラグを正しく許可するなら，確かに必要ありませ
ん．)ほとんどのオプション・フラグは \cdrom\ デバイスにまったく意味をな
しません: $O_CREAT$，$O_NOCTTY$，$O_TRUNC$，$O_APPEND$，$O_SYNC$ は 
\cdrom\ に意味はありません．

それゆえ，デバイスが $ioctl$ コマンドを発するためだけに開かれることを
示すのに，私たちは $O_NONBLOCK$ フラグの使用を提案します．$O_NONBLOCK$ 
の厳密な意味は，デバイスを開いてそれに続くデバイスへの呼出しが待機する
プロセスを呼び出すのを引き起こさないことです．``ある正しいデータ-
\cdrom\ を挿入するまで待機しないように'' とこれを解釈します．したがっ
て \cdrom\ に関する $open()$ コールの実装の提案は次の通りです:
\begin{itemize}
\item $O_RDONLY$ の他にフラグが設定されていないなら，デバイスはデータ
転送のために開かれ，転送の初期化が成功した場合だけ戻り値は 0 になりま
す．その呼出しは，トレイを閉じるようないくつかの \cdrom\ に対する動作
を生じさせても構いません．
\item $O_NONBLOCK$ オプション・フラグが設定されているなら，全デバイス
が存在しないということがない限り，開くことは常に成功します．ドライブは
全く動作しないでしょう．
\end{itemize}

\subsection{規格はいかがですか}

この提案がある標準化協会でなく \linux\ コミュニティからあったので，受
入れをためらうかも知れません．SUN, SGI, HP とその他すべての Unix，そし
てハードウェア・ベンダはいかがですか．ところでこれらの会社は，概して，
自社製品をサポートするハードウェアとソフトウェアの両方を管理し，独自の
規格を設定するのに十分大規模であるという，幸運な位置にあります．何十も
あるいはそれ以上のさまざまな競合するハードウェアの設定を扱う必要はない
のです．\footnote{\cdrom\ をマウントする SUN の取組み方はもともと大変
よいものと個人的に私は思っています: Solaris では，ボリューム-デーモン
が新たに挿入された \cdrom\ を {\tt /cdrom/$<volume-name>$/} に自動でマ
ウントします．私見では，これをさらに押し進めて，ローカル・エリア・ネッ
トワーク上{\bf すべての} \cdrom\ が同様な場所にマウントされるべきです．
すなわち \cdrom\ を挿入した特定の計算機に関係なく，全てのシステムのディ
レクトリ・ツリーの同じ場所にいつでも現れるのです．\linux\ のユーザ-プ
ログラムのように実装したい場合，私はさまざまなドライバの異なった動作と
メディアの交換に関する情報をもたらす $ioctl$ の必要性とに出会います．}

デバイスが $ioctl$ コマンドのためだけに開かれていることを示すために 
$O_NONBLOCK$ を使用することは，\linux\ コミュニティで容易に導入される
ことができると私たちは思います．CD-プレーヤーのすべての作者に，プログ
ラムに対する私たち独自のパッチを送ることができることを，お知らせする必
要があるでしょう．$O_NONBLOCK$ の使用は，\linux\ 以外の他のオペレーティ
ング・システム上の CD-プレーヤーの動作に影響を及ぼさないのが最も好まし
いことです．結局，ユーザは $ioctl(file_descriptor,
CDROM_CLEAR_OPTIONS, CDO_USE_FFLAGS)$ をコールして古い動作にいつでも戻
すことができます．

\subsection{好ましい $open()$ のストラテジ}

$CDROM_SET/CLEAR_OPTIONS$ $ioctl$ により，({\bf いかなる}型の) \cdrom\ 
デバイスの動作時設定がなされるように \cdromc\ のルーチンは設計されてい
ます．したがってさまざまな制御のモードが設定できます:
\begin{description}
\item[$CDO_AUTO_CLOSE \mathrel| CDO_USE_FFLAGS \mathrel| CDO_LOCK$] こ
れはデフォルトの設定です．(将来 $CDO_CHECK_TYPE$ をともなった方がよい
でしょう．) デバイスが何か他のプロセスによってまだ開かれていず，データ
のために開かれていて ($O_NONBLOCK$ は設定されてなく)，トレイが開いてい
ることが分かっているなら，トレイを閉じようとします．それから，ディスク
がドライブに入っていること，そして $CDO_CHECK_TYPE$ が設定されているな
らその型が `データ・モード 1' であることが照合されます．全てのテストに
合格した時のみ戻り値は 0 です．ファイル・システムが破壊しないよう蓋は
ロックされます．オーディオのために開かれ(，$O_NONBLOCK$ が設定され)て
いるなら動作せず，値 0 が返されます．
\item[0] $open()$ は常に成功するでしょう．オプション・フラグは無視され
ます．動作せず，完全な検査はなされません．
\item[$CDO_AUTO_CLOSE \mathrel| CDO_AUTO_EJECT \mathrel| CDO_LOCK$] こ
れは現在の sbpcd-ドライバの動作を最小にします．オプション・フラグは無
視され，必要ならトレイは最初に開いた時に閉じられます．同様に，トレイは
最後の解放時に開かれます．すなわち \cdrom\ がマウントされていないな
ら，ユーザが取り換えることができるように，自動的にイジェクトされます．
\end{description}
新しい \cdrom\ ドライブの設計とオプション・フラグの解釈にこれらのオプ
ションが適応するのを(ドライバを維持する方とユーザ・プログラムの開発者)
すべての方が納得できると私たちは思います．

\section{\cdromc のルーチンの説明}

\cdromc\ のわずかなルーチンだけがドライバに移されます．本節でこれらを，
さらにカーネルへのインターフェースを `引き継ぐ' ルーチンの機能を扱いま
す．\cdromc\ に属するヘッダ・ファイルは \ucdrom\ と呼ばれます．しかし
将来 {\tt cdrom.h} に含まれるかも知れません．

\subsection{$struct\ file_operations\ cdrom_fops$}

この構造体の内容は \ref{cdrom.c}~節で説明しました．この構造体はカーネ
ルにブロック・デバイスを登録する際に使用されます:
$$
register_blkdev(major, <name>, \&cdrom_fops);
$$

\subsection{$Int\ register_cdrom(int\ major, char * name, struct\
cdrom_device_ops\ * cdo)$}

カーネルに $cdrom_fops$ を登録するのと同様です．\ref{cdrom.c}~節で説明
したように，デバイス制御構造体は一般的な \cdrom\ インターフェースに登
録されます:
$$
register_cdrom(major, <name>, \&<device>_dops);
$$
この関数は成功時に 0，エラー時にはそれ以外を返します．

\subsection{$Int\ unregister_cdrom(int\ major, char * name)$}

メジャー番号 $major$ の未登録のデバイス $name$ は \cdrom\ インターフェー
スから登録済みのデバイス制御ルーチンを切り離します．この関数は成功時に 
0，エラー時にはそれ以外を返します．

\subsection{$Int\ cdrom_open(struct\ inode * ip, struct\ file * fp)$}

この関数は低水準ドライバによって直接呼ばれません．標準の $cdrom_fops$ 
にリストされています．VFS がファイルを開くならこの関数は有効になります．
全ての能力とデバイスに接続された $cdrom_device_ops$ に設定されたオプショ
ンに注意して，このルーチンにストラテジ・ロジックが実装されます．それか
らプログラム・フローはデバイスに依存した $open()$ コールに移動されます．

\subsection{$Void\ cdrom_release(struct\ inode *ip, struct\ file
*fp)$}

この関数は $cdrom_open()$ のリバース・ロジックを実装します．それからデ
バイスに依存した $release()$ ルーチンを呼び出します．使用回数が 0 に達
すると，割り当てられたバッファは $sync_dev(dev)$ と 
$invalidate_buffers(dev)$ への呼出しによってフラッシュされます．

\subsection{$Int\ cdrom_ioctl(struct\ inode *ip, struct\ file *fp,
                       unsigned\ int\ cmd, unsigned\ long\ arg)$}
\label{cdrom-ioctl}

この関数は同様な方法で \cdrom\ デバイスのための $ioctl$ の全ての要求を
扱います．さまざまな呼出しは 3 つの範疇に分かれます: デバイス制御によっ
て直接実装され得る $ioctl$，$audio_ioctl()$ コールを経由するもの，おそ
らくデバイスに依存した残りのもの．一般に負の戻り値はエラーを表わします．

\subsubsection{直接実装された $ioctl$}
\label{ioctl-direct}

以下の `古い' \cdrom-$ioctl$ は，実装され，そしてマスクされないなら，
$cdrom_device_ops$ のデバイス制御を直接呼び出すことにより実装されます:
\begin{description}
\item[CDROMMULTISESSION] \cdrom\ の最後のセッションを要求します．
\item[CDROMEJECT] トレイを開きます．
\item[CDROMCLOSETRAY] トレイを閉じます．
\item[CDROMEJECT_SW] $arg\not=0$ なら，(最初に開く時にトレイを閉じる)
auto-close と(最後の解放時にイジェクトする) auto-eject に動作を設定し
ます．さもなければ，$open()$ と $release()$ コール時に non-moving に動
作を設定します．
\item[CDROM_GET_MCN or CDROM_GET_UPC] CD からメディア・カタログ番号を
得ます．
\end{description}

\subsubsection{$audio_ioctl()$ を経由して定着される $ioctl$}
\label{ioctl-audio}

以下の $ioctl$ の設定は，$cdrom_fops$ に $audio_ioctl()$ 関数を呼び出
すことにより全て実装されます．メモリの検査と割り当ては $cdrom_ioctl()$ 
で実行され，またアドレス・フォーマット ($CDROM_LBA$/$CDROM_MSF$) の衛
生化がなされます．
\begin{description}
\item[CDROMSUBCHNL] $struct\ cdrom_subchnl *{}$ 型の引数 $arg$ にサブ-
チャンネル・データを得ます．
\item[CDROMREADTOCHDR] $struct\ cdrom_tochdr *{}$ 型の $arg$ に目次の
ヘッダを読み込みます．
\item[CDROMREADTOCENTRY] $arg$ に目次の登録を読み込み，$struct\
cdrom_tocentry *{}$ 型の $arg$ により指定されます．
\item[CDROMPLAYMSF] $struct\ cdrom_msf *{}$ 型の $arg$ によって限界の
定められた，分，秒，フレーム・フォーマットに指定されたオーディオ・フラ
グメントを再生します．
\item[CDROMPLAYTRKIND] $struct\ cdrom_ti *{}$ 型の $arg$ によって限界
の定められたトラック-インデックス・フォーマットにオーディオ・フラグメ
ントを再生します．
\item[CDROMVOLCTRL] $struct\ cdrom_volctrl *{}$ 型の $arg$ により指定
された音量に設定します．
\item[CDROMVOLREAD] $struct\ cdrom_volctrl *{}$ 型の $arg$ により音量
を読み込みます．
\item[CDROMSTART] ディスクを回転させます．
\item[CDROMSTOP] オーディオ・フラグメントの再生を停止します．
\item[CDROMPAUSE] オーディオ・フラグメントの再生を一時停止します．
\item[CDROMRESUME] 再生を再開します．
\end{description}

\subsubsection{\cdromc\ の新しい $ioctl$}

以下の $ioctl$ はユーザ・プログラムが個々の \cdrom\ デバイスの動作を制
御できるよう導入されました．新しい $ioctl$ コマンドはその名前にあるア
ンダースコアによって見極められます．
\begin{description}
\item[CDROM_SET_OPTIONS] $arg$ で指定されたオプションを設定します．変
更後オプション・フラグ・レジスタを返します．現在のフラグを読み込むため
に $arg = \rm0$ をお使いください．
\item[CDROM_CLEAR_OPTIONS] $arg$ で指定されたオプションを無効にします．
変更後オプション・フラグ・レジスタを返します．
\item[CDROM_SELECT_SPEED] $arg$ で指定されたディスクのヘッド-レート速
度を選択します．値 0 は `自動選択' を意味します．すなわちオーディオ・
ディスクをリアル・タイムで再生し，データ・ディスクを最高速にします．値 
$arg$ は $cdrom_dops$ に見つかるドライブの最大ヘッド・レートに対して検
査されます．
\item[CDROM_SELECT_DISC] ジューク-ボックスから番号 $arg$ のディスクを
選択します．最初のディスクの番号は 0 です．番号 $arg$ は $cdrom_dops$ 
に見つかるジューク-ボックス内のディスクの最大数に対して検査されます．
\item[CDROM_MEDIA_CHANGED] 最後の呼出し以降ディスクが交換されたなら 1 
を返します．VFS による $cdrom_media_changed$ への呼出しは独立な待ち行
列によって扱われることに注意してください．ですから両機構がメディアの変
更を一度検出するでしょう．現在 \cdromc\ はメジャー・デバイス当たり最大 
16 マイナー・デバイスを実装しています．
\item[CDROM_DRIVE_STATUS] $drive_status()$ への呼出しによりドライブの
状態が返されます．戻り値は \ref{drive status}~節で定義されている通りで
す．この呼出しがドライブの現在の再生の活動度に関する情報を返さないこと
に注意してください; これは $CDROMSUBCHNL$ への $ioctl$ コールを経由し
て獲得されます．
\item[CDROM_DISC_STATUS] $disc_status()$ への呼出しにより現在ドライブ
に入っているディスクの型を返します．戻り値は \ref{disc status}~節で定
義されている通りです．
\end{description}

\subsubsection{デバイスに依存する $ioct$}

結局その他すべての $ioctl$ は実装されていれば $dev_ioctl()$ 関数に引き
渡されます．メモリの割当と照合は実行されません．

\subsection{ドライバのアップデート法}

\begin{enumerate}
\item 現在のドライバのバックアップをとってください．
\item \cdromc\ と \ucdrom\ を理解してください．それらはこの文書をとも
なったディレクトリ・ツリーにあります．
\item {\tt cdrom.h} の直後に {\tt \char`\<linux/ucdrom.h>} をインクルー
ドしてください．
\item $\&<your-drive>_fops$ から $\&cdrom_fops$ へ $register_blkdev$ 
の 3 番目の引数を変更してください．
\item その行の直後に \cdrom\ ルーチン:
$$register_cdrom(major, <name>,<your-drive>_dops);$$
へ登録するために 1 行加えてください．同様に $unregister_cdrom()$ への
呼出しを加えてください．
\item 御自身のソースにデバイス制御{\bf 構造体}の例をコピーしてください．
例えば {\tt cm206.c} から $cm206_dops$ をコピーし，ドライバに対応した
名前あるいはただたまたまお好きな名前に全てのエントリーを変更してくださ
い．ドライバがある関数をサポートしないなら，$NULL$ エントリーを作って
ください．{\bf 能力}エントリーでドライブが原理的にサポートできる全ての
能力をリストすべきです．リストに無い能力がドライブにあるなら，私にお知
らせください．
\item \ucdrom\ にリストされたプロトタイプに，そして \ref{cdrom.c}~節で
与えられた仕様にしたがって，御自身の $<device>_dops$ 構造体に全ての関
数を実装してください．おそらく大部分のコードをすでに実装しているはずで
す．単にプロトタイプと戻り値を適応する必要があるかも知れません．
\item $audio_ioctl$ への御自身の $<device>_ioctl()$ 関数の名前を変え，
プロトタイプを少し変更してください．コードが大丈夫なら 
\ref{cdrom-ioctl}~節の最初の部分にリストされたエントリーを削除してくだ
さい．これらはただ前ステップで適応させたルーチンへの呼出しです．
\item オーディオ・コマンドを扱う $audio_ioctl()$ 関数のメモリを検査す
るコードの残り全てを削除しても構いません．(これらは \ref{cdrom-ioctl}~
節の 2 番目の部分にリストされています．) メモリの割当には全然必要あり
ません．ですから $switch$ 文のほとんどの $case$ は以下のように見えます:
$$
case\ CDROMREADTOCENTRY\colon
get_toc_entry\bigl((struct\ cdrom_tocentry *{})\ arg\bigr);
$$
\item 残り全ての $ioctl$ case 文はデバイスに依存した $ioctl$ の別々の 
$<device>_ioctl$ 関数に移動すべきです．メモリの検査と割当はこのコード
になければならないことに注意してください!
\item $<device>_open()$ と $<device>_release()$ のプロトタイプを変更し
てください．どのようなストラテジック・コードも削除してください．(すな
わちトレイの移動，蓋のロックなど．)
\item ドライバを再コンパイルしてください．{\tt cdrom.o} と御自身のドラ
イバの両方をモジュール化すると，デバッグが非常に簡単なので，私たちはお
勧めします．
\end{enumerate} 

\section{謝辞}

全ての関係者の方々に感謝致します．執筆中たいへん親切に示唆と批評をいた
だいた \linux\ \cdrom\ デバイス・ドライバの開発者，Thomas~Quinot~氏，
Jon~Tombs~氏，Ken~Pizzini~氏，Eberhard~M\"onkeberg~氏，Andrew~Kroll~氏
に感謝致します．最後にもちろん，こういったことをまず最初に可能にしてい
ただいた Linus~Torvalds~氏に感謝したいと思います．
\end{document}
