public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* cx23885
@ 2010-02-15 12:20 Michael
  2010-02-15 12:54 ` cx23885 Andy Walls
  0 siblings, 1 reply; 19+ messages in thread
From: Michael @ 2010-02-15 12:20 UTC (permalink / raw)
  To: linux-media

Hello

Does anybody know whether this card is currently supported and if yes, is it 
by cx88 or by cx23885?

http://www.commell.com.tw/Product/Surveillance/MPX-885.htm

It is based on the Connexant 23885 chip but uses an Mini-PCIe interface.

Thanks

Michael


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 12:20 cx23885 Michael
@ 2010-02-15 12:54 ` Andy Walls
  2010-02-15 13:15   ` cx23885 Michael
  0 siblings, 1 reply; 19+ messages in thread
From: Andy Walls @ 2010-02-15 12:54 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

On Mon, 2010-02-15 at 13:20 +0100, Michael wrote:
> Hello
> 
> Does anybody know whether this card is currently supported 

Likely no.  I have not checked the source to be sure.


> and if yes, is it 
> by cx88 or by cx23885?
> 
> http://www.commell.com.tw/Product/Surveillance/MPX-885.htm
> 
> It is based on the Connexant 23885 chip but uses an Mini-PCIe interface.

cx88 handles PCI bridge chips: CX2388[0123]

cx23885 handles PCIe bridge chips: CX2388[578]

>From the picture of the card from the datasheet it has a CX23885 chip.

Regards,
Andy

> Thanks
> 
> Michael



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 12:54 ` cx23885 Andy Walls
@ 2010-02-15 13:15   ` Michael
  2010-02-15 14:41     ` cx23885 Steven Toth
  0 siblings, 1 reply; 19+ messages in thread
From: Michael @ 2010-02-15 13:15 UTC (permalink / raw)
  To: linux-media

Hi Andy

>> Does anybody know whether this card is currently supported
> 
> Likely no.  I have not checked the source to be sure.
> 
Is this because the driver does not have the right capabilities or is it 
"just" a PCI-id missing in the driver?

The latter would be quite easy to add, I guess.
> 
>> and if yes, is it
>> by cx88 or by cx23885?
>> 
>> http://www.commell.com.tw/Product/Surveillance/MPX-885.htm
>> 
>> It is based on the Connexant 23885 chip but uses an Mini-PCIe interface.
> 
> cx88 handles PCI bridge chips: CX2388[0123]
> 
> cx23885 handles PCIe bridge chips: CX2388[578]
> 
>>From the picture of the card from the datasheet it has a CX23885 chip.
> 

That means, if a driver might support it, then the cx23885 driver not the 
cx88, correct?

Thanks

Michael

> Regards,
> Andy
> 
>> Thanks
>> 
>> Michael



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 13:15   ` cx23885 Michael
@ 2010-02-15 14:41     ` Steven Toth
  2010-02-15 15:21       ` cx23885 Michael
  0 siblings, 1 reply; 19+ messages in thread
From: Steven Toth @ 2010-02-15 14:41 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

On 2/15/10 8:15 AM, Michael wrote:
> Hi Andy
>
>>> Does anybody know whether this card is currently supported
>>
>> Likely no.  I have not checked the source to be sure.
>>
> Is this because the driver does not have the right capabilities or is it
> "just" a PCI-id missing in the driver?

A mixture of both, analog support in the 885 driver is limited. Generally, yes - 
start by adding the PCI id.

>
> The latter would be quite easy to add, I guess.
>>
>>> and if yes, is it
>>> by cx88 or by cx23885?
>>>
>>> http://www.commell.com.tw/Product/Surveillance/MPX-885.htm
>>>
>>> It is based on the Connexant 23885 chip but uses an Mini-PCIe interface.
>>
>> cx88 handles PCI bridge chips: CX2388[0123]
>>
>> cx23885 handles PCIe bridge chips: CX2388[578]
>>
>> > From the picture of the card from the datasheet it has a CX23885 chip.
>>
>
> That means, if a driver might support it, then the cx23885 driver not the
> cx88, correct?

Correct.


-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com
+1.646.355.8490


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 14:41     ` cx23885 Steven Toth
@ 2010-02-15 15:21       ` Michael
  2010-02-15 17:11         ` cx23885 Steven Toth
  2010-02-15 17:27         ` cx23885 Devin Heitmueller
  0 siblings, 2 replies; 19+ messages in thread
From: Michael @ 2010-02-15 15:21 UTC (permalink / raw)
  To: linux-media

Steven Toth wrote:

>> Is this because the driver does not have the right capabilities or is it
>> "just" a PCI-id missing in the driver?
> 
> A mixture of both, analog support in the 885 driver is limited. Generally,
> yes - start by adding the PCI id.
> 

So, does this imply that you see a chance to get this card running? :-)

If so, I will order one card and try. There is not much I want to do with 
the card. It should simply digitize an external camera signal. I want to 
display it with mplayer. It should, however, be reliable and not crash the 
system or drop the stream or whatever.

So far, it seems that this is the only mini-pcie video digitizer card that 
exists. I would have taken a bttv based one instead, but as there is none...

Thanks

Michael


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 15:21       ` cx23885 Michael
@ 2010-02-15 17:11         ` Steven Toth
  2010-02-15 20:41           ` cx23885 Michael
  2010-02-15 17:27         ` cx23885 Devin Heitmueller
  1 sibling, 1 reply; 19+ messages in thread
From: Steven Toth @ 2010-02-15 17:11 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

On 2/15/10 10:21 AM, Michael wrote:
> Steven Toth wrote:
>
>>> Is this because the driver does not have the right capabilities or is it
>>> "just" a PCI-id missing in the driver?
>>
>> A mixture of both, analog support in the 885 driver is limited. Generally,
>> yes - start by adding the PCI id.
>>
>
> So, does this imply that you see a chance to get this card running? :-)
>
> If so, I will order one card and try. There is not much I want to do with
> the card. It should simply digitize an external camera signal. I want to
> display it with mplayer. It should, however, be reliable and not crash the
> system or drop the stream or whatever.
>
> So far, it seems that this is the only mini-pcie video digitizer card that
> exists. I would have taken a bttv based one instead, but as there is none...

The hardware has no mpeg encoder, so if by digitizer you mean raw high bitrate 
video frames then yes, and if mplayer is capable of supporting the v4l mmap 
interfaces then yes. (I've have zero experience of mplayer with raw video - not 
sure if this works).

It feels like a reach, the design looks like a 'same-old' cx23885/7/8 which you 
could potentially use in tvtime - with some work.

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com
+1.646.355.8490


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 15:21       ` cx23885 Michael
  2010-02-15 17:11         ` cx23885 Steven Toth
@ 2010-02-15 17:27         ` Devin Heitmueller
  2010-02-15 20:29           ` cx23885 Michael
  1 sibling, 1 reply; 19+ messages in thread
From: Devin Heitmueller @ 2010-02-15 17:27 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

On Mon, Feb 15, 2010 at 10:21 AM, Michael <auslands-kv@gmx.de> wrote:
> So, does this imply that you see a chance to get this card running? :-)
>
> If so, I will order one card and try. There is not much I want to do with
> the card. It should simply digitize an external camera signal. I want to
> display it with mplayer. It should, however, be reliable and not crash the
> system or drop the stream or whatever.
>
> So far, it seems that this is the only mini-pcie video digitizer card that
> exists. I would have taken a bttv based one instead, but as there is none...

I would probably advise against using a cx23885 based design for
analog under Linux right now.  There is *some* analog support in the
driver, but it is not very mature and has a host of issues/bugs.
Also, there is currently no analog audio support in the driver, so if
you do not have an encoder then it will not work.

In other words, even if all you did need was to add another PCI ID,
you would still be very likely to run into problems.

We (KernelLabs) have a handful of patches that can eventually get into
the upstream driver, although right now progress is slow on that front
and you certainly shouldn't buy hardware based on the expectation that
the patches are forthcoming.

Devin

-- 
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 17:27         ` cx23885 Devin Heitmueller
@ 2010-02-15 20:29           ` Michael
  0 siblings, 0 replies; 19+ messages in thread
From: Michael @ 2010-02-15 20:29 UTC (permalink / raw)
  To: linux-media

Devin Heitmueller wrote:

> I would probably advise against using a cx23885 based design for
> analog under Linux right now.  There is *some* analog support in the
> driver, but it is not very mature and has a host of issues/bugs.
> Also, there is currently no analog audio support in the driver, so if
> you do not have an encoder then it will not work.
>

Well, I don't need audio, just video. A raw stream is everything I need, as 
it is displayed by mplayer directly.

But you mean that this most probably wouldn't work as the analog support is 
not good enough for the time being?

> In other words, even if all you did need was to add another PCI ID,
> you would still be very likely to run into problems.
> 
> We (KernelLabs) have a handful of patches that can eventually get into
> the upstream driver, although right now progress is slow on that front
> and you certainly shouldn't buy hardware based on the expectation that
> the patches are forthcoming.
> 
Well, would these patches help me to get the card working for my purpose 
(raw video stream)? I don't mind patching the driver. I am no developer, but 
applying a patch and compiling the driver I should manage.

Otherwise do you know another mini-pci-express video capture card that is 
supported by the linux kernel?

Thanks for your help

Michael
> Devin
> 



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 17:11         ` cx23885 Steven Toth
@ 2010-02-15 20:41           ` Michael
  2010-02-15 20:53             ` cx23885 Steven Toth
  0 siblings, 1 reply; 19+ messages in thread
From: Michael @ 2010-02-15 20:41 UTC (permalink / raw)
  To: linux-media

Steven Toth wrote:

> The hardware has no mpeg encoder, so if by digitizer you mean raw high
> bitrate video frames then yes, and if mplayer is capable of supporting the
> v4l mmap interfaces then yes. (I've have zero experience of mplayer with
> raw video - not sure if this works).

Well, I have mplayer working with a bttv based card sending rawyuv2, if I 
remember correctly. But this is on a different computer.

The board that I want to use has only mini-pci-express and the only card I 
found so far is this MPX-885.

> 
> It feels like a reach, the design looks like a 'same-old' cx23885/7/8
> which you could potentially use in tvtime - with some work.
> 

Well if tvtime runs then mplayer will most probably, too. The question is, 
what means "with some work" :-)

Michael


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 20:41           ` cx23885 Michael
@ 2010-02-15 20:53             ` Steven Toth
  2010-02-15 22:17               ` cx23885 Michael
  0 siblings, 1 reply; 19+ messages in thread
From: Steven Toth @ 2010-02-15 20:53 UTC (permalink / raw)
  To: Michael; +Cc: linux-media


> Well if tvtime runs then mplayer will most probably, too. The question is,
> what means "with some work" :-)

If you haven't worked on the cx23885 driver in the past, and you're not 
accustomed to developing tv/video drivers then you're going to struggle, massively.

Not that I'm trying to discourage, on the contrary, the more driver developers 
the better. In reality this isn't something you can fix with an evenings work.

However, if you would like to take a shot then look at the existing support for 
the HVR1800 board in the cx23885 tree. Specifically look at the raw video 
support in the cx23885-video.c file and you'll also want to investigate the 
cx25840 driver for configuring the A/V subsystem.

Feel free to submit patches.

Regards,

- Steve

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com
+1.646.355.8490


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 20:53             ` cx23885 Steven Toth
@ 2010-02-15 22:17               ` Michael
  2010-02-15 22:20                 ` cx23885 Steven Toth
  2010-02-15 22:47                 ` cx23885 Michael
  0 siblings, 2 replies; 19+ messages in thread
From: Michael @ 2010-02-15 22:17 UTC (permalink / raw)
  To: linux-media

Now comes the best part:

I found a linux driver on the producers web page. And it is written by ... 
Steven Toth :-)

http://www.commell.com.tw/Product/Surveillance/MPX-885/mpx-885.rar

I am looking at the files to see what they have changed (if anything at 
all).

One thing I found pretty fast is that they added in cx23885-card.c:

[CX23885_BOARD_MPX885] = {
	    .name       = "MPX-885",
        .porta      = CX23885_ANALOG_VIDEO,
        .portb      = CX23885_MPEG_ENCODER,
        .portc      = CX23885_MPEG_DVB,
        .input          = {{
            .type   = CX23885_VMUX_COMPOSITE1,
            .vmux   = CX25840_VIN1_CH1,
            .gpio0  = 0,
        }, {
            .type   = CX23885_VMUX_COMPOSITE2,
            .vmux   = CX25840_VIN2_CH1,
            .gpio0  = 0,
        }, {
            .type   = CX23885_VMUX_COMPOSITE3,
            .vmux   = CX25840_VIN3_CH1,
            .gpio0  = 0,
        }, {
            .type   = CX23885_VMUX_COMPOSITE4,
            .vmux   = CX25840_VIN4_CH1,
            .gpio0  = 0,
        } }

Now, concerning the rest of the code, I'm afraid my knowledge is far below 
what is needed to understand just a little bit of it. I can try to compile 
the code, but they state it is for kernel 2.6.21, so I don't know whether it 
compiles for 2.6.31 (or newer).

I can try to make a diff, but I guess there will be lots of changes between 
this rather old code and an actual cx23885 version.

But maybe it is a start. What do you think?

Michael

Steven Toth wrote:

> 
>> Well if tvtime runs then mplayer will most probably, too. The question
>> is, what means "with some work" :-)
> 
> If you haven't worked on the cx23885 driver in the past, and you're not
> accustomed to developing tv/video drivers then you're going to struggle,
> massively.
> 
> Not that I'm trying to discourage, on the contrary, the more driver
> developers the better. In reality this isn't something you can fix with an
> evenings work.
> 
> However, if you would like to take a shot then look at the existing
> support for the HVR1800 board in the cx23885 tree. Specifically look at
> the raw video support in the cx23885-video.c file and you'll also want to
> investigate the cx25840 driver for configuring the A/V subsystem.
> 
> Feel free to submit patches.
> 
> Regards,
> 
> - Steve
> 



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:17               ` cx23885 Michael
@ 2010-02-15 22:20                 ` Steven Toth
  2010-02-16 11:37                   ` cx23885 Michael
  2010-02-15 22:47                 ` cx23885 Michael
  1 sibling, 1 reply; 19+ messages in thread
From: Steven Toth @ 2010-02-15 22:20 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

> One thing I found pretty fast is that they added in cx23885-card.c:

This looks promising.

> But maybe it is a start. What do you think?

I repeat I my original comment below.

>> Feel free to submit patches.

^^^ indeed, good luck.

Regards,

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com
+1.646.355.8490


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:17               ` cx23885 Michael
  2010-02-15 22:20                 ` cx23885 Steven Toth
@ 2010-02-15 22:47                 ` Michael
  2010-02-15 22:56                   ` cx23885 Michael
  2010-02-15 22:58                   ` cx23885 Michael
  1 sibling, 2 replies; 19+ messages in thread
From: Michael @ 2010-02-15 22:47 UTC (permalink / raw)
  To: linux-media

I've done a diff against 2.6.31, but there are too many differences, so I 
can't easily tell what they have added and what was changed in the 
development between 2.6.21 and 2.6.31.

One thing is clear: They added several "case" instructions with code for the 
MPX-885. So I guess, they really got it working. 

I'm downloading kernel 2.6.21 now and make a diff with these drivers.

Michael

Michael wrote:

> Now comes the best part:
> 
> I found a linux driver on the producers web page. And it is written by ...
> Steven Toth :-)
> 
> http://www.commell.com.tw/Product/Surveillance/MPX-885/mpx-885.rar
> 
> I am looking at the files to see what they have changed (if anything at
> all).
> 
> One thing I found pretty fast is that they added in cx23885-card.c:
> 
> [CX23885_BOARD_MPX885] = {
> .name       = "MPX-885",
>         .porta      = CX23885_ANALOG_VIDEO,
>         .portb      = CX23885_MPEG_ENCODER,
>         .portc      = CX23885_MPEG_DVB,
>         .input          = {{
>             .type   = CX23885_VMUX_COMPOSITE1,
>             .vmux   = CX25840_VIN1_CH1,
>             .gpio0  = 0,
>         }, {
>             .type   = CX23885_VMUX_COMPOSITE2,
>             .vmux   = CX25840_VIN2_CH1,
>             .gpio0  = 0,
>         }, {
>             .type   = CX23885_VMUX_COMPOSITE3,
>             .vmux   = CX25840_VIN3_CH1,
>             .gpio0  = 0,
>         }, {
>             .type   = CX23885_VMUX_COMPOSITE4,
>             .vmux   = CX25840_VIN4_CH1,
>             .gpio0  = 0,
>         } }
> 
> Now, concerning the rest of the code, I'm afraid my knowledge is far below
> what is needed to understand just a little bit of it. I can try to compile
> the code, but they state it is for kernel 2.6.21, so I don't know whether
> it compiles for 2.6.31 (or newer).
> 
> I can try to make a diff, but I guess there will be lots of changes
> between this rather old code and an actual cx23885 version.
> 
> But maybe it is a start. What do you think?
> 
> Michael
> 
> Steven Toth wrote:
> 
>> 
>>> Well if tvtime runs then mplayer will most probably, too. The question
>>> is, what means "with some work" :-)
>> 
>> If you haven't worked on the cx23885 driver in the past, and you're not
>> accustomed to developing tv/video drivers then you're going to struggle,
>> massively.
>> 
>> Not that I'm trying to discourage, on the contrary, the more driver
>> developers the better. In reality this isn't something you can fix with
>> an evenings work.
>> 
>> However, if you would like to take a shot then look at the existing
>> support for the HVR1800 board in the cx23885 tree. Specifically look at
>> the raw video support in the cx23885-video.c file and you'll also want to
>> investigate the cx25840 driver for configuring the A/V subsystem.
>> 
>> Feel free to submit patches.
>> 
>> Regards,
>> 
>> - Steve
>>



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:47                 ` cx23885 Michael
@ 2010-02-15 22:56                   ` Michael
  2010-02-15 23:00                     ` cx23885 Steven Toth
  2010-02-15 23:22                     ` cx23885 Ralph Siemsen
  2010-02-15 22:58                   ` cx23885 Michael
  1 sibling, 2 replies; 19+ messages in thread
From: Michael @ 2010-02-15 22:56 UTC (permalink / raw)
  To: linux-media

[-- Attachment #1: Type: text/plain, Size: 456 bytes --]

Well, this did not work. The cx23885 driver was not included in kernel 
2.6.21, so no diff. The diff of the 2.6.21 cx25840 is twice as big as the 
2.6.31 diff. :-(

If anybody can give me a hint, what to include in a patch and what was old 
stuff that has jsut changed in 2.6.31, I'd be grateful.

Attached is the diff of cx23885, the commell version against kernel 
2.6.31.4.

> 
> I'm downloading kernel 2.6.21 now and make a diff with these drivers.
> 

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: cx23885-commell.diff --]
[-- Type: text/x-patch; name="cx23885-commell.diff", Size: 51072 bytes --]

diff -u cx23885/cimax2.c cx23885-commell/cimax2.c
--- cx23885/cimax2.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cimax2.c	2009-11-11 09:36:16.000000000 +0100
@@ -75,7 +75,6 @@
 	void *priv;
 };
 
-struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */
 
 int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
 						u8 *buf, int len)
@@ -183,10 +182,11 @@
 	if (ret != 0)
 		return ret;
 
-	mutex_lock(&gpio_mutex);
+	mutex_lock(&dev->gpio_lock);
 
 	/* write addr */
 	cx_write(MC417_OEN, NETUP_EN_ALL);
+	msleep(2);
 	cx_write(MC417_RWD, NETUP_CTRL_OFF |
 				NETUP_ADLO | (0xff & addr));
 	cx_clear(MC417_RWD, NETUP_ADLO);
@@ -194,9 +194,10 @@
 				NETUP_ADHI | (0xff & (addr >> 8)));
 	cx_clear(MC417_RWD, NETUP_ADHI);
 
-	if (read) /* data in */
+	if (read) { /* data in */
 		cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
-	else /* data out */
+		msleep(2);
+	} else /* data out */
 		cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
 
 	/* choose chip */
@@ -206,7 +207,7 @@
 	cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
 	mem = netup_ci_get_mem(dev);
 
-	mutex_unlock(&gpio_mutex);
+	mutex_unlock(&dev->gpio_lock);
 
 	if (!read)
 		if (mem < 0)
@@ -295,10 +296,18 @@
 }
 
 /* work handler */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void netup_read_ci_status(void *_state)
+#else
 static void netup_read_ci_status(struct work_struct *work)
+#endif
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	struct netup_ci_state *state = _state;
+#else
 	struct netup_ci_state *state =
 			container_of(work, struct netup_ci_state, work);
+#endif
 	u8 buf[33];
 	int ret;
 
@@ -403,7 +412,6 @@
 	switch (port->nr) {
 	case 1:
 		state->ci_i2c_addr = 0x40;
-		mutex_init(&gpio_mutex);
 		break;
 	case 2:
 		state->ci_i2c_addr = 0x41;
@@ -442,7 +450,12 @@
 	if (0 != ret)
 		goto err;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	INIT_WORK(&state->work, netup_read_ci_status, state);
+#else
 	INIT_WORK(&state->work, netup_read_ci_status);
+#endif
+	schedule_work(&state->work);
 
 	ci_dbg_print("%s: CI initialized!\n", __func__);
 
diff -u cx23885/cx23885-417.c cx23885-commell/cx23885-417.c
--- cx23885/cx23885-417.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-417.c	2009-11-11 09:36:16.000000000 +0100
@@ -37,6 +37,7 @@
 #include <media/cx2341x.h>
 
 #include "cx23885.h"
+#include "cx23885-ioctl.h"
 
 #define CX23885_FIRM_IMAGE_SIZE 376836
 #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -318,7 +319,7 @@
 	}
 }
 
-static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
 {
 	u32 regval;
 
@@ -382,7 +383,7 @@
 	return mc417_wait_ready(dev);
 }
 
-static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
 {
 	int retval;
 	u32 regval;
@@ -630,6 +631,39 @@
 	return retval;
 }
 
+void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+	u32 val;
+
+	/* Set the gpio value */
+	mc417_register_read(dev, 0x900C, &val);
+	val |= (mask & 0x000ffff);
+	mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+	u32 val;
+
+	/* Clear the gpio value */
+	mc417_register_read(dev, 0x900C, &val);
+	val &= ~(mask & 0x0000ffff);
+	mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+	u32 val;
+
+	/* Enable GPIO direction bits */
+	mc417_register_read(dev, 0x9020, &val);
+	if (asoutput)
+		val |= (mask & 0x0000ffff);
+	else
+		val &= ~(mask & 0x0000ffff);
+
+	mc417_register_write(dev, 0x9020, val);
+}
 /* ------------------------------------------------------------------ */
 
 /* MPEG encoder API */
@@ -955,25 +989,8 @@
 	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
 		IVTV_CMD_HW_BLOCKS_RST);
 
-	/* Restore GPIO settings, make sure EIO14 is enabled as an output. */
-	dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
-		__func__, gpio_output);
-	/* Power-up seems to have GPIOs AFU. This was causing digital side
-	 * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
-	 * power-up.
-	 * gpio_output |= (1<<14);
-	 */
-	/* Note: GPIO14 is specific to the HVR1800 here */
-	gpio_output = 0x10ff0411 | (1<<14);
-	retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
-	dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
-		__func__, gpio_output);
-
-	dprintk(1, "%s: GPIO value  EIO 0-15 was = 0x%x\n",
-		__func__, value);
-	value |= (1<<14);
-	dprintk(1, "%s: GPIO value  EIO 0-15 now = 0x%x\n",
-		__func__, value);
+	/* F/W power up disturbs the GPIOs, restore state */
+	retval |= mc417_register_write(dev, 0x9020, gpio_output);
 	retval |= mc417_register_write(dev, 0x900C, value);
 
 	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
@@ -1191,6 +1208,13 @@
 	if (i == ARRAY_SIZE(cx23885_tvnorms))
 		return -EINVAL;
 	dev->encodernorm = cx23885_tvnorms[i];
+#if 0
+	/* Notify the video decoder and other i2c clients.
+	 * This will likely need to be enabled for non NTSC
+	 * formats.
+	 */
+	call_all(dev, core, s_std, id);
+#endif
 	return 0;
 }
 
@@ -1708,6 +1732,11 @@
 	.vidioc_log_status	 = vidioc_log_status,
 	.vidioc_querymenu	 = vidioc_querymenu,
 	.vidioc_queryctrl	 = vidioc_queryctrl,
+	.vidioc_g_chip_ident	 = cx23885_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	 = cx23885_g_register,
+	.vidioc_s_register	 = cx23885_s_register,
+#endif
 };
 
 static struct video_device cx23885_mpeg_template = {
@@ -1788,9 +1817,6 @@
 		return err;
 	}
 
-	/* Initialize MC417 registers */
-	cx23885_mc417_init(dev);
-
 	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
 	       dev->name, dev->v4l_device->num);
 
diff -u cx23885/cx23885-cards.c cx23885-commell/cx23885-cards.c
--- cx23885/cx23885-cards.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-cards.c	2009-11-11 09:36:16.000000000 +0100
@@ -25,9 +25,11 @@
 #include <linux/delay.h>
 #include <media/cx25840.h>
 
+#include "compat.h"
 #include "cx23885.h"
 #include "tuner-xc2028.h"
 #include "netup-init.h"
+#include "cx23888-ir.h"
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -201,6 +203,42 @@
 		.name		= "Mygica X8506 DMB-TH",
 		.portb		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_MAGICPRO_PROHDTVE2] = {
+		.name		= "Magic-Pro ProHDTV Extreme 2",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1850] = {
+		.name		= "Hauppauge WinTV-HVR1850",
+		.portb		= CX23885_MPEG_ENCODER,
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_COMPRO_VIDEOMATE_E800] = {
+		.name		= "Compro VideoMate E800",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_MPX885] = {
+	    .name       = "MPX-885",
+        .porta      = CX23885_ANALOG_VIDEO,
+        .portb      = CX23885_MPEG_ENCODER,
+        .portc      = CX23885_MPEG_DVB,
+        .input          = {{
+            .type   = CX23885_VMUX_COMPOSITE1,
+            .vmux   = CX25840_VIN1_CH1,
+            .gpio0  = 0,
+        }, {
+            .type   = CX23885_VMUX_COMPOSITE2,
+            .vmux   = CX25840_VIN2_CH1,
+            .gpio0  = 0,
+        }, {
+            .type   = CX23885_VMUX_COMPOSITE3,
+            .vmux   = CX25840_VIN3_CH1,
+            .gpio0  = 0,
+        }, {
+            .type   = CX23885_VMUX_COMPOSITE4,
+            .vmux   = CX25840_VIN4_CH1,
+            .gpio0  = 0,
+        } },
+    },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -324,7 +362,23 @@
 		.subvendor = 0x14f1,
 		.subdevice = 0x8651,
 		.card      = CX23885_BOARD_MYGICA_X8506,
-	},
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8657,
+		.card      = CX23885_BOARD_MAGICPRO_PROHDTVE2,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8541,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1850,
+	}, {
+		.subvendor = 0x1858,
+		.subdevice = 0xe800,
+		.card      = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
+	}, {
+	    .subvendor = 0x0,
+        .subdevice = 0x0,
+        .card      = CX23885_BOARD_MPX885,
+    },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
 
@@ -483,8 +537,13 @@
 		/* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
 		 * DVB-T and MPEG2 HW Encoder */
 		break;
+	case 85021:
+		/* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM,
+			Dual channel ATSC and MPEG2 HW Encoder */
+		break;
 	default:
-		printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n",
+		printk(KERN_WARNING "%s: warning: "
+			"unknown hauppauge model #%d\n",
 			dev->name, tv.model);
 		break;
 	}
@@ -514,6 +573,7 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
 	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
 		/* Tuner Reset Command */
 		bitmask = 0x04;
 		break;
@@ -574,13 +634,23 @@
 		/* CX23417 GPIO's */
 		/* EIO15 Zilog Reset */
 		/* EIO14 S5H1409/CX24227 Reset */
+		mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+		/* Put the demod into reset and protect the eeprom */
+		mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Bring the demod and blaster out of reset */
+		mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
 
 		/* Force the TDA8295A into reset and back */
-		cx_set(GP0_IO, 0x00040004);
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_set(dev, GPIO_2);
 		mdelay(20);
-		cx_clear(GP0_IO, 0x00000004);
+		cx23885_gpio_clear(dev, GPIO_2);
 		mdelay(20);
-		cx_set(GP0_IO, 0x00040004);
+		cx23885_gpio_set(dev, GPIO_2);
 		mdelay(20);
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1200:
@@ -655,6 +725,7 @@
 		break;
 	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
 		/* GPIO-2  xc3028 tuner reset */
 
 		/* The following GPIO's are on the internal AVCore (cx25840) */
@@ -715,19 +786,82 @@
 		cx23885_gpio_set(dev, GPIO_9);
 		break;
 	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
 		/* GPIO-1 reset XC5000 */
-		/* GPIO-2 reset LGS8GL5 */
+		/* GPIO-2 reset LGS8GL5 / LGS8G75 */
 		cx_set(GP0_IO, 0x00060000);
 		cx_clear(GP0_IO, 0x00000006);
 		mdelay(100);
 		cx_set(GP0_IO, 0x00060006);
 		mdelay(100);
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		/* GPIO-0 656_CLK */
+		/* GPIO-1 656_D0 */
+		/* GPIO-2 Wake# */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+		/* GPIO-19 IR_RX */
+		/* GPIO-20 C_IR_TX */
+		/* GPIO-21 I2S DAT */
+		/* GPIO-22 I2S WCLK */
+		/* GPIO-23 I2S BCLK */
+		/* ALT GPIO: EXP GPIO LATCH */
+
+		/* CX23417 GPIO's */
+		/* GPIO-14 S5H1411/CX24228 Reset */
+		/* GPIO-13 EEPROM write protect */
+		mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
+
+		/* Put the demod into reset and protect the eeprom */
+		mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
+		mdelay(100);
+
+		/* Bring the demod out of reset */
+		mc417_gpio_set(dev, GPIO_14);
+		mdelay(100);
+
+		/* CX24228 GPIO */
+		/* Connected to IF / Mux */
+		break;
+    case CX23885_BOARD_MPX885:
+		/* GPIO-0 656_CLK */
+		/* GPIO-1 656_D0 */
+		/* GPIO-2 8295A Reset */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+		/* GPIO-19 IR_RX */
+
+		/* CX23417 GPIO's */
+		/* EIO15 Zilog Reset */
+		/* EIO14 S5H1409/CX24227 Reset */
+		mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+		/* Put the demod into reset and protect the eeprom */
+		mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Bring the demod and blaster out of reset */
+		mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Force the TDA8295A into reset and back */
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_set(dev, GPIO_2);
+		mdelay(20);
+		cx23885_gpio_clear(dev, GPIO_2);
+		mdelay(20);
+		cx23885_gpio_set(dev, GPIO_2);
+		mdelay(20);
+		break;
 	}
 }
 
 int cx23885_ir_init(struct cx23885_dev *dev)
 {
+	int ret = 0;
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
@@ -741,12 +875,43 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1210:
 		/* FIXME: Implement me */
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		ret = cx23888_ir_probe(dev);
+		if (ret)
+			break;
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+		dev->pci_irqmask |= PCI_MSK_IR;
+		break;
 	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
 		request_module("ir-kbd-i2c");
 		break;
+    case CX23885_BOARD_MPX885:
+        break;
 	}
 
-	return 0;
+	return ret;
+}
+
+void cx23885_ir_fini(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		dev->pci_irqmask &= ~PCI_MSK_IR;
+		cx_clear(PCI_INT_MSK, PCI_MSK_IR);
+		cx23888_ir_remove(dev);
+		dev->sd_ir = NULL;
+		break;
+	}
+}
+
+void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR))
+			cx_set(PCI_INT_MSK, PCI_MSK_IR);
+		break;
+	}
 }
 
 void cx23885_card_setup(struct cx23885_dev *dev)
@@ -778,9 +943,14 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1275:
 	case CX23885_BOARD_HAUPPAUGE_HVR1255:
 	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 		if (dev->i2c_bus[0].i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0xc0);
 		break;
+    case CX23885_BOARD_MPX885:
+		if (dev->i2c_bus[0].i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0xc0);
+        break;
 	}
 
 	switch (dev->board) {
@@ -827,10 +997,27 @@
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
 	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
 		ts1->gen_ctrl_val  = 0x5; /* Parallel */
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+    case CX23885_BOARD_MPX885:
+		/* Defaults for VID B - Analog encoder */
+		/* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+		ts1->gen_ctrl_val    = 0x10e;
+		ts1->ts_clk_en_val   = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val     = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+		/* APB_TSVALERR_POL (active low)*/
+		ts1->vld_misc_val    = 0x2000;
+		ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+
+		/* Defaults for VID C */
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+        break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -844,6 +1031,8 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1275:
 	case CX23885_BOARD_HAUPPAUGE_HVR1255:
 	case CX23885_BOARD_HAUPPAUGE_HVR1210:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
 	default:
 		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -860,11 +1049,21 @@
 	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
 	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[2].i2c_adap,
-				"cx25840", "cx25840", 0x88 >> 1);
+				"cx25840", "cx25840", 0x88 >> 1, NULL);
 		v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
 		break;
+    case CX23885_BOARD_MPX885:
+        
+		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_bus[2].i2c_adap,
+				"cx25840", "cx25840", 0x88 >> 1, NULL);
+		v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
+		
+        break;
 	}
 
 	/* AUX-PLL 27MHz CLK */
diff -u cx23885/cx23885-core.c cx23885-commell/cx23885-core.c
--- cx23885/cx23885-core.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-core.c	2009-11-11 09:36:16.000000000 +0100
@@ -28,10 +28,14 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include "compat.h"
 #include <asm/div64.h>
 
 #include "cx23885.h"
 #include "cimax2.h"
+#include "cx23888-ir.h"
+#include "cx23885-ir.h"
+#include "cx23885-input.h"
 
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -713,12 +717,26 @@
 		dev->hwrevision = 0xa1;
 		break;
 	case 0x02:
-		/* CX23885-13Z */
+		/* CX23885-13Z/14Z */
 		dev->hwrevision = 0xb0;
 		break;
 	case 0x03:
-		/* CX23888-22Z */
-		dev->hwrevision = 0xc0;
+		if (dev->pci->device == 0x8880) {
+			/* CX23888-21Z/22Z */
+			dev->hwrevision = 0xc0;
+		} else {
+			/* CX23885-14Z */
+			dev->hwrevision = 0xa4;
+		}
+		break;
+	case 0x04:
+		if (dev->pci->device == 0x8880) {
+			/* CX23888-31Z */
+			dev->hwrevision = 0xd0;
+		} else {
+			/* CX23885-15Z, CX23888-31Z */
+			dev->hwrevision = 0xa5;
+		}
 		break;
 	case 0x0e:
 		/* CX23887-15Z */
@@ -739,11 +757,29 @@
 			__func__, dev->hwrevision);
 }
 
+/* Find the first v4l2_subdev member of the group id in hw */
+struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw)
+{
+	struct v4l2_subdev *result = NULL;
+	struct v4l2_subdev *sd;
+
+	spin_lock(&dev->v4l2_dev.lock);
+	v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) {
+		if (sd->grp_id == hw) {
+			result = sd;
+			break;
+		}
+	}
+	spin_unlock(&dev->v4l2_dev.lock);
+	return result;
+}
+
 static int cx23885_dev_setup(struct cx23885_dev *dev)
 {
 	int i;
 
 	mutex_init(&dev->lock);
+	mutex_init(&dev->gpio_lock);
 
 	atomic_inc(&dev->refcount);
 
@@ -756,6 +792,7 @@
 
 	/* Configure the internal memory */
 	if (dev->pci->device == 0x8880) {
+		/* Could be 887 or 888, assume a default */
 		dev->bridge = CX23885_BRIDGE_887;
 		/* Apply a sensible clock frequency for the PCIe bridge */
 		dev->clk_freq = 25000000;
@@ -868,6 +905,14 @@
 	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
 		__func__, dev->radio_type, dev->radio_addr);
 
+	/* The cx23417 encoder has GPIO's that need to be initialised
+	 * before DVB, so that demodulators and tuners are out of
+	 * reset before DVB uses them.
+	 */
+	if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
+		(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
+			cx23885_mc417_init(dev);
+
 	/* init hardware */
 	cx23885_reset(dev);
 
@@ -1250,6 +1295,7 @@
 	switch (dev->bridge) {
 	case CX23885_BRIDGE_885:
 	case CX23885_BRIDGE_887:
+	case CX23885_BRIDGE_888:
 		/* enable irqs */
 		dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
 		cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
@@ -1292,6 +1338,12 @@
 		/* clear TS1_SOP_OE and TS1_OE_HI */
 		reg = reg & ~0xa;
 		cx_write(PAD_CTRL, reg);
+#if 0
+		/*
+		 * cx_write(CLK_DELAY, cx_read(CLK_DELAY) & ~0x80000011); ????
+		 * cx_write(ALT_PIN_OUT_SEL, 0x10100045); ?? need to undo this?
+		 */
+#endif
 		cx_write(port->reg_src_sel, 0);
 		cx_write(port->reg_gen_ctrl, 8);
 
@@ -1602,7 +1654,11 @@
 	return handled;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs)
+#else
 static irqreturn_t cx23885_irq(int irq, void *dev_id)
+#endif
 {
 	struct cx23885_dev *dev = dev_id;
 	struct cx23885_tsport *ts1 = &dev->ts1;
@@ -1612,6 +1668,7 @@
 	u32 ts1_status, ts1_mask;
 	u32 ts2_status, ts2_mask;
 	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+	bool ir_handled = false;
 
 	pci_status = cx_read(PCI_INT_STAT);
 	pci_mask = cx_read(PCI_INT_MSK);
@@ -1637,18 +1694,12 @@
 	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
 		ts2_status, ts2_mask, ts2_count);
 
-	if ((pci_status & PCI_MSK_RISC_RD) ||
-	    (pci_status & PCI_MSK_RISC_WR) ||
-	    (pci_status & PCI_MSK_AL_RD) ||
-	    (pci_status & PCI_MSK_AL_WR) ||
-	    (pci_status & PCI_MSK_APB_DMA) ||
-	    (pci_status & PCI_MSK_VID_C) ||
-	    (pci_status & PCI_MSK_VID_B) ||
-	    (pci_status & PCI_MSK_VID_A) ||
-	    (pci_status & PCI_MSK_AUD_INT) ||
-	    (pci_status & PCI_MSK_AUD_EXT) ||
-	    (pci_status & PCI_MSK_GPIO0) ||
-	    (pci_status & PCI_MSK_GPIO1)) {
+	if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
+			  PCI_MSK_AL_RD   | PCI_MSK_AL_WR   | PCI_MSK_APB_DMA |
+			  PCI_MSK_VID_C   | PCI_MSK_VID_B   | PCI_MSK_VID_A   |
+			  PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
+			  PCI_MSK_GPIO0   | PCI_MSK_GPIO1   |
+			  PCI_MSK_IR)) {
 
 		if (pci_status & PCI_MSK_RISC_RD)
 			dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
@@ -1697,6 +1748,10 @@
 		if (pci_status & PCI_MSK_GPIO1)
 			dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
 				PCI_MSK_GPIO1);
+
+		if (pci_status & PCI_MSK_IR)
+			dprintk(7, " (PCI_MSK_IR        0x%08x)\n",
+				PCI_MSK_IR);
 	}
 
 	if (cx23885_boards[dev->board].cimax > 0 &&
@@ -1727,12 +1782,55 @@
 	if (vida_status)
 		handled += cx23885_video_irq(dev, vida_status);
 
+	if (pci_status & PCI_MSK_IR) {
+		v4l2_subdev_call(dev->sd_ir, ir, interrupt_service_routine,
+				 pci_status, &ir_handled);
+		if (ir_handled)
+			handled++;
+	}
+
 	if (handled)
 		cx_write(PCI_INT_STAT, pci_status);
 out:
 	return IRQ_RETVAL(handled);
 }
 
+static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
+				    unsigned int notification, void *arg)
+{
+	struct cx23885_dev *dev;
+
+	if (sd == NULL)
+		return;
+
+	dev = to_cx23885(sd->v4l2_dev);
+
+	switch (notification) {
+	case V4L2_SUBDEV_IR_RX_NOTIFY: /* Called in an IRQ context */
+		if (sd == dev->sd_ir)
+			cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
+		break;
+	case V4L2_SUBDEV_IR_TX_NOTIFY: /* Called in an IRQ context */
+		if (sd == dev->sd_ir)
+			cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
+		break;
+	}
+}
+
+static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+	INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
+	INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
+#else
+	INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler,
+		  &dev->ir_rx_work);
+	INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler,
+		  &dev->ir_tx_work);
+#endif
+	dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
+}
+
 static inline int encoder_on_portb(struct cx23885_dev *dev)
 {
 	return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
@@ -1829,6 +1927,9 @@
 	if (err < 0)
 		goto fail_free;
 
+	/* Prepare to handle notifications from subdevices */
+	cx23885_v4l2_dev_notify_init(dev);
+
 	/* pci init */
 	dev->pci = pci_dev;
 	if (pci_enable_device(pci_dev)) {
@@ -1871,6 +1972,14 @@
 		break;
 	}
 
+	/*
+	 * The CX2388[58] IR controller can start firing interrupts when
+	 * enabled, so these have to take place after the cx23885_irq() handler
+	 * is hooked up by the call to request_irq() above.
+	 */
+	cx23885_ir_pci_int_enable(dev);
+	cx23885_input_init(dev);
+
 	return 0;
 
 fail_irq:
@@ -1887,6 +1996,9 @@
 	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
 	struct cx23885_dev *dev = to_cx23885(v4l2_dev);
 
+	cx23885_input_fini(dev);
+	cx23885_ir_fini(dev);
+
 	cx23885_shutdown(dev);
 
 	pci_disable_device(pci_dev);
diff -u cx23885/cx23885-dvb.c cx23885-commell/cx23885-dvb.c
--- cx23885/cx23885-dvb.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-dvb.c	2009-11-11 09:36:16.000000000 +0100
@@ -26,6 +26,7 @@
 #include <linux/kthread.h>
 #include <linux/file.h>
 #include <linux/suspend.h>
+#include "compat.h"
 
 #include "cx23885.h"
 #include <media/v4l2-common.h>
@@ -255,15 +256,18 @@
 static struct tda18271_config hauppauge_tda18271_config = {
 	.std_map = &hauppauge_tda18271_std_map,
 	.gate    = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
 };
 
 static struct tda18271_config hauppauge_hvr1200_tuner_config = {
 	.std_map = &hauppauge_hvr1200_tda18271_std_map,
 	.gate    = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
 };
 
 static struct tda18271_config hauppauge_hvr1210_tuner_config = {
 	.gate    = TDA18271_GATE_DIGITAL,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
 };
 
 static struct tda18271_std_map hauppauge_hvr127x_std_map = {
@@ -275,6 +279,7 @@
 
 static struct tda18271_config hauppauge_hvr127x_config = {
 	.std_map = &hauppauge_hvr127x_std_map,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
 };
 
 static struct lgdt3305_config hauppauge_lgdt3305_config = {
@@ -396,7 +401,7 @@
 
 static struct stv0900_config netup_stv0900_config = {
 	.demod_address = 0x68,
-	.xtal = 27000000,
+	.xtal = 8000000,
 	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
 	.diseqc_mode = 2,/* 2/3 PWM */
 	.ts_config_regs = stv0900_ts_regs,
@@ -408,14 +413,14 @@
 
 static struct stv6110_config netup_stv6110_tunerconfig_a = {
 	.i2c_address = 0x60,
-	.mclk = 27000000,
-	.iq_wiring = 0,
+	.mclk = 16000000,
+	.clk_div = 1,
 };
 
 static struct stv6110_config netup_stv6110_tunerconfig_b = {
 	.i2c_address = 0x63,
-	.mclk = 27000000,
-	.iq_wiring = 1,
+	.mclk = 16000000,
+	.clk_div = 1,
 };
 
 static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -483,10 +488,54 @@
 		}
 		break;
 	}
-	return (port->set_frontend_save) ?
-		port->set_frontend_save(fe, param) : -ENODEV;
+	return 0;
 }
 
+static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe,
+					 unsigned int cmd, void *parg,
+					 unsigned int stage)
+{
+	int err = 0;
+
+	switch (stage) {
+	case DVB_FE_IOCTL_PRE:
+
+		switch (cmd) {
+		case FE_SET_FRONTEND:
+			err = cx23885_dvb_set_frontend(fe,
+				(struct dvb_frontend_parameters *) parg);
+			break;
+		}
+		break;
+
+	case DVB_FE_IOCTL_POST:
+		/* no post-ioctl handling required */
+		break;
+	}
+	return err;
+};
+
+
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
+	.prod = LGS8GXX_PROD_LGS8G75,
+	.demod_address = 0x19,
+	.serial_ts = 0,
+	.ts_clk_pol = 1,
+	.ts_clk_gated = 1,
+	.if_clk_freq = 30400, /* 30.4 MHz */
+	.if_freq = 6500, /* 6.50 MHz */
+	.if_neg_center = 1,
+	.ext_adc = 0,
+	.adc_signed = 1,
+	.adc_vpp = 2, /* 1.6 Vpp */
+	.if_neg_edge = 1,
+};
+
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
+	.i2c_address = 0x61,
+	.if_khz = 6500,
+};
+
 static int dvb_register(struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
@@ -526,12 +575,6 @@
 				   0x60, &dev->i2c_bus[1].i2c_adap,
 				   &hauppauge_hvr127x_config);
 		}
-
-		/* FIXME: temporary hack */
-		/* define bridge override to set_frontend */
-		port->set_frontend_save = fe0->dvb.frontend->ops.set_frontend;
-		fe0->dvb.frontend->ops.set_frontend = cx23885_dvb_set_frontend;
-
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1255:
 		i2c_bus = &dev->i2c_bus[0];
@@ -574,6 +617,36 @@
 			break;
 		}
 		break;
+    case CX23885_BOARD_MPX885:
+		i2c_bus = &dev->i2c_bus[0];
+		switch (alt_tuner) {
+		case 1:
+			fe0->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_ezqam_config,
+					   &i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(tda829x_attach, fe0->dvb.frontend,
+					   &dev->i2c_bus[1].i2c_adap, 0x42,
+					   &tda829x_no_probe);
+				dvb_attach(tda18271_attach, fe0->dvb.frontend,
+					   0x60, &dev->i2c_bus[1].i2c_adap,
+					   &hauppauge_tda18271_config);
+			}
+			break;
+		case 0:
+		default:
+			fe0->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_generic_config,
+					   &i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL)
+				dvb_attach(mt2131_attach, fe0->dvb.frontend,
+					   &i2c_bus->i2c_adap,
+					   &hauppauge_generic_tunerconfig, 0);
+			break;
+		}
+        break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
 		i2c_bus = &dev->i2c_bus[0];
 		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
@@ -723,6 +796,7 @@
 	}
 	case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
 		i2c_bus = &dev->i2c_bus[0];
 
 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
@@ -833,6 +907,30 @@
 				&mygica_x8506_xc5000_config);
 		}
 		break;
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+		i2c_bus = &dev->i2c_bus[0];
+		i2c_bus2 = &dev->i2c_bus[1];
+		fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+			&magicpro_prohdtve2_lgs8g75_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(xc5000_attach,
+				fe0->dvb.frontend,
+				&i2c_bus2->i2c_adap,
+				&magicpro_prohdtve2_xc5000_config);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+		i2c_bus = &dev->i2c_bus[0];
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+			&hcw_s5h1411_config,
+			&i2c_bus->i2c_adap);
+		if (fe0->dvb.frontend != NULL)
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				0x60, &dev->i2c_bus[0].i2c_adap,
+				&hauppauge_tda18271_config);
+		break;
+
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
@@ -855,7 +953,8 @@
 
 	/* register everything */
 	ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
-		&dev->pci->dev, adapter_nr, 0);
+					&dev->pci->dev, adapter_nr, 0,
+					cx23885_dvb_fe_ioctl_override);
 
 	/* init CI & MAC */
 	switch (dev->board) {
diff -u cx23885/cx23885.h cx23885-commell/cx23885.h
--- cx23885/cx23885.h	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885.h	2009-11-11 09:36:20.000000000 +0100
@@ -29,6 +29,7 @@
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
+#include "compat.h"
 
 #include "btcx-risc.h"
 #include "cx23885-reg.h"
@@ -76,6 +77,10 @@
 #define CX23885_BOARD_HAUPPAUGE_HVR1255        20
 #define CX23885_BOARD_HAUPPAUGE_HVR1210        21
 #define CX23885_BOARD_MYGICA_X8506             22
+#define CX23885_BOARD_MAGICPRO_PROHDTVE2       23
+#define CX23885_BOARD_HAUPPAUGE_HVR1850        24
+#define CX23885_BOARD_COMPRO_VIDEOMATE_E800    25
+#define CX23885_BOARD_MPX885                26
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -87,6 +92,12 @@
 #define GPIO_7 0x00000080
 #define GPIO_8 0x00000100
 #define GPIO_9 0x00000200
+#define GPIO_10 0x00000400
+#define GPIO_11 0x00000800
+#define GPIO_12 0x00001000
+#define GPIO_13 0x00002000
+#define GPIO_14 0x00004000
+#define GPIO_15 0x00008000
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -288,10 +299,6 @@
 	/* Allow a single tsport to have multiple frontends */
 	u32                        num_frontends;
 	void                       *port_priv;
-
-	/* FIXME: temporary hack */
-	int (*set_frontend_save) (struct dvb_frontend *,
-				  struct dvb_frontend_parameters *);
 };
 
 struct cx23885_dev {
@@ -317,6 +324,7 @@
 
 	int                        nr;
 	struct mutex               lock;
+	struct mutex               gpio_lock;
 
 	/* board details */
 	unsigned int               board;
@@ -331,6 +339,7 @@
 		CX23885_BRIDGE_UNDEFINED = 0,
 		CX23885_BRIDGE_885 = 885,
 		CX23885_BRIDGE_887 = 887,
+		CX23885_BRIDGE_888 = 888,
 	} bridge;
 
 	/* Analog video */
@@ -345,6 +354,16 @@
 	unsigned int               has_radio;
 	struct v4l2_subdev 	   *sd_cx25840;
 
+	/* Infrared */
+	struct v4l2_subdev         *sd_ir;
+	struct work_struct	   ir_rx_work;
+	unsigned long		   ir_rx_notifications;
+	struct work_struct	   ir_tx_work;
+	unsigned long		   ir_tx_notifications;
+
+	struct card_ir		   *ir_input;
+	atomic_t		   ir_input_stopping;
+
 	/* V4l */
 	u32                        freq;
 	struct video_device        *video_dev;
@@ -372,6 +391,13 @@
 #define call_all(dev, o, f, args...) \
 	v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
 
+#define CX23885_HW_888_IR (1 << 0)
+
+#define call_hw(dev, grpid, o, f, args...) \
+	v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args)
+
+extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw);
+
 extern struct list_head cx23885_devlist;
 
 #define SRAM_CH01  0 /* Video A */
@@ -395,7 +421,7 @@
 	u32  cmds_start;
 	u32  ctrl_start;
 	u32  cdt;
-	u32  fifo_start;;
+	u32  fifo_start;
 	u32  fifo_size;
 	u32  ptr1_reg;
 	u32  ptr2_reg;
@@ -460,6 +486,8 @@
 	int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
+extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev);
+extern void cx23885_ir_fini(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
 extern void cx23885_card_setup(struct cx23885_dev *dev);
 extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
@@ -504,6 +532,13 @@
 extern void cx23885_mc417_init(struct cx23885_dev *dev);
 extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
 extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+extern int mc417_register_read(struct cx23885_dev *dev,
+				u16 address, u32 *value);
+extern int mc417_register_write(struct cx23885_dev *dev,
+				u16 address, u32 value);
+extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
 
 
 /* ----------------------------------------------------------- */
diff -u cx23885/cx23885-i2c.c cx23885-commell/cx23885-i2c.c
--- cx23885/cx23885-i2c.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-i2c.c	2009-11-11 09:36:16.000000000 +0100
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <asm/io.h>
 
+#include "compat.h"
 #include "cx23885.h"
 
 #include <media/v4l2-common.h>
@@ -276,6 +277,9 @@
 static struct i2c_algorithm cx23885_i2c_algo_template = {
 	.master_xfer	= i2c_xfer,
 	.functionality	= cx23885_functionality,
+#ifdef NEED_ALGO_CONTROL
+	.algo_control = dummy_algo_control,
+#endif
 };
 
 /* ----------------------------------------------------------------------- */
@@ -283,8 +287,13 @@
 static struct i2c_adapter cx23885_i2c_adap_template = {
 	.name              = "cx23885",
 	.owner             = THIS_MODULE,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
 	.id                = I2C_HW_B_CX23885,
+#endif
 	.algo              = &cx23885_i2c_algo_template,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+	.class             = I2C_CLASS_TV_ANALOG,
+#endif
 };
 
 static struct i2c_client cx23885_i2c_client_template = {
@@ -357,6 +366,7 @@
 		printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
 			dev->name, bus->nr);
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
 	/* Instantiate the IR receiver device, if present */
 	if (0 == bus->i2c_rc) {
 		struct i2c_board_info info;
@@ -369,6 +379,7 @@
 		i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
 	}
 
+#endif
 	return bus->i2c_rc;
 }
 
Nur in cx23885-commell: cx23885-input.c.
Nur in cx23885-commell: cx23885-input.h.
Nur in cx23885-commell: cx23885-ioctl.c.
Nur in cx23885-commell: cx23885-ioctl.h.
Nur in cx23885-commell: cx23885-ir.c.
Nur in cx23885-commell: cx23885-ir.h.
Nur in cx23885: cx23885.mod.c.
diff -u cx23885/cx23885-reg.h cx23885-commell/cx23885-reg.h
--- cx23885/cx23885-reg.h	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-reg.h	2009-11-11 09:36:20.000000000 +0100
@@ -212,8 +212,9 @@
 
 #define DEV_CNTRL2	0x00040000
 
-#define PCI_MSK_GPIO1   (1 << 24)
-#define PCI_MSK_GPIO0   (1 << 23)
+#define PCI_MSK_IR        (1 << 28)
+#define PCI_MSK_GPIO1     (1 << 24)
+#define PCI_MSK_GPIO0     (1 << 23)
 #define PCI_MSK_APB_DMA   (1 << 12)
 #define PCI_MSK_AL_WR     (1 << 11)
 #define PCI_MSK_AL_RD     (1 << 10)
diff -u cx23885/cx23885-vbi.c cx23885-commell/cx23885-vbi.c
--- cx23885/cx23885-vbi.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-vbi.c	2009-11-11 09:36:16.000000000 +0100
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 
+#include "compat.h"
 #include "cx23885.h"
 
 static unsigned int vbibufs = 4;
@@ -85,6 +86,19 @@
 	return 0;
 }
 
+#if 0
+/* not (yet) used */
+static int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
+{
+	/* stop dma */
+	cx_clear(VID_A_DMA_CTL, 0x00000022);
+
+	/* disable irqs */
+	cx_clear(PCI_INT_MSK, 0x000001);
+	cx_clear(VID_A_INT_MSK, 0x00000022);
+	return 0;
+}
+#endif
 
 static int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
 			     struct cx23885_dmaqueue *q)
diff -u cx23885/cx23885-video.c cx23885-commell/cx23885-video.c
--- cx23885/cx23885-video.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/cx23885-video.c	2009-11-11 09:36:16.000000000 +0100
@@ -29,12 +29,14 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include "compat.h"
 #include <linux/kthread.h>
 #include <asm/div64.h>
 
 #include "cx23885.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include "cx23885-ioctl.h"
 
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -80,51 +82,82 @@
 	{
 		.name     = "8 bpp, gray",
 		.fourcc   = V4L2_PIX_FMT_GREY,
+#if 0
+		.cxformat = ColorFormatY8,
+#endif
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "15 bpp RGB, le",
 		.fourcc   = V4L2_PIX_FMT_RGB555,
+#if 0
+		.cxformat = ColorFormatRGB15,
+#endif
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "15 bpp RGB, be",
 		.fourcc   = V4L2_PIX_FMT_RGB555X,
+#if 0
+		.cxformat = ColorFormatRGB15 | ColorFormatBSWAP,
+#endif
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "16 bpp RGB, le",
 		.fourcc   = V4L2_PIX_FMT_RGB565,
+#if 0
+		.cxformat = ColorFormatRGB16,
+#endif
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "16 bpp RGB, be",
 		.fourcc   = V4L2_PIX_FMT_RGB565X,
+#if 0
+		.cxformat = ColorFormatRGB16 | ColorFormatBSWAP,
+#endif
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "24 bpp RGB, le",
 		.fourcc   = V4L2_PIX_FMT_BGR24,
+#if 0
+		.cxformat = ColorFormatRGB24,
+#endif
 		.depth    = 24,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "32 bpp RGB, le",
 		.fourcc   = V4L2_PIX_FMT_BGR32,
+#if 0
+		.cxformat = ColorFormatRGB32,
+#endif
 		.depth    = 32,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "32 bpp RGB, be",
 		.fourcc   = V4L2_PIX_FMT_RGB32,
+#if 0
+		.cxformat = ColorFormatRGB32 | ColorFormatBSWAP |
+			ColorFormatWSWAP,
+#endif
 		.depth    = 32,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "4:2:2, packed, YUYV",
 		.fourcc   = V4L2_PIX_FMT_YUYV,
+#if 0
+		.cxformat = ColorFormatYUY2,
+#endif
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}, {
 		.name     = "4:2:2, packed, UYVY",
 		.fourcc   = V4L2_PIX_FMT_UYVY,
+#if 0
+		.cxformat = ColorFormatYUY2 | ColorFormatBSWAP,
+#endif
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},
@@ -248,6 +281,9 @@
 	V4L2_CID_SATURATION,
 	V4L2_CID_HUE,
 	V4L2_CID_AUDIO_VOLUME,
+#if 0
+	V4L2_CID_AUDIO_BALANCE,
+#endif
 	V4L2_CID_AUDIO_MUTE,
 	0
 };
@@ -404,6 +440,10 @@
 	/* Tell the internal A/V decoder */
 	v4l2_subdev_call(dev->sd_cx25840, video, s_routing,
 			INPUT(input)->vmux, 0, 0);
+#if 0
+	/* Let the AVCore default */
+	v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, 0, 0, 0);
+#endif
 
 	return 0;
 }
@@ -442,6 +482,22 @@
 	return 0;
 }
 
+#if 0
+#ifdef CONFIG_PM
+static int cx23885_stop_video_dma(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+	/* stop dma */
+	cx_clear(VID_A_DMA_CTL, 0x11);
+
+	/* disable irqs */
+	cx_clear(PCI_INT_MSK, 0x000001);
+	cx_clear(VID_A_INT_MSK, 0x000011);
+
+	return 0;
+}
+#endif
+#endif
 
 static int cx23885_restart_video_queue(struct cx23885_dev *dev,
 			       struct cx23885_dmaqueue *q)
@@ -765,6 +821,20 @@
 
 	dprintk(1, "post videobuf_queue_init()\n");
 
+#if 0
+	if (fh->radio) {
+		int board = dev->board;
+		dprintk(1, "video_open: setting radio device\n");
+		cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
+		cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0);
+		cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1);
+		cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2);
+		dev->tvaudio = WW_FM;
+		cx23885_set_tvaudio(dev);
+		cx23885_set_stereo(dev, V4L2_TUNER_MODE_STEREO, 1);
+		call_all(dev, tuner, s_radio);
+	}
+#endif
 	unlock_kernel();
 
 	return 0;
@@ -860,6 +930,9 @@
 	}
 
 	videobuf_mmap_free(&fh->vidq);
+#if 0
+	videobuf_mmap_free(&fh->vbiq);
+#endif
 	file->private_data = NULL;
 	kfree(fh);
 
@@ -867,6 +940,9 @@
 	 * we want to use the mpeg encoder in another session to capture
 	 * tuner video. Closing this will result in no video to the encoder.
 	 */
+#if 0
+	call_all(dev, tuner, s_standby);
+#endif
 
 	return 0;
 }
@@ -894,6 +970,9 @@
 {
 	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
 		" (disabled - no action)\n", __func__);
+#if 1
+	call_all(dev, core, s_ctrl, ctl);
+#endif
 	return 0;
 }
 
@@ -1007,6 +1086,9 @@
 	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
 	cap->version = CX23885_VERSION_CODE;
 	cap->capabilities =
+#if 0
+		V4L2_CAP_VIDEO_OVERLAY |
+#endif
 		V4L2_CAP_VIDEO_CAPTURE |
 		V4L2_CAP_READWRITE     |
 		V4L2_CAP_STREAMING     |
@@ -1243,6 +1325,9 @@
 	t->type       = V4L2_TUNER_ANALOG_TV;
 	t->capability = V4L2_TUNER_CAP_NORM;
 	t->rangehigh  = 0xffffffffUL;
+#if 0
+	cx23885_get_stereo(dev, t);
+#endif
 	t->signal = 0xffff ; /* LOCKED */
 	return 0;
 }
@@ -1256,6 +1341,9 @@
 		return -EINVAL;
 	if (0 != t->index)
 		return -EINVAL;
+#if 0
+	cx23885_set_stereo(dev, t->audmode, 1);
+#endif
 	return 0;
 }
 
@@ -1312,34 +1400,105 @@
 		cx23885_set_freq(dev, f);
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register(struct file *file, void *fh,
-				struct v4l2_dbg_register *reg)
+#if 0
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	strcpy(cap->driver, "cx23885");
+	strlcpy(cap->card, cx23885_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
+	cap->version = CX23885_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	if (unlikely(t->index > 0))
+		return -EINVAL;
+
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	call_all(dev, tuner, g_tuner, t);
+	return 0;
+}
 
-	if (!v4l2_chip_match_host(&reg->match))
+static int radio_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	if (i->index != 0)
 		return -EINVAL;
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
 
-	call_all(dev, core, g_register, reg);
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
 
+	memset(a, 0, sizeof(*a));
+	strcpy(a->name, "Radio");
 	return 0;
 }
 
-static int vidioc_s_register(struct file *file, void *fh,
-				struct v4l2_dbg_register *reg)
+/* FIXME: Should add a standard for radio */
+
+static int radio_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
-	if (!v4l2_chip_match_host(&reg->match))
+	if (0 != t->index)
 		return -EINVAL;
 
-	call_all(dev, core, s_register, reg);
+	call_all(dev, tuner, s_tuner, t);
 
 	return 0;
 }
-#endif
 
+static int radio_s_audio(struct file *file, void *fh,
+			  struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *c)
+{
+	int i;
+
+	if (c->id <  V4L2_CID_BASE ||
+		c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		for (i = 0; i < CX23885_CTLS; i++)
+			if (cx23885_ctls[i].v.id == c->id)
+				break;
+		*c = cx23885_ctls[i].v;
+	} else
+		*c = no_ctl;
+	return 0;
+}
+#endif
 /* ----------------------------------------------------------- */
 
 static void cx23885_vid_timeout(unsigned long data)
@@ -1395,6 +1554,16 @@
 		spin_unlock(&dev->slock);
 		handled++;
 	}
+#if 0
+	/* risc1 vbi */
+	if (status & 0x08) {
+		spin_lock(&dev->slock);
+		count = cx_read(MO_VBI_GPCNT);
+		cx88_wakeup(core, &dev->vbiq, count);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+#endif
 	/* risc2 y */
 	if (status & 0x10) {
 		dprintk(2, "stopper video\n");
@@ -1403,6 +1572,16 @@
 		spin_unlock(&dev->slock);
 		handled++;
 	}
+#if 0
+	/* risc2 vbi */
+	if (status & 0x80) {
+		dprintk(2, "stopper vbi\n");
+		spin_lock(&dev->slock);
+		cx8800_restart_vbi_queue(dev, &dev->vbiq);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+#endif
 
 	return handled;
 }
@@ -1449,9 +1628,10 @@
 	.vidioc_s_tuner       = vidioc_s_tuner,
 	.vidioc_g_frequency   = vidioc_g_frequency,
 	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_g_chip_ident  = cx23885_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register    = vidioc_g_register,
-	.vidioc_s_register    = vidioc_s_register,
+	.vidioc_g_register    = cx23885_g_register,
+	.vidioc_s_register    = cx23885_s_register,
 #endif
 };
 
@@ -1472,12 +1652,52 @@
 	.ioctl         = video_ioctl2,
 };
 
+#if 0
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+	.vidioc_querycap      = radio_querycap,
+	.vidioc_g_tuner       = radio_g_tuner,
+	.vidioc_enum_input    = radio_enum_input,
+	.vidioc_g_audio       = radio_g_audio,
+	.vidioc_s_tuner       = radio_s_tuner,
+	.vidioc_s_audio       = radio_s_audio,
+	.vidioc_s_input       = radio_s_input,
+	.vidioc_queryctrl     = radio_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+};
+
+static struct video_device cx23885_radio_template = {
+	.name                 = "cx23885-radio",
+	.fops                 = &radio_fops,
+	.ioctl_ops 	      = &radio_ioctl_ops,
+	.minor                = -1,
+};
+#endif
 
 void cx23885_video_unregister(struct cx23885_dev *dev)
 {
 	dprintk(1, "%s()\n", __func__);
 	cx_clear(PCI_INT_MSK, 1);
 
+#if 0
+	if (dev->radio_dev) {
+		if (-1 != dev->radio_dev->minor)
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		if (-1 != dev->vbi_dev->minor)
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+		btcx_riscmem_free(dev->pci, &dev->vbiq.stopper);
+	}
+#endif
 	if (dev->video_dev) {
 		if (-1 != dev->video_dev->minor)
 			video_unregister_device(dev->video_dev);
@@ -1513,6 +1733,16 @@
 		VID_A_DMA_CTL, 0x11, 0x00);
 
 	/* Don't enable VBI yet */
+#if 0
+	/* init vbi dma queues */
+	INIT_LIST_HEAD(&dev->vbiq.active);
+	INIT_LIST_HEAD(&dev->vbiq.queued);
+	dev->vbiq.timeout.function = cx23885_vbi_timeout;
+	dev->vbiq.timeout.data = (unsigned long)dev;
+	init_timer(&dev->vbiq.timeout);
+	cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper,
+		VID_A_DMA_CTL, 0x88, 0x00);
+#endif
 	cx_set(PCI_INT_MSK, 1);
 
 	if (TUNER_ABSENT != dev->tuner_type) {
@@ -1521,11 +1751,11 @@
 		if (dev->tuner_addr)
 			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[1].i2c_adap,
-				"tuner", "tuner", dev->tuner_addr);
+				"tuner", "tuner", dev->tuner_addr, NULL);
 		else
-			sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[1].i2c_adap,
-				"tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV));
+				"tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
 		if (sd) {
 			struct tuner_setup tun_setup;
 
@@ -1537,6 +1767,12 @@
 		}
 	}
 
+#if 0
+	if (cx23885_boards[dev->board].audio_chip == V4L2_IDENT_WM8775)
+		/* Must use v4l2_i2c_new_subdev instead of request_module
+		   once this is implemented for real. */
+		request_module("wm8775");
+#endif
 
 	/* register v4l devices */
 	dev->video_dev = cx23885_vdev_init(dev, dev->pci,
@@ -1550,6 +1786,33 @@
 	}
 	printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
 	       dev->name, dev->video_dev->num);
+#if 0
+	dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
+		&cx23885_vbi_template, "vbi");
+	err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+				    vbi_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s/0: can't register vbi device\n",
+			dev->name);
+		goto fail_unreg;
+	}
+	printk(KERN_INFO "%s/0: registered device vbi%d\n",
+	       dev->name, dev->vbi_dev->num);
+
+	if (dev->has_radio) {
+		dev->radio_dev = cx23885_vdev_init(dev, dev->pci,
+			&cx23885_radio_template, "radio");
+		err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+					    radio_nr[dev->nr]);
+		if (err < 0) {
+			printk(KERN_INFO "%s/0: can't register radio device\n",
+			       dev->name);
+			goto fail_unreg;
+		}
+		printk(KERN_INFO "%s/0: registered device radio%d\n",
+		       dev->name, dev->radio_dev->num);
+	}
+#endif
 	/* initial device configuration */
 	mutex_lock(&dev->lock);
 	cx23885_set_tvnorm(dev, dev->tvnorm);
Nur in cx23885-commell: cx23888-ir.c.
Nur in cx23885-commell: cx23888-ir.h.
diff -u cx23885/Makefile cx23885-commell/Makefile
--- cx23885/Makefile	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/Makefile	2009-10-25 08:18:46.000000000 +0100
@@ -1,5 +1,6 @@
 cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o \
 		    cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+		    cx23885-ioctl.o cx23885-ir.o cx23885-input.o cx23888-ir.o \
 		    netup-init.o cimax2.o netup-eeprom.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
Nur in cx23885: modules.order.
diff -u cx23885/netup-eeprom.c cx23885-commell/netup-eeprom.c
--- cx23885/netup-eeprom.c	2010-02-15 23:22:38.000000000 +0100
+++ cx23885-commell/netup-eeprom.c	2009-11-11 09:36:16.000000000 +0100
@@ -97,11 +97,21 @@
 {
 	int i, j;
 
-	cinfo->rev =  netup_eeprom_read(i2c_adap, 13);
+	cinfo->rev =  netup_eeprom_read(i2c_adap, 63);
 
-	for (i = 0, j = 0; i < 6; i++, j++)
+	for (i = 64, j = 0; i < 70; i++, j++)
 		cinfo->port[0].mac[j] =  netup_eeprom_read(i2c_adap, i);
 
-	for (i = 6, j = 0; i < 12; i++, j++)
+	for (i = 70, j = 0; i < 76; i++, j++)
 		cinfo->port[1].mac[j] =  netup_eeprom_read(i2c_adap, i);
+#if 0
+	printk(KERN_INFO "NetUP Dual DVB-S2 CI card rev=0x%x MAC1=%02X:%02X:"
+	"%02X:%02X:%02X:%02X MAC2=%02X:%02X:%02X:%02X:%02X:%02X\n", cinfo->rev,
+		cinfo->port[0].mac[0], cinfo->port[0].mac[1],
+		cinfo->port[0].mac[2], cinfo->port[0].mac[3],
+		cinfo->port[0].mac[4], cinfo->port[0].mac[5],
+		cinfo->port[1].mac[0], cinfo->port[1].mac[1],
+		cinfo->port[1].mac[2], cinfo->port[1].mac[3],
+		cinfo->port[1].mac[4], cinfo->port[1].mac[5]);
+#endif
 };


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:47                 ` cx23885 Michael
  2010-02-15 22:56                   ` cx23885 Michael
@ 2010-02-15 22:58                   ` Michael
  1 sibling, 0 replies; 19+ messages in thread
From: Michael @ 2010-02-15 22:58 UTC (permalink / raw)
  To: linux-media

[-- Attachment #1: Type: text/plain, Size: 129 bytes --]

And here the cx25840 diff, again commell versus 2.6.31.4.

P.S.: I will order a card now. Otherwise I can't test any patches...


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: cx25840-commell.diff --]
[-- Type: text/x-patch; name="cx25840-commell.diff", Size: 47692 bytes --]

diff -u cx25840/cx25840-audio.c cx25840-commell/cx25840-audio.c
--- cx25840/cx25840-audio.c	2010-02-15 23:23:01.000000000 +0100
+++ cx25840-commell/cx25840-audio.c	2009-11-11 09:36:38.000000000 +0100
@@ -20,90 +20,141 @@
 #include <linux/i2c.h>
 #include <media/v4l2-common.h>
 #include <media/cx25840.h>
+#include "compat.h"
 
 #include "cx25840-core.h"
 
-static int set_audclk_freq(struct i2c_client *client, u32 freq)
+/*
+ * Note: The PLL and SRC parameters are based on a reference frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * However, it's not the exact reference frequency that matters, only that the
+ * firmware and modules that comprise the driver for a particular board all
+ * use the same value (close to the ideal value).
+ *
+ * Comments below will note which reference frequency is assumed for various
+ * parameters.  They will usually be one of
+ *
+ *	ref_freq = 28.636360 MHz
+ *		or
+ *	ref_freq = 28.636363 MHz
+ */
+
+static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
 {
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
-	if (freq != 32000 && freq != 44100 && freq != 48000)
-		return -EINVAL;
-
-	/* common for all inputs and rates */
-	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
-	if (!state->is_cx23885 && !state->is_cx231xx)
-		cx25840_write(client, 0x127, 0x50);
-
 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		switch (freq) {
 		case 32000:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1006040f);
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x1006040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x1bb39ee
+			 * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
+			 * 196.6 MHz pre-postdivide
+			 * FIXME < 200 MHz is out of specified valid range
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x01bb39ee);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
 
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x01bb39ee);
-			}
-
-			if (state->is_cx25836)
+			if (is_cx2583x(state))
 				break;
 
