From: <sen...@us...> - 2009-03-31 22:41:45
|
Revision: 374 http://open2x.svn.sourceforge.net/open2x/?rev=374&view=rev Author: senquack Date: 2009-03-31 22:41:43 +0000 (Tue, 31 Mar 2009) Log Message: ----------- TV Tweaking Daemon Added Paths: ----------- trunk/utils/tv_daemon/ trunk/utils/tv_daemon/Makefile trunk/utils/tv_daemon/mmsp2_regs.h trunk/utils/tv_daemon/tv_daemon.c Added: trunk/utils/tv_daemon/Makefile =================================================================== --- trunk/utils/tv_daemon/Makefile (rev 0) +++ trunk/utils/tv_daemon/Makefile 2009-03-31 22:41:43 UTC (rev 374) @@ -0,0 +1,42 @@ +#CFLAGS=-c -O2 -g -Wall -DPLATFORM_GP2X -mcpu=arm920t -mtune=arm920 -ffast-math -W -Wall -pthread -msoft-float +CFLAGS=-c -O3 -Wall -DPLATFORM_GP2X -mcpu=arm920t -mtune=arm920 -ffast-math -W -Wall -pthread -msoft-float +#CFLAGS=-DDEBUG -c -O5 -Wall -DPLATFORM_GP2X -mcpu=arm920t -mtune=arm920 -ffast-math -W -Wall -pthread -msoft-float + +#LDFLAGS=-L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -Wl,-rpath,/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -static -lgcc -lm -lc -ldl -larmmem -msoft-float -O2 +LDFLAGS=-L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -Wl,-rpath,/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -lgcc -lm -lc -ldl -msoft-float -O2 + +SOURCES=tv_daemon.c + + +OBJECTS=$(SOURCES:.c=.o) +EXECUTABLEGP=tv_daemon + +CC=arm-open2x-linux-gcc +STRIP=arm-open2x-linux-strip +CFLAGS+=-I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include/ \ + -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/include/ \ + -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include/SDL -D_REENTRANT \ + -msoft-float -DPLATFORM_GP2X + +all: + make gpversion + +gpversion: $(SOURCES) $(EXECUTABLEGP) + + +$(EXECUTABLEGP): $(OBJECTS) +# $(CC) $(LDFLAGS) -static $(OBJECTS) -o $@ $(GPLDFLAGS) + $(CC) $(LDFLAGS) $(OBJECTS) -o $@ $(GPLDFLAGS) + $(STRIP) $@ + + + +.c.o: + $(CC) $(CFLAGS) $< -o $@ + +cleanobjs: + rm -f $(OBJECTS) + +clean: + -rm -f tv_daemon *~ *.o *.bak + Added: trunk/utils/tv_daemon/mmsp2_regs.h =================================================================== --- trunk/utils/tv_daemon/mmsp2_regs.h (rev 0) +++ trunk/utils/tv_daemon/mmsp2_regs.h 2009-03-31 22:41:43 UTC (rev 374) @@ -0,0 +1,205 @@ +/* + * MMSP2 (MP2520F) Registers + * Only listed needed regs for HW blit stuff + * + * 2005-12-20 Paeryn + */ + + +#ifndef _MMSP2_REG_H_ +#define _MMSP2_REG_H_ + +/* + * Blitter registers + */ + +#define MESGDSTCTRL (0x0000>>2) +#define MESG_DSTENB (1<<6) +#define MESG_BSTBPP 0x60 +#define MESG_DSTBPP_8 (0<<5) +#define MESG_DSTBPP_16 (1<<5) + +#define MESGDSTADDR (0x0004>>2) +#define MESGDSTSTRIDE (0x0008>>2) +#define MESGSRCCTRL (0x000C>>2) +#define MESG_INVIDEO (1<<8) +#define MESG_SRCENB (1<<7) +#define MESG_SRCBPP 0x60 +#define MESG_SRCBPP_8 (0<<5) +#define MESG_SRCBPP_16 (1<<5) +#define MESG_SRCBPP_1 (1<<6) + +#define MESGSRCADDR (0x0010>>2) +#define MESGSRCSTRIDE (0x0014>>2) +#define MESGSRCFORCOLOR (0x0018>>2) +#define MESGSRCBACKCOLOR (0x001C>>2) +#define MESGPATCTRL (0x0020>>2) +#define MESG_PATMONO (1<<6) +#define MESG_PATENB (1<<5) +#define MESG_PATBPP 0x18 +#define MESG_PATBPP_8 (0<<3) +#define MESG_PATBPP_16 (1<<3) +#define MESG_PATBPP_1 (1<<4) +#define MESG_YOFFSET 0x07 + +#define MESGFORCOLOR (0x0024>>2) +#define MESGBACKCOLOR (0x0028>>2) +#define MESGSIZE (0x002C>>2) +#define MESG_HEIGHT 16 +#define MESG_WIDTH 0 + +#define MESGCTRL (0x0030>>2) +#define MESG_TRANSPCOLOR 16 +#define MESG_TRANSPEN (1<<11) +#define MESG_FFCLR (1<<10) +#define MESG_YDIR (1<< 9) +#define MESG_YDIR_NEG (0<< 9) +#define MESG_YDIR_POS (1<< 9) +#define MESG_XDIR (1<< 8) +#define MESG_XDIR_NEG (0<< 8) +#define MESG_XDIR_POS (1<< 8) +#define MESG_ROP 0xFF + +#define MESGSTATUS (0x0034>>2) +#define MESG_BUSY (1<<0) + +#define MESGFIFOSTATUS (0x0038>>2) +#define MESG_FULL (1<<31) +#define MESG_REMAIN 0x1f + +#define MESGFIFO (0x003C>>2) +#define MESGPAT (0x0080>>2) + +/* + * Basic ROPs + */ +#define MESG_ROP_NULL 0xAA +#define MESG_ROP_COPY 0xCC +#define MESG_ROP_PAT 0xF0 + + +/* + * Control registers + */ +#define SYSCLKENREG (0x0904>>1) +#define FASTIOCLK (1<<10) + +#define VCLKENREG (0x090A>>1) +#define GRPCLK (1<<2) + +#define SC_STATUS (0x1802>>1) +#define SC_DISP_FIELD (1<<7) + +#define GPIOB_PINLVL (0x1182>>1) +#define GPIOB_VSYNC (1<<4) + +#define DPC_CNTL (0x2800>>1) +#define DPC_INTERLACE (1<<5) +#define DPC_X_MAX (0x2816>>1) +#define DPC_Y_MAX (0x2818>>1) +#define DPC_V_SYNC (0x2920>>1) +#define DPC_VSFLDPOL (1<<6) +#define DPC_VSFLDEN (1<<7) +#define DPC_CLKCNTL (0x2848>>1) + +#define MLC_OVLAY_CNTR (0x2880>>1) +#define DISP_BOTH_PATH (1<<15) +#define DISP_OVLY2SCALE (1<<14) +#define DISP_FLD_POL (1<<13) +#define DISP_GAMM_BYPATH (1<<12) +#define DISP_SWAP (1<<11) +#define DISP_CURSOR (1<< 9) +#define DISP_SUBPICTURE (1<< 8) +#define DISP_OSD (1<< 7) +#define DISP_STL5EN (1<< 6) +#define DISP_STL4EN (1<< 5) +#define DISP_STL3EN (1<< 4) +#define DISP_STL2EN (1<< 3) +#define DISP_STL1EN (1<< 2) +#define DISP_VLBON (1<< 1) +#define DISP_VLAON (1<< 0) + +//senquack - new registers undefined before: +#define MLC_YUV_CNTL (0x2884>>1) +#define MLC_YUVA_TP_HSC (0x2886>>1) // bits 15:12 must be 0 +#define MLC_YUVA_BT_HSC (0x2888>>1) // bits 15:12 must be 0 +#define MLC_VLA_ENDX (0x2898>>1) +#define MLC_VLA_TP_VSCL (0x288A>>1) +#define MLC_VLA_TP_VSCH (0x288C>>1) // bits 15:9 of this are reserved +#define MLC_YUVA_TP_PXW (0x2892>>1) +#define MLC_YUVA_BT_PXW (0x2894>>1) + + +#define MLC_STL_CNTL (0x28DA>>1) +#define MLC_STL_BPP 9 +#define MLC_STL_BPP_4 0x00AA +#define MLC_STL_BPP_8 0x02AA +#define MLC_STL_BPP_16 0x04AA +#define MLC_STL_BPP_24 0x06AA +#define MLC_STL5ACT (1<<8) +#define MLC_STL4ACT (1<<6) +#define MLC_STL3ACT (1<<6) +#define MLC_STL2ACT (1<<4) +#define MLC_STL1ACT (1<<0) +#define MLC_STL_DEFAULT 0xAA + +#define MLC_STL_MIXMUX (0x28DC>>1) +#define MLC_STL5_MIXMUX 8 +#define MLC_STL4_MIXMUX 6 +#define MLC_STL3_MIXMUX 4 +#define MLC_STL2_MIXMUX 2 +#define MLC_STL1_MIXMUX 0 + +#define MLC_STL_ALPHAL (0x28DE>>1) +#define MLC_STL3_ALPHA 8 +#define MLC_STL2_ALPHA 4 +#define MLC_STL1_ALPHA 0 + +#define MLC_STL_ALPHAH (0x28E0>>1) +#define MLC_STL5_ALPHA 4; +#define MLC_STL4_ALPHA 0; + +#define MLC_STL1_STX (0x28E2>>1) +#define MLC_STL1_ENDX (0x28E4>>1) +#define MLC_STL1_STY (0x28E6>>1) +#define MLC_STL1_ENDY (0x28E8>>1) +#define MLC_STL2_STX (0x28EA>>1) +#define MLC_STL2_ENDX (0x28EC>>1) +#define MLC_STL2_STY (0x28EE>>1) +#define MLC_STL2_ENDY (0x28F0>>1) +#define MLC_STL3_STX (0x28F2>>1) +#define MLC_STL3_ENDX (0x28F4>>1) +#define MLC_STL3_STY (0x28F6>>1) +#define MLC_STL3_ENDY (0x28F8>>1) +#define MLC_STL4_STX (0x28FA>>1) +#define MLC_STL4_ENDX (0x28FC>>1) +#define MLC_STL4_STY (0x28FE>>1) +#define MLC_STL4_ENDY (0x2900>>1) +#define MLC_STL_CKEY_GB (0x2902>>1) +#define MLC_STL_CKEYG 8 +#define MLC_STL_CKEYB 0 +#define MLC_STL_CKEY_R (0x2904>>1) +#define MLC_STL_HSC (0x2906>>1) +#define MLC_STL_VSCL (0x2908>>1) +#define MLC_STL_VSCH (0x290A>>1) +#define MLC_STL_HW (0x290C>>1) +#define MLC_STL_OADRL (0x290E>>1) +#define MLC_STL_OADRH (0x2910>>1) +#define MLC_STL_EADRL (0x2912>>1) +#define MLC_STL_EADRH (0x2914>>1) +#define MLC_STL_PALLT_A (0x2958>>1) +#define MLC_STL_PALLT_D (0x295A>>1) + +#define MLC_HWC_CNTL (0x291E>>1) +#define MLC_HWC_STX (0x2920>>1) +#define MLC_HWC_STY (0x2922>>1) +#define MLC_HWC_FGR (0x2924>>1) +#define MLC_HWC_FB (0x2926>>1) +#define MLC_HWC_BGR (0x2928>>1) +#define MLC_HWC_BB (0x292A>>1) +#define MLC_HWC_OADRL (0x292C>>1) +#define MLC_HWC_OADRH (0x292E>>1) +#define MLC_HWC_EADRL (0x2930>>1) +#define MLC_HWC_EADRH (0x2932>>1) + +#endif Added: trunk/utils/tv_daemon/tv_daemon.c =================================================================== --- trunk/utils/tv_daemon/tv_daemon.c (rev 0) +++ trunk/utils/tv_daemon/tv_daemon.c 2009-03-31 22:41:43 UTC (rev 374) @@ -0,0 +1,831 @@ +/* tv_daemon.c TV tweaking daemon for Open2X. + Copyright (C) 2008 Dan Silsby (Senor Quack) + Portions of code based on : + + parts (c) Rlyehs Work (minlib) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <linux/fb.h> +#include <unistd.h> +#include <stropts.h> +#include <errno.h> +#include <time.h> +#include <signal.h> +#include "mmsp2_regs.h" + +#define MIN_PITCH 1 +#define MAX_PITCH 2048 +//#define MIN_XOFFSET (-50) +//#define MAX_XOFFSET 35 +//#define MIN_YOFFSET (-15) +//#define MAX_YOFFSET 45 +#define MIN_XOFFSET (-50) +#define MAX_XOFFSET 35 +#define MIN_YOFFSET (-21) // Any less than this, my NTSC TV displays black +#define MAX_YOFFSET 85 // Can probably go further than this but, damn, do we need to? +#define MIN_XSCALE 12 +#define MAX_XSCALE 200 +#define MIN_YSCALE 12 +#define MAX_YSCALE 200 +#define MIN_VXSCALE 12 +#define MAX_VXSCALE 200 +#define MIN_VYSCALE 12 +#define MAX_VYSCALE 200 +#define DEFAULT_NTSC_XOFFSET 10 +#define DEFAULT_NTSC_YOFFSET (-7) +//Changed this to the NTSC default since someone showed that it was too far to the right: +//#define DEFAULT_PAL_XOFFSET 16 +#define DEFAULT_PAL_XOFFSET 10 +#define DEFAULT_PAL_YOFFSET 19 +#define MIN_DELAY 1 +#define MAX_DELAY 120 +#define DEFAULT_DELAY 1 +#define MIN_FIRST_DELAY 1 +#define MAX_FIRST_DELAY 120 +#define DEFAULT_FIRST_DELAY 4 + +//senquack - pulled from Rlyeh's minlib for improved TVout: +#define gp2x_cx25874_read(a) gp2x_i2c_read(0x8A,(a)) +#define gp2x_cx25874_write(a,v) gp2x_i2c_write(0x8A,(a),(v)) +typedef struct { unsigned char id,addr,data;} i2cw; +typedef struct { unsigned char id,addr,*pdata;} i2cr; + +// Found out from GPH sources that LCD is one, not zero as many seem to think: +enum { LCD = 1, PAL = 4, NTSC = 3 }; + +extern int errno; +unsigned short *gp2x_memregs; +int memfd; +int cx25874 = 0; // fd for chip device driver + +int xoffset = 999; // Magic 999 tells program if xoffset wasn't given on command line +int yoffset = 999; // "" +int xscale_percent = 100; +int yscale_percent = 100; +int vxscale_percent = 100; +int vyscale_percent = 100; +int first_delay = DEFAULT_FIRST_DELAY; // How many seconds to wait before first tweak? +int delay = DEFAULT_DELAY; // How many seconds to wait inbetween subsequent tweaks? +int mode = NTSC; +int tweak_only_once = 0; +int tweak_yuv = 0; +int enable_tvmode = 0; +//int stubborn_fix = 0; /* for apps like Tilematch and Blingo, their SDL has few bugs +// that leave registers for tvout incorrectly set, this +// will fix that if enabled. */ +int scaling_tweak = 1; /* Hit the scaling registers? For apps like mame and lemonboy2x, + if this is 1 it will cause problems. They hit the scaling + registers intentionally but without at least some other + tweaks they can't display tv properly. */ +int pal_overscan_fix = 0;/* When in PAL mode, apply Rlyeh's overscan stuff. I have a suspicion + that this is what is causing people problems with cut-off lower + portions of the picture on PAL TVs, so it is now turned off by + default. */ +int pitch = 0; + +void gp2x_video_RGB_setscaling(int W, int H); +void *trymmap (void *start, size_t length, int prot, int flags, int fd, off_t offset); +unsigned char initphys (void); +void gp2x_i2c_write(unsigned char id, unsigned char addr, unsigned char data); +void gp2x_video_RGB_setscaling(int W, int H); +void gp2x_video_YUV_setscaling(int region, int W, int H); +void tweaktvout(int pal, int init_tv, int force_phys_pitch); +void loop (void); +void closephys (void); +void displayhelp (void); + +void *trymmap (void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + char *p; + int aa; + + p = mmap (start, length, prot, flags, fd, offset); + if (p == (char *)0xFFFFFFFF) + { + aa = errno; + printf ("mmap failed. errno = %d\n", aa); + exit(1); + } + + return p; +} + +unsigned char initphys (void) +{ + memfd = open("/dev/mem", O_RDWR); + if (memfd == -1) + { + printf ("Opening /dev/mem failed\n"); + return 0; + } + + gp2x_memregs = (unsigned short *)trymmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0xc0000000); + return 1; +} + +//senquack - pulled from Rlyeh's minlib for improved TVout: +/* Function: gp2x_i2c_write + This function writes a byte into an I2C address. + + Parameters: + id (0..) - i2c ID + addr - address to write data to. + data (0..255) - data to be written. + + See also: + <gp2x_i2c_read> + + Credits: + rlyeh */ + +void gp2x_i2c_write(unsigned char id, unsigned char addr, unsigned char data) +{ + i2cw a; + a.id = id, a.addr = addr, a.data = data; + ioctl(cx25874, _IOW('v', 0x00, i2cw), &a); //CX25874_I2C_WRITE_BYTE +} + +//senquack - pulled from Rlyeh's minlib for improved TVout, extensively modified +/* Function: gp2x_video_RGB_setscaling + This function adjusts a given resolution to fit the whole display (320,240). + + Notes: + - Draw at (0,0) coordinates always, whatever resolution you are working with. + - Call this function once. Do not call this function in every frame. + + Parameters: + W (1..) - virtual width in pixels to scale to 320. + H (1..) - virtual height in pixels to scale to 240. + + Default: + - (W,H) are set to (320,240). + + Credits: + rlyeh */ + +void gp2x_video_RGB_setscaling(int W, int H) +{ + short tmp; + int bpp=(gp2x_memregs[0x28DA>>1]>>9)&0x3; + int mul = (gp2x_memregs[DPC_CNTL] & 0x100 ? 512 : 1024); + + // some video modes are 360-pixels wide so we must account for that when + // doing scaling ratio: + int div = gp2x_memregs[MLC_STL_HW] >> (bpp - 1); + if (div != 360) + { + div = 320; + } + + // scale horizontal + tmp = (unsigned short)((float)mul *((float)W / (float)div)); + // round to nearest multiple of 8 + tmp &= ~0x7; + gp2x_memregs[MLC_STL_HSC]=tmp; + + // scale vertical + tmp = (unsigned short)((float)320.0*bpp *(H/240.0)); + // round to nearest multiple of 8 + tmp &= ~0x7; + gp2x_memregs[MLC_STL_VSCL]=tmp; + gp2x_memregs[MLC_STL_VSCH] = 0; +} + +////senquack - pulled from Rlyeh's minlib for improved TVout, +// extensively modified. Alters only the top of Region A +// (for video playing) +///* Function: gp2x_video_YUV_setscaling +// This function adjusts a given resolution to fit the whole display (320,240). +// +// Notes: +// - Draw at (0,0) coordinates of each framebuffer always, whatever resolution you are working with. +// - Call this function once. Do not call this function in every frame. +// +// Parameters: +// region (0..3) - YUV region (0..3) +// W (1..) - virtual width in pixels to scale to 320. +// H (1..) - virtual height in pixels to scale to 240. +// +// Default: +// - (W,H) are set to (320,240) for each region. +// +// Credits: +// rlyeh */ +// +void gp2x_video_YUV_setscaling(int region, int W, int H) +{ + short reg; + + //senquack - set region A Top pixel skip register to 0: + gp2x_memregs[MLC_YUV_CNTL] &= ~(1<<3); + gp2x_memregs[MLC_YUV_CNTL] &= ~(1<<2); + + //VERTICAL SCALING: + reg = (float)gp2x_memregs[MLC_YUVA_TP_PXW] * ((float)H / 240.0); + gp2x_memregs[MLC_VLA_TP_VSCL] = reg; + gp2x_memregs[MLC_VLA_TP_VSCH] &= ~0x1FF; + + //HORIZONTAL SCALING: + reg = 1024.0 * ((float)W / 320.0); + reg &= 0x7FF; + gp2x_memregs[MLC_YUVA_TP_HSC] = reg; +} + +// Parameters: pal 0: NTSC 1: PAL +// init_tv 0: Don't set tv mode 1: set tv mode indicated by pal +// force_phys_pitch Override physical pitch to be this number (720 needed for +// gngeo)... disabled if 0 +// Note: I got it to automatically deal with various pitches, so no need for the last +// parameter for now +void tweaktvout(int pal, int init_tv, int force_phys_pitch) +{ + static int set_scaling = 0; // Done the initial setting of scaling yet? +// static int initial_stubborn_fix = 0; // Done the initial stubborn fix? + + unsigned int bytes_per_pixel = (gp2x_memregs[MLC_STL_CNTL]>>9)&0x3; + unsigned int width = 320; + unsigned int height = 240; + unsigned int pitch, phys_pitch; +// static int scaled_width = -1; +// static int scaled_height = -1; + int orig_w = 320; // orig_w and orig_h get set to the user-specified scaled + // percentage of 320x240 a little later before anything + // gets tweaked. Later tweaks tweak based on the auto- + // detected height and width no longer need to do + // any math, the stored values are already scaled properly. + int orig_h = 240; + + static int scaled_vwidth = -1, scaled_vheight = -1; + + if ((scaled_vwidth == -1) || (scaled_vheight == -1)) + { + // We can't do auto-detection of height and width on the YUV layers, so + // these get set once and then YUV is set to these values that never change. + scaled_vwidth = (int)(320.0 * (100.0 / (float)vxscale_percent)); + scaled_vheight = (int)(240.0 * (100.0 / (float)vyscale_percent)); + } + + + if (init_tv) + { + cx25874 = open("/dev/cx25874",O_RDWR); + if (cx25874 != -1) + { + ioctl(cx25874, _IOW('v', 0x02, unsigned char), pal ? PAL : NTSC); + close(cx25874); + } else + { + cx25874 = 0; + } + } + + // Open special Open2X device driver that doesn't reset the hardware on opening + cx25874 = open("/dev/cx25874_open2x",O_RDWR); + if (cx25874 == -1) + { + cx25874 = 0; +#if DEBUG + printf("Error opening /dev/cx25874_open2x, some tweaks won't be applied.\n"); +#endif + return; + } + + if (!(gp2x_memregs[DPC_CNTL]&0x100)) + { +#if DEBUG + printf("Cannot tweak, TV output not enabled! Exiting..\n"); +#endif + if (cx25874) + close (cx25874); + cx25874 = 0; +// closephys(); +// exit(1); + return; + } + + // Do one-time setting of scaling registers before anything. + if (scaling_tweak && !set_scaling) +// if (!set_scaling) + { + gp2x_memregs[DPC_Y_MAX] = 239; + orig_w = (long)(320.0 * (100.0 / (float)xscale_percent)); + orig_h = (long)(240.0 * (100.0 / (float)yscale_percent)); + + gp2x_video_RGB_setscaling( orig_w, orig_h ); + + + set_scaling = 1; + } + +// if (tweak_yuv) +// { +// gp2x_video_YUV_setscaling(0, scaled_vwidth, scaled_vheight ); +// } + +// // This fixes apps that used a buggy SDL like some of Ruckage's fenix games +// // and Tilematch. When using TVout, they have horrible interlacing otherwise. +// if (stubborn_fix && !initial_stubborn_fix && cx25874) +// { +//// gp2x_memregs[MLC_STL_HW] = 640; +// gp2x_memregs[MLC_STL_HW] = (bytes_per_pixel == 1) ? 320 : 640; +//// gp2x_memregs[MLC_STL1_ENDX] = 639; +//// gp2x_memregs[MLC_STL1_ENDX] = (bytes_per_pixel == 1) ? 319 : 639; +// gp2x_memregs[MLC_STL1_ENDX] = 719; +// gp2x_memregs[DPC_X_MAX] = 719; +// gp2x_memregs[MLC_STL_MIXMUX] = 0; +// gp2x_memregs[MLC_STL_ALPHAL] = 255; +// gp2x_memregs[MLC_STL_ALPHAH] = 255; +// gp2x_memregs[MLC_OVLAY_CNTR] |= DISP_STL1EN; +// // This is the critical fix for interlacing: +//// gp2x_memregs[MLC_STL_EADRL] = gp2x_memregs[MLC_STL_OADRL]; +//// gp2x_memregs[MLC_STL_EADRH] = gp2x_memregs[MLC_STL_OADRH]; +// initial_stubborn_fix = 1; +// } +// + // This is the critical fix for interlacing: + gp2x_memregs[MLC_STL_EADRL] = gp2x_memregs[MLC_STL_OADRL]; + gp2x_memregs[MLC_STL_EADRH] = gp2x_memregs[MLC_STL_OADRH]; + + +#if DEBUG + printf("Detecting hw of %d\n", gp2x_memregs[MLC_STL_HW]); + printf("Detecting endx of %d\n", gp2x_memregs[MLC_STL1_ENDX]); + printf("Detecting YUV endx of %d\n", gp2x_memregs[MLC_VLA_ENDX]); + printf("DPC_X_MAX: %d\n", gp2x_memregs[DPC_X_MAX]); + printf("DPC_Y_MAX: %d\n", gp2x_memregs[DPC_Y_MAX]); + printf("MLC_STL_HSC: %d\n", gp2x_memregs[MLC_STL_HSC]); + printf("MLC_STL_VSCL: %d\n", gp2x_memregs[MLC_STL_VSCL]); +#endif + + // Auto-detection of width + width = gp2x_memregs[MLC_STL_HW] >> (bytes_per_pixel - 1); + + // Some SDLs set the width wrong, apparently (Blingo's fenix, spout) + if (width == 640) + { + width = 320; + } + + // Massage the vertical scaling register if it gets fubar'd + if (gp2x_memregs[MLC_STL_VSCL] < 32) + { + // For some reason, it seems a lot of code out there (early minlibs) + // ends up putting this at very low values, making it impossible to + // see anyhthing. Fix this to a sane value if this occurs. +#ifdef DEBUG + printf("VSCL went out of whack, resetting scaling..\n"); +#endif +// gp2x_video_RGB_setscaling( orig_w, orig_h ); +// gp2x_video_RGB_setscaling( width, (int)(((float)width / 320.0) * 240.0) ); +// gp2x_video_RGB_setscaling( width, (int)(((float)width / 320.0) * 240.0) + 8 ); + if (gp2x_memregs[MLC_STL_HSC] == 489) + { + // using an old version of minlib and program has changed to 320x240 mode + gp2x_memregs[MLC_STL_VSCL] = (bytes_per_pixel == 1) ? 320 : 640; + } else + { + // Since the VSCL register has been wiped out, we have no way of knowing + // what the height is supposed to be. All we can do is look at the width + // and come up with a height that matches a 4:3 width:height ratio and hope + // for the best. Seems to work pretty well. + // If I don't have the +24 here, the image goes off the bottom of the screen. + // Who knows what it does with or without in PAL mode, I only have a NTSC tv. + gp2x_video_RGB_setscaling( width, (int)(((float)width / 320.0) * 240.0) + 24 ); +// gp2x_video_RGB_setscaling( width, (int)(((float)width / 320.0) * 240.0) ); + } + +#ifdef DEBUG + printf("after reset, MLC_STL_HSC: %d\n", gp2x_memregs[MLC_STL_HSC]); + printf("after reset, MLC_STL_VSCL: %d\n", gp2x_memregs[MLC_STL_VSCL]); +#endif + + } + + // Auto-detection of height (not so easy as the width) + int tmp = gp2x_memregs[MLC_STL_VSCL]; + tmp += 7; + tmp &= ~0x7; + height = (int)(((float)tmp * 240.0) / (320.0 * (float)bytes_per_pixel)); + height += 7; + height &= ~0x7; + + + +#ifdef DEBUG + printf("orig_w: %d orig_h: %d\n", orig_w, orig_h); + printf("Detecting width, height of %d,%d\n", width, height); + printf("Detecting bpp of %d\n", bytes_per_pixel); +#endif + + pitch = phys_pitch = width << (bytes_per_pixel == 1 ? 0 : 1); + + if (force_phys_pitch > 0) + { + phys_pitch=force_phys_pitch; + } + +// // Do maintenance tweak: + if (scaling_tweak) + { + gp2x_video_RGB_setscaling(width, height); + } + + if (tweak_yuv) + { + gp2x_video_YUV_setscaling(0, scaled_vwidth, scaled_vheight ); + gp2x_memregs[MLC_VLA_ENDX] = 719; + } + + // A few last tweaks for the display controller before moving to the encoder chip + gp2x_memregs[MLC_STL1_ENDX]= 719; + gp2x_memregs[MLC_STL_HW] = phys_pitch; + + // BEGIN RLYEH'S TV IMAGE CENTERING: + // -------------------------------- + int lines, syncs_start, syncs_end; + + //horizontal adjustment + if (cx25874) + { + gp2x_cx25874_write(0x8c, (unsigned char) (50 - 11 + 3 - xoffset) ); + } + + + //vertical adjustment + if(pal) + lines = 288, syncs_start = 1, syncs_end = 24; + else + lines = 240, syncs_start = 1, syncs_end = 22; + + lines -= yoffset, syncs_end += yoffset; + + gp2x_memregs[DPC_Y_MAX] = lines - 1; + gp2x_memregs[0x2820 >> 1] &= (0xFF00); + gp2x_memregs[0x2820 >> 1] |= (syncs_start << 8); + gp2x_memregs[0x2822 >> 1] &= ~(0x1FF); + gp2x_memregs[0x2822 >> 1] |= syncs_end; // syncs_end = verBackPorch+verFontPorch - 1 + +// if(pal && cx25874) + //senquack - think this might be the code causing PAL problems with bottom part of image + // cut off. No way of knowing, I don't have a PAL tv. This code is now turned off + // by default. + if(pal && pal_overscan_fix && cx25874) + { + //bottom screen image cut off (PAL 320x288 full -> PAL 320x240 centered w/ black borders) + int real_lines = 288, + wanted_lines = 240, + top_spacing = (real_lines - wanted_lines) << 1, + active_lines = wanted_lines + top_spacing; + + active_lines += -top_spacing +5 + yoffset; + + gp2x_cx25874_write(0x84, active_lines & 0xFF); //reduce overscan, VACTIVE_0 + gp2x_cx25874_write(0x86, 0x26 | ((active_lines & 0x100)>>1) ); + + gp2x_cx25874_write(0x94, active_lines & 0xFF); //reduce overscan, VACTIVE_1 + gp2x_cx25874_write(0x96, 0x31 | ((active_lines & 0x300)>>8) ); + } + + // END RLYEH'S TV IMAGE CENTERING + // -------------------------------- + + if (cx25874) + { + close(cx25874); + } +} + +void loop (void) +{ + struct timespec timereq, timerem; + timereq.tv_sec = first_delay; + timereq.tv_nsec = 0; + + // Do initial tweak (but only after waiting) + nanosleep(&timereq, &timerem); + tweaktvout((mode == PAL), enable_tvmode, pitch ); + + if (tweak_only_once) + return; + + timereq.tv_sec = delay; + timereq.tv_nsec = 0; + + while (1) + { + nanosleep(&timereq, &timerem); +#if DEBUG + printf("Tweaking TV..\n"); +#endif + tweaktvout(mode == PAL, 0, pitch); + } +} + +void closephys (void) +{ + close (memfd); +} + +void displayhelp (void) +{ + printf("Open2X TV tweaking daemon written by Senor Quack v1.0\n"); + printf(" Copyright (C) 2009 Daniel Silsby\n"); + printf(" Portions of code adapted from Rlyeh's minlib \n"); + printf("OPTIONS:\n"); + printf("-h\t\tDisplay help and version info\n"); + printf("-p\t\tUse PAL timings (default is NTSC)\n"); + printf("-P\t\tApply Rlyeh's PAL overscan tweak (untested)\n"); + printf("-e\t\tEnable TV mode initially (normally not needed)\n"); +// printf("-s\t\tEnable 'stubborn' fix for some older SDL/Fenix apps\n"); +// printf("\t\t\tlike Tilematch or Blingo (fixes flicker)\n"); + printf("-S\t\tDisable tweaking of scaling registers (for Mame,Lemonboy2x,etc)\n"); +// printf("-fPITCH\t\tForce physical pitch of PITCH. Valid range: %d..%d\n", +// MIN_PITCH, MAX_PITCH); +// printf("\t\t\t(Normally 320 for 1bpp mode, 640 for 2bpp mode, but some\n" +// "\t\t\t programs like gngeo need a setting of 720 forced here.)\n"); + printf("-xOFFSET\tMove image right/left. Valid range: %d..%d\n", + MIN_XOFFSET, MAX_XOFFSET); + printf("\t\t\t(if not specified, default is %d for NTSC, %d for PAL)\n", + DEFAULT_NTSC_XOFFSET, DEFAULT_PAL_XOFFSET); + printf("-yOFFSET\tMove image up/down. Valid range: %d..%d\n", + MIN_YOFFSET, MAX_YOFFSET); + printf("\t\t\t(if not specified, default is %d for NTSC, %d for PAL)\n", + DEFAULT_NTSC_YOFFSET, DEFAULT_PAL_YOFFSET); + printf("-XSCALE\t\tScale image horizontally SCALE%%. Valid range: %d..%d\n", + MIN_XSCALE, MAX_XSCALE); + printf("\t\t\t(if not specified, default is 100)\n"); + printf("-YSCALE\t\tScale image vertically SCALE%%. Valid range: %d..%d\n", + MIN_YSCALE, MAX_YSCALE); + printf("-vxSCALE\tScale YUV video image horizontally SCALE%%. Valid range: %d..%d\n", + MIN_XSCALE, MAX_XSCALE); + printf("\t\t\t(if not specified, default is 100)\n"); + printf("-vySCALE\tScale YUV video image vertically SCALE%%. Valid range: %d..%d\n", + MIN_YSCALE, MAX_YSCALE); + printf("\t\t\t(if not specified, default is 100)\n"); + printf("-V\t\tTweak YUV video layer as well as RBG layer.\n"); + printf("-dSECS\t\tSleep this many seconds inbetween tweaks.\n"); + printf("\t\t\tValid range: %d..%d Default is %d seconds\n", + MIN_DELAY, MAX_DELAY, DEFAULT_DELAY); + printf("-DSECS\t\tSleep this many seconds before the first tweak.\n"); + printf("\t\t\tValid range: %d..%d Default is %d seconds\n", + MIN_FIRST_DELAY, MAX_FIRST_DELAY, DEFAULT_FIRST_DELAY); + printf("-t\t\tOnly tweak once and then terminate\n"); + printf("\t\t\t(if not specified, tweak infinitely)\n"); +} + +int main(int argc, char *argv[]) +{ + // We are gonna be killall'd a lot, so try to be submissive: + signal(SIGINT,&exit); + signal(SIGTERM, &exit); + // but don't disappear when run from shell scripts + signal(SIGHUP, SIG_IGN); + + if (!initphys()) { + printf("Error mapping registers!\n"); + printf("Exiting..\n"); + return 1; + } + + int cur_arg = 1; + while (cur_arg < argc) + { + // We have been passed command-line parameters + switch (argv[cur_arg][1]) + { + case 'h': + displayhelp(); + return(0); + break; + case 'p': + mode = PAL; + break; + case 'P': + pal_overscan_fix = 1; + break; + case 'e': + enable_tvmode = 1; + break; +// case 's': +// stubborn_fix = 1; +// break; + case 'S': + scaling_tweak = 0; + break; + case 'v': + switch (argv[cur_arg][2]) + { + case 'x': + if (strlen(&argv[cur_arg][3]) <= 3) + { + vxscale_percent = atoi(&argv[cur_arg][3]); + if (vxscale_percent < MIN_VXSCALE || vxscale_percent > MAX_VXSCALE) + { + printf("ERROR: Video X-axis scaling percentage out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad video X-axis scaling percentage\n\n"); + displayhelp(); + exit(1); + } + break; + case 'y': + if (strlen(&argv[cur_arg][3]) <= 3) + { + vyscale_percent = atoi(&argv[cur_arg][3]); + if (vyscale_percent < MIN_VYSCALE || vyscale_percent > MAX_VYSCALE) + { + printf("ERROR: Video Y-axis scaling percentage out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad video Y-axis scaling percentage\n\n"); + displayhelp(); + exit(1); + } + break; + default: + printf("ERROR: bad video scaling parameter\n\n"); + displayhelp(); + exit(1); + break; + } + break; + case 'V': + tweak_yuv = 1; + break; + case 't': + tweak_only_once = 1; + break; +// case 'f': +// if (strlen(&argv[cur_arg][2]) <= 4) +// { +// pitch = atoi(&argv[cur_arg][2]); +// if (pitch < MIN_PITCH || pitch > MAX_PITCH) +// { +// printf("ERROR: pitch out of range\n\n"); +// displayhelp(); +// exit(1); +// } +// } else +// { +// printf("ERROR: bad pitch\n\n"); +// displayhelp(); +// exit(1); +// } +// break; + case 'x': + if (strlen(&argv[cur_arg][2]) <= 3) + { + xoffset = atoi(&argv[cur_arg][2]); + if (xoffset < MIN_XOFFSET || xoffset > MAX_XOFFSET) + { + printf("ERROR: X offset out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad X offset\n\n"); + displayhelp(); + exit(1); + } + break; + case 'y': + if (strlen(&argv[cur_arg][2]) <= 3) + { + yoffset = atoi(&argv[cur_arg][2]); + if (yoffset < MIN_YOFFSET || yoffset > MAX_YOFFSET) + { + printf("ERROR: Y offset out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad Y offset\n\n"); + displayhelp(); + exit(1); + } + break; + case 'X': + if (strlen(&argv[cur_arg][2]) <= 3) + { + xscale_percent = atoi(&argv[cur_arg][2]); + if (xscale_percent < MIN_XSCALE || xscale_percent > MAX_XSCALE) + { + printf("ERROR: X-axis scaling percentage out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad X-axis scaling percentage\n\n"); + displayhelp(); + exit(1); + } + break; + case 'Y': + if (strlen(&argv[cur_arg][2]) <= 3) + { + yscale_percent = atoi(&argv[cur_arg][2]); + if (yscale_percent < MIN_YSCALE || yscale_percent > MAX_YSCALE) + { + printf("ERROR: Y-axis scaling percentage out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad Y-axis scaling percentage\n\n"); + displayhelp(); + exit(1); + } + break; + case 'd': + if (strlen(&argv[cur_arg][2]) <= 3) + { + delay = atoi(&argv[cur_arg][2]); + if (delay < MIN_DELAY || delay > MAX_DELAY) + { + printf("ERROR: delay out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad delay given\n\n"); + displayhelp(); + exit(1); + } + break; + case 'D': + if (strlen(&argv[cur_arg][2]) <= 3) + { + first_delay = atoi(&argv[cur_arg][2]); + if (first_delay < MIN_FIRST_DELAY || first_delay > MAX_FIRST_DELAY) + { + printf("ERROR: 'first delay' out of range\n\n"); + displayhelp(); + exit(1); + } + } else + { + printf("ERROR: bad 'first delay' given\n\n"); + displayhelp(); + exit(1); + } + break; + default: + // invalid parameter + printf("ERROR: invalid parameter passed\n\n"); + displayhelp(); + exit(1); + } // switch + cur_arg++; + } // while (argc > 1) + + if (xoffset == 999) + { + // parameter wasn't specified, set to default for the given mode + xoffset = (mode == PAL ? DEFAULT_PAL_XOFFSET : DEFAULT_NTSC_XOFFSET); + } + + if (yoffset == 999) + { + // parameter wasn't specified, set to default for the given mode + yoffset = (mode == PAL ? DEFAULT_PAL_YOFFSET : DEFAULT_NTSC_YOFFSET); + } + + // main loop + loop(); + + closephys(); + return 0; +} + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |