Standardizing through another software level

At the time this document is written, all drivers directly implement the ioctl () calls through their own routines, with the danger of forgetting calls to verifyarea() and the risk of divergence in implementation.

For this reason, we1 propose to define another software-level, that separates the ioctl () and open() implementation from the actual hardware implementation. We believe that CDROM drives are specific enough (i.e., different from other block-devices such as floppy or hard disc drives), to define a set of 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 cdrom.c, and a low-level CDROM driver hands over the interfacing to the kernel by registering the following general struct fileoperations:

$\displaystyle \halign$$#$  & $#$  & $/*$#$*/$$\displaystyle \cr$struct & fileoperations cdromfops={$\displaystyle \hidewidth$$\displaystyle \cr$ & NULL, & lseek$\displaystyle \cr$ & blockread, & readgeneral block-dev read$\displaystyle \cr$ & blockwrite, & writegeneralblock-devwrite$\displaystyle \cr$ & NULL, & readdir$\displaystyle \cr$ & NULL, & select$\displaystyle \cr$ & cdromioctl, & ioctl$\displaystyle \cr$ & NULL, & mmap$\displaystyle \cr$ & cdromopen, & open$\displaystyle \cr$ & cdromrelease, & release$\displaystyle \cr$ & NULL, & fsync$\displaystyle \cr$ & NULL, & fasync$\displaystyle \cr$ & cdrommediachanged, & mediachange$\displaystyle \cr$ & NULL & revalidate$\displaystyle \cr$};$\displaystyle \cr$

Every active CDROM device shares this struct. The routines declared above are all implemented in cdrom.c, and this is the place where the 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 capabilities that are typical to CDROM (removable-media) devices.

Registration of the CDROM device driver should now be to the general routines in cdrom.c, not to the VFS any more. This is done though the call

registercdrom(int major, char*name, struct cdromdeviceops deviceoptions)

The device operations structure lists the implemented routines for interfacing to the hardware, and some specifications of capabilities of the device, such as the maximum head-transfer rate. [It is impossible to come up with a complete list of all capabilities of (future) CDROM drives, as the developments in technology follow-up at an incredible rate. Maybe write-operation (WORM devices) will become very popular in the future.] The list now is:

$\displaystyle \halign$$#$  & $#$  & to10em$#$$\displaystyle \hss$ & $/*$#$*/$$\displaystyle \cr$struct & cdromdeviceops {$\displaystyle \hidewidth$$\displaystyle \cr$ & int & (*open)(kdevt, int)$\displaystyle \cr$ & void & (*release)(kdevt);$\displaystyle \cr$ & int & (*openfiles)(kdevt);$\displaystyle \cr$ & int & (*drivestatus)(kdevt);$\displaystyle \cr$ & int & (*discstatus)(kdevt);$\displaystyle \cr$ & int & (*mediachanged )(kdevt);$\displaystyle \cr$ & int & (*traymove)(kdevt, int);$\displaystyle \cr$ & int & (*lockdoor)(kdevt, int);$\displaystyle \cr$ & int & (*selectspeed )(kdevt, int);$\displaystyle \cr$ & int & (*selectdisc)(kdevt, int);$\displaystyle \cr$ & int & (*getlastsession)(kdevt, struct cdrommultisession*);$\displaystyle \cr$ & int & (*getmcn)(kdevt, struct cdrommcn*);$\displaystyle \cr$ & int & (*reset)(kdevt);$\displaystyle \cr$ & int & (*audioioctl )(kdevt, unsigned int, void*);$\displaystyle \cr$ & int & (*devioctl )(kdevt, unsigned int, unsigned long);$\displaystyle \cr$


& $\displaystyle \llap$const int & capability; & capabilityflags$\displaystyle \cr$ & int & mask; & maskofcapability:disablesthem$\displaystyle \cr$ & $\displaystyle \llap$$const $float & speed; & maximumspeedforreadingdata$\displaystyle \cr$ & $\displaystyle \llap$$const $int & minors; & numberofsupportedminordevices$\displaystyle \cr$ & $\displaystyle \llap$$const $int & capacity; & numberofdiscsinjukebox$\displaystyle \cr$


& int & options; & optionsflags$\displaystyle \cr$ & long & mcflags; & media-changebufferflags($2×16$)$\displaystyle \cr$}$\displaystyle \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 ioctls. The flags capability specify the hardware-capabilities on registration of the device, the flags mask can be used to mask some of those capabilities (for one reason or another). The value minors should be a positive value indicating the number of minor devices that are supported by the driver, normally 1. (They are supposed to be numbered from 0 upwards). The value capacity should be the number of discs the drive can hold simultaneously, if it is designed as a juke-box, or otherwise 1.

Two registers contain variables local to the CDROM device. The flags options are used to specify how the general CDROM routines should behave. These various flags registers should provide enough flexibility to adapt to the different user's wishes (and not the `arbitrary' wishes of the author of the low-level device driver, as is the case in the old scheme). The register mcflags is used to buffer the information from mediachanged () to two separate queues.

Note that most functions have fewer parameters than their blkdevfops counterparts. This is because very little of the information in the structures inode and file are used, the main parameter is the device dev, from which the minor-number can be extracted. (Most low-level CDROM drivers don't even look at that value as only one device is supported.)

The intermediate software layer that cdrom.c forms will performs some additional bookkeeping. The minor number of the device is checked against the maximum registered in < device > dops. The function cdromioctl () will verify the appropriate user-memory regions for read and write, and in case a location on the CD is transferred, it will `sanitize' the format by making requests to the low-level drivers in a standard format, and translating all formats between the user-software and low level drivers. This relieves much of the drivers memory checking and format checking and translation. Also, the necessary structures will be declared on the program stack.

The implementation of the functions should be as defined in the following sections. Three functions must be implemented, namely open(), release() and openfiles(). 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.



Subsections