好久没有来了, 想不到还有不少人关注
分享一下源码....
/***************************************************************************
name: atapiEject
action: loads or ejects CD-ROM
returns:whatever atapiCmd() returns
****************************************************************************/
static int atapiEject(driveinfo *Drive, bool Load)
{
u8 Pkt={ATAPI_CMD_START_STOP, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
drivecmd Cmd;
printf("atapiEject:");
memset(&Cmd, 0, sizeof(Cmd));
Pkt= (Load ? 3 : 2);
return(atapiCmd(Drive, &Cmd, Pkt));
}
/***************************************************************************
name: atapiGetEventStatus
action: Get Disc is present && Tray opend or Closed
returns: whatever atapiCmd() returns
****************************************************************************/
static int atapiGetEventStatus(driveinfo *Drive, u8 *Buffer, unsigned Count)
{
u8 Pkt={ATAPI_CMD_GET_EVENT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
drivecmd Cmd;
printf("atapiGetEventStatus:");
memset(&Cmd, 0, sizeof(Cmd));
Cmd.Count=Count;
Cmd.Data=Buffer;
Pkt=1;
Pkt=0x10;
Pkt=Count;
return(atapiCmd(Drive, &Cmd, Pkt));
}
/***************************************************************************
name: atapiChkTrayIsOpen
action: check cd-rom tray opened or closed
returns: 1 is opend , 0 is closed and -1 is Error
****************************************************************************/
static int atapiChkTrayIsOpen(driveinfo *Drive)
{
u8 Buffer;
int Temp;
Temp=atapiGetEventStatus(Drive, Buffer, 6);
if (Temp != 0)
{
return(-1);
}
return(Buffer&0x01); // Bit 0 is Tray Status, See SFF-8090 v6R7 P362
}
/***************************************************************************
name: atapiTOCEnt
action: reads one or more table-of-contents entries from audio CD
returns:whatever atapiCmd() returns
****************************************************************************/
static int atapiTOCEnt(driveinfo *Drive, u8 *Buffer, unsigned Count)
{
u8 Pkt={ATAPI_CMD_READTOC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
drivecmd Cmd;
printf("atapiTOCEnt:");
memset(&Cmd, 0, sizeof(Cmd));
Cmd.Count=Count;
Cmd.Data=Buffer;
Pkt=2;
Pkt=Count >> 8;
Pkt=Count;
return(atapiCmd(Drive, &Cmd, Pkt));
}
/***************************************************************************
name: atapiTOC
action: reads table of contents of audio CD and prints starting
time of each track
returns:whatever atapiCmd() returns
****************************************************************************/
static int atapiTOC(driveinfo *Drive)
{
u8 *Entry, Buffer;
int TOCEnt, Temp;
printf("atapiTOC:\n");
// 16-bit TOC length, 8-bit first track, 8-bit last track
TOCEnt = 4;
#ifdef DEBUG
printf(" calling atapiTOCEnt with Count=%u\n", TOCEnt);
#endif
// Read TOC
Temp=atapiTOCEnt(Drive, Buffer, TOCEnt);
if(Temp != 0)
{
return(Temp);
}
// NumTracks = LastTrack - FristTrack + 1
NumTracks=Buffer - Buffer + 1;
// Check NumTracks(must in range 1~99)
if(NumTracks <= 0 || NumTracks > 99)
{
printf(" error: bad number of tracks %d\n", NumTracks);
return(-1);
}
// Check MAX_TRACKS handle
if(NumTracks > MAX_TRACKS)
{
printf(" warning: too many tracks(%u); reducing to %u.\n",NumTracks, MAX_TRACKS);
NumTracks=MAX_TRACKS;
}
// read 4-byte header and 8-byte table-of-contents entries
TOCEnt = 4 + 8 * (NumTracks+1);
#ifdef DEBUG
printf(" calling atapiTOCEnt with Count=%u\n", TOCEnt);
#endif
// Read TOC
Temp=atapiTOCEnt(Drive, Buffer, TOCEnt);
if(Temp != 0)
{
return(Temp);
}
// point to first TOC entry
Entry=Buffer + 4;
// read NumTracks+1 entries the last entry is for the disk lead-out
for(Temp=0; Temp < NumTracks + 1; Temp++)
{
Track.Min=Entry;
Track.Sec=Entry;
Track.Frame=Entry;
printf("%02u:%02u:%02u ", Track.Min, Track.Sec, Track.Frame);
// advance to next entry
Entry += 8;
}
printf("\n");
return(0);
}
/***************************************************************************
name: atapiPlay
action: plays audio from time index Start to End (units of 1/75 sec)
returns:whatever atapiCmd() returns
****************************************************************************/
static int atapiPlay(driveinfo *Drive, atapimsf *Start, atapimsf *End)
{
u8 Pkt={ATAPI_CMD_PLAY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
drivecmd Cmd;
printf("atapiPlay:");
memset(&Cmd, 0, sizeof(Cmd));
Pkt=Start->Min;
Pkt=Start->Sec;
Pkt=Start->Frame;
Pkt=End->Min;
Pkt=End->Sec;
Pkt=End->Frame;
return(atapiCmd(Drive, &Cmd, Pkt));
}
/***************************************************************************
name: atapiPause
action: pauses or continues audio CD
returns:whatever atapiCmd() returns
****************************************************************************/
static int atapiPause(driveinfo *Drive, bool Continue)
{
u8 Pkt={ATAPI_CMD_PAUSE,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
drivecmd Cmd;
printf("atapiPause:");
memset(&Cmd, 0, sizeof(Cmd));
Pkt=Continue ? 1 : 0;
return(atapiCmd(Drive, &Cmd, Pkt));
}
/***************************************************************************
name: atapiStop
action: stop audio play or scan
return: whatever atapiCmd() returns
****************************************************************************/
static int atapiStop(driveinfo *Drive)
{
u8 Pkt={ATAPI_CMD_STOP,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
drivecmd Cmd;
printf("atapiStop:");
memset(&Cmd, 0, sizeof(Cmd));
return(atapiCmd(Drive, &Cmd, Pkt));
}
LLM 解释
ATAPI CD-ROM 控制功能模块解析
模块概述
该代码实现了通过ATAPI命令集控制CD-ROM设备的核心功能,包括托盘操作、TOC读取、播放控制等,适用于DOS环境下的CD播放应用开发。代码采用模块化设计,每个函数封装特定的ATAPI命令,通过构造12字节CDB(Command Descriptor Block)实现与CD-ROM驱动器的通信。
核心功能解析
1. 托盘控制函数
static int atapiEject(driveinfo *Drive, bool Load)
-
功能:控制CD-ROM托盘弹出/关闭
-
实现细节:
- 使用
ATAPI_CMD_START_STOP
命令(0x1B)
- Pkt[4]位设置操作模式:0x03为关闭托盘,0x02为弹出托盘
- 通过
atapiCmd()
发送命令并返回执行结果
2. 托盘状态检测
static int atapiChkTrayIsOpen(driveinfo *Drive)
-
功能:检测托盘当前状态(打开/关闭)
-
技术要点:
- 调用
atapiGetEventStatus()
获取事件状态
- 解析返回缓冲区第5字节的第0位(依据SFF-8090 v6R7规范P362)
- 返回值定义:1(打开)/0(关闭)/-1(错误)
3. TOC(目录表)读取
static int atapiTOC(driveinfo *Drive)
-
功能:读取CD音轨信息并存储音轨起始时间
-
处理流程:
- 首次读取4字节获取TOC头部(包含首尾轨号)
- 计算音轨数量并校验有效性(1-99范围)
- 二次读取完整TOC数据(4字节头 + 8字节/轨 × (轨数+1))
- 解析每个音轨的起始时间(分:秒:帧格式)
-
数据结构:使用
Track[]
数组存储各轨MSF(分/秒/帧)信息
4. 播放控制函数集
-
播放:
atapiPlay()
使用ATAPI_CMD_PLAY
命令(0x43),通过Pkt[3-5]和Pkt[6-8]设置起止MSF时间
-
暂停/继续:
atapiPause()
使用ATAPI_CMD_PAUSE
命令(0x4B),Pkt[8]位控制暂停(0)或继续(1)
-
停止:
atapiStop()
使用ATAPI_CMD_STOP
命令(0x4E)终止当前播放
技术特点与兼容性
-
ATAPI命令规范:严格遵循SCSI-2/ATAPI标准,命令包(CDB)长度固定为12字节,符合大多数IDE/ATAPI CD-ROM驱动器要求
-
错误处理:每个函数返回atapiCmd()
的执行结果,便于上层调用者处理硬件通信错误
-
调试支持:通过#ifdef DEBUG
条件编译提供调试信息输出,便于开发阶段问题定位
-
资源限制:定义MAX_TRACKS
宏限制最大处理音轨数,防止缓冲区溢出
潜在优化方向
-
错误信息增强:可添加ATAPI错误码解析,提供更具体的故障原因
-
多驱动器支持:扩展
driveinfo
结构以支持多CD-ROM设备枚举
-
播放状态查询:实现
ATAPI_CMD_GET_PERFORMANCE
命令获取实时播放位置
-
DOS环境适配:需补充实模式下的端口I/O函数(
inb
/outb
)及中断处理代码
使用注意事项
- 需实现
atapiCmd()
函数完成底层ATAPI命令发送与数据传输
-
driveinfo
结构需包含CD-ROM驱动器的端口地址、DMA通道等硬件信息
- 在DOS环境下使用时需注意内存模式(实模式/保护模式)对指针操作的影响
- 音轨时间以CD标准帧率(75帧/秒)存储,转换为标准时间需进行帧到秒的换算
该模块可作为DOS/WIN两栖CD播放程序的底层驱动,通过条件编译区分不同环境下的I/O实现,从而达到跨平台兼容的目标。