-			/* src3/4/6_ctl = 0x0801f77f */
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
 			cx25840_write4(client, 0x900, 0x0801f77f);
 			cx25840_write4(client, 0x904, 0x0801f77f);
 			cx25840_write4(client, 0x90c, 0x0801f77f);
 			break;
 
 		case 44100:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1009040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x00ec6bd6);
-			}
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x1009040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x0ec6bd6
+			 * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
+			 * 271 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
 
-			if (state->is_cx25836)
+			if (is_cx2583x(state))
 				break;
 
-			/* src3/4/6_ctl = 0x08016d59 */
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
 			cx25840_write4(client, 0x900, 0x08016d59);
 			cx25840_write4(client, 0x904, 0x08016d59);
 			cx25840_write4(client, 0x90c, 0x08016d59);
 			break;
 
 		case 48000:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x100a040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x0098d6e5);
-			}
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x100a040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x098d6e5
+			 * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
+			 * 295 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x0098d6e5);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
 
-			if (state->is_cx25836)
+			if (is_cx2583x(state))
 				break;
 
-			/* src3/4/6_ctl = 0x08014faa */
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
 			cx25840_write4(client, 0x900, 0x08014faa);
 			cx25840_write4(client, 0x904, 0x08014faa);
 			cx25840_write4(client, 0x90c, 0x08014faa);
@@ -112,91 +163,249 @@
 	} else {
 		switch (freq) {
 		case 32000:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1e08040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x012a0869);
-			}
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
+			 */
+			cx25840_write4(client, 0x108, 0x1e08040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x12a0869
+			 * 28636363 * 0x8.9504348/0x1e = 32000 * 256
+			 * 246 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x012a0869);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x54);
 
-			if (state->is_cx25836)
+			if (is_cx2583x(state))
 				break;
 
-			/* src1_ctl = 0x08010000 */
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
 			cx25840_write4(client, 0x8f8, 0x08010000);
 
-			/* src3/4/6_ctl = 0x08020000 */
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
 			cx25840_write4(client, 0x900, 0x08020000);
 			cx25840_write4(client, 0x904, 0x08020000);
 			cx25840_write4(client, 0x90c, 0x08020000);
-
-			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
-			cx25840_write(client, 0x127, 0x54);
 			break;
 
 		case 44100:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
+			 */
+			cx25840_write4(client, 0x108, 0x1809040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x0ec6bd6
+			 * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
+			 * 271 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
 				break;
-			}
 
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
+			cx25840_write4(client, 0x8f8, 0x080160cd);
+
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
+			cx25840_write4(client, 0x900, 0x08017385);
+			cx25840_write4(client, 0x904, 0x08017385);
+			cx25840_write4(client, 0x90c, 0x08017385);
+			break;
+
+		case 48000:
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
+			 */
+			cx25840_write4(client, 0x108, 0x180a040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x098d6e5
+			 * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
+			 * 295 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x0098d6e5);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
+
+			/* src1_ctl */
+			/* 0x1.8000 = 48000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08018000);
+
+			/* src3/4/6_ctl */
+			/* 0x1.5555 = 2 * (32000/48000) */
+			cx25840_write4(client, 0x900, 0x08015555);
+			cx25840_write4(client, 0x904, 0x08015555);
+			cx25840_write4(client, 0x90c, 0x08015555);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
 
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1809040f);
+	return 0;
+}
 
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x00ec6bd6);
-			}
+static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	return cx25840_set_audclk_freq(client, freq);
+}
 
-			if (state->is_cx25836)
-				break;
+static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+		case 44100:
+		case 48000:
+			/* We don't have register values
+			 * so avoid destroying registers. */
+			/* FIXME return -EINVAL; */
+			break;
+		}
+	} else {
+		switch (freq) {
+		case 32000:
+		case 44100:
+			/* We don't have register values
+			 * so avoid destroying registers. */
+			/* FIXME return -EINVAL; */
+			break;
+
+		case 48000:
+			/* src1_ctl */
+			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
+			cx25840_write4(client, 0x8f8, 0x0801867c);
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
+			cx25840_write4(client, 0x900, 0x0801f77f);
+			cx25840_write4(client, 0x904, 0x0801f77f);
+			cx25840_write4(client, 0x90c, 0x0801f77f);
+			break;
+
+		case 44100:
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
+			cx25840_write4(client, 0x900, 0x08016d59);
+			cx25840_write4(client, 0x904, 0x08016d59);
+			cx25840_write4(client, 0x90c, 0x08016d59);
+			break;
+
+		case 48000:
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	} else {
+		switch (freq) {
+		/* FIXME These cases make different assumptions about audclk */
+		case 32000:
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08010000);
 
-			/* src1_ctl = 0x08010000 */
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
+			cx25840_write4(client, 0x900, 0x08020000);
+			cx25840_write4(client, 0x904, 0x08020000);
+			cx25840_write4(client, 0x90c, 0x08020000);
+			break;
+
+		case 44100:
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
 			cx25840_write4(client, 0x8f8, 0x080160cd);
 
-			/* src3/4/6_ctl = 0x08020000 */
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
 			cx25840_write4(client, 0x900, 0x08017385);
 			cx25840_write4(client, 0x904, 0x08017385);
 			cx25840_write4(client, 0x90c, 0x08017385);
 			break;
 
 		case 48000:
-			if (!state->is_cx23885 && !state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x180a040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x0098d6e5);
-			}
-
-			if (state->is_cx25836)
-				break;
+			/* src1_ctl */
+			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
+			cx25840_write4(client, 0x8f8, 0x0801867c);
 
-			if (!state->is_cx23885 && !state->is_cx231xx) {
-				/* src1_ctl */
-				cx25840_write4(client, 0x8f8, 0x08018000);
-
-				/* src3/4/6_ctl */
-				cx25840_write4(client, 0x900, 0x08015555);
-				cx25840_write4(client, 0x904, 0x08015555);
-				cx25840_write4(client, 0x90c, 0x08015555);
-			} else {
-
-				cx25840_write4(client, 0x8f8, 0x0801867c);
-
-				cx25840_write4(client, 0x900, 0x08014faa);
-				cx25840_write4(client, 0x904, 0x08014faa);
-				cx25840_write4(client, 0x90c, 0x08014faa);
-			}
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
 			break;
 		}
 	}
@@ -206,6 +415,25 @@
 	return 0;
 }
 
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (freq != 32000 && freq != 44100 && freq != 48000)
+		return -EINVAL;
+
+	if (is_cx231xx(state))
+		return cx231xx_set_audclk_freq(client, freq);
+
+	if (is_cx2388x(state))
+		return cx23885_set_audclk_freq(client, freq);
+
+	if (is_cx2583x(state))
+		return cx25836_set_audclk_freq(client, freq);
+
+	return cx25840_set_audclk_freq(client, freq);
+}
+
 void cx25840_audio_set_path(struct i2c_client *client)
 {
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
@@ -243,7 +471,7 @@
 	cx25840_and_or(client, 0x810, ~0x1, 0x00);
 
 	/* Ensure the controller is running when we exit */
-	if (state->is_cx23885 || state->is_cx231xx)
+	if (is_cx2388x(state) || is_cx231xx(state))
 		cx25840_and_or(client, 0x803, ~0x10, 0x10);
 }
 
@@ -383,7 +611,7 @@
 	struct cx25840_state *state = to_state(sd);
 	int retval;
 
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		cx25840_and_or(client, 0x810, ~0x1, 1);
 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		cx25840_and_or(client, 0x803, ~0x10, 0);
@@ -392,7 +620,7 @@
 	retval = set_audclk_freq(client, freq);
 	if (state->aud_input != CX25840_AUDIO_SERIAL)
 		cx25840_and_or(client, 0x803, ~0x10, 0x10);
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		cx25840_and_or(client, 0x810, ~0x1, 0);
 	return retval;
 }
diff -u cx25840/cx25840-core.c cx25840-commell/cx25840-core.c
--- cx25840/cx25840-core.c	2010-02-15 23:23:00.000000000 +0100
+++ cx25840-commell/cx25840-core.c	2011-10-13 00:03:10.000000000 +0200
@@ -41,6 +41,7 @@
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 #include <media/cx25840.h>
+#include "compat.h"
 
 #include "cx25840-core.h"
 
@@ -54,6 +55,11 @@
 
 MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+#endif
 
 /* ----------------------------------------------------------------------- */
 
@@ -178,10 +184,16 @@
 	cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 static void cx25840_work_handler(struct work_struct *work)
 {
 	struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
-	cx25840_loadfw(state->c);
+#else
+static void cx25840_work_handler(void *arg)
+{
+	struct cx25840_state *state = arg;
+#endif
+//	cx25840_loadfw(state->c);
 	wake_up(&state->fw_wait);
 }
 
@@ -209,7 +221,11 @@
 	   Otherwise the kernel is blocked waiting for the
 	   bit-banging i2c interface to finish uploading the
 	   firmware. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
+#else
+	INIT_WORK(&state->fw_work, cx25840_work_handler, state);
+#endif
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
 	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
@@ -258,29 +274,237 @@
 	DEFINE_WAIT(wait);
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 	struct workqueue_struct *q;
+    int value;
+    int orig_3d_comb;
 
-	/* Internal Reset */
-	cx25840_and_or(client, 0x102, ~0x01, 0x01);
-	cx25840_and_or(client, 0x102, ~0x01, 0x00);
-
-	/* Stop microcontroller */
-	cx25840_and_or(client, 0x803, ~0x10, 0x00);
+    orig_3d_comb = cx25840_read4(client, 0x478);
+    orig_3d_comb &= 0x11000000;
 
-	/* DIF in reset? */
-	cx25840_write(client, 0x398, 0);
+      cx25840_write(client, 0x000, 0);
+    
+      /* Internal Reset */
+      cx25840_and_or(client, 0x102, ~0x01, 0x01);
+      cx25840_and_or(client, 0x102, ~0x01, 0x00);
+      /* Stop microcontroller */
+    cx25840_and_or(client, 0x803, ~0x10, 0x00);
+    
+      /* DIF in reset? */
+      cx25840_write(client, 0x398, 0);
+    
+// autodetect
+    value = cx25840_read4(client, 0x15c);
+    value &= 0xffffc7ff;
+    value |= 0x00001000;
+    cx25840_write4(client, 0x15c, value);
+
+    value = cx25840_read4(client, 0x13c);
+    value |= 0x00000001;
+    cx25840_write4(client, 0x13c, value);
+    value &= 0xfffffffe;
+    cx25840_write4(client, 0x13c, value);
+    //reset thresher
+    cx25840_write4(client, 0x4a4, 0x8000);
+    cx25840_write4(client, 0x4a4, 0x0);
+    //restore video muted
+    cx25840_write(client, 0x414, 0x0);
+    cx25840_write(client, 0x420, 0x0);
+    cx25840_write(client, 0x421, 0x0);
+    cx25840_write(client, 0x415, 0x0);
+    
+    value = cx25840_read4(client, 0x498);
+    value &= 0xfff00000;
+    value |= 0x00000802;
+    cx25840_write4(client, 0x498, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    value |= 0x00000020;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffe7ff;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x494);
+    value &= 0xffff0000;
+    value |= 0x00001000;
+    cx25840_write4(client, 0x494, value);
+
+    value = cx25840_read4(client, 0x420);
+    value &= 0xdfffffff;
+    cx25840_write4(client, 0x420, value);
+
+    value = cx25840_read4(client, 0x404);
+    value &= 0xfffffffc;
+    value |= 0x00000003;
+    cx25840_write4(client, 0x404, value);
+
+    value = cx25840_read4(client, 0x404);
+    value &= 0xfffffff7;
+    value |= 0x00000008;
+    cx25840_write4(client, 0x404, value);
+
+//set input mux 0x0502 channel 0x0201
+    value = cx25840_read4(client, 0x100);
+    value &= 0x00E9FFFF;
+	value |= 0x11100000;
+    cx25840_write4(client, 0x100, value);
+    value = cx25840_read4(client, 0x100);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xfffffff0;
+    value |= 0x00000005;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    value |= 0x00000020;
+    cx25840_write4(client, 0x400, value);
+
+    //3d comb
+    cx25840_write4(client, 0x490, 0xcd3f0288);  
+
+//do mode ctrl[S]
+    value = cx25840_read4(client, 0x474);
+    value &= 0xfffffc00;
+    value |= 0x00000024;
+    cx25840_write4(client, 0x474, value);
+/*    value = cx25840_read4(client, 0x474);
+    value &= 0xffc00fff;
+    value |= 0x001e6000;
+    cx25840_write4(client, 0x474, value);
+    value = cx25840_read4(client, 0x474);
+    value &= 0x00ffffff;
+    value |= 0x1e000000;
+    cx25840_write4(client, 0x474, value);
+*/
+    value = cx25840_read4(client, 0x470);
+    value &= 0xfffffc00;
+    value |= 0x00000089;
+    cx25840_write4(client, 0x470, value);
+//do mode ctrl[E]
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xfffffff0;
+    value |= 0x00000004;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    value |= 0x00000020;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x478);
+    value &= 0x3fffffff;
+    value |= orig_3d_comb;    
+    cx25840_write4(client, 0x478, value);
+
+    //do mode ctrl   
+    value = cx25840_read4(client, 0x490);
+    value &= 0xfffffffc;
+    cx25840_write4(client, 0x490, value);
+
+    value = cx25840_read4(client, 0x474);
+    value &= 0xfffffc00;
+    value |= 0x00000024;
+    cx25840_write4(client, 0x474, value);
+/*    value = cx25840_read4(client, 0x474);
+    value &= 0xffc00fff;
+    value |= 0x001e6000;
+    cx25840_write4(client, 0x474, value);
+    value = cx25840_read4(client, 0x474);
+    value &= 0x00ffffff;
+    value |= 0x1e000000;
+    cx25840_write4(client, 0x474, value);
+*/
+    value = cx25840_read4(client, 0x470);
+    value &= 0xfffffc00;
+    value |= 0x00000089;
+    cx25840_write4(client, 0x470, value);
+    
+    //brightness
+	cx25840_write(client, 0x414, 0);
+    //contrast
+	cx25840_write(client, 0x415, 0x80);
+    //sharpness
+	cx25840_write(client, 0x416, 0);
+    //saturation
+	cx25840_write(client, 0x420, 0x80);
+	cx25840_write(client, 0x421, 0x80);
+    //hue
+	cx25840_write(client, 0x422, 0);
+	cx25840_write4(client, 0x418, 0);
+	cx25840_write4(client, 0x41c, 0);
+	cx25840_write4(client, 0x100, 0x11100000);
+    cx25840_write4(client, 0x400, 0xe021);
+    cx25840_write4(client, 0x400, 0xe021);
+    cx25840_write4(client, 0x104, 0x704dd80);
+/*     cx25840_write4(client, 0x490, 0xcd3f0288);
+//do mode ctrl 
+   cx25840_write4(client, 0x474, 0x1e1e601a);
+    cx25840_write4(client, 0x474, 0x1e1e601a);
+    cx25840_write4(client, 0x474, 0x1e1e601a);
+    cx25840_write4(client, 0x470, 0x5b2d007f);
+    cx25840_write4(client, 0x49c, 0x20504014);
+    cx25840_write4(client, 0x498, 0x802);
+    cx25840_write4(client, 0x498, 0x802);
+*/
+    cx25840_write4(client, 0x160, 0x1d);
+    cx25840_write4(client, 0x164, 0x2);
+#if 1 //wpwp
+	/*
+	 * Come out of digital power down
+	 * The CX23888, at least, needs this, otherwise registers aside from
+	 * 0x0-0x2 can't be read or written.
+	 */
 
-	/* Trust the default xtal, no division */
-	/* This changes for the cx23888 products */
-	cx25840_write(client, 0x2, 0x76);
+	/*
+	 * Trust the default xtal, no division
+	 * '885: 28.636363... MHz
+	 * '887: 25.000000 MHz
+	 * '888: 50.000000 MHz
+	 */
+	cx25840_write(client, 0x2, 0x77);
 
-	/* Bring down the regulator for AUX clk */
+	/* Power up all the PLL's and DLL */
 	cx25840_write(client, 0x1, 0x40);
 
-	/* Sys PLL frac */
-	cx25840_write4(client, 0x11c, 0x01d1744c);
-
-	/* Sys PLL int */
-	cx25840_write4(client, 0x118, 0x00000416);
+	/* Sys PLL */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/*
+		 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x00e8ba26);
+		cx25840_write4(client, 0x118, 0x0000040b);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		/*
+		 * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x01d1744c);
+		cx25840_write4(client, 0x118, 0x00000416);
+		break;
+	case V4L2_IDENT_CX23885_AV:
+	default:
+		/*
+		 * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x00CCCCCC);
+		cx25840_write4(client, 0x118, 0x00000414);
+		break;
+	}
 
 	/* Disable DIF bypass */
 	cx25840_write4(client, 0x33c, 0x00000001);
@@ -288,11 +512,17 @@
 	/* DIF Src phase inc */
 	cx25840_write4(client, 0x340, 0x0df7df83);
 
-	/* Vid PLL frac */
-	cx25840_write4(client, 0x10c, 0x01b6db7b);
-
-	/* Vid PLL int */
-	cx25840_write4(client, 0x108, 0x00000512);
+	/*
+	 * Vid PLL
+	 * Setup for a BT.656 pixel clock of 13.5 Mpixels/second
+	 *
+	 * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
+	 * 432.0 MHz before post divide
+	 */
+	cx25840_write4(client, 0x10c, 0x002be2c9);
+	cx25840_write4(client, 0x108, 0x0000040f);
+    cx25840_write4(client, 0x10c, 0x01B6DB7B);
+    cx25840_write4(client, 0x108, 0x00000512);
 
 	/* Luma */
 	cx25840_write4(client, 0x414, 0x00107d12);
@@ -300,11 +530,43 @@
 	/* Chroma */
 	cx25840_write4(client, 0x420, 0x3d008282);
 
-	/* Aux PLL frac */
-	cx25840_write4(client, 0x114, 0x017dbf48);
-
-	/* Aux PLL int */
-	cx25840_write4(client, 0x110, 0x000a030e);
+	/*
+	 * Aux PLL
+	 * Initial setup for audio sample clock:
+	 * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz
+	 * Intial I2S output/master clock(?):
+	 * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
+	 */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/*
+		 * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x00bedfa4);
+		cx25840_write4(client, 0x110, 0x000a0307);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		/*
+		 * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x017dbf48);
+		cx25840_write4(client, 0x110, 0x000a030e);
+		break;
+	case V4L2_IDENT_CX23885_AV:
+	default:
+		/*
+		 * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x01bf0c9e);
+		cx25840_write4(client, 0x110, 0x000a030c);
+		break;
+	};
 
 	/* ADC2 input select */
 	cx25840_write(client, 0x102, 0x10);
@@ -314,6 +576,10 @@
 
 	/* Enable format auto detect */
 	cx25840_write(client, 0x400, 0);
+#if 0
+	/* Force to NTSC-M and Disable autoconf regs */
+	cx25840_write(client, 0x400, 0x21);
+#endif
 	/* Fast subchroma lock */
 	/* White crush, Chroma AGC & Chroma Killer enabled */
 	cx25840_write(client, 0x401, 0xe8);
@@ -321,11 +587,25 @@
 	/* Select AFE clock pad output source */
 	cx25840_write(client, 0x144, 0x05);
 
+	/* Drive GPIO2 direction and values for HVR1700
+	 * where an onboard mux selects the output of demodulator
+	 * vs the 417. Failure to set this results in no DTV.
+	 * It's safe to set this across all Hauppauge boards
+	 * currently, regardless of the board type.
+	 */
+	cx25840_write(client, 0x160, 0x1d);
+
+	cx25840_write(client, 0x164, 0x02);
+#endif
 	/* Do the firmware load in a work handler to prevent.
 	   Otherwise the kernel is blocked waiting for the
 	   bit-banging i2c interface to finish uploading the
 	   firmware. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
+#else
+	INIT_WORK(&state->fw_work, cx25840_work_handler, state);
+#endif
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
 	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
@@ -334,10 +614,10 @@
 	finish_wait(&state->fw_wait, &wait);
 	destroy_workqueue(q);
 
-	cx25840_std_setup(client);
+//	cx25840_std_setup(client);
 
 	/* (re)set input */
-	set_input(client, state->vid_input, state->aud_input);
+//	set_input(client, state->vid_input, state->aud_input);
 
 	/* start microcontroller */
 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
@@ -388,6 +668,10 @@
 
 	/* Enable format auto detect */
 	cx25840_write(client, 0x400, 0);
+#if 0
+	/* Force to NTSC-M and Disable autoconf regs */
+	cx25840_write(client, 0x400, 0x21);
+#endif
 	/* Fast subchroma lock */
 	/* White crush, Chroma AGC & Chroma Killer enabled */
 	cx25840_write(client, 0x401, 0xe8);
@@ -396,7 +680,11 @@
 	   Otherwise the kernel is blocked waiting for the
 	   bit-banging i2c interface to finish uploading the
 	   firmware. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
+#else
+	INIT_WORK(&state->fw_work, cx25840_work_handler, state);
+#endif
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
 	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
@@ -405,7 +693,7 @@
 	finish_wait(&state->fw_wait, &wait);
 	destroy_workqueue(q);
 
-	cx25840_std_setup(client);
+//	cx25840_std_setup(client);
 
 	/* (re)set input */
 	set_input(client, state->vid_input, state->aud_input);
@@ -485,13 +773,10 @@
 	}
 
 	/* DEBUG: Displays configured PLL frequency */
-	if (!state->is_cx231xx) {
+	if (!is_cx231xx(state)) {
 		pll_int = cx25840_read(client, 0x108);
 		pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
 		pll_post = cx25840_read(client, 0x109);
-		v4l_dbg(1, cx25840_debug, client,
-			"PLL regs = int: %u, frac: %u, post: %u\n",
-			pll_int, pll_frac, pll_post);
 
 		if (pll_post) {
 			int fin, fsc;
@@ -629,7 +914,7 @@
 	v4l_dbg(1, cx25840_debug, client,
 		"decoder set video input %d, audio input %d\n",
 		vid_input, aud_input);
-
+#if 1 //wpwp
 	if (vid_input >= CX25840_VIN1_CH1) {
 		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
 			vid_input);
@@ -669,7 +954,7 @@
 	 * configuration in reg (for the cx23885) so we have no
 	 * need to attempt to flip bits for earlier av decoders.
 	 */
-	if (!state->is_cx23885 && !state->is_cx231xx) {
+	if (!is_cx2388x(state) && !is_cx231xx(state)) {
 		switch (aud_input) {
 		case CX25840_AUDIO_SERIAL:
 			/* do nothing, use serial audio input */
@@ -692,31 +977,38 @@
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
 	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
 
-	if (!state->is_cx23885 && !state->is_cx231xx) {
+	if (!is_cx2388x(state) && !is_cx231xx(state)) {
 		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 0x12 : 0x10);
 		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
 		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-			cx25840_and_or(client, 0x102, ~0x4, 4);
+			cx25840_and_or(client, 0x102, ~0x4, 0x14);
 		else
-			cx25840_and_or(client, 0x102, ~0x4, 0);
+			cx25840_and_or(client, 0x102, ~0x4, 0x10);
 	} else {
 		if (is_composite)
 			/* ADC2 input select channel 2 */
-			cx25840_and_or(client, 0x102, ~0x2, 0);
+			cx25840_and_or(client, 0x102, ~0x2, 0x10);
 		else
 			/* ADC2 input select channel 3 */
-			cx25840_and_or(client, 0x102, ~0x2, 2);
+			cx25840_and_or(client, 0x102, ~0x2, 0x12);
 	}
 
+//	cx25840_and_or(client, 0x400, 0xffffffdf, 0x20);
+//	cx25840_and_or(client, 0x400, 0xfffff9ff, 0);
+
+    
+//	cx25840_and_or(client, 0x490, 0xfffffffc, 0);
+//	cx25840_and_or(client, 0x474, 0xfffffc00, 0x24);
+//	cx25840_and_or(client, 0x470, 0xfffffc00, 0x89);
 	state->vid_input = vid_input;
 	state->aud_input = aud_input;
-	if (!state->is_cx25836) {
+	if (!is_cx2583x(state)) {
 		cx25840_audio_set_path(client);
 		input_change(client);
 	}
 
-	if (state->is_cx23885) {
+	if (is_cx2388x(state)) {
 		/* Audio channel 1 src : Parallel 1 */
 		cx25840_write(client, 0x124, 0x03);
 
@@ -732,7 +1024,7 @@
 		 */
 		cx25840_write(client, 0x918, 0xa0);
 		cx25840_write(client, 0x919, 0x01);
-	} else if (state->is_cx231xx) {
+	} else if (is_cx231xx(state)) {
 		/* Audio channel 1 src : Parallel 1 */
 		cx25840_write(client, 0x124, 0x03);
 
@@ -746,7 +1038,7 @@
 		cx25840_write(client, 0x918, 0xa0);
 		cx25840_write(client, 0x919, 0x01);
 	}
-
+#endif
 	return 0;
 }
 
@@ -757,7 +1049,7 @@
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 	u8 fmt = 0; 	/* zero is autodetect */
 	u8 pal_m = 0;
-
+#if 1
 	/* First tests should be against specific std */
 	if (state->std == V4L2_STD_NTSC_M_JP) {
 		fmt = 0x2;
@@ -796,8 +1088,9 @@
 	cx25840_and_or(client, 0x400, ~0xf, fmt);
 	cx25840_and_or(client, 0x403, ~0x3, pal_m);
 	cx25840_std_setup(client);
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		input_change(client);
+#endif    
 	return 0;
 }
 
@@ -846,12 +1139,12 @@
 		break;
 
 	case V4L2_CID_HUE:
-		if (ctrl->value < -128 || ctrl->value > 127) {
+		if (ctrl->value < 0 || ctrl->value > 255) {
 			v4l_err(client, "invalid hue setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
-		cx25840_write(client, 0x422, ctrl->value);
+		cx25840_write(client, 0x422, ctrl->value - 128 );
 		break;
 
 	case V4L2_CID_AUDIO_VOLUME:
@@ -859,7 +1152,7 @@
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
-		if (state->is_cx25836)
+		if (is_cx2583x(state))
 			return -EINVAL;
 		return cx25840_audio_s_ctrl(sd, ctrl);
 
@@ -889,14 +1182,14 @@
 		ctrl->value = cx25840_read(client, 0x420) >> 1;
 		break;
 	case V4L2_CID_HUE:
-		ctrl->value = (s8)cx25840_read(client, 0x422);
+		ctrl->value = (s8)cx25840_read(client, 0x422) + 128;
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
-		if (state->is_cx25836)
+		if (is_cx2583x(state))
 			return -EINVAL;
 		return cx25840_audio_g_ctrl(sd, ctrl);
 	default:
@@ -1200,11 +1493,11 @@
 	if (!state->is_initialized) {
 		/* initialize and load firmware */
 		state->is_initialized = 1;
-		if (state->is_cx25836)
+		if (is_cx2583x(state))
 			cx25836_initialize(client);
-		else if (state->is_cx23885)
+		else if (is_cx2388x(state))
 			cx23885_initialize(client);
-		else if (state->is_cx231xx)
+		else if (is_cx231xx(state))
 			cx231xx_initialize(client);
 		else
 			cx25840_initialize(client);
@@ -1247,17 +1540,17 @@
 	v4l_dbg(1, cx25840_debug, client, "%s output\n",
 			enable ? "enable" : "disable");
 	if (enable) {
-		if (state->is_cx23885 || state->is_cx231xx) {
+		if (is_cx2388x(state) || is_cx231xx(state)) {
 			u8 v = (cx25840_read(client, 0x421) | 0x0b);
 			cx25840_write(client, 0x421, v);
 		} else {
 			cx25840_write(client, 0x115,
-					state->is_cx25836 ? 0x0c : 0x8c);
+					is_cx2583x(state) ? 0x0c : 0x8c);
 			cx25840_write(client, 0x116,
-					state->is_cx25836 ? 0x04 : 0x07);
+					is_cx2583x(state) ? 0x04 : 0x07);
 		}
 	} else {
-		if (state->is_cx23885 || state->is_cx231xx) {
+		if (is_cx2388x(state) || is_cx231xx(state)) {
 			u8 v = cx25840_read(client, 0x421) & ~(0x0b);
 			cx25840_write(client, 0x421, v);
 		} else {
@@ -1283,7 +1576,7 @@
 	default:
 		break;
 	}
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		return -EINVAL;
 
 	switch (qc->id) {
@@ -1337,7 +1630,7 @@
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		return -EINVAL;
 	return set_input(client, state->vid_input, input);
 }
@@ -1347,7 +1640,7 @@
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		input_change(client);
 	return 0;
 }
@@ -1364,7 +1657,7 @@
 		return 0;
 
 	vt->signal = vpres ? 0xffff : 0x0;
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		return 0;
 
 	vt->capability |=
@@ -1395,7 +1688,7 @@
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (state->radio || state->is_cx25836)
+	if (state->radio || is_cx2583x(state))
 		return 0;
 
 	switch (vt->audmode) {
@@ -1436,11 +1729,11 @@
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		cx25836_initialize(client);
-	else if (state->is_cx23885)
+	else if (is_cx2388x(state))
 		cx23885_initialize(client);
-	else if (state->is_cx231xx)
+	else if (is_cx231xx(state))
 		cx231xx_initialize(client);
 	else
 		cx25840_initialize(client);
@@ -1461,7 +1754,7 @@
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	log_video_status(client);
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		log_audio_status(client);
 	return 0;
 }
@@ -1512,12 +1805,50 @@
 
 /* ----------------------------------------------------------------------- */
 
+static u32 get_cx2388x_ident(struct i2c_client *client)
+{
+	u32 ret;
+
+	/* Come out of digital power down */
+	cx25840_write(client, 0x000, 0);
+
+	/* Detecting whether the part is cx23885/7/8 is more
+	 * difficult than it needs to be. No ID register. Instead we
+	 * probe certain registers indicated in the datasheets to look
+	 * for specific defaults that differ between the silicon designs. */
+
+	/* It's either 885/7 if the IR Tx Clk Divider register exists */
+	if (cx25840_read4(client, 0x204) & 0xffff) {
+		/* CX23885 returns bogus repetitive byte values for the DIF,
+		 * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */
+		ret = cx25840_read4(client, 0x300);
+		if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
+			/* No DIF */
+			ret = V4L2_IDENT_CX23885_AV;
+		} else {
+			/* CX23887 has a broken DIF, but the registers
+			 * appear valid (but unsed), good enough to detect. */
+			ret = V4L2_IDENT_CX23887_AV;
+		}
+	} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
+		/* DIF PLL Freq Word reg exists; chip must be a CX23888 */
+		ret = V4L2_IDENT_CX23888_AV;
+	} else {
+		v4l_err(client, "Unable to detect h/w, assuming cx23887\n");
+		ret = V4L2_IDENT_CX23887_AV;
+	}
+
+	/* Back into digital power down */
+	cx25840_write(client, 0x000, 2);
+	return ret;
+}
+
 static int cx25840_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct cx25840_state *state;
 	struct v4l2_subdev *sd;
-	u32 id;
+	u32 id = V4L2_IDENT_NONE;
 	u16 device_id;
 
 	/* Check if the adapter supports the needed features */
@@ -1534,17 +1865,22 @@
 	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
 	if ((device_id & 0xff00) == 0x8300) {
 		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
-	}
-	else if ((device_id & 0xff00) == 0x8400) {
+	} else if ((device_id & 0xff00) == 0x8400) {
 		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
 	} else if (device_id == 0x0000) {
-		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
-	} else if (device_id == 0x1313) {
-		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+		id = get_cx2388x_ident(client);
 	} else if ((device_id & 0xfff0) == 0x5A30) {
-		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
-	}
-	else {
+		/* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
+		id = V4L2_IDENT_CX2310X_AV;
+	} else if ((device_id & 0xff) == (device_id >> 8)) {
+		v4l_err(client,
+			"likely a confused/unresponsive cx2388[578] A/V decoder"
+			" found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+		v4l_err(client, "A method to reset it from the cx25840 driver"
+			" software is not known at this time\n");
+		return -ENODEV;
+	} else {
 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
 		return -ENODEV;
 	}
@@ -1555,18 +1891,46 @@
 
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
-	/* Note: revision '(device_id & 0x0f) == 2' was never built. The
-	   marking skips from 0x1 == 22 to 0x3 == 23. */
-	v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
-		    (device_id & 0xfff0) >> 4,
-		    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
-		    client->addr << 1, client->adapter->name);
+	switch (id) {
+	case V4L2_IDENT_CX23885_AV:
+		v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX23888_AV:
+		v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX2310X_AV:
+		v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
+			 device_id, client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX25840:
+	case V4L2_IDENT_CX25841:
+	case V4L2_IDENT_CX25842:
+	case V4L2_IDENT_CX25843:
+		/* Note: revision '(device_id & 0x0f) == 2' was never built. The
+		   marking skips from 0x1 == 22 to 0x3 == 23. */
+		v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
+			 (device_id & 0xfff0) >> 4,
+			 (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1
+						: (device_id & 0x0f),
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX25836:
+	case V4L2_IDENT_CX25837:
+	default:
+		v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
+			 (device_id & 0xfff0) >> 4, device_id & 0x0f,
+			 client->addr << 1, client->adapter->name);
+		break;
+	}
 
 	state->c = client;
-	state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
-	state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
-	state->is_cx231xx = (device_id == 0x5a3e);
-	state->vid_input = CX25840_COMPOSITE7;
+	state->vid_input = CX25840_COMPOSITE1;
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
 	state->pvr150_workaround = 0;
@@ -1578,12 +1942,6 @@
 	state->id = id;
 	state->rev = device_id;
 
-	if (state->is_cx23885) {
-		/* Drive GPIO2 direction and values */
-		cx25840_write(client, 0x160, 0x1d);
-		cx25840_write(client, 0x164, 0x00);
-	}
-
 	return 0;
 }
 
@@ -1596,15 +1954,19 @@
 	return 0;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
 static const struct i2c_device_id cx25840_id[] = {
 	{ "cx25840", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, cx25840_id);
 
+#endif
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 	.name = "cx25840",
 	.probe = cx25840_probe,
 	.remove = cx25840_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
 	.id_table = cx25840_id,
+#endif
 };
diff -u cx25840/cx25840-core.h cx25840-commell/cx25840-core.h
--- cx25840/cx25840-core.h	2010-02-15 23:23:00.000000000 +0100
+++ cx25840-commell/cx25840-core.h	2009-11-11 09:36:36.000000000 +0100
@@ -20,9 +20,11 @@
 #ifndef _CX25840_CORE_H_
 #define _CX25840_CORE_H_
 
+#include "compat.h"
 
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
 #include <linux/i2c.h>
 
 /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
@@ -48,9 +50,6 @@
 	int vbi_line_offset;
 	u32 id;
 	u32 rev;
-	int is_cx25836;
-	int is_cx23885;
-	int is_cx231xx;
 	int is_initialized;
 	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
 	struct work_struct fw_work;   /* work entry for fw load */
@@ -61,6 +60,24 @@
 	return container_of(sd, struct cx25840_state, sd);
 }
 
+static inline bool is_cx2583x(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX25836 ||
+	       state->id == V4L2_IDENT_CX25837;
+}
+
+static inline bool is_cx231xx(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX2310X_AV;
+}
+
+static inline bool is_cx2388x(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX23885_AV ||
+	       state->id == V4L2_IDENT_CX23887_AV ||
+	       state->id == V4L2_IDENT_CX23888_AV;
+}
+
 /* ----------------------------------------------------------------------- */
 /* cx25850-core.c 							   */
 int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
diff -u cx25840/cx25840-firmware.c cx25840-commell/cx25840-firmware.c
--- cx25840/cx25840-firmware.c	2010-02-15 23:23:01.000000000 +0100
+++ cx25840-commell/cx25840-firmware.c	2009-11-11 09:36:38.000000000 +0100
@@ -20,13 +20,10 @@
 #include <linux/firmware.h>
 #include <media/v4l2-common.h>
 #include <media/cx25840.h>
+#include "compat.h"
 
 #include "cx25840-core.h"
 
-#define FWFILE "v4l-cx25840.fw"
-#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
-#define FWFILE_CX231XX "v4l-cx231xx-avcore-01.fw"
-
 /*
  * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
  * size of the firmware chunks sent down the I2C bus to the chip.
@@ -40,11 +37,11 @@
 
 #define FWDEV(x) &((x)->dev)
 
-static char *firmware = FWFILE;
+static char *firmware = "";
 
 module_param(firmware, charp, 0444);
 
-MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
+MODULE_PARM_DESC(firmware, "Firmware image to load");
 
 static void start_fw_load(struct i2c_client *client)
 {
@@ -65,6 +62,19 @@
 	cx25840_write(client, 0x803, 0x03);
 }
 
+static const char *get_fw_name(struct i2c_client *client)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (firmware[0])
+		return firmware;
+	if (is_cx2388x(state))
+		return "v4l-cx23885-avcore-01.fw";
+	if (is_cx231xx(state))
+		return "v4l-cx231xx-avcore-01.fw";
+	return "v4l-cx25840.fw";
+}
+
 static int check_fw_load(struct i2c_client *client, int size)
 {
 	/* DL_ADDR_HB DL_ADDR_LB */
@@ -72,11 +82,13 @@
 	s |= cx25840_read(client, 0x800);
 
 	if (size != s) {
-		v4l_err(client, "firmware %s load failed\n", firmware);
+		v4l_err(client, "firmware %s load failed\n",
+				get_fw_name(client));
 		return -EINVAL;
 	}
 
-	v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size);
+	v4l_info(client, "loaded %s firmware (%d bytes)\n",
+			get_fw_name(client), size);
 	return 0;
 }
 
@@ -96,26 +108,29 @@
 	const struct firmware *fw = NULL;
 	u8 buffer[FWSEND];
 	const u8 *ptr;
+	const char *fwname = get_fw_name(client);
 	int size, retval;
 	int MAX_BUF_SIZE = FWSEND;
+	u32 gpio_oe = 0, gpio_da = 0;
 
-	if (state->is_cx23885)
-		firmware = FWFILE_CX23885;
-	else if (state->is_cx231xx)
-		firmware = FWFILE_CX231XX;
+	if (is_cx2388x(state)) {
+		/* Preserve the GPIO OE and output bits */
+		gpio_oe = cx25840_read(client, 0x160);
+		gpio_da = cx25840_read(client, 0x164);
+	}
 
-	if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) {
+	if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
 		v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
 		MAX_BUF_SIZE = 16;  /* cx231xx cannot accept more than 16 bytes at a time */
 	}
 
-	if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
-		v4l_err(client, "unable to open firmware %s\n", firmware);
+	if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
+		v4l_err(client, "unable to open firmware %s\n", fwname);
 		return -EINVAL;
 	}
 
 	start_fw_load(client);
-
+#if 0
 	buffer[0] = 0x08;
 	buffer[1] = 0x02;
 
@@ -136,11 +151,17 @@
 		size -= len;
 		ptr += len;
 	}
-
+#endif
 	end_fw_load(client);
 
 	size = fw->size;
 	release_firmware(fw);
 
+	if (is_cx2388x(state)) {
+		/* Restore GPIO configuration after f/w load */
+		cx25840_write(client, 0x160, gpio_oe);
+		cx25840_write(client, 0x164, gpio_da);
+	}
+
 	return check_fw_load(client, size);
 }
Nur in cx25840: cx25840.mod.c.
diff -u cx25840/cx25840-vbi.c cx25840-commell/cx25840-vbi.c
--- cx25840/cx25840-vbi.c	2010-02-15 23:23:01.000000000 +0100
+++ cx25840-commell/cx25840-vbi.c	2009-11-11 09:36:38.000000000 +0100
@@ -20,6 +20,7 @@
 #include <linux/i2c.h>
 #include <media/v4l2-common.h>
 #include <media/cx25840.h>
+#include "compat.h"
 
 #include "cx25840-core.h"
 
Nur in cx25840: modules.order.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:56                   ` cx23885 Michael
@ 2010-02-15 23:00                     ` Steven Toth
  2010-02-15 23:22                     ` cx23885 Ralph Siemsen
  1 sibling, 0 replies; 19+ messages in thread
From: Steven Toth @ 2010-02-15 23:00 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

On 2/15/10 5:56 PM, Michael wrote:
> Well, this did not work. The cx23885 driver was not included in kernel
> 2.6.21, so no diff. The diff of the 2.6.21 cx25840 is twice as big as the
> 2.6.31 diff. :-(
>
> If anybody can give me a hint, what to include in a patch and what was old
> stuff that has jsut changed in 2.6.31, I'd be grateful.
>
> Attached is the diff of cx23885, the commell version against kernel
> 2.6.31.4.
>
>>
>> I'm downloading kernel 2.6.21 now and make a diff with these drivers.
>>

Start by patching the current cx23885 driver with all of the switch statements 
related to the new board CX23885_BOARD_MPX885.

-cards.c -core.c etc.

I already see some issues in their MPX885 additions, driving wrong gpios and 
assuming the encoder is attached - but it's a good start.

-- 
Steven Toth - Kernel Labs
http://www.kernellabs.com
+1.646.355.8490


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:56                   ` cx23885 Michael
  2010-02-15 23:00                     ` cx23885 Steven Toth
@ 2010-02-15 23:22                     ` Ralph Siemsen
  2010-02-16  0:36                       ` cx23885 Andy Walls
  1 sibling, 1 reply; 19+ messages in thread
From: Ralph Siemsen @ 2010-02-15 23:22 UTC (permalink / raw)
  To: Michael; +Cc: linux-media

[-- Attachment #1: Type: text/plain, Size: 749 bytes --]

On Mon, Feb 15, 2010 at 11:56:52PM +0100, Michael wrote:
> 
> If anybody can give me a hint, what to include in a patch and what was old 
> stuff that has jsut changed in 2.6.31, I'd be grateful.

Their source tree contains a .hg_archival.txt file which looks like
it can be used to identify the original v4l-dvb tree they used.

Attached is a diff from that v4l version to the MPX-885 tree.
 cx23885/cx23885-cards.c    |   90 ++++++++++++++++
 cx23885/cx23885-dvb.c      |   30 +++++
 cx23885/cx23885-video.c    |    2 
 cx23885/cx23885.h          |    1 
 cx25840/cx25840-core.c     |  248 +++++++++++++++++++++++++++++++++++++++------
 cx25840/cx25840-firmware.c |    4 
 6 files changed, 338 insertions(+), 37 deletions(-)

Hope it helps...
-R


[-- Attachment #2: MPX-885.patch --]
[-- Type: text/plain, Size: 19073 bytes --]

diff -uNr v4l-dvb/linux/drivers/media/video/cx23885/cx23885-cards.c MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885-cards.c
--- v4l-dvb/linux/drivers/media/video/cx23885/cx23885-cards.c	2010-02-15 18:19:26.000000000 -0500
+++ MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885-cards.c	2009-11-11 09:36:16.000000000 -0500
@@ -216,6 +216,29 @@
 		.name		= "Compro VideoMate E800",
 		.portc		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_MPX885] = {
+	    .name       = "MPX-885",
+        .porta      = CX23885_ANALOG_VIDEO,
+        .portb      = CX23885_MPEG_ENCODER,
+        .portc      = CX23885_MPEG_DVB,
+        .input          = {{
+            .type   = CX23885_VMUX_COMPOSITE1,
+            .vmux   = CX25840_VIN1_CH1,
+            .gpio0  = 0,
+        }, {
+            .type   = CX23885_VMUX_COMPOSITE2,
+            .vmux   = CX25840_VIN2_CH1,
+            .gpio0  = 0,
+        }, {
+            .type   = CX23885_VMUX_COMPOSITE3,
+            .vmux   = CX25840_VIN3_CH1,
+            .gpio0  = 0,
+        }, {
+            .type   = CX23885_VMUX_COMPOSITE4,
+            .vmux   = CX25840_VIN4_CH1,
+            .gpio0  = 0,
+        } },
+    },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -351,7 +374,11 @@
 		.subvendor = 0x1858,
 		.subdevice = 0xe800,
 		.card      = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
-	},
+	}, {
+	    .subvendor = 0x0,
+        .subdevice = 0x0,
+        .card      = CX23885_BOARD_MPX885,
+    },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
 
@@ -798,6 +825,37 @@
 		/* CX24228 GPIO */
 		/* Connected to IF / Mux */
 		break;
+    case CX23885_BOARD_MPX885:
+		/* GPIO-0 656_CLK */
+		/* GPIO-1 656_D0 */
+		/* GPIO-2 8295A Reset */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+		/* GPIO-19 IR_RX */
+
+		/* CX23417 GPIO's */
+		/* EIO15 Zilog Reset */
+		/* EIO14 S5H1409/CX24227 Reset */
+		mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+		/* Put the demod into reset and protect the eeprom */
+		mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Bring the demod and blaster out of reset */
+		mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+		mdelay(100);
+
+		/* Force the TDA8295A into reset and back */
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_set(dev, GPIO_2);
+		mdelay(20);
+		cx23885_gpio_clear(dev, GPIO_2);
+		mdelay(20);
+		cx23885_gpio_set(dev, GPIO_2);
+		mdelay(20);
+		break;
 	}
 }
 
@@ -827,6 +885,8 @@
 	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
 		request_module("ir-kbd-i2c");
 		break;
+    case CX23885_BOARD_MPX885:
+        break;
 	}
 
 	return ret;
@@ -887,6 +947,10 @@
 		if (dev->i2c_bus[0].i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0xc0);
 		break;
+    case CX23885_BOARD_MPX885:
+		if (dev->i2c_bus[0].i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0xc0);
+        break;
 	}
 
 	switch (dev->board) {
@@ -938,6 +1002,22 @@
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+    case CX23885_BOARD_MPX885:
+		/* Defaults for VID B - Analog encoder */
+		/* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+		ts1->gen_ctrl_val    = 0x10e;
+		ts1->ts_clk_en_val   = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val     = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+		/* APB_TSVALERR_POL (active low)*/
+		ts1->vld_misc_val    = 0x2000;
+		ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+
+		/* Defaults for VID C */
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+        break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -976,6 +1056,14 @@
 				"cx25840", "cx25840", 0x88 >> 1, NULL);
 		v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
 		break;
+    case CX23885_BOARD_MPX885:
+        
+		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_bus[2].i2c_adap,
+				"cx25840", "cx25840", 0x88 >> 1, NULL);
+		v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
+		
+        break;
 	}
 
 	/* AUX-PLL 27MHz CLK */
diff -uNr v4l-dvb/linux/drivers/media/video/cx23885/cx23885-dvb.c MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885-dvb.c
--- v4l-dvb/linux/drivers/media/video/cx23885/cx23885-dvb.c	2010-02-15 18:19:26.000000000 -0500
+++ MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885-dvb.c	2009-11-11 09:36:16.000000000 -0500
@@ -617,6 +617,36 @@
 			break;
 		}
 		break;
+    case CX23885_BOARD_MPX885:
+		i2c_bus = &dev->i2c_bus[0];
+		switch (alt_tuner) {
+		case 1:
+			fe0->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_ezqam_config,
+					   &i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(tda829x_attach, fe0->dvb.frontend,
+					   &dev->i2c_bus[1].i2c_adap, 0x42,
+					   &tda829x_no_probe);
+				dvb_attach(tda18271_attach, fe0->dvb.frontend,
+					   0x60, &dev->i2c_bus[1].i2c_adap,
+					   &hauppauge_tda18271_config);
+			}
+			break;
+		case 0:
+		default:
+			fe0->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_generic_config,
+					   &i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL)
+				dvb_attach(mt2131_attach, fe0->dvb.frontend,
+					   &i2c_bus->i2c_adap,
+					   &hauppauge_generic_tunerconfig, 0);
+			break;
+		}
+        break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
 		i2c_bus = &dev->i2c_bus[0];
 		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
diff -uNr v4l-dvb/linux/drivers/media/video/cx23885/cx23885.h MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885.h
--- v4l-dvb/linux/drivers/media/video/cx23885/cx23885.h	2010-02-15 18:19:26.000000000 -0500
+++ MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885.h	2009-11-11 09:36:20.000000000 -0500
@@ -80,6 +80,7 @@
 #define CX23885_BOARD_MAGICPRO_PROHDTVE2       23
 #define CX23885_BOARD_HAUPPAUGE_HVR1850        24
 #define CX23885_BOARD_COMPRO_VIDEOMATE_E800    25
+#define CX23885_BOARD_MPX885                26
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
diff -uNr v4l-dvb/linux/drivers/media/video/cx23885/cx23885-video.c MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885-video.c
--- v4l-dvb/linux/drivers/media/video/cx23885/cx23885-video.c	2010-02-15 18:19:26.000000000 -0500
+++ MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx23885/cx23885-video.c	2009-11-11 09:36:16.000000000 -0500
@@ -970,7 +970,7 @@
 {
 	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
 		" (disabled - no action)\n", __func__);
-#if 0
+#if 1
 	call_all(dev, core, s_ctrl, ctl);
 #endif
 	return 0;
diff -uNr v4l-dvb/linux/drivers/media/video/cx25840/cx25840-core.c MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx25840/cx25840-core.c
--- v4l-dvb/linux/drivers/media/video/cx25840/cx25840-core.c	2010-02-15 18:19:26.000000000 -0500
+++ MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx25840/cx25840-core.c	2011-10-13 00:03:10.000000000 -0400
@@ -193,7 +193,7 @@
 {
 	struct cx25840_state *state = arg;
 #endif
-	cx25840_loadfw(state->c);
+//	cx25840_loadfw(state->c);
 	wake_up(&state->fw_wait);
 }
 
@@ -274,23 +274,197 @@
 	DEFINE_WAIT(wait);
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 	struct workqueue_struct *q;
+    int value;
+    int orig_3d_comb;
 
+    orig_3d_comb = cx25840_read4(client, 0x478);
+    orig_3d_comb &= 0x11000000;
+
+      cx25840_write(client, 0x000, 0);
+    
+      /* Internal Reset */
+      cx25840_and_or(client, 0x102, ~0x01, 0x01);
+      cx25840_and_or(client, 0x102, ~0x01, 0x00);
+      /* Stop microcontroller */
+    cx25840_and_or(client, 0x803, ~0x10, 0x00);
+    
+      /* DIF in reset? */
+      cx25840_write(client, 0x398, 0);
+    
+// autodetect
+    value = cx25840_read4(client, 0x15c);
+    value &= 0xffffc7ff;
+    value |= 0x00001000;
+    cx25840_write4(client, 0x15c, value);
+
+    value = cx25840_read4(client, 0x13c);
+    value |= 0x00000001;
+    cx25840_write4(client, 0x13c, value);
+    value &= 0xfffffffe;
+    cx25840_write4(client, 0x13c, value);
+    //reset thresher
+    cx25840_write4(client, 0x4a4, 0x8000);
+    cx25840_write4(client, 0x4a4, 0x0);
+    //restore video muted
+    cx25840_write(client, 0x414, 0x0);
+    cx25840_write(client, 0x420, 0x0);
+    cx25840_write(client, 0x421, 0x0);
+    cx25840_write(client, 0x415, 0x0);
+    
+    value = cx25840_read4(client, 0x498);
+    value &= 0xfff00000;
+    value |= 0x00000802;
+    cx25840_write4(client, 0x498, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    value |= 0x00000020;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffe7ff;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x494);
+    value &= 0xffff0000;
+    value |= 0x00001000;
+    cx25840_write4(client, 0x494, value);
+
+    value = cx25840_read4(client, 0x420);
+    value &= 0xdfffffff;
+    cx25840_write4(client, 0x420, value);
+
+    value = cx25840_read4(client, 0x404);
+    value &= 0xfffffffc;
+    value |= 0x00000003;
+    cx25840_write4(client, 0x404, value);
+
+    value = cx25840_read4(client, 0x404);
+    value &= 0xfffffff7;
+    value |= 0x00000008;
+    cx25840_write4(client, 0x404, value);
+
+//set input mux 0x0502 channel 0x0201
+    value = cx25840_read4(client, 0x100);
+    value &= 0x00E9FFFF;
+	value |= 0x11100000;
+    cx25840_write4(client, 0x100, value);
+    value = cx25840_read4(client, 0x100);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xfffffff0;
+    value |= 0x00000005;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    value |= 0x00000020;
+    cx25840_write4(client, 0x400, value);
+
+    //3d comb
+    cx25840_write4(client, 0x490, 0xcd3f0288);  
+
+//do mode ctrl[S]
+    value = cx25840_read4(client, 0x474);
+    value &= 0xfffffc00;
+    value |= 0x00000024;
+    cx25840_write4(client, 0x474, value);
+/*    value = cx25840_read4(client, 0x474);
+    value &= 0xffc00fff;
+    value |= 0x001e6000;
+    cx25840_write4(client, 0x474, value);
+    value = cx25840_read4(client, 0x474);
+    value &= 0x00ffffff;
+    value |= 0x1e000000;
+    cx25840_write4(client, 0x474, value);
+*/
+    value = cx25840_read4(client, 0x470);
+    value &= 0xfffffc00;
+    value |= 0x00000089;
+    cx25840_write4(client, 0x470, value);
+//do mode ctrl[E]
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xfffffff0;
+    value |= 0x00000004;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x400);
+    value &= 0xffffffdf;
+    value |= 0x00000020;
+    cx25840_write4(client, 0x400, value);
+
+    value = cx25840_read4(client, 0x478);
+    value &= 0x3fffffff;
+    value |= orig_3d_comb;    
+    cx25840_write4(client, 0x478, value);
+
+    //do mode ctrl   
+    value = cx25840_read4(client, 0x490);
+    value &= 0xfffffffc;
+    cx25840_write4(client, 0x490, value);
+
+    value = cx25840_read4(client, 0x474);
+    value &= 0xfffffc00;
+    value |= 0x00000024;
+    cx25840_write4(client, 0x474, value);
+/*    value = cx25840_read4(client, 0x474);
+    value &= 0xffc00fff;
+    value |= 0x001e6000;
+    cx25840_write4(client, 0x474, value);
+    value = cx25840_read4(client, 0x474);
+    value &= 0x00ffffff;
+    value |= 0x1e000000;
+    cx25840_write4(client, 0x474, value);
+*/
+    value = cx25840_read4(client, 0x470);
+    value &= 0xfffffc00;
+    value |= 0x00000089;
+    cx25840_write4(client, 0x470, value);
+    
+    //brightness
+	cx25840_write(client, 0x414, 0);
+    //contrast
+	cx25840_write(client, 0x415, 0x80);
+    //sharpness
+	cx25840_write(client, 0x416, 0);
+    //saturation
+	cx25840_write(client, 0x420, 0x80);
+	cx25840_write(client, 0x421, 0x80);
+    //hue
+	cx25840_write(client, 0x422, 0);
+	cx25840_write4(client, 0x418, 0);
+	cx25840_write4(client, 0x41c, 0);
+	cx25840_write4(client, 0x100, 0x11100000);
+    cx25840_write4(client, 0x400, 0xe021);
+    cx25840_write4(client, 0x400, 0xe021);
+    cx25840_write4(client, 0x104, 0x704dd80);
+/*     cx25840_write4(client, 0x490, 0xcd3f0288);
+//do mode ctrl 
+   cx25840_write4(client, 0x474, 0x1e1e601a);
+    cx25840_write4(client, 0x474, 0x1e1e601a);
+    cx25840_write4(client, 0x474, 0x1e1e601a);
+    cx25840_write4(client, 0x470, 0x5b2d007f);
+    cx25840_write4(client, 0x49c, 0x20504014);
+    cx25840_write4(client, 0x498, 0x802);
+    cx25840_write4(client, 0x498, 0x802);
+*/
+    cx25840_write4(client, 0x160, 0x1d);
+    cx25840_write4(client, 0x164, 0x2);
+#if 1 //wpwp
 	/*
 	 * Come out of digital power down
 	 * The CX23888, at least, needs this, otherwise registers aside from
 	 * 0x0-0x2 can't be read or written.
 	 */
-	cx25840_write(client, 0x000, 0);
-
-	/* Internal Reset */
-	cx25840_and_or(client, 0x102, ~0x01, 0x01);
-	cx25840_and_or(client, 0x102, ~0x01, 0x00);
-
-	/* Stop microcontroller */
-	cx25840_and_or(client, 0x803, ~0x10, 0x00);
-
-	/* DIF in reset? */
-	cx25840_write(client, 0x398, 0);
 
 	/*
 	 * Trust the default xtal, no division
@@ -298,7 +472,7 @@
 	 * '887: 25.000000 MHz
 	 * '888: 50.000000 MHz
 	 */
-	cx25840_write(client, 0x2, 0x76);
+	cx25840_write(client, 0x2, 0x77);
 
 	/* Power up all the PLL's and DLL */
 	cx25840_write(client, 0x1, 0x40);
@@ -327,7 +501,7 @@
 		 * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
 		 * 572.73 MHz before post divide
 		 */
-		cx25840_write4(client, 0x11c, 0x00000000);
+		cx25840_write4(client, 0x11c, 0x00CCCCCC);
 		cx25840_write4(client, 0x118, 0x00000414);
 		break;
 	}
@@ -347,6 +521,8 @@
 	 */
 	cx25840_write4(client, 0x10c, 0x002be2c9);
 	cx25840_write4(client, 0x108, 0x0000040f);
+    cx25840_write4(client, 0x10c, 0x01B6DB7B);
+    cx25840_write4(client, 0x108, 0x00000512);
 
 	/* Luma */
 	cx25840_write4(client, 0x414, 0x00107d12);
@@ -418,8 +594,9 @@
 	 * currently, regardless of the board type.
 	 */
 	cx25840_write(client, 0x160, 0x1d);
-	cx25840_write(client, 0x164, 0x00);
 
+	cx25840_write(client, 0x164, 0x02);
+#endif
 	/* Do the firmware load in a work handler to prevent.
 	   Otherwise the kernel is blocked waiting for the
 	   bit-banging i2c interface to finish uploading the
@@ -437,10 +614,10 @@
 	finish_wait(&state->fw_wait, &wait);
 	destroy_workqueue(q);
 
-	cx25840_std_setup(client);
+//	cx25840_std_setup(client);
 
 	/* (re)set input */
-	set_input(client, state->vid_input, state->aud_input);
+//	set_input(client, state->vid_input, state->aud_input);
 
 	/* start microcontroller */
 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
@@ -516,7 +693,7 @@
 	finish_wait(&state->fw_wait, &wait);
 	destroy_workqueue(q);
 
-	cx25840_std_setup(client);
+//	cx25840_std_setup(client);
 
 	/* (re)set input */
 	set_input(client, state->vid_input, state->aud_input);
@@ -600,9 +777,6 @@
 		pll_int = cx25840_read(client, 0x108);
 		pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
 		pll_post = cx25840_read(client, 0x109);
-		v4l_dbg(1, cx25840_debug, client,
-			"PLL regs = int: %u, frac: %u, post: %u\n",
-			pll_int, pll_frac, pll_post);
 
 		if (pll_post) {
 			int fin, fsc;
@@ -740,7 +914,7 @@
 	v4l_dbg(1, cx25840_debug, client,
 		"decoder set video input %d, audio input %d\n",
 		vid_input, aud_input);
-
+#if 1 //wpwp
 	if (vid_input >= CX25840_VIN1_CH1) {
 		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
 			vid_input);
@@ -805,21 +979,28 @@
 
 	if (!is_cx2388x(state) && !is_cx231xx(state)) {
 		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 0x12 : 0x10);
 		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
 		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-			cx25840_and_or(client, 0x102, ~0x4, 4);
+			cx25840_and_or(client, 0x102, ~0x4, 0x14);
 		else
-			cx25840_and_or(client, 0x102, ~0x4, 0);
+			cx25840_and_or(client, 0x102, ~0x4, 0x10);
 	} else {
 		if (is_composite)
 			/* ADC2 input select channel 2 */
-			cx25840_and_or(client, 0x102, ~0x2, 0);
+			cx25840_and_or(client, 0x102, ~0x2, 0x10);
 		else
 			/* ADC2 input select channel 3 */
-			cx25840_and_or(client, 0x102, ~0x2, 2);
+			cx25840_and_or(client, 0x102, ~0x2, 0x12);
 	}
 
+//	cx25840_and_or(client, 0x400, 0xffffffdf, 0x20);
+//	cx25840_and_or(client, 0x400, 0xfffff9ff, 0);
+
+    
+//	cx25840_and_or(client, 0x490, 0xfffffffc, 0);
+//	cx25840_and_or(client, 0x474, 0xfffffc00, 0x24);
+//	cx25840_and_or(client, 0x470, 0xfffffc00, 0x89);
 	state->vid_input = vid_input;
 	state->aud_input = aud_input;
 	if (!is_cx2583x(state)) {
@@ -857,7 +1038,7 @@
 		cx25840_write(client, 0x918, 0xa0);
 		cx25840_write(client, 0x919, 0x01);
 	}
-
+#endif
 	return 0;
 }
 
@@ -868,7 +1049,7 @@
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 	u8 fmt = 0; 	/* zero is autodetect */
 	u8 pal_m = 0;
-
+#if 1
 	/* First tests should be against specific std */
 	if (state->std == V4L2_STD_NTSC_M_JP) {
 		fmt = 0x2;
@@ -909,6 +1090,7 @@
 	cx25840_std_setup(client);
 	if (!is_cx2583x(state))
 		input_change(client);
+#endif    
 	return 0;
 }
 
@@ -957,12 +1139,12 @@
 		break;
 
 	case V4L2_CID_HUE:
-		if (ctrl->value < -128 || ctrl->value > 127) {
+		if (ctrl->value < 0 || ctrl->value > 255) {
 			v4l_err(client, "invalid hue setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
-		cx25840_write(client, 0x422, ctrl->value);
+		cx25840_write(client, 0x422, ctrl->value - 128 );
 		break;
 
 	case V4L2_CID_AUDIO_VOLUME:
@@ -1000,7 +1182,7 @@
 		ctrl->value = cx25840_read(client, 0x420) >> 1;
 		break;
 	case V4L2_CID_HUE:
-		ctrl->value = (s8)cx25840_read(client, 0x422);
+		ctrl->value = (s8)cx25840_read(client, 0x422) + 128;
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_BASS:
@@ -1748,7 +1930,7 @@
 	}
 
 	state->c = client;
-	state->vid_input = CX25840_COMPOSITE7;
+	state->vid_input = CX25840_COMPOSITE1;
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
 	state->pvr150_workaround = 0;
diff -uNr v4l-dvb/linux/drivers/media/video/cx25840/cx25840-firmware.c MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx25840/cx25840-firmware.c
--- v4l-dvb/linux/drivers/media/video/cx25840/cx25840-firmware.c	2010-01-05 18:25:14.000000000 -0500
+++ MPX-885/linux/v4l-dvb/linux/drivers/media/video/cx25840/cx25840-firmware.c	2009-11-11 09:36:38.000000000 -0500
@@ -130,7 +130,7 @@
 	}
 
 	start_fw_load(client);
-
+#if 0
 	buffer[0] = 0x08;
 	buffer[1] = 0x02;
 
@@ -151,7 +151,7 @@
 		size -= len;
 		ptr += len;
 	}
-
+#endif
 	end_fw_load(client);
 
 	size = fw->size;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 23:22                     ` cx23885 Ralph Siemsen
@ 2010-02-16  0:36                       ` Andy Walls
  0 siblings, 0 replies; 19+ messages in thread
From: Andy Walls @ 2010-02-16  0:36 UTC (permalink / raw)
  To: Ralph Siemsen; +Cc: Michael, linux-media

On Mon, 2010-02-15 at 18:22 -0500, Ralph Siemsen wrote:
> On Mon, Feb 15, 2010 at 11:56:52PM +0100, Michael wrote:
> > 
> > If anybody can give me a hint, what to include in a patch and what was old 
> > stuff that has jsut changed in 2.6.31, I'd be grateful.
> 
> Their source tree contains a .hg_archival.txt file which looks like
> it can be used to identify the original v4l-dvb tree they used.
> 
> Attached is a diff from that v4l version to the MPX-885 tree.
>  cx23885/cx23885-cards.c    |   90 ++++++++++++++++
>  cx23885/cx23885-dvb.c      |   30 +++++
>  cx23885/cx23885-video.c    |    2 
>  cx23885/cx23885.h          |    1 
>  cx25840/cx25840-core.c     |  248 +++++++++++++++++++++++++++++++++++++++------
>  cx25840/cx25840-firmware.c |    4 
>  6 files changed, 338 insertions(+), 37 deletions(-)
> 
> Hope it helps...
> -R


That is very helpful.

However, changes to the CX25840 module, since their MPX885 changes were
developed, are extenesive when it comes to initialization of the
CX23885/7/8 A/V decoder.  Their changes will be difficult to port.

I also see changes which will at least break existing drivers and apps.
For example, this one will violate a key assumption made by the ivtv
driver:

-       state->vid_input = CX25840_COMPOSITE7;
+       state->vid_input = CX25840_COMPOSITE1;


This sort of thing is typical of many vendor driver developments: get it
working for this part as fast as possible so the product can ship -
don't worry about anything else.

It is still decent of them to provide a linux driver and the source
changes without a hassle.  RAR format is inconvenient on linux though.

Regards,
Andy


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: cx23885
  2010-02-15 22:20                 ` cx23885 Steven Toth
@ 2010-02-16 11:37                   ` Michael
  0 siblings, 0 replies; 19+ messages in thread
From: Michael @ 2010-02-16 11:37 UTC (permalink / raw)
  To: linux-media

O.K. I ordered the card now. Can take one or two weeks for it to arrive. 
Gonna come back to the list then.

Michael

Steven Toth wrote:

>> One thing I found pretty fast is that they added in cx23885-card.c:
> 
> This looks promising.
> 
>> But maybe it is a start. What do you think?
> 
> I repeat I my original comment below.
> 
>>> Feel free to submit patches.
> 
> ^^^ indeed, good luck.
> 
> Regards,
> 



^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2010-02-16 11:38 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-15 12:20 cx23885 Michael
2010-02-15 12:54 ` cx23885 Andy Walls
2010-02-15 13:15   ` cx23885 Michael
2010-02-15 14:41     ` cx23885 Steven Toth
2010-02-15 15:21       ` cx23885 Michael
2010-02-15 17:11         ` cx23885 Steven Toth
2010-02-15 20:41           ` cx23885 Michael
2010-02-15 20:53             ` cx23885 Steven Toth
2010-02-15 22:17               ` cx23885 Michael
2010-02-15 22:20                 ` cx23885 Steven Toth
2010-02-16 11:37                   ` cx23885 Michael
2010-02-15 22:47                 ` cx23885 Michael
2010-02-15 22:56                   ` cx23885 Michael
2010-02-15 23:00                     ` cx23885 Steven Toth
2010-02-15 23:22                     ` cx23885 Ralph Siemsen
2010-02-16  0:36                       ` cx23885 Andy Walls
2010-02-15 22:58                   ` cx23885 Michael
2010-02-15 17:27         ` cx23885 Devin Heitmueller
2010-02-15 20:29           ` cx23885 Michael

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox