CDROM ioctl 调用总结

2004 年 11 月

本文档旨在描述 CDROM 层支持的 ioctl(2) 调用。这些调用在 Linux 2.6 版本中主要在 `drivers/cdrom/cdrom.c` 和 `drivers/block/scsi_ioctl.c` 中实现。

ioctl 值列在 `` 中。截至本文撰写时,它们如下所示:

CDROMPAUSE

暂停音频操作

CDROMRESUME

恢复暂停的音频操作

CDROMPLAYMSF

播放音频 MSF (struct cdrom_msf)

CDROMPLAYTRKIND

播放音频轨道/索引 (struct cdrom_ti)

CDROMREADTOCHDR

读取 TOC 头 (struct cdrom_tochdr)

CDROMREADTOCENTRY

读取 TOC 条目 (struct cdrom_tocentry)

CDROMSTOP

停止光盘驱动器

CDROMSTART

启动光盘驱动器

CDROMEJECT

弹出光盘介质

CDROMVOLCTRL

控制输出音量 (struct cdrom_volctrl)

CDROMSUBCHNL

读取子通道数据 (struct cdrom_subchnl)

CDROMREADMODE2

读取 CDROM 模式 2 数据 (2336 字节) (struct cdrom_read)

CDROMREADMODE1

读取 CDROM 模式 1 数据 (2048 字节) (struct cdrom_read)

CDROMREADAUDIO

(struct cdrom_read_audio)

CDROMEJECT_SW

启用(1)/禁用(0) 自动弹出

CDROMMULTISESSION

获取多段会话光盘的最后一段会话起始地址 (struct cdrom_multisession)

CDROM_GET_MCN

获取“通用产品代码”(如果可用)(struct cdrom_mcn)

CDROM_GET_UPC

已废弃,请改用 CDROM_GET_MCN。

CDROMRESET

硬重置驱动器

CDROMVOLREAD

获取驱动器的音量设置 (struct cdrom_volctrl)

CDROMREADRAW

以原始模式读取数据 (2352 字节) (struct cdrom_read)

CDROMREADCOOKED

以处理模式读取数据

CDROMSEEK

寻址到 msf 地址

CDROMPLAYBLK

仅限 scsi-cd, (struct cdrom_blk)

CDROMREADALL

读取所有 2646 字节

CDROMGETSPINDOWN

返回 4 位 spindown 值

CDROMSETSPINDOWN

设置 4 位 spindown 值

CDROMCLOSETRAY

CDROMEJECT 的对应操作

CDROM_SET_OPTIONS

设置行为选项

CDROM_CLEAR_OPTIONS

清除行为选项

CDROM_SELECT_SPEED

设置光盘驱动器速度

CDROM_SELECT_DISC

选择光盘 (适用于自动点唱机)

CDROM_MEDIA_CHANGED

检查介质是否改变

CDROM_TIMED_MEDIA_CHANGE

检查介质自给定时间以来是否改变 (struct cdrom_timed_media_change_info)

CDROM_DRIVE_STATUS

获取托盘位置等

CDROM_DISC_STATUS

获取光盘类型等

CDROM_CHANGER_NSLOTS

获取插槽数量

CDROM_LOCKDOOR

锁定或解锁仓门

CDROM_DEBUG

打开/关闭调试消息

CDROM_GET_CAPABILITY

获取能力

CDROMAUDIOBUFSIZ

设置音频缓冲区大小

DVD_READ_STRUCT

读取结构

DVD_WRITE_STRUCT

写入结构

DVD_AUTH

认证

CDROM_SEND_PACKET

发送数据包到驱动器

CDROM_NEXT_WRITABLE

获取下一个可写块

CDROM_LAST_WRITTEN

获取光盘上最后写入的块

以下信息是通过阅读内核源代码确定的。随着时间的推移,可能会进行一些更正。


一般

除非另有说明,所有 ioctl 调用在成功时返回 0,在错误时返回 -1 并将 errno 设置为适当的值。(某些 ioctl 返回非负数据值。)

除非另有说明,所有 ioctl 调用在尝试将数据复制到或从用户地址空间复制失败时,返回 -1 并将 errno 设置为 EFAULT。

各个驱动程序可能会返回此处未列出的错误代码。

除非另有说明,所有数据结构和常量均定义在 `` 中。


CDROMPAUSE

暂停音频操作

用法

ioctl(fd, CDROMPAUSE, 0);
输入

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

CDROMRESUME

恢复暂停的音频操作

用法

ioctl(fd, CDROMRESUME, 0);
输入

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

CDROMPLAYMSF

播放音频 MSF

(struct cdrom_msf)

用法

struct cdrom_msf msf;

ioctl(fd, CDROMPLAYMSF, &msf);
输入

`cdrom_msf` 结构,描述要播放的音乐片段

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

注意
  • MSF 代表分-秒-帧

  • LBA 代表逻辑块地址

  • 片段以开始和结束时间描述,其中每个时间都以分:秒:帧表示。一帧是 1/75 秒。

CDROMPLAYTRKIND

播放音频轨道/索引

(struct cdrom_ti)

用法

struct cdrom_ti ti;

ioctl(fd, CDROMPLAYTRKIND, &ti);
输入

`cdrom_ti` 结构,描述要播放的音乐片段

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

注意
  • 片段以开始和结束时间描述,其中每个时间都以轨道和索引表示。

CDROMREADTOCHDR

读取 TOC 头

(struct cdrom_tochdr)

用法

cdrom_tochdr header;

ioctl(fd, CDROMREADTOCHDR, &header);
输入

`cdrom_tochdr` 结构

输出

`cdrom_tochdr` 结构

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

CDROMREADTOCENTRY

读取 TOC 条目

(struct cdrom_tocentry)

用法

struct cdrom_tocentry entry;

ioctl(fd, CDROMREADTOCENTRY, &entry);
输入

`cdrom_tocentry` 结构

输出

`cdrom_tocentry` 结构

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

  • EINVAL `entry.cdte_format` 不是 CDROM_MSF 或 CDROM_LBA

  • EINVAL 请求的轨道超出范围

  • EIO 读取 TOC 时发生 I/O 错误

注意
  • TOC 代表目录 (Table Of Contents)

  • MSF 代表分-秒-帧

  • LBA 代表逻辑块地址

CDROMSTOP

停止光盘驱动器

用法

ioctl(fd, CDROMSTOP, 0);
输入

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

注意
  • 此 ioctl 的确切解释取决于设备,但大多数设备似乎都会使驱动器停止转动。

CDROMSTART

启动光盘驱动器

用法

ioctl(fd, CDROMSTART, 0);
输入

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

注意
  • 此 ioctl 的确切解释取决于设备,但大多数设备似乎都会使驱动器启动和/或关闭托盘。其他设备则完全忽略此 ioctl。

CDROMEJECT
  • 弹出光盘介质

用法

ioctl(fd, CDROMEJECT, 0);
输入

输出

错误返回
  • ENOSYS 光盘驱动器不具备弹出能力

  • EBUSY 其他进程正在访问驱动器,或仓门已锁定

注意
  • 参见下面的 CDROM_LOCKDOOR。

CDROMCLOSETRAY

CDROMEJECT 的对应操作

用法

ioctl(fd, CDROMCLOSETRAY, 0);
输入

输出

错误返回
  • ENOSYS 光盘驱动器不具备关闭托盘的能力

  • EBUSY 其他进程正在访问驱动器,或仓门已锁定

注意
  • 参见下面的 CDROM_LOCKDOOR。

CDROMVOLCTRL

控制输出音量 (struct cdrom_volctrl)

用法

struct cdrom_volctrl volume;

ioctl(fd, CDROMVOLCTRL, &volume);
输入

`cdrom_volctrl` 结构,包含多达 4 个通道的音量。

输出

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

CDROMVOLREAD

获取驱动器的音量设置

(struct cdrom_volctrl)

用法

struct cdrom_volctrl volume;

ioctl(fd, CDROMVOLREAD, &volume);
输入

输出

当前音量设置。

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

CDROMSUBCHNL

读取子通道数据

(struct cdrom_subchnl)

用法

struct cdrom_subchnl q;

ioctl(fd, CDROMSUBCHNL, &q);
输入

`cdrom_subchnl` 结构

输出

`cdrom_subchnl` 结构

错误返回
  • ENOSYS 光盘驱动器不具备音频功能。

  • EINVAL 格式不是 CDROM_MSF 或 CDROM_LBA

注意
  • 返回时,格式根据用户请求转换为 CDROM_MSF 或 CDROM_LBA

CDROMREADRAW

以原始模式读取数据 (2352 字节)

(struct cdrom_read)

用法

union {

  struct cdrom_msf msf;               /* input */
  char buffer[CD_FRAMESIZE_RAW];      /* return */
} arg;
ioctl(fd, CDROMREADRAW, &arg);
输入

`cdrom_msf` 结构,指示要读取的地址。

只有起始值是重要的。

输出

数据写入用户提供的地址。

错误返回
  • EINVAL 地址小于 0,或 msf 小于 0:2:0

  • ENOMEM 内存不足

注意
  • 截至 2.6.8.1 版本,`` 中的注释表明此 ioctl 接受 `cdrom_read` 结构,但实际源代码读取的是 `cdrom_msf` 结构并将数据缓冲区写入同一地址。

  • MSF 值通过此公式转换为 LBA 值

    lba = (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
    
CDROMREADMODE1

读取 CDROM 模式 1 数据 (2048 字节)

(struct cdrom_read)

注意

与 CDROMREADRAW 相同,只是块大小为 CD_FRAMESIZE (2048) 字节

CDROMREADMODE2

读取 CDROM 模式 2 数据 (2336 字节)

(struct cdrom_read)

注意

与 CDROMREADRAW 相同,只是块大小为 CD_FRAMESIZE_RAW0 (2336) 字节

CDROMREADAUDIO

(struct cdrom_read_audio)

用法

struct cdrom_read_audio ra;

ioctl(fd, CDROMREADAUDIO, &ra);
输入

`cdrom_read_audio` 结构,包含读取起始点和长度

输出

音频数据,返回到由 ra 指示的缓冲区

错误返回
  • EINVAL 格式不是 CDROM_MSF 或 CDROM_LBA

  • EINVAL `nframes` 不在 [1 75] 范围内

  • ENXIO 驱动器没有队列 (可能意味着无效的文件描述符 fd)

  • ENOMEM 内存不足

CDROMEJECT_SW

启用(1)/禁用(0) 自动弹出

用法

int val;

ioctl(fd, CDROMEJECT_SW, val);
输入

指定自动弹出标志。

输出

错误返回
  • ENOSYS 驱动器不具备弹出能力。

  • EBUSY 仓门已锁定

CDROMMULTISESSION

获取多段会话光盘的最后一段会话起始地址

(struct cdrom_multisession)

用法

struct cdrom_multisession ms_info;

ioctl(fd, CDROMMULTISESSION, &ms_info);
输入

`cdrom_multisession` 结构,包含所需

格式。

输出

`cdrom_multisession` 结构填充有 `last_session` 信息。

错误返回
  • EINVAL 格式不是 CDROM_MSF 或 CDROM_LBA

CDROM_GET_MCN

获取“通用产品代码”(如果可用)

(struct cdrom_mcn)

用法

struct cdrom_mcn mcn;

ioctl(fd, CDROM_GET_MCN, &mcn);
输入

输出

通用产品代码

错误返回
  • ENOSYS 驱动器不具备读取 MCN 数据的能力。

注意
  • 源代码注释说明

    The following function is implemented, although very few
    audio discs give Universal Product Code information, which
    should just be the Medium Catalog Number on the box.  Note,
    that the way the code is written on the CD is /not/ uniform
    across all discs!
    
CDROM_GET_UPC

CDROM_GET_MCN (已废弃)

截至 2.6.8.1 版本,未实现

CDROMRESET

硬重置驱动器

用法

ioctl(fd, CDROMRESET, 0);
输入

输出

错误返回
  • EACCES 访问被拒绝:需要 CAP_SYS_ADMIN 权限

  • ENOSYS 驱动器不具备重置能力。

CDROMREADCOOKED

以处理模式读取数据

用法

u8 buffer[CD_FRAMESIZE]

ioctl(fd, CDROMREADCOOKED, buffer);
输入

输出

2048 字节数据,“处理”模式。

注意

并非所有驱动器都实现。

CDROMREADALL

读取所有 2646 字节

与 CDROMREADCOOKED 相同,但读取 2646 字节。

CDROMSEEK

寻址到 msf 地址

用法

struct cdrom_msf msf;

ioctl(fd, CDROMSEEK, &msf);
输入

要寻址到的 MSF 地址。

输出

CDROMPLAYBLK

仅限 scsi-cd

(struct cdrom_blk)

用法

struct cdrom_blk blk;

ioctl(fd, CDROMPLAYBLK, &blk);
输入

要播放的区域

输出

CDROMGETSPINDOWN

已过时,曾仅限于 ide-cd

用法

char spindown;

ioctl(fd, CDROMGETSPINDOWN, &spindown);
输入

输出

当前 4 位 spindown 值。

CDROMSETSPINDOWN

已过时,曾仅限于 ide-cd

用法

char spindown

ioctl(fd, CDROMSETSPINDOWN, &spindown);
输入

用于控制 spindown 的 4 位值 (待办:此处需更多细节)

输出

CDROM_SET_OPTIONS

设置行为选项

用法

int options;

ioctl(fd, CDROM_SET_OPTIONS, options);
输入

驱动器选项的新值。以下各项的逻辑“或”:

CDO_AUTO_CLOSE

首次 open(2) 时关闭托盘

CDO_AUTO_EJECT

最后释放时打开托盘

CDO_USE_FFLAGS

在 open 时使用 O_NONBLOCK 信息

CDO_LOCK

在文件打开时锁定托盘

CDO_CHECK_TYPE

在打开数据时检查类型

输出

在 ioctl 返回值中返回结果选项设置。错误时返回 -1。

错误返回
  • ENOSYS 所选选项不受驱动器支持。

CDROM_CLEAR_OPTIONS

清除行为选项

与 CDROM_SET_OPTIONS 相同,只是所选选项被关闭。

CDROM_SELECT_SPEED

设置光盘驱动器速度

用法

int speed;

ioctl(fd, CDROM_SELECT_SPEED, speed);
输入

新的驱动器速度。

输出

错误返回
  • ENOSYS 驱动器不支持速度选择。

CDROM_SELECT_DISC

选择光盘 (适用于自动点唱机)

用法

int disk;

ioctl(fd, CDROM_SELECT_DISC, disk);
输入

要加载到驱动器中的光盘。

输出

错误返回
  • EINVAL 光盘编号超出驱动器容量

CDROM_MEDIA_CHANGED

检查介质是否改变

用法

int slot;

ioctl(fd, CDROM_MEDIA_CHANGED, slot);
输入

要测试的插槽编号,除了自动换碟机外始终为零。

也可能是特殊值 CDSL_NONE 或 CDSL_CURRENT

输出

ioctl 返回值为 0 或 1,取决于介质是否

已改变,或错误时返回 -1。

错误返回
  • ENOSYS 驱动器无法检测到介质改变

  • EINVAL 插槽编号超出驱动器容量

  • ENOMEM 内存不足

CDROM_DRIVE_STATUS

获取托盘位置等

用法

int slot;

ioctl(fd, CDROM_DRIVE_STATUS, slot);
输入

要测试的插槽编号,除了自动换碟机外始终为零。

也可能是特殊值 CDSL_NONE 或 CDSL_CURRENT

输出

ioctl 返回值将是以下值之一

来自 ``

CDS_NO_INFO

信息不可用。

CDS_NO_DISC

CDS_TRAY_OPEN

CDS_DRIVE_NOT_READY

CDS_DISC_OK

-1

错误

错误返回
  • ENOSYS 驱动器无法检测到驱动器状态

  • EINVAL 插槽编号超出驱动器容量

  • ENOMEM 内存不足

CDROM_DISC_STATUS

获取光盘类型等

用法

ioctl(fd, CDROM_DISC_STATUS, 0);
输入

输出

ioctl 返回值将是以下值之一

来自 ``

  • CDS_NO_INFO

  • CDS_AUDIO

  • CDS_MIXED

  • CDS_XA_2_2

  • CDS_XA_2_1

  • CDS_DATA_1

错误返回

目前无

注意
  • 源代码注释说明

    Ok, this is where problems start.  The current interface for
    the CDROM_DISC_STATUS ioctl is flawed.  It makes the false
    assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.
    Unfortunately, while this is often the case, it is also
    very common for CDs to have some tracks with data, and some
    tracks with audio.      Just because I feel like it, I declare
    the following to be the best way to cope.  If the CD has
    ANY data tracks on it, it will be returned as a data CD.
    If it has any XA tracks, I will return it as that.      Now I
    could simplify this interface by combining these returns with
    the above, but this more clearly demonstrates the problem
    with the current interface.  Too bad this wasn't designed
    to use bitmasks...             -Erik
    
    Well, now we have the option CDS_MIXED: a mixed-type CD.
    User level programmers might feel the ioctl is not very
    useful.
                    ---david
    
CDROM_CHANGER_NSLOTS

获取插槽数量

用法

ioctl(fd, CDROM_CHANGER_NSLOTS, 0);
输入

输出

ioctl 返回值将是 CD 换碟机中的插槽数量。对于非多碟设备,通常为 1。

错误返回

CDROM_LOCKDOOR

锁定或解锁仓门

用法

int lock;

ioctl(fd, CDROM_LOCKDOOR, lock);
输入

仓门锁定标志,1=锁定,0=解锁

输出

错误返回
  • EDRIVE_CANT_DO_THIS

    不支持仓门锁定功能。

  • EBUSY

    当多个用户打开驱动器且不具备 CAP_SYS_ADMIN 权限时尝试解锁

注意

截至 2.6.8.1 版本,锁定标志是全局的,意味着所有 CD 驱动器将同时锁定或解锁。这可能是一个错误。

EDRIVE_CANT_DO_THIS 值在 `` 中定义,目前 (2.6.8.1) 与 EOPNOTSUPP 相同。

CDROM_DEBUG

打开/关闭调试消息

用法

int debug;

ioctl(fd, CDROM_DEBUG, debug);
输入

光盘调试标志,0=禁用,1=启用

输出

ioctl 返回值将是新的调试标志。

错误返回
  • EACCES 访问被拒绝:需要 CAP_SYS_ADMIN 权限

CDROM_GET_CAPABILITY

获取能力

用法

ioctl(fd, CDROM_GET_CAPABILITY, 0);
输入

输出

ioctl 返回值是当前设备能力标志。参见 CDC_CLOSE_TRAY, CDC_OPEN_TRAY 等。

CDROMAUDIOBUFSIZ

设置音频缓冲区大小

用法

int arg;

ioctl(fd, CDROMAUDIOBUFSIZ, val);
输入

新的音频缓冲区大小

输出

ioctl 返回值是新的音频缓冲区大小,或错误时返回 -1。

错误返回
  • ENOSYS 该驱动程序不支持。

注意

并非所有驱动程序都支持。

DVD_READ_STRUCT 读取结构

用法

dvd_struct s;

ioctl(fd, DVD_READ_STRUCT, &s);
输入

`dvd_struct` 结构,包含

类型

指定所需信息,可以是 DVD_STRUCT_PHYSICAL, DVD_STRUCT_COPYRIGHT, DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA, DVD_STRUCT_MANUFACT 之一

physical.layer_num

所需层,从 0 开始索引

copyright.layer_num

所需层,从 0 开始索引

disckey.agid

输出

`dvd_struct` 结构,包含

物理

当 `type == DVD_STRUCT_PHYSICAL` 时

版权

当 `type == DVD_STRUCT_COPYRIGHT` 时

disckey.value

当 `type == DVD_STRUCT_DISCKEY` 时

bca.{len,value}

当 `type == DVD_STRUCT_BCA` 时

manufact.{len,valu}

当 `type == DVD_STRUCT_MANUFACT` 时

错误返回
  • EINVAL `physical.layer_num` 超过层数

  • EIO 从驱动器收到无效响应

DVD_WRITE_STRUCT 写入结构

截至 2.6.8.1 版本,未实现

DVD_AUTH 认证

用法

dvd_authinfo ai;

ioctl(fd, DVD_AUTH, &ai);
输入

`dvd_authinfo` 结构。参见 ``

输出

`dvd_authinfo` 结构。

错误返回
  • ENOTTY `ai.type` 未识别。

CDROM_SEND_PACKET

发送数据包到驱动器

用法

struct cdrom_generic_command cgc;

ioctl(fd, CDROM_SEND_PACKET, &cgc);
输入

`cdrom_generic_command` 结构,包含要发送的数据包。

输出

`cdrom_generic_command` 结构,包含结果。

错误返回
  • EIO

    命令失败。

  • EPERM

    操作不允许,原因可能是尝试对只读打开的驱动器执行写入命令,或该命令需要 CAP_SYS_RAWIO 权限

  • EINVAL

    `cgc.data_direction` 未设置

CDROM_NEXT_WRITABLE

获取下一个可写块

用法

long next;

ioctl(fd, CDROM_NEXT_WRITABLE, &next);
输入

输出

下一个可写块。

注意

如果设备不直接支持此 ioctl,则

ioctl 将返回 CDROM_LAST_WRITTEN + 7。

CDROM_LAST_WRITTEN

获取光盘上最后写入的块

用法

long last;

ioctl(fd, CDROM_LAST_WRITTEN, &last);
输入

输出

光盘上最后写入的块

注意

如果设备不直接支持此 ioctl,则结果将从光盘的目录表中导出。如果目录表无法读取,此 ioctl 将返回错误。