📄 dsa.c
字号:
CLEAR_DSA_DATA; tran_state = D_SYNC02; retry = 0; break; case D_SYNC02: /* When Rv lowers ACK; Tx pulls up DATA */ if (DSA_ACK_LOW) { SET_DSA_DATA; tran_state = D_SYNC03; retry = 0; } else { /* * Following code seems to avoid simultaneous transmission * start problem! */ SET_DSA_DATA; CLEAR_DSA_DATA; if (retry++ > 30) microEngine(); /* DSA not ready, talk with uP */ } break; case D_SYNC03: /* When Rv pulls up ACK, we are in sync */ if (DSA_ACK_HIGH) { mask = 0x80; dsa_byte = cmd; /* Command byte */ dsa_second = 0; tran_state = D_TRAN01; } else if (retry++ > 30) microEngine(); /* DSA not ready, talk with uP */ break; case D_TRAN01: /* Tx sets data then lowers STROBE */ if ((dsa_byte & mask) == 0) { CLEAR_DSA_DATA; } else { SET_DSA_DATA; } mask >>= 1; CLEAR_DSA_STROBE; tran_state = D_TRAN02; retry = 0; break; case D_TRAN02: /* Rv lowers ACK; Tx pulls up STROBE */ if (DSA_ACK_LOW) { SET_DSA_STROBE; tran_state = D_TRAN03; retry = 0; } else if (retry++ > 30) microEngine(); /* DSA not ready, talk with uP */ break; case D_TRAN03: /* Rv pulls ACK; one bit done */ if (DSA_ACK_HIGH) { if (mask == 0) { /* 8b sent */ mask = 0x80; if (dsa_second) { /* Both bytes are sent */ /* Prepare for communication acknowledge phase */ SET_DSA_STROBE; SET_DSA_DATA; CLEAR_DSA_ACK; /* Tx lowers ACK */ tran_state = D_ACK02; retry = 0; } else { /* Only 1 byte sent */ dsa_second = 1; dsa_byte = data; tran_state = D_TRAN01; } } else tran_state = D_TRAN01; } else if (retry++ > 30) microEngine(); /* DSA not ready, talk with uP */ break; case D_ACK02: /* Rv lowers STROBE */ TDSATimeCount++; if (TDSATimeCount > 0xfff) { /* Time out */ CPRINTF("TRE RETRY", TDSATimeCount); SET_DSA_STROBE; /* Resync */ SET_DSA_DATA; SET_DSA_ACK; tran_state = D_IDLE; /* Transmission failed */ } else { if (DSA_STROBE_LOW) { /* Rv lowers STROBE; Tx pulls ACK*/ SET_DSA_ACK; SET_DSA_STROBE; SET_DSA_DATA; tran_state = D_IDLE; DEBUGASSIGN(dbgMaxTranElapse, (elapsed > dbgMaxTranElapse) ? elapsed : dbgMaxTranElapse); return; } else if (retry++ > 30) microEngine(); /* DSA not ready, talk with uP */ } break; default: break; } /* End of Switch(tran_state) */ }}/* receive information from CD *//* return dsa_word */void receive_dsa(void){ char r_tmp; int CDDA_intro_time; /* * Talk with uP while receiving from DSA. Otherwise, uP may be * left out for long period of time, and it may think E3204 is * dead. */ microEngine();#ifdef ECHO MIC_service();#endif /* * If we are lost in the communication for too long, then try to * recover it! */ if (RDSATimeCount > 0x1800) { /* Max I see is ~0x500 */ rec_state = R_IDLE; RDSATimeCount = 0; DEBUGINC(1, dbgDSArcv); dsa_word = SERVO_ERROR << 8; /* Return error (whatever kind) */ dsa_flag = 0; /* Breaks to avoid infinite loop*/ CPRINTF("REC RETRY", dsa_word); return; } if (rec_state != R_IDLE) { RDSATimeCount++; DEBUGASSIGN(dbgMaxRDSA, (RDSATimeCount > dbgMaxRDSA) ? RDSATimeCount : dbgMaxRDSA); } switch (rec_state) { case R_IDLE: /* Tx lowers DATA to indicate intend for SYNC */ SET_DSA_ACK; SET_DSA_DATA; SET_DSA_STROBE; if (DSA_DATA_LOW) { /* Tx starts SYNC; Rv lowers ACK */ CLEAR_DSA_ACK; dsa_rcv_mask = 0x8000; /* Most significant bit first */ dsa_word = 0; rec_state = R_W_SYNC1; } break; case R_W_SYNC1: /* Tx pulls up DATA; Rv pulls up ACK; SYNC done */ RDSATimeCount = 0; if (DSA_DATA_HIGH) { SET_DSA_ACK; rec_state = R_REC0; } break; /* data tranmission */ /* wait ST to 0 */ /* if it is 0, set ACK to 0 */ case R_REC0: /* Tx lowers STROBE; Rv gets DATA then lower ACK*/ if (DSA_STROBE_LOW) { if (DSA_DATA_HIGH) dsa_word |= dsa_rcv_mask; dsa_rcv_mask >>= 1; CLEAR_DSA_ACK; rec_state = R_REC1; } break; /* wait ST to 1 */ /* if it is 1, set ACK to 1 */ case R_REC1: /* Tx raises STROBE; Rv raises ACK (1b done) */ if (DSA_STROBE_HIGH) { SET_DSA_ACK; rec_state = (dsa_rcv_mask == 0) ? R_W_ACK0 : R_REC0; } break; case R_W_ACK0: /* Tx lowers ACK when done; Rv lowers STROBE */ if (DSA_ACK_LOW) { SET_DSA_DATA; /* Receive count is correct. */ CLEAR_DSA_STROBE; rec_state = R_W_ACK1; } break; case R_W_ACK1: /* Tx raises ACK; Rv raises STROBE (done) */ if (DSA_ACK_HIGH) { SET_DSA_STROBE; DEBUGASSIGN(dbgReceiveDsa, dsa_word); /* Got the data */ r_tmp = (dsa_word >> 8) & 0xff; if (r_tmp == SERVO_SEC) { r_tmp = dsa_word & 0xff; /* update seconds */ servo_info &= ~((uint)0xff); servo_info |= (uint)hex2bcd[r_tmp];#ifdef ANTI_SHOCK /* for CDDA */ SERVO_cdtime = adjCDtime(CDDA_track_start_time, (servo_info & 0xffff) << 8, 1);#endif dsa_word = 0; /* Filter out timing info. */ OSD_update_time = 1; } else if (r_tmp == SERVO_MIN) { r_tmp = dsa_word & 0xff; /* update minutes */ servo_info &= ~((uint)0xff00); servo_info |= (uint)hex2bcd[r_tmp] << 8; dsa_word = 0; /* Filter out timing info. */ OSD_update_time = 1; } else if (r_tmp == SERVO_INDEX) { r_tmp = dsa_word & 0xff; /* update index */ servo_info &= ~((uint)0xff00 << 8); servo_info |= (uint)hex2bcd[r_tmp] << 16; dsa_word = 0; /* Filter out timing info. */ } else if (r_tmp == SERVO_TRACK) { /* CDDA's track number is different from video */ r_tmp = (dsa_word & 0xff) - (CDinfo.type != CD_CDDA); /* Used to inform that new track has come. * ignore it until ~10 secs before track end. */ if ((cur_track_number == bcd2hex[servo_info>>24]) && (AV_near_track_end_time < (servo_info & 0xffff))) {#ifdef FAST_MODE_CONTROL if (!fast_mode_ctrl)#endif { AV_near_track_end_time = xINFINITY; servo_track_changed = 1; } } /* * When servo_track changes, also clear servo_min/sec. * Otherwise, for short audio tracks, we may stop * early because of the left over servo_min/sec. */ servo_info = (uint)hex2bcd[r_tmp] << 24; dsa_word = 0; /* Filter out timing info. */ OSD_update_time = 1; } else if (r_tmp == SERVO_CLOSED) { cd_tray_closed(); } dsa_flag = 0; rec_state = R_IDLE; } break; default: break; } /* End of Switch(rec_state) */ if (OSD_update_time) { OSD_update_time = 0; /* use servo time to check end of play */ if (TDM_isCDDA) { /* only do it when we received second */ int tmp_time; tmp_time = ((servo_info & 0xffff) << 8); if (second_endCDtime != xMAX_CDTIME) /* intro mode */ { CDDA_intro_time = adjCDtime(second_endCDtime, CDDA_track_start_time, -1); } else { CDDA_intro_time = xMAX_CDTIME; } if ((CDDA_play_time <= tmp_time) || (CDDA_intro_time <= tmp_time)|| /* victor: because of the ATTI_REL mode and some wrongly encoded CD might have incorrect track info, there is a possibility that CDDA_play_time hasn't been reached before a new track occurs(ABEX), we add a check on the new track here. */ (servo_track_changed)){ end_of_play = 1; servo_track_changed = 0; /* reset it, very important */ } } OSD_update_info(); /* OSD info needs to update */ }}/* * Receive data from servo. Since receive_dsa filters out disk's timing * information (and set dsa_word to 0), we'll retry up to 3 times to * get non-timing information. * * Input * quit_on_any: * Return with anything (including tk/index/mm/ss). Setting of this * flag will also force something to be returned (i.e. even if * forceDSAabort is set, we'll not abort and return). * * Return: * 1: If successful or exhaust 3 retries. * 0: If force to quit due to forceDSAabort * * Side effect: * Global variable dsa_word has the non-timing info received from * servo. * */int receive_dsa_all(quit_on_any)int quit_on_any;{ int retry = 3; int count; unsigned int prevClock, elapsed; do { DEBUGASSIGN(count, 0); dsa_flag = 1; prevClock = glbTimer; do { DEBUGINC(1, count); DEBUGASSIGN(dbgMaxRcvAll, (count > dbgMaxRcvAll) ? count : dbgMaxRcvAll); /* glbTimer is updated in the interrupt handler */ elapsed = glbTimer - prevClock; if (elapsed > TEN_SECOND) { DEBUGINC(1, dbgServoRcv); /* * We have been here for 10 seconds, that's way too long for * receive_dsa_all. It is unlikely we are ever going to * receive anything. Let's break out of here and return error. * * I have seen elapsed time of 6.5 seconds. */ dsa_word = SERVO_ERROR << 8; rec_state = R_IDLE; /* Terminate receive. */ /* !!! Need to be more robust!! */ break; } receive_dsa(); /* * If we have received a higher priority command, then * quit and go handle the higher priroity command. Don't * wait to finish reciving, whatever we are getting is * garbage anyway. */ if (forceDSAabort) return(0); } while (dsa_flag); DEBUGASSIGN(dbgMaxRcvElapse, (elapsed > dbgMaxRcvElapse) ? elapsed : dbgMaxRcvElapse); if (dsa_word || quit_on_any) break; } while (--retry); return(1);}/************************************************** DSA operation function***************************************************//* * Set CD-module's modes. * * NOTE: SERVO has a bug, if it receives 2 trans_dsa(DSA_mode, mode) in * a "short" period of time, the mode is actually not changed * even though it will report the mode has been changed. * * Therefore, we can't use the standard way to retry dsa_mode. * At track boundary, we'll get SERVO_TRACK, SERVO_INDEX, SERVO_MIN, * and receive_dsa_all only retries 3 time, so we many not get * a chance to see SERVO_MODE_STATUS if we just retry like other * cases. * * When going into DOUBLE speed, the servo usually takes around * 1 second to respond! When going into NORMAL speed, the response * time is a lot shorter. * * Input: * mode: set CD's mode * * Return: * 0: fail * 1: successful */int dsa_mode(mode)int mode;{ int retry = 2; int force_quit; /* 1: force abort; 0: receive OK */ unsigned int nextTimer; DISP_naicigam(); if (currDSAmode == mode) return; currDSAmode = mode; do { trans_dsa(DSA_MODE, mode); /* Give up to 1 second for SERVO_MODE_STATUS reply */ nextTimer = glbTimer + TWO_SECOND; do { force_quit = !receive_dsa_all(0); if (force_quit || dsa_word) break; } while (glbTimer <= nextTimer); if ((dsa_word == ((SERVO_MODE_STATUS << 8) | mode)) || force_quit) return(1); } while (--retry); DEBUGASSIGN(dbgDSAmode, dsa_word); err_code = ERR_DSAMODE; return(0);}/* * This function simulates real dsa_release function by set the CDDA_play_time * to a big number, so the end_of_play will not be set until a track change. * * Return: * 1: successful */int dsa_release(unsigned int track_start, unsigned int track_end){ CDDA_play_time = adjCDtime(track_end, track_start, -1); return (1);}/* * Close the tray. Servo answers with TRAY MOVING (which we ignore) * and TRAY CLOSED command. */int dsa_close(int power_down){ int tmp;#ifndef THREE_CDS int retry = 2; int force_quit; /* 1: force abort; 0: receive OK */#ifdef SERVO_7 /* for the new PHLIPS LOADER 7001, we have to send * a Clear Toc command before close */ dsa_cleartoc();#endif /* SERVO_7 */ do { trans_dsa(DSA_CLOSE, 0); do { force_quit = !receive_dsa_all(0); tmp = (dsa_word >> 8) & 0xff; if ((tmp == SERVO_CLOSED) || force_quit) return(1); /* Closed*/ else if (tmp == SERVO_ERROR) return(0); /* Loader open */ else if (tmp == SERVO_MOVING) continue; /* Intermediate */ else break; /* Unexpected result */ } while (1); } while (--retry); /* Retry if we get unexpected result */#else /* If not powering down, for 3-CD loaders we just send the command * and return..for smoother playing. */#ifdef SERVO_6003 TRAY_CLOSE;#else trans_dsa(DSA_CLOSE, 0);#endif if (power_down) {#ifdef SERVO_6003 cd_opened = 1; eject_6003_retry = 2; TRAY_CLOSE;#else do { receive_dsa_all(0); tmp = (dsa_word >> 8) & 0xff; if (tmp == SERVO_CLOSED) return(1); /* Closed*/ else if (tmp == SERVO_MOVING) continue; /* Intermediate */ else break; /* Unexpected result */ } while (1);#endif }#endif /* THREE_CDS */ DEBUGASSIGN(dbgDSAclose, dsa_word); return(0);}/* This command clears the TOC info stored in memory, and is only allowed * in stop mode. The command must be sent at disc change in case of * single tray loader, or top loader applications. */int dsa_cleartoc(void){ int retry = 2; int force_quit; /* 1: force abort; 0: receive OK */ do { trans_dsa(DSA_CLEARTOC, 0); force_quit = !receive_dsa_all(0); if (((dsa_word & 0xff00) == (SERVO_CLEARTOCED << 8)) || force_quit) return(1); } while (--retry); /* Shall never get here! */ DEBUGASSIGN(dbgDSAcleartoc, dsa_word); return(0);}/* * Opens the tray. If the CD-module is in PLAY mode, it first performs * a STOP procedure before the tray opens. When the moving of the tray * starts, the CD-module send the TRAY MOVING command (we ignore). Then * we we'll get TRAY OPENED. This command clears the internal 'pause mode * indicator. */int dsa_open(void){#ifndef THREE_CDS int tmp; int retry = 2; /* Retry twice */ int force_quit; /* 1: force abort; 0: receive OK */ DISP_naicigam();#ifdef SERVO_7 /* for the new PHLIPS LOADER, we have to send a stop command before open */ if (!cd_stop) dsa_stop();#endif /* SERVO_7 */ do { trans_dsa(DSA_OPEN, 0); do { force_quit = !receive_dsa_all(0); tmp = (dsa_word >> 8) & 0xff; if ((tmp == SERVO_OPENED) || force_quit) { /* Reset OSD info when we open CD drive */ servo_info = 0; num_of_track = 0; return(1); /* Opened */ } else if (tmp == SERVO_MOVING) continue; /* Intermediate */ else break; /* Unexpected result */ } while (1); } while (--retry); /* Retry if we get unexpected result */#else /* For 3-CD loaders we just send the command and return.. * for smoother playing. */#ifdef SERVO_6003 TRAY_OPEN;#else trans_dsa(DSA_OPEN, 0);#endif#endif /* THREE_CDS */ DEBUGASSIGN(dbgDSAopen, dsa_word); return(0);}/* * Stops playing the disk and brakes. This command also clears the * internal 'pause mode indicator' */int dsa_stop(void){ int retry = 2; int force_quit; /* 1: force abort; 0: receive OK */ DISP_naicigam(); do {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -