📄 aztcd.c
字号:
##########################################################################*//* Macros for the drive hardware interface handshake, these macros use busy waiting *//* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/# define OP_OK op_ok()void op_ok(void){ aztTimeOutCount=0; do { aztIndatum=inb(DATA_PORT); aztTimeOutCount++; if (aztTimeOutCount>=AZT_TIMEOUT) { printk("aztcd: Error Wait OP_OK\n"); break; } } while (aztIndatum!=AFL_OP_OK);}/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/# define PA_OK pa_ok()void pa_ok(void){ aztTimeOutCount=0; do { aztIndatum=inb(DATA_PORT); aztTimeOutCount++; if (aztTimeOutCount>=AZT_TIMEOUT) { printk("aztcd: Error Wait PA_OK\n"); break; } } while (aztIndatum!=AFL_PA_OK);} /* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/# define STEN_LOW sten_low()void sten_low(void){ aztTimeOutCount=0; do { aztIndatum=inb(STATUS_PORT); aztTimeOutCount++; if (aztTimeOutCount>=AZT_TIMEOUT) { if (azt_init_end) printk("aztcd: Error Wait STEN_LOW commands:%x\n",aztCmd); break; } } while (aztIndatum&AFL_STATUS);}/* Wait for DTEN=Low = handshake signal 'Data available'*/# define DTEN_LOW dten_low()void dten_low(void){ aztTimeOutCount=0; do { aztIndatum=inb(STATUS_PORT); aztTimeOutCount++; if (aztTimeOutCount>=AZT_TIMEOUT) { printk("aztcd: Error Wait DTEN_OK\n"); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -