📄 aztcd.c
字号:
break;
}
} while (aztIndatum & AFL_DATA);
}
/*
* Macro for timer wait on STEN=Low, should only be used for 'slow' commands;
* may cause kernel panic when used in the wrong place
*/
#define STEN_LOW_WAIT statusAzt()
void statusAzt(void)
{
AztTimeout = AZT_STATUS_DELAY;
SET_TIMER(aztStatTimer, HZ / 100);
sleep_on(&azt_waitq);
if (AztTimeout <= 0)
printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",
aztCmd);
return;
}
static void aztStatTimer(void)
{
if (!(inb(STATUS_PORT) & AFL_STATUS)) {
wake_up(&azt_waitq);
return;
}
AztTimeout--;
if (AztTimeout <= 0) {
wake_up(&azt_waitq);
printk("aztcd: Error aztStatTimer: Timeout\n");
return;
}
SET_TIMER(aztStatTimer, HZ / 100);
}
/*##########################################################################
CDROM Drive Command Functions
##########################################################################
*/
/*
* Send a single command, return -1 on error, else 0
*/
static int aztSendCmd(int cmd)
{
unsigned char data;
int retry;
#ifdef AZT_DEBUG
printk("aztcd: Executing command %x\n", cmd);
#endif
if ((azt_port == 0x1f0) || (azt_port == 0x170))
SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */
aztCmd = cmd;
outb(POLLED, MODE_PORT);
do {
if (inb(STATUS_PORT) & AFL_STATUS)
break;
inb(DATA_PORT); /* if status left from last command, read and */
} while (1); /* discard it */
do {
if (inb(STATUS_PORT) & AFL_DATA)
break;
inb(DATA_PORT); /* if data left from last command, read and */
} while (1); /* discard it */
for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
outb((unsigned char) cmd, CMD_PORT);
STEN_LOW;
data = inb(DATA_PORT);
if (data == AFL_OP_OK) {
return 0;
} /*OP_OK? */
if (data == AFL_OP_ERR) {
STEN_LOW;
data = inb(DATA_PORT);
printk
("### Error 1 aztcd: aztSendCmd %x Error Code %x\n",
cmd, data);
}
}
if (retry >= AZT_RETRY_ATTEMPTS) {
printk("### Error 2 aztcd: aztSendCmd %x \n", cmd);
azt_error = 0xA5;
}
RETURNM("aztSendCmd", -1);
}
/*
* Send a play or read command to the drive, return -1 on error, else 0
*/
static int sendAztCmd(int cmd, struct azt_Play_msf *params)
{
unsigned char data;
int retry;
#ifdef AZT_DEBUG
printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n",
params->start.min, params->start.sec, params->start.frame,
params->end.min, params->end.sec, params->end.frame);
#endif
for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
aztSendCmd(cmd);
outb(params->start.min, CMD_PORT);
outb(params->start.sec, CMD_PORT);
outb(params->start.frame, CMD_PORT);
outb(params->end.min, CMD_PORT);
outb(params->end.sec, CMD_PORT);
outb(params->end.frame, CMD_PORT);
STEN_LOW;
data = inb(DATA_PORT);
if (data == AFL_PA_OK) {
return 0;
} /*PA_OK ? */
if (data == AFL_PA_ERR) {
STEN_LOW;
data = inb(DATA_PORT);
printk
("### Error 1 aztcd: sendAztCmd %x Error Code %x\n",
cmd, data);
}
}
if (retry >= AZT_RETRY_ATTEMPTS) {
printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd);
azt_error = 0xA5;
}
RETURNM("sendAztCmd", -1);
}
/*
* Send a seek command to the drive, return -1 on error, else 0
*/
static int aztSeek(struct azt_Play_msf *params)
{
unsigned char data;
int retry;
#ifdef AZT_DEBUG
printk("aztcd: aztSeek %02x:%02x:%02x\n",
params->start.min, params->start.sec, params->start.frame);
#endif
for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
aztSendCmd(ACMD_SEEK);
outb(params->start.min, CMD_PORT);
outb(params->start.sec, CMD_PORT);
outb(params->start.frame, CMD_PORT);
STEN_LOW;
data = inb(DATA_PORT);
if (data == AFL_PA_OK) {
return 0;
} /*PA_OK ? */
if (data == AFL_PA_ERR) {
STEN_LOW;
data = inb(DATA_PORT);
printk("### Error 1 aztcd: aztSeek\n");
}
}
if (retry >= AZT_RETRY_ATTEMPTS) {
printk("### Error 2 aztcd: aztSeek\n ");
azt_error = 0xA5;
}
RETURNM("aztSeek", -1);
}
/* Send a Set Disk Type command
does not seem to work with Aztech drives, behavior is completely indepen-
dent on which mode is set ???
*/
static int aztSetDiskType(int type)
{
unsigned char data;
int retry;
#ifdef AZT_DEBUG
printk("aztcd: set disk type command: type= %i\n", type);
#endif
for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
aztSendCmd(ACMD_SET_DISK_TYPE);
outb(type, CMD_PORT);
STEN_LOW;
data = inb(DATA_PORT);
if (data == AFL_PA_OK) { /*PA_OK ? */
azt_read_mode = type;
return 0;
}
if (data == AFL_PA_ERR) {
STEN_LOW;
data = inb(DATA_PORT);
printk
("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",
type, data);
}
}
if (retry >= AZT_RETRY_ATTEMPTS) {
printk("### Error 2 aztcd: aztSetDiskType %x\n ", type);
azt_error = 0xA5;
}
RETURNM("aztSetDiskType", -1);
}
/* used in azt_poll to poll the status, expects another program to issue a
* ACMD_GET_STATUS directly before
*/
static int aztStatus(void)
{
int st;
/* int i;
i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ???
if (!i)
*/ STEN_LOW;
if (aztTimeOutCount < AZT_TIMEOUT) {
st = inb(DATA_PORT) & 0xFF;
return st;
} else
RETURNM("aztStatus", -1);
}
/*
* Get the drive status
*/
static int getAztStatus(void)
{
int st;
if (aztSendCmd(ACMD_GET_STATUS))
RETURNM("getAztStatus 1", -1);
STEN_LOW;
st = inb(DATA_PORT) & 0xFF;
#ifdef AZT_DEBUG
printk("aztcd: Status = %x\n", st);
#endif
if ((st == 0xFF) || (st & AST_CMD_CHECK)) {
printk
("aztcd: AST_CMD_CHECK error or no status available\n");
return -1;
}
if (((st & AST_MODE_BITS) != AST_BUSY)
&& (aztAudioStatus == CDROM_AUDIO_PLAY))
/* XXX might be an error? look at q-channel? */
aztAudioStatus = CDROM_AUDIO_COMPLETED;
if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) {
aztDiskChanged = 1;
aztTocUpToDate = 0;
aztAudioStatus = CDROM_AUDIO_NO_STATUS;
}
return st;
}
/*
* Send a 'Play' command and get the status. Use only from the top half.
*/
static int aztPlay(struct azt_Play_msf *arg)
{
if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0)
RETURNM("aztPlay", -1);
return 0;
}
/*
* Subroutines to automatically close the door (tray) and
* lock it closed when the cd is mounted. Leave the tray
* locking as an option
*/
static void aztCloseDoor(void)
{
aztSendCmd(ACMD_CLOSE);
STEN_LOW;
return;
}
static void aztLockDoor(void)
{
#if AZT_ALLOW_TRAY_LOCK
aztSendCmd(ACMD_LOCK);
STEN_LOW;
#endif
return;
}
static void aztUnlockDoor(void)
{
#if AZT_ALLOW_TRAY_LOCK
aztSendCmd(ACMD_UNLOCK);
STEN_LOW;
#endif
return;
}
/*
* Read a value from the drive. Should return quickly, so a busy wait
* is used to avoid excessive rescheduling. The read command itself must
* be issued with aztSendCmd() directly before
*/
static int aztGetValue(unsigned char *result)
{
int s;
STEN_LOW;
if (aztTimeOutCount >= AZT_TIMEOUT) {
printk("aztcd: aztGetValue timeout\n");
return -1;
}
s = inb(DATA_PORT) & 0xFF;
*result = (unsigned char) s;
return 0;
}
/*
* Read the current Q-channel info. Also used for reading the
* table of contents.
*/
int aztGetQChannelInfo(struct azt_Toc *qp)
{
unsigned char notUsed;
int st;
#ifdef AZT_DEBUG
printk("aztcd: starting aztGetQChannelInfo Time:%li\n", jiffies);
#endif
if ((st = getAztStatus()) == -1)
RETURNM("aztGetQChannelInfo 1", -1);
if (aztSendCmd(ACMD_GET_Q_CHANNEL))
RETURNM("aztGetQChannelInfo 2", -1);
/*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */
if (aztGetValue(¬Used))
RETURNM("aztGetQChannelInfo 3", -1); /*??? Nullbyte einlesen */
if ((st & AST_MODE_BITS) == AST_INITIAL) {
qp->ctrl_addr = 0; /* when audio stop ACMD_GET_Q_CHANNEL returns */
qp->track = 0; /* only one byte with Aztech drives */
qp->pointIndex = 0;
qp->trackTime.min = 0;
qp->trackTime.sec = 0;
qp->trackTime.frame = 0;
qp->diskTime.min = 0;
qp->diskTime.sec = 0;
qp->diskTime.frame = 0;
return 0;
} else {
if (aztGetValue(&qp->ctrl_addr) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->track) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->pointIndex) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->trackTime.min) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->trackTime.sec) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->trackTime.frame) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(¬Used) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->diskTime.min) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->diskTime.sec) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
if (aztGetValue(&qp->diskTime.frame) < 0)
RETURNM("aztGetQChannelInfo 4", -1);
}
#ifdef AZT_DEBUG
printk("aztcd: exiting aztGetQChannelInfo Time:%li\n", jiffies);
#endif
return 0;
}
/*
* Read the table of contents (TOC) and TOC header if necessary
*/
static int aztUpdateToc()
{
int st;
#ifdef AZT_DEBUG
printk("aztcd: starting aztUpdateToc Time:%li\n", jiffies);
#endif
if (aztTocUpToDate)
return 0;
if (aztGetDiskInfo() < 0)
return -EIO;
if (aztGetToc(0) < 0)
return -EIO;
/*audio disk detection
with my Aztech drive there is no audio status bit, so I use the copy
protection bit of the first track. If this track is copy protected
(copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */
if (!(Toc[DiskInfo.first].ctrl_addr & 0x40))
DiskInfo.audio = 1;
else
DiskInfo.audio = 0;
/* XA detection */
if (!DiskInfo.audio) {
azt_Play.start.min = 0; /*XA detection only seems to work */
azt_Play.start.sec = 2; /*when we play a track */
azt_Play.start.frame = 0;
azt_Play.end.min = 0;
azt_Play.end.sec = 0;
azt_Play.end.frame = 1;
if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
return -1;
DTEN_LOW;
for (st = 0; st < CD_FRAMESIZE; st++)
inb(DATA_PORT);
}
DiskInfo.xa = getAztStatus() & AST_MODE;
if (DiskInfo.xa) {
printk
("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n");
}
/*multisession detection
support for multisession CDs is done automatically with Aztech drives,
we don't have to take care about TOC redirection; if we want the isofs
to take care about redirection, we have to set AZT_MULTISESSION to 1 */
DiskInfo.multi = 0;
#if AZT_MULTISESSION
if (DiskInfo.xa) {
aztGetMultiDiskInfo(); /*here Disk.Info.multi is set */
}
#endif
if (DiskInfo.multi) {
DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min;
DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec;
DiskInfo.lastSession.frame =
Toc[DiskInfo.next].diskTime.frame;
printk("aztcd: Multisession support experimental\n");
} else {
DiskInfo.lastSession.min =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -