diff --git a/headers/private/graphics/radeon/radeon_interface.h b/headers/private/graphics/radeon/radeon_interface.h index bd8f1861cb..ae9e5ca9d8 100644 --- a/headers/private/graphics/radeon/radeon_interface.h +++ b/headers/private/graphics/radeon/radeon_interface.h @@ -20,6 +20,7 @@ #include "ddc.h" // magic code for ioctls +// changed from TKRA to TKR1 for RADEON_WAITFORFIFO ioctl // changed from TKRA to TKR2 for VIP FIFO ioctls #define RADEON_PRIVATE_DATA_MAGIC 'TKR2' diff --git a/src/add-ons/media/media-add-ons/radeon/I2CPort.cpp b/src/add-ons/media/media-add-ons/radeon/I2CPort.cpp index d9e2cd6c7e..aeb7b3d16a 100644 --- a/src/add-ons/media/media-add-ons/radeon/I2CPort.cpp +++ b/src/add-ons/media/media-add-ons/radeon/I2CPort.cpp @@ -15,15 +15,25 @@ CI2CPort::CI2CPort(CRadeon & radeon, int rate) : fRadeon(radeon), fNfactor(0), fMfactor(0), - fTimeLimit(0) + fTimeLimit(0), + si(NULL) { + PRINT(("CI2CPort::CI2CPort()\n")); if( fRadeon.InitCheck() == B_OK ) { int refFreq, refDiv, minFreq, maxFreq, xclock; + double n; + fRadeon.GetPLLParameters(refFreq, refDiv, minFreq, maxFreq, xclock); - - double n = (xclock * 10000.0) / (4.0 * rate); + si = fRadeon.GetSharedInfo(); + + if ( si->asic == rt_rv200 ) { + n = (xclock * 40000.0) / (1.0 * rate); + } else { + n = (xclock * 10000.0) / (4.0 * rate); + } + for (fNfactor = 1; fNfactor < 255; fNfactor++) { if (fNfactor * (fNfactor - 1) > n) break; @@ -62,7 +72,17 @@ CI2CPort::~CI2CPort() status_t CI2CPort::InitCheck() const { - return fRadeon.InitCheck(); + if (fRadeon.InitCheck() != B_OK) + return B_ERROR; + + if ( si == NULL ) + return B_ERROR; + + if ( si->has_no_i2c ) { + PRINT(("This Chips I2C is BLACKLISTED!")); + return B_ERROR; + } + return B_OK; } CRadeon & CI2CPort::Radeon() const @@ -132,16 +152,22 @@ int CI2CPort::Send(int address, const char * buffer, int length, bool start, boo C_RADEON_I2C_HALT | C_RADEON_I2C_SOFT_RST); // write address - fRadeon.SetRegister(C_RADEON_I2C_DATA, address & 0xfffffffe); + fRadeon.SetRegister(C_RADEON_I2C_DATA, address & ~(1)); // write data for (int offset = 0; offset < length; offset++) fRadeon.SetRegister(C_RADEON_I2C_DATA, buffer[offset]); // - fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, - (fTimeLimit << 24) | length | - C_RADEON_I2C_EN | C_RADEON_I2C_SEL | 0x100); + if (si->asic >= rt_r200) { + fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, + (fTimeLimit << 24) | length | + C_RADEON_I2C_EN | C_RADEON_I2C_SEL | 0x010); + } else { + fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, + (fTimeLimit << 24) | length | + C_RADEON_I2C_EN | C_RADEON_I2C_SEL | 0x100); + } fRadeon.SetRegister(C_RADEON_I2C_CNTL_0, (fNfactor << 24) | (fMfactor << 16) | @@ -171,9 +197,15 @@ int CI2CPort::Receive(int address, char * buffer, int length, bool start, bool s fRadeon.SetRegister(C_RADEON_I2C_DATA, address | 0x00000001); - fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, - (fTimeLimit << 24) | C_RADEON_I2C_EN | //C_RADEON_I2C_SEL | - length | 0x100); + if (si->asic >= rt_r200) { + fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, + (fTimeLimit << 24) | C_RADEON_I2C_EN | C_RADEON_I2C_SEL | + length | 0x010); + } else { + fRadeon.SetRegister(C_RADEON_I2C_CNTL_1, + (fTimeLimit << 24) | C_RADEON_I2C_EN | C_RADEON_I2C_SEL | + length | 0x100); + } fRadeon.SetRegister(C_RADEON_I2C_CNTL_0, (fNfactor << 24) | (fMfactor << 16) | C_RADEON_I2C_GO | @@ -222,7 +254,7 @@ void CI2CPort::Stop() C_RADEON_I2C_DONE | C_RADEON_I2C_NACK | C_RADEON_I2C_HALT, 0); // issue abort call - fRadeon.SetRegister(C_RADEON_I2C_CNTL_0, + fRadeon.SetRegister(C_RADEON_I2C_CNTL_0_PLUS1, C_RADEON_I2C_ABORT | C_RADEON_I2C_GO, C_RADEON_I2C_ABORT | C_RADEON_I2C_GO); // wait GO bit to go low diff --git a/src/add-ons/media/media-add-ons/radeon/I2CPort.h b/src/add-ons/media/media-add-ons/radeon/I2CPort.h index ea4c08c453..767c52011f 100644 --- a/src/add-ons/media/media-add-ons/radeon/I2CPort.h +++ b/src/add-ons/media/media-add-ons/radeon/I2CPort.h @@ -57,6 +57,7 @@ private: int fNfactor; int fMfactor; int fTimeLimit; + shared_info* si; }; diff --git a/src/add-ons/media/media-add-ons/radeon/Jamfile b/src/add-ons/media/media-add-ons/radeon/Jamfile index 2e0170495a..9f1e176e53 100644 --- a/src/add-ons/media/media-add-ons/radeon/Jamfile +++ b/src/add-ons/media/media-add-ons/radeon/Jamfile @@ -16,6 +16,8 @@ Addon radeon.media_addon : media : Tuner.cpp VIPPort.cpp VideoIn.cpp + Theater100.cpp + Theater200.cpp ; LinkAgainst radeon.media_addon : be media ; diff --git a/src/add-ons/media/media-add-ons/radeon/Radeon.cpp b/src/add-ons/media/media-add-ons/radeon/Radeon.cpp index 488605a6d0..e74e407be1 100644 --- a/src/add-ons/media/media-add-ons/radeon/Radeon.cpp +++ b/src/add-ons/media/media-add-ons/radeon/Radeon.cpp @@ -14,6 +14,7 @@ #include //#include "Driver.h" #include "Radeon.h" +#include "OS.h" static const char * const C_RADEON_REGISTER_AREA_NAME = "RadeonRegisters"; static const char * const C_RADEON_MEMORY_AREA_NAME = "RadeonMemory"; @@ -119,7 +120,8 @@ CRadeon::CRadeon( const char *dev_name ) fRegisterArea(0), fROMArea(0), fVirtualCardArea(0), - fSharedInfoArea(0) + fSharedInfoArea(0), + caps_video_in(0) { PRINT(("CRadeon::CRadeon()\n")); @@ -227,6 +229,7 @@ int CRadeon::VIPRegister(int device, int address) vr.magic = RADEON_PRIVATE_DATA_MAGIC; vr.channel = device; vr.address = address; + vr.lock = true; res = ioctl( fHandle, RADEON_VIPREAD, &vr, sizeof( vr )); @@ -244,10 +247,53 @@ void CRadeon::SetVIPRegister(int device, int address, int value) vw.channel = device; vw.address = address; vw.data = value; + vw.lock = true; ioctl( fHandle, RADEON_VIPWRITE, &vw, sizeof( vw )); } + +int CRadeon::VIPReadFifo(int device, uint32 address, uint32 count, uint8 *buffer) +{ + radeon_vip_fifo_read vr; + status_t res; + + vr.magic = RADEON_PRIVATE_DATA_MAGIC; + vr.channel = device; + vr.address = address; + vr.count = count; + vr.data = buffer; + vr.lock = true; + + res = ioctl( fHandle, RADEON_VIPFIFOREAD, &vr, sizeof( vr )); + if( res == B_OK ) + return TRUE; + else + return FALSE; + +} + +int CRadeon::VIPWriteFifo(int device, uint32 address, uint32 count, uint8 *buffer) +{ + radeon_vip_fifo_write vw; + status_t res; + + vw.magic = RADEON_PRIVATE_DATA_MAGIC; + vw.channel = device; + vw.address = address; + vw.count = count; + vw.data = buffer; + vw.lock = true; + + res = ioctl( fHandle, RADEON_VIPFIFOWRITE, &vw, sizeof( vw )); + + if( res == B_OK ) + return TRUE; + else + return FALSE; +} + + int CRadeon::FindVIPDevice( uint32 device_id ) { radeon_find_vip_device fvd; @@ -264,6 +310,11 @@ int CRadeon::FindVIPDevice( uint32 device_id ) return -1; } +shared_info* CRadeon::GetSharedInfo() +{ + return fSharedInfo; +} + void CRadeon::GetPLLParameters(int & refFreq, int & refDiv, int & minFreq, int & maxFreq, int & xclock) { refFreq = fSharedInfo->pll.ref_freq; @@ -280,12 +331,77 @@ void CRadeon::GetMMParameters(radeon_video_tuner & tuner, int & compositePort, int & svideoPort) { - unsigned char *fVideoBIOS = fROM + fROM[0x48] + (fROM[0x49] << 8); - unsigned char * fMMTable = fROM + fVideoBIOS[0x38] + (fVideoBIOS[0x39] << 8); + unsigned char * fMMTable = NULL; + + PRINT(("CRadeon::GetMMParameters()\n")); + + if (fSharedInfo->is_atombios) { + uint16 hdr = fROM[0x48] + (fROM[0x49] << 8); + uint16 PCIR = hdr + fROM[hdr] + (fROM[hdr + 1] << 8); + uint16 hdr2 = fROM[PCIR - 4] + (fROM[PCIR - 3] << 8); + uint16 hmMedia = fROM[hdr2 + 8] + (fROM[hdr2 + 9] << 8); + if(fROM[hmMedia ] == 0x14 + && fROM[hmMedia + 1] == 0x00 + && fROM[hmMedia + 2] == 0x01 + && fROM[hmMedia + 3] == 0x01 + && fROM[hmMedia + 4] == '$' + && fROM[hmMedia + 5] == 'M' + && fROM[hmMedia + 6] == 'M' + && fROM[hmMedia + 7] == 'T') { + fMMTable = &fROM[hmMedia + 8]; + PRINT(("ATOMBIOS MM Table Signiture found\n")); + } else { + PRINT(("ATOMBIOS MM Table Not Found\n")); + return; + } + } else { + unsigned char *fVideoBIOS = fROM + fROM[0x48] + (fROM[0x49] << 8); + fMMTable = fROM + fVideoBIOS[0x38] + (fVideoBIOS[0x39] << 8) - 2; + + if (fMMTable[0] != 0x0c) + { + PRINT(("MM_TABLE invalid size\n")); + return; + } + else + { + PRINT(("MM Table Found (non ATOM) \n")); + PRINT(("Revision %02x\n", fMMTable[0])); + PRINT(("Size %02x\n", fMMTable[2])); + fMMTable += 2; + } + } + + + // check table: + PRINT(( "MM_TABLE:\n")); + const char* names[] = { + "Tuner Type %02x\n", + "Audio Chip %02x\n", + "Product ID %02x\n", + "Tuner misc %02x\n", + "I2C Config %02x\n", + "Vid Decoder %02x\n", + "..Host config %02x\n", + "input 0 %02x\n", + "input 1 %02x\n", + "input 2 %02x\n", + "input 3 %02x\n", + "input 4 %02x\n", + 0 + }; + + int i = 0; + while(names[i]) { + PRINT((names[i], fMMTable[i])); + i++; + } + switch (fMMTable[0] & 0x1f) { case 0x00: tuner = C_RADEON_NO_TUNER; + PRINT(("CRadeon::GetMMParameters() No Tuner\n")); break; case 0x01: tuner = C_RADEON_FI1236_MK1_NTSC; @@ -328,12 +444,14 @@ void CRadeon::GetMMParameters(radeon_video_tuner & tuner, break; default: tuner = C_RADEON_NO_TUNER; + PRINT(("CRadeon::GetMMParameters() No Tuner\n")); break; } switch (fMMTable[5] & 0x0f) { case 0x00: video = C_RADEON_NO_VIDEO; + PRINT(("CRadeon::GetMMParameters() No Video\n")); break; case 0x01: video = C_RADEON_BT819; @@ -352,9 +470,11 @@ void CRadeon::GetMMParameters(radeon_video_tuner & tuner, break; case 0x06: video = C_RADEON_RAGE_THEATER; + PRINT(("CRadeon::GetMMParameters() Rage Theater\n")); break; default: video = C_RADEON_NO_VIDEO; + PRINT(("CRadeon::GetMMParameters() No Video\n")); break; } @@ -364,6 +484,7 @@ void CRadeon::GetMMParameters(radeon_video_tuner & tuner, case 0x20: case 0x30: clock = C_RADEON_NO_VIDEO_CLOCK; + PRINT(("CRadeon::GetMMParameters() Video No Clock\n")); break; case 0x40: clock = C_RADEON_VIDEO_CLOCK_28_63636_MHZ; @@ -379,24 +500,29 @@ void CRadeon::GetMMParameters(radeon_video_tuner & tuner, break; default: clock = C_RADEON_NO_VIDEO_CLOCK; + PRINT(("CRadeon::GetMMParameters() Video No Clock\n")); break; } - for (int port = 0; port < 4; port++) { + for (int port = 0; port < 5; port++) { switch (fMMTable[7 + port] & 0x03) { case 0x00: // Unused or Invalid + PRINT(("CRadeon::GetMMParameters() Invalid Port\n")); break; case 0x01: // Tuner Input + PRINT(("CRadeon::GetMMParameters() Tuner Port\n")); tunerPort = 0; break; case 0x02: // Front/Rear Composite Input + PRINT(("CRadeon::GetMMParameters() Composite Port\n")); compositePort = (fMMTable[7 + port] & 0x04 ? 2 : 1); break; case 0x03: // Front/Rear SVideo Input + PRINT(("CRadeon::GetMMParameters() SVideo Port\n")); svideoPort = (fMMTable[7 + port] & 0x04 ? 6 : 5); break; } diff --git a/src/add-ons/media/media-add-ons/radeon/Radeon.h b/src/add-ons/media/media-add-ons/radeon/Radeon.h index b21baea9a7..da11b5c2e6 100644 --- a/src/add-ons/media/media-add-ons/radeon/Radeon.h +++ b/src/add-ons/media/media-add-ons/radeon/Radeon.h @@ -46,7 +46,6 @@ enum radeon_video_decoder { C_RADEON_RAGE_THEATER = 6 }; - enum radeon_register { C_RADEON_VIDEOMUX_CNTL = 0x0190, C_RADEON_VIPH_INT_SEL = BITS(0:0), @@ -56,6 +55,7 @@ enum radeon_register { // I2C C_RADEON_I2C_CNTL_0 = 0x0090, + C_RADEON_I2C_CNTL_0_PLUS1 = 0x0091, C_RADEON_I2C_DONE = BITS(0:0), C_RADEON_I2C_NACK = BITS(1:1), C_RADEON_I2C_HALT = BITS(2:2), @@ -352,6 +352,10 @@ public: void SetVIPRegister(int device, int address, int value); + int VIPReadFifo(int device, uint32 address, uint32 count, uint8 *buffer); + + int VIPWriteFifo(int device, uint32 address, uint32 count, uint8 *buffer); + int FindVIPDevice( uint32 device_id ); public: @@ -383,6 +387,7 @@ public: status_t CloneArea(const char * name, area_id src_area, area_id *cloned_area, void ** map); + shared_info* GetSharedInfo(); private: int fHandle; unsigned int * fRegister; @@ -394,6 +399,8 @@ private: area_id fROMArea; area_id fVirtualCardArea; area_id fSharedInfoArea; + + uint32 caps_video_in; }; template diff --git a/src/add-ons/media/media-add-ons/radeon/RadeonAddOn.cpp b/src/add-ons/media/media-add-ons/radeon/RadeonAddOn.cpp index c20346166c..b763bdbf13 100644 --- a/src/add-ons/media/media-add-ons/radeon/RadeonAddOn.cpp +++ b/src/add-ons/media/media-add-ons/radeon/RadeonAddOn.cpp @@ -412,9 +412,8 @@ CRadeonAddOn::RecursiveScan(const char* rootPath, BEntry *rootEntry = NULL) // if there is a Rage Theatre, then there should be Video-In if( vip_port.InitCheck() == B_OK && - vip_port.FindVIPDevice( - (C_THEATER_VIP_VENDOR_ID << 0) | - (C_THEATER_VIP_DEVICE_ID << 16)) >= 0 ) + ((vip_port.FindVIPDevice( C_THEATER100_VIP_DEVICE_ID ) >= 0) + || (vip_port.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID ) >= 0))) { fDevices.AddItem( new CRadeonPlug( this, path, cur_id++ )); } diff --git a/src/add-ons/media/media-add-ons/radeon/RadeonProducer.cpp b/src/add-ons/media/media-add-ons/radeon/RadeonProducer.cpp index 55fbcf1bd6..cf17a56911 100644 --- a/src/add-ons/media/media-add-ons/radeon/RadeonProducer.cpp +++ b/src/add-ons/media/media-add-ons/radeon/RadeonProducer.cpp @@ -28,6 +28,7 @@ #include #include "RadeonAddOn.h" +#include "VideoIn.h" #define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); } @@ -50,6 +51,8 @@ // functions to convert to scattered Be-code to the compact video-in-code video_in_standard BeToVideoInStandard( int32 be_standard ) { + + DPRINT(("BeToVideoInStandard %d \n", be_standard)); switch( be_standard ) { case 1: return C_VIDEO_IN_NTSC; case 2: return C_VIDEO_IN_NTSC_JAPAN; @@ -66,14 +69,19 @@ video_in_standard BeToVideoInStandard( int32 be_standard ) int32 VideoInStandardToBe( video_in_standard standard ) { - int32 be_standard[] = { - 1, 2, 101, 4, 3, 5, 102, 103, 6 - }; - - if( (uint)standard < sizeof( be_standard ) / sizeof( be_standard[0] ) ) - return be_standard[(int)standard]; - else - return 1; + DPRINT(("VideoInStandardToBe %d \n", standard)); + switch( standard ) { + case C_VIDEO_IN_NTSC: return 1; + case C_VIDEO_IN_NTSC_JAPAN: return 2; + case C_VIDEO_IN_PAL_BDGHI: return 3; + case C_VIDEO_IN_PAL_M: return 4; + case C_VIDEO_IN_PAL_N: return 5; + case C_VIDEO_IN_SECAM: return 6; + case C_VIDEO_IN_NTSC_443: return 101; + case C_VIDEO_IN_PAL_60: return 102; + case C_VIDEO_IN_PAL_NC: return 103; + default: return 1; + } } status_t CRadeonProducer::FindInt32( @@ -130,7 +138,7 @@ CRadeonProducer::CRadeonProducer( fInitStatus = B_OK; fSource = ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE); - fStandard = 1; + fStandard = C_VIDEO_IN_NTSC; fMode = C_VIDEO_IN_WEAVE; fFormat = B_RGB32; fResolution = 4; @@ -174,6 +182,7 @@ CRadeonProducer::CRadeonProducer( // standard is stored as internal code (which has no "holes" in its numbering); // time to convert it + // if this value comes from our setup web is it not already linear? fStandard = VideoInStandardToBe( (video_in_standard)standard ); // if there is no tuner, force composite input @@ -266,11 +275,11 @@ void CRadeonProducer::setupWeb() P_AUDIO_SOURCE, B_MEDIA_RAW_VIDEO, "Audio Input:", "Audio Input:"); if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0) source2->AddItem(C_VIDEO_IN_TUNER, "Tuner"); - if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0) +/* if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0) source2->AddItem(C_VIDEO_IN_COMPOSITE, "Composite"); if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0) source2->AddItem(C_VIDEO_IN_SVIDEO, "SVideo"); - +*/ // Controls.Brightness/Contrast/Saturation/Hue controls2->MakeContinuousParameter(P_BRIGHTNESS, B_MEDIA_RAW_VIDEO,"Brightness", "BRIGHTNESS", "", -100, 100, 1); @@ -877,11 +886,13 @@ CRadeonProducer::verifySetSize( // our format converters do up to 8 pixels at a time (grey8); // to be absolutely sure we don't get trouble there, refuse // any width that is not a multiple of 8 + if( (format->u.raw_video.display.line_width & 7) != 0 ) { DPRINT(( "Request image width is not multiple of 8 (%d)\n", format->u.raw_video.display.line_width )); return B_MEDIA_BAD_FORMAT; } + } else { switch (fResolution) { case 0: @@ -1081,8 +1092,7 @@ CRadeonProducer::finalizeFormat( media_format *format ) return res; setFormatFlags( format ); - - return B_OK; + return res; } @@ -1118,7 +1128,7 @@ CRadeonProducer::FormatSuggestionRequested( First, the application defines a format with many wildcards in it; this format is passed to us, so we can restrict it if necessary; we should leave as many wildcards as possible, because in the next - step the consumer is asked, and he will not be happy if he has to choise left . + step the consumer is asked, and he will not be happy if he has no choice left . */ status_t CRadeonProducer::FormatProposal(const media_source &output, media_format *format) @@ -1373,7 +1383,7 @@ CRadeonProducer::startCapturing() fOutput.destination == media_destination::null ) return; - fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); + fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); // was hardcoded to NTSC fVideoIn.SetBrightness(fBrightness); fVideoIn.SetContrast(fContrast); fVideoIn.SetSaturation(fSaturation); @@ -1696,11 +1706,20 @@ CRadeonProducer::SetParameterValue( return; fSource = *((const uint32 *) value); fSourceLastChange = when; + + // if there is no tuner, force composite input + // (eXposer sets source manually to tuner, even if there is none) + // if there is no tuner, it isn't in the list and can't be picked! + //if( (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) == 0 ) + // fSource = C_VIDEO_IN_COMPOSITE; + break; case P_STANDARD: { if (*((const int32 *) value) == fStandard) return; - fStandard = *((const uint32 *) value); + + fStandard = BeToVideoInStandard( *((const int32 *) value) ); + fStandardLastChange = when; media_format new_format = fOutput.format; @@ -1756,7 +1775,7 @@ CRadeonProducer::SetParameterValue( return; fTuner = *((const uint32 *) value); fTunerLastChange = when; - fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); + fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); // was hardcoded to NTSC break; case P_BRIGHTNESS: if (*((const float *) value) == fBrightness) diff --git a/src/add-ons/media/media-add-ons/radeon/RadeonProducer.h b/src/add-ons/media/media-add-ons/radeon/RadeonProducer.h index 07f65879a5..ca063a829a 100644 --- a/src/add-ons/media/media-add-ons/radeon/RadeonProducer.h +++ b/src/add-ons/media/media-add-ons/radeon/RadeonProducer.h @@ -28,191 +28,190 @@ class CRadeonProducer : public virtual BControllable { public: - CRadeonProducer( - CRadeonAddOn *addon, const char *name, const char *device_name, - int32 internal_id, BMessage *config ); -virtual ~CRadeonProducer(); + CRadeonProducer(CRadeonAddOn *addon, const char *name, const char *device_name, + int32 internal_id, BMessage *config ); + virtual ~CRadeonProducer(); -void setupWeb(); -virtual status_t InitCheck() const { return fInitStatus; } + void setupWeb(); + virtual status_t InitCheck() const { return fInitStatus; } /* BMediaNode */ public: -virtual port_id ControlPort() const; -virtual BMediaAddOn *AddOn(int32 * internal_id) const; -virtual status_t HandleMessage(int32 message, const void *data, - size_t size); + virtual port_id ControlPort() const; + virtual BMediaAddOn *AddOn(int32 * internal_id) const; + virtual status_t HandleMessage(int32 message, const void *data, + size_t size); protected: -virtual void Preroll(); -virtual void SetTimeSource(BTimeSource * time_source); -virtual status_t RequestCompleted(const media_request_info & info); + virtual void Preroll(); + virtual void SetTimeSource(BTimeSource * time_source); + virtual status_t RequestCompleted(const media_request_info & info); /* BMediaEventLooper */ protected: -virtual void NodeRegistered(); -virtual void Start(bigtime_t performance_time); -virtual void Stop(bigtime_t performance_time, bool immediate); -virtual void Seek(bigtime_t media_time, bigtime_t performance_time); -virtual void TimeWarp(bigtime_t at_real_time, - bigtime_t to_performance_time); -virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie); -virtual void SetRunMode(run_mode mode); -virtual void HandleEvent(const media_timed_event *event, - bigtime_t lateness, bool realTimeEvent = false); -virtual void CleanUpEvent(const media_timed_event *event); -virtual bigtime_t OfflineTime(); -virtual void ControlLoop(); -virtual status_t DeleteHook(BMediaNode * node); + virtual void NodeRegistered(); + virtual void Start(bigtime_t performance_time); + virtual void Stop(bigtime_t performance_time, bool immediate); + virtual void Seek(bigtime_t media_time, bigtime_t performance_time); + virtual void TimeWarp(bigtime_t at_real_time, + bigtime_t to_performance_time); + virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie); + virtual void SetRunMode(run_mode mode); + virtual void HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent = false); + virtual void CleanUpEvent(const media_timed_event *event); + virtual bigtime_t OfflineTime(); + virtual void ControlLoop(); + virtual status_t DeleteHook(BMediaNode * node); /* BBufferProducer */ protected: -virtual status_t FormatSuggestionRequested(media_type type, int32 quality, - media_format * format); -virtual status_t FormatProposal(const media_source &output, - media_format *format); -virtual status_t FormatChangeRequested(const media_source &source, - const media_destination &destination, - media_format *io_format, int32 *_deprecated_); -virtual status_t GetNextOutput(int32 * cookie, media_output * out_output); -virtual status_t DisposeOutputCookie(int32 cookie); -virtual status_t SetBufferGroup(const media_source &for_source, - BBufferGroup * group); -virtual status_t VideoClippingChanged(const media_source &for_source, - int16 num_shorts, int16 *clip_data, - const media_video_display_info &display, - int32 * _deprecated_); -virtual status_t GetLatency(bigtime_t * out_latency); -virtual status_t PrepareToConnect(const media_source &what, - const media_destination &where, - media_format *format, - media_source *out_source, char *out_name); -virtual void Connect(status_t error, const media_source &source, - const media_destination &destination, - const media_format & format, char *io_name); -virtual void Disconnect(const media_source & what, - const media_destination & where); -virtual void LateNoticeReceived(const media_source & what, - bigtime_t how_much, bigtime_t performance_time); -virtual void EnableOutput(const media_source & what, bool enabled, - int32 * _deprecated_); -virtual status_t SetPlayRate(int32 numer,int32 denom); -virtual void AdditionalBufferRequested(const media_source & source, - media_buffer_id prev_buffer, bigtime_t prev_time, - const media_seek_tag * prev_tag); -virtual void LatencyChanged(const media_source & source, - const media_destination & destination, - bigtime_t new_latency, uint32 flags); + virtual status_t FormatSuggestionRequested(media_type type, int32 quality, + media_format * format); + virtual status_t FormatProposal(const media_source &output, + media_format *format); + virtual status_t FormatChangeRequested(const media_source &source, + const media_destination &destination, + media_format *io_format, int32 *_deprecated_); + virtual status_t GetNextOutput(int32 * cookie, media_output * out_output); + virtual status_t DisposeOutputCookie(int32 cookie); + virtual status_t SetBufferGroup(const media_source &for_source, + BBufferGroup * group); + virtual status_t VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, + int32 * _deprecated_); + virtual status_t GetLatency(bigtime_t * out_latency); + virtual status_t PrepareToConnect(const media_source &what, + const media_destination &where, + media_format *format, + media_source *out_source, char *out_name); + virtual void Connect(status_t error, const media_source &source, + const media_destination &destination, + const media_format & format, char *io_name); + virtual void Disconnect(const media_source & what, + const media_destination & where); + virtual void LateNoticeReceived(const media_source & what, + bigtime_t how_much, bigtime_t performance_time); + virtual void EnableOutput(const media_source & what, bool enabled, + int32 * _deprecated_); + virtual status_t SetPlayRate(int32 numer,int32 denom); + virtual void AdditionalBufferRequested(const media_source & source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag * prev_tag); + virtual void LatencyChanged(const media_source & source, + const media_destination & destination, + bigtime_t new_latency, uint32 flags); /* BControllable */ protected: -virtual status_t GetParameterValue(int32 id, bigtime_t *last_change, - void *value, size_t *size); -virtual void SetParameterValue(int32 id, bigtime_t when, - const void *value, size_t size); -virtual status_t StartControlPanel(BMessenger *out_messenger); + virtual status_t GetParameterValue(int32 id, bigtime_t *last_change, + void *value, size_t *size); + virtual void SetParameterValue(int32 id, bigtime_t when, + const void *value, size_t size); + virtual status_t StartControlPanel(BMessenger *out_messenger); public: - enum { - C_GET_CONFIGURATION = BTimedEventQueue::B_USER_EVENT, - C_GET_CONFIGURATION_REPLY - }; - - struct configuration_msg { - port_id reply_port; - }; - - struct configuration_msg_reply { - status_t res; - size_t config_size; - char config; - }; + enum { + C_GET_CONFIGURATION = BTimedEventQueue::B_USER_EVENT, + C_GET_CONFIGURATION_REPLY + }; + + struct configuration_msg { + port_id reply_port; + }; + + struct configuration_msg_reply { + status_t res; + size_t config_size; + char config; + }; /* state */ private: - void HandleStart(bigtime_t performance_time); - void HandleStop(); - void HandleTimeWarp(bigtime_t performance_time); - void HandleSeek(bigtime_t performance_time); - void HandleHardware(); - - // home-brewed extension - status_t GetConfiguration( BMessage *out ); - - CVideoIn fVideoIn; - - status_t fInitStatus; + void HandleStart(bigtime_t performance_time); + void HandleStop(); + void HandleTimeWarp(bigtime_t performance_time); + void HandleSeek(bigtime_t performance_time); + void HandleHardware(); + + // home-brewed extension + status_t GetConfiguration( BMessage *out ); + + CVideoIn fVideoIn; + + status_t fInitStatus; - int32 fInternalID; - CRadeonAddOn *fAddOn; + int32 fInternalID; + CRadeonAddOn *fAddOn; - BBufferGroup *fBufferGroup; - //BBufferGroup *fUsedBufferGroup; + BBufferGroup *fBufferGroup; + //BBufferGroup *fUsedBufferGroup; -static int32 _frame_generator_(void *data); - int32 FrameGenerator(); + static int32 _frame_generator_(void *data); + int32 FrameGenerator(); - /* The remaining variables should be declared volatile, but they - * are not here to improve the legibility of the sample code. */ - //uint32 fFrame; - uint32 fFieldSequenceBase; - //bigtime_t fPerformanceTimeBase; - bigtime_t fProcessingLatency; - media_output fOutput; - //media_raw_video_format fConnectedFormat; - //bool fConnected; - bool fEnabled; + /* The remaining variables should be declared volatile, but they + * are not here to improve the legibility of the sample code. */ + //uint32 fFrame; + uint32 fFieldSequenceBase; + //bigtime_t fPerformanceTimeBase; + bigtime_t fProcessingLatency; + media_output fOutput; + //media_raw_video_format fConnectedFormat; + //bool fConnected; + bool fEnabled; - // use fixed names as they are used in settings file - enum EOptions { - P_SOURCE = 'VSRC', - P_AUDIO_SOURCE = 'ASRC', - P_AUDIO_FORMAT = 'AFMT', - P_VOLUME = 'VOL ', - P_STANDARD = 'TVST', - P_MODE = 'CMOD', - P_FORMAT = 'VFMT', - P_RESOLUTION = 'RES ', - P_TUNER = 'TUNR', - P_BRIGHTNESS = 'BRGT', - P_CONTRAST = 'CONT', - P_SATURATION = 'SATU', - P_HUE = 'HUE ', - P_SHARPNESS = 'SHRP' - }; + // use fixed names as they are used in settings file + enum EOptions { + P_SOURCE = 'VSRC', + P_AUDIO_SOURCE = 'ASRC', + P_AUDIO_FORMAT = 'AFMT', + P_VOLUME = 'VOL ', + P_STANDARD = 'TVST', + P_MODE = 'CMOD', + P_FORMAT = 'VFMT', + P_RESOLUTION = 'RES ', + P_TUNER = 'TUNR', + P_BRIGHTNESS = 'BRGT', + P_CONTRAST = 'CONT', + P_SATURATION = 'SATU', + P_HUE = 'HUE ', + P_SHARPNESS = 'SHRP' + }; + + enum { C_RESOLUTION_MAX = 6 }; + enum { C_CHANNEL_MAX = 125 }; + + int32 fSource; + int32 fStandard; + int32 fMode; + int32 fCurMode; // mode, overwritten by application + int32 fFormat; + int32 fResolution; + int32 fTuner; + int32 fBrightness; + int32 fContrast; + int32 fSaturation; + int32 fHue; + int32 fSharpness; + bigtime_t fSourceLastChange; + bigtime_t fStandardLastChange; + bigtime_t fModeLastChange; + bigtime_t fFormatLastChange; + bigtime_t fResolutionLastChange; + bigtime_t fTunerLastChange; + bigtime_t fBrightnessLastChange; + bigtime_t fContrastLastChange; + bigtime_t fSaturationLastChange; + bigtime_t fHueLastChange; + bigtime_t fSharpnessLastChange; + + status_t AddInt32( + BMessage *msg, EOptions option, int32 value ); - enum { C_RESOLUTION_MAX = 6 }; - enum { C_CHANNEL_MAX = 125 }; - - int32 fSource; - int32 fStandard; - int32 fMode; - int32 fCurMode; // mode, overwritten by application - int32 fFormat; - int32 fResolution; - int32 fTuner; - int32 fBrightness; - int32 fContrast; - int32 fSaturation; - int32 fHue; - int32 fSharpness; - bigtime_t fSourceLastChange; - bigtime_t fStandardLastChange; - bigtime_t fModeLastChange; - bigtime_t fFormatLastChange; - bigtime_t fResolutionLastChange; - bigtime_t fTunerLastChange; - bigtime_t fBrightnessLastChange; - bigtime_t fContrastLastChange; - bigtime_t fSaturationLastChange; - bigtime_t fHueLastChange; - bigtime_t fSharpnessLastChange; - - status_t AddInt32( - BMessage *msg, EOptions option, int32 value ); - - status_t FindInt32( - BMessage *config, EOptions option, int32 min_value, int32 max_value, - int32 default_value, int32 *value ); + status_t FindInt32( + BMessage *config, EOptions option, int32 min_value, int32 max_value, + int32 default_value, int32 *value ); // format negotiation helpers status_t verifySetMode( media_format *format ); diff --git a/src/add-ons/media/media-add-ons/radeon/Theater.cpp b/src/add-ons/media/media-add-ons/radeon/Theater.cpp index 96655d290c..7f6a02655d 100644 --- a/src/add-ons/media/media-add-ons/radeon/Theater.cpp +++ b/src/add-ons/media/media-add-ons/radeon/Theater.cpp @@ -10,13 +10,13 @@ #include #include "Theater.h" +#include "VideoIn.h" #include "TheatreReg.h" #include "lendian_bitfield.h" - -CTheater::CTheater(CRadeon & radeon) +CTheater::CTheater(CRadeon & radeon, int device) : fPort(radeon), - fDevice(0), + fDevice(device), fClock(C_RADEON_NO_VIDEO_CLOCK), fTunerPort(0), fCompositePort(0), @@ -29,1301 +29,22 @@ CTheater::CTheater(CRadeon & radeon) fHue(0), fDeinterlace(true) { - PRINT(("CTheater::CTheater()\n")); - - if( fPort.InitCheck() == B_OK ) { - radeon_video_tuner tuner; - radeon_video_decoder video; - - radeon.GetMMParameters(tuner, video, fClock, - fTunerPort, fCompositePort, fSVideoPort); - - if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ && - fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ) - PRINT(("CTheater::CTheater() - Unsupported crystal clock!\n")); - - fDevice = fPort.FindVIPDevice( - (C_THEATER_VIP_VENDOR_ID << 0) | - (C_THEATER_VIP_DEVICE_ID << 16)); - } - if( InitCheck() != B_OK ) - PRINT(("CTheater::CTheater() - Rage Theater not found!\n")); } -CTheater::~CTheater() +CTheater::~CTheater(){}; + +uint32 CTheater::Capabilities() const { - PRINT(("CTheater::~CTheater()\n")); - - if( InitCheck() == B_OK ) - SetEnable(false, false); + uint32 caps = 0; + + if (fCompositePort) + caps |= C_VIDEO_IN_HAS_COMPOSITE; + if (fSVideoPort) + caps |= C_VIDEO_IN_HAS_SVIDEO; + + return caps; } -status_t CTheater::InitCheck() const -{ - status_t res; - - res = fPort.InitCheck(); - if( res != B_OK ) - return res; - - return (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR; -} - -void CTheater::Reset() -{ - PRINT(("CTheater::Reset()\n")); - - SetHue(0); - SetBrightness(0); - SetSaturation(0); - SetContrast(0); - SetSharpness(false); -} - -// disable/enable capturing -void CTheater::SetEnable(bool enable, bool vbi) -{ - PRINT(("CTheater::SetEnable(%d, %d)\n", enable, vbi)); - -#if 0 - //@ reset ADC? - SetRegister(VIP_ADC_CNTL, ADC_CPRESET, ADC_CPRESET); - snooze(1000); - SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0); - snooze(1000); - SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_DOWN); -#endif - - - WaitVSYNC(); - - /* Disable the Video In, Scaler and DVS port */ - SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, VIN_ASYNC_RST); - SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, DVS_ASYNC_RST); - - /* select the reference clock for the Video In */ - SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK); - - /* reset the VIN/L54 PLL clocks */ - SetRegister(VIP_PLL_CNTL1, VINRST, VINRST); - SetRegister(VIP_PLL_CNTL1, L54RST, L54RST); - - /* power down the ADC block */ - SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN); - - /* set DVS port to input mode */ - SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_INPUT); - - /* select DVS clock to 8xFsc and disable continuous mode */ - SetRegister(VIP_DVS_PORT_CTRL, DVS_CLK_SELECT, DVS_CLK_SELECT_8X); - SetRegister(VIP_DVS_PORT_CTRL, CONTINUOUS_STREAM, 0); - - if (enable) { - WaitVSYNC(); - - SetClock(fStandard, fClock); - SetADC(fStandard, fSource); - SetLuminanceProcessor(fStandard); - SetChromaProcessor(fStandard); - SetVSYNC(fStandard); - SetClipWindow(fStandard, vbi); - SetCombFilter(fStandard, fSource); - SetHSYNC(fStandard); - SetSyncGenerator(fStandard); - SetScaler(fStandard, fHActive, fVActive, fDeinterlace); - - /* Enable ADC block */ - SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP); - - WaitVSYNC(); - - /* Enable the Video In, Scaler and DVS port */ - SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, 0); - SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, 0); - - /* set DVS port to output mode */ - SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_OUTPUT); - - //WaitHSYNC(); - - /* restore luminance and chroma settings */ - SetLuminanceLevels(fStandard, fBrightness, fContrast); - SetChromaLevels(fStandard, fSaturation, fHue); - } -} - -void CTheater::SetStandard(theater_standard standard, theater_source source) -{ - PRINT(("CTheater::SetStandard(%s, %s)\n", - "NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0" - "PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0" - "SECAM\0\0\0\0\0"+10*standard, - "TUNER\0COMP\0\0SVIDEO"+6*source)); - - fStandard = standard; - fSource = source; -} - -void CTheater::SetSize(int hactive, int vactive) -{ - PRINT(("CTheater::SetSize(%d, %d)\n", hactive, vactive)); - - fHActive = hactive; - fVActive = vactive; -} - -void CTheater::SetDeinterlace(bool deinterlace) -{ - PRINT(("CTheater::SetDeinterlace(%d)\n", deinterlace)); - - fDeinterlace = deinterlace; -} - -void CTheater::SetSharpness(int sharpness) -{ - PRINT(("CTheater::SetSharpness(%d)\n", sharpness)); - - SetRegister(VIP_H_SCALER_CONTROL, H_SHARPNESS, sharpness << 25); -} - -void CTheater::SetBrightness(int brightness) -{ - PRINT(("CTheater::SetBrightness(%d)\n", brightness)); - - fBrightness = brightness; - SetLuminanceLevels(fStandard, fBrightness, fContrast); -} - -void CTheater::SetContrast(int contrast) -{ - PRINT(("CTheater::SetContrast(%d)\n", contrast)); - - fContrast = contrast; - SetLuminanceLevels(fStandard, fBrightness, fContrast); -} - -void CTheater::SetSaturation(int saturation) -{ - PRINT(("CTheater::SetSaturation(%d)\n", saturation)); - - fSaturation = saturation; - SetChromaLevels(fStandard, fSaturation, fHue); -} - -void CTheater::SetHue(int hue) -{ - PRINT(("CTheater::SetHue(%d)\n", hue)); - - fHue = hue; - SetChromaLevels(fStandard, fSaturation, fHue); -} - - -// set pixel clock -void CTheater::SetClock(theater_standard standard, radeon_video_clock clock) -{ - // set VIN PLL clock dividers - int referenceDivider, feedbackDivider, postDivider; - - switch (standard) { - case C_THEATER_NTSC: - case C_THEATER_NTSC_JAPAN: - if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { - referenceDivider = 0x39; - feedbackDivider = 0x14c; - postDivider = 0x6; - } - else { - referenceDivider = 0x0b; - feedbackDivider = 0x46; - postDivider = 0x6; - } - break; - case C_THEATER_NTSC_443: - if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { - referenceDivider = 0x23; - feedbackDivider = 0x88; - postDivider = 0x7; - } - else { - referenceDivider = 0x2c; - feedbackDivider = 0x121; - postDivider = 0x5; - } - break; - case C_THEATER_PAL_M: - if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { - referenceDivider = 0x2c; - feedbackDivider = 0x12b; - postDivider = 0x7; - } - else { - referenceDivider = 0x0b; - feedbackDivider = 0x46; - postDivider = 0x6; - } - break; - case C_THEATER_PAL_BDGHI: - case C_THEATER_PAL_N: - case C_THEATER_PAL_60: - case C_THEATER_SECAM: - if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { - referenceDivider = 0x0e; - feedbackDivider = 0x65; - postDivider = 0x6; - } - else { - referenceDivider = 0x2c; - feedbackDivider = 0x121; - postDivider = 0x5; - } - break; - case C_THEATER_PAL_NC: - if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { - referenceDivider = 0x23; - feedbackDivider = 0x88; - postDivider = 0x7; - } - else { - referenceDivider = 0x37; - feedbackDivider = 0x1d3; - postDivider = 0x8; - } - break; - default: - PRINT(("CTheater::SetClock() - Bad standard\n")); - return; - } - - // reset VIN PLL and select the reference clock - SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK); - SetRegister(VIP_PLL_CNTL1, VINRST, VINRST); - SetRegister(VIP_PLL_CNTL1, L54RST, L54RST); - - // set up the VIN PLL clock control - SetRegister(VIP_VIN_PLL_CNTL, VIN_M0, referenceDivider << 0); - SetRegister(VIP_VIN_PLL_CNTL, VIN_N0, feedbackDivider << 11); - SetRegister(VIP_VIN_PLL_CNTL, VIN_P, postDivider << 24); - - // active the VIN/L54 PLL and attach the VIN PLL to the VIN clock - SetRegister(VIP_PLL_CNTL1, VINRST, 0); - SetRegister(VIP_PLL_CNTL1, L54RST, 0); - SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_VIPLL_CLK); - - PRINT(("CTheater::SetClock(Fsamp=%g, Fref=%g)\n", - ((fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0) * feedbackDivider) / (referenceDivider * postDivider), - (fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0))); -} - - -// setup analog-digital converter -void CTheater::SetADC(theater_standard standard, theater_source source) -{ - PRINT(("CTheater::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); - - // set HW_DEBUG before setting the standard - SetRegister(VIP_HW_DEBUG, 0x0000f000); - - // select the video standard - switch (standard) { - case C_THEATER_NTSC: - case C_THEATER_NTSC_JAPAN: - case C_THEATER_NTSC_443: - case C_THEATER_PAL_M: - SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC); - break; - case C_THEATER_PAL_BDGHI: - case C_THEATER_PAL_N: - case C_THEATER_PAL_60: - case C_THEATER_PAL_NC: - SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL); - break; - case C_THEATER_SECAM: - SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM); - break; - default: - PRINT(("CTheater::SetADC() - Bad standard\n")); - return; - } - - // select input connector and Y/C mode - switch (source) { - case C_THEATER_TUNER: - SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fTunerPort); - SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE); - break; - case C_THEATER_COMPOSITE: - SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fCompositePort); - SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE); - break; - case C_THEATER_SVIDEO: - SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fSVideoPort); - SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_SVIDEO); - break; - default: - PRINT(("CTheater::SetADC() - Bad source\n")); - return; - } - - SetRegister(VIP_ADC_CNTL, I_CLAMP_SEL, I_CLAMP_SEL_22); - SetRegister(VIP_ADC_CNTL, I_AGC_SEL, I_AGC_SEL_7); - - SetRegister(VIP_ADC_CNTL, EXT_CLAMP_CAP, EXT_CLAMP_CAP_EXTERNAL); - SetRegister(VIP_ADC_CNTL, EXT_AGC_CAP, EXT_AGC_CAP_EXTERNAL); - SetRegister(VIP_ADC_CNTL, ADC_DECI_BYPASS, ADC_DECI_WITH_FILTER); - SetRegister(VIP_ADC_CNTL, VBI_DECI_BYPASS, VBI_DECI_WITH_FILTER); - SetRegister(VIP_ADC_CNTL, DECI_DITHER_EN, 0 << 12); - SetRegister(VIP_ADC_CNTL, ADC_CLK_SEL, ADC_CLK_SEL_8X); - SetRegister(VIP_ADC_CNTL, ADC_BYPASS, ADC_BYPASS_INTERNAL); - switch (standard) { - case C_THEATER_NTSC: - case C_THEATER_NTSC_JAPAN: - case C_THEATER_NTSC_443: - case C_THEATER_PAL_M: - SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_NTSC); - break; - case C_THEATER_PAL_BDGHI: - case C_THEATER_PAL_N: - case C_THEATER_PAL_60: - case C_THEATER_PAL_NC: - case C_THEATER_SECAM: - SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_PAL); - break; - } - SetRegister(VIP_ADC_CNTL, ADC_PAICM, 1 << 18); - - SetRegister(VIP_ADC_CNTL, ADC_PDCBIAS, 2 << 20); - SetRegister(VIP_ADC_CNTL, ADC_PREFHI, ADC_PREFHI_2_7); - SetRegister(VIP_ADC_CNTL, ADC_PREFLO, ADC_PREFLO_1_5); - - SetRegister(VIP_ADC_CNTL, ADC_IMUXOFF, 0 << 26); - SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0 << 27); -} - - -// setup horizontal sync PLL -void CTheater::SetHSYNC(theater_standard standard) -{ - static const uint16 hs_line_total[] = { - 0x38E, 0x38E, 0x46F, 0x38D, 0x46F, 0x395, 0x46F, 0x467, 0x46F }; - - static const uint32 hs_dto_inc[] = { - 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x3E7A2 }; - - // TK: completely different in gatos - static const uint8 hs_pll_sgain[] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2 }; - static const uint8 hs_pll_fgain[] = { - 8, 8, 8, 8, 8, 8, 8, 8, 8 }; - - static const uint8 gen_lock_delay[] = { - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }; - - static const uint8 min_pulse_width[] = { - 0x21, 0x21, 0x29, 0x21, 0x29, 0x21, 0x29, 0x29, 0x29 }; - static const uint8 max_pulse_width[] = { - 0x64, 0x64, 0x7D, 0x64, 0x7D, 0x65, 0x7D, 0x7D, 0x7D }; - - static const uint16 win_close_limit[] = { - 0x0A0, 0x0A0, 0x0C7, 0x0A0, 0x0C7, 0x0A0, 0x0C7, 0x0C7, 0x0C7 }; - static const uint16 win_open_limit[] = { - 0x1B7, 0x1B7, 0x228, 0x1B7, 0x228, 0x1BB, 0x228, 0x224, 0x228 }; - - - // set number of samples per line - SetRegister(VIP_HS_PLINE, HS_LINE_TOTAL, hs_line_total[standard]); - - SetRegister(VIP_HS_DTOINC, HS_DTO_INC, hs_dto_inc[standard]); - - SetRegister(VIP_HS_PLLGAIN, HS_PLL_SGAIN, hs_pll_sgain[standard] << 0); - SetRegister(VIP_HS_PLLGAIN, HS_PLL_FGAIN, (uint32)hs_pll_fgain[standard] << 4); - - SetRegister(VIP_HS_GENLOCKDELAY, GEN_LOCK_DELAY, gen_lock_delay[standard]); - - // set min/max pulse width in samples - SetRegister(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH, min_pulse_width[standard] << 0); - SetRegister(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH, (uint32)max_pulse_width[standard] << 8); - - SetRegister(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT, win_close_limit[standard] << 0); - SetRegister(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT, (uint32)win_open_limit[standard] << 16); - - - PRINT(("CTheater::SetHSYNC(total=%d, pulse=%d/%d, window=%d/%d)\n", - Register(VIP_HS_PLINE, HS_LINE_TOTAL), - Register(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH) >> 0, - Register(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH) >> 8, - Register(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT) >> 0, - Register(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT) >> 16)); -} - - -// wait until horizontal scaler is locked -void CTheater::WaitHSYNC() -{ - for (int timeout = 0; timeout < 1000; timeout++) { - if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0) - return; - snooze(20); - } - PRINT(("CTheater::WaitHSYNC() - wait for HSync locking time out!\n")); -} - - -// setup vertical sync and field detector -void CTheater::SetVSYNC(theater_standard standard) -{ - static const uint16 vsync_int_trigger[] = { - 0x2AA, 0x2AA, 0x353, 0x2AA, 0x353, 0x2B0, 0x353, 0x34D, 0x353 }; - static const uint16 vsync_int_hold[] = { - 0x017, 0x017, 0x01C, 0x017, 0x01C, 0x017, 0x01C, 0x01C, 0x01C }; - // PAL value changed from 26b to 26d - else, odd/even field detection fails sometimes; - // did the same for PAL N, PAL NC and SECAM - static const uint16 vs_field_blank_start[] = { - 0x206, 0x206, 0x206, 0x206, 0x26d, 0x26d, 0x26d, 0x206, 0x26d }; - static const uint8 vs_field_blank_end[] = { - 0x00a, 0x00a, 0x00a, 0x00a, 0x02a, 0x02a, 0x02a, 0x00a, 0x02a }; - // NTSC value changed from 1 to 105 - else, odd/even fields were always swapped; - // did the same for NTSC Japan, NTSC 443, PAL M and PAL 60 - static const uint16 vs_field_id_location[] = { - 0x105, 0x105, 0x105, 0x105, 0x1, 0x1, 0x1, 0x105, 0x1 }; - static const uint16 vs_frame_total[] = { - 0x217, 0x217, 0x217, 0x217, 0x27B, 0x27B, 0x27B, 0x217, 0x27B }; - - SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_TRIGGER, vsync_int_trigger[standard] << 0); - SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_HOLD, (uint32)vsync_int_hold[standard] << 16); - - SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_START, vs_field_blank_start[standard] << 0); - SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_END, (uint32)vs_field_blank_end[standard] << 16); - SetRegister(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL, vs_frame_total[standard]); - - SetRegister(VIP_VS_FIELD_ID_CNTL, VS_FIELD_ID_LOCATION, vs_field_id_location[standard] << 0); - - // auto-detect fields - SetRegister(VIP_VS_COUNTER_CNTL, FIELD_DETECT_MODE, FIELD_DETECT_DETECTED); - - // don't flip fields - SetRegister(VIP_VS_COUNTER_CNTL, FIELD_FLIP_EN, 0 ); - - PRINT(("CTheater::SetVSYNC(total=%d)\n", - Register(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL))); -} - -// wait until a visible line is viewed -void CTheater::WaitVSYNC() -{ - for (int timeout = 0; timeout < 1000; timeout++) { - int lineCount = Register(VIP_VS_LINE_COUNT, VS_LINE_COUNT); - if (lineCount > 1 && lineCount < 20) - return; - snooze(20); - } - PRINT(("CTheater::WaitVSYNC() - wait for VBI timed out!\n")); -} - - -// setup timing generator -void CTheater::SetSyncGenerator(theater_standard standard) -{ - static const uint16 blank_int_start[] = { - 0x031, 0x031, 0x046, 0x031, 0x046, 0x046, 0x046, 0x031, 0x046 }; - static const uint8 blank_int_length[] = { - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; - - static const uint16 sync_tip_start[] = { - 0x0372, 0x0372, 0x0453, 0x0371, 0x0453, 0x0379, 0x0453, 0x044B, 0x0453 }; - static const uint8 sync_tip_length[] = { - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; - - static const uint8 uv_int_start[] = { - 0x03B, 0x03B, 0x052, 0x03B, 0x052, 0x03B, 0x052, 0x03C, 0x068 }; - static const uint8 u_int_length[] = { - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; - static const uint8 v_int_length[] = { - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; - - // set blank interrupt position - SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_START, blank_int_start[standard] ); - SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH, (uint32)blank_int_length[standard] << 8); - - SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START, sync_tip_start[standard]); - SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH, (uint32)sync_tip_length[standard] << 12); - - SetRegister(VIP_SG_UVGATE_GATE, UV_INT_START, uv_int_start[standard] << 0); - - SetRegister(VIP_SG_UVGATE_GATE, U_INT_LENGTH, (uint32)u_int_length[standard] << 8); - SetRegister(VIP_SG_UVGATE_GATE, V_INT_LENGTH, (uint32)v_int_length[standard] << 12); - - PRINT(("CTheater::SetSyncGenerator(black=%d/%d, synctip=%d/%d, uvgate=%d/%d-%d)\n", - Register(VIP_SG_BLACK_GATE, BLANK_INT_START) >> 0, - Register(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH) >> 8, - Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START), - Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH) >> 12, - Register(VIP_SG_UVGATE_GATE, UV_INT_START), - Register(VIP_SG_UVGATE_GATE, U_INT_LENGTH) >> 8, - Register(VIP_SG_UVGATE_GATE, V_INT_LENGTH) >> 12)); -} - - -// setup input comb filter. -// this is really ugly but I cannot find a scheme -void CTheater::SetCombFilter(theater_standard standard, theater_source source) -{ - enum { - _3Tap_2D_adaptive_Comb = 1, // composite - _2Tap_C_combed_Y_Sub = 2, - _2Tap_C_combed_Y_combed = 3, - _3Tap_C_combed_Y_Sub = 4, - _3Tap_C_combed_Y_combed = 5, - YC_mode_Comb_filter_off = 6, // S-Video - YC_mode_2Tap_YV_filter = 7, - YC_mode_3Tap_YV_filter = 8 - }; - - // make sure to keep bitfield in sync with register definition! - // we could define each component as an uint8, but this would waste space - // and would require an extra register-composition - typedef struct { - LBITFIELD32_12 ( - comb_hck : 8, - comb_vck : 8, - comb_filter_en : 1, - comb_adaptiv_en : 1, - comb_bpfmuxsel : 3, - comb_coutsel : 2, - comb_sumdiff0sel : 1, - comb_sumdiff1sel : 2, - comb_yvlpfsel : 1, - comb_dlylinesel : 2, - comb_ydlyinsel : 2, - comb_ysubbw : 1 - ); - } comb_cntl0; - - typedef struct { - LBITFIELD32_7 ( - comb_ydlyoutsel : 2, - comb_coresize : 2, - comb_ysuben : 1, - comb_youtsel : 1, - comb_syncpfsel : 2, - comb_synclpfrst : 1, - comb_debug : 1 - ); - } comb_cntl1; - - typedef struct { - LBITFIELD32_4 ( - comb_hyk0 : 8, - comb_vyk0 : 8, - comb_hyk1 : 8, - comb_vyk1 : 8 - ); - } comb_cntl2; - - typedef struct { - LBITFIELD32_2 ( - comb_tap0length : 16, - comb_tap1length : 12 - ); - } comb_line_length; - - typedef struct { - const uint8 *types; - const comb_cntl0 *cntl0; - const comb_cntl1 *cntl1; - const comb_cntl2 *cntl2; - const comb_line_length *line_length; - } comb_settings; - - static const uint8 comb_types_ntsc_m[] = { - _3Tap_2D_adaptive_Comb, - _2Tap_C_combed_Y_Sub, - _2Tap_C_combed_Y_combed, - _3Tap_C_combed_Y_Sub, - _3Tap_C_combed_Y_combed, - YC_mode_Comb_filter_off, - YC_mode_2Tap_YV_filter, - YC_mode_3Tap_YV_filter, - 0 - }; - - static const comb_cntl0 comb_cntl0_ntsc_m[] = { - { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 1, 0 }, - { 0, 0, 1, 0, 1, 2, 0, 1, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 1, 2, 0, 1, 1, 1, 0, 0 }, - { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 2, 0 }, - { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 1, 0 }, - { 0, 0, 0, 0, 5, 2, 0, 0, 1, 1, 0, 0 } - }; - - static const comb_cntl1 comb_cntl1_ntsc_m[] = { - { 0, 0, 1, 0, 0, 0, 0 }, - { 2, 0, 1, 0, 0, 0, 0 }, - { 3, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 1, 0, 0 }, - { 3, 0, 0, 0, 1, 0, 0 }, - { 1, 0, 0, 0, 2, 0, 0 }, - { 3, 0, 0, 0, 0, 0, 0 }, - { 3, 0, 0, 0, 1, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_ntsc_m[] = { - { 0x10, 0x10, 0x16, 0x16 }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_ntsc_m[] = { - { 0x38A, 0x718 }, - { 0x38A, 0x718 }, - { 0x38A, 0x718 }, - { 0x38A, 0x718 }, - { 0x38A, 0x718 }, - { 0, 0 }, - { 0x38A, 0 }, - { 0x38A, 0x718 } - }; - - - static const uint8 comb_types_ntsc_433[] = { - _2Tap_C_combed_Y_Sub, - _2Tap_C_combed_Y_combed, - _3Tap_C_combed_Y_Sub, - _3Tap_C_combed_Y_combed, - YC_mode_Comb_filter_off, - YC_mode_2Tap_YV_filter, - YC_mode_3Tap_YV_filter, - 0 - }; - - static const comb_cntl0 comb_cntl0_ntsc_433[] = { - { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 1, 0 }, - { 0, 0, 1, 0, 1, 2, 0, 1, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 1, 2, 0, 1, 1, 1, 0, 0 }, - { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 2, 0 }, - { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 1, 0 }, - { 0, 0, 0, 0, 5, 2, 0, 0, 1, 1, 0, 0 } - }; - - static const comb_cntl1 comb_cntl1_ntsc_433[] = { - { 2, 0, 1, 0, 0, 0, 0 }, - { 3, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 1, 0, 0 }, - { 3, 0, 0, 0, 1, 0, 0 }, - { 1, 0, 0, 0, 2, 0, 0 }, - { 3, 0, 0, 0, 0, 0, 0 }, - { 3, 0, 0, 0, 1, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_ntsc_433[] = { - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_ntsc_433[] = { - { 0x462, 0x8C9 }, - { 0x462, 0x8C9 }, - { 0x462, 0x8C9 }, - { 0x462, 0x8C9 }, - { 0, 0 }, - { 0x462, 0x8C9 }, - { 0x462, 0x8C9 } - }; - - - static const uint8 comb_types_pal_m[] = { - _2Tap_C_combed_Y_Sub, - YC_mode_2Tap_YV_filter, - 0 - }; - - static const comb_cntl0 comb_cntl0_pal_m[] = { - { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, - { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } - }; - - static const comb_cntl1 comb_cntl1_pal_m[] = { - { 1, 0, 1, 1, 2, 0, 0 }, - { 1, 0, 0, 1, 2, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_pal_m[] = { - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_pal_m[] = { - { 0x389, 0 }, - { 0x389, 0 } - }; - - - static const uint8 comb_types_pal_n[] = { - _3Tap_2D_adaptive_Comb, - _2Tap_C_combed_Y_Sub, - YC_mode_2Tap_YV_filter, - 0 - }; - - static const comb_cntl0 comb_cntl0_pal_n[] = { - { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, - { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } - }; - - static const comb_cntl1 comb_cntl1_pal_n[] = { - { 0, 0, 1, 0, 0, 0, 0 }, - { 1, 0, 1, 1, 2, 0, 0 }, - { 1, 0, 0, 1, 2, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_pal_n[] = { - { 0x10, 0x10, 0x16, 0x16 }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_pal_n[] = { - { 0x46B, 0x8DA }, - { 0x46C, 0 }, - { 0x46C, 0 } - }; - - - static const uint8 comb_types_pal_nc[] = { - _3Tap_2D_adaptive_Comb, - _2Tap_C_combed_Y_Sub, - YC_mode_2Tap_YV_filter, - 0 - }; - - // used to represent an N/A for easier copy'n'paste -#define X 0 - - static const comb_cntl0 comb_cntl0_pal_nc[] = { - { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, - { X, X, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, - { X, X, 1, 0, 5, 0, 1, 2, X, 0, 2, 0 } - }; - - static const comb_cntl1 comb_cntl1_pal_nc[] = { - { 0, 0, 1, 0, 0, 0, 0 }, - { 1, 0, 1, 1, 2, 0, 0 }, - { 1, 0, 0, 1, 2, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_pal_nc[] = { - { 0x10, 0x10, 0x16, 0x16 }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_pal_nc[] = { - { 0x391, 0x726 }, - { 0x394, X }, - { 0x394, X } - }; - - - static const uint8 comb_types_pal[] = { - _3Tap_2D_adaptive_Comb, - _2Tap_C_combed_Y_Sub, - YC_mode_2Tap_YV_filter, - 0 - }; - - static const comb_cntl0 comb_cntl0_pal[] = { - { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, - { 0, 0, 1, 0, 5, 0, 1, 2, X, 0, 2, 0 } - }; - - static const comb_cntl1 comb_cntl1_pal[] = { - { 0, 0, 1, 0, 0, 0, 0 }, - { 1, 0, 1, 1, 2, 0, 0 }, - { 1, 0, 0, 1, 2, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_pal[] = { - { 2, 1, 8, 6 }, - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_pal[] = { - { 0x46B, 0x8DA }, - { 0x46C, X }, - { 0x46C, X } - }; - - - static const uint8 comb_types_pal_60[] = { - _2Tap_C_combed_Y_Sub, - YC_mode_2Tap_YV_filter, - 0 - }; - - static const comb_cntl0 comb_cntl0_pal_60[] = { - { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, - { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } - }; - - static const comb_cntl1 comb_cntl1_pal_60[] = { - { 1, 0, 1, 1, 2, 0, 0 }, - { 1, 0, 0, 1, 2, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_pal_60[] = { - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_pal_60[] = { - { 0x463, 0 }, - { 0x463, 0 } - }; - - - static const uint8 comb_types_secam[] = { - _2Tap_C_combed_Y_Sub, // could be another type, spec is unclear here - YC_mode_2Tap_YV_filter, - 0, - }; - - static const comb_cntl0 comb_cntl0_secam[] = { - { X, X, 0, 0, 4, X, X, X, X, 2, 2, 1 }, - { X, X, 0, 0, 5, X, X, X, X, 2, 2, X } - }; - - static const comb_cntl1 comb_cntl1_secam[] = { - { 1, 0, 1, 0, 2, 0, 0 }, - { 1, X, 0, 0, 2, 0, 0 } - }; - - static const comb_cntl2 comb_cntl2_secam[] = { - { 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF } - }; - - static const comb_line_length comb_line_length_secam[] = { - { 0x46A, 0 }, - { 0x46A, 0 } - }; - -#undef X - - static const comb_settings comb_settings_list[] = { - { comb_types_ntsc_m, comb_cntl0_ntsc_m, comb_cntl1_ntsc_m, comb_cntl2_ntsc_m, comb_line_length_ntsc_m }, - { comb_types_ntsc_m, comb_cntl0_ntsc_m, comb_cntl1_ntsc_m, comb_cntl2_ntsc_m, comb_line_length_ntsc_m }, - { comb_types_ntsc_433, comb_cntl0_ntsc_433, comb_cntl1_ntsc_433, comb_cntl2_ntsc_433, comb_line_length_ntsc_433 }, - { comb_types_pal_m, comb_cntl0_pal_m, comb_cntl1_pal_m, comb_cntl2_pal_m, comb_line_length_pal_m }, - { comb_types_pal_n, comb_cntl0_pal_n, comb_cntl1_pal_n, comb_cntl2_pal_n, comb_line_length_pal_n }, - { comb_types_pal_nc, comb_cntl0_pal_nc, comb_cntl1_pal_nc, comb_cntl2_pal_nc, comb_line_length_pal_nc }, - { comb_types_pal, comb_cntl0_pal, comb_cntl1_pal, comb_cntl2_pal, comb_line_length_pal }, - { comb_types_pal_60, comb_cntl0_pal_60, comb_cntl1_pal_60, comb_cntl2_pal_60, comb_line_length_pal_60 }, - { comb_types_secam, comb_cntl0_secam, comb_cntl1_secam, comb_cntl2_secam, comb_line_length_secam } - }; - - int min_type, max_type, type; - const comb_settings *settings; - int i = 0; - - PRINT(("CTheater::SetCombFilter(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); - - // I don't really understand what the different types mean; - // what is particularly strange is that many types are defined for few standards only - if( source == C_THEATER_TUNER || source == C_THEATER_COMPOSITE ) { - min_type = _3Tap_2D_adaptive_Comb; - max_type = _3Tap_C_combed_Y_combed; - } else { - min_type = YC_mode_Comb_filter_off; - max_type = YC_mode_3Tap_YV_filter; - } - - settings = &comb_settings_list[standard]; - - for( type = min_type; type <= max_type; ++type ) { - for( i = 0; settings->types[i]; ++i ) { - if( settings->types[i] == type ) - break; - } - - if( settings->types[i] != 0 ) - break; - } - - if( type > max_type ) { - PRINT(("CTheater::SetCombFilter() - No settings for this standard and input type combination!!!\n")); - return; - } - - SetRegister(VIP_COMB_CNTL0, *(const int32 *)(settings->cntl0 + i)); - SetRegister(VIP_COMB_CNTL1, *(const int32 *)(settings->cntl1 + i)); - SetRegister(VIP_COMB_CNTL2, *(const int32 *)(settings->cntl2 + i)); - SetRegister(VIP_COMB_LINE_LENGTH, *(const int32 *)(settings->line_length + i)); - - - // reset the comb filter - SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST); - SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST); -} - - -// setup luma processor -void CTheater::SetLuminanceProcessor(theater_standard standard) -{ - static const uint16 synctip_ref0[] = { - 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037 }; - static const uint16 synctip_ref1[] = { - 0x029, 0x029, 0x029, 0x029, 0x029, 0x026, 0x026, 0x026, 0x026 }; - static const uint16 clamp_ref[] = { - 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B }; - static const uint16 agc_peakwhite[] = { - 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF }; - static const uint16 vbi_peakwhite[] = { - 0x0D2, 0x0D2, 0xD2, 0x0D2, 0x0D2, 0x0C6, 0x0C6, 0x0C6, 0x0C6 }; - - static const uint16 wpa_threshold[] = { - 0x406, 0x406, 0x4FC, 0x406, 0x59C, 0x488, 0x59C, 0x59C, 0x57A }; - static const uint16 wpa_trigger_lo[] = { - 0x0B3, 0x0B3, 0x0B3, 0x0B3, 0x096, 0x096, 0x096, 0x0B3, 0x096 }; - static const uint16 wpa_trigger_hi[] = { - 0x21B, 0x21B, 0x21B, 0x21B, 0x1C2, 0x1C2, 0x1C2, 0x21B, 0x1C2 }; - static const uint16 lp_lockout_start[] = { - 0x206, 0x206, 0x206, 0x206, 0x263, 0x263, 0x263, 0x206, 0x263 }; - // PAL: changed 0x2c to 0x0c; NTSC: changed 0x21 to 0x0b - static const uint16 lp_lockout_end[] = { - 0x00B, 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00C, 0x00B, 0x00C }; - - PRINT(("CTheater::SetLuminanceProcessor(%c)\n", "NJ4MNCB6S"[standard])); - - SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0, synctip_ref0[standard] << 0); - SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF1, (uint32)synctip_ref1[standard] << 8); - SetRegister(VIP_LP_AGC_CLAMP_CNTL0, CLAMP_REF, (uint32)clamp_ref[standard] << 16); - SetRegister(VIP_LP_AGC_CLAMP_CNTL0, AGC_PEAKWHITE, (uint32)agc_peakwhite[standard] << 24); - SetRegister(VIP_LP_AGC_CLAMP_CNTL1, VBI_PEAKWHITE, (uint32)vbi_peakwhite[standard] << 0); - - SetRegister(VIP_LP_WPA_CNTL0, WPA_THRESHOLD, wpa_threshold[standard] << 0); - SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_LO, wpa_trigger_lo[standard] << 0); - SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_HI, (uint32)wpa_trigger_hi[standard] << 16); - SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_START, lp_lockout_start[standard] << 0); - SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_END, (uint32)lp_lockout_end[standard] << 16); -} - - -// setup brightness and contrast -void CTheater::SetLuminanceLevels(theater_standard standard, int brightness, int contrast) -{ - double ref0, setup, gain; - - ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0); - - switch (standard) { - case C_THEATER_NTSC: - case C_THEATER_PAL_M: - case C_THEATER_NTSC_443: - setup = 7.5 * ref0 / 40.0; - gain = 219.0 / (92.5 * ref0 / 40.0); - break; - - case C_THEATER_NTSC_JAPAN: - setup = 0.0; - gain = 219.0 / (100.0 * ref0 / 40.0); - break; - - case C_THEATER_PAL_BDGHI: - case C_THEATER_PAL_N: - case C_THEATER_SECAM: - case C_THEATER_PAL_60: - case C_THEATER_PAL_NC: - setup = 0.0; - gain = 219.0 / (100.0 * ref0 / 43.0); - break; - - default: - setup = 0.0; - gain = 0.0; - break; - } - - if (contrast <= -100) - contrast = -99; - - /* set luminance processor constrast (7:0) */ - SetRegister(VIP_LP_CONTRAST, CONTRAST, - int(64.0 * ((contrast + 100) / 100.0) * gain) << 0); - - /* set luminance processor brightness (13:0) */ - SetRegister(VIP_LP_BRIGHTNESS, BRIGHTNESS, - int(16.0 * ((brightness - setup) + 16.0 / ((contrast + 100) * gain / 100.0))) & BRIGHTNESS); -} - - -// setup chroma demodulator -void CTheater::SetChromaProcessor(theater_standard standard) -{ - PRINT(("CTheater::SetChromaProcessor(%c)\n", "NJ4MNCB6S"[standard])); - - static const uint32 ch_dto_inc[] = { - 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x3E7A28 }; - static const uint8 ch_pll_sgain[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 5 }; - static const uint8 ch_pll_fgain[] = { - 2, 2, 2, 2, 2, 2, 2, 2, 6 }; - - static const uint8 ch_height[] = { - 0xCD, 0xCD, 0xCD, 0x91, 0x91, 0x9C, 0x9C, 0x9C, 0x66 }; - static const uint8 ch_kill_level[] = { - 0x0C0, 0xC0, 0xC0, 0x8C, 0x8C, 0x90, 0x90, 0x90, 0x60 }; - static const uint8 ch_agc_error_lim[] = { - 2, 2, 2, 2, 2, 2, 2, 2, 3 }; - static const uint8 ch_agc_filter_en[] = { - 0, 0, 0, 0, 0, 0, 1, 0, 0 }; - static const uint8 ch_agc_loop_speed[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - static const uint16 cr_burst_gain[] = { - 0x7A, 0x71, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1FF }; - static const uint16 cb_burst_gain[] = { - 0xAC, 0x9F, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0x1FF }; - static const uint16 crdr_active_gain[] = { - 0x7A, 0x71, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x11C }; - static const uint16 cbdb_active_gain[] = { - 0xAC, 0x9F, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0x15A }; - static const uint16 cp_vert_lockout_start[] = { - 0x207, 0x207, 0x207, 0x207, 0x269, 0x269, 0x269, 0x207, 0x269 }; - static const uint8 cp_vert_lockout_end[] = { - 0x00E, 0x00E, 0x00E, 0x00E, 0x00E, 0x012, 0x012, 0x00E, 0x012 }; - - SetRegister(VIP_CP_PLL_CNTL0, CH_DTO_INC, ch_dto_inc[standard] << 0); - SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_SGAIN, (uint32)ch_pll_sgain[standard] << 24); - SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_FGAIN, (uint32)ch_pll_fgain[standard] << 28); - - SetRegister(VIP_CP_AGC_CNTL, CH_HEIGHT, ch_height[standard] << 0); - SetRegister(VIP_CP_AGC_CNTL, CH_KILL_LEVEL, (uint32)ch_kill_level[standard] << 8); - SetRegister(VIP_CP_AGC_CNTL, CH_AGC_ERROR_LIM, (uint32)ch_agc_error_lim[standard] << 16); - SetRegister(VIP_CP_AGC_CNTL, CH_AGC_FILTER_EN, (uint32)ch_agc_filter_en[standard] << 18); - SetRegister(VIP_CP_AGC_CNTL, CH_AGC_LOOP_SPEED, (uint32)ch_agc_loop_speed[standard] << 19); - - SetRegister(VIP_CP_BURST_GAIN, CR_BURST_GAIN, cr_burst_gain[standard] << 0); - SetRegister(VIP_CP_BURST_GAIN, CB_BURST_GAIN, (uint32)cb_burst_gain[standard] << 16); - - SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, crdr_active_gain[standard] << 0); - SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, (uint32)cbdb_active_gain[standard] << 16); - - SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_START, cp_vert_lockout_start[standard] << 0); - SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_END, (uint32)cp_vert_lockout_end[standard] << 16); -} - - -// set colour saturation and hue. -// hue makes sense for NTSC only and seems to act as saturation for PAL -void CTheater::SetChromaLevels(theater_standard standard, int saturation, int hue) -{ - int ref0; - double gain, CRgain, CBgain; - - /* compute Cr/Cb gains */ - ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0); - - switch (standard) { - case C_THEATER_NTSC: - case C_THEATER_NTSC_443: - case C_THEATER_PAL_M: - CRgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; - CBgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; - break; - - case C_THEATER_NTSC_JAPAN: - CRgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; - CBgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; - break; - - case C_THEATER_PAL_BDGHI: - case C_THEATER_PAL_60: - case C_THEATER_PAL_NC: - case C_THEATER_PAL_N: - CRgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; - CBgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; - break; - - case C_THEATER_SECAM: - CRgain = 32.0 * 32768.0 / 280000.0 / (33554432.0 / 35.46985) * (1.597 / 1.902) / 1.5; - CBgain = 32.0 * 32768.0 / 230000.0 / (33554432.0 / 35.46985) * (1.267 / 1.505) / 1.5; - break; - - default: - PRINT(("CTheater::SetChromaLevels() - Bad standard\n")); - CRgain = 0.0; - CBgain = 0.0; - break; - } - - if (saturation >= 0) - gain = 1.0 + 4.9 * saturation / 100.0; - else - gain = 1.0 + saturation / 100.0; - - SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, int(128 * CRgain * gain) << 0); - SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, int(128 * CBgain * gain) << 16); - - if (hue >= 0) - hue = (256 * hue) / 360; - else - hue = (256 * (hue + 360)) / 360; - - SetRegister(VIP_CP_HUE_CNTL, HUE_ADJ, hue << 0); -} - - -// these values are used by scaler as well -static const uint16 h_active_start[] = { - 0x06b, 0x06B, 0x07E, 0x067, 0x09A, 0x07D, 0x09A, 0x084, 0x095 }; -static const uint16 h_active_end[] = { - 0x363, 0x363, 0x42A, 0x363, 0x439, 0x439, 0x439, 0x363, 0x439 }; -static const uint16 v_active_start[] = { - 0x025, 0x025, 0x025, 0x025, 0x02E, 0x02E, 0x02E, 0x025, 0x02E }; -// PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d -// leads to trouble, and the last 2 lines seem to be used for VBI data -// (read: garbage) anyway -static const uint16 v_active_end[] = { - 0x204, 0x204, 0x204, 0x204, 0x269, 0x269, 0x269, 0x204, 0x269 }; -static const uint16 h_vbi_wind_start[] = { - 0x064, 0x064, 0x064, 0x064, 0x084, 0x084, 0x084, 0x064, 0x084 }; -static const uint16 h_vbi_wind_end[] = { - 0x366, 0x366, 0x366, 0x366, 0x41F, 0x41F, 0x41F, 0x366, 0x41F }; -static const uint16 v_vbi_wind_start[] = { - 0x00b, 0x00b, 0x00b, 0x00b, 0x008, 0x008, 0x008, 0x00b, 0x008 }; -static const uint16 v_vbi_wind_end[] = { - 0x024, 0x024, 0x024, 0x024, 0x02d, 0x02d, 0x02d, 0x024, 0x02d }; - -void CTheater::getActiveRange( theater_standard standard, CRadeonRect &rect ) -{ - rect.SetTo( - h_active_start[standard], v_active_start[standard], - h_active_end[standard], v_active_end[standard] ); -} - -void CTheater::getVBIRange( theater_standard standard, CRadeonRect &rect ) -{ - rect.SetTo( - h_vbi_wind_start[standard], v_vbi_wind_start[standard], - h_vbi_wind_end[standard], v_vbi_wind_end[standard] ); -} - -// program clipping engine -void CTheater::SetClipWindow(theater_standard standard, bool vbi) -{ - // set horizontal active window - SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START, h_active_start[standard] << 0); - SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END, (uint32)h_active_end[standard] << 16); - - // set vertical active window - SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START, v_active_start[standard] << 0); - SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END, (uint32)v_active_end[standard] << 16); - - // set horizontal VBI window - SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_START, h_vbi_wind_start[standard] << 0); - SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_END, (uint32)h_vbi_wind_end[standard] << 16); - - // set vertical VBI window - SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_START, v_vbi_wind_start[standard] << 0); - SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_END, (uint32)v_vbi_wind_end[standard] << 16); - - // set VBI scaler control - SetRegister(VIP_VBI_SCALER_CONTROL, (1 << 16) & VBI_SCALING_RATIO); - - // enable/disable VBI capture - SetRegister(VIP_VBI_CONTROL, VBI_CAPTURE_ENABLE, - vbi ? VBI_CAPTURE_EN : VBI_CAPTURE_DIS); - - PRINT(("CTheater::SetClipWindow(active=%d/%d/%d/%d, vbi=%d/%d/%d/%d)\n", - Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START) >> 0, - Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END) >> 16, - Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START) >> 0, - Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END) >> 16, - Register(VIP_H_VBI_WINDOW, H_VBI_WIND_START) >> 0, - Register(VIP_H_VBI_WINDOW, H_VBI_WIND_END) >> 16, - Register(VIP_V_VBI_WINDOW, V_VBI_WIND_START) >> 0, - Register(VIP_V_VBI_WINDOW, V_VBI_WIND_END) >> 16)); - -} - - -// setup capture scaler. -void CTheater::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace) -{ - int oddOffset, evenOffset; - uint16 h_active_width, v_active_height; - -// ASSERT(vactive <= 511); - - // TK: Gatos uses different values here - h_active_width = h_active_end[standard] - h_active_start[standard] + 1; - v_active_height = v_active_end[standard] - v_active_start[standard] + 1; - - // for PAL, we have 572 lines only, but need 576 lines; - // my attempts to find those missing lines all failed, so if the application requests - // 576 lines, we had to upscale the video which is not supported by hardware; - // solution: restrict to 572 lines - the scaler will fill out the missing lines with black - if( vactive > v_active_height ) - vactive = v_active_height; - - if (deinterlace) { - // progressive scan - evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height); - } - else { - // interlaced - evenOffset = (int) ((512 * vactive) / v_active_height); - oddOffset = 2048 - evenOffset; - } - - // set scale input window - SetRegister(VIP_SCALER_IN_WINDOW, H_IN_WIND_START, h_active_start[standard] << 0); - SetRegister(VIP_SCALER_IN_WINDOW, V_IN_WIND_START, (uint32)v_active_start[standard] << 16); - - SetRegister(VIP_SCALER_OUT_WINDOW, H_OUT_WIND_WIDTH, hactive << 0); - SetRegister(VIP_SCALER_OUT_WINDOW, V_OUT_WIND_HEIGHT, (vactive / 2) << 16); - - SetRegister(VIP_H_SCALER_CONTROL, H_SCALE_RATIO, (((uint32)h_active_width << 16) / hactive) << 0); - SetRegister(VIP_V_SCALER_CONTROL, V_SCALE_RATIO, ((vactive << 11) / v_active_height) << 0); - - // enable horizontal and vertical scaler - SetRegister(VIP_H_SCALER_CONTROL, H_BYPASS, - h_active_width == hactive ? H_BYPASS : 0); - SetRegister(VIP_V_SCALER_CONTROL, V_BYPASS, - v_active_height == vactive ? V_BYPASS : 0); - - // set deinterlace control - SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0); - SetRegister(VIP_V_DEINTERLACE_CONTROL, EVENF_OFFSET, evenOffset << 0); - SetRegister(VIP_V_DEINTERLACE_CONTROL, ODDF_OFFSET, oddOffset << 11); - - SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0); - - PRINT(("CTheater::SetScaler(active=%d/%d/%d/%d, scale=%d/%d)\n", - Register(VIP_SCALER_IN_WINDOW, H_IN_WIND_START) >> 0, - Register(VIP_SCALER_IN_WINDOW, V_IN_WIND_START) >> 16, - hactive, vactive, - Register(VIP_H_SCALER_CONTROL, H_SCALE_RATIO), - Register(VIP_V_SCALER_CONTROL, V_SCALE_RATIO))); -} - - int CTheater::Register(int index) { return fPort.Register(fDevice, index); @@ -1347,17 +68,3 @@ void CTheater::SetRegister(int index, int mask, int value) fPort.SetRegister(fDevice, index, (fPort.Register(fDevice, index) & ~mask) | (value & mask)); } - -int CTheater::CurrentLine() -{ - return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT; -} - -void CTheater::PrintToStream() -{ - PRINT(("<<< Rage Theater Registers >>>\n")); - for (int index = 0x0400; index <= 0x06ff; index += 4) { - int value = Register(index); - PRINT(("REG_0x%04x = 0x%08x\n", index, value)); - } -} diff --git a/src/add-ons/media/media-add-ons/radeon/Theater.h b/src/add-ons/media/media-add-ons/radeon/Theater.h index f4502c958e..ac4d691964 100644 --- a/src/add-ons/media/media-add-ons/radeon/Theater.h +++ b/src/add-ons/media/media-add-ons/radeon/Theater.h @@ -7,7 +7,6 @@ / Copyright 2001, Carlos Hasan / *******************************************************************************/ - #ifndef __THEATER_H__ #define __THEATER_H__ @@ -15,8 +14,9 @@ #include "VIPPort.h" enum theater_identifier { - C_THEATER_VIP_VENDOR_ID = 0x1002, - C_THEATER_VIP_DEVICE_ID = 0x4d54 +// C_THEATER_VIP_VENDOR_ID = 0x1002, + C_THEATER100_VIP_DEVICE_ID = 0x4D541002, + C_THEATER200_VIP_DEVICE_ID = 0x4d4a1002 }; @@ -39,71 +39,43 @@ enum theater_source { C_THEATER_SVIDEO = 2 }; - class CTheater { public: - CTheater(CRadeon & radeon); + CTheater(CRadeon & radeon, int device); - ~CTheater(); + virtual ~CTheater(); - status_t InitCheck() const; + virtual status_t InitCheck() const = 0; - void Reset(); + virtual void Reset() = 0; - void SetEnable(bool enable, bool vbi); + virtual void SetEnable(bool enable, bool vbi) = 0; - void SetStandard(theater_standard standard, theater_source source); + virtual void SetStandard(theater_standard standard, theater_source source) = 0; - void SetSize(int hactive, int vactive); + virtual void SetSize(int hactive, int vactive) = 0; - void SetDeinterlace(bool deinterlace); + virtual void SetDeinterlace(bool deinterlace) = 0; - void SetSharpness(int sharpness); + virtual void SetSharpness(int sharpness) = 0; - void SetBrightness(int brightness); + virtual void SetBrightness(int brightness) = 0; - void SetContrast(int contrast); + virtual void SetContrast(int contrast) = 0; - void SetSaturation(int saturation); + virtual void SetSaturation(int saturation) = 0; - void SetHue(int hue); + virtual void SetHue(int hue) = 0; - int CurrentLine(); + virtual int CurrentLine() = 0; - void getActiveRange( theater_standard standard, CRadeonRect &rect ); + virtual void getActiveRange( theater_standard standard, CRadeonRect &rect ) = 0; - void getVBIRange( theater_standard standard, CRadeonRect &rect ); + virtual void getVBIRange( theater_standard standard, CRadeonRect &rect ) = 0; - void PrintToStream(); + virtual void PrintToStream() = 0; -private: - void SetClock(theater_standard standard, radeon_video_clock clock); - - void SetADC(theater_standard standard, theater_source source); - - void SetHSYNC(theater_standard standard); - - void WaitHSYNC(); - - void SetVSYNC(theater_standard standard); - - void WaitVSYNC(); - - void SetSyncGenerator(theater_standard standard); - - void SetCombFilter(theater_standard standard, theater_source source); - - void SetLuminanceProcessor(theater_standard standard); - - void SetLuminanceLevels(theater_standard standard, int brightness, int contrast); - - void SetChromaProcessor(theater_standard standard); - - void SetChromaLevels(theater_standard standard, int saturation, int hue); - - void SetClipWindow(theater_standard standard, bool vbi); - - void SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace); + uint32 Capabilities() const; public: int Register(int index); @@ -114,7 +86,7 @@ public: void SetRegister(int index, int mask, int value); -private: +protected: CVIPPort fPort; int fDevice; radeon_video_clock fClock; diff --git a/src/add-ons/media/media-add-ons/radeon/Theater100.cpp b/src/add-ons/media/media-add-ons/radeon/Theater100.cpp new file mode 100644 index 0000000000..7a4f9fd95c --- /dev/null +++ b/src/add-ons/media/media-add-ons/radeon/Theater100.cpp @@ -0,0 +1,1327 @@ +/****************************************************************************** +/ +/ File: Theater.cpp +/ +/ Description: ATI Rage Theater Video Decoder interface. +/ +/ Copyright 2001, Carlos Hasan +/ +*******************************************************************************/ + +#include +#include "Theater100.h" +#include "Theater.h" +#include "TheatreReg.h" +#include "lendian_bitfield.h" + +CTheater100::CTheater100(CRadeon & radeon, int device) +:CTheater(radeon, device) +{ + PRINT(("CTheater100::CTheater100()\n")); + + if( fPort.InitCheck() == B_OK ) { + radeon_video_tuner tuner; + radeon_video_decoder video; + + radeon.GetMMParameters(tuner, video, fClock, + fTunerPort, fCompositePort, fSVideoPort); + + if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ && + fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ) + PRINT(("CTheater100::CTheater100() - Unsupported crystal clock!\n")); + + //fDevice = fPort.FindVIPDevice( C_THEATER100_VIP_DEVICE_ID ); + + } + + if( InitCheck() != B_OK ) + PRINT(("CTheater100::CTheater100() - Rage Theater not found!\n")); +} + +CTheater100::~CTheater100() +{ + PRINT(("CTheater100::~CTheater100()\n")); + + if( InitCheck() == B_OK ) + SetEnable(false, false); +} + +status_t CTheater100::InitCheck() const +{ + status_t res; + + res = fPort.InitCheck(); + if( res != B_OK ) + return res; + + return (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR; +} + +void CTheater100::Reset() +{ + PRINT(("CTheater100::Reset()\n")); + + SetHue(0); + SetBrightness(0); + SetSaturation(0); + SetContrast(0); + SetSharpness(false); +} + +// disable/enable capturing +void CTheater100::SetEnable(bool enable, bool vbi) +{ + PRINT(("CTheater100::SetEnable(%d, %d)\n", enable, vbi)); + +#if 0 + //@ reset ADC? + SetRegister(VIP_ADC_CNTL, ADC_CPRESET, ADC_CPRESET); + snooze(1000); + SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0); + snooze(1000); + SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_DOWN); +#endif + + + WaitVSYNC(); + + /* Disable the Video In, Scaler and DVS port */ + SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, VIN_ASYNC_RST); + SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, DVS_ASYNC_RST); + + /* select the reference clock for the Video In */ + SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK); + + /* reset the VIN/L54 PLL clocks */ + SetRegister(VIP_PLL_CNTL1, VINRST, VINRST); + SetRegister(VIP_PLL_CNTL1, L54RST, L54RST); + + /* power down the ADC block */ + SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN); + + /* set DVS port to input mode */ + SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_INPUT); + + /* select DVS clock to 8xFsc and disable continuous mode */ + SetRegister(VIP_DVS_PORT_CTRL, DVS_CLK_SELECT, DVS_CLK_SELECT_8X); + SetRegister(VIP_DVS_PORT_CTRL, CONTINUOUS_STREAM, 0); + + if (enable) { + WaitVSYNC(); + + SetClock(fStandard, fClock); + SetADC(fStandard, fSource); + SetLuminanceProcessor(fStandard); + SetChromaProcessor(fStandard); + SetVSYNC(fStandard); + SetClipWindow(fStandard, vbi); + SetCombFilter(fStandard, fSource); + SetHSYNC(fStandard); + SetSyncGenerator(fStandard); + SetScaler(fStandard, fHActive, fVActive, fDeinterlace); + + /* Enable ADC block */ + SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP); + + WaitVSYNC(); + + /* Enable the Video In, Scaler and DVS port */ + SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, 0); + SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, 0); + + /* set DVS port to output mode */ + SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_OUTPUT); + + //WaitHSYNC(); + + /* restore luminance and chroma settings */ + SetLuminanceLevels(fStandard, fBrightness, fContrast); + SetChromaLevels(fStandard, fSaturation, fHue); + } +} + +void CTheater100::SetStandard(theater_standard standard, theater_source source) +{ + PRINT(("CTheater100::SetStandard(%s, %s)\n", + "NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0" + "PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0" + "SECAM\0\0\0\0\0"+10*standard, + "TUNER\0COMP\0\0SVIDEO"+6*source)); + + fStandard = standard; + fSource = source; +} + +void CTheater100::SetSize(int hactive, int vactive) +{ + PRINT(("CTheater100::SetSize(%d, %d)\n", hactive, vactive)); + + fHActive = hactive; + fVActive = vactive; +} + +void CTheater100::SetDeinterlace(bool deinterlace) +{ + PRINT(("CTheater100::SetDeinterlace(%d)\n", deinterlace)); + + fDeinterlace = deinterlace; +} + +void CTheater100::SetSharpness(int sharpness) +{ + PRINT(("CTheater100::SetSharpness(%d)\n", sharpness)); + + SetRegister(VIP_H_SCALER_CONTROL, H_SHARPNESS, sharpness << 25); +} + +void CTheater100::SetBrightness(int brightness) +{ + PRINT(("CTheater100::SetBrightness(%d)\n", brightness)); + + fBrightness = brightness; + SetLuminanceLevels(fStandard, fBrightness, fContrast); +} + +void CTheater100::SetContrast(int contrast) +{ + PRINT(("CTheater100::SetContrast(%d)\n", contrast)); + + fContrast = contrast; + SetLuminanceLevels(fStandard, fBrightness, fContrast); +} + +void CTheater100::SetSaturation(int saturation) +{ + PRINT(("CTheater100::SetSaturation(%d)\n", saturation)); + + fSaturation = saturation; + SetChromaLevels(fStandard, fSaturation, fHue); +} + +void CTheater100::SetHue(int hue) +{ + PRINT(("CTheater100::SetHue(%d)\n", hue)); + + fHue = hue; + SetChromaLevels(fStandard, fSaturation, fHue); +} + + +// set pixel clock +void CTheater100::SetClock(theater_standard standard, radeon_video_clock clock) +{ + // set VIN PLL clock dividers + int referenceDivider, feedbackDivider, postDivider; + + switch (standard) { + case C_THEATER_NTSC: + case C_THEATER_NTSC_JAPAN: + if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { + referenceDivider = 0x39; + feedbackDivider = 0x14c; + postDivider = 0x6; + } + else { + referenceDivider = 0x0b; + feedbackDivider = 0x46; + postDivider = 0x6; + } + break; + case C_THEATER_NTSC_443: + if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { + referenceDivider = 0x23; + feedbackDivider = 0x88; + postDivider = 0x7; + } + else { + referenceDivider = 0x2c; + feedbackDivider = 0x121; + postDivider = 0x5; + } + break; + case C_THEATER_PAL_M: + if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { + referenceDivider = 0x2c; + feedbackDivider = 0x12b; + postDivider = 0x7; + } + else { + referenceDivider = 0x0b; + feedbackDivider = 0x46; + postDivider = 0x6; + } + break; + case C_THEATER_PAL_BDGHI: + case C_THEATER_PAL_N: + case C_THEATER_PAL_60: + case C_THEATER_SECAM: + if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { + referenceDivider = 0x0e; + feedbackDivider = 0x65; + postDivider = 0x6; + } + else { + referenceDivider = 0x2c; + feedbackDivider = 0x121; + postDivider = 0x5; + } + break; + case C_THEATER_PAL_NC: + if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { + referenceDivider = 0x23; + feedbackDivider = 0x88; + postDivider = 0x7; + } + else { + referenceDivider = 0x37; + feedbackDivider = 0x1d3; + postDivider = 0x8; + } + break; + default: + PRINT(("CTheater100::SetClock() - Bad standard\n")); + return; + } + + // reset VIN PLL and select the reference clock + SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK); + SetRegister(VIP_PLL_CNTL1, VINRST, VINRST); + SetRegister(VIP_PLL_CNTL1, L54RST, L54RST); + + // set up the VIN PLL clock control + SetRegister(VIP_VIN_PLL_CNTL, VIN_M0, referenceDivider << 0); + SetRegister(VIP_VIN_PLL_CNTL, VIN_N0, feedbackDivider << 11); + SetRegister(VIP_VIN_PLL_CNTL, VIN_P, postDivider << 24); + + // active the VIN/L54 PLL and attach the VIN PLL to the VIN clock + SetRegister(VIP_PLL_CNTL1, VINRST, 0); + SetRegister(VIP_PLL_CNTL1, L54RST, 0); + SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_VIPLL_CLK); + + PRINT(("CTheater100::SetClock(Fsamp=%g, Fref=%g)\n", + ((fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0) * feedbackDivider) / (referenceDivider * postDivider), + (fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0))); +} + + +// setup analog-digital converter +void CTheater100::SetADC(theater_standard standard, theater_source source) +{ + PRINT(("CTheater100::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); + + // set HW_DEBUG before setting the standard + SetRegister(VIP_HW_DEBUG, 0x0000f000); + + // select the video standard + switch (standard) { + case C_THEATER_NTSC: + case C_THEATER_NTSC_JAPAN: + case C_THEATER_NTSC_443: + case C_THEATER_PAL_M: + SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC); + break; + case C_THEATER_PAL_BDGHI: + case C_THEATER_PAL_N: + case C_THEATER_PAL_60: + case C_THEATER_PAL_NC: + SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL); + break; + case C_THEATER_SECAM: + SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM); + break; + default: + PRINT(("CTheater100::SetADC() - Bad standard\n")); + return; + } + + // select input connector and Y/C mode + switch (source) { + case C_THEATER_TUNER: + SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fTunerPort); + SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE); + break; + case C_THEATER_COMPOSITE: + SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fCompositePort); + SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE); + break; + case C_THEATER_SVIDEO: + SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fSVideoPort); + SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_SVIDEO); + break; + default: + PRINT(("CTheater100::SetADC() - Bad source\n")); + return; + } + + SetRegister(VIP_ADC_CNTL, I_CLAMP_SEL, I_CLAMP_SEL_22); + SetRegister(VIP_ADC_CNTL, I_AGC_SEL, I_AGC_SEL_7); + + SetRegister(VIP_ADC_CNTL, EXT_CLAMP_CAP, EXT_CLAMP_CAP_EXTERNAL); + SetRegister(VIP_ADC_CNTL, EXT_AGC_CAP, EXT_AGC_CAP_EXTERNAL); + SetRegister(VIP_ADC_CNTL, ADC_DECI_BYPASS, ADC_DECI_WITH_FILTER); + SetRegister(VIP_ADC_CNTL, VBI_DECI_BYPASS, VBI_DECI_WITH_FILTER); + SetRegister(VIP_ADC_CNTL, DECI_DITHER_EN, 0 << 12); + SetRegister(VIP_ADC_CNTL, ADC_CLK_SEL, ADC_CLK_SEL_8X); + SetRegister(VIP_ADC_CNTL, ADC_BYPASS, ADC_BYPASS_INTERNAL); + switch (standard) { + case C_THEATER_NTSC: + case C_THEATER_NTSC_JAPAN: + case C_THEATER_NTSC_443: + case C_THEATER_PAL_M: + SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_NTSC); + break; + case C_THEATER_PAL_BDGHI: + case C_THEATER_PAL_N: + case C_THEATER_PAL_60: + case C_THEATER_PAL_NC: + case C_THEATER_SECAM: + SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_PAL); + break; + } + SetRegister(VIP_ADC_CNTL, ADC_PAICM, 1 << 18); + + SetRegister(VIP_ADC_CNTL, ADC_PDCBIAS, 2 << 20); + SetRegister(VIP_ADC_CNTL, ADC_PREFHI, ADC_PREFHI_2_7); + SetRegister(VIP_ADC_CNTL, ADC_PREFLO, ADC_PREFLO_1_5); + + SetRegister(VIP_ADC_CNTL, ADC_IMUXOFF, 0 << 26); + SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0 << 27); +} + + +// setup horizontal sync PLL +void CTheater100::SetHSYNC(theater_standard standard) +{ + static const uint16 hs_line_total[] = { + 0x38E, 0x38E, 0x46F, 0x38D, 0x46F, 0x395, 0x46F, 0x467, 0x46F }; + + static const uint32 hs_dto_inc[] = { + 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x3E7A2 }; + + // TK: completely different in gatos + static const uint8 hs_pll_sgain[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + static const uint8 hs_pll_fgain[] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8 }; + + static const uint8 gen_lock_delay[] = { + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }; + + static const uint8 min_pulse_width[] = { + 0x21, 0x21, 0x29, 0x21, 0x29, 0x21, 0x29, 0x29, 0x29 }; + static const uint8 max_pulse_width[] = { + 0x64, 0x64, 0x7D, 0x64, 0x7D, 0x65, 0x7D, 0x7D, 0x7D }; + + static const uint16 win_close_limit[] = { + 0x0A0, 0x0A0, 0x0C7, 0x0A0, 0x0C7, 0x0A0, 0x0C7, 0x0C7, 0x0C7 }; + static const uint16 win_open_limit[] = { + 0x1B7, 0x1B7, 0x228, 0x1B7, 0x228, 0x1BB, 0x228, 0x224, 0x228 }; + + + // set number of samples per line + SetRegister(VIP_HS_PLINE, HS_LINE_TOTAL, hs_line_total[standard]); + + SetRegister(VIP_HS_DTOINC, HS_DTO_INC, hs_dto_inc[standard]); + + SetRegister(VIP_HS_PLLGAIN, HS_PLL_SGAIN, hs_pll_sgain[standard] << 0); + SetRegister(VIP_HS_PLLGAIN, HS_PLL_FGAIN, (uint32)hs_pll_fgain[standard] << 4); + + SetRegister(VIP_HS_GENLOCKDELAY, GEN_LOCK_DELAY, gen_lock_delay[standard]); + + // set min/max pulse width in samples + SetRegister(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH, min_pulse_width[standard] << 0); + SetRegister(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH, (uint32)max_pulse_width[standard] << 8); + + SetRegister(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT, win_close_limit[standard] << 0); + SetRegister(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT, (uint32)win_open_limit[standard] << 16); + + + PRINT(("CTheater100::SetHSYNC(total=%d, pulse=%d/%d, window=%d/%d)\n", + Register(VIP_HS_PLINE, HS_LINE_TOTAL), + Register(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH) >> 0, + Register(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH) >> 8, + Register(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT) >> 0, + Register(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT) >> 16)); +} + + +// wait until horizontal scaler is locked +void CTheater100::WaitHSYNC() +{ + for (int timeout = 0; timeout < 1000; timeout++) { + if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0) + return; + snooze(20); + } + PRINT(("CTheater100::WaitHSYNC() - wait for HSync locking time out!\n")); +} + + +// setup vertical sync and field detector +void CTheater100::SetVSYNC(theater_standard standard) +{ + static const uint16 vsync_int_trigger[] = { + 0x2AA, 0x2AA, 0x353, 0x2AA, 0x353, 0x2B0, 0x353, 0x34D, 0x353 }; + static const uint16 vsync_int_hold[] = { + 0x017, 0x017, 0x01C, 0x017, 0x01C, 0x017, 0x01C, 0x01C, 0x01C }; + // PAL value changed from 26b to 26d - else, odd/even field detection fails sometimes; + // did the same for PAL N, PAL NC and SECAM + static const uint16 vs_field_blank_start[] = { + 0x206, 0x206, 0x206, 0x206, 0x26d, 0x26d, 0x26d, 0x206, 0x26d }; + static const uint8 vs_field_blank_end[] = { + 0x00a, 0x00a, 0x00a, 0x00a, 0x02a, 0x02a, 0x02a, 0x00a, 0x02a }; + // NTSC value changed from 1 to 105 - else, odd/even fields were always swapped; + // did the same for NTSC Japan, NTSC 443, PAL M and PAL 60 + static const uint16 vs_field_id_location[] = { + 0x105, 0x105, 0x105, 0x105, 0x1, 0x1, 0x1, 0x105, 0x1 }; + static const uint16 vs_frame_total[] = { + 0x217, 0x217, 0x217, 0x217, 0x27B, 0x27B, 0x27B, 0x217, 0x27B }; + + SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_TRIGGER, vsync_int_trigger[standard] << 0); + SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_HOLD, (uint32)vsync_int_hold[standard] << 16); + + SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_START, vs_field_blank_start[standard] << 0); + SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_END, (uint32)vs_field_blank_end[standard] << 16); + SetRegister(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL, vs_frame_total[standard]); + + SetRegister(VIP_VS_FIELD_ID_CNTL, VS_FIELD_ID_LOCATION, vs_field_id_location[standard] << 0); + + // auto-detect fields + SetRegister(VIP_VS_COUNTER_CNTL, FIELD_DETECT_MODE, FIELD_DETECT_DETECTED); + + // don't flip fields + SetRegister(VIP_VS_COUNTER_CNTL, FIELD_FLIP_EN, 0 ); + + PRINT(("CTheater100::SetVSYNC(total=%d)\n", + Register(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL))); +} + +// wait until a visible line is viewed +void CTheater100::WaitVSYNC() +{ + for (int timeout = 0; timeout < 1000; timeout++) { + int lineCount = Register(VIP_VS_LINE_COUNT, VS_LINE_COUNT); + if (lineCount > 1 && lineCount < 20) + return; + snooze(20); + } + PRINT(("CTheater100::WaitVSYNC() - wait for VBI timed out!\n")); +} + + +// setup timing generator +void CTheater100::SetSyncGenerator(theater_standard standard) +{ + static const uint16 blank_int_start[] = { + 0x031, 0x031, 0x046, 0x031, 0x046, 0x046, 0x046, 0x031, 0x046 }; + static const uint8 blank_int_length[] = { + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; + + static const uint16 sync_tip_start[] = { + 0x0372, 0x0372, 0x0453, 0x0371, 0x0453, 0x0379, 0x0453, 0x044B, 0x0453 }; + static const uint8 sync_tip_length[] = { + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; + + static const uint8 uv_int_start[] = { + 0x03B, 0x03B, 0x052, 0x03B, 0x052, 0x03B, 0x052, 0x03C, 0x068 }; + static const uint8 u_int_length[] = { + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; + static const uint8 v_int_length[] = { + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; + + // set blank interrupt position + SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_START, blank_int_start[standard] ); + SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH, (uint32)blank_int_length[standard] << 8); + + SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START, sync_tip_start[standard]); + SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH, (uint32)sync_tip_length[standard] << 12); + + SetRegister(VIP_SG_UVGATE_GATE, UV_INT_START, uv_int_start[standard] << 0); + + SetRegister(VIP_SG_UVGATE_GATE, U_INT_LENGTH, (uint32)u_int_length[standard] << 8); + SetRegister(VIP_SG_UVGATE_GATE, V_INT_LENGTH, (uint32)v_int_length[standard] << 12); + + PRINT(("CTheater100::SetSyncGenerator(black=%d/%d, synctip=%d/%d, uvgate=%d/%d-%d)\n", + Register(VIP_SG_BLACK_GATE, BLANK_INT_START) >> 0, + Register(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH) >> 8, + Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START), + Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH) >> 12, + Register(VIP_SG_UVGATE_GATE, UV_INT_START), + Register(VIP_SG_UVGATE_GATE, U_INT_LENGTH) >> 8, + Register(VIP_SG_UVGATE_GATE, V_INT_LENGTH) >> 12)); +} + + +// setup input comb filter. +// this is really ugly but I cannot find a scheme +void CTheater100::SetCombFilter(theater_standard standard, theater_source source) +{ + enum { + _3Tap_2D_adaptive_Comb = 1, // composite + _2Tap_C_combed_Y_Sub = 2, + _2Tap_C_combed_Y_combed = 3, + _3Tap_C_combed_Y_Sub = 4, + _3Tap_C_combed_Y_combed = 5, + YC_mode_Comb_filter_off = 6, // S-Video + YC_mode_2Tap_YV_filter = 7, + YC_mode_3Tap_YV_filter = 8 + }; + + // make sure to keep bitfield in sync with register definition! + // we could define each component as an uint8, but this would waste space + // and would require an extra register-composition + typedef struct { + LBITFIELD32_12 ( + comb_hck : 8, + comb_vck : 8, + comb_filter_en : 1, + comb_adaptiv_en : 1, + comb_bpfmuxsel : 3, + comb_coutsel : 2, + comb_sumdiff0sel : 1, + comb_sumdiff1sel : 2, + comb_yvlpfsel : 1, + comb_dlylinesel : 2, + comb_ydlyinsel : 2, + comb_ysubbw : 1 + ); + } comb_cntl0; + + typedef struct { + LBITFIELD32_7 ( + comb_ydlyoutsel : 2, + comb_coresize : 2, + comb_ysuben : 1, + comb_youtsel : 1, + comb_syncpfsel : 2, + comb_synclpfrst : 1, + comb_debug : 1 + ); + } comb_cntl1; + + typedef struct { + LBITFIELD32_4 ( + comb_hyk0 : 8, + comb_vyk0 : 8, + comb_hyk1 : 8, + comb_vyk1 : 8 + ); + } comb_cntl2; + + typedef struct { + LBITFIELD32_2 ( + comb_tap0length : 16, + comb_tap1length : 12 + ); + } comb_line_length; + + typedef struct { + const uint8 *types; + const comb_cntl0 *cntl0; + const comb_cntl1 *cntl1; + const comb_cntl2 *cntl2; + const comb_line_length *line_length; + } comb_settings; + + static const uint8 comb_types_ntsc_m[] = { + _3Tap_2D_adaptive_Comb, + _2Tap_C_combed_Y_Sub, + _2Tap_C_combed_Y_combed, + _3Tap_C_combed_Y_Sub, + _3Tap_C_combed_Y_combed, + YC_mode_Comb_filter_off, + YC_mode_2Tap_YV_filter, + YC_mode_3Tap_YV_filter, + 0 + }; + + static const comb_cntl0 comb_cntl0_ntsc_m[] = { + { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 1, 0 }, + { 0, 0, 1, 0, 1, 2, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 1, 2, 0, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 2, 0 }, + { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 1, 0 }, + { 0, 0, 0, 0, 5, 2, 0, 0, 1, 1, 0, 0 } + }; + + static const comb_cntl1 comb_cntl1_ntsc_m[] = { + { 0, 0, 1, 0, 0, 0, 0 }, + { 2, 0, 1, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 1, 0, 0 }, + { 3, 0, 0, 0, 1, 0, 0 }, + { 1, 0, 0, 0, 2, 0, 0 }, + { 3, 0, 0, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 1, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_ntsc_m[] = { + { 0x10, 0x10, 0x16, 0x16 }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_ntsc_m[] = { + { 0x38A, 0x718 }, + { 0x38A, 0x718 }, + { 0x38A, 0x718 }, + { 0x38A, 0x718 }, + { 0x38A, 0x718 }, + { 0, 0 }, + { 0x38A, 0 }, + { 0x38A, 0x718 } + }; + + + static const uint8 comb_types_ntsc_433[] = { + _2Tap_C_combed_Y_Sub, + _2Tap_C_combed_Y_combed, + _3Tap_C_combed_Y_Sub, + _3Tap_C_combed_Y_combed, + YC_mode_Comb_filter_off, + YC_mode_2Tap_YV_filter, + YC_mode_3Tap_YV_filter, + 0 + }; + + static const comb_cntl0 comb_cntl0_ntsc_433[] = { + { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 1, 0 }, + { 0, 0, 1, 0, 1, 2, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 1, 2, 0, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 2, 0 }, + { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 1, 0 }, + { 0, 0, 0, 0, 5, 2, 0, 0, 1, 1, 0, 0 } + }; + + static const comb_cntl1 comb_cntl1_ntsc_433[] = { + { 2, 0, 1, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 1, 0, 0 }, + { 3, 0, 0, 0, 1, 0, 0 }, + { 1, 0, 0, 0, 2, 0, 0 }, + { 3, 0, 0, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 1, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_ntsc_433[] = { + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_ntsc_433[] = { + { 0x462, 0x8C9 }, + { 0x462, 0x8C9 }, + { 0x462, 0x8C9 }, + { 0x462, 0x8C9 }, + { 0, 0 }, + { 0x462, 0x8C9 }, + { 0x462, 0x8C9 } + }; + + + static const uint8 comb_types_pal_m[] = { + _2Tap_C_combed_Y_Sub, + YC_mode_2Tap_YV_filter, + 0 + }; + + static const comb_cntl0 comb_cntl0_pal_m[] = { + { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, + { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } + }; + + static const comb_cntl1 comb_cntl1_pal_m[] = { + { 1, 0, 1, 1, 2, 0, 0 }, + { 1, 0, 0, 1, 2, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_pal_m[] = { + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_pal_m[] = { + { 0x389, 0 }, + { 0x389, 0 } + }; + + + static const uint8 comb_types_pal_n[] = { + _3Tap_2D_adaptive_Comb, + _2Tap_C_combed_Y_Sub, + YC_mode_2Tap_YV_filter, + 0 + }; + + static const comb_cntl0 comb_cntl0_pal_n[] = { + { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, + { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } + }; + + static const comb_cntl1 comb_cntl1_pal_n[] = { + { 0, 0, 1, 0, 0, 0, 0 }, + { 1, 0, 1, 1, 2, 0, 0 }, + { 1, 0, 0, 1, 2, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_pal_n[] = { + { 0x10, 0x10, 0x16, 0x16 }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_pal_n[] = { + { 0x46B, 0x8DA }, + { 0x46C, 0 }, + { 0x46C, 0 } + }; + + + static const uint8 comb_types_pal_nc[] = { + _3Tap_2D_adaptive_Comb, + _2Tap_C_combed_Y_Sub, + YC_mode_2Tap_YV_filter, + 0 + }; + + // used to represent an N/A for easier copy'n'paste +#define X 0 + + static const comb_cntl0 comb_cntl0_pal_nc[] = { + { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, + { X, X, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, + { X, X, 1, 0, 5, 0, 1, 2, X, 0, 2, 0 } + }; + + static const comb_cntl1 comb_cntl1_pal_nc[] = { + { 0, 0, 1, 0, 0, 0, 0 }, + { 1, 0, 1, 1, 2, 0, 0 }, + { 1, 0, 0, 1, 2, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_pal_nc[] = { + { 0x10, 0x10, 0x16, 0x16 }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_pal_nc[] = { + { 0x391, 0x726 }, + { 0x394, X }, + { 0x394, X } + }; + + + static const uint8 comb_types_pal[] = { + _3Tap_2D_adaptive_Comb, + _2Tap_C_combed_Y_Sub, + YC_mode_2Tap_YV_filter, + 0 + }; + + static const comb_cntl0 comb_cntl0_pal[] = { + { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, + { 0, 0, 1, 0, 5, 0, 1, 2, X, 0, 2, 0 } + }; + + static const comb_cntl1 comb_cntl1_pal[] = { + { 0, 0, 1, 0, 0, 0, 0 }, + { 1, 0, 1, 1, 2, 0, 0 }, + { 1, 0, 0, 1, 2, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_pal[] = { + { 2, 1, 8, 6 }, + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_pal[] = { + { 0x46B, 0x8DA }, + { 0x46C, X }, + { 0x46C, X } + }; + + + static const uint8 comb_types_pal_60[] = { + _2Tap_C_combed_Y_Sub, + YC_mode_2Tap_YV_filter, + 0 + }; + + static const comb_cntl0 comb_cntl0_pal_60[] = { + { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, + { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } + }; + + static const comb_cntl1 comb_cntl1_pal_60[] = { + { 1, 0, 1, 1, 2, 0, 0 }, + { 1, 0, 0, 1, 2, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_pal_60[] = { + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_pal_60[] = { + { 0x463, 0 }, + { 0x463, 0 } + }; + + + static const uint8 comb_types_secam[] = { + _2Tap_C_combed_Y_Sub, // could be another type, spec is unclear here + YC_mode_2Tap_YV_filter, + 0, + }; + + static const comb_cntl0 comb_cntl0_secam[] = { + { X, X, 0, 0, 4, X, X, X, X, 2, 2, 1 }, + { X, X, 0, 0, 5, X, X, X, X, 2, 2, X } + }; + + static const comb_cntl1 comb_cntl1_secam[] = { + { 1, 0, 1, 0, 2, 0, 0 }, + { 1, X, 0, 0, 2, 0, 0 } + }; + + static const comb_cntl2 comb_cntl2_secam[] = { + { 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF } + }; + + static const comb_line_length comb_line_length_secam[] = { + { 0x46A, 0 }, + { 0x46A, 0 } + }; + +#undef X + + static const comb_settings comb_settings_list[] = { + { comb_types_ntsc_m, comb_cntl0_ntsc_m, comb_cntl1_ntsc_m, comb_cntl2_ntsc_m, comb_line_length_ntsc_m }, + { comb_types_ntsc_m, comb_cntl0_ntsc_m, comb_cntl1_ntsc_m, comb_cntl2_ntsc_m, comb_line_length_ntsc_m }, + { comb_types_ntsc_433, comb_cntl0_ntsc_433, comb_cntl1_ntsc_433, comb_cntl2_ntsc_433, comb_line_length_ntsc_433 }, + { comb_types_pal_m, comb_cntl0_pal_m, comb_cntl1_pal_m, comb_cntl2_pal_m, comb_line_length_pal_m }, + { comb_types_pal_n, comb_cntl0_pal_n, comb_cntl1_pal_n, comb_cntl2_pal_n, comb_line_length_pal_n }, + { comb_types_pal_nc, comb_cntl0_pal_nc, comb_cntl1_pal_nc, comb_cntl2_pal_nc, comb_line_length_pal_nc }, + { comb_types_pal, comb_cntl0_pal, comb_cntl1_pal, comb_cntl2_pal, comb_line_length_pal }, + { comb_types_pal_60, comb_cntl0_pal_60, comb_cntl1_pal_60, comb_cntl2_pal_60, comb_line_length_pal_60 }, + { comb_types_secam, comb_cntl0_secam, comb_cntl1_secam, comb_cntl2_secam, comb_line_length_secam } + }; + + int min_type, max_type, type; + const comb_settings *settings; + int i = 0; + + PRINT(("CTheater100::SetCombFilter(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); + + // I don't really understand what the different types mean; + // what is particularly strange is that many types are defined for few standards only + if( source == C_THEATER_TUNER || source == C_THEATER_COMPOSITE ) { + min_type = _3Tap_2D_adaptive_Comb; + max_type = _3Tap_C_combed_Y_combed; + } else { + min_type = YC_mode_Comb_filter_off; + max_type = YC_mode_3Tap_YV_filter; + } + + settings = &comb_settings_list[standard]; + + for( type = min_type; type <= max_type; ++type ) { + for( i = 0; settings->types[i]; ++i ) { + if( settings->types[i] == type ) + break; + } + + if( settings->types[i] != 0 ) + break; + } + + if( type > max_type ) { + PRINT(("CTheater100::SetCombFilter() - No settings for this standard and input type combination!!!\n")); + return; + } + + SetRegister(VIP_COMB_CNTL0, *(const int32 *)(settings->cntl0 + i)); + SetRegister(VIP_COMB_CNTL1, *(const int32 *)(settings->cntl1 + i)); + SetRegister(VIP_COMB_CNTL2, *(const int32 *)(settings->cntl2 + i)); + SetRegister(VIP_COMB_LINE_LENGTH, *(const int32 *)(settings->line_length + i)); + + + // reset the comb filter + SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST); + SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST); +} + + +// setup luma processor +void CTheater100::SetLuminanceProcessor(theater_standard standard) +{ + static const uint16 synctip_ref0[] = { + 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037 }; + static const uint16 synctip_ref1[] = { + 0x029, 0x029, 0x029, 0x029, 0x029, 0x026, 0x026, 0x026, 0x026 }; + static const uint16 clamp_ref[] = { + 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B }; + static const uint16 agc_peakwhite[] = { + 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF }; + static const uint16 vbi_peakwhite[] = { + 0x0D2, 0x0D2, 0xD2, 0x0D2, 0x0D2, 0x0C6, 0x0C6, 0x0C6, 0x0C6 }; + + static const uint16 wpa_threshold[] = { + 0x406, 0x406, 0x4FC, 0x406, 0x59C, 0x488, 0x59C, 0x59C, 0x57A }; + static const uint16 wpa_trigger_lo[] = { + 0x0B3, 0x0B3, 0x0B3, 0x0B3, 0x096, 0x096, 0x096, 0x0B3, 0x096 }; + static const uint16 wpa_trigger_hi[] = { + 0x21B, 0x21B, 0x21B, 0x21B, 0x1C2, 0x1C2, 0x1C2, 0x21B, 0x1C2 }; + static const uint16 lp_lockout_start[] = { + 0x206, 0x206, 0x206, 0x206, 0x263, 0x263, 0x263, 0x206, 0x263 }; + // PAL: changed 0x2c to 0x0c; NTSC: changed 0x21 to 0x0b + static const uint16 lp_lockout_end[] = { + 0x00B, 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00C, 0x00B, 0x00C }; + + PRINT(("CTheater100::SetLuminanceProcessor(%c)\n", "NJ4MNCB6S"[standard])); + + SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0, synctip_ref0[standard] << 0); + SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF1, (uint32)synctip_ref1[standard] << 8); + SetRegister(VIP_LP_AGC_CLAMP_CNTL0, CLAMP_REF, (uint32)clamp_ref[standard] << 16); + SetRegister(VIP_LP_AGC_CLAMP_CNTL0, AGC_PEAKWHITE, (uint32)agc_peakwhite[standard] << 24); + SetRegister(VIP_LP_AGC_CLAMP_CNTL1, VBI_PEAKWHITE, (uint32)vbi_peakwhite[standard] << 0); + + SetRegister(VIP_LP_WPA_CNTL0, WPA_THRESHOLD, wpa_threshold[standard] << 0); + SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_LO, wpa_trigger_lo[standard] << 0); + SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_HI, (uint32)wpa_trigger_hi[standard] << 16); + SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_START, lp_lockout_start[standard] << 0); + SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_END, (uint32)lp_lockout_end[standard] << 16); +} + + +// setup brightness and contrast +void CTheater100::SetLuminanceLevels(theater_standard standard, int brightness, int contrast) +{ + double ref0, setup, gain; + + ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0); + + switch (standard) { + case C_THEATER_NTSC: + case C_THEATER_PAL_M: + case C_THEATER_NTSC_443: + setup = 7.5 * ref0 / 40.0; + gain = 219.0 / (92.5 * ref0 / 40.0); + break; + + case C_THEATER_NTSC_JAPAN: + setup = 0.0; + gain = 219.0 / (100.0 * ref0 / 40.0); + break; + + case C_THEATER_PAL_BDGHI: + case C_THEATER_PAL_N: + case C_THEATER_SECAM: + case C_THEATER_PAL_60: + case C_THEATER_PAL_NC: + setup = 0.0; + gain = 219.0 / (100.0 * ref0 / 43.0); + break; + + default: + setup = 0.0; + gain = 0.0; + break; + } + + if (contrast <= -100) + contrast = -99; + + /* set luminance processor constrast (7:0) */ + SetRegister(VIP_LP_CONTRAST, CONTRAST, + int(64.0 * ((contrast + 100) / 100.0) * gain) << 0); + + /* set luminance processor brightness (13:0) */ + SetRegister(VIP_LP_BRIGHTNESS, BRIGHTNESS, + int(16.0 * ((brightness - setup) + 16.0 / ((contrast + 100) * gain / 100.0))) & BRIGHTNESS); +} + + +// setup chroma demodulator +void CTheater100::SetChromaProcessor(theater_standard standard) +{ + PRINT(("CTheater100::SetChromaProcessor(%c)\n", "NJ4MNCB6S"[standard])); + + static const uint32 ch_dto_inc[] = { + 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x3E7A28 }; + static const uint8 ch_pll_sgain[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 5 }; + static const uint8 ch_pll_fgain[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 6 }; + + static const uint8 ch_height[] = { + 0xCD, 0xCD, 0xCD, 0x91, 0x91, 0x9C, 0x9C, 0x9C, 0x66 }; + static const uint8 ch_kill_level[] = { + 0x0C0, 0xC0, 0xC0, 0x8C, 0x8C, 0x90, 0x90, 0x90, 0x60 }; + static const uint8 ch_agc_error_lim[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 3 }; + static const uint8 ch_agc_filter_en[] = { + 0, 0, 0, 0, 0, 0, 1, 0, 0 }; + static const uint8 ch_agc_loop_speed[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + static const uint16 cr_burst_gain[] = { + 0x7A, 0x71, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1FF }; + static const uint16 cb_burst_gain[] = { + 0xAC, 0x9F, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0x1FF }; + static const uint16 crdr_active_gain[] = { + 0x7A, 0x71, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x11C }; + static const uint16 cbdb_active_gain[] = { + 0xAC, 0x9F, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0x15A }; + static const uint16 cp_vert_lockout_start[] = { + 0x207, 0x207, 0x207, 0x207, 0x269, 0x269, 0x269, 0x207, 0x269 }; + static const uint8 cp_vert_lockout_end[] = { + 0x00E, 0x00E, 0x00E, 0x00E, 0x00E, 0x012, 0x012, 0x00E, 0x012 }; + + SetRegister(VIP_CP_PLL_CNTL0, CH_DTO_INC, ch_dto_inc[standard] << 0); + SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_SGAIN, (uint32)ch_pll_sgain[standard] << 24); + SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_FGAIN, (uint32)ch_pll_fgain[standard] << 28); + + SetRegister(VIP_CP_AGC_CNTL, CH_HEIGHT, ch_height[standard] << 0); + SetRegister(VIP_CP_AGC_CNTL, CH_KILL_LEVEL, (uint32)ch_kill_level[standard] << 8); + SetRegister(VIP_CP_AGC_CNTL, CH_AGC_ERROR_LIM, (uint32)ch_agc_error_lim[standard] << 16); + SetRegister(VIP_CP_AGC_CNTL, CH_AGC_FILTER_EN, (uint32)ch_agc_filter_en[standard] << 18); + SetRegister(VIP_CP_AGC_CNTL, CH_AGC_LOOP_SPEED, (uint32)ch_agc_loop_speed[standard] << 19); + + SetRegister(VIP_CP_BURST_GAIN, CR_BURST_GAIN, cr_burst_gain[standard] << 0); + SetRegister(VIP_CP_BURST_GAIN, CB_BURST_GAIN, (uint32)cb_burst_gain[standard] << 16); + + SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, crdr_active_gain[standard] << 0); + SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, (uint32)cbdb_active_gain[standard] << 16); + + SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_START, cp_vert_lockout_start[standard] << 0); + SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_END, (uint32)cp_vert_lockout_end[standard] << 16); +} + + +// set colour saturation and hue. +// hue makes sense for NTSC only and seems to act as saturation for PAL +void CTheater100::SetChromaLevels(theater_standard standard, int saturation, int hue) +{ + int ref0; + double gain, CRgain, CBgain; + + /* compute Cr/Cb gains */ + ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0); + + switch (standard) { + case C_THEATER_NTSC: + case C_THEATER_NTSC_443: + case C_THEATER_PAL_M: + CRgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; + CBgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; + break; + + case C_THEATER_NTSC_JAPAN: + CRgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; + CBgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; + break; + + case C_THEATER_PAL_BDGHI: + case C_THEATER_PAL_60: + case C_THEATER_PAL_NC: + case C_THEATER_PAL_N: + CRgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; + CBgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; + break; + + case C_THEATER_SECAM: + CRgain = 32.0 * 32768.0 / 280000.0 / (33554432.0 / 35.46985) * (1.597 / 1.902) / 1.5; + CBgain = 32.0 * 32768.0 / 230000.0 / (33554432.0 / 35.46985) * (1.267 / 1.505) / 1.5; + break; + + default: + PRINT(("CTheater100::SetChromaLevels() - Bad standard\n")); + CRgain = 0.0; + CBgain = 0.0; + break; + } + + if (saturation >= 0) + gain = 1.0 + 4.9 * saturation / 100.0; + else + gain = 1.0 + saturation / 100.0; + + SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, int(128 * CRgain * gain) << 0); + SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, int(128 * CBgain * gain) << 16); + + if (hue >= 0) + hue = (256 * hue) / 360; + else + hue = (256 * (hue + 360)) / 360; + + SetRegister(VIP_CP_HUE_CNTL, HUE_ADJ, hue << 0); +} + + +// these values are used by scaler as well +static const uint16 h_active_start[] = { + 0x06b, 0x06B, 0x07E, 0x067, 0x09A, 0x07D, 0x09A, 0x084, 0x095 }; +static const uint16 h_active_end[] = { + 0x363, 0x363, 0x42A, 0x363, 0x439, 0x439, 0x439, 0x363, 0x439 }; +static const uint16 v_active_start[] = { + 0x025, 0x025, 0x025, 0x025, 0x02E, 0x02E, 0x02E, 0x025, 0x02E }; +// PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d +// leads to trouble, and the last 2 lines seem to be used for VBI data +// (read: garbage) anyway +static const uint16 v_active_end[] = { + 0x204, 0x204, 0x204, 0x204, 0x269, 0x269, 0x269, 0x204, 0x269 }; +static const uint16 h_vbi_wind_start[] = { + 0x064, 0x064, 0x064, 0x064, 0x084, 0x084, 0x084, 0x064, 0x084 }; +static const uint16 h_vbi_wind_end[] = { + 0x366, 0x366, 0x366, 0x366, 0x41F, 0x41F, 0x41F, 0x366, 0x41F }; +static const uint16 v_vbi_wind_start[] = { + 0x00b, 0x00b, 0x00b, 0x00b, 0x008, 0x008, 0x008, 0x00b, 0x008 }; +static const uint16 v_vbi_wind_end[] = { + 0x024, 0x024, 0x024, 0x024, 0x02d, 0x02d, 0x02d, 0x024, 0x02d }; + +void CTheater100::getActiveRange( theater_standard standard, CRadeonRect &rect ) +{ + rect.SetTo( + h_active_start[standard], v_active_start[standard], + h_active_end[standard], v_active_end[standard] ); +} + +void CTheater100::getVBIRange( theater_standard standard, CRadeonRect &rect ) +{ + rect.SetTo( + h_vbi_wind_start[standard], v_vbi_wind_start[standard], + h_vbi_wind_end[standard], v_vbi_wind_end[standard] ); +} + +// program clipping engine +void CTheater100::SetClipWindow(theater_standard standard, bool vbi) +{ + // set horizontal active window + SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START, h_active_start[standard] << 0); + SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END, (uint32)h_active_end[standard] << 16); + + // set vertical active window + SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START, v_active_start[standard] << 0); + SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END, (uint32)v_active_end[standard] << 16); + + // set horizontal VBI window + SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_START, h_vbi_wind_start[standard] << 0); + SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_END, (uint32)h_vbi_wind_end[standard] << 16); + + // set vertical VBI window + SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_START, v_vbi_wind_start[standard] << 0); + SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_END, (uint32)v_vbi_wind_end[standard] << 16); + + // set VBI scaler control + SetRegister(VIP_VBI_SCALER_CONTROL, (1 << 16) & VBI_SCALING_RATIO); + + // enable/disable VBI capture + SetRegister(VIP_VBI_CONTROL, VBI_CAPTURE_ENABLE, + vbi ? VBI_CAPTURE_EN : VBI_CAPTURE_DIS); + + PRINT(("CTheater100::SetClipWindow(active=%d/%d/%d/%d, vbi=%d/%d/%d/%d)\n", + Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START) >> 0, + Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END) >> 16, + Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START) >> 0, + Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END) >> 16, + Register(VIP_H_VBI_WINDOW, H_VBI_WIND_START) >> 0, + Register(VIP_H_VBI_WINDOW, H_VBI_WIND_END) >> 16, + Register(VIP_V_VBI_WINDOW, V_VBI_WIND_START) >> 0, + Register(VIP_V_VBI_WINDOW, V_VBI_WIND_END) >> 16)); + +} + + +// setup capture scaler. +void CTheater100::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace) +{ + int oddOffset, evenOffset; + uint16 h_active_width, v_active_height; + +// ASSERT(vactive <= 511); + + // TK: Gatos uses different values here + h_active_width = h_active_end[standard] - h_active_start[standard] + 1; + v_active_height = v_active_end[standard] - v_active_start[standard] + 1; + + // for PAL, we have 572 lines only, but need 576 lines; + // my attempts to find those missing lines all failed, so if the application requests + // 576 lines, we had to upscale the video which is not supported by hardware; + // solution: restrict to 572 lines - the scaler will fill out the missing lines with black + if( vactive > v_active_height ) + vactive = v_active_height; + + if (deinterlace) { + // progressive scan + evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height); + } + else { + // interlaced + evenOffset = (int) ((512 * vactive) / v_active_height); + oddOffset = 2048 - evenOffset; + } + + // set scale input window + SetRegister(VIP_SCALER_IN_WINDOW, H_IN_WIND_START, h_active_start[standard] << 0); + SetRegister(VIP_SCALER_IN_WINDOW, V_IN_WIND_START, (uint32)v_active_start[standard] << 16); + + SetRegister(VIP_SCALER_OUT_WINDOW, H_OUT_WIND_WIDTH, hactive << 0); + SetRegister(VIP_SCALER_OUT_WINDOW, V_OUT_WIND_HEIGHT, (vactive / 2) << 16); + + SetRegister(VIP_H_SCALER_CONTROL, H_SCALE_RATIO, (((uint32)h_active_width << 16) / hactive) << 0); + SetRegister(VIP_V_SCALER_CONTROL, V_SCALE_RATIO, ((vactive << 11) / v_active_height) << 0); + + // enable horizontal and vertical scaler + SetRegister(VIP_H_SCALER_CONTROL, H_BYPASS, + h_active_width == hactive ? H_BYPASS : 0); + SetRegister(VIP_V_SCALER_CONTROL, V_BYPASS, + v_active_height == vactive ? V_BYPASS : 0); + + // set deinterlace control + SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0); + SetRegister(VIP_V_DEINTERLACE_CONTROL, EVENF_OFFSET, evenOffset << 0); + SetRegister(VIP_V_DEINTERLACE_CONTROL, ODDF_OFFSET, oddOffset << 11); + + SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0); + + PRINT(("CTheater100::SetScaler(active=%d/%d/%d/%d, scale=%d/%d)\n", + Register(VIP_SCALER_IN_WINDOW, H_IN_WIND_START) >> 0, + Register(VIP_SCALER_IN_WINDOW, V_IN_WIND_START) >> 16, + hactive, vactive, + Register(VIP_H_SCALER_CONTROL, H_SCALE_RATIO), + Register(VIP_V_SCALER_CONTROL, V_SCALE_RATIO))); +} + +int CTheater100::CurrentLine() +{ + return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT; +} + +void CTheater100::PrintToStream() +{ + PRINT(("<<< Rage Theater Registers >>>\n")); + for (int index = 0x0400; index <= 0x06ff; index += 4) { + int value = Register(index); + value = value; // unused var if debug is off + PRINT(("REG_0x%04x = 0x%08x\n", index, value)); + } +} diff --git a/src/add-ons/media/media-add-ons/radeon/Theater100.h b/src/add-ons/media/media-add-ons/radeon/Theater100.h new file mode 100644 index 0000000000..03b4b45933 --- /dev/null +++ b/src/add-ons/media/media-add-ons/radeon/Theater100.h @@ -0,0 +1,86 @@ +/****************************************************************************** +/ +/ File: Theater.h +/ +/ Description: ATI Rage Theater Video Decoder interface. +/ +/ Copyright 2001, Carlos Hasan +/ +*******************************************************************************/ + +#ifndef __THEATER100_H__ +#define __THEATER100_H__ + +#include "Theater.h" +#include "Radeon.h" +#include "VIPPort.h" + +class CTheater100 : public CTheater +{ +public: + CTheater100(CRadeon & radeon, int device); + + ~CTheater100(); + + status_t InitCheck() const; + + void Reset(); + + void SetEnable(bool enable, bool vbi); + + void SetStandard(theater_standard standard, theater_source source); + + void SetSize(int hactive, int vactive); + + void SetDeinterlace(bool deinterlace); + + void SetSharpness(int sharpness); + + void SetBrightness(int brightness); + + void SetContrast(int contrast); + + void SetSaturation(int saturation); + + void SetHue(int hue); + + int CurrentLine(); + + void getActiveRange( theater_standard standard, CRadeonRect &rect ); + + void getVBIRange( theater_standard standard, CRadeonRect &rect ); + + void PrintToStream(); + +private: + void SetClock(theater_standard standard, radeon_video_clock clock); + + void SetADC(theater_standard standard, theater_source source); + + void SetHSYNC(theater_standard standard); + + void WaitHSYNC(); + + void SetVSYNC(theater_standard standard); + + void WaitVSYNC(); + + void SetSyncGenerator(theater_standard standard); + + void SetCombFilter(theater_standard standard, theater_source source); + + void SetLuminanceProcessor(theater_standard standard); + + void SetLuminanceLevels(theater_standard standard, int brightness, int contrast); + + void SetChromaProcessor(theater_standard standard); + + void SetChromaLevels(theater_standard standard, int saturation, int hue); + + void SetClipWindow(theater_standard standard, bool vbi); + + void SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace); + +}; + +#endif diff --git a/src/add-ons/media/media-add-ons/radeon/Theater200.cpp b/src/add-ons/media/media-add-ons/radeon/Theater200.cpp new file mode 100644 index 0000000000..c995764978 --- /dev/null +++ b/src/add-ons/media/media-add-ons/radeon/Theater200.cpp @@ -0,0 +1,1230 @@ +/****************************************************************************** +/ +/ File: Theater.cpp +/ +/ Description: ATI Rage Theater Video Decoder interface. +/ +/ Copyright 2001, Carlos Hasan +/ +*******************************************************************************/ + +#include +#include "Theater.h" +#include "Theater200.h" +#include "TheatreReg.h" +#include "lendian_bitfield.h" +#include +#include +#include + + +const char* DEFAULT_MICROC_PATH = "/boot/home/config/settings/Media/RageTheater200/ativmc20.cod"; +const char* DEFAULT_MICROC_TYPE = "BINARY"; + +CTheater200::CTheater200(CRadeon & radeon, int device) + :CTheater(radeon, device), + fMode(MODE_UNINITIALIZED), + microcode_path(NULL), + microcode_type(NULL) + +{ + PRINT(("CTheater200::CTheater200()\n")); + + fMode = MODE_UNINITIALIZED; + + if( fPort.InitCheck() == B_OK ) { + radeon_video_tuner tuner; + radeon_video_decoder video; + + radeon.GetMMParameters(tuner, video, fClock, + fTunerPort, fCompositePort, fSVideoPort); + + if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ && + fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ) + PRINT(("CTheater200::CTheater200() - Unsupported crystal clock!\n")); + + // fDevice = fPort.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID ); + + } + + if( InitCheck() != B_OK ) + PRINT(("CTheater200::CTheater200() - Rage Theater not found!\n")); + + InitTheatre(); + +} + +CTheater200::~CTheater200() +{ + PRINT(("CTheater200::~CTheater200()\n")); + + if( InitCheck() == B_OK ) + SetEnable(false, false); + +} + +status_t CTheater200::InitCheck() const +{ + status_t res; + + res = fPort.InitCheck(); + if( res != B_OK ) + { + PRINT(("CTheater200::InitCheck() fPort Failed\n")); + return res; + } + + res = (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR; + if( res != B_OK ) + { + PRINT(("CTheater200::InitCheck() Invalid VIP Channel\n")); + return res; + } + + if (fMode != MODE_INITIALIZED_FOR_TV_IN); + return B_ERROR; + + PRINT(("CTheater200::InitCheck() Sucess\n")); + return res; +} + +void CTheater200::Reset() +{ + PRINT(("CTheater200::Reset()\n")); + + SetHue(0); + SetBrightness(0); + SetSaturation(0); + SetContrast(0); + SetSharpness(false); +} + +status_t CTheater200::DSPLoadMicrocode(char* micro_path, char* micro_type, struct rt200_microc_data* microc_datap) +{ + FILE* file; + struct rt200_microc_head* microc_headp = µc_datap->microc_head; + struct rt200_microc_seg* seg_list = NULL; + struct rt200_microc_seg* curr_seg = NULL; + struct rt200_microc_seg* prev_seg = NULL; + uint32 i; + + if (micro_path == NULL) + return -1; + + if (micro_type == NULL) + return -1; + + file = fopen(micro_path, "r"); + if (file == NULL) { + PRINT(("Cannot open microcode file\n")); + return -1; + } + + if (!strcmp(micro_type, "BINARY")) + { + if (fread(microc_headp, sizeof(struct rt200_microc_head), 1, file) != 1) + { + PRINT(("Cannot read header from file: %s\n", micro_path)); + goto fail_exit; + } + + PRINT(("Microcode: num_seg: %x\n", microc_headp->num_seg)); + + if (microc_headp->num_seg == 0) + goto fail_exit; + + for (i = 0; i < microc_headp->num_seg; i++) + { + int ret; + + curr_seg = (struct rt200_microc_seg*) malloc(sizeof(struct rt200_microc_seg)); + if (curr_seg == NULL) + { + PRINT(("Cannot allocate memory\n")); + goto fail_exit; + } + + ret = fread(&curr_seg->num_bytes, 4, 1, file); + ret += fread(&curr_seg->download_dst, 4, 1, file); + ret += fread(&curr_seg->crc_val, 4, 1, file); + if (ret != 3) + { + PRINT(("Cannot read segment from microcode file: %s\n", micro_path)); + goto fail_exit; + } + + curr_seg->data = (unsigned char*) malloc(curr_seg->num_bytes); + if (curr_seg->data == NULL) + { + PRINT(("cannot allocate memory\n")); + goto fail_exit; + } + + PRINT(("Microcode: segment number: %x\n", i)); + PRINT(("Microcode: curr_seg->num_bytes: %x\n", curr_seg->num_bytes)); + PRINT(("Microcode: curr_seg->download_dst: %x\n", curr_seg->download_dst)); + PRINT(("Microcode: curr_seg->crc_val: %x\n", curr_seg->crc_val)); + + if (seg_list) + { + prev_seg->next = curr_seg; + curr_seg->next = NULL; + prev_seg = curr_seg; + } + else + seg_list = prev_seg = curr_seg; + + } + + curr_seg = seg_list; + while (curr_seg) + { + if ( fread(curr_seg->data, curr_seg->num_bytes, 1, file) != 1 ) + { + PRINT(("Cannot read segment data\n")); + goto fail_exit; + } + + curr_seg = curr_seg->next; + } + } + else if (!strcmp(micro_type, "ASCII")) + { + char tmp1[12], tmp2[12], tmp3[12], tmp4[12]; + unsigned int ltmp; + + if ((fgets(tmp1, 12, file) != NULL) && + (fgets(tmp2, 12, file) != NULL) && + (fgets(tmp3, 12, file) != NULL) && + fgets(tmp4, 12, file) != NULL) + { + microc_headp->device_id = strtoul(tmp1, NULL, 16); + microc_headp->vendor_id = strtoul(tmp2, NULL, 16); + microc_headp->revision_id = strtoul(tmp3, NULL, 16); + microc_headp->num_seg = strtoul(tmp4, NULL, 16); + } + else + { + PRINT(("Cannot read header from file: %s\n", micro_path)); + goto fail_exit; + } + + PRINT(("Microcode: num_seg: %x\n", microc_headp->num_seg)); + + if (microc_headp->num_seg == 0) + goto fail_exit; + + for (i = 0; i < microc_headp->num_seg; i++) + { + curr_seg = (struct rt200_microc_seg*) malloc(sizeof(struct rt200_microc_seg)); + if (curr_seg == NULL) + { + PRINT(("Cannot allocate memory\n")); + goto fail_exit; + } + + if (fgets(tmp1, 12, file) != NULL && + fgets(tmp2, 12, file) != NULL && + fgets(tmp3, 12, file) != NULL) + { + curr_seg->num_bytes = strtoul(tmp1, NULL, 16); + curr_seg->download_dst = strtoul(tmp2, NULL, 16); + curr_seg->crc_val = strtoul(tmp3, NULL, 16); + } + else + { + PRINT(("Cannot read segment from microcode file: %s\n", micro_path)); + goto fail_exit; + } + + curr_seg->data = (unsigned char*) malloc(curr_seg->num_bytes); + if (curr_seg->data == NULL) + { + PRINT(("cannot allocate memory\n")); + goto fail_exit; + } + + PRINT(("Microcode: segment number: %x\n", i)); + PRINT(("Microcode: curr_seg->num_bytes: %x\n", curr_seg->num_bytes)); + PRINT(("Microcode: curr_seg->download_dst: %x\n", curr_seg->download_dst)); + PRINT(("Microcode: curr_seg->crc_val: %x\n", curr_seg->crc_val)); + + if (seg_list) + { + curr_seg->next = NULL; + prev_seg->next = curr_seg; + prev_seg = curr_seg; + } + else + seg_list = prev_seg = curr_seg; + } + + curr_seg = seg_list; + while (curr_seg) + { + for ( i = 0; i < curr_seg->num_bytes; i+=4) + { + + if ( fgets(tmp1, 12, file) == NULL ) + { + PRINT(("Cannot read from file\n")); + goto fail_exit; + } + ltmp = strtoul(tmp1, NULL, 16); + + *(unsigned int*)(curr_seg->data + i) = ltmp; + } + + curr_seg = curr_seg->next; + } + + } + else + { + PRINT(("File type %s unknown\n", micro_type)); + } + + microc_datap->microc_seg_list = seg_list; + + fclose(file); + return 0; + +fail_exit: + curr_seg = seg_list; + while(curr_seg) + { + free(curr_seg->data); + prev_seg = curr_seg; + curr_seg = curr_seg->next; + free(prev_seg); + } + fclose(file); + + return -1; +} + + +void CTheater200::DSPCleanMicrocode(struct rt200_microc_data* microc_datap) +{ + struct rt200_microc_seg* seg_list = microc_datap->microc_seg_list; + struct rt200_microc_seg* prev_seg; + + while(seg_list) + { + free(seg_list->data); + prev_seg = seg_list; + seg_list = seg_list->next; + free(prev_seg); + } +} + + +status_t CTheater200::DspInit() +{ + uint32 data; + int i = 0; + + PRINT(("CTheater200::Dsp_Init()\n")); + + /* Map FIFOD to DSP Port I/O port */ + data = Register(VIP_HOSTINTF_PORT_CNTL); + SetRegister(VIP_HOSTINTF_PORT_CNTL, data & (~VIP_HOSTINTF_PORT_CNTL__FIFO_RW_MODE)); + + /* The default endianess is LE. It matches the ost one for x86 */ + data = Register(VIP_HOSTINTF_PORT_CNTL); + SetRegister(VIP_HOSTINTF_PORT_CNTL, data & (~VIP_HOSTINTF_PORT_CNTL__FIFOD_ENDIAN_SWAP)); + + /* Wait until Shuttle bus channel 14 is available */ + data = Register(VIP_TC_STATUS); + while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) + data = Register(VIP_TC_STATUS); + + PRINT(("Microcode: dsp_init: channel 14 available\n")); + + return B_OK; +} + +status_t CTheater200::DspLoad( struct rt200_microc_data* microc_datap ) +{ + + struct rt200_microc_seg* seg_list = microc_datap->microc_seg_list; + uint8 data8; + uint32 data, fb_scratch0, fb_scratch1; + uint32 i; + uint32 tries = 0; + uint32 result = 0; + uint32 seg_id = 0; + + PRINT(("Microcode: before everything: %x\n", data8)); + + if (ReadFifo(0x000, &data8)) + PRINT(("Microcode: FIFO status0: %x\n", data8)); + else + { + PRINT(("Microcode: error reading FIFO status0\n")); + return -1; + } + + + if (ReadFifo(0x100, &data8)) + PRINT(("Microcode: FIFO status1: %x\n", data8)); + else + { + PRINT(("Microcode: error reading FIFO status1\n")); + return -1; + } + + /* + * Download the Boot Code and CRC Checking Code (first segment) + */ + //debugger("DSPLoad"); + seg_id = 1; + while(result != DSP_OK && tries++ < 10) + { + + /* Put DSP in reset before download (0x02) */ + data = Register(VIP_TC_DOWNLOAD); + SetRegister(VIP_TC_DOWNLOAD, (data & ~VIP_TC_DOWNLOAD__TC_RESET_MODE) | (0x02 << 17)); + + /* + * Configure shuttle bus for tranfer between DSP I/O "Program Interface" + * and Program Memory at address 0 + */ + + SetRegister(VIP_TC_SOURCE, 0x90000000); + SetRegister(VIP_TC_DESTINATION, 0x00000000); + SetRegister(VIP_TC_COMMAND, 0xe0000044 | ((seg_list->num_bytes - 1) << 7)); + + /* Load first segment */ + PRINT(("Microcode: Loading first segment\n")); + + if (!WriteFifo(0x700, seg_list->num_bytes, seg_list->data)) + { + PRINT(("Microcode: write to FIFOD failed\n")); + return -1; + } + + /* Wait until Shuttle bus channel 14 is available */ + i = data = 0; + data = Register(VIP_TC_STATUS); + while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) + data = Register(VIP_TC_STATUS); + + if (i >= 10000) + { + PRINT(("Microcode: channel 14 timeout\n")); + return -1; + } + + PRINT(("Microcode: dsp_load: checkpoint 1\n")); + PRINT(("Microcode: TC_STATUS: %x\n", data)); + + /* transfer the code from program memory to data memory */ + SetRegister(VIP_TC_SOURCE, 0x00000000); + SetRegister(VIP_TC_DESTINATION, 0x10000000); + SetRegister(VIP_TC_COMMAND, 0xe0000006 | ((seg_list->num_bytes - 1) << 7)); + + /* Wait until Shuttle bus channel 14 is available */ + i = data = 0; + data = Register(VIP_TC_STATUS); + while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) + data = Register(VIP_TC_STATUS); + + if (i >= 10000) + { + PRINT(("Microcode: channel 14 timeout\n")); + return -1; + } + PRINT(("Microcode: dsp_load: checkpoint 2\n")); + PRINT(("Microcode: TC_STATUS: %x\n", data)); + + /* Take DSP out from reset (0x0) */ + data = Register(VIP_TC_DOWNLOAD); + SetRegister(VIP_TC_DOWNLOAD, data & ~VIP_TC_DOWNLOAD__TC_RESET_MODE); + + data = Register(VIP_TC_STATUS); + PRINT(("Microcode: dsp_load: checkpoint 3\n")); + PRINT(("Microcode: TC_STATUS: %x\n", data)); + + /* send dsp_download_check_CRC */ + fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 193); + fb_scratch1 = (unsigned int)seg_list->crc_val; + + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("Microcode: dsp_load: checkpoint 4\n")); + } + + //debugger("DSPLoad"); + + if (tries >= 10) + { + PRINT(("Microcode: Download of boot degment failed\n")); + return -1; + } + + PRINT(("Microcode: Download of boot code succeeded\n")); + + while((seg_list = seg_list->next) != NULL) + { + seg_id++; + result = tries = 0; + while(result != DSP_OK && tries++ < 10) + { + /* + * Configure shuttle bus for tranfer between DSP I/O "Program Interface" + * and Data Memory at address 0 + */ + + SetRegister(VIP_TC_SOURCE, 0x90000000); + SetRegister(VIP_TC_DESTINATION, 0x10000000); + SetRegister(VIP_TC_COMMAND, 0xe0000044 | ((seg_list->num_bytes - 1) << 7)); + + if (!WriteFifo(0x700, seg_list->num_bytes, seg_list->data)) + { + PRINT(("Microcode: write to FIFOD failed\n")); + return -1; + } + + i = data = 0; + data = Register(VIP_TC_STATUS); + while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) + data = Register(VIP_TC_STATUS); + + /* send dsp_download_check_CRC */ + fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 193); + fb_scratch1 = (unsigned int)seg_list->crc_val; + + result = DspSendCommand(fb_scratch1, fb_scratch0); + } + + if (i >=10) + { + PRINT(("Microcode: DSP failed to move seg: %x from data to code memory\n", seg_id)); + return -1; + } + + PRINT(("Microcode: segment: %x loaded\n", seg_id)); + + /* + * The segment is downloaded correctly to data memory. Now move it to code memory + * by using dsp_download_code_transfer command. + */ + + fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 194); + fb_scratch1 = (unsigned int)seg_list->download_dst; + + result = DspSendCommand(fb_scratch1, fb_scratch0); + + if (result != DSP_OK) + { + PRINT(("Microcode: DSP failed to move seg: %x from data to code memory\n", seg_id)); + return -1; + } + } + + PRINT(("Microcode: download complete\n")); + + /* + * The last step is sending dsp_download_check_CRC with "download complete" + */ + + fb_scratch0 = ((165 << 8) & 0xff00) | (0xff & 193); + fb_scratch1 = (unsigned int)0x11111; + + result = DspSendCommand(fb_scratch1, fb_scratch0); + + if (result == DSP_OK) + PRINT(("Microcode: DSP microcode successfully loaded\n")); + else + { + PRINT(("Microcode: DSP microcode UNsuccessfully loaded\n")); + return -1; + } + + return 0; +} + +status_t CTheater200::DspSendCommand(uint32 fb_scratch1, uint32 fb_scratch0) +{ + uint32 data; + int i; + + /* + * Clear the FB_INT0 bit in INT_CNTL + */ + data = Register(VIP_INT_CNTL); + SetRegister(VIP_INT_CNTL, data | VIP_INT_CNTL__FB_INT0_CLR); + + /* + * Write FB_SCRATCHx registers. If FB_SCRATCH1==0 then we have a DWORD command. + */ + SetRegister(VIP_FB_SCRATCH0, fb_scratch0); + if (fb_scratch1 != 0) + SetRegister(VIP_FB_SCRATCH1, fb_scratch1); + + /* + * Attention DSP. We are talking to you. + */ + data = Register(VIP_FB_INT); + SetRegister(VIP_FB_INT, data | VIP_FB_INT__INT_7); + + /* + * Wait (by polling) for the DSP to process the command. + */ + i = 0; + data = Register(VIP_INT_CNTL); + while((!(data & VIP_INT_CNTL__FB_INT0)) && (i++ < 10)) + { + snooze(1000); + data = Register(VIP_INT_CNTL); + } + + /* + * The return code is in FB_SCRATCH0 + */ + fb_scratch0 = Register(VIP_FB_SCRATCH0); + + /* + * If we are here it means we got an answer. Clear the FB_INT0 bit. + */ + data = Register(VIP_INT_CNTL); + SetRegister(VIP_INT_CNTL, data | VIP_INT_CNTL__FB_INT0_CLR); + + return fb_scratch0; +} + +void CTheater200::InitTheatre() +{ + uint32 data; + uint32 M, N, P; + + /* this will give 108Mhz at 27Mhz reference */ + M = 28; + N = 224; + P = 1; + + ShutdownTheatre(); + snooze(100000); + fMode = MODE_INITIALIZATION_IN_PROGRESS; + + data = M | (N << 11) | (P <<24); + SetRegister(VIP_DSP_PLL_CNTL, data); + + Register(VIP_PLL_CNTL0, data); + data |= 0x2000; + SetRegister(VIP_PLL_CNTL0, data); + + /* RT_regw(VIP_I2C_SLVCNTL, 0x249); */ + Register(VIP_PLL_CNTL1, data); + data |= 0x00030003; + SetRegister(VIP_PLL_CNTL1, data); + + Register(VIP_PLL_CNTL0, data); + data &= 0xfffffffc; + SetRegister(VIP_PLL_CNTL0, data); + snooze(15000); + + Register(VIP_CLOCK_SEL_CNTL, data); + data |= 0x1b; + SetRegister(VIP_CLOCK_SEL_CNTL, data); + + Register(VIP_MASTER_CNTL, data); + data &= 0xffffff07; + SetRegister(VIP_MASTER_CNTL, data); + data &= 0xffffff03; + SetRegister(VIP_MASTER_CNTL, data); + snooze(1000); + + if (microcode_path == NULL) + { + microcode_path = const_cast(DEFAULT_MICROC_PATH); + PRINT(("Microcode: Use default microcode path: %s\n", DEFAULT_MICROC_PATH)); + } + else + { + PRINT(("Microcode: Use microcode path: %s\n", microcode_path)); + } + + if (microcode_type == NULL) + { + microcode_type = const_cast(DEFAULT_MICROC_TYPE); + PRINT(("Microcode: Use default microcode type: %s\n", DEFAULT_MICROC_TYPE)); + } + else + { + PRINT(("Microcode: Use microcode type: %s\n", microcode_type)); + } + + if (DSPDownloadMicrocode() < 0) + { + ShutdownTheatre(); + return; + } + + //DspSetLowPowerState(1); + //DspSetVideoStreamFormat(1); + + fMode = MODE_INITIALIZED_FOR_TV_IN; +} + +int CTheater200::DSPDownloadMicrocode() +{ + struct rt200_microc_data microc_data; + microc_data.microc_seg_list = NULL; + + if (DSPLoadMicrocode(microcode_path, microcode_type, µc_data) < 0) + { + PRINT(("Microcode: cannot load microcode\n")); + goto err_exit; + } + else + { + PRINT(("Microcode: device_id: %x\n", microc_data.microc_head.device_id)); + PRINT(("Microcode: vendor_id: %x\n", microc_data.microc_head.vendor_id)); + PRINT(("Microcode: rev_id: %x\n", microc_data.microc_head.revision_id)); + PRINT(("Microcode: num_seg: %x\n", microc_data.microc_head.num_seg)); + } + + if (DspInit() < 0) + { + PRINT(("Microcode: dsp_init failed\n")); + goto err_exit; + } + else + { + PRINT(("Microcode: dsp_init OK\n")); + } + + if (DspLoad(µc_data) < 0) + { + PRINT(("Microcode: dsp_download failed\n")); + goto err_exit; + } + else + { + PRINT(("Microcode: dsp_download OK\n")); + } + + DSPCleanMicrocode(µc_data); + return 0; + +err_exit: + + DSPCleanMicrocode(µc_data); + return -1; + +} + +void CTheater200::ShutdownTheatre() +{ + fMode = MODE_UNINITIALIZED; +} + +void CTheater200::ResetTheatreRegsForNoTVout() +{ + SetRegister(VIP_CLKOUT_CNTL, 0x0); + SetRegister(VIP_HCOUNT, 0x0); + SetRegister(VIP_VCOUNT, 0x0); + SetRegister(VIP_DFCOUNT, 0x0); +#if 0 + SetRegister(VIP_CLOCK_SEL_CNTL, 0x2b7); /* versus 0x237 <-> 0x2b7 */ + SetRegister(VIP_VIN_PLL_CNTL, 0x60a6039); +#endif + SetRegister(VIP_FRAME_LOCK_CNTL, 0x0); +} + +void CTheater200::ResetTheatreRegsForTVout() +{ + SetRegister(VIP_CLKOUT_CNTL, 0x29); +#if 1 + SetRegister(VIP_HCOUNT, 0x1d1); + SetRegister(VIP_VCOUNT, 0x1e3); +#else + SetRegister(VIP_HCOUNT, 0x322); + SetRegister(VIP_VCOUNT, 0x151); +#endif + SetRegister(VIP_DFCOUNT, 0x01); + SetRegister(VIP_CLOCK_SEL_CNTL, 0x2b7); /* versus 0x237 <-> 0x2b7 */ + SetRegister(VIP_VIN_PLL_CNTL, 0x60a6039); + SetRegister(VIP_FRAME_LOCK_CNTL, 0x0f); +} + +int32 CTheater200::DspSetVideostreamformat(int32 format) +{ + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = ((format << 8) & 0xff00) | (65 & 0xff); + result = DspSendCommand(0, fb_scratch0); + + PRINT(("dsp_set_videostreamformat: %x\n", result)); + + return result; +} + +int32 CTheater200::DspGetSignalLockStatus() +{ + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = 0 | (77 & 0xff); + + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_get_signallockstatus: %x, h_pll: %x, v_pll: %x\n", \ + result, (result >> 8) & 0xff, (result >> 16) & 0xff)); + + return result; +} + +// disable/enable capturing +void CTheater200::SetEnable(bool enable, bool vbi) +{ + + PRINT(("CTheater200::SetEnable(%d, %d)\n", enable, vbi)); + + if (enable) { + WaitVSYNC(); + + SetADC(fStandard, fSource); + + SetScaler(fStandard, fHActive, fVActive, fDeinterlace); + + // Enable ADC block + SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP); + + WaitVSYNC(); + + // restore luminance and chroma settings + SetLuminanceLevels(fStandard, fBrightness, fContrast); + SetChromaLevels(fStandard, fSaturation, fHue); + } +} + +void CTheater200::SetStandard(theater_standard standard, theater_source source) +{ + PRINT(("CTheater200::SetStandard(%s, %s)\n", + "NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0" + "PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0" + "SECAM\0\0\0\0\0"+10*standard, + "TUNER\0COMP\0\0SVIDEO"+6*source)); + + fStandard = standard; + fSource = source; +} + +void CTheater200::SetSize(int hactive, int vactive) +{ + PRINT(("CTheater200::SetSize(%d, %d)\n", hactive, vactive)); + + fHActive = hactive; + fVActive = vactive; +} + +void CTheater200::SetDeinterlace(bool deinterlace) +{ + PRINT(("CTheater200::SetDeinterlace(%d)\n", deinterlace)); + + fDeinterlace = deinterlace; +} + +/* one assumes as sharpness is not used it's not supported */ +void CTheater200::SetSharpness(int sharpness) +{ + int32 fb_scratch0 = 0; + int32 fb_scratch1 = 1; + int32 result; + + PRINT(("CTheater200::SetSharpness(%d)\n", sharpness)); + + fb_scratch0 = 0 | (73 & 0xff); + result = DspSendCommand(fb_scratch1, fb_scratch0); +} + +void CTheater200::SetBrightness(int brightness) +{ + PRINT(("CTheater200::SetBrightness(%d)\n", brightness)); + + fBrightness = brightness; + SetLuminanceLevels(fStandard, fBrightness, fContrast); +} + +void CTheater200::SetContrast(int contrast) +{ + PRINT(("CTheater200::SetContrast(%d)\n", contrast)); + + fContrast = contrast; + SetLuminanceLevels(fStandard, fBrightness, fContrast); +} + +void CTheater200::SetSaturation(int saturation) +{ + PRINT(("CTheater200::SetSaturation(%d)\n", saturation)); + + fSaturation = saturation; + SetChromaLevels(fStandard, fSaturation, fHue); +} + +void CTheater200::SetHue(int hue) +{ + PRINT(("CTheater200::SetHue(%d)\n", hue)); + + fHue = hue; + SetChromaLevels(fStandard, fSaturation, fHue); +} + +// setup analog-digital converter +void CTheater200::SetADC(theater_standard standard, theater_source source) +{ + uint32 fb_scratch0 = 0; + uint32 result; + uint32 data = 0; + + PRINT(("CTheater200::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); + + // set HW_DEBUG before setting the standard + SetRegister(VIP_HW_DEBUG, 0x0000f000); + + // select the video standard + switch (standard) { + case C_THEATER_NTSC: + case C_THEATER_NTSC_JAPAN: + case C_THEATER_NTSC_443: + case C_THEATER_PAL_M: + // SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC); + // break; + case C_THEATER_PAL_BDGHI: + case C_THEATER_PAL_N: + case C_THEATER_PAL_60: + case C_THEATER_PAL_NC: + // SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL); + // break; + case C_THEATER_SECAM: + // SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM); + fb_scratch0 = ((standard << 8) & 0xff00) | (52 & 0xff); + result = DspSendCommand(0, fb_scratch0); + break; + default: + PRINT(("CTheater200::SetADC() - Bad standard\n")); + return; + } + + Register(VIP_GPIO_CNTL, data); + PRINT(("VIP_GPIO_CNTL: %x\n", data)); + + Register(VIP_GPIO_INOUT, data); + PRINT(("VIP_GPIO_INOUT: %x\n", data)); + + // select input connector and Y/C mode + switch (source) { + case C_THEATER_TUNER: + // set video input connector + fb_scratch0 = ((fTunerPort << 8) & 0xff00) | (55 & 0xff); + DspSendCommand(0, fb_scratch0); + + /* this is to set the analog mux used for sond */ + Register(VIP_GPIO_CNTL, data); + data &= ~0x10; + SetRegister(VIP_GPIO_CNTL, data); + + Register(VIP_GPIO_INOUT, data); + data &= ~0x10; + SetRegister(VIP_GPIO_INOUT, data); + break; + case C_THEATER_COMPOSITE: + // set video input connector + fb_scratch0 = ((fCompositePort << 8) & 0xff00) | (55 & 0xff); + DspSendCommand(0, fb_scratch0); + + /* this is to set the analog mux used for sond */ + Register(VIP_GPIO_CNTL, data); + data |= 0x10; + SetRegister(VIP_GPIO_CNTL, data); + + Register(VIP_GPIO_INOUT, data); + data |= 0x10; + SetRegister(VIP_GPIO_INOUT, data); + break; + case C_THEATER_SVIDEO: + // set video input connector + fb_scratch0 = ((fSVideoPort << 8) & 0xff00) | (55 & 0xff); + DspSendCommand(0, fb_scratch0); + + /* this is to set the analog mux used for sond */ + Register(VIP_GPIO_CNTL, data); + data |= 0x10; + SetRegister(VIP_GPIO_CNTL, data); + + Register(VIP_GPIO_INOUT, data); + data |= 0x10; + SetRegister(VIP_GPIO_INOUT, data); + break; + default: + PRINT(("CTheater200::SetADC() - Bad source\n")); + return; + } + + + Register(VIP_GPIO_CNTL, data); + PRINT(("VIP_GPIO_CNTL: %x\n", data)); + + Register(VIP_GPIO_INOUT, data); + PRINT(("VIP_GPIO_INOUT: %x\n", data)); + + + DspConfigureI2SPort(0, 0, 0); + DspConfigureSpdifPort(0); + + /*dsp_audio_detection(t, 0);*/ + DspAudioMute(1, 1); + DspSetAudioVolume(128, 128, 0); + +} + +// wait until horizontal scaler is locked +void CTheater200::WaitHSYNC() +{ + for (int timeout = 0; timeout < 1000; timeout++) { + if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0) + return; + snooze(20); + } + PRINT(("CTheater200::WaitHSYNC() - wait for HSync locking time out!\n")); +} + + + +// wait until a visible line is viewed +void CTheater200::WaitVSYNC() +{ + for (int timeout = 0; timeout < 1000; timeout++) { + int lineCount = CurrentLine(); + if (lineCount > 1 && lineCount < 20) + return; + snooze(20); + } + PRINT(("CTheater200::WaitVSYNC() - wait for VBI timed out!\n")); +} + +// setup brightness and contrast +void CTheater200::SetLuminanceLevels(theater_standard standard, int brightness, int contrast) +{ + + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + /* set luminance processor constrast */ + fb_scratch0 = ((contrast << 8) & 0xff00) | (71 & 0xff); + result = DspSendCommand(fb_scratch1, fb_scratch0); + PRINT(("dsp_set_contrast: %x\n", result)); + + /* set luminance processor brightness */ + fb_scratch0 = ((brightness << 8) & 0xff00) | (67 & 0xff); + DspSendCommand(fb_scratch1, fb_scratch0); + PRINT(("dsp_set_brightness: %x\n", result)); + +} + +// set colour saturation and hue. +// hue makes sense for NTSC only and seems to act as saturation for PAL +void CTheater200::SetChromaLevels(theater_standard standard, int saturation, int hue) +{ + + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + + // Set Hue + fb_scratch0 = ((hue << 8) & 0xff00) | (75 & 0xff); + DspSendCommand(fb_scratch1, fb_scratch0); + + // Set Saturation + fb_scratch0 = ((saturation << 8) & 0xff00) | (69 & 0xff); + DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_set_saturation: %x\n", saturation)); + PRINT(("dsp_set_tint: %x\n", hue)); +} + + +// these values are used by scaler as well +static const uint16 h_active_start[] = { + 0x06b, 0x06B, 0x07E, 0x067, 0x09A, 0x07D, 0x09A, 0x084, 0x095 }; +static const uint16 h_active_end[] = { + 0x363, 0x363, 0x42A, 0x363, 0x439, 0x439, 0x439, 0x363, 0x439 }; +static const uint16 v_active_start[] = { + 0x025, 0x025, 0x025, 0x025, 0x02E, 0x02E, 0x02E, 0x025, 0x02E }; +// PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d +// leads to trouble, and the last 2 lines seem to be used for VBI data +// (read: garbage) anyway +static const uint16 v_active_end[] = { + 0x204, 0x204, 0x204, 0x204, 0x269, 0x269, 0x269, 0x204, 0x269 }; +static const uint16 h_vbi_wind_start[] = { + 0x064, 0x064, 0x064, 0x064, 0x084, 0x084, 0x084, 0x064, 0x084 }; +static const uint16 h_vbi_wind_end[] = { + 0x366, 0x366, 0x366, 0x366, 0x41F, 0x41F, 0x41F, 0x366, 0x41F }; +static const uint16 v_vbi_wind_start[] = { + 0x00b, 0x00b, 0x00b, 0x00b, 0x008, 0x008, 0x008, 0x00b, 0x008 }; +static const uint16 v_vbi_wind_end[] = { + 0x024, 0x024, 0x024, 0x024, 0x02d, 0x02d, 0x02d, 0x024, 0x02d }; + + +void CTheater200::getActiveRange( theater_standard standard, CRadeonRect &rect ) +{ + + rect.SetTo( + h_active_start[standard], v_active_start[standard], + h_active_end[standard], v_active_end[standard] ); + +} + +void CTheater200::getVBIRange( theater_standard standard, CRadeonRect &rect ) +{ + + rect.SetTo( + h_vbi_wind_start[standard], v_vbi_wind_start[standard], + h_vbi_wind_end[standard], v_vbi_wind_end[standard] ); + +} + +// setup capture scaler. +void CTheater200::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace) +{ + + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int oddOffset, evenOffset; + uint16 h_active_width, v_active_height; + +// ASSERT(vactive <= 511); + + // TK: Gatos uses different values here + h_active_width = h_active_end[standard] - h_active_start[standard] + 1; + v_active_height = v_active_end[standard] - v_active_start[standard] + 1; + + // for PAL, we have 572 lines only, but need 576 lines; + // my attempts to find those missing lines all failed, so if the application requests + // 576 lines, we had to upscale the video which is not supported by hardware; + // solution: restrict to 572 lines - the scaler will fill out the missing lines with black + if( vactive > v_active_height ) + vactive = v_active_height; + + if (deinterlace) { + // progressive scan + evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height); + } + else { + // interlaced + evenOffset = (int) ((512 * vactive) / v_active_height); + oddOffset = 2048 - evenOffset; + } + + // Set Horizontal Size + fb_scratch0 = ((h_active_width << 8) & 0x00ffff00) | (195 & 0xff); + fb_scratch1 = ((h_active_end[standard] << 16) & 0xffff0000) | (h_active_start[standard] & 0xffff); + DspSendCommand(fb_scratch1, fb_scratch0); + + // Set Vertical Size + fb_scratch0 = ((v_active_height << 8) & 0x00ffff00) | (196 & 0xff); + fb_scratch1 = ((v_active_end[standard] << 16) & 0xffff0000) | (v_active_start[standard] + 1 & 0xffff); + DspSendCommand(fb_scratch1, fb_scratch0); +} + +int32 CTheater200::DspAudioMute(int8 left, int8 right) +{ + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = ((right << 16) & 0xff0000) | ((left << 8) & 0xff00) | (21 & 0xff); + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_audio_mute: %x\n", result)); + + return result; +} + +int32 CTheater200::DspSetAudioVolume(int8 left, int8 right, int8 auto_mute) +{ + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = ((auto_mute << 24) & 0xff000000) + | ((right << 16) & 0xff0000) + | ((left << 8) & 0xff00) | (22 & 0xff); + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_set_audio_volume: %x\n", result)); + + return result; +} + +int32 CTheater200::DspConfigureI2SPort(int8 tx_mode, int8 rx_mode, int8 clk_mode) +{ + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = ((clk_mode << 24) & 0xff000000) | ((rx_mode << 16) & 0xff0000) + | ((tx_mode << 8) & 0xff00) | (40 & 0xff); + + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_configure_i2s_port: %x\n", result)); + + return result; +} + +int32 CTheater200::DspConfigureSpdifPort(int8 state) +{ + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = ((state << 8) & 0xff00) | (41 & 0xff); + + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_configure_spdif_port: %x\n", result)); + + return result; +} + +int CTheater200::ReadFifo( uint32 address, uint8 *buffer) +{ + return fPort.ReadFifo(fDevice, address, 1, buffer); +} + +int CTheater200::WriteFifo( uint32 address, uint32 count, uint8 *buffer) +{ + return fPort.WriteFifo(fDevice, address, count, buffer); +} + +int CTheater200::CurrentLine() +{ +// return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT; + int32 fb_scratch1 = 0; + int32 fb_scratch0 = 0; + int32 result; + + fb_scratch0 = 0 | (78 & 0xff); + result = DspSendCommand(fb_scratch1, fb_scratch0); + + PRINT(("dsp_get_signallinenumber: %x, linenum: %x\n", \ + result, (result >> 8) & 0xffff)); + + return result; + +} + +void CTheater200::PrintToStream() +{ + PRINT(("<<< Rage Theater Registers >>>\n")); + /*for (int index = 0x0400; index <= 0x06ff; index += 4) { + int value = Register(index); + PRINT(("REG_0x%04x = 0x%08x\n", index, value)); + } */ +} diff --git a/src/add-ons/media/media-add-ons/radeon/Theater200.h b/src/add-ons/media/media-add-ons/radeon/Theater200.h new file mode 100644 index 0000000000..3dace07769 --- /dev/null +++ b/src/add-ons/media/media-add-ons/radeon/Theater200.h @@ -0,0 +1,147 @@ +/****************************************************************************** +/ +/ File: Theater200.h +/ +/ Description: ATI Rage Theater Video Decoder interface. +/ +/ Based on code from X.org +/ +*******************************************************************************/ + +#ifndef __THEATER200_H__ +#define __THEATER200_H__ + +#include "Theater.h" +#include "Radeon.h" +#include "VIPPort.h" + +enum theater200_state +{ + MODE_UNINITIALIZED, + MODE_INITIALIZATION_IN_PROGRESS, + MODE_INITIALIZED_FOR_TV_IN +}; + +class CTheater200 : public CTheater { +public: + CTheater200(CRadeon & radeon, int device); + + ~CTheater200(); + + status_t InitCheck() const; + + void Reset(); + + void SetEnable(bool enable, bool vbi); + + void SetStandard(theater_standard standard, theater_source source); + + void SetSize(int hactive, int vactive); + + void SetDeinterlace(bool deinterlace); + + void SetSharpness(int sharpness); + + void SetBrightness(int brightness); + + void SetContrast(int contrast); + + void SetSaturation(int saturation); + + void SetHue(int hue); + + int CurrentLine(); + + // help no idea + void getActiveRange( theater_standard standard, CRadeonRect &rect ); + + // help no idea. + void getVBIRange( theater_standard standard, CRadeonRect &rect ); + + void PrintToStream(); + +private: + + status_t DspInit(); + + status_t DspLoad( struct rt200_microc_data* microc_datap ); + + status_t DspGetMicrocode( char* micro_path, + char* micro_type, + struct rt200_microc_data* microc_datap ); + + status_t DSPLoadMicrocode( char* micro_path, + char* micro_type, + struct rt200_microc_data* microc_datap ); + + void DSPCleanMicrocode(struct rt200_microc_data* microc_datap); + + status_t DspSendCommand( uint32 fb_scratch1, uint32 fb_scratch0 ); + + void InitTheatre(); + + int DSPDownloadMicrocode(); + + void ShutdownTheatre(); + + // in accelerant? + void ResetTheatreRegsForNoTVout(); + void ResetTheatreRegsForTVout(); + + int32 DspSetVideostreamformat(int32 format); + int32 DspGetSignalLockStatus(); + int32 DspAudioMute(int8 left, int8 right); + int32 DspSetAudioVolume(int8 left, int8 right, int8 auto_mute); + int32 DspConfigureI2SPort(int8 tx_mode, int8 rx_mode, int8 clk_mode); + int32 DspConfigureSpdifPort(int8 state); + + // does nothing now + void SetClock(theater_standard standard, radeon_video_clock clock){;}; + + // source not correct values for PAL NTSC etc... + void SetADC(theater_standard standard, theater_source source); + + // does nothing now + void SetHSYNC(theater_standard standard){;}; + + void WaitHSYNC(); + + // does nothing now + void SetVSYNC(theater_standard standard){;}; + + void WaitVSYNC(); + + // does nothing now + void SetSyncGenerator(theater_standard standard){;}; + + // does nothing now + void SetCombFilter(theater_standard standard, theater_source source){;}; + + // does nothing now + void SetLuminanceProcessor(theater_standard standard){;}; + + void SetLuminanceLevels(theater_standard standard, int brightness, int contrast); + + // does nothing now + void SetChromaProcessor(theater_standard standard); + + void SetChromaLevels(theater_standard standard, int saturation, int hue); + + // does nothing now + void SetClipWindow(theater_standard standard, bool vbi); + + // um, help + void SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace); + +public: + int ReadFifo(uint32 address, uint8 *buffer); + + int WriteFifo(uint32 address, uint32 count, uint8 *buffer); + +private: + theater200_state fMode; + char* microcode_path; + char* microcode_type; +}; + +#endif diff --git a/src/add-ons/media/media-add-ons/radeon/TheatreReg.h b/src/add-ons/media/media-add-ons/radeon/TheatreReg.h index 7736bf9c8b..8136a3cf70 100644 --- a/src/add-ons/media/media-add-ons/radeon/TheatreReg.h +++ b/src/add-ons/media/media-add-ons/radeon/TheatreReg.h @@ -1229,7 +1229,132 @@ enum theater_register { VIP_CRT_DTO_INCREMENTS = 0x0394, VIP_VSYNC_DIFF_CNTL = 0x03a0, VIP_VSYNC_DIFF_LIMITS = 0x03a4, - VIP_VSYNC_DIFF_RD_DATA = 0x03a8 + VIP_VSYNC_DIFF_RD_DATA = 0x03a8, + + DSP_OK = 0x21, + DSP_INVALID_PARAMETER = 0x22, + DSP_MISSING_PARAMETER = 0x23, + DSP_UNKNOWN_COMMAND = 0x24, + DSP_UNSUCCESS = 0x25, + DSP_BUSY = 0x26, + DSP_RESET_REQUIRED = 0x27, + DSP_UNKNOWN_RESULT = 0x28, + DSP_CRC_ERROR = 0x29, + DSP_AUDIO_GAIN_ADJ_FAIL = 0x2a, + DSP_AUDIO_GAIN_CHK_ERROR = 0x2b, + DSP_WARNING = 0x2c, + DSP_POWERDOWN_MODE = 0x2d, + + RT200_NTSC_M = 0x01, + RT200_NTSC_433 = 0x03, + RT200_NTSC_J = 0x04, + RT200_PAL_B = 0x05, + RT200_PAL_D = 0x06, + RT200_PAL_G = 0x07, + RT200_PAL_H = 0x08, + RT200_PAL_I = 0x09, + RT200_PAL_N = 0x0a, + RT200_PAL_Ncomb = 0x0b, + RT200_PAL_M = 0x0c, + RT200_PAL_60 = 0x0d, + RT200_SECAM = 0x0e, + RT200_SECAM_B = 0x0f, + RT200_SECAM_D = 0x10, + RT200_SECAM_G = 0x11, + RT200_SECAM_H = 0x12, + RT200_SECAM_K = 0x13, + RT200_SECAM_K1 = 0x14, + RT200_SECAM_L = 0x15, + RT200_SECAM_L1 = 0x16, + RT200_480i = 0x17, + RT200_480p = 0x18, + RT200_576i = 0x19, + RT200_720p = 0x1a, + RT200_1080i = 0x1b + +}; + + +/* RT200 stuff there's no way I'm converting these to enums...*/ +/* RT200 */ +#define VIP_INT_CNTL__FB_INT0 0x02000000 +#define VIP_INT_CNTL__FB_INT0_CLR 0x02000000 +#define VIP_GPIO_INOUT 0x0030 +#define VIP_GPIO_CNTL 0x0034 +#define VIP_CLKOUT_GPIO_CNTL 0x0038 +#define VIP_RIPINTF_PORT_CNTL 0x003c + +/* RT200 */ +#define VIP_GPIO_INOUT 0x0030 +#define VIP_GPIO_CNTL 0x0034 +#define VIP_HOSTINTF_PORT_CNTL 0x003c +#define VIP_HOSTINTF_PORT_CNTL__HAD_HCTL_SDA_SN 0x00000008 +#define VIP_HOSTINTF_PORT_CNTL__HAD_HCTL_SDA_SP 0x00000080 +#define VIP_HOSTINTF_PORT_CNTL__HAD_HCTL_SDA_SR 0x00000100 +#define VIP_HOSTINTF_PORT_CNTL__SUB_SYS_ID_EN 0x00010000 +#define VIP_HOSTINTF_PORT_CNTL__FIFO_RW_MODE 0x00300000 +#define VIP_HOSTINTF_PORT_CNTL__FIFOA_ENDIAN_SWAP 0x00c00000 +#define VIP_HOSTINTF_PORT_CNTL__FIFOB_ENDIAN_SWAP 0x03000000 +#define VIP_HOSTINTF_PORT_CNTL__FIFOC_ENDIAN_SWAP 0x0c000000 +#define VIP_HOSTINTF_PORT_CNTL__FIFOD_ENDIAN_SWAP 0x30000000 +#define VIP_HOSTINTF_PORT_CNTL__FIFOE_ENDIAN_SWAP 0xc0000000 + +/* RT200 */ +#define VIP_DSP_PLL_CNTL 0x0bc + +/* RT200 */ +#define VIP_TC_SOURCE 0x300 +#define VIP_TC_DESTINATION 0x304 +#define VIP_TC_COMMAND 0x308 + +/* RT200 */ +#define VIP_TC_STATUS 0x030c +#define VIP_TC_STATUS__TC_CHAN_BUSY 0x00007fff +#define VIP_TC_STATUS__TC_WRITE_PENDING 0x00008000 +#define VIP_TC_STATUS__TC_FIFO_4_EMPTY 0x00040000 +#define VIP_TC_STATUS__TC_FIFO_6_EMPTY 0x00080000 +#define VIP_TC_STATUS__TC_FIFO_8_EMPTY 0x00100000 +#define VIP_TC_STATUS__TC_FIFO_10_EMPTY 0x00200000 +#define VIP_TC_STATUS__TC_FIFO_4_FULL 0x04000000 +#define VIP_TC_STATUS__TC_FIFO_6_FULL 0x08080000 +#define VIP_TC_STATUS__TC_FIFO_8_FULL 0x10080000 +#define VIP_TC_STATUS__TC_FIFO_10_FULL 0x20080000 +#define VIP_TC_STATUS__DSP_ILLEGAL_OP 0x80080000 + +/* RT200 */ +#define VIP_TC_DOWNLOAD 0x0310 +#define VIP_TC_DOWNLOAD__TC_DONE_MASK 0x00003fff +#define VIP_TC_DOWNLOAD__TC_RESET_MODE 0x00060000 + +/* RT200 */ +#define VIP_FB_INT 0x0314 +#define VIP_FB_INT__INT_7 0x00000080 +#define VIP_FB_SCRATCH0 0x0318 +#define VIP_FB_SCRATCH1 0x031c + +struct rt200_microc_head +{ + unsigned int device_id; + unsigned int vendor_id; + unsigned int revision_id; + unsigned int num_seg; +}; + +struct rt200_microc_seg +{ + unsigned int num_bytes; + unsigned int download_dst; + unsigned int crc_val; + + unsigned char* data; + struct rt200_microc_seg* next; +}; + + +struct rt200_microc_data +{ + struct rt200_microc_head microc_head; + struct rt200_microc_seg* microc_seg_list; }; #endif diff --git a/src/add-ons/media/media-add-ons/radeon/VIPPort.h b/src/add-ons/media/media-add-ons/radeon/VIPPort.h index 7f9ee8b3ea..d93559e000 100644 --- a/src/add-ons/media/media-add-ons/radeon/VIPPort.h +++ b/src/add-ons/media/media-add-ons/radeon/VIPPort.h @@ -58,6 +58,14 @@ public: fRadeon.SetVIPRegister( device, address, value ); } + int ReadFifo(int device, uint32 address, uint32 count, uint8 *buffer) { + return fRadeon.VIPReadFifo( device, address, count, buffer ); + } + + int WriteFifo(int device, uint32 address, uint32 count, uint8 *buffer) { + return fRadeon.VIPWriteFifo( device, address, count, buffer ); + } + int FindVIPDevice( uint32 device_id ) { return fRadeon.FindVIPDevice( device_id ); } diff --git a/src/add-ons/media/media-add-ons/radeon/VideoIn.cpp b/src/add-ons/media/media-add-ons/radeon/VideoIn.cpp index 46fcefbb05..c2393b424b 100644 --- a/src/add-ons/media/media-add-ons/radeon/VideoIn.cpp +++ b/src/add-ons/media/media-add-ons/radeon/VideoIn.cpp @@ -64,13 +64,14 @@ static const struct { { { 910, 525 }, { 112, 37, 755, 480 }, { 73, 13, 798, 22 } } // NTSC-Raw }; - +class CTheater100; +class CTheater200; CVideoIn::CVideoIn( const char *dev_name ) : fRadeon( dev_name ), fCapture(fRadeon), fI2CPort(fRadeon), - fTheater(fRadeon), + fTheater(NULL), fTuner(fI2CPort), fSound(fI2CPort), fBuffer0(0), @@ -84,7 +85,9 @@ CVideoIn::CVideoIn( const char *dev_name ) fBufferPeriod(0), started( false ) { + Trace("CVideoIn::CVideoIn()"); + } CVideoIn::~CVideoIn() @@ -94,12 +97,12 @@ CVideoIn::~CVideoIn() FreeBuffers(); } -status_t CVideoIn::InitCheck() const +status_t CVideoIn::InitCheck() { status_t res; + int device; Trace("CVideoIn::InitCheck()"); - if( (res = fRadeon.InitCheck()) != B_OK ) return res; @@ -109,12 +112,35 @@ status_t CVideoIn::InitCheck() const if( (res = fI2CPort.InitCheck()) != B_OK ) return res; - return fTheater.InitCheck(); + //debugger("init"); + // detect type of theatre and initialise specific theater class + if ((device = fRadeon.FindVIPDevice( C_THEATER100_VIP_DEVICE_ID )) != -1) + { + Trace("CVideoIn::Found Rage Theater 100"); + fTheater = new CTheater100(fRadeon, device); + } + else if ((device = fRadeon.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID )) != -1) + { + Trace("CVideoIn::Found Rage Theater 200"); + fTheater = new CTheater200(fRadeon, device); + } + + if (fTheater) + { + res = fTheater->InitCheck(); + } + else + { + res = B_ERROR; + } + + return res; } int CVideoIn::Capabilities() const { - return (fTuner.InitCheck() == B_OK ? C_VIDEO_IN_HAS_TUNER + C_VIDEO_IN_HAS_COMPOSITE + C_VIDEO_IN_HAS_SVIDEO : 0) + + return fTheater->Capabilities() + + (fTuner.InitCheck() == B_OK ? C_VIDEO_IN_HAS_TUNER : 0) + (fSound.InitCheck() == B_OK ? C_VIDEO_IN_HAS_SOUND : 0); } @@ -166,13 +192,13 @@ void CVideoIn::Start(video_in_source source, video_in_standard standard, if( mode == C_VIDEO_IN_BOB ) fBufferPeriod >>= 1; - fTheater.SetStandard(kStandard[standard], kSource[source]); - fTheater.SetSize(width, (mode != C_VIDEO_IN_WEAVE ? 2 * height : height)); + fTheater->SetStandard(kStandard[standard], kSource[source]); + fTheater->SetSize(width, (mode != C_VIDEO_IN_WEAVE ? 2 * height : height)); fCapture.SetBuffer(C_RADEON_CAPTURE_CCIR656, kMode[mode], fBuffer0, fBuffer1, fBufferLength, fBufferBytesPerRow >> 1); fCapture.SetClip(0, kTiming[standard].vbi.height, width - 1, kTiming[standard].vbi.height + (mode != C_VIDEO_IN_WEAVE ? height : height >> 1) - 1); - fTheater.SetEnable(true, false); + fTheater->SetEnable(true, false); if( fSound.InitCheck() == B_OK ) fSound.SetEnable(true); fCapture.SetInterrupts(true); @@ -190,7 +216,7 @@ void CVideoIn::Stop() fCapture.SetInterrupts(false); if( fSound.InitCheck() == B_OK ) fSound.SetEnable(false); - fTheater.SetEnable(false, false); + fTheater->SetEnable(false, false); FreeBuffers(); } @@ -217,35 +243,35 @@ void CVideoIn::SetBrightness(int brightness) { Trace("CVideoIn::SetBrightness()"); - fTheater.SetBrightness(brightness); + fTheater->SetBrightness(brightness); } void CVideoIn::SetContrast(int contrast) { Trace("CVideoIn::SetContrast()"); - fTheater.SetContrast(contrast); + fTheater->SetContrast(contrast); } void CVideoIn::SetSaturation(int saturation) { Trace("CVideoIn::SetSaturation()"); - fTheater.SetSaturation(saturation); + fTheater->SetSaturation(saturation); } void CVideoIn::SetHue(int hue) { Trace("CVideoIn::SetHue()"); - fTheater.SetHue(hue); + fTheater->SetHue(hue); } void CVideoIn::SetSharpness(int sharpness) { Trace("CVideoIn::SetSharpness()"); - fTheater.SetSharpness(sharpness); + fTheater->SetSharpness(sharpness); } void CVideoIn::SetFrequency(float frequency, float picture) @@ -360,12 +386,10 @@ int CVideoIn::Capture(color_space colorSpace, void * bits, int bitsLength, // always copy into main memory first, even if it must be converted by CPU - // reading from graphics mem is incredibly slow if (colorSpace == B_YCbCr422 && bitsLength <= fBufferLength && bytesPerRow == fBufferBytesPerRow) { - PRINT(("%d, %p\n", captured_buffer, bits)); - fRadeon.DMACopy( captured_buffer, bits, bitsLength, true, false ); } - else if (colorSpace == B_RGB32 && bitsLength <= 2 * fBufferLength && bytesPerRow == 2 * fBufferBytesPerRow) { - + + else if (colorSpace == B_RGB32 && bitsLength <= 2 * fBufferLength && bytesPerRow == 2 * fBufferBytesPerRow) { fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false ); #define RGB32 @@ -373,6 +397,7 @@ int CVideoIn::Capture(color_space colorSpace, void * bits, int bitsLength, #undef RGB32 } + else if (colorSpace == B_RGB16 && bitsLength <= fBufferLength && bytesPerRow == fBufferBytesPerRow) { fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false ); @@ -381,6 +406,7 @@ int CVideoIn::Capture(color_space colorSpace, void * bits, int bitsLength, #undef RGB16 } + else if (colorSpace == B_RGB15 && bitsLength <= fBufferLength && bytesPerRow == fBufferBytesPerRow) { fRadeon.DMACopy( captured_buffer, convert_buffer, fBufferLength, true, false ); diff --git a/src/add-ons/media/media-add-ons/radeon/VideoIn.h b/src/add-ons/media/media-add-ons/radeon/VideoIn.h index 72085f11da..5374934faf 100644 --- a/src/add-ons/media/media-add-ons/radeon/VideoIn.h +++ b/src/add-ons/media/media-add-ons/radeon/VideoIn.h @@ -19,6 +19,8 @@ #include "Tuner.h" #include "MSP3430.h" #include "Theater.h" +#include "Theater100.h" +#include "Theater200.h" enum video_in_source { C_VIDEO_IN_TUNER, @@ -83,7 +85,7 @@ public: ~CVideoIn(); - status_t InitCheck() const; + status_t InitCheck(); int Capabilities() const; @@ -126,7 +128,7 @@ private: CRadeon fRadeon; CCapture fCapture; CI2CPort fI2CPort; - CTheater fTheater; + CTheater* fTheater; CTuner fTuner; CMSP3430 fSound; int32 fBuffer0; diff --git a/src/add-ons/media/media-add-ons/radeon/yuv_converter.h b/src/add-ons/media/media-add-ons/radeon/yuv_converter.h index f3890294cc..734616619f 100644 --- a/src/add-ons/media/media-add-ons/radeon/yuv_converter.h +++ b/src/add-ons/media/media-add-ons/radeon/yuv_converter.h @@ -172,6 +172,6 @@ "jg 2b\n" "emms\n" : - : "a" (convert_buffer), "d" (bits), + : "a" (convert_buffer), "d" (bits), "g" (c_offs), "g" (y_offs), "g" (masks), "g" (scale), "g" (masks_8bit), "c" (bytesPerRow), "S" (bitsLength), "D" (bytesPerRow));