/** * Author: Milind Changire * * Copyright Corel Comptuer Corp (c) 1997-1998 * * Video Capture driver for the Philips SAA7111 interfacing via reg 3CF/B6 * of the CyberPro2000 using the I2C interface. * The IGS SDK for video capture has been used to develop this device driver. * http://www.igst.com * * Note: * Use tabstop=2 for viewing/editing. * * * Note: * All operations handle YUV422 data and NOT RGB data. * The YUV to RGB conversion routines can be used to convert a captured frame * to create a photograph or portrait for a Video Conferencing application. * */ // 30.Sep.1998 added for Rev.5 Phillips 7111 chip // enable7111() call, setting CPLD bit 2 = 1 - disable 7111, 0 - enable 7111 #include #ifdef MODULE #include #include #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #endif #include #include #include #include #include #include //#include //#include //#include #include /*****************************************************************************/ #include "igs.h" #include "igsvideo.h" #include "fifotab.h" #include "igscop.h" #include "vidcap.h" extern int set_CPLD(int bitset, int bitmask); static const char vidcap_name[] = "vidcap"; static int vidcap_major = 0; static int gbCaptured = 0; static int gbCaptured2 = 0; static int open_vidcap(struct inode* inodep, struct file* filep); static void release_vidcap(struct inode* inodep, struct file* filep); static int vidcap_ioctl(struct inode* inodep, struct file* filep, unsigned int cmd, unsigned long arg); static void release_video(); int setup_vidcap(); static struct file_operations vidcap_fops = { NULL, /* no special lseek */ NULL, /* no special read */ NULL, /* no special write */ NULL, /* no special readdir */ NULL, /* no special select */ vidcap_ioctl, NULL, /* no special mmap */ open_vidcap, release_vidcap, NULL, /* no special fsync */ NULL, /* no special fasync */ NULL, /* no special check_media_change */ NULL /* no special revaldate */ }; int XlatY[XLATTABSIZE*5] = { 0 }; int XlatU_B[XLATTABSIZE] = { 0 }; int XlatU_G[XLATTABSIZE] = { 0 }; int XlatV_G[XLATTABSIZE] = { 0 }; int XlatV_R[XLATTABSIZE] = { 0 }; /*for 7110 initialization*/ #define P7110_Count 53 static unsigned char Phil7110_00[P7110_Count]= {0x4c,0x3f,0x0d,0xef,0xbd,0xf0,0x00,0x01, 0xf8,0xf8,0x60,0x60,0x00,0x86,0x18,0x70, 0x00,0x2c,0x40,0x50,0x42,0x1a,0xfc,0xd3, 0xf0,0x91,0xff,0xff,0xff,0xff,0xff,0xff, 0xd9,0x16,0x40,0x4c,0x80,0x40,0x80,0x41, 0xfe,0x01,0xc5,0x0f,0x03,0x01,0x81,0x03, 0x44,0x45,0x02,0x8c,0x03 }; /*for 7111 initialization*/ #define P7111_Count 17 static unsigned char Phil7111_02[P7111_Count]= {// 2 3 4 5 6 7 8 9 0xc0,0x23,0x00,0x00,0xeb,0xe0,0x48,0x40, // a b c d e f 10 11 0x80,0x47,0x40,0x00,0x02,0x00,0xc0,0x0c, //12 0x80 }; /*reg_00 to reg_12*/ #define PATH_SIZE 99 char szTextBuffer[PATH_SIZE] = { 0 }; char *q = (char*)0; int mBpp = 0; /*currnet graphics mode bpp*/ int IGAIRQn = 0; /*V_Sync IRQ#*/ int UsageID = 0; unsigned short WhichCamera = 0; unsigned short wMaxTable = 0; unsigned short wMemSize = 0; unsigned short wMemType = 0; unsigned short iVFilterOn[2] = { 0 }; unsigned short iReg74[2] = { 0 }; unsigned short iReg75[2] = { 0 }; unsigned short iRegD9[2] = { 0 }; unsigned short iRegDA[2] = { 0 }; unsigned short iRegDD[2] = { 0 }; unsigned short savedReg74 = 0; unsigned short savedReg75 = 0; unsigned short savedRegD9 = 0; unsigned short savedRegDA = 0; unsigned short savedRegDD = 0; int maxXExt = 0; /* 1 based */ int maxYExt = 0; /* 1 based */ unsigned short gwWidthBytes = 0; unsigned long dwOffsetOffScreen = 0; unsigned long dwOffsetOffScreen_V2 = 0; unsigned long dwChipID = 0; unsigned short wGarbageLine = 0; int wMPEG2Enable = 0; /* flag to inicate whether full * screen cature is supported or * not */ int gwXMirror = 0; int gwYMirror = 0; unsigned short wMAX_SIZE_X_NTSC = 0; unsigned short wMAX_SIZE_Y_NTSC = 0; unsigned short wFixCapWid320 = 0; unsigned short wDEFAULT_SRC_WIDTH = 0; unsigned short wDEFAULT_SRC_HEIGHT = 0; unsigned short wDEFAULT_SRC_WIDTH_V2 = 0; unsigned short wDEFAULT_SRC_HEIGHT_V2 = 0; int gwVideoStandard = NTSC; #if SUPPORTVUNDERSCAN int wV_Underscan = 0; int iMaxLines = 0; /* # of scan lines within which * we drop one scan line */ int iWhichLine = 0; /* which scan line we drop */ #endif int x0 = 0; /* PIP */ int y0 = 0; /* PIP */ int x1 = 0; /* PIP */ int y1 = 0; /* PIP */ int x_ext = 0; /* all purpose: horz screen res */ int y_ext = 0; /* all purpose: vert screen res */ int i = 0; int xx = 0; int yy = 0; int igs_pixel_size = 0; /* all purpose: bits per pixel */ unsigned long dwPtr1 = 0; /* off screen video mem address */ unsigned long dwPtr2 = 0; /* for Overlay1 and Overlay2 */ unsigned short wCaptureW = 0; unsigned short wCaptureH = 0; unsigned char glpYUVBuf[352*2*240] = { 0 }; unsigned char* glpOverlay1Data = ((unsigned char*)(long) (0xd0000000L + 640*480*3)); unsigned char* glpOverlay2Data = ((unsigned char*)(long) (0xd0000000L + 640*480*3 + 640*240*2)); /* Arbitrary offset * for 2nd Overlay * data. Must be in * sync with dwPtr2 */ /*****************************************************************************/ int IGS_InitParam(void) { if (Init_ConfigData()==FALSE) return(1); IGS_InitXlatTab(); /*first YUV->RGB xlat table*/ return(0); } int Init_ConfigData(void) { unsigned long dwDDRAW; mBpp = GetBpp(); maxXExt = GetCurrentScreenSize(X_SCREEN); maxYExt = GetCurrentScreenSize(Y_SCREEN); /* set default offscreen address, but application can overwrite it by calling dwSetOffScreenPtr() */ dwOffsetOffScreen = (unsigned long) maxXExt * maxYExt * mBpp/8; wMemSize = GetVMemSize(); dwDDRAW = GetVideoFIFO(); #if SUPPORTVUNDERSCAN /*get underscan information*/ wV_Underscan = (ReadReg(0x3d4,0x45) & 0x10) >>4; if (wV_Underscan==1) { iMaxLines = ReadReg(0x3d4,0x44) + 0x11; iWhichLine = iMaxLines >> 4; iMaxLines = iMaxLines & 0x0F; } #endif if (dwDDRAW==1) return TRUE; else return FALSE; } /** * Color translation table used for YUV to RGB conversion. */ void IGS_InitXlatTab (void) /*YUV->RGB xlat table*/ { int i, j; for (i=0; i 253) j = 253; else j = i; // orig: XlatY[i] = (int ) j; XlatY[i] = j; } for (i=0; i 240) j = 240; else j = i; j -= 128; XlatU_B[i] = MulDiv(j,219,126); /* j*219/126 */ XlatU_G[i] = MulDiv(j, 74,219); XlatV_G[i] = MulDiv(j,153,219); XlatV_R[i] = MulDiv(j,219,160); XlatY[i+latU_B] = MulDiv(j,219,126); XlatY[i+latU_G] = MulDiv(j, 74,219); XlatY[i+latV_G] = MulDiv(j,153,219); XlatY[i+latV_R] = MulDiv(j,219,160); } } /********************************************************** Get current graphics mode color depth in: none return 8 - 8 Bpp (256 color mode) 16 - 16 Bpp (High color mode) 24 - 24 Bpp (True color mode) **********************************************************/ int GetBpp(void) { unsigned char modeBpp; outb_p(ExtSeqMisc, IGSEXTINDEX); modeBpp = inb_p(IGSEXTDATA) & 0x07; switch (modeBpp) { case 2: case 6: modeBpp = 16; break; case 3: case 4: modeBpp = 24; break; case 1: default:modeBpp = 8; break; } return ((int) modeBpp); } /*============================================= in: iScreen is X_SCREEN or Y_SCREEN out: return current x_resolution or y_resolution (1 based value) =============================================*/ int GetCurrentScreenSize(int iScreen) { int iDE; /*H or V Display Enable*/ unsigned char bCrt01, bCrt12, bCrt07, bExt11; if (iScreen == Y_SCREEN) { outb_p(0x07, CRTINDEX); bCrt07 = inb_p(CRTDATA); outb_p(0x12, CRTINDEX); bCrt12 = inb_p(CRTDATA); outb_p(0x11, IGSEXTINDEX); bExt11 = inb_p(IGSEXTDATA); iDE = bCrt12 + (((unsigned short)bExt11 & 0x02) << 9) + ((bCrt07 & 0x02) << 7) + ((bCrt07 & 0x40) << 3) + 1; } else { outb_p(0x01, CRTINDEX); bCrt01 = inb_p(CRTDATA); iDE = ((int)bCrt01 + 1) * 8; } return iDE; } /*============================================= in: None out: return current video memory size 0: 1MB, 1: 2MB, 2: 4MB =============================================*/ int GetVMemSize(void) { unsigned char bData; outb_p(0x72, IGSEXTINDEX); bData = inb_p(IGSEXTDATA) & 0x03; /*0: 1MB, 1: 2MB, 2: 4MB.*/ return bData; } /*============================================= This routine is used internally: Get Video FIFO and other informations return 0: error, 1: success =============================================*/ int GetVideoFIFO(void) { int k, wTableIndex, iMpeg1, iMpeg2; unsigned short *wPtr; /*save FIFO control regs*/ outb_p(ExtFIFOReg0, IGSEXTINDEX); savedReg74 = ((inb_p(IGSEXTDATA)) << 8) + ExtFIFOReg0; outb_p(ExtFIFOReg1, IGSEXTINDEX); savedReg75 = ((inb_p(IGSEXTDATA)) << 8) + ExtFIFOReg1; outb_p(FIFO_TIMING_CTL_L, IGSEXTINDEX); savedRegD9 = ((inb_p(IGSEXTDATA)) << 8) + FIFO_TIMING_CTL_L; outb_p(FIFO_TIMING_CTL_H, IGSEXTINDEX); savedRegDA = ((inb_p(IGSEXTDATA)) << 8) + FIFO_TIMING_CTL_H; outb_p(FIFO_CTL_I, IGSEXTINDEX); savedRegDD = ((inb_p(IGSEXTDATA)) << 8) + FIFO_CTL_I; switch (maxXExt) { default: case 640: wTableIndex = 0; break; case 800: wTableIndex = 1; break; case 1024: wTableIndex = 2; break; case 1280: wTableIndex = 3; break; case 1600: wTableIndex = 4; break; } if (wMemSize == 0) iMpeg1 = (unsigned short) ( dwMPEG1_1MB[wTableIndex] >> (mBpp-8) ); else iMpeg1 = (unsigned short) ( dwMPEG1_2MB[wTableIndex] >> (mBpp-8) ); iMpeg1 &= 0x00FF; /*got the index to the FIFO table (MPEG1)*/ iMpeg2 = (unsigned short) ( dwMPEG2_2MB[wTableIndex] >> (mBpp-8) ); iMpeg2 &= 0x00FF; /*got the index to the FIFO table (MPEG2)*/ /*Copy data to working sets for MPEG1 and MPEG2 size images*/ wPtr = wFIFOTable[iMpeg1]->wFIFOData; iVFilterOn[0] = *wPtr++; iReg74[0] = *wPtr++; iReg75[0] = *wPtr++; iRegD9[0] = *wPtr++; iRegDA[0] = *wPtr++; iRegDD[0] = *wPtr++; wPtr = wFIFOTable[iMpeg2]->wFIFOData; iVFilterOn[1] = *wPtr++; iReg74[1] = *wPtr++; iReg75[1] = *wPtr++; iRegD9[1] = *wPtr++; iRegDA[1] = *wPtr++; iRegDD[1] = *wPtr++; if (iMpeg2 != 0xFF) wMPEG2Enable = 1; else wMPEG2Enable = 0; /* full screen capture should be disabled */ if ( (iMpeg1 != 0xFF) ) return 1; /*sucessful*/ else return 0; /*fail (capture can not be supported in this mode)*/ } /********************************************************** Initialize IGS Video Hardware and Decoder to a default state in: none Note: This function should not be called before DetectDecoder, since there is decoder dependant code in this routine This is one time only initialization routine. **********************************************************/ void IGS_InitVideo(void) { unsigned long dwL; /* --- Initialize IGS Video Registers --- */ Out_Video_Reg( DISP_CTL_I, 0x00 ); /*This is only init to default value before set Reg_E8<2,0> final working addr will be set at IGS_SetCaptureAddr*/ dwL = dwOffsetOffScreen >> 2; Out_Video_Reg(CAPTURE_ADDR_L, (unsigned char)(dwL & 0x0000ffL) ); Out_Video_Reg(CAPTURE_ADDR_M, (unsigned char)(( dwL & 0x00ff00L) >> 8)); Out_Video_Reg(CAPTURE_ADDR_H, (unsigned char)(( dwL & 0xff0000L) >> 16)); Out_Video_Reg(VFAC_CTL_MODE_III, 0x00); Out_Video_Reg(VFAC_CTL_MODE_II, 0x10); outw_p((0x0100 + CAPTURE_BANK_CTL), IGSEXTINDEX); outw_p((iRegD9[0] & 0xFF00 | V_DST_Y1_LO), IGSEXTINDEX); outw_p((iRegDA[0] & 0xFF00 | V_DST_Y1_HI), IGSEXTINDEX); Out_Video_Reg(DEST_RECT_TOP_L, 0x00); Out_Video_Reg(DEST_RECT_TOP_H, 0x00); Out_Video_Reg(DDA_Y_INC_L, 0x00); Out_Video_Reg(DDA_Y_INC_H, 0x10); Out_Video_Reg(MEMORY_START_L, 0x00); Out_Video_Reg(MEMORY_START_M, 0x0f); Out_Video_Reg(MEMORY_START_H, 0x03); Out_Video_Reg(DEST_RECT_LEFT_L, 0x20); Out_Video_Reg(DEST_RECT_LEFT_H, 0x00); Out_Video_Reg(DEST_RECT_RIGHT_L, 0x60); Out_Video_Reg(DEST_RECT_RIGHT_H, 0x01); Out_Video_Reg(DEST_RECT_BOTTOM_L, 0xe0); Out_Video_Reg(DEST_RECT_BOTTOM_H, 0x00); Out_Video_Reg(MEMORY_OFFSET_PHASE, 0x50); Out_Video_Reg(COLOR_CMP_RED, 0x00); Out_Video_Reg(COLOR_CMP_GREEN,0x00); Out_Video_Reg(COLOR_CMP_BLUE, 0x00); Out_Video_Reg(DDA_X_INC_L, 0x00); Out_Video_Reg(DDA_X_INC_H, 0x10); Out_Video_Reg(VIDEO_FORMAT, 0x00); Out_Video_Reg(MISC_CTL_I, 0x00); Out_Video_Reg(MISC_CTL_I, 0x01); Out_Video_Reg(MISC_CTL_I, 0xc0); Out_Video_Reg(MISC_CTL_I, 0x01); outw_p((0x0000 + CAPTURE_DDA_X_INIT_L), IGSEXTINDEX); outw_p((0x0800 + CAPTURE_DDA_X_INIT_H), IGSEXTINDEX); outw_p((0x0000 + CAPTURE_DDA_Y_INIT_L), IGSEXTINDEX); outw_p((0x0800 + CAPTURE_DDA_Y_INIT_H), IGSEXTINDEX); outw_p((0x3F00 + CAPTURE_NEW_CTL_I), IGSEXTINDEX); outw_p((0xC000 + CAPTURE_NEW_CTL_II), IGSEXTINDEX); outw_p((0x1000 + CAPTURE_MODE_I), IGSEXTINDEX); outw_p((0x5000 + CAPTURE_MODE_II), IGSEXTINDEX); outw_p((0x8000 + CAPTURE_TV_CTL), IGSEXTINDEX); outw_p((0xB400 + CAPTURE_CTL_MISC), IGSEXTINDEX); outw_p((0x0500 + CAPTURE_BANK_CTL), IGSEXTINDEX); outw_p((0x4000 + CAPTURE_X2_CTL_I), IGSEXTINDEX); switch (WhichCamera) { default: case PHILIPS7111: { outb_p(0xbe, IGSEXTINDEX); if ( (inb_p(IGSEXTDATA) & 0x04) == 0x00 ) { Out_Video_Reg_M( CAPTURE_MODE_I, 0x01, 0xfe ); /* Enable 8 bit video*/ // Milind: outb_p(0xb6, IGSEXTINDEX); sendOneByte(P7111Port,0x10,0xC8); /* 7111 - 8 bit*/ Out_Video_Reg( CAPTURE_H_START_L, 0x0F ); Out_Video_Reg( CAPTURE_H_START_H, 0x00 ); Out_Video_Reg( CAPTURE_H_END_L, 0x90 ); Out_Video_Reg( CAPTURE_H_END_H, 0x05 ); } else { Out_Video_Reg( CAPTURE_H_START_L, 0x07 ); Out_Video_Reg( CAPTURE_H_START_H, 0x00 ); Out_Video_Reg( CAPTURE_H_END_L, 0xC8 ); Out_Video_Reg( CAPTURE_H_END_H, 0x02 ); } } break; case PHILIPS7110: { Out_Video_Reg( CAPTURE_H_START_L, 0x00 ); Out_Video_Reg( CAPTURE_H_START_H, 0x00 ); Out_Video_Reg( CAPTURE_H_END_L, 0x82 ); Out_Video_Reg( CAPTURE_H_END_H, 0x02 ); } break; } Out_Video_Reg( DISP_CTL_I, 0x04 ); } /********************************************************** Turn on IGS video (Turn on both External Out and External In) in: none Note: . This function should be called at least once to enable IGS video hardware. . In case video stops accidently, this function together with IGS_VideoOff can be used to reenable the video hardware. **********************************************************/ void IGS_VideoOn(void) { IGS_SetFreezeVid(ON); Out_Video_Reg_M(0xb5, 0x01, 0xFE); /* Enable Vafc*/ Out_Video_Reg(MISC_CTL_I, 0xc0); Out_Video_Reg(MISC_CTL_I, 0x01); Out_Video_Reg_M(DISP_CTL_I, 0x84, 0x7B); /* Milind: */ while((inb_p(0x3da) & 0x08)); /* skip current Vertical Retrace */ while(!(inb_p(0x3da) & 0x08)); /* wait for Vertical Retrace to begin */ Out_Video_Reg_M(VFAC_CTL_MODE_I, 0x41, 0xBE); /*Video capture enable*/ ResetSeq(); IGS_SetFreezeVid(OFF); } /********************************************************** Turn off IGS video (Turn off both External Out and External In) in: none **********************************************************/ void IGS_VideoOff(void) { Out_Video_Reg( DISP_CTL_I, 0x00 );/* Video disabled*/ /* Milind: */ while(!(inb_p(0x3da) & 0x08)); /* wait for Vertical Retrace to begin */ Out_Video_Reg( VFAC_CTL_MODE_I, 0x40 ); Out_Video_Reg_M( 0xb5, 0x00, 0xFE ); /* Disable Vafc */ ResetSeq(); } /*========================================================= This routine is used internally in: none =========================================================*/ void ResetSeq(void) { unsigned char reg_70; outb_p(0x70, IGSEXTINDEX); reg_70 = inb_p(IGSEXTDATA) | 0x80; outb_p(reg_70, IGSEXTDATA); reg_70 &= 0x7F; outb_p(reg_70, IGSEXTDATA); } /*========================================================= This routine is used internally in: none Byte OUTPORT with bit mask in: bValue=bit/bits to be set/clear, untouched bit/bits must be zero bMask=bit/bits to be masked, 1:mask, 0:to be set/clear e.g. set <4,3>=<1,0>, bValue=0x10 and bMask=E7 =========================================================*/ void Out_Video_Reg_M( unsigned char bIndex, unsigned char bValue, unsigned char bMask ) { outb_p(bIndex, IGSEXTINDEX); outb_p((inb_p(IGSEXTDATA) & bMask) | bValue, IGSEXTDATA); } /*========================================================= This routine is used internally in: none =========================================================*/ void Out_Video_Reg( unsigned char bIndex, unsigned char bValue ) { outb_p(bIndex, IGSEXTINDEX); outb_p(bValue, IGSEXTDATA); } /*----------------------------------------------------- Enable Graphics Engine This routine shows an example that enables graphics engine's memory mapped IO at base of 0xBF000 (notice this is working DOS program). However, enable to linear address is recommanded. E.g. video memory is located at 0xFE000000, we can use 0xFE8BF000 as graphics engine's memory mapped IO base, We need set 3CE_33 bits 0,1,2,3, that is, OUTPORT(igs_index_port, 0x0F33); -----------------------------------------------------*/ void EnableCop() { // orig : outw_p(0x1C33, IGSEXTINDEX); //enable graphics engine at BF000 outw_p(0x0f33, IGSEXTINDEX); //enable graphics engine at BF000 } /********************************************************** Set pointer to video memory used to store captured data in: dwL - 32 bit value pointing to video memory, usually is off-screen to store YUV422 captured data. Note: . dwL must be physical memory pointer, not virtual. Please see Init_ConfigData as an example . With this pointer, application can access captured image data directly. **********************************************************/ void dwSetOffScreenPtr(unsigned long dwL) { dwOffsetOffScreen = dwL; } /********************************************************** Set pointer to video memory used by Video 2 overlay window in: dwL - 32 bit value pointing to video memory, usually is off-screen to store YUV422 overlay data. Note: . dwL must be physical memory pointer, not virtual. **********************************************************/ void dwSetOffScreenPtr_V2(unsigned long dwL) { dwOffsetOffScreen_V2 = dwL; } /*---------------------------------------------- IGS Graphics Engine Funtions Note: the Graphics engine routines are not necessary in overlay and capture programming. All overlay and capture data can be manipulated by using CPU. ----------------------------------------------*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Basic bitblt - source copy (a color map as source) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*------------------------------------------------------ copy a rectangle from src (sx, sy) to dst (dx, dy) ----------------------------------------------------*/ void SrcCopy(int sx, int sy, int dx, int dy, int w, int h) { unsigned long op; wait_for_cop_ready(); *Cop_control = 0; *Fore_Mix = (char) Mix_S; if (igs_pixel_size != 2) { *Op_Dimension_1 = w-1; *Dst_Start_Ptr = (unsigned long)dy*(x_ext+1) + dx; *Src_Start_Ptr = (unsigned long)sy*(x_ext+1) + sx; } else { *Op_Dimension_1 = w-1; *Dst_Start_Ptr =((unsigned long)dy*(x_ext+1) + dx)*3; *Dst_X_Phase =((unsigned char)dy*(x_ext+1) + dx) ; *Src_Start_Ptr =((unsigned long)sy*(x_ext+1) + sx)*3; } *Op_Dimension_2 = h-1; op = Fore_Src_PxMap; op |= PxBlt; op |= Pattern_Foreground | Right_Down; *Px_OpL = LOWORD(op); *Px_OpH = HIWORD(op); } /*------------------------------------------------------ copy a rectangle from src (sx, sy) to dst (dx, dy) This routine play a trick to copy data in different dimension as the current screen resolution. The off-screen is used as base start pointer. This routine should be used together with IGS_SetPIPWindow ----------------------------------------------------*/ void SrcCopy_0(int sx, int sy, int dx, int dy, int w, int h) { unsigned long op; wait_for_cop_ready(); *Cop_control = 0; *Fore_Mix = (char) Mix_S; *Op_Dimension_1 = w-1; *Dst_Start_Ptr = (unsigned long)(y_ext+1)*(x_ext+1); *Dst_Start_Ptr += (unsigned long)dy*(352*2) + dx; *Src_Start_Ptr = (unsigned long)(y_ext+1)*(x_ext+1); *Src_Start_Ptr += (unsigned long)sy*(352*2) + sx; *Op_Dimension_2 = h-1; op = Fore_Src_PxMap; op |= PxBlt; op |= Pattern_Foreground | Right_Down; *Px_OpL = LOWORD(op); *Px_OpH = HIWORD(op); } /*------------------------------------------------------ fill a rectangle with solid color ----------------------------------------------------*/ void PaintWindow(int x, int y, int w, int h, unsigned long c) { unsigned long op; wait_for_cop_ready(); *Cop_control = 0; *Fore_Mix = (char) Mix_S; *Fore_Color = c; if (igs_pixel_size != 2) { *Op_Dimension_1 = w-1; *Dst_Start_Ptr = (unsigned long)y*(x_ext+1) + x; } else { *Op_Dimension_1 = w-1; *Dst_Start_Ptr =((unsigned long)y*(x_ext+1) + x)*3; *Dst_X_Phase =((unsigned char)y*(x_ext+1) + x) ; } *Op_Dimension_2 = h-1; op = Fore_Src_color; op |= PxBlt; op |= Pattern_Foreground | Right_Down; *Px_OpL = LOWORD(op); //this can be byte, 2 bytes or 4 bytes access, *Px_OpH = HIWORD(op); //but, hi byte must be the last to access. } /*----------------------------------------------------- This routine waits until Graphics Engine is not busy. -----------------------------------------------------*/ void wait_for_cop_ready(void) { unsigned long WaitCount; // // WaitCount=0x000FFFF0; // while(WaitCount!=0) // <- with counter { // if ((*Cop_control & 0x80)==0) // return; // else // WaitCount --; // } // *Cop_control = 0; // <- force to reset } /*----------------------------------------------------- Set some Graphics Engine registers which are not touched by most operations. -----------------------------------------------------*/ void Set_IGS_Px_Map(int w, int pixelsize) { if (pixelsize != 2) { *Src_Map_Width = w; *Dst_Map_Width = w; } else //24 bpp true color { *Src_Map_Width = (w+1)*3-1; *Dst_Map_Width = (w+1)*3-1; } *Px_Map_Format = pixelsize; } /*========================================================= This routine is used internally in: =========================================================*/ unsigned char ReadReg(unsigned short wReg, unsigned char bIndex) { unsigned char bReturn; outb_p(bIndex, wReg); bReturn = inb_p(wReg+1); return bReturn; } /********************************************************** Initialize Philips 7111 in: none return TRUE if successful FALSE if error *********************************************************/ int InitPhil7111(void) { if (sendMoreByte(P7111Port,0x02,Phil7111_02,P7111_Count) == FALSE) return FALSE; return TRUE; } /********************************************************** Setup width and Height of video source window (this routine does not set hardware registers) in: nWidth = width of captured video image in pixel. nHeight = height of captured video image in scan line. return 0 if successful -1 if error note: . full screen capture may not be available in some modes due to off-screen memory requirment. So make sure to check retuned value to see it is successful or not. . Application must call this routine to set gwWidthBytes before calling IGS_AdjustVideoWindow IGS_SetCaptureAddr **********************************************************/ int IGS_SetSrcWindowSize(unsigned short wWidth, unsigned short wHeight) { int iFlag; iFlag = 0; /*to indicate successful*/ //if (wWidth % 2) if (wWidth & 1) iFlag = -1; /*error*/ if ( (wWidth > MAXMPEG1) && (wMPEG2Enable == 0) ) iFlag = -1; /*error*/ wDEFAULT_SRC_WIDTH = wWidth; wDEFAULT_SRC_HEIGHT = wHeight; gwWidthBytes = wDEFAULT_SRC_WIDTH*2; return (iFlag); } /********************************************************** Setup width and Height of video source window (this routine does not set hardware registers) in: nWidth = width of captured video image in pixel. nHeight = height of captured video image in scan line. return 0 if successful -1 if error note . video 2 may not be available in some modes due to off-screen memory requirment. So application should make sure the offscreen has enough space to hold 2nd video source data. **********************************************************/ int IGS_SetSrcWindowSize_V2(unsigned short wWidth, unsigned short wHeight) { int iFlag; iFlag = 0; /*to indicate successful*/ //if (wWidth % 2) if (wWidth & 1) iFlag = -1; /*error*/ wDEFAULT_SRC_WIDTH_V2 = wWidth; wDEFAULT_SRC_HEIGHT_V2 = wHeight; return (iFlag); } /********************************************************** Setup captured video format in: nFormat = YUV422 else: not support yet **********************************************************/ void IGS_SetCaptureFormat(unsigned char nFormat) { switch (nFormat) { case YUV422: Out_Video_Reg_M( VIDEO_FORMAT, 0x00, 0xF8 ); break; default: break; } } /********************************************************** Setup video overlay format in: nFormat = COLORKEY = WINDOWKEY **********************************************************/ void IGS_SetOverlayFormat(unsigned char nFormat) { switch (nFormat) { case COLORKEY: Out_Video_Reg_M( DISP_CTL_I, 0x00, 0xFD ); break; case WINDOWKEY: default: Out_Video_Reg_M( DISP_CTL_I, 0x02, 0xFD ); break; } } /********************************************************** Setup video 2 overlay format in: nFormat = COLORKEY = WINDOWKEY **********************************************************/ void IGS_SetOverlayFormat_V2(unsigned char nFormat) { Out_Video_Reg(CAPTURE_BANK_CTL, 0x01); switch (nFormat) { case COLORKEY: Out_Video_Reg_M(V_DST_Y2_HI, 0x00, 0xFD); break; case WINDOWKEY: default: Out_Video_Reg_M(V_DST_Y2_HI, 0x02, 0xFD); break; } } /********************************************************** Setup capture window address (Setup incoming video address) in: none Note: 1. It is only necessary to call this routine once. 2. Please note that the capture address varies for different graphics modes and the address is defined in the variable dwOffsetOffScreen which must be set by application before calling this routine. 3. dwOffsetOffScreen has been set a default value in routine Init_ConfigData, 4. application can call dwSetOffScreenPtr() to overwite the 32 variable dwOffsetOffScreen. **********************************************************/ void IGS_SetCaptureAddr(void) { if (gwWidthBytes <= wFixCapWid320) Change_VideoFIFO(0); /*set MPEG1 FIFO*/ else Change_VideoFIFO(1); /*set MPEG2 FIFO*/ if (wDEFAULT_SRC_HEIGHT <= 240) { if (gwVideoStandard == NTSC) { Set_Capture_Scale(wDEFAULT_SRC_WIDTH,wMAX_SIZE_X_NTSC,wDEFAULT_SRC_HEIGHT,NTSC_SRC_HEIGHT/2); wGarbageLine = NTSC_GarbageLine/2; } else if (gwVideoStandard == PAL) { Set_Capture_Scale(wDEFAULT_SRC_WIDTH,wMAX_SIZE_X_NTSC,wDEFAULT_SRC_HEIGHT,PAL_SRC_HEIGHT/2); wGarbageLine = PAL_GarbageLine/2; } Out_Video_Reg_M( VFAC_CTL_MODE_III, 0x00, 0xFD ); /*Interlace bit=0*/ Out_Video_Reg_M( CAPTURE_CTL_MISC, 0x04, 0xFB ); /*Data Good bit=1*/ } else { if (gwVideoStandard == NTSC) { Set_Capture_Scale(wDEFAULT_SRC_WIDTH,wMAX_SIZE_X_NTSC,wDEFAULT_SRC_HEIGHT,NTSC_SRC_HEIGHT); wGarbageLine = NTSC_GarbageLine; } else if (gwVideoStandard == PAL) { Set_Capture_Scale(wDEFAULT_SRC_WIDTH,wMAX_SIZE_X_NTSC,wDEFAULT_SRC_HEIGHT,PAL_SRC_HEIGHT); wGarbageLine = PAL_GarbageLine; } Out_Video_Reg_M( VFAC_CTL_MODE_III, 0x02, 0xFD ); /*Interlace bit=1*/ Out_Video_Reg_M( CAPTURE_CTL_MISC, 0x00, 0xFB ); /*Data Good bit=0*/ } Out_Video_Reg(CAPTURE_PITCH_L, (unsigned char) (gwWidthBytes >> 3) ); IGS_SetCaptureClip(gwVideoStandard); IGS_SetXYMirror(gwXMirror,gwYMirror); } /********************************************************** Scale up the overlay window (source window unchange) in: wSrcXExt - source window width wDstXExt - destination window width wSrcYExt - source window height wDstYExt - destination window height **********************************************************/ void IGS_SetScale( unsigned short wSrcXExt, unsigned short wDstXExt, unsigned short wSrcYExt, unsigned short wDstYExt ) { unsigned long dwScale; Out_Video_Reg( DDA_X_INIT_L, 0x0 ); /*0x800*/ Out_Video_Reg( DDA_X_INIT_H, 0x8 ); if ( wSrcXExt == wDstXExt ) dwScale = 4096; /*0x1000*/ else dwScale = ((unsigned long)(wSrcXExt - 2) * 4096) / (unsigned long)wDstXExt; Out_Video_Reg( DDA_X_INC_L, LOBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( DDA_X_INC_H, HIBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( DDA_Y_INIT_L, 0x0 ); /*0x800*/ Out_Video_Reg( DDA_Y_INIT_H, 0x8 ); if ( wSrcYExt == wDstYExt ) dwScale = 4096; /*0x1000*/ else dwScale = ((unsigned long)(wSrcYExt - 2) * 4096) / (unsigned long)wDstYExt; Out_Video_Reg( DDA_Y_INC_L, LOBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( DDA_Y_INC_H, HIBYTE( (unsigned short)dwScale ) ); } /********************************************************** Scale up video 2 overlay window (video 2 source window unchange) in: wSrcXExt - source window width wDstXExt - destination window width wSrcYExt - source window height wDstYExt - destination window height **********************************************************/ void IGS_SetScale_V2(unsigned short wSrcXExt, unsigned short wDstXExt, unsigned short wSrcYExt, unsigned short wDstYExt) { unsigned long dwScale; Out_Video_Reg(CAPTURE_BANK_CTL, 0x01); /*initial value registers are same as video 1*/ Out_Video_Reg( DDA_X_INIT_L, 0x0 ); Out_Video_Reg( DDA_X_INIT_H, 0x8 ); if ( wSrcXExt == wDstXExt ) dwScale = 4096; else dwScale = ((unsigned long)(wSrcXExt - 2) * 4096) / (unsigned long)wDstXExt; Out_Video_Reg( V_SRC_STRIDE_LO, LOBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( V_SRC_STRIDE_HI, HIBYTE( (unsigned short)dwScale ) ); /*initial value registers are same as video 1*/ Out_Video_Reg( DDA_Y_INIT_L, 0x0 ); Out_Video_Reg( DDA_Y_INIT_H, 0x8 ); if ( wSrcYExt == wDstYExt ) dwScale = 4096; else dwScale = ((unsigned long)(wSrcYExt - 2) * 4096) / (unsigned long)wDstYExt; Out_Video_Reg( V_DST_X2_LO, LOBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( V_DST_X2_HI, HIBYTE( (unsigned short)dwScale ) ); Out_Video_Reg(CAPTURE_BANK_CTL, 0x00); } /********************************************************** Create and Position the overlay window with adjustment if overlay windows is moved to far left or far right in: Rectangle to be overlayed to the screen: cx - current x of the window cy - current y of the window wWinWidth - current window width wWinHeight - current window height **********************************************************/ void IGS_AdjustVideoWindow(int cx, int cy, int wWinWidth, int wWinHeight) { int i = 0, j = 0, wX = 0, wY = 0, iDstWidth = 0; if ( cx > 0) { wX = 0; i = cx; } else { i = 0; wX = abs(cx); wX = (unsigned short)(((unsigned long)wX*wDEFAULT_SRC_WIDTH)/(unsigned long)wWinWidth); } if ( cy > 0) { wY = 0; j = cy; } else { j = 0; wY = abs(cy); wY = (unsigned short)(((unsigned long)wY*wDEFAULT_SRC_HEIGHT)/(unsigned long)wWinHeight); } /*move to far right, need to adjust source fetch (also need consider DDA)*/ if ( (cx+wWinWidth) > maxXExt ) { iDstWidth = maxXExt - cx; if ((unsigned short)wWinWidth!=gwWidthBytes/2) iDstWidth = (unsigned short) ((unsigned long) iDstWidth*(gwWidthBytes/2)/wWinWidth); } else iDstWidth = gwWidthBytes/2; /*The following line will support Video Screen being moved to far left*/ IGS_SetSrcAddr(wX, wY, iDstWidth, wDEFAULT_SRC_WIDTH); /*move to far right, need to adjust destination display end*/ if ( (cx+wWinWidth) > maxXExt ) iDstWidth = maxXExt - cx; else iDstWidth = wWinWidth; IGS_SetOverlayWindow(i, j, cx+iDstWidth, cy+wWinHeight); } /********************************************************** Create and Position the 2nd overlay window with adjustment if overlay windows is moved to far left or far right in: Rectangle to be overlayed to the screen: cx - current x of the window cy - current y of the window wWinWidth - current window width wWinHeight - current window height **********************************************************/ void IGS_AdjustVideoWindow_V2(int cx, int cy, int wWinWidth, int wWinHeight) { int i, j, wX, wY; if ( cx > 0) { wX = 0; i = cx; } else { i = 0; wX = abs(cx); wX = (unsigned short)(((unsigned long)wX*wDEFAULT_SRC_WIDTH_V2)/(unsigned long)wWinWidth); } if ( cy > 0) { wY = 0; j = cy; } else { j = 0; wY = abs(cy); wY = (unsigned short)(((unsigned long)wY*wDEFAULT_SRC_HEIGHT_V2)/(unsigned long)wWinHeight); } /*The following line will support Video Screen being moved to far left*/ IGS_SetSrcAddr_V2(wX, wY, wDEFAULT_SRC_WIDTH_V2, wDEFAULT_SRC_WIDTH_V2); IGS_SetOverlayWindow_V2(i, j, cx+wWinWidth, cy+wWinHeight); } /*============================================= This routine is used internally: Routine: to change Video FIFO in: which=table to be used =============================================*/ void Change_VideoFIFO( int which ) { if (iVFilterOn[which] == 0) Out_Video_Reg_M( DISP_CTL_I, 0x20, 0xDF ); else Out_Video_Reg_M( DISP_CTL_I, 0x00, 0xDF ); outw_p(iReg74[which], IGSEXTINDEX); outw_p(iReg75[which], IGSEXTINDEX); outw_p(iRegD9[which], IGSEXTINDEX); outw_p(iRegDA[which], IGSEXTINDEX); outw_p(iRegDD[which], IGSEXTINDEX); } /*============================================= This routine is used internally in wSrcXExt, wDstXExt = wMAX_SIZE_X_NTSC (640/720) wSrcYExt, wDstYExt = 480/2 or 480 ===============================================*/ void Set_Capture_Scale( unsigned short wSrcXExt, unsigned short wDstXExt, unsigned short wSrcYExt, unsigned short wDstYExt ) { unsigned long dwScale; if ( wSrcXExt == wDstXExt ) dwScale = 4096; else { dwScale = ((unsigned long)(wSrcXExt ) * 4096) / (unsigned long)wDstXExt; } Out_Video_Reg( CAPTURE_DDA_X_INC_L, LOBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( CAPTURE_DDA_X_INC_H, HIBYTE( (unsigned short)dwScale ) ); if ( wSrcYExt == wDstYExt ) dwScale = 4096; else { dwScale = (((unsigned long)wSrcYExt * 4096) / (unsigned long)wDstYExt ) + 0x1E; } Out_Video_Reg( CAPTURE_DDA_Y_INC_L, LOBYTE( (unsigned short)dwScale ) ); Out_Video_Reg( CAPTURE_DDA_Y_INC_H, HIBYTE( (unsigned short)dwScale ) ); } /*============================================= This routine is used to set Capture Src Clip in: gwVideoStandard == NTSC or PAL =============================================*/ void IGS_SetCaptureClip(int gwVideoStandard) { switch (WhichCamera) { default: case PHILIPS7111: if (gwVideoStandard == NTSC) { outw_p((0x0B00 + CAPTURE_V_START_L), IGSEXTINDEX ); /*some garbage lines*/ outw_p((0x0000 + CAPTURE_V_START_H), IGSEXTINDEX ); outw_p((0xFD00 + CAPTURE_V_END_L), IGSEXTINDEX ); /*480+GarbageLines=end-start*/ outw_p((0x0000 + CAPTURE_V_END_H), IGSEXTINDEX ); } else if (gwVideoStandard == PAL) { outw_p(0x1000 + CAPTURE_V_START_L, IGSEXTINDEX ); /*some garbage lin*/ outw_p(0x0000 + CAPTURE_V_START_H, IGSEXTINDEX ); outw_p(0x3200 + CAPTURE_V_END_L, IGSEXTINDEX ); /*576+GarbageLines=end-start*/ outw_p(0x0100 + CAPTURE_V_END_H, IGSEXTINDEX ); } break; case PHILIPS7110: if (gwVideoStandard == NTSC) { outw_p(0x0B00 + CAPTURE_V_START_L, IGSEXTINDEX ); outw_p(0x0000 + CAPTURE_V_START_H, IGSEXTINDEX ); outw_p(0xFD00 + CAPTURE_V_END_L, IGSEXTINDEX ); outw_p(0x0000 + CAPTURE_V_END_H, IGSEXTINDEX ); } else if (gwVideoStandard == PAL) { outw_p(0x1000 + CAPTURE_V_START_L, IGSEXTINDEX ); outw_p(0x0000 + CAPTURE_V_START_H, IGSEXTINDEX ); outw_p(0x3200 + CAPTURE_V_END_L, IGSEXTINDEX ); outw_p(0x0100 + CAPTURE_V_END_H, IGSEXTINDEX ); } break; } } /********************************************************** To mirror capture image in: gwXMirror: 1: x-mirror, 0: x-normal gwYMirror: 1: y-mirror, 0: y-normal **********************************************************/ void IGS_SetXYMirror(int gwXMirror, int gwYMirror) { unsigned long dwL; dwL = dwOffsetOffScreen; if (gwYMirror) { dwL += (unsigned long) (wDEFAULT_SRC_HEIGHT+2)*wDEFAULT_SRC_WIDTH*2; Out_Video_Reg_M( CAPTURE_MODE_I, 0x40, 0xBF ); /*Y mirror*/ Out_Video_Reg_M( VFAC_CTL_MODE_II, 0x20, 0xDF ); /*O-E polarity reverse*/ } else { Out_Video_Reg_M( CAPTURE_MODE_I, 0x00, 0xBF ); /*Y normal*/ Out_Video_Reg_M( VFAC_CTL_MODE_II, 0x00, 0xDF ); /*O-E polarity normal*/ } if (gwXMirror) { dwL += (unsigned long) wDEFAULT_SRC_WIDTH*2 - 2; Out_Video_Reg_M( CAPTURE_MODE_I, 0x80, 0x7F ); /*X mirror*/ } else Out_Video_Reg_M( CAPTURE_MODE_I, 0x00, 0x7F ); /*X normal*/ IGS_SetFreezeVid(ON); /*only need freeze when set capture addr*/ Set_Capture_addr(dwL); IGS_SetFreezeVid(OFF); ResetSeq(); } /*========================================================= This routine is used internally in: OnOff = ON or OFF Note: This routine is used only at 1) anytime when we touch capture address registers (0xEB,0xEC,0xED) 2) anytime when we touch video capture enable register (0xE8) =========================================================*/ void IGS_SetFreezeVid (int OnOff) { if (OnOff==ON) /*note Freeze is On (i.e capture is off)*/ { Out_Video_Reg_M(VFAC_CTL_MODE_I, 0x0C, 0xF3); outb_p(VIDEO_ROM_UCB4G_HI, IGSEXTINDEX); while ( !(inb_p(IGSEXTDATA) & 0x02) ); } else { udelay(TimeDelay1); Out_Video_Reg_M(VFAC_CTL_MODE_I, 0x00, 0xF3); } ResetSeq(); } /*============================================= This routine is used internally: To set Capture Address in: dwOffAddr points to off-screen address with garbage line adjustment Note: Freeze and Unfreeze should be used before and after this function. =============================================*/ void Set_Capture_addr( unsigned long dwOffAddr) { unsigned long dwL; dwL = dwOffAddr >> 2; Out_Video_Reg(CAPTURE_ADDR_L, (unsigned char) (dwL & 0x0000ffL)); Out_Video_Reg(CAPTURE_ADDR_M, (unsigned char) ((dwL & 0x00ff00L) >> 8)); Out_Video_Reg(CAPTURE_ADDR_H, (unsigned char) ((dwL & 0xff0000L) >> 16)); } /********************************************************** Clean up some status which were set during the video overlay/capture in: none Note: This function should be called just before the application exits **********************************************************/ void IGS_VideoCleanUp(void) { /*restore FIFO control regs*/ outw_p(savedReg74, IGSEXTINDEX); outw_p(savedReg75, IGSEXTINDEX); outw_p(savedRegD9, IGSEXTINDEX); outw_p(savedRegDA, IGSEXTINDEX); } /********************************************************** Clean up some status for video 2 overlay hardware in: none Note: This function should be called right after application closes video 2. **********************************************************/ void IGS_VideoCleanUp_V2(void) { int i; int iStart=0x40; int iMaxNum=0x4D; /*clear Video_2 registers*/ Out_Video_Reg(CAPTURE_BANK_CTL, 0x00); for (i=iStart; i> 8); Out_Video_Reg(COLOR_CMP_GREEN,bData); bData = (unsigned char) (cref >> 16); Out_Video_Reg(COLOR_CMP_BLUE, bData); } /********************************************************** Setup video overlay window (destination window) in: Rectangle to be overlayed to the screen: wLeft (x1) wTop (y1) wRight (x2) wBottom (y2) **********************************************************/ void IGS_SetOverlayWindow(unsigned short wLeft, unsigned short wTop, unsigned short wRight, unsigned short wBottom) { int iDropLine, iRemainder; /*cap the right screen to be the screen width*/ if (wRight > (unsigned short) maxXExt) wRight = maxXExt; #if SUPPORTVUNDERSCAN if (wV_Underscan==1) { iDropLine = wTop / iMaxLines; iRemainder= wTop % iMaxLines; if (iRemainder > 0) iDropLine ++; wTop = wTop - iDropLine; } #endif Out_Video_Reg( DEST_RECT_LEFT_L, LOBYTE( wLeft ) ); Out_Video_Reg( DEST_RECT_LEFT_H, HIBYTE( wLeft ) ); Out_Video_Reg( DEST_RECT_RIGHT_L, LOBYTE( wRight ) ); Out_Video_Reg( DEST_RECT_RIGHT_H, HIBYTE( wRight ) ); Out_Video_Reg( DEST_RECT_TOP_L, LOBYTE( wTop ) ); Out_Video_Reg( DEST_RECT_TOP_H, HIBYTE( wTop ) ); Out_Video_Reg( DEST_RECT_BOTTOM_L, LOBYTE( wBottom) ); Out_Video_Reg( DEST_RECT_BOTTOM_H, HIBYTE( wBottom) ); } /********************************************************** Setup video 2 overlay window (destination window) in: Rectangle to be overlayed to the screen: wLeft (x1) wTop (y1) wRight (x2) wBottom (y2) **********************************************************/ void IGS_SetOverlayWindow_V2(unsigned short wLeft, unsigned short wTop, unsigned short wRight, unsigned short wBottom) { int iDropLine, iRemainder; if (wRight > (unsigned short) maxXExt) wRight = maxXExt; #if SUPPORTVUNDERSCAN if (wV_Underscan==1) { iDropLine = wTop / iMaxLines; iRemainder= wTop % iMaxLines; if (iRemainder > 0) iDropLine ++; wTop = wTop - iDropLine; } #endif Out_Video_Reg(CAPTURE_BANK_CTL, 0x00); Out_Video_Reg(V_DST_X1_LO, LOBYTE(wLeft)); Out_Video_Reg(V_DST_X1_HI, HIBYTE(wLeft)); Out_Video_Reg(V_DST_X2_LO, LOBYTE(wRight)); Out_Video_Reg(V_DST_X2_HI, HIBYTE(wRight)); Out_Video_Reg(V_DST_Y1_LO, LOBYTE(wTop)); Out_Video_Reg(V_DST_Y1_HI, HIBYTE(wTop)); Out_Video_Reg(V_DST_Y2_LO, LOBYTE(wBottom)); Out_Video_Reg(V_DST_Y2_HI, HIBYTE(wBottom)); } /********************************************************** Setup source video window address (source window to be overlayed) in: wX - source start x wY - source start y wPixelWidth - source window width (similar to XGA dimension 1) wMapWidth - source window map width Note: Source height is not specifically defined and it is embedded in destination window and DDA parameters (in IGS_SetScale) **********************************************************/ void IGS_SetSrcAddr(unsigned short wX, unsigned short wY, unsigned short wPixelWidth, unsigned short wMapWidth) { unsigned long dwL; unsigned char bHigh; unsigned short wFetchPitch; unsigned short wBytePitch = wMapWidth*2; /*Reduce some scanlines to avoid garbages from decoder*/ dwL = ( dwOffsetOffScreen + (wGarbageLine+wY) * wBytePitch + wX * WBPP ) >> 2; /*playback start addr*/ Out_Video_Reg( MEMORY_START_L, (unsigned char) ( dwL & 0x0000ffL ) ); Out_Video_Reg( MEMORY_START_M, (unsigned char) ( ( dwL & 0x00ff00L ) >> 8 ) ); Out_Video_Reg( MEMORY_START_H, (unsigned char) ( ( dwL & 0xff0000L ) >> 16 ) ); /*pitch is a multiple of 64 bits*/ wBytePitch = wBytePitch >> 3; wFetchPitch = ( wPixelWidth * WBPP + 7 ) >> 3; bHigh = HIBYTE( wBytePitch ); bHigh = bHigh | ( ( HIBYTE( wFetchPitch ) ) << 4 ); Out_Video_Reg( MEMORY_PITCH_L, LOBYTE( wBytePitch ) ); Out_Video_Reg( MEMORY_PITCH_H, bHigh ); Out_Video_Reg( MEMORY_OFFSET_PHASE, LOBYTE( wFetchPitch ) ); } /********************************************************** Setup source video 2 window address (source window to be overlayed) in: wX - source start x wY - source start y wPixelWidth - source window width (similar to XGA dimension 1) wMapWidth - source window map width Note: Source height is not specifically defined and it is embedded in destination window and DDA parameters (in IGS_SetScale) **********************************************************/ void IGS_SetSrcAddr_V2(unsigned short wX, unsigned short wY, unsigned short wPixelWidth, unsigned short wMapWidth) { unsigned long dwL; unsigned char bHigh; unsigned short wFetchPitch; unsigned short wBytePitch = wMapWidth*2; /*get to 2nd video offset*/ dwL = (dwOffsetOffScreen_V2 + wY * wBytePitch + wX * WBPP) >> 2; /*playback start addr*/ Out_Video_Reg(CAPTURE_BANK_CTL, 0x00); Out_Video_Reg(V_SRC_START_LO, (unsigned char)(dwL & 0x0000ffL)); Out_Video_Reg(V_SRC_START_MI, (unsigned char)((dwL & 0x00ff00L) >> 8)); Out_Video_Reg(V_SRC_START_HI, (unsigned char)((dwL & 0xff0000L) >> 16)); /*pitch is a multiple of 64 bits*/ wBytePitch = wBytePitch >> 3; /*64 bit address field*/ wFetchPitch = (wPixelWidth * WBPP + 7) >> 3; bHigh = HIBYTE(wBytePitch); bHigh = bHigh | ((HIBYTE(wFetchPitch)) << 4); Out_Video_Reg(V_SRC_STRIDE_LO, LOBYTE(wBytePitch)); Out_Video_Reg(V_SRC_STRIDE_HI, bHigh); Out_Video_Reg(V_SRC_FETCH_LO, LOBYTE(wFetchPitch)); } /********************************************************** Set Picture in Picture window in: x0, y0, x1, y1 are (x,y) position relative to captured data area (not screen coordination). iCaptureW, iCaptureH are capture width and height. E.g. if capture size is 352x240, then (x0,y0) and (x1,y1) are relative to the area (0,0) and (351,239). iCaptureW, iCaptureH are 352 and 240. **********************************************************/ void IGS_SetPIPWindow(int x0, int y0, int x1, int y1, int iCaptureW, int iCaptureH) { unsigned long wX0,wX1; unsigned long wY0,wY1; unsigned short wReg6061; unsigned short wReg6465; wReg6061 = ReadReg(IGSEXTINDEX, CAPTURE_H_START_H); wReg6061 = (wReg6061 << 8) + ReadReg(IGSEXTINDEX, CAPTURE_H_START_L); wReg6465 = ReadReg(IGSEXTINDEX, CAPTURE_V_START_H); wReg6465 = (wReg6465 << 8) + ReadReg(IGSEXTINDEX, CAPTURE_H_START_L); wX0 = (unsigned long) 2*x0; wX0 = (unsigned long) wX0 * wMAX_SIZE_X_NTSC/iCaptureW; wX0 += wReg6061; /*add capture clip information*/ wX1 = (unsigned long) 2*x1; wX1 = (unsigned long) wX1 * wMAX_SIZE_X_NTSC/iCaptureW; wX1 += wReg6061; /*add capture clip information*/ wY0 = (unsigned long) y0 * wMAX_SIZE_Y_NTSC/iCaptureH; wY0 += wReg6465; /*add capture clip information*/ wY1 = (unsigned long) y1 * wMAX_SIZE_Y_NTSC/iCaptureH; wY1 += wReg6465; /*add capture clip information*/ Out_Video_Reg(CAP_PIP_HSTART_L, (unsigned char) wX0); Out_Video_Reg(CAP_PIP_HSTART_H, (unsigned char)(wX0 >> 8)); Out_Video_Reg(CAP_PIP_HEND_L, (unsigned char) wX1); Out_Video_Reg(CAP_PIP_HEND_H, (unsigned char)(wX1 >> 8)); Out_Video_Reg(CAP_PIP_VSTART_L, (unsigned char) wY0); Out_Video_Reg(CAP_PIP_VSTART_H, (unsigned char)(wY0 >> 8)); Out_Video_Reg(CAP_PIP_VEND_L, (unsigned char) wY1); Out_Video_Reg(CAP_PIP_VEND_H, (unsigned char)(wY1 >> 8)); } /********************************************************** Enable/Disable Picture in Picture in: ON - enable PiP OFF - disable PiP **********************************************************/ void IGS_EnablePIP(int OnOff) { if (OnOff == ON) Out_Video_Reg_M(CAPTURE_NEW_CTL_I, 0x80, 0x7F); //enable PIP else Out_Video_Reg_M(CAPTURE_NEW_CTL_I, 0x00, 0x7F); //disable PIP } /********************************************************** Detect which decoder is hooked up in: None return PHILIPS7110 - Philips 7110 Decoder PHILIPS7111 - Philips 7111 Decoder NODECODER - No decoder detected. *********************************************************/ int DetectDecoder(void) { int wCameraID = NODECODER; #if 0 if ( sendOneByte(0x9C, 21, Phil7110_00[21]) == TRUE ) { wCameraID = PHILIPS7110; WhichCamera = wCameraID; wFixCapWid320 = 320*2; /*as a indicator: Width < 320 or not*/ wMAX_SIZE_X_NTSC = 640; wMAX_SIZE_Y_NTSC = 240; return wCameraID; } #endif outb_p(0xb6, IGSEXTINDEX); if (sendOneByte(P7111Port, 0x02, 0xD8) == TRUE) { printk("7111 Detected\n"); wCameraID = PHILIPS7111; WhichCamera = wCameraID; wFixCapWid320 = 352*2; /*as a indicator: Width < 352 or not*/ wMAX_SIZE_X_NTSC = 704; wMAX_SIZE_Y_NTSC = 240; return wCameraID; } else printk("7111 NOT Detected\n"); return wCameraID; } /** * InteGraphics Systems code: * Communication routines to talk to the Philips SAA7111 via the CyberPro2000 * registers 3ce (index:b6) and 3cf (data). * Communication between CyberPro2000 and SAA7111 is accomplished by using the * I2C interface. * IMPORTANT: I2C line is LO. * [Slave addresses change according to the status of the I2C line (HI/LO)] * * TODO: * Change the delay() function to udelay(). * Check if udelay can be used in kernel code. */ /*========================================================= This routine is used internally in: bVal out: return ture if successful =========================================================*/ int writeI2C(unsigned char bVal) { int i; unsigned char bBit = 0x80; /* Start from high bit -- Bit 7. Write each bit.*/ int bReturn = TRUE; for (i=0; i<8; i++) { if ( bVal & bBit ) { outb_p(0xb6, IGSEXTINDEX); outb_p(0x40, IGSEXTDATA); udelay(TIME1); outb_p(0x50, IGSEXTDATA); udelay(TIME1); if (AcknowledgeClk()!=0) bReturn = FALSE; outb_p(0x40, IGSEXTDATA); udelay(TIME1); } else { outb_p(0xb6, IGSEXTINDEX); outb_p(0x00, IGSEXTDATA); udelay(TIME1); outb_p(0x10, IGSEXTDATA); udelay(TIME1); if (AcknowledgeClk()!=0) bReturn = FALSE; outb_p(0x00, IGSEXTDATA); udelay(TIME1); } bBit = bBit >> 1; } return bReturn; } /*========================================================= This routine is used internally in: none return 0 if successful -1 if error =========================================================*/ int Acknowledge(void) { unsigned long i=0L; outb_p(0xb6, IGSEXTINDEX); outb_p(0x40, IGSEXTDATA); udelay(TIME1); outb_p(0x50, IGSEXTDATA); udelay(TIME1); while ( (inb_p(IGSEXTDATA) & 0x80) && (i++> 8); yuv = *lpnYUVBuf; /*Y1 U1*/ lpnYUVBuf++; y1 = (unsigned char) yuv; vv = (unsigned char) (yuv >> 8); #if 0 /* 1st RGB pixel */ *lpbRGBBuf++ = (unsigned char) min(CVHI, max(CVLO,(XlatY[y0] + XlatU_B[uu]))); *lpbRGBBuf++ = (unsigned char) min(CVHI, max(CVLO,(XlatY[y0] - XlatU_G[uu] - XlatV_G[vv]))); *lpbRGBBuf++ = (unsigned char) min(CVHI, max(CVLO,(XlatY[y0] + XlatV_R[vv]))); #endif /* 1st RGB pixel */ data = min(CVHI, max(CVLO,(XlatY[y0] + XlatU_B[uu]))); put_user(data, lpbRGBBuf); lpbRGBBuf++; /* Blue */ data = min(CVHI, max(CVLO,(XlatY[y0] - XlatU_G[uu] - XlatV_G[vv]))); put_user(data, lpbRGBBuf); lpbRGBBuf++; /* Green */ data = min(CVHI, max(CVLO,(XlatY[y0] + XlatV_R[vv]))); put_user(data, lpbRGBBuf); lpbRGBBuf++; /* Red */ #if 0 /* 2nd RGB pixel */ *lpbRGBBuf++ = (unsigned char) min(CVHI, max(CVLO,(XlatY[y1] + XlatU_B[uu]))); *lpbRGBBuf++ = (unsigned char) min(CVHI, max(CVLO,(XlatY[y1] - XlatU_G[uu] - XlatV_G[vv]))); *lpbRGBBuf++ = (unsigned char) min(CVHI, max(CVLO,(XlatY[y1] + XlatV_R[vv]))); #endif /* 2nd RGB pixel */ data = min(CVHI, max(CVLO,(XlatY[y1] + XlatU_B[uu]))); put_user(data, lpbRGBBuf); lpbRGBBuf++; /* Blue */ data = min(CVHI, max(CVLO,(XlatY[y1] - XlatU_G[uu] - XlatV_G[vv]))); put_user(data, lpbRGBBuf); lpbRGBBuf++; /* Green */ data = min(CVHI, max(CVLO,(XlatY[y1] + XlatV_R[vv]))); put_user(data, lpbRGBBuf); lpbRGBBuf++; /* Red */ } } /********************************************************** Color conversion from YUV to RGB24 It also dynamically flips the image in: fpDst - far Ptr to Destination buffer (RGB buffer) fpSrc - far Ptr to Source buffer (YUV buffer) wWidth - Width of the rectangle (pixel based) wHeight - Height of the rectangle **********************************************************/ void ConvertYUVtoRGB24(char* fpDst, char* fpSrc, unsigned short wWidth, unsigned short wHeight) { int row; unsigned char* fpTmp; for (row = 0; row < (int) wHeight; row++) { fpTmp = (unsigned char*) fpSrc + ((long) wWidth * 2 * row); YUV422To24RGB( /** * uncomment to flip the image * (unsigned char*)fpDst + ((long)wWidth*3 * (wHeight - (row + 1))), */ (unsigned char*)fpDst + ((long)wWidth * 3 * row), /* 3 bytes/pixel! */ fpTmp, wWidth*2); } } /** * int setup_vidcap() * Initializes Philips SAA7111 and IGS CyberPro2000 registers * required for video capture. * Actual values for displaying the captured video are set * in vidcap_ioctl * * Returns: -ENXIO if Philips SAA7111 can't be detected or * if current video mode does not support Video Capture. */ int setup_vidcap() { x_ext = GetCurrentScreenSize(X_SCREEN)-1; /* need 0 based value */ y_ext = GetCurrentScreenSize(Y_SCREEN)-1; EnableCop(); /* for 2D engine only */ igs_pixel_size = (GetBpp()>>3) - 1; //fits graphics engine register /* 0: 8bpp; 1:16bpp; 2:24bpp */ Set_IGS_Px_Map(x_ext,igs_pixel_size); /* Initialize video parameters */ if (IGS_InitParam() != 0) { printk("vidcap.c: Error, the current mode does not support capture!\n"); return -ENXIO; /* error */ } IGS_InitVideo(); dwPtr1 = (unsigned long)(x_ext+1) * (y_ext+1) * GetBpp()/8; dwPtr2 = (unsigned long)(x_ext+1) * (wCaptureH*2); return 0; } void enable7111(int state) { //we want to write a bit pattern 0X10 to CPLD, where X - 7111 state //1 = disabled, 0 = enabled // if (board_id > 0x500) set_CPLD(state<<2, 0x04); } /** * Device Driver exported functions. */ static int open_vidcap(struct inode* inodep, struct file* filep) { MOD_INC_USE_COUNT; enable7111(0); //enable 7111 printk("Old vidcap driver for Rev.5: Turning Phillips 7111 codec ON.\n"); if (DetectDecoder() == PHILIPS7111) { InitPhil7111(); } return setup_vidcap(); } static void release_vidcap(struct inode* inodep, struct file* filep) { enable7111(1); printk("Old vidcap driver for Rev.5: Turning Phillips 7111 codec OFF.\n"); MOD_DEC_USE_COUNT; } static int vidcap_ioctl(struct inode* inodep, struct file* filep, unsigned int cmd, unsigned long arg) { int xpos = 0, ypos = 0; switch (cmd) { #if 0 Test code! case CMD_DUMP: { /** * Dump YUV data to 2nd Overlay Data area. * This ioctl was created to test the speed of the YUV data transfer rate * for a prospective Video Conferencing software. * The rate of transfer for a single application for a frame of * X Y * 352*2 * 240 is 170 to 210 frames per 10 sec. */ struct YUV2RGB_param test; memcpy_fromfs(&test, (void*)arg, sizeof(test)); while(!(inb_p(0x3da) & 0x08)); memcpy_fromfs(glpOverlay2Data, test.lpYUVBuf, 352*2*240); } break; #endif case CMD_CAPTURE: { /** * Start Video Capture: i.e. first overlay */ struct vidcap_rect rect; memcpy_fromfs(&rect, (void*)arg, sizeof(rect)); dwSetOffScreenPtr(dwPtr1); // wCaptureW = 704/2; wCaptureW = 640/2; wCaptureH = 480/2; /* 1st video window */ IGS_SetCaptureFormat(YUV422); IGS_SetSrcWindowSize(wCaptureW, wCaptureH); IGS_SetOverlayFormat(COLORKEY); IGS_SetCaptureAddr(); IGS_SetScale(wCaptureW, wCaptureW, wCaptureH, wCaptureH); IGS_AdjustVideoWindow(xpos, ypos, wCaptureW, wCaptureH); IGS_SetRGBKeyColor(0x00000000); /*set color key registers*/ PaintWindow(0, 0, wCaptureW, wCaptureH, 0x00); /*fill color key color 0x00*/ IGS_VideoOn(); gbCaptured = 1; } break; case CMD_CAPTURE2: { int iterations = 1; /* 2nd video window */ dwSetOffScreenPtr_V2(dwPtr1 + dwPtr2); IGS_SetSrcWindowSize_V2(wCaptureW, wCaptureH); IGS_SetOverlayFormat_V2(WINDOWKEY); /* Scale the 2nd overlay. * Destination width and height state the final dimensions of the * overlay. */ // orig -IGS_SetScale_V2(wCaptureW, wCaptureW*3/2, wCaptureH, wCaptureH*3/2); IGS_SetScale_V2(wCaptureW, wCaptureW, wCaptureH, wCaptureH); xx=wCaptureW; yy=wCaptureH+2; /* Scale the video window. Destination width and height state the * dimensions of the overlay. */ // orig -IGS_AdjustVideoWindow_V2(xx, yy, wCaptureW*3/2, wCaptureH*3/2); IGS_AdjustVideoWindow_V2(xx, yy, wCaptureW, wCaptureH); Set_IGS_Px_Map(x_ext,igs_pixel_size); IGS_OverlayOn_V2(); /* Following peice of code is carried forward from IGS Demo application. * YUV data (frames) is copied to off-screen memory specified by * dwSetOffScreenPtr_V2(). * These frames can be pumped from the network using Video DMA. */ #if 1 while (iterations--) /*if key pressed, then break*/ { IGS_FreezeVideo(); Set_IGS_Px_Map(x_ext,igs_pixel_size); SrcCopy(0, (y_ext+1), 0, (y_ext+1+wCaptureH*2), x_ext+1, wCaptureH*2); IGS_UnfreezeVideo(); udelay(100); /*in milliseconds*/ } #endif gbCaptured2 = 1; } break; case CMD_START_PIP: /*--------------------------------------------------------------------- Demo 4. Picture in Picture (PiP) It shows that: . Capture a 352x240 and overlay it by using COLOR-KEY. . Program PiP capture H/W. . Copy a YUV422 data and fit the data into PiP area. Note: ---------------------------------------------------------------------*/ /*Program PiP*/ x0=100; y0=100; x1=200; y1=175; IGS_SetPIPWindow(x0, y0, x1, y1, wCaptureW, wCaptureH); IGS_EnablePIP(ON); Set_IGS_Px_Map(wCaptureW*2-1,igs_pixel_size); /*move some captured YUV422 data to PiP area*/ { /* Please define ITERATIONS=50 in your shell environment */ int iterations = ITERATIONS; while(iterations--) { SrcCopy_0(0, 0, x0*2, (y0+NTSC_GarbageLine), (x1-x0)*2, (y1-y0)); } } /** * YUV data other than captured data can be dumped at the PIP data * offset. This can be video conferencing data in the particular * dimensions set for PIP using Video DMA. **/ break; case CMD_END_PIP: IGS_EnablePIP(OFF); break; case CMD_RELEASE: { release_video(); } break; case CMD_RELEASE2: { if (gbCaptured2) { IGS_OverlayOff_V2(); IGS_VideoCleanUp_V2(); IGS_VideoOff(); IGS_VideoCleanUp(); } } break; case CMD_MOVETO: { /* ioctl to move first overlay (CMD_CAPTURE) to a different location * on the screen. This can be used to imitate a window move operation * under X. */ struct vidcap_rect rect; memcpy_fromfs(&rect, (void*)arg, sizeof(rect)); IGS_VideoOff(); IGS_AdjustVideoWindow(rect.x, rect.y, wCaptureW, wCaptureH); IGS_VideoOn(); } break; case CMD_FREEZE: { IGS_FreezeVideo(); } break; case CMD_UNFREEZE: { IGS_UnfreezeVideo(); } break; case CMD_HIDE: { while(!(inb_p(0x3da) & 0x08)); Out_Video_Reg_M(DISP_CTL_I, 0x00, 0x7f); } break; case CMD_SHOW: { while(!(inb_p(0x3da) & 0x08)); Out_Video_Reg_M(DISP_CTL_I, 0x80, 0x7f); } break; #if 0 Test code! /** * This code can be used to copy captured frames to user allocated * memory. Also, the YUV to RGB conversion routines can be used to * convert YUV frames to RGB frames. The conversion routines can be * stripped out of this driver code and used in user application. */ case CMD_YUV2RGB_TEST: { struct YUV2RGB_param test; memcpy_fromfs(&test, (void*)arg, sizeof(test)); #if 0 Following are redundant verifications. They both mean the same. Take care for the size of the buffer. if (verify_area(VERIFY_WRITE, test.lpRGBBuf, test.rgb_buf_size) == -EFAULT) { printk("test.rgb_buf_size(%d) caused -EFAULT on verify_area.\n", test.rgb_buf_size); return -EFAULT; } if (verify_area(VERIFY_WRITE, test.lpRGBBuf, test.width*test.height*3) == -EFAULT) { printk("test.width*test.height*3(%d) caused -EFAULT on verify_area.\n", test.width*test.height*3); return -EFAULT; } #endif //IGS_FreezeVideo(); //while(!(inb_p(0x3da) & 0x08)); //memcpy(glpYUVBuf, glpOverlay1Data, 352*2*240); //IGS_UnfreezeVideo(); #if 0 ConvertYUVtoRGB24(test.lpRGBBuf, //(unsigned char*)(long)(0xd0000000L + (640*480*3)), glpYUVBuf, test.width, test.height); #else memcpy_tofs(test.lpYUVBuf, glpOverlay1Data, 352*2*240); //IGS_UnfreezeVideo(); #endif } break; #endif } return 0; } void release_video() { if (!gbCaptured) return; gbCaptured = 0; IGS_VideoOff(); IGS_VideoCleanUp(); } #ifndef MODULE long vidcap_init(long mem_start, long mem_emd) { if (vidcap_major = register_chrdev(0, vidcap_name, &vidcap_fops)) printk("vidcap_init: Unable to get major for Video Capture Device\n"); else printk("vidcap_init: vidcap_major = %d\n", vidcap_major); return mem_start; } #else int init_module(void) { if ((vidcap_major = register_chrdev(103, vidcap_name, &vidcap_fops)) == -EBUSY) { printk("vidcap_init: Unable to get major for Video Capture Device\n"); return -EIO; } else { printk("vidcap_init: vidcap_major = 103 (%d)\n", vidcap_major); } return 0; } void cleanup_module(void) { release_video(); unregister_chrdev(vidcap_major, vidcap_name); } #endif