Jason Tackaberry wrote:
On Fri, 2007-01-12 at 23:31 +0800, mike lewis wrote:
Before I go off to bed I just have to say that I figured out what the
issue was. vidix wasn't detecting the RAm size of my card. So I hard
coded the RAM size (from 16 to 32) and now there is not more artifacts
on the screen.
Where did you hardcode this?
I think the proper way is not to hardcode it, but to apply the so-called
"matroxfb-full-memory" kernel patch. Another useful patch might be the
one called "matroxfb-g400-clock", I don't know why they haven't made it
into the kernel for such a long time. You can find older versions of
them in the 'patches' directory of the DirectFB source, and I guess they
apply to recent kernels too, or you can easily adapt them by hand. If
you prefer, you can use mine attached in this message, already adapted
for 2.6.18 (should also apply to 2.6.19), the one called
linux-2.6.18_matroxfb-address-ioctl_v3.diff is necessary for newer
versions of DirectFB.
Good luck,
Lucian
diff -Naur linux-2.6.18_orig/drivers/video/matrox/matroxfb_base.c
linux-2.6.18/drivers/video/matrox/matroxfb_base.c
--- linux-2.6.18_orig/drivers/video/matrox/matroxfb_base.c 2006-10-21
11:23:46.000000000 +0200
+++ linux-2.6.18/drivers/video/matrox/matroxfb_base.c 2006-10-21
11:49:05.000000000 +0200
@@ -721,7 +721,7 @@
DBG(__FUNCTION__)
fix->smem_start = ACCESS_FBINFO(video.base) +
ACCESS_FBINFO(curr.ydstorg.bytes);
- fix->smem_len = ACCESS_FBINFO(video.len_usable) -
ACCESS_FBINFO(curr.ydstorg.bytes);
+ fix->smem_len = ACCESS_FBINFO(video.len) -
ACCESS_FBINFO(curr.ydstorg.bytes);
}
static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info
*info)
diff -Naur linux-2.6.18_orig/drivers/video/matrox/matroxfb_DAC1064.c
linux-2.6.18/drivers/video/matrox/matroxfb_DAC1064.c
--- linux-2.6.18_orig/drivers/video/matrox/matroxfb_DAC1064.c 2006-10-21
11:23:46.000000000 +0200
+++ linux-2.6.18/drivers/video/matrox/matroxfb_DAC1064.c 2006-10-21
11:55:09.000000000 +0200
@@ -808,6 +808,96 @@
return;
}
+static void g400_preinit(WPMINFO2) {
+ unsigned int m, n, p, rfhcnt, mclk, clk;
+ u_int32_t opt, opt2;
+
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &opt);
+ opt &= 0xE0000100;
+ opt |= ACCESS_FBINFO(values).reg.opt;
+ if (ACCESS_FBINFO(devflags.novga))
+ opt &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ opt &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ opt |= 0x20000000;
+ opt |= 0x20;
+
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &opt2);
+ opt2 &= ~0x0F3F0100;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, opt2);
+
+ /* switch all clocks to PCI source */
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG,
+ opt | 0x4);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG,
+ ACCESS_FBINFO(values).reg.opt3 & ~0x00300C03);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt);
+
+ DAC1064_calcclock(PMINFO ACCESS_FBINFO(values.pll.system),
+ ACCESS_FBINFO(limits.system.vcomax),
+ &m, &n, &p );
+ ACCESS_FBINFO(hw).DACclk[0] = m;
+ ACCESS_FBINFO(hw).DACclk[1] = n;
+ ACCESS_FBINFO(hw).DACclk[2] = p;
+
+ outDAC1064(PMINFO DAC1064_XSYSPLLM, m );
+ outDAC1064(PMINFO DAC1064_XSYSPLLN, n );
+ outDAC1064(PMINFO DAC1064_XSYSPLLP, p );
+ for (clk = 65536; clk; --clk) {
+ if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
+ break;
+ }
+ if (!clk)
+ printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+
+ /* switch clocks to their real PLL source(s) */
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG,
+ opt | 0x4);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG,
+ ACCESS_FBINFO(values).reg.opt3);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt);
+
+ mclk = ACCESS_FBINFO(values.pll.system) * 1000;
+ switch ((ACCESS_FBINFO(values).reg.opt3 >> 13) & 0x7) {
+ case 0:
+ mclk = mclk * 1 / 3;
+ break;
+ case 1:
+ mclk = mclk * 2 / 5;
+ break;
+ case 2:
+ mclk = mclk * 4 / 9;
+ break;
+ case 3:
+ mclk = mclk * 1 / 2;
+ break;
+ case 4:
+ mclk = mclk * 2 / 3;
+ break;
+ default:
+ mclk = mclk * 1 / 1;
+ break;
+ }
+
+ /* 15 ns? */
+ rfhcnt = (mclk - 66667) / (64 * 66667);
+ if (rfhcnt > 63)
+ rfhcnt = 63;
+ rfhcnt <<= 15;
+
+ mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+ mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+ udelay(200);
+ mga_outl(M_MACCESS, 0x00000000);
+ mga_outl(M_MACCESS, 0x00008000);
+ udelay(100);
+ mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+ opt |= rfhcnt;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt);
+ ACCESS_FBINFO(hw).MXoptionReg = opt;
+}
+
static int MGAG100_preinit(WPMINFO2) {
static const int vxres_g100[] = { 512, 640, 768, 800, 832,
960,
1024, 1152, 1280, 1600, 1664,
1920,
@@ -865,6 +955,10 @@
g450_preinit(PMINFO2);
return 0;
}
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ g400_preinit(PMINFO2);
+ return 0;
+ }
hw->MXoptionReg &= 0xC0000100;
hw->MXoptionReg |= 0x00000020;
if (ACCESS_FBINFO(devflags.novga))
@@ -927,26 +1021,6 @@
udelay(100);
mga_outw(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
hw->MXoptionReg |= 0x00078020;
- } else {
- pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG,
®50);
- reg50 &= ~0x00000100;
- reg50 |= 0x00000000;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG,
reg50);
-
- if (ACCESS_FBINFO(devflags.memtype) == -1)
- hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt &
0x1C00;
- else
- hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) &
7) << 10;
- if (ACCESS_FBINFO(devflags.sgram))
- hw->MXoptionReg |= 0x4000;
- mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
- mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
- udelay(200);
- mga_outl(M_MACCESS, 0x00000000);
- mga_outl(M_MACCESS, 0x00008000);
- udelay(100);
- mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
- hw->MXoptionReg |= 0x00040020;
}
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG,
hw->MXoptionReg);
return 0;
@@ -979,7 +1053,7 @@
mga_setr(M_EXTVGA_INDEX, 0x06, 0x00);
}
}
- if (ACCESS_FBINFO(devflags.g450dac)) {
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
/* either leave MCLK as is... or they were set in preinit */
hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
diff -Naur linux-2.6.18_orig/drivers/video/matrox/matroxfb_misc.c
linux-2.6.18/drivers/video/matrox/matroxfb_misc.c
--- linux-2.6.18_orig/drivers/video/matrox/matroxfb_misc.c 2006-10-21
11:23:46.000000000 +0200
+++ linux-2.6.18/drivers/video/matrox/matroxfb_misc.c 2006-10-21
11:55:09.000000000 +0200
@@ -601,16 +601,17 @@
static int parse_pins4(WPMINFO const struct matrox_bios* bd) {
MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000
: bd->pins[ 39] * 4000;
MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ?
MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000;
- MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71);
+ MINFO->values.reg.mctlwtst = get_u32(bd->pins + 81);
MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) |
((bd->pins[87] << 22) & 0x00C00000) |
((bd->pins[86] << 1) & 0x000001E0) |
( bd->pins[86] & 0x0000000F);
MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) |
((bd->pins[53] << 22) & 0x10000000) |
- ((bd->pins[53] << 7) & 0x00001C00);
- MINFO->values.reg.opt3 = get_u32(bd->pins + 67);
- MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000
: bd->pins[ 65] * 4000;
+ ((bd->pins[53] << 7) & 0x00001C00) |
+ (((bd->pins[92] << 10) ^ 0x00004000)
& 0x00004000);
+ MINFO->values.reg.opt3 = get_u32(bd->pins + 77);
+ MINFO->values.pll.system = (bd->pins[ 76] == 0xFF) ? 200000
: bd->pins[ 76] * 4000;
MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 :
27000;
return 0;
}
diff -Naur linux-2.6.18_orig/drivers/video/matrox/matroxfb_base.c
linux-2.6.18/drivers/video/matrox/matroxfb_base.c
--- linux-2.6.18_orig/drivers/video/matrox/matroxfb_base.c 2006-10-21
11:23:46.000000000 +0200
+++ linux-2.6.18/drivers/video/matrox/matroxfb_base.c 2006-10-21
11:43:59.000000000 +0200
@@ -190,6 +190,7 @@
ACCESS_FBINFO(crtc1.panpos) = -1; /* No update pending
anymore */
extvga_reg = mga_inb(M_EXTVGA_INDEX);
mga_setr(M_EXTVGA_INDEX, 0x00, panpos);
+ mga_inb(M_EXTVGA_INDEX);
if (extvga_reg != 0x00) {
mga_outb(M_EXTVGA_INDEX, extvga_reg);
}
@@ -207,16 +208,36 @@
status = mga_inl(M_STATUS);
+ if (status & 0x220)
+ mga_outl(M_ICLEAR, status & 0x220);
+
if (status & 0x20) {
- mga_outl(M_ICLEAR, 0x20);
ACCESS_FBINFO(crtc1.vsync.cnt)++;
matroxfb_crtc1_panpos(PMINFO2);
wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait));
handled = 1;
}
if (status & 0x200) {
- mga_outl(M_ICLEAR, 0x200);
ACCESS_FBINFO(crtc2.vsync.cnt)++;
+ ACCESS_FBINFO(crtc2.vsync.field) = (mga_inl(0x3C48) >> 24) ^ 1;
+ if (ACCESS_FBINFO(crtc2.pan) &&
+ ACCESS_FBINFO(crtc2.address.field) !=
ACCESS_FBINFO(crtc2.vsync.field)) {
+ ACCESS_FBINFO(crtc2.pan) = 0;
+ mga_outl(0x3C28,
ACCESS_FBINFO(crtc2.address.offset[0]));
+ mga_outl(0x3C2C,
ACCESS_FBINFO(crtc2.address.offset[1]));
+ mga_outl(0x3C30,
ACCESS_FBINFO(crtc2.address.offset[2]));
+ mga_outl(0x3C34,
ACCESS_FBINFO(crtc2.address.offset[3]));
+ mga_outl(0x3C38,
ACCESS_FBINFO(crtc2.address.offset[4]));
+ mga_outl(0x3C3C,
ACCESS_FBINFO(crtc2.address.offset[5]));
+ mga_inl(0x3C3C);
+ }
+ if (ACCESS_FBINFO(spic.pan) &&
+ ACCESS_FBINFO(spic.address.field) !=
ACCESS_FBINFO(crtc2.vsync.field)) {
+ ACCESS_FBINFO(spic.pan) = 0;
+ mga_outl(0x3C54, ACCESS_FBINFO(spic.address.offset[0]));
+ mga_outl(0x3C58, ACCESS_FBINFO(spic.address.offset[1]));
+ mga_inl(0x3C58);
+ }
wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait));
handled = 1;
}
@@ -299,6 +320,162 @@
return 0;
}
+int matroxfb_address(WPMINFO struct matrox_address *address)
+{
+ if (address->device == MATROX_ADDRESS_DEVICE_CRTC1) {
+ int diff, linecomp = ACCESS_FBINFO(fbcon).var.yres;
+ unsigned int p0, p1, p2, p3, pos;
+ unsigned long flags;
+ int err;
+
+ pos = address->offset[0] * ACCESS_FBINFO(curr.final_bppShift) /
32;
+ pos += ACCESS_FBINFO(curr.ydstorg.chunks);
+
+ p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF;
+ p1 = ACCESS_FBINFO(hw).CRTC[0x0C] = (pos & 0xFF00) >> 8;
+ p2 = ACCESS_FBINFO(hw).CRTCEXT[0] =
(ACCESS_FBINFO(hw).CRTCEXT[0] & 0xB0) |
+ ((pos >> 16) & 0x0F) |
((pos >> 14) & 0x40);
+ p3 = ACCESS_FBINFO(hw).CRTCEXT[8] = pos >> 21;
+
+ err = matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = linecomp - mga_inl(0x1E20);
+ } while (-2 < diff && diff < 2);
+
+ CRITBEGIN
+
+ matroxfb_DAC_lock_irqsave(flags);
+ mga_setr(M_CRTC_INDEX, 0x0D, p0);
+ mga_setr(M_CRTC_INDEX, 0x0C, p1);
+ mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+ if (!err) {
+ ACCESS_FBINFO(crtc1.panpos) = p2;
+ } else {
+ /* Abort any pending change */
+ ACCESS_FBINFO(crtc1.panpos) = -1;
+ mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+ mga_inb(M_EXTVGA_INDEX);
+ }
+ matroxfb_DAC_unlock_irqrestore(flags);
+
+ CRITEND
+
+ address->field = -1; /* N/A */
+ address->count = ACCESS_FBINFO(crtc1.vsync.cnt);
+
+ return 0;
+ } else
+ if (address->device == MATROX_ADDRESS_DEVICE_CRTC2 &&
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ int diff, c2vlinecomp = (mga_inl(0x3C44) >> 16) & 0xFFF;
+ int err;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ err = matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = c2vlinecomp - mga_inl(0x3C48);
+ } while (-2 < diff && diff < 2);
+
+ if (!err && address->field == ACCESS_FBINFO(crtc2.vsync.field))
{
+ ACCESS_FBINFO(crtc2.address) = *address;
+ ACCESS_FBINFO(crtc2.pan) = 1;
+ } else {
+ ACCESS_FBINFO(crtc2.pan) = 0;
+
+ mga_outl(0x3C28, address->offset[0]);
+ mga_outl(0x3C2C, address->offset[1]);
+ mga_outl(0x3C30, address->offset[2]);
+ mga_outl(0x3C34, address->offset[3]);
+ mga_outl(0x3C38, address->offset[4]);
+ mga_outl(0x3C3C, address->offset[5]);
+ mga_inl(0x3C3C);
+ }
+
+ address->field = ACCESS_FBINFO(crtc2.vsync.field);
+ address->count = ACCESS_FBINFO(crtc2.vsync.cnt);
+
+ return 0;
+ } else
+ if (address->device == MATROX_ADDRESS_DEVICE_SPIC &&
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ int diff, c2vlinecomp = (mga_inl(0x3C44) >> 16) & 0xFFF;
+ int err;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ err = matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = c2vlinecomp - mga_inl(0x3C48);
+ } while (-2 < diff && diff < 2);
+
+ if (!err && address->field == ACCESS_FBINFO(crtc2.vsync.field))
{
+ ACCESS_FBINFO(spic.address) = *address;
+ ACCESS_FBINFO(spic.pan) = 1;
+ } else {
+ ACCESS_FBINFO(spic.pan) = 0;
+
+ mga_outl(0x3C54, address->offset[0]);
+ mga_outl(0x3C58, address->offset[1]);
+ mga_inl(0x3C58);
+ }
+
+ address->field = ACCESS_FBINFO(crtc2.vsync.field);
+ address->count = ACCESS_FBINFO(crtc2.vsync.cnt);
+
+ return 0;
+ } else
+ if (address->device == MATROX_ADDRESS_DEVICE_BES &&
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ int diff, besvcnt = (mga_inl(0x3DC0) >> 16) & 0xFFF;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = besvcnt - mga_inl(0x1E20);
+ } while (-2 < diff && diff < 2);
+
+ mga_outl(0x3D00, address->offset[0]);
+ mga_outl(0x3D04, address->offset[1]);
+ mga_outl(0x3D10, address->offset[2]);
+ mga_outl(0x3D14, address->offset[3]);
+ mga_outl(0x3D60, address->offset[4]);
+ mga_outl(0x3D64, address->offset[5]);
+ mga_inl(0x3D64);
+
+ address->field = -1; /* N/A */
+ address->count = ACCESS_FBINFO(crtc1.vsync.cnt);
+
+ return 0;
+ } else
+ if (address->device == MATROX_ADDRESS_DEVICE_BES &&
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) {
+ int diff, besvcnt = (mga_inl(0x3DC0) >> 16) & 0xFFF;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = besvcnt - mga_inl(0x1E20);
+ } while (-2 < diff && diff < 2);
+
+ mga_outl(0x3D00, address->offset[0]);
+ mga_outl(0x3D04, address->offset[1]);
+ mga_outl(0x3D10, address->offset[2]);
+ mga_outl(0x3D14, address->offset[3]);
+ mga_inl(0x3D14);
+
+ address->field = -1; /* N/A */
+ address->count = ACCESS_FBINFO(crtc1.vsync.cnt);
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
/* --------------------------------------------------------------------- */
static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
@@ -1158,6 +1335,23 @@
up_read(&ACCESS_FBINFO(altout).lock);
return err;
}
+ case MATROXFB_ADDRESS:
+ {
+ struct matrox_address address;
+ int err;
+
+ if (copy_from_user(&address, argp,
sizeof(address)))
+ return -EFAULT;
+
+ err = matroxfb_address(PMINFO &address);
+ if (err)
+ return err;
+
+ if (copy_to_user(argp, &address,
sizeof(address)))
+ return -EFAULT;
+
+ return 0;
+ }
}
return -ENOTTY;
}
diff -Naur linux-2.6.18_orig/drivers/video/matrox/matroxfb_base.h
linux-2.6.18/drivers/video/matrox/matroxfb_base.h
--- linux-2.6.18_orig/drivers/video/matrox/matroxfb_base.h 2006-10-21
11:23:46.000000000 +0200
+++ linux-2.6.18/drivers/video/matrox/matroxfb_base.h 2006-10-21
11:43:59.000000000 +0200
@@ -354,6 +354,20 @@
struct matrox_vsync {
wait_queue_head_t wait;
unsigned int cnt;
+ unsigned int field;
+};
+
+#define MATROXFB_ADDRESS _IOWR('n', 0xFC, struct matrox_address)
+
+#define MATROX_ADDRESS_DEVICE_CRTC1 0
+#define MATROX_ADDRESS_DEVICE_BES 1
+#define MATROX_ADDRESS_DEVICE_CRTC2 2
+#define MATROX_ADDRESS_DEVICE_SPIC 3
+struct matrox_address {
+ u32 device;
+ u32 field;
+ u32 count;
+ u32 offset[6];
};
struct matrox_fb_info {
@@ -387,8 +401,14 @@
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock;
+ int pan;
+ struct matrox_address address;
} crtc2;
struct {
+ int pan;
+ struct matrox_address address;
+ } spic;
+ struct {
struct rw_semaphore lock;
struct {
int brightness, contrast, saturation, hue, gamma;
diff -Naur linux-2.6.18_orig/drivers/video/matrox/matroxfb_misc.c
linux-2.6.18/drivers/video/matrox/matroxfb_misc.c
--- linux-2.6.18_orig/drivers/video/matrox/matroxfb_misc.c 2006-10-21
11:23:46.000000000 +0200
+++ linux-2.6.18/drivers/video/matrox/matroxfb_misc.c 2006-10-21
11:43:59.000000000 +0200
@@ -265,7 +265,7 @@
vs = m->VSyncStart - 1;
ve = m->VSyncEnd - 1;
vt = m->VTotal - 2;
- lc = vd;
+ lc = vd + 1;
/* G200 cannot work with (ht & 7) == 6 */
if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
ht++;
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-devel mailing list
Freevo-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-devel