CDROM ioctl 调用概述¶
Edward A. Falk <efalk@google.com>
2004年11月
本文档试图描述 CDROM 层支持的 ioctl(2) 调用。 这些调用(截至 Linux 2.6)主要在 drivers/cdrom/cdrom.c 和 drivers/block/scsi_ioctl.c 中实现。
ioctl 值在 <linux/cdrom.h> 中列出。 截至本文撰写时,它们如下:
CDROMPAUSE
暂停音频操作
CDROMRESUME
恢复暂停的音频操作
CDROMPLAYMSF
播放音频 MSF (struct cdrom_msf)
CDROMPLAYTRKIND
播放音频轨道/索引 (struct cdrom_ti)
CDROMREADTOCHDR
读取 TOC 标头 (struct cdrom_tochdr)
CDROMREADTOCENTRY
读取 TOC 条目 (struct cdrom_tocentry)
CDROMSTOP
停止 CDROM 驱动器
CDROMSTART
启动 CDROM 驱动器
CDROMEJECT
弹出 CDROM 媒体
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 位主轴停止值
CDROMSETSPINDOWN
设置 4 位主轴停止值
CDROMCLOSETRAY
CDROMEJECT 的对应操作
CDROM_SET_OPTIONS
设置行为选项
CDROM_CLEAR_OPTIONS
清除行为选项
CDROM_SELECT_SPEED
设置 CD-ROM 速度
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。
各个驱动程序可能会返回此处未列出的错误代码。
除非另有说明,否则所有数据结构和常量都在 <linux/cdrom.h> 中定义
- CDROMPAUSE
暂停音频操作
用法
ioctl(fd, CDROMPAUSE, 0);
- 输入
无
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- CDROMRESUME
恢复暂停的音频操作
用法
ioctl(fd, CDROMRESUME, 0);
- 输入
无
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- CDROMPLAYMSF
播放音频 MSF
(struct cdrom_msf)
用法
struct cdrom_msf msf; ioctl(fd, CDROMPLAYMSF, &msf);
- 输入
cdrom_msf 结构,描述要播放的音乐片段
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- 备注
MSF 代表分钟-秒-帧
LBA 代表逻辑块地址
片段被描述为开始和结束时间,其中每个时间被描述为分钟:秒:帧。 一帧是 1/75 秒。
- CDROMPLAYTRKIND
播放音频轨道/索引
(struct cdrom_ti)
用法
struct cdrom_ti ti; ioctl(fd, CDROMPLAYTRKIND, &ti);
- 输入
cdrom_ti 结构,描述要播放的音乐片段
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- 备注
片段被描述为开始和结束时间,其中每个时间被描述为轨道和索引。
- CDROMREADTOCHDR
读取 TOC 标头
(struct cdrom_tochdr)
用法
cdrom_tochdr header; ioctl(fd, CDROMREADTOCHDR, &header);
- 输入
cdrom_tochdr 结构
- 输出
cdrom_tochdr 结构
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- CDROMREADTOCENTRY
读取 TOC 条目
(struct cdrom_tocentry)
用法
struct cdrom_tocentry entry; ioctl(fd, CDROMREADTOCENTRY, &entry);
- 输入
cdrom_tocentry 结构
- 输出
cdrom_tocentry 结构
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
EINVAL entry.cdte_format 不是 CDROM_MSF 或 CDROM_LBA
EINVAL 请求的轨道超出范围
EIO 读取 TOC 时发生 I/O 错误
- 备注
TOC 代表目录表
MSF 代表分钟-秒-帧
LBA 代表逻辑块地址
- CDROMSTOP
停止 CDROM 驱动器
用法
ioctl(fd, CDROMSTOP, 0);
- 输入
无
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- 备注
对此 ioctl 的确切解释取决于设备,但大多数设备似乎会使驱动器停止旋转。
- CDROMSTART
启动 CDROM 驱动器
用法
ioctl(fd, CDROMSTART, 0);
- 输入
无
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- 备注
对此 ioctl 的确切解释取决于设备,但大多数设备似乎会使驱动器启动旋转和/或关闭托盘。 其他设备完全忽略 ioctl。
- CDROMEJECT
弹出 CDROM 媒体
用法
ioctl(fd, CDROMEJECT, 0);
- 输入
无
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备弹出功能
EBUSY 其他进程正在访问驱动器,或者门被锁定
- 备注
请参阅下面的 CDROM_LOCKDOOR。
- CDROMCLOSETRAY
CDROMEJECT 的对应操作
用法
ioctl(fd, CDROMCLOSETRAY, 0);
- 输入
无
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备关闭托盘的功能
EBUSY 其他进程正在访问驱动器,或者门被锁定
- 备注
请参阅下面的 CDROM_LOCKDOOR。
- CDROMVOLCTRL
控制输出音量 (struct cdrom_volctrl)
用法
struct cdrom_volctrl volume; ioctl(fd, CDROMVOLCTRL, &volume);
- 输入
cdrom_volctrl 结构,其中包含最多 4 个通道的音量。
- 输出
无
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- CDROMVOLREAD
获取驱动器的音量设置
(struct cdrom_volctrl)
用法
struct cdrom_volctrl volume; ioctl(fd, CDROMVOLREAD, &volume);
- 输入
无
- 输出
当前的音量设置。
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
- CDROMSUBCHNL
读取子通道数据
(struct cdrom_subchnl)
用法
struct cdrom_subchnl q; ioctl(fd, CDROMSUBCHNL, &q);
- 输入
cdrom_subchnl 结构
- 输出
cdrom_subchnl 结构
- 错误返回
ENOSYS cd 驱动器不具备音频功能。
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,<linux/cdrom.h> 中的注释表明此 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 位主轴停止值的值。
- CDROMSETSPINDOWN
已过时,以前仅限 ide-cd
用法
char spindown ioctl(fd, CDROMSETSPINDOWN, &spindown);
- 输入
用于控制主轴停止的 4 位值(TODO:此处提供更多详细信息)
- 输出
无
- CDROM_SET_OPTIONS
设置行为选项
用法
int options; ioctl(fd, CDROM_SET_OPTIONS, options);
- 输入
驱动器选项的新值。 逻辑“或”运算
CDO_AUTO_CLOSE
首次打开时关闭托盘 (2)
CDO_AUTO_EJECT
上次释放时打开托盘
CDO_USE_FFLAGS
在打开时使用 O_NONBLOCK 信息
CDO_LOCK
在打开的文件上锁定托盘
CDO_CHECK_TYPE
检查打开时的数据类型
- 输出
返回 ioctl 返回值中生成的选项设置。 错误时返回 -1。
- 错误返回
ENOSYS 驱动器不支持所选选项。
- CDROM_CLEAR_OPTIONS
清除行为选项
与 CDROM_SET_OPTIONS 相同,只是关闭所选选项。
- CDROM_SELECT_SPEED
设置 CD-ROM 速度
用法
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。
已更改,或者错误时返回 -1。
- 错误返回
ENOSYS 驱动器无法检测媒体更改
EINVAL 插槽号超出驱动器的容量
ENOMEM 内存不足
- CDROM_DRIVE_STATUS
获取托盘位置等
用法
int slot; ioctl(fd, CDROM_DRIVE_STATUS, slot);
- 输入
要测试的插槽号,除点唱机外始终为零。
也可以是特殊值 CDSL_NONE 或 CDSL_CURRENT
- 输出
Ioctl 返回值将为以下值之一
来自 <linux/cdrom.h>
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 返回值将为以下值之一
来自 <linux/cdrom.h>
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 值在 <linux/cdrom.h> 中定义,目前 (2.6.8.1) 与 EOPNOTSUPP 相同
- CDROM_DEBUG
打开/关闭调试消息
用法
int debug; ioctl(fd, CDROM_DEBUG, debug);
- 输入
Cdrom 调试标志,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 结构体,包含:
type
指定所需的信息,取值可以是 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 结构体,包含:
physical
当 type == DVD_STRUCT_PHYSICAL 时使用
copyright
当 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 结构体。请参阅 <linux/cdrom.h>
- 输出
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 返回错误。