CDROM
API
A universal device driver exists (cdrom.o) in Linux to access
any cd, regardless of the interface it is connected to.
(scsi, ide, usb, IIel)
All functions to access a cdrom device are via
linux/cdrom.h
The API is consistent, and, relatively simple. You use the
ioctl() function with the constants defined in linux/cdrom.h to
access the cdrom itself.
The ioctl() function is universal for all device
drivers. Therefore, while a large number of error messages are
possible, only a small range is returned for any function to
the cdrom interface driver. Those values are listed for each
function described below.
Track Layouts
A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332,
2336, 2340, or 2352 bytes long.
The basic unit of measure is the FRAME. Regardless of
format a frame is universally 2352 bytes long.
CD-DA audio (red):
| audio bytes
|
98x24 chunks (2352)
|
data (yellow, mode1 form1)
| sync - head - data - EDC - zero - ECC |
| 12 - 4 - 2048 - 4 -
8 - 276 |
data (yellow, mode2 form2) |
sync - head - data
|
| 12 - 4 - 2336
|
CD-XA data (green, mode2 form1) |
sync - head - sub - data - EDC - ECC |
| 12 - 4 - 8 - 2048 -
4 - 276 |
data (green, mode2
form2) | sync - head - sub - data - EDC
|
| 12 - 4 - 8 - 2324 - 4
|
CD audio speed is 75 frames per second for 74 minutes playing
time making
74*75 = 5550 frames per cd
Addressing
accessing sections of a cd is in one of two formats
LBA: logical block address
MSF: Minutes, Sectors, Frames
most functions contain the ability to work in either mode (and
return similar). You can succesfully mix and match at anytime.
(Internally, the driver converts all msf commands to lba).
A logical block address is expressed in frames
(starting at 0).
The start of MSF addressing is biased 150 frames
(2 seconds) into the cd. Thus an msf of 0:0:0 is an lba address
of frame 149.
the api uses the struct
struct cdrom_msf
{
u_char
minute;
u_char
second;
u_char
frame;
};
when working with msf values.
Where relevant the api uses a consistent union to address in
both modes
union cdrom_addr
{
int
lba;
struct
cdrom_msf msf;
}
BASIC FILE OPEN AND CLOSE
int cd_fd=
open("/dev/cdrom",O_RDONLY | O_NONBLOCK);
returns 0 on
success
close(fd);
EJECT AND LOAD
ioctl(cd_fd,CDROMEJECT);
//eject
ioctl(cd_fd,CDROMCLOSETRAY); // load
ioctl(cd_fd,CDROMEJECT_SW,true | false); // enable eject
on close
Eject and load work irrespective of cd installed or
otherwise
Error returns:
-EBUSY drive->usage >
1
-EIO cmdQ failed
PAUSE & RESUME
ioctl(cd_fd,CDROMPAUSE);
ioctl(cd_fd,CDROMRESUME);
Error returns:
-EIO cmdQ
failed
START & STOP
ioctl(cd_fd,CDROMSTART);
ioctl(cd_fd,CDROMSTOP);
Error Returns:
-EIO cmdQ
failed
VOLUME
u_char volumes[4];
ioctl(cd_fd,CDROMVOLCTRL, &volumes); //
write values
ioctl(cd_fd,CDROMVOLREAD, &volumes); //
read values
Returns:
-EFAULT bad struct
-EIO queue packe fail
channels are 0..255 in volume
channels 3 and 4 generally return zero
RESET
ioctl(cd_fd,CDROMRESET);
returns -EPERM op not
permitted
READ SUBCHANNEL
// simply reads status of the cd
struct cdrom_subchnl
{
u_char
cdsc_format; // required CDROM_MSF or LBA
u_char
cdsc_audiostatus; //
filled
CDROM_AUDIO_INVALID 0x00
/* audio status not supported
*/
CDROM_AUDIO_PLAY 0x11
/* audio play operation
in progress */
CDROM_AUDIO_PAUSED 0x12
/* audio play operation paused */
CDROM_AUDIO_COMPLETED 0x13 /* audio play
successfully completed */
CDROM_AUDIO_ERROR 0x14
/* audio play stopped due to error
*/
CDROM_AUDIO_NO_STATUS 0x15 /* no current
audio status to return */
u_char
cdsc_adr: 4; // not used
u_char
cdsc_ctrl: 4; // filled
u_char
cdsc_trk; //
filled
u_char
cdsc_ind; //
filled
union
cdrom_addr relative; // filled
union
cdrom_addr absolute; // filled
};
ioctl(cd_fd,
CDROMSUBCHNL, sc);
Returns:
-EFAULT bad struct
-EIO queue packe fail
GET TOC HEADER
// reads beginning and ending tracks of cd // FROM TRACK
1
struct cdrom_tochdr
{
u_char cdth_trk0; /* start
track */
u_char cdth_trk1; /* end
track */
};
ioctl(cd_fd,CDROMREADTOCHDR,&tochdr);
A pure data cd will return 1:1
Returns:
-EFAULT invalid tochdr
struct
-EIO cdrom_read_toc
failed.
struct cdrom_tocentry
{
u_char
cdte_track; // required
u_char cdte_adr
:4; // filled
u_char
cdte_ctrl :4; // filled
CDROM_DATA_TRACK 0x04 track is data or
audio
u_char
cdte_format; // required CDROM_MSF or CDROM_LBA
union
cdrom_addr cdte_addr; // filled;
u_char
cdte_datamode; // not used
};
ioctl(cd_fd,CDROMREADTOCENTRY,&tc);
returns:
-EFAULT invalid struct
-EINVAL invalid
track;
-EIO cdrom_read_toc
failed
General flow
controlling aspects of the cd is accomplished using a mix of
the above functions. To wit:
open("/dev/cdrom",O_RDONLY | O_NONBLOCK);
ioctl(cd_fd,CDROMCLOSETRAY); // (if required)
ioctl(cd_fd,CDROMREADTOCHDR,&tochdr); //
find out how many tracks
ioctl(cd_fd,CDROMREADTOCENTRY,&tc);
// read info for each of these tracks
for(;;)
{
ioctl(cd_fd,
CDROMSUBCHNL, sc);
/read status
.. perfom ops
}
ioctl(cd_fd,CDROMEJECT);
//eject
close(fd);
The remining functions are what you can
do with the cd, including playing tracks.
PLAY TRACK(S)
struct cdrom_ti
{
u_char
start_track //from
1
u_char
cdti_ind0; /* not used */
u_char
end_track; /* from 1*/
u_char
cdti_ind1; /* not used */
};
ioctl(cd_fd,CDROMPLAYTRKIND,&ti);
Returns:
-EFAULT invalid
struct
-EINVAL start > end or invalid
track
-EIO cmdQ failed
PLAY MSF
struct cdrom_msf
{
u_char cdmsf_min0;
/* start position in real minutes */
u_char
cdmsf_sec0; /* real seconds */
u_char
cdmsf_frame0; /* frames */
u_char
cdmsf_min1; /* end ... */
u_char
cdmsf_sec1;
u_char
cdmsf_frame1;
};
ioctl(cd_fd,
CDROMPLAYMSF, &ms);
Returns:
-EFAULT invalid msf
struct
-EINVAL start >
end;
-EIO cmdQ failed
PLAY BLOCK
struct cdrom_blk
{
unsigned
from; // in
lba
unsigned short
len; // in
frames
};
ioctl(cd_fd,CDROMPLAYBLK,&blk);
This ioctl is only used by the scsi-cd driver.
It is for playing audio in logical block addressing mode.
CD BARCODE
struct cdrom_mcn
{
u_char
medium_catalog_number[14]; /* 13 ASCII digits, null-terminated
*/
};
ioctl(cd_fd,CDROM_GET_UPC, &mcn); //deprecated
ioctl(cd_fd,CDROM_GET_MCN, &mcn);
Returns:
-EFAULT bad
struct
-EIO queue packe fail
(playing)
MULTISESSION
struct cdrom_multisession
{
union cdrom_addr addr; /*
Returned: address start-of-last-session
u_char xa_flag;
/*
Returned: 1= XA disk otherwise addr is invalid */
u_char addr_format;
/* Required: CDROM_LBA or CDROM_MSF */
};
ioctl(cd_fd,CDROMMULTISESSION,&ms_info);
Returns:
-EFAULT bad struct, or
oversized nframes (blocksize)
-EINVAL addr_format not set
to msf or lba
-EIO cdrom_read_toc
failed.
READ RAW FRAMES
struct cdrom_read_audio ra
{
union
cdrom_addr addr; /* REQUIRED frame address */
u_char
addr_format; /* REQUIRED .....CDROM_LBA or CDROM_MSF
*/
int nframes;
/* REQUIRED number of
2352-byte-frames to read
u_char
*buf; /* REQUIRED frame
buffer (size: nframes*2352 bytes) */
};
ioctl(cd_fd,CDROMREADAUDIO,&ra);
Returns:
returns no fault on nframes =0 (dummy op)
-EFAULT bad struct, or oversized nframes
-EINVAL ra.nframes bad or
format unknown, or lba oversize
-ENOMEM can't make temp
malloc for buffer
-EIO packet command or
cdrom_read_toc failed.
READ RAW MSF
READ MODE1
READ MODE2
union
{
struct cdrom_msf
msf
char bigbuf[2536];
};
ioctl(cd_fd,CDROMREADRAW,&msf);
ioctl(cd_fd,CDROMREADMODE1,msf);
ioctl(cd_fd,CDROMREADMODE2,buf);
returns EINVAL on scsi 2048
Bytes
returns EINVAL on scsi 2336
Bytes
In each case, the begiining of the buffer which contains the
msf values is overwritten with the requested data
READ SLOT
ioctl(cd_fd,CDROMLOADFROMSLOT,slot);
// the loadsloat as been deprecated and cuases a kernel
message in ide-cdrom.
ioctl(cd_fd,CDROM_SELECT_DISC,slotnum) ;
startng at 0 (-1 = defaultunlodad
Returns:
-EBUSY in use;
-EIO cdrom_read_toc
failed.
-ENOENT NOT_READY