📄 tdm.c
字号:
/* Copyright 1997, ESS Technology, Inc. *//* SCCSID @(#)tdm.c 1.121 3/30/98 */#include "common.h"#include "const.h"#include "buffer.h"#include "constvar.h"#include "debug.h"#include "mvd.h"#include "pts.h"#include "tact.h"#include "tdm.h"#include "util.h"#include "vcxi.h"#include "xport.h"#include "timedef.h"#include "play.h"#include "fsosd.h"#ifdef SVCD#include "mpegvid.h"#else#include "mpeg1vid.h"#endif#ifdef CUST4#include "ioport.h"#include "dsa4.h"#endif/************************************************************************ * Local defines. * ************************************************************************//* Definition for CD's submode byte. */#define CDSUBMODE_EOR 0x100 /* End of record (last sector * * of a logical record.) */#define CDSUBMODE_V 0x200 /* Video sector */#define CDSUBMODE_A 0x400 /* Audio sector */#define CDSUBMODE_D 0x800 /* Data (program related data) */#define CDSUBMODE_T 0x1000 /* Trigger (when set to 1 * * generates a interrupt for * * synchronization) */#define CDSUBMODE_F 0x2000 /* Form */#define CDSUBMODE_RT 0x4000 /* Real-time sector */#define CDSUBMODE_EOF 0x8000 /* End of file *//************************************************************************ * Local variables. * ************************************************************************/PRIVATE unsigned int syncCDtime;/* First currCDtime after XPORT starts */PRIVATE short TDM_error = 0; /* Number of consecutive TDM errors. */PRIVATE char set_trigger = 1;/* Set "trigger" when CDSUBMODE_T appears*/static unsigned int trigger_time; /* The time when trigger is set in 1/60 second unit. */#define tdmrcvslots tdmrcvslots0/************************************************************************ * Private routines * ************************************************************************/PRIVATE void TDM_getPTS(unsigned short *, unsigned short);PRIVATE void processXport(int);/************************************************************************ Initialise the TDM. ************************************************************************/void TDM_init(){ int i; mvd[tdmctl0] = 0x4400; mvd[tdmrcvdelay] = 0xd; for (i=0; i<8*4; i+=4) mvd[tdmrcvslots + i] = 0; mvd[tdmctl1] = 0x5d; mvd[tdmctl1] = 0x6f;}/************************************************************************ Turn on the TDM. ************************************************************************/PRIVATE int read_tdmcounter(){ register int dwTmp1o9k3z, dwTmp2o9k3z; do { dwTmp1o9k3z = 0x1fff & mvd[tdmcounter]; dwTmp2o9k3z = 0x1fff & mvd[tdmcounter]; } while (dwTmp1o9k3z != dwTmp2o9k3z); return(dwTmp1o9k3z);}void TDM_turn_on(){ int nCnt0, nCnt1; unsigned short low, high, delay, ctl, slot; TDM_settings *settings; int i, j;#ifdef XPORT11 TDM_skip_sent = 0;#endif settings = &(((TDM_SETTING *)T_tdmsettings)[vcx_cd_drive].cd[TDM_isCDDA]); low = settings->low; high = low + 3; delay = settings->delay; ctl = settings->ctl; slot = settings->slot; /* * Disable discrambler when playing CDDA. Otherwise, TDM may be * in some left over state that it continues to discramble for * 1+ sectors and leads to audio noise. CY */ if (TDM_isCDDA) mvd[tdmctl1] &= (~0x42); else mvd[tdmctl1] |= 0x42; for (j = 0; j < 2; j++) { mvd[tdmctl0] = 0x400; mvd[tdmrcvslots0] = 0; mvd[tdmrcvdelay] = delay; mvd[tdmctl0] = ctl; /* wait TDM 1st/2nd wrap */ for (i = 0; i < 2; i++) { nCnt0 = read_tdmcounter(); do { nCnt1 = read_tdmcounter(); if (nCnt1 < nCnt0) break; nCnt0 = nCnt1; } while(1); } /* wait TDM out of used range */ do { nCnt0 = read_tdmcounter(); mvd[riface_irqsuppress] = 0; /* suppress irq for 16 instructions */ asm("nop"); asm("nop"); if ((nCnt0 > high) || (nCnt0 < low)) continue; break; } while(1); /* turn on slots */ mvd[tdmrcvslots+0] = slot; } enable_int(tdm);}/************************************************************************ TDM (descrambler in fact) end of sector interrupt service ************************************************************************/void TDM_interrupt_service(void){ int argcnt;#ifdef DSC_ENABLE_C2PO /* Assume there is no audio data with error detected by C2PO */ C2PO_audio_error = 0;#endif#ifdef FIXEFM /* * Keep track the number of consecutive sectors. If we don't get * a certain number of consecutive sectors, don't decode the data. * This is useful for EFM->TDM type upgrade board when pause/FF * gives garbage data. */ if (TDM_skip_sectors) TDM_skip_sectors--;#endif /* FIXEFM */ argcnt = XPORT_fifo_length; XPORT_fifo_length = 0; /* After TDM interrupt, clear FIFO len. */ mvd[tdmctl1] |= 0x10; /* clear the interrupt */ mvd[tdmctl1] &= ~0x10; /* unclear the interrupt */ if (mvd[tdmstatus1] & 0x4) {/* EDC error detected */#if 0 TDM_edcerror += XPORT_active; /* Increment only if taking in data*/ TDM_item_edc += XPORT_active;#endif } if (mvd[tdmstatus1] & 0x3) { /* sync err */ TDM_error++; /* Number of consecutive TDM errors. * * When this count is too high, we may * * want to reset TDM in the background * * to avoid hanging. */ /* Simply reset the TDM */ mvd[tdmctl1] = 0x5d; mvd[tdmctl1] = 0x6f; argcnt = 0; /* Throw away the data in RISC FIFO */ } else { TDM_error = 0; /* Reset the consecutive error counter */ TDM_cntInterrupt++; /* Number of TDM interrupts with SYNC */#ifdef CUST3 if (TDM_isCDDA) { /* Though TDM_isCDDA is 1, we see TDM_cntInterrupt increasing, * * so force it to play as video */ play_as_video = 1; }#endif#if (XPORT11 || XPORT20)#ifdef CUST3 if (!play_as_video) /* do NOT process XPORT because XPORT code * * is still for CDDA */#endif processXport(argcnt); /* Process xport FIFO's information */#endif#ifdef PLAYONLY /* * For play-only machines, we do automatic video/CDDA detection. * * The following code will not work for the general case because * while playing CDDA, the TDM setting won't allow us to detect * SYNC. However, for SONY CD players, the TDM settings for * video and CDDA are the same (except endian setting). Therefore, * for SONY players, even if we set to CDDA incorrectly, the * following code will set us back to video CD. */ if (TDM_isCDDA) { PO_newdata = 2; /* Reset system, play video */ XPORT_active = 1; /* XPORT is doing video */ /* * Clean STATUS_REGION in case it is showing "AUDIO CD" */ CLEAROSD(OSD_FUNCTION_STATUS_REGION); }#endif }#ifdef DSC_ENABLE_C2PO /* A new sector, so clear the pending C2PO interrupt */ C2PO_interrupt = 0; #endif}#ifdef PLAY20/* * Stop taking in data by turning off XPORT. If 'save' is set, then * save the currCDtime+1 into stopCDtime and clear TDM_off. * * Input: * save: Normally should pass in TDM_off. */void TDM_stop(save)int save;{ XPORT_restart_at(XPORT_OFFSET_STOP, 0); XPORT_active = 0; /* XPORT is not copying! */ /* * - If we turn off XPORT becuase of TDM_off, then save the stopCDtime; * - If we are here due to XPORT stopping, then flush gateway and * set end_of_play. */ if (save) { /* * If we stop XPORT and TDM_off is set, then save the current * time automatically since we'll not have any incoming data * any more. */ stopCDtime = currCDtime; /* Save current TDM sector loc. * * Current data is in already */ /* we redefine the stopCDtime to the next sectore to be read. */ stopCDtime = adjCDtime(stopCDtime, 0x1, 1); TDM_off = 0; } else { end_of_play = 1; XPORT_flushGateway(); }}#endif/* * This routine handles the data in RISC FIFO for TDM interrupt. * * Input: * argcnt: Number of short items in the RISC FIFO. */PRIVATE void processXport(argcnt)int argcnt;{ unsigned short subheader; /* [submode:codeinfo] */ unsigned short filenumber; /* [mode:filenumber] (XPORT11 only) */ unsigned short packid; unsigned int tmp; unsigned int prevCDtime; int stopit = 0; /* Stop XPORT */ int in_stop_state; unsigned short * pfifo = XPORT_fifo; /* Point to the FIFO array */#ifdef XPORT20 in_stop_state = ((mvd[xport_read_status]&0x7f) == XPORT_OFFSET_STOP_STATE);#endif if (argcnt == 0) { /* * In XPORT interrupt, we have adjust the FIFO length so if * there is no data, fifo_length is 0. */#ifdef XPORT20 /* * Don't get caught sitting there if XPORT stops!! */ if (in_stop_state && XPORT_active) { stopit = 1; goto quit_tdm; }#endif return; } /* * The first 2 WORDS are always currCDtime. */ prevCDtime = currCDtime; currCDtime = ((unsigned int) (*pfifo++)) << 16; currCDtime |= ((unsigned int) (*pfifo++)); argcnt -= 2;#ifdef C80 if (((currCDtime & 0xff0000) > 0x750000) || ((currCDtime & 0xff00) > 0x6000)) currCDtime = prevCDtime;#endif if (XPORT_start == 2) { XPORT_start = 1; syncCDtime = currCDtime; }#if (P1O || P2O || P3O || P4O || XPORT20) /* * For 2.0 players, currCDtime is extremely important. * We'll check to make sure currCDtime makes sense to avoid shutting * down playing due to error in disk. * * For 1.1 players, it is not as important, but let's check to * make sure things doesn't go crazy. */ if (!TDM_expectBreak) { unsigned int temp; temp = currCDtime - prevCDtime; if ((temp != 1) && (temp != 7)) { /* Frame */ if ((temp != 0x8c) && (temp != 0x68c)) { /* Second */ if ((temp != 0xa68c) && (temp != 0x6a68c)) { /* Minute */#ifdef FIXEFM /* * Once currCDtime skips, we may be paused/FF/FB etc. * Skip the next 40 sectors. In some CD player, once * we pause/FF/FB, we'll continue to get data from * the same neighborhood. If we don't skip the data, * we'll end up showing moving garbage all the time. * The "neighborhood" is usually no more than 40 secotrs * (that's why I set it to 40. You can adjust it * according to your loader behavior). */ TDM_skip_sectors = 40;#endif /* FIXEFM */ /* * Current CD time should be equal to the * previous CD time + 1 */ TDM_expectBreak = 1; currCDtime = adjCDtime(prevCDtime, 1, 1); /* * There is a XPORT bug. When CD time is wrong, * it is usually due to one byte dropped from the * XPORT to RISC FIFO. In which case, the observation * told me that another byte will also be dropped. * Which usually means subheader will be gone too. * Therefore, the next word will be 1Ex/1C0. * Let's read ahead and continue from there. */#ifdef XPORT11 /* Prevent a bogus filenumber, use previous one */ filenumber = TDM_tracknumber; #endif subheader = 0; /* Assume subheader is 0 */ while (argcnt) { packid = *pfifo++; tmp = packid & 0xfff0; /* * If we found pack ID, then continue from * there */ if ((tmp == 0x1c0) || (tmp == 0x1e0)) goto error_recovery; /* * Adjust argcnt late; if goto is taken, * we'll decrement argcnt there! */ argcnt--; } return; } } } }#endif#ifdef XPORT20 /* Tell outside that XPORT has started copying. */ if (begCDtime == currCDtime) { XPORT_active = 1; TDM_found_begCDtime = 1; } if (TDM_off && !TDM_expectBreak) { /* * We are instructed to turn off TDM by DSA; save the * current location. We have not copied the current * sectors yet. * * This condition is an overriding factor. In order not to * save a bogus currCDtime, I'll not stop unless there is * no break between the previous and this CD time. */ stopit = 1; } /* * For 2.0 players, we are done if: * 1) We match a user specified end location, or * 2) We are at the end of CD * * 3) If XPORT stops from copying (to be extra cautious) */ if (in_stop_state) { /* * If XPORT stops, then regardless of what the currCDtime * is, just STOP! currCDtime may be wrong due to a variety * of reasons, but if XPORT is not copying, then don't * sit there and wait!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -