- tm6000 DVB support

Message ID 4B673B2D.6040507@arcor.de (mailing list archive)
State Superseded, archived
Headers

Commit Message

Stefan Ringel Feb. 1, 2010, 8:35 p.m. UTC
  add Terratec Cinergy Hybrid XE
bugfix i2c transfer
add frontend callback
add init for tm6010
add digital-init for tm6010
add callback for analog/digital switch
bugfix usb transfer in DVB-mode

signed-off-by: Stefan Ringel <stefan.ringel@arcor.de>

 int tm6000_init_digital_mode (struct tm6000_core *dev);
@@ -231,7 +242,12 @@ int tm6000_set_standard (struct tm6000_core *dev,
v4l2_std_id *norm);
 int tm6000_i2c_register(struct tm6000_core *dev);
 int tm6000_i2c_unregister(struct tm6000_core *dev);
 
+#if 1
 /* In tm6000-queue.c */
+#if 0
+int tm6000_init_isoc(struct tm6000_core *dev, int max_packets);
+void tm6000_uninit_isoc(struct tm6000_core *dev);
+#endif
 
 int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
 
@@ -276,3 +292,4 @@ extern int tm6000_debug;
         __FUNCTION__ , ##arg); } while (0)
 
 
+#endif
  

Comments

Devin Heitmueller Feb. 1, 2010, 8:52 p.m. UTC | #1
On Mon, Feb 1, 2010 at 3:35 PM, Stefan Ringel <stefan.ringel@arcor.de> wrote:
> add Terratec Cinergy Hybrid XE
> bugfix i2c transfer
> add frontend callback
> add init for tm6010
> add digital-init for tm6010
> add callback for analog/digital switch
> bugfix usb transfer in DVB-mode
>
> signed-off-by: Stefan Ringel <stefan.ringel@arcor.de>

Hi Stefan,

It's good to see you're making progress.  However, this is going to
need *alot* of work before it will be able to be accepted upstream.

You should start by breaking it down into a patch series, so that the
incremental changes can be reviewed.  That will allow you to explain
in the patch descriptions why all the individual changes you have made
are required.

However, I will try to put some of my thoughts down based on the quick
glance I took at the patch.

Why did you define a new callback for changing the tuner mode?  We
have successfully provided infrastructure on other bridges to toggle
GPIOs when changing modes.  For example, the em28xx has fields in the
board profile that allow you to toggle GPIOs when going back and forth
between digital and analog mode.

You've got a bunch of changes in the xc3028 tuner that will
*definitely* need close inspection and would need to be validated on a
variety of products using the xc3028 before they could be accepted
upstream.  While you have done what you felt was necessary to make it
work for your board, this cannot be at the cost of possible
regressions to other products that are already supported.

You really should look into fixing whatever is screwed up in the
tm6000 i2c implementation so that the read support works, rather than
relying on nothing ever having to perform a read operation.

What function does the "tm6000" member in the zl10353 config do?  It
doesn't seem to be used anywhere.

There are a bunch of codingstyle issues which will need to be fixed.

My foremost concerns are obviously the things that touch other
drivers, since your work could cause regressions/breakage for other
boards, which is actually much worse than your board not being
supported.
  
Stefan Ringel Feb. 1, 2010, 9:23 p.m. UTC | #2
Am 01.02.2010 21:52, schrieb Devin Heitmueller:
> On Mon, Feb 1, 2010 at 3:35 PM, Stefan Ringel <stefan.ringel@arcor.de> wrote:
>   
>> add Terratec Cinergy Hybrid XE
>> bugfix i2c transfer
>> add frontend callback
>> add init for tm6010
>> add digital-init for tm6010
>> add callback for analog/digital switch
>> bugfix usb transfer in DVB-mode
>>
>> signed-off-by: Stefan Ringel <stefan.ringel@arcor.de>
>>     
> Hi Stefan,
>
> It's good to see you're making progress.  However, this is going to
> need *alot* of work before it will be able to be accepted upstream.
>
> You should start by breaking it down into a patch series, so that the
> incremental changes can be reviewed.  That will allow you to explain
> in the patch descriptions why all the individual changes you have made
> are required.
>
>   
how can I generate it?
> However, I will try to put some of my thoughts down based on the quick
> glance I took at the patch.
>
> Why did you define a new callback for changing the tuner mode?  We
> have successfully provided infrastructure on other bridges to toggle
> GPIOs when changing modes.  For example, the em28xx has fields in the
> board profile that allow you to toggle GPIOs when going back and forth
> between digital and analog mode.
>
>   
I don't know, how you mean it. I'm amateur programmer.
> You've got a bunch of changes in the xc3028 tuner that will
> *definitely* need close inspection and would need to be validated on a
> variety of products using the xc3028 before they could be accepted
> upstream.  While you have done what you felt was necessary to make it
> work for your board, this cannot be at the cost of possible
> regressions to other products that are already supported.
>
> You really should look into fixing whatever is screwed up in the
> tm6000 i2c implementation so that the read support works, rather than
> relying on nothing ever having to perform a read operation.
>
> What function does the "tm6000" member in the zl10353 config do?  It
> doesn't seem to be used anywhere.
>
>   
I'll switch it next week to demodulator module.
> There are a bunch of codingstyle issues which will need to be fixed.
>
> My foremost concerns are obviously the things that touch other
> drivers, since your work could cause regressions/breakage for other
> boards, which is actually much worse than your board not being
> supported.
>
>   

Cheers

Stefan Ringel
  
Devin Heitmueller Feb. 1, 2010, 9:44 p.m. UTC | #3
On Mon, Feb 1, 2010 at 4:23 PM, Stefan Ringel <stefan.ringel@arcor.de> wrote:
>> You should start by breaking it down into a patch series, so that the
>> incremental changes can be reviewed.  That will allow you to explain
>> in the patch descriptions why all the individual changes you have made
>> are required.
>>
>>
> how can I generate it?

You can use quilt to break it up into a patch series, or create a
local hg clone of v4l-dvb.

>> Why did you define a new callback for changing the tuner mode?  We
>> have successfully provided infrastructure on other bridges to toggle
>> GPIOs when changing modes.  For example, the em28xx has fields in the
>> board profile that allow you to toggle GPIOs when going back and forth
>> between digital and analog mode.
>>
>>
> I don't know, how you mean it. I'm amateur programmer.

Look at how the ".dvb_gpio" and ".gpio" fields are used in the board
profiles in em28xx-cards.c.  We toggle the GPIOs when switching the
from analog to digital mode, without the tuner having to do any sort
of callback.

>> What function does the "tm6000" member in the zl10353 config do?  It
>> doesn't seem to be used anywhere.
>>
>>
> I'll switch it next week to demodulator module.

Are you saying the zl10353 isn't working right now in your patch?  I'm
a bit confused.  If it doesn't work, then your patch title is a bit
misleading since it suggests that your patch provides DVB support for
the tm6000.  If it does work, then the tm6000 member shouldn't be
needed at all in the zl10353 config.

Cheers,

Devin
  
Stefan Ringel Feb. 1, 2010, 10 p.m. UTC | #4
Am 01.02.2010 22:44, schrieb Devin Heitmueller:
> On Mon, Feb 1, 2010 at 4:23 PM, Stefan Ringel <stefan.ringel@arcor.de> wrote:
>   
>>> You should start by breaking it down into a patch series, so that the
>>> incremental changes can be reviewed.  That will allow you to explain
>>> in the patch descriptions why all the individual changes you have made
>>> are required.
>>>
>>>
>>>       
>> how can I generate it?
>>     
> You can use quilt to break it up into a patch series, or create a
> local hg clone of v4l-dvb.
>
>   
>>> Why did you define a new callback for changing the tuner mode?  We
>>> have successfully provided infrastructure on other bridges to toggle
>>> GPIOs when changing modes.  For example, the em28xx has fields in the
>>> board profile that allow you to toggle GPIOs when going back and forth
>>> between digital and analog mode.
>>>
>>>
>>>       
>> I don't know, how you mean it. I'm amateur programmer.
>>     
> Look at how the ".dvb_gpio" and ".gpio" fields are used in the board
> profiles in em28xx-cards.c.  We toggle the GPIOs when switching the
> from analog to digital mode, without the tuner having to do any sort
> of callback.
>
>   
It's a bad example. em28xx use a reg-set, but tm6000 not !! It use a
gpio usb request.

tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_5, 1);


I don't know, that it with the ".gpio" fields works. And when it switch
from analog to digital, I don't see the way.

>>> What function does the "tm6000" member in the zl10353 config do?  It
>>> doesn't seem to be used anywhere.
>>>
>>>
>>>       
>> I'll switch it next week to demodulator module.
>>     
> Are you saying the zl10353 isn't working right now in your patch?  I'm
> a bit confused.  If it doesn't work, then your patch title is a bit
> misleading since it suggests that your patch provides DVB support for
> the tm6000.  If it does work, then the tm6000 member shouldn't be
> needed at all in the zl10353 config.
>
>   
I'm emulating it in hack.c and the zl10353 module doesn't work, if I
switch to it.
> Cheers,
>
> Devin
>
>
  
Mauro Carvalho Chehab Feb. 1, 2010, 10:52 p.m. UTC | #5
Stefan Ringel wrote:
> add Terratec Cinergy Hybrid XE
> bugfix i2c transfer
> add frontend callback
> add init for tm6010
> add digital-init for tm6010
> add callback for analog/digital switch
> bugfix usb transfer in DVB-mode
> 
> signed-off-by: Stefan Ringel <stefan.ringel@arcor.de>

Devin is right with respect to the changes: you should break into small
patches for us to better understand what you're doing. 

In particular, some parts of the changes (like tuner-xc2028) are known 
to be working fine with other drivers, so any change there should be done 
with the enough care to not break other drivers.

> 
> diff --git a/drivers/media/common/tuners/tuner-xc2028.c
> b/drivers/media/common/tuners/tuner-xc2028.c
> index ed50168..2297c00 100644
> --- a/drivers/media/common/tuners/tuner-xc2028.c
> +++ b/drivers/media/common/tuners/tuner-xc2028.c
> @@ -15,6 +15,7 @@
>  #include <linux/delay.h>
>  #include <media/tuner.h>
>  #include <linux/mutex.h>
> +#include "compat.h"
>  #include <asm/unaligned.h>
>  #include "tuner-i2c.h"
>  #include "tuner-xc2028.h"
> @@ -994,6 +995,13 @@ static int generic_set_freq(struct dvb_frontend
> *fe, u32 freq /* in HZ */,
>             buf[0], buf[1], buf[2], buf[3],
>             freq / 1000000, (freq % 1000000) / 1000);
>  
> +    if (priv->ctrl.switch_mode) {
> +        if (new_mode == T_ANALOG_TV)
> +            do_tuner_callback(fe, SWITCH_TV_MODE, 0);
> +        if (new_mode == T_DIGITAL_TV)
> +            do_tuner_callback(fe, SWITCH_TV_MODE, 1);
> +    }
> +   
>      rc = 0;

The decision taken at the driver were the opposite: the bridge driver should
have the logic to reset the tuner. This works perfectly on em28xx and other
drivers that use xc3028.

I don't see a good reason to revert the logic here. Also, such change should
be done on all drivers that use xc3028 and xc5000.

>  
>  ret:
> @@ -1114,7 +1122,11 @@ static int xc2028_set_params(struct dvb_frontend *fe,
>  
>      /* All S-code tables need a 200kHz shift */
>      if (priv->ctrl.demod) {
> -        demod = priv->ctrl.demod + 200;
> +        if (priv->ctrl.fname == "xc3028L-v36.fw") {
> +            demod = priv->ctrl.demod;
> +        } else {
> +            demod = priv->ctrl.demod + 200;
> +        }

Instead, you should be using the firmware version. 

As the firmware version is written at the firmware file, it is easy to do the tests 
based on the firmware version, even on devices like tm6000 where the version read
method may fail.
 
Yet, I suspect that the currently available v36 firmwares already take this into 
consideration (or the drivers that use those firmwares do the offset internally).

So, this change needs to be checked against the existing drivers.

>          /*
>           * The DTV7 S-code table needs a 700 kHz shift.
>           * Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this
> @@ -1123,8 +1135,8 @@ static int xc2028_set_params(struct dvb_frontend *fe,
>           * use this firmware after initialization, but a tune to a UHF
>           * channel should then cause DTV78 to be used.
>           */
> -        if (type & DTV7)
> -            demod += 500;
> +        if (type  & DTV7)
> +        demod += 500;

This hunk is wrong.

>      }
>  
>      return generic_set_freq(fe, p->frequency,
> @@ -1240,6 +1252,10 @@ static const struct dvb_tuner_ops
> xc2028_dvb_tuner_ops = {
>      .get_rf_strength   = xc2028_signal,
>      .set_params        = xc2028_set_params,
>      .sleep             = xc2028_sleep,
> +#if 0
> +    int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
> +    int (*get_status)(struct dvb_frontend *fe, u32 *status);
> +#endif
>  };
>  
>  struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
> diff --git a/drivers/media/common/tuners/tuner-xc2028.h
> b/drivers/media/common/tuners/tuner-xc2028.h
> index 9778c96..c9a4fb4 100644
> --- a/drivers/media/common/tuners/tuner-xc2028.h
> +++ b/drivers/media/common/tuners/tuner-xc2028.h
> @@ -42,6 +42,7 @@ struct xc2028_ctrl {
>      unsigned int        disable_power_mgmt:1;
>      unsigned int            read_not_reliable:1;
>      unsigned int        demod;
> +    unsigned int        switch_mode:1;

This struct is meant to pass static parameters to the driver. the analog/digital
mode is dynamic, so, this is not the right place for doing it.

>      enum firmware_type    type:2;
>  };
>  
> @@ -54,6 +55,7 @@ struct xc2028_config {
>  /* xc2028 commands for callback */
>  #define XC2028_TUNER_RESET    0
>  #define XC2028_RESET_CLK    1
> +#define SWITCH_TV_MODE        2
>  
>  #if defined(CONFIG_MEDIA_TUNER_XC2028) ||
> (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
>  extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
> diff --git a/drivers/media/dvb/frontends/zl10353.h
> b/drivers/media/dvb/frontends/zl10353.h
> index 6e3ca9e..015bc36 100644
> --- a/drivers/media/dvb/frontends/zl10353.h
> +++ b/drivers/media/dvb/frontends/zl10353.h
> @@ -45,6 +45,8 @@ struct zl10353_config
>      /* clock control registers (0x51-0x54) */
>      u8 clock_ctl_1;  /* default: 0x46 */
>      u8 pll_0;        /* default: 0x15 */
> +   
> +    int tm6000:1;

This doesn't make sense. The zl10353 doesn't need to know if the device is
a tm6000 or not. If the tm6000 driver needs something special, then we need
to discover what he is doing and name the zl10353 feature accordingly.


>  };
>  
>  #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE)
> && defined(MODULE))
> diff --git a/drivers/staging/tm6000/hack.c b/drivers/staging/tm6000/hack.c
> index f181fce..c1e1880 100644
> --- a/drivers/staging/tm6000/hack.c
> +++ b/drivers/staging/tm6000/hack.c
> @@ -37,7 +37,6 @@ static inline int tm6000_snd_control_msg(struct
> tm6000_core *dev, __u8 request,

This "hack" file is a good candidate to be removed ;) It is, in fact a zl10353
code with the tm6000 initialization, made by cloning the zl10353 parameters
that the original driver does.

>  
>  static int pseudo_zl10353_pll(struct tm6000_core *tm6000_dev, struct
> dvb_frontend_parameters *p)
>  {
> -    int ret;
>      u8 *data = kzalloc(50*sizeof(u8), GFP_KERNEL);
>  
>  printk(KERN_ALERT "should set frequency %u\n", p->frequency);
> @@ -51,7 +50,7 @@ printk(KERN_ALERT "and bandwith %u\n",
> p->u.ofdm.bandwidth);
>      }
>  
>      // init ZL10353
> -    data[0] = 0x0b;
> +/*    data[0] = 0x0b;
>      ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x501e, 0x00, data,
> 0x1);
>      msleep(15);
>      data[0] = 0x80;
> @@ -159,7 +158,7 @@ printk(KERN_ALERT "and bandwith %u\n",
> p->u.ofdm.bandwidth);
>              msleep(15);
>              data[0] = 0x5a;
>              ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e,
> 0x00, data, 0x1);
> -            msleep(15);
> +            msleep(15)
>              data[0] = 0xe9;
>              ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e,
> 0x00, data, 0x1);
>              msleep(15);
> @@ -189,7 +188,162 @@ printk(KERN_ALERT "and bandwith %u\n",
> p->u.ofdm.bandwidth);
>              msleep(15);
>          break;
>      }
> -
> +*/

Please use #if 0 to temporarily remove a code that it is not needed. Yet, maybe
removing this code will break tm6000 devices. tm6010 has some differences
when compared with tm6000. So, if your device is tm6010, the better is to
run the above code if is not a tm6010.

> +    switch(p->u.ofdm.bandwidth) {
> +        case BANDWIDTH_8_MHZ:
> +            data[0] = 0x03;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x501e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x44;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x511e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x40;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x46;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x521e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x15;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x531e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x0f;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x541e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x80;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x01;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x00;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x8b;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x631e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x75;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xcc1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0xe6; //0x19;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6c1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x09; //0xf7;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6d1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x67;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x651e,0,data,1);
> +            msleep(40);
> +            data[0] = 0xe5;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x661e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x75;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5c1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x17;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5f1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x40;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5e1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x01;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x701e,0,data,1);
> +            msleep(40);
> +            break;
> +        case BANDWIDTH_7_MHZ:
> +            data[0] = 0x03;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x501e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x44;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x511e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x40;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x46;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x521e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x15;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x531e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x0f;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x541e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x80;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x01;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x00;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x83;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x631e,0,data,1);
> +            msleep(40);
> +            data[0] = 0xa3;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xcc1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0xe6; //0x19;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6c1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x09; //0xf7;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6d1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x5a;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x651e,0,data,1);
> +            msleep(40);
> +            data[0] = 0xe9;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x661e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x86;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5c1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x17;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5f1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x40;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5e1e,0,data,1);
> +            msleep(40);
> +            data[0] = 0x01;
> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x701e,0,data,1);
> +            msleep(40);
> +            break;
> +        default:
> +            printk(KERN_ALERT "tm6000: bandwidth not supported\n");
> +    }
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x0f1f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x091f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);
> +   
> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x0b1f,0,data,2);
> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
> +    msleep(40);

The same comment here: maybe the above code only applies to tm6010.

> +   
>      kfree(data);
>  
>      return 0;
> diff --git a/drivers/staging/tm6000/tm6000-cards.c
> b/drivers/staging/tm6000/tm6000-cards.c
> index 59fb505..652a54a 100644
> --- a/drivers/staging/tm6000/tm6000-cards.c
> +++ b/drivers/staging/tm6000/tm6000-cards.c
> @@ -32,7 +32,7 @@
>  #include "tm6000.h"
>  #include "tm6000-regs.h"
>  #include "tuner-xc2028.h"
> -#include "tuner-xc5000.h"
> +#include "xc5000.h"

Please send this hunk on a separate patch. Since it fixes compilation, I'll
need to apply it before the Kconfig changes, when tm6000 upstream.

>  
>  #define TM6000_BOARD_UNKNOWN            0
>  #define TM5600_BOARD_GENERIC            1
> @@ -44,6 +44,10 @@
>  #define TM6000_BOARD_FREECOM_AND_SIMILAR    7
>  #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV    8
>  #define TM6010_BOARD_HAUPPAUGE_900H        9
> +#define TM6010_BOARD_BEHOLD_WANDER        10
> +#define TM6010_BOARD_BEHOLD_VOYAGER        11
> +#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE    12
> +
>  
>  #define TM6000_MAXBOARDS        16
>  static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
> @@ -208,7 +212,21 @@ struct tm6000_board tm6000_boards[] = {
>          },
>          .gpio_addr_tun_reset = TM6000_GPIO_2,
>      },
> -
> +    [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
> +        .name         = "Terratec Cinergy Hybrid XE",
> +        .tuner_type   = TUNER_XC2028, /* has a XC3028 */
> +        .tuner_addr   = 0xc2 >> 1,
> +        .demod_addr   = 0x1e >> 1,
> +        .type         = TM6010,
> +        .caps = {
> +            .has_tuner    = 1,
> +            .has_dvb      = 1,
> +            .has_zl10353  = 1,
> +            .has_eeprom   = 1,
> +            .has_remote   = 1,
> +        },
> +        .gpio_addr_tun_reset = TM6010_GPIO_2,
> +    }
>  };
>  
>  /* table of devices that work with this driver */
> @@ -221,12 +239,13 @@ struct usb_device_id tm6000_id_table [] = {
>      { USB_DEVICE(0x2040, 0x6600), .driver_info =
> TM6010_BOARD_HAUPPAUGE_900H },
>      { USB_DEVICE(0x6000, 0xdec0), .driver_info =
> TM6010_BOARD_BEHOLD_WANDER },
>      { USB_DEVICE(0x6000, 0xdec1), .driver_info =
> TM6010_BOARD_BEHOLD_VOYAGER },
> +    { USB_DEVICE(0x0ccd, 0x0086), .driver_info =
> TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
>      { },
>  };

New board definition: please send this as a separate patch.

>  
>  /* Tuner callback to provide the proper gpio changes needed for xc2028 */
>  
> -static int tm6000_tuner_callback(void *ptr, int component, int command,
> int arg)
> +int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
>  {
>      int rc=0;
>      struct tm6000_core *dev = ptr;
> @@ -252,11 +271,14 @@ static int tm6000_tuner_callback(void *ptr, int
> component, int command, int arg)
>          switch (arg) {
>          case 0:
>              tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
> +                    dev->tuner_reset_gpio, 0x01);
> +            msleep(60);
> +            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>                      dev->tuner_reset_gpio, 0x00);
> -            msleep(130);
> +            msleep(75);
>              tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>                      dev->tuner_reset_gpio, 0x01);
> -            msleep(130);
> +            msleep(60);
>              break;
>          case 1:
>              tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
> @@ -269,13 +291,33 @@ static int tm6000_tuner_callback(void *ptr, int
> component, int command, int arg)
>                          TM6000_GPIO_CLK, 0);
>              if (rc<0)
>                  return rc;
> -            msleep(100);
> +            msleep(10);
>              rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>                          TM6000_GPIO_CLK, 1);
> -            msleep(100);
> +            msleep(10);
> +            break;
> +        }
> +        break;
> +       
> +    case SWITCH_TV_MODE:
> +        /* switch between analog and  digital */
> +        switch (arg) {
> +        case 0:
> +            printk(KERN_INFO "switch to analog");
> +            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
> +                    TM6010_GPIO_5, 1);
> +            printk(KERN_INFO "analog");
> +            break;
> +        case 1:
> +            printk(KERN_INFO "switch to digital");
> +            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
> +                    TM6010_GPIO_5, 0);
> +            printk(KERN_INFO "digital");
>              break;
>          }
> +    break;
>      }

Those tuner callback initializations are board-specific. So, it is better to test
for your board model, if you need something different than what's currently done.

> +   
>      return (rc);
>  }
>  
> @@ -290,7 +332,7 @@ static void tm6000_config_tuner (struct tm6000_core
> *dev)
>      memset(&tun_setup, 0, sizeof(tun_setup));
>      tun_setup.type   = dev->tuner_type;
>      tun_setup.addr   = dev->tuner_addr;
> -    tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
> +    tun_setup.mode_mask = T_ANALOG_TV | T_RADIO | T_DIGITAL_TV;
>      tun_setup.tuner_callback = tm6000_tuner_callback;
>  
>      v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
> &tun_setup);
> @@ -302,15 +344,19 @@ static void tm6000_config_tuner (struct
> tm6000_core *dev)
>          memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
>          memset (&ctl,0,sizeof(ctl));
>  
> -        ctl.mts   = 1;
> -        ctl.read_not_reliable = 1;
> +        ctl.input1 = 1;
> +        ctl.read_not_reliable = 0;
>          ctl.msleep = 10;
> -
> +        ctl.demod = XC3028_FE_ZARLINK456;
> +        ctl.vhfbw7 = 1;
> +        ctl.uhfbw8 = 1;
> +        ctl.switch_mode = 1;
>          xc2028_cfg.tuner = TUNER_XC2028;
>          xc2028_cfg.priv  = &ctl;
>  
>          switch(dev->model) {
>          case TM6010_BOARD_HAUPPAUGE_900H:
> +        case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
>              ctl.fname = "xc3028L-v36.fw";
>              break;
>          default:

> @@ -402,6 +448,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
>          }
>  #endif
>      }
> +    return 0;
>  
>  err2:
>      v4l2_device_unregister(&dev->v4l2_dev);

This hunk also looks a bug fix. If so, please submit as a separate patch.

> @@ -459,13 +506,13 @@ static int tm6000_usb_probe(struct usb_interface
> *interface,
>      /* Check to see next free device and mark as used */
>      nr=find_first_zero_bit(&tm6000_devused,TM6000_MAXBOARDS);
>      if (nr >= TM6000_MAXBOARDS) {
> -        printk ("tm6000: Supports only %i em28xx
> boards.\n",TM6000_MAXBOARDS);
> +        printk ("tm6000: Supports only %i tm60xx
> boards.\n",TM6000_MAXBOARDS);
>          usb_put_dev(usbdev);
>          return -ENOMEM;
>      }

Also a typo bug fix. I don't really mind if you fold this with another patch,
but the better would be to have a separate patch for it.

>  
>      /* Create and initialize dev struct */
> -    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> +    dev = kzalloc(sizeof(*(dev)), GFP_KERNEL);

The extra parenthesis is uneeded here.

>      if (dev == NULL) {
>          printk ("tm6000" ": out of memory!\n");
>          usb_put_dev(usbdev);
> diff --git a/drivers/staging/tm6000/tm6000-core.c
> b/drivers/staging/tm6000/tm6000-core.c
> index d41af1d..33bbbd3 100644
> --- a/drivers/staging/tm6000/tm6000-core.c
> +++ b/drivers/staging/tm6000/tm6000-core.c
> @@ -219,33 +219,53 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
>  
>  int tm6000_init_digital_mode (struct tm6000_core *dev)
>  {
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
> -
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
> -    msleep(50);
> -
> -    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
> -    msleep(50);
> -    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
> -    msleep(50);
> -    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
> -    msleep(100);
> -
> +    if (dev->dev_type == TM6010) {
> +        int val;
> +        u8 buf[2];
> +       
> +        /* digital init */
> +        val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, 0);
> +        val &= ~0x60;
> +        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, val);
> +        val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, 0);
> +        val |= 0x40;
> +        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, val);
> +        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xfe, 0x28);
> +        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xfc);
> +        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xe6, 0xff);
> +        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe);
> +        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
> +        printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
> +       
> +
> +    } else  {
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
> +
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
> +        msleep(50);
> +
> +        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
> +        msleep(50);
> +        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
> +        msleep(50);
> +        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
> +        msleep(100);
> +    }
>      return 0;
>  }
>  
> @@ -394,7 +414,15 @@ struct reg_init tm6010_init_tab[] = {
>      { REQ_07_SET_GET_AVREG, 0x3f, 0x00 },
>  
>      { REQ_05_SET_GET_USBREG, 0x18, 0x00 },
> -
> +   
> +    /* additional from Terratec Cinergy Hybrid XE */
> +    { REQ_07_SET_GET_AVREG, 0xdc, 0xaa },
> +    { REQ_07_SET_GET_AVREG, 0xdd, 0x30 },
> +    { REQ_07_SET_GET_AVREG, 0xde, 0x20 },
> +    { REQ_07_SET_GET_AVREG, 0xdf, 0xd0 },
> +    { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
> +    { REQ_07_SET_GET_AVREG, 0xd8, 0x2f },
> +   
>      /* set remote wakeup key:any key wakeup */
>      { REQ_07_SET_GET_AVREG,  0xe5,  0xfe },
>      { REQ_07_SET_GET_AVREG,  0xda,  0xff },
> @@ -404,6 +432,7 @@ int tm6000_init (struct tm6000_core *dev)
>  {
>      int board, rc=0, i, size;
>      struct reg_init *tab;
> +    u8 buf[40];

Why "40" ? Please avoid using magic numbers here, especially if you're
not checking at the logic if you're writing outside the buffer.

>      if (dev->dev_type == TM6010) {
>          tab = tm6010_init_tab;
> @@ -424,61 +453,129 @@ int tm6000_init (struct tm6000_core *dev)
>          }
>      }
>  
> -    msleep(5); /* Just to be conservative */
> -
> -    /* Check board version - maybe 10Moons specific */
> -    board=tm6000_get_reg16 (dev, 0x40, 0, 0);
> -    if (board >=0) {
> -        printk (KERN_INFO "Board version = 0x%04x\n",board);
> -    } else {
> -        printk (KERN_ERR "Error %i while retrieving board
> version\n",board);
> -    }
> -
> +    /* hack */
>      if (dev->dev_type == TM6010) {
> -        /* Turn xceive 3028 on */
> -        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_3, 0x01);
> -        msleep(11);
> -    }
> -
> -    /* Reset GPIO1 and GPIO4. */
> -    for (i=0; i< 2; i++) {
> -        rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> -                    dev->tuner_reset_gpio, 0x00);
> -        if (rc<0) {
> -            printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
> -            return rc;
> -        }
> -
> -        msleep(10); /* Just to be conservative */
> -        rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> -                    dev->tuner_reset_gpio, 0x01);
> -        if (rc<0) {
> -            printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
> -            return rc;
> -        }
> -
> -        msleep(10);
> -        rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 0);
> -        if (rc<0) {
> -            printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
> -            return rc;
> -        }
> -
> -        msleep(10);
> -        rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 1);
> -        if (rc<0) {
> -            printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
> -            return rc;
> -        }
> -
> -        if (!i) {
> -            rc=tm6000_get_reg16(dev, 0x40,0,0);
> -            if (rc>=0) {
> -                printk ("board=%d\n", rc);
> +       
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_4, 0);
> +        msleep(15);
> +               
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_1, 0);
> +   
> +        msleep(50);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_1, 1);
> +       
> +        msleep(15);


The reset code are device dependent. Please don't remove the previous code, or you'll
break the init for the other devices. Instead, add a switch above, checking for your
specific model. The better is to have all those device-specific initializations inside
tm6000-cards. Please take a look on how this is solved on em28xx driver.

> +        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x0010, 0x4400, buf, 2);
> +       
> +        msleep(15);
> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0xf432, 0x0000, buf, 2);
> +   
> +        msleep(15);
> +        buf[0] = 0x12;
> +        buf[1] = 0x34;
> +        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf432, 0x0000, buf, 2);
> +   
> +        msleep(15);
> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0xf432, 0x0000, buf, 2);
> +   
> +        msleep(15);
> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x0032, 0x0000, buf, 2);
> +
> +        msleep(15);
> +        buf[0] = 0x00;
> +        buf[1] = 0x01;
> +        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf332, 0x0000, buf, 2);
> +   
> +        msleep(15);
> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x00c0, 0x0000, buf, 39);
> +   
> +        msleep(15);
> +        buf[0] = 0x00;
> +        buf[1] = 0x00;
> +        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf332, 0x0000, buf, 2);
> +   
> +        msleep(15);
> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x7f1f, 0x0000, buf, 2);
> +//        printk(KERN_INFO "buf %#x %#x \n", buf[0], buf [1]);
> +        msleep(15);


Insead, use tm6000_get_reg() or tm6000_set_reg(). Passing the USB direction as
0x40/0xc0 is very ugly, and makes the code harder to understand.

Also,
	req=0x0e corresponds to REQ_14_SET_GET_I2C_WR2_RDN
	req=0x10 corresponds to REQ_16_SET_GET_I2C_WR1_RDN

So, the above code is just reading/writing some data via I2C. It should be replaced
by some changes at the corresponding i2c driver for the devices that the above
code is controlling.

As a temporary hack, you might do some initialization by calling i2c_master_send/
i2c_master_recv. For example, em28xx driver has this hack:

/* FIXME: Should be replaced by a proper mt9m001 driver */
static int em28xx_initialize_mt9m001(struct em28xx *dev)
{
        int i;
        unsigned char regs[][3] = {
                { 0x0d, 0x00, 0x01, },
                { 0x0d, 0x00, 0x00, },
                { 0x04, 0x05, 0x00, },  /* hres = 1280 */
                { 0x03, 0x04, 0x00, },  /* vres = 1024 */
                { 0x20, 0x11, 0x00, },
                { 0x06, 0x00, 0x10, },
                { 0x2b, 0x00, 0x24, },
                { 0x2e, 0x00, 0x24, },
                { 0x35, 0x00, 0x24, },
                { 0x2d, 0x00, 0x20, },
                { 0x2c, 0x00, 0x20, },
                { 0x09, 0x0a, 0xd4, },
                { 0x35, 0x00, 0x57, },
        };

        for (i = 0; i < ARRAY_SIZE(regs); i++)
                i2c_master_send(&dev->i2c_client, &regs[i][0], 3);

        return 0;
}


> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_4, 1);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                    TM6010_GPIO_0, 1);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_7, 0);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_5, 1);
> +   
> +        msleep(15);

Also, this is device-specific.

> +   
> +        for (i=0; i< size; i++) {
> +            rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
> +            if (rc<0) {
> +                printk (KERN_ERR "Error %i while setting req %d, "
> +                         "reg %d to value %d\n", rc,
> +                         tab[i].req,tab[i].reg, tab[i].val);
> +                return rc;
>              }
>          }
> +           
> +        msleep(15);


> +   
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_4, 0);
> +        msleep(15);
> +
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_1, 0);
> +   
> +        msleep(50);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_1, 1);
> +       
> +        msleep(15);
> +        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
> +//        printk(KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_2, 1);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_2, 0);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_2, 1);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_2, 1);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_2, 0);
> +        msleep(15);
> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
> +                TM6010_GPIO_2, 1);
> +        msleep(15);
>      }
> +    /* hack end */

Idem. All GPIO's are  device-specific.

> +   
> +    msleep(5); /* Just to be conservative */
>  
> +    /* Check board version - maybe 10Moons specific */
> +    if (dev->dev_type == TM5600) {
> +         board=tm6000_get_reg16 (dev, 0x40, 0, 0);
> +        if (board >=0) {
> +            printk (KERN_INFO "Board version = 0x%04x\n",board);
> +        } else {
> +            printk (KERN_ERR "Error %i while retrieving board
> version\n",board);
> +        }
> +    }
> +   
>      msleep(50);
>  
>      return 0;
> diff --git a/drivers/staging/tm6000/tm6000-dvb.c
> b/drivers/staging/tm6000/tm6000-dvb.c
> index e900d6d..31458d3 100644
> --- a/drivers/staging/tm6000/tm6000-dvb.c
> +++ b/drivers/staging/tm6000/tm6000-dvb.c
> @@ -17,7 +17,9 @@
>     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>   */
>  
> +#include <linux/kernel.h>
>  #include <linux/usb.h>
> +#include <compat.h>
>  
>  #include "tm6000.h"
>  #include "tm6000-regs.h"
> @@ -30,17 +32,61 @@
>  
>  #include "tuner-xc2028.h"
>  
> +static void inline print_err_status (struct tm6000_core *dev,
> +                     int packet, int status)
> +{
> +    char *errmsg = "Unknown";
> +
> +    switch(status) {
> +    case -ENOENT:
> +        errmsg = "unlinked synchronuously";
> +        break;
> +    case -ECONNRESET:
> +        errmsg = "unlinked asynchronuously";
> +        break;
> +    case -ENOSR:
> +        errmsg = "Buffer error (overrun)";
> +        break;
> +    case -EPIPE:
> +        errmsg = "Stalled (device not responding)";
> +        break;
> +    case -EOVERFLOW:
> +        errmsg = "Babble (bad cable?)";
> +        break;
> +    case -EPROTO:
> +        errmsg = "Bit-stuff error (bad cable?)";
> +        break;
> +    case -EILSEQ:
> +        errmsg = "CRC/Timeout (could be anything)";
> +        break;
> +    case -ETIME:
> +        errmsg = "Device does not respond";
> +        break;
> +    }
> +    if (packet<0) {
> +        dprintk(dev, 1, "URB status %d [%s].\n",
> +            status, errmsg);
> +    } else {
> +        dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
> +            packet, status, errmsg);
> +    }
> +}
> +
> +
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
> +static void tm6000_urb_received(struct urb *urb, struct pt_regs *ptregs)
> +#else
>  static void tm6000_urb_received(struct urb *urb)
> +#endif
>  {
>      int ret;
>      struct tm6000_core* dev = urb->context;
>  
> -    if(urb->status != 0){
> -        printk(KERN_ERR "tm6000: status != 0\n");
> +    if(urb->status != 0) {
> +        print_err_status (dev,0,urb->status);
>      }
>      else if(urb->actual_length>0){
> -        dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
> -                           urb->actual_length);
> +        dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
> urb->actual_length);
>      }
>  
>      if(dev->dvb->streams > 0) {
> @@ -56,49 +102,37 @@ static void tm6000_urb_received(struct urb *urb)
>  int tm6000_start_stream(struct tm6000_core *dev)
>  {
>      int ret;
> -    unsigned int pipe, maxPaketSize;
> +    unsigned int pipe, size;
>      struct tm6000_dvb *dvb = dev->dvb;
>  
>      printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
>  
>      tm6000_init_digital_mode(dev);
>  
> -/*
> -    ret = tm6000_set_led_status(tm6000_dev, 0x1);
> -    if(ret < 0) {
> -        return -1;
> -    }
> -*/
> -
>      dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
>      if(dvb->bulk_urb == NULL) {
>          printk(KERN_ERR "tm6000: couldn't allocate urb\n");
>          return -ENOMEM;
>      }
>  
> -    maxPaketSize = dev->bulk_in->desc.wMaxPacketSize;
> +    pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
> +                              & USB_ENDPOINT_NUMBER_MASK);
> +                             
> +    size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
> +    size = size * 15; // 512 x 8 or 12 or 15
>  
> -    dvb->bulk_urb->transfer_buffer = kzalloc(maxPaketSize, GFP_KERNEL);
> +    dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
>      if(dvb->bulk_urb->transfer_buffer == NULL) {
>          usb_free_urb(dvb->bulk_urb);
>          printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
>          return -ENOMEM;
>      }
> -
> -    pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
> -                              & USB_ENDPOINT_NUMBER_MASK);
> -
> +   
>      usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
>                           dvb->bulk_urb->transfer_buffer,
> -                         maxPaketSize,
> +                         size,
>                           tm6000_urb_received, dev);
>  
> -    ret = usb_set_interface(dev->udev, 0, 1);
> -    if(ret < 0) {
> -        printk(KERN_ERR "tm6000: error %i in %s during set
> interface\n", ret, __FUNCTION__);
> -        return ret;
> -    }
> -
>      ret = usb_clear_halt(dev->udev, pipe);
>      if(ret < 0) {
>          printk(KERN_ERR "tm6000: error %i in %s during pipe
> reset\n",ret,__FUNCTION__);
> @@ -107,15 +141,14 @@ int tm6000_start_stream(struct tm6000_core *dev)
>      else {
>          printk(KERN_ERR "tm6000: pipe resetted\n");
>      }
> -
> -//     mutex_lock(&tm6000_driver.open_close_mutex);
> +   
> +//    mutex_lock(&tm6000_driver.open_close_mutex);
>      ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
>  
> -
> -//     mutex_unlock(&tm6000_driver.open_close_mutex);
> +//    mutex_unlock(&tm6000_driver.open_close_mutex);
>      if (ret) {
>          printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
> -
> +       
>          kfree(dvb->bulk_urb->transfer_buffer);
>          usb_free_urb(dvb->bulk_urb);
>          return ret;
> @@ -126,18 +159,12 @@ int tm6000_start_stream(struct tm6000_core *dev)
>  
>  void tm6000_stop_stream(struct tm6000_core *dev)
>  {
> -    int ret;
>      struct tm6000_dvb *dvb = dev->dvb;
>  
> -//     tm6000_set_led_status(tm6000_dev, 0x0);
> -
> -    ret = usb_set_interface(dev->udev, 0, 0);
> -    if(ret < 0) {
> -        printk(KERN_ERR "tm6000: error %i in %s during set
> interface\n",ret,__FUNCTION__);
> -    }
> -
>      if(dvb->bulk_urb) {
> +        printk (KERN_INFO "urb killing\n");
>          usb_kill_urb(dvb->bulk_urb);
> +        printk (KERN_INFO "urb buffer free\n");
>          kfree(dvb->bulk_urb->transfer_buffer);
>          usb_free_urb(dvb->bulk_urb);
>          dvb->bulk_urb = NULL;
> @@ -154,7 +181,7 @@ int tm6000_start_feed(struct dvb_demux_feed *feed)
>      mutex_lock(&dvb->mutex);
>      if(dvb->streams == 0) {
>          dvb->streams = 1;
> -//         mutex_init(&tm6000_dev->streaming_mutex);
> +//        mutex_init(&tm6000_dev->streming_mutex);
>          tm6000_start_stream(dev);
>      }
>      else {
> @@ -173,14 +200,17 @@ int tm6000_stop_feed(struct dvb_demux_feed *feed) {
>      printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
>  
>      mutex_lock(&dvb->mutex);
> -    --dvb->streams;
>  
> -    if(0 == dvb->streams) {
> +    printk (KERN_INFO "stream %#x\n", dvb->streams);
> +    --(dvb->streams);
> +    if(dvb->streams == 0) {
> +        printk (KERN_INFO "stop stream\n");
>          tm6000_stop_stream(dev);
> -//         mutex_destroy(&tm6000_dev->streaming_mutex);
> +//        mutex_destroy(&tm6000_dev->streaming_mutex);
>      }
> +   
>      mutex_unlock(&dvb->mutex);
> -//     mutex_destroy(&tm6000_dev->streaming_mutex);
> +//    mutex_destroy(&tm6000_dev->streaming_mutex);
>  
>      return 0;
>  }
> @@ -191,13 +221,16 @@ int tm6000_dvb_attach_frontend(struct tm6000_core
> *dev)
>  
>      if(dev->caps.has_zl10353) {
>          struct zl10353_config config =
> -                    {.demod_address = dev->demod_addr >> 1,
> +                    {.demod_address = dev->demod_addr,
>                       .no_tuner = 1,
> -//                      .input_frequency = 0x19e9,
> -//                      .r56_agc_targets =  0x1c,
> +                     .parallel_ts = 1,
> +                     .if2 = 45700,
> +                     .disable_i2c_gate_ctrl = 1,
> +                     .tm6000 = 1,
>                      };
>  
>          dvb->frontend = pseudo_zl10353_attach(dev, &config,
> +//        dvb->frontend = dvb_attach (zl10353_attach, &config,

Don't use C99 comments. Always comment with /* */


>                                 &dev->i2c_adap);
>      }
>      else {
> @@ -235,7 +268,8 @@ int tm6000_dvb_register(struct tm6000_core *dev)
>              .i2c_adap = &dev->i2c_adap,
>              .i2c_addr = dev->tuner_addr,
>          };
> -
> +       
> +        dvb->frontend->callback = tm6000_tuner_callback;
>          ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
>          if (ret < 0) {
>              printk(KERN_ERR
> @@ -258,8 +292,8 @@ int tm6000_dvb_register(struct tm6000_core *dev)
>      dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
>                                  | DMX_MEMORY_BASED_FILTERING;
>      dvb->demux.priv = dev;
> -    dvb->demux.filternum = 256;
> -    dvb->demux.feednum = 256;
> +    dvb->demux.filternum = 5; //256;
> +    dvb->demux.feednum = 5; //256;

Don't use C99 comments. Always comment with /* */

>      dvb->demux.start_feed = tm6000_start_feed;
>      dvb->demux.stop_feed = tm6000_stop_feed;
>      dvb->demux.write_to_decoder = NULL;
> @@ -307,7 +341,7 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
>          usb_free_urb(bulk_urb);
>      }
>  
> -//     mutex_lock(&tm6000_driver.open_close_mutex);
> +//    mutex_lock(&tm6000_driver.open_close_mutex);
>      if(dvb->frontend) {
>          dvb_frontend_detach(dvb->frontend);
>          dvb_unregister_frontend(dvb->frontend);
> @@ -317,6 +351,6 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
>      dvb_dmx_release(&dvb->demux);
>      dvb_unregister_adapter(&dvb->adapter);
>      mutex_destroy(&dvb->mutex);
> -//     mutex_unlock(&tm6000_driver.open_close_mutex);
> +//    mutex_unlock(&tm6000_driver.open_close_mutex);
>  
>  }

Please send a separate patch for the dvb fixes.

> diff --git a/drivers/staging/tm6000/tm6000-i2c.c
> b/drivers/staging/tm6000/tm6000-i2c.c
> index 4da10f5..3e43ad7 100644
> --- a/drivers/staging/tm6000/tm6000-i2c.c
> +++ b/drivers/staging/tm6000/tm6000-i2c.c
> @@ -86,6 +86,11 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
>                  msgs[i].len == 1 ? 0 : msgs[i].buf[1],
>                  msgs[i + 1].buf, msgs[i + 1].len);
>              i++;
> +           
> +            if ((dev->dev_type == TM6010) && (addr == 0xc2)) {
> +                tm6000_set_reg(dev, 0x32, 0,0);
> +                tm6000_set_reg(dev, 0x33, 0,0);
> +            }
>              if (i2c_debug >= 2)
>                  for (byte = 0; byte < msgs[i].len; byte++)
>                      printk(" %02x", msgs[i].buf[byte]);
> @@ -99,6 +104,12 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
>                  REQ_16_SET_GET_I2C_WR1_RDN,
>                  addr | msgs[i].buf[0] << 8, 0,
>                  msgs[i].buf + 1, msgs[i].len - 1);
> +               
> +           
> +            if ((dev->dev_type == TM6010) && (addr == 0xc2)) {
> +                tm6000_set_reg(dev, 0x32, 0,0);
> +                tm6000_set_reg(dev, 0x33, 0,0);
> +            }
>          }

Please send a separate patch for the i2c fixes.

On both logic, don't check for 0xc2, but for the i2c address of the tuner. I
have here one device with a tm6000. After having this patch applied, 
I'll test with it, and see if setting those two register values to 0 also fixes
for tm6000.

>          if (i2c_debug >= 2)
>              printk("\n");
> @@ -198,7 +209,7 @@ static struct i2c_algorithm tm6000_algo = {
>  
>  static struct i2c_adapter tm6000_adap_template = {
>      .owner = THIS_MODULE,
> -    .class = I2C_CLASS_TV_ANALOG,
> +    .class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
>      .name = "tm6000",
>      .id = I2C_HW_B_TM6000,
>      .algo = &tm6000_algo,
> diff --git a/drivers/staging/tm6000/tm6000.h
> b/drivers/staging/tm6000/tm6000.h
> index 877cbf6..e403ca0 100644
> --- a/drivers/staging/tm6000/tm6000.h
> +++ b/drivers/staging/tm6000/tm6000.h
> @@ -23,12 +23,15 @@
>  // Use the tm6000-hack, instead of the proper initialization code
>  //#define HACK 1
>  
> +#include "compat.h"
>  #include <linux/videodev2.h>
>  #include <media/v4l2-common.h>
>  #include <media/videobuf-vmalloc.h>
>  #include "tm6000-usb-isoc.h"
>  #include <linux/i2c.h>
> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
>  #include <linux/mutex.h>
> +#endif
>  #include <media/v4l2-device.h>
>  
>  
> @@ -78,6 +81,10 @@ struct tm6000_dmaqueue {
>      /* thread for generating video stream*/
>      struct task_struct         *kthread;
>      wait_queue_head_t          wq;
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
> +    struct semaphore           *notify;
> +    int                        rmmod:1;
> +#endif

You may just drop the code for kernels < 2.6 (on a separate patch). The current
backport starts with 2.6.16.

>      /* Counters to control fps rate */
>      int                        frame;
>      int                        ini_jiffies;
> @@ -90,12 +97,14 @@ enum tm6000_core_state {
>      DEV_MISCONFIGURED = 0x04,
>  };
>  
> +#if 1
>  /* io methods */
>  enum tm6000_io_method {
>      IO_NONE,
>      IO_READ,
>      IO_MMAP,
>  };
> +#endif
>  
>  enum tm6000_mode {
>      TM6000_MODE_UNKNOWN=0,
> @@ -202,6 +211,9 @@ struct tm6000_fh {
>              V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
>              V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
>  
> +/* In tm6000-cards.c */
> +
> +int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
>  /* In tm6000-core.c */
>  
>  int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
> @@ -209,7 +221,6 @@ int tm6000_read_write_usb (struct tm6000_core *dev,
> u8 reqtype, u8 req,
>  int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
>  int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
>  int tm6000_init (struct tm6000_core *dev);
> -int tm6000_init_after_firmware (struct tm6000_core *dev);
>  
>  int tm6000_init_analog_mode (struct tm6000_core *dev);
>  int tm6000_init_digital_mode (struct tm6000_core *dev);
> @@ -231,7 +242,12 @@ int tm6000_set_standard (struct tm6000_core *dev,
> v4l2_std_id *norm);
>  int tm6000_i2c_register(struct tm6000_core *dev);
>  int tm6000_i2c_unregister(struct tm6000_core *dev);
>  
> +#if 1
>  /* In tm6000-queue.c */
> +#if 0
> +int tm6000_init_isoc(struct tm6000_core *dev, int max_packets);
> +void tm6000_uninit_isoc(struct tm6000_core *dev);
> +#endif
>  
>  int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
>  
> @@ -276,3 +292,4 @@ extern int tm6000_debug;
>          __FUNCTION__ , ##arg); } while (0)
>  
>  
> +#endif
>
  
Mauro Carvalho Chehab Feb. 1, 2010, 11:05 p.m. UTC | #6
Stefan Ringel wrote:
> Am 01.02.2010 22:44, schrieb Devin Heitmueller:
>> On Mon, Feb 1, 2010 at 4:23 PM, Stefan Ringel <stefan.ringel@arcor.de> wrote:
>>   
>>>> You should start by breaking it down into a patch series, so that the
>>>> incremental changes can be reviewed.  That will allow you to explain
>>>> in the patch descriptions why all the individual changes you have made
>>>> are required.
>>>>
>>>>
>>>>       
>>> how can I generate it?
>>>     
>> You can use quilt to break it up into a patch series, or create a
>> local hg clone of v4l-dvb.
>>
>>   
>>>> Why did you define a new callback for changing the tuner mode?  We
>>>> have successfully provided infrastructure on other bridges to toggle
>>>> GPIOs when changing modes.  For example, the em28xx has fields in the
>>>> board profile that allow you to toggle GPIOs when going back and forth
>>>> between digital and analog mode.
>>>>
>>>>
>>>>       
>>> I don't know, how you mean it. I'm amateur programmer.
>>>     
>> Look at how the ".dvb_gpio" and ".gpio" fields are used in the board
>> profiles in em28xx-cards.c.  We toggle the GPIOs when switching the
>> from analog to digital mode, without the tuner having to do any sort
>> of callback.
>>
>>   
> It's a bad example. em28xx use a reg-set, but tm6000 not !! It use a
> gpio usb request.
> 
> tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_5, 1);
> 
> 
> I don't know, that it with the ".gpio" fields works. And when it switch
> from analog to digital, I don't see the way.

All devices with Xceive tuners need to reset the chip via GPIO, in order to load
the firmware. On em28xx, I wrote a patch that moved all specific init code to
a struct (basically used by gpio's), and a generic code to do the reset. It basically
contains what GPIO pins are used, and how many time it should wait.

For example:

/* Board Hauppauge WinTV HVR 900 digital */
static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
        {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x04,   0x0f,           10},
        {EM2880_R04_GPO,        0x0c,   0x0f,           10},
        { -1,                   -1,     -1,             -1},
};

The first line of the above code will execute this logic:
	a = read(EM28XXR08_GPIO) & ~0x2e;
	write (a & ~EM_GPIO_4);
	msleep(10);


So, it will basically preserve bits 8,7,6,4 and 1 of register 8,
and will clear bit 4 (EM_GPIO_4 is 1 << 4 - e. g. bit 4).
After that, it will sleep for 10 miliseconds, and will then do a
reset on bit 3 of Register 4 (writing 0, then 1 to the bit).

> 
>>>> What function does the "tm6000" member in the zl10353 config do?  It
>>>> doesn't seem to be used anywhere.
>>>>
>>>>
>>>>       
>>> I'll switch it next week to demodulator module.
>>>     
>> Are you saying the zl10353 isn't working right now in your patch?  I'm
>> a bit confused.  If it doesn't work, then your patch title is a bit
>> misleading since it suggests that your patch provides DVB support for
>> the tm6000.  If it does work, then the tm6000 member shouldn't be
>> needed at all in the zl10353 config.
>>
>>   
> I'm emulating it in hack.c and the zl10353 module doesn't work, if I
> switch to it.

the hack.c needs to be validated against the zl10353, in order to identify
what are the exact needs for tm6000. Some devices require serial mode, while
others require parallel mode.

I bet that playing with zl10353_config, we'll find the proper init values 
required by tm6000.
  
Stefan Ringel Feb. 2, 2010, 4:14 p.m. UTC | #7
Am 02.02.2010 00:05, schrieb Mauro Carvalho Chehab:
> Stefan Ringel wrote:
>   
>> Am 01.02.2010 22:44, schrieb Devin Heitmueller:
>>     
>>> On Mon, Feb 1, 2010 at 4:23 PM, Stefan Ringel <stefan.ringel@arcor.de> wrote:
>>>   
>>>       
>>>>> You should start by breaking it down into a patch series, so that the
>>>>> incremental changes can be reviewed.  That will allow you to explain
>>>>> in the patch descriptions why all the individual changes you have made
>>>>> are required.
>>>>>
>>>>>
>>>>>       
>>>>>           
>>>> how can I generate it?
>>>>     
>>>>         
>>> You can use quilt to break it up into a patch series, or create a
>>> local hg clone of v4l-dvb.
>>>
>>>   
>>>       
>>>>> Why did you define a new callback for changing the tuner mode?  We
>>>>> have successfully provided infrastructure on other bridges to toggle
>>>>> GPIOs when changing modes.  For example, the em28xx has fields in the
>>>>> board profile that allow you to toggle GPIOs when going back and forth
>>>>> between digital and analog mode.
>>>>>
>>>>>
>>>>>       
>>>>>           
>>>> I don't know, how you mean it. I'm amateur programmer.
>>>>     
>>>>         
>>> Look at how the ".dvb_gpio" and ".gpio" fields are used in the board
>>> profiles in em28xx-cards.c.  We toggle the GPIOs when switching the
>>> from analog to digital mode, without the tuner having to do any sort
>>> of callback.
>>>
>>>   
>>>       
>> It's a bad example. em28xx use a reg-set, but tm6000 not !! It use a
>> gpio usb request.
>>
>> tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_5, 1);
>>
>>
>> I don't know, that it with the ".gpio" fields works. And when it switch
>> from analog to digital, I don't see the way.
>>     
> All devices with Xceive tuners need to reset the chip via GPIO, in order to load
> the firmware. On em28xx, I wrote a patch that moved all specific init code to
> a struct (basically used by gpio's), and a generic code to do the reset. It basically
> contains what GPIO pins are used, and how many time it should wait.
>
> For example:
>
> /* Board Hauppauge WinTV HVR 900 digital */
> static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
>         {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
>         {EM2880_R04_GPO,        0x04,   0x0f,           10},
>         {EM2880_R04_GPO,        0x0c,   0x0f,           10},
>         { -1,                   -1,     -1,             -1},
> };
>
> The first line of the above code will execute this logic:
> 	a = read(EM28XXR08_GPIO) & ~0x2e;
> 	write (a & ~EM_GPIO_4);
> 	msleep(10);
>
>
> So, it will basically preserve bits 8,7,6,4 and 1 of register 8,
> and will clear bit 4 (EM_GPIO_4 is 1 << 4 - e. g. bit 4).
> After that, it will sleep for 10 miliseconds, and will then do a
> reset on bit 3 of Register 4 (writing 0, then 1 to the bit).
>   

reset example :

static struct tm6010_seq terratec[] = {
            {TM6010_GPIO_2,    1,    60},  /* GPIO 2 going to high */
            {TM6010_GPIO_2,    0,    75},  /* GPIO 2 going to lo */
            {TM6010_GPIO_2,    1,    60},  /* GPIO 2 going to high */
            { -1         ,    -1,    -1},
}

Is that correct?


>>     
>>>>> What function does the "tm6000" member in the zl10353 config do?  It
>>>>> doesn't seem to be used anywhere.
>>>>>
>>>>>
>>>>>       
>>>>>           
>>>> I'll switch it next week to demodulator module.
>>>>     
>>>>         
>>> Are you saying the zl10353 isn't working right now in your patch?  I'm
>>> a bit confused.  If it doesn't work, then your patch title is a bit
>>> misleading since it suggests that your patch provides DVB support for
>>> the tm6000.  If it does work, then the tm6000 member shouldn't be
>>> needed at all in the zl10353 config.
>>>
>>>   
>>>       
>> I'm emulating it in hack.c and the zl10353 module doesn't work, if I
>> switch to it.
>>     
> the hack.c needs to be validated against the zl10353, in order to identify
> what are the exact needs for tm6000. Some devices require serial mode, while
> others require parallel mode.
>
> I bet that playing with zl10353_config, we'll find the proper init values 
> required by tm6000.
>
>   

I have separately write in the hack.c the value from terratec hybrid
stick. The older value I haven't clean.
  
Mauro Carvalho Chehab Feb. 2, 2010, 4:44 p.m. UTC | #8
Stefan Ringel wrote:

>> So, it will basically preserve bits 8,7,6,4 and 1 of register 8,
>> and will clear bit 4 (EM_GPIO_4 is 1 << 4 - e. g. bit 4).
>> After that, it will sleep for 10 miliseconds, and will then do a
>> reset on bit 3 of Register 4 (writing 0, then 1 to the bit).
>>   
> 
> reset example :
> 
> static struct tm6010_seq terratec[] = {
>             {TM6010_GPIO_2,    1,    60},  /* GPIO 2 going to high */
>             {TM6010_GPIO_2,    0,    75},  /* GPIO 2 going to lo */
>             {TM6010_GPIO_2,    1,    60},  /* GPIO 2 going to high */
>             { -1         ,    -1,    -1},
> }
> 
> Is that correct?

Yes. In the case of tm6010, it has separate registers for each GPIO, so, you
don't need a bitmask.

>> the hack.c needs to be validated against the zl10353, in order to identify
>> what are the exact needs for tm6000. Some devices require serial mode, while
>> others require parallel mode.
>>
>> I bet that playing with zl10353_config, we'll find the proper init values 
>> required by tm6000.
>>
>>   
> 
> I have separately write in the hack.c the value from terratec hybrid
> stick. The older value I haven't clean.

Ok, but maybe you missed my point: at the long term, we should get rid of hack.c, and
be sure that all needed initializations are done by zl10353 driver or by tm6010-dvb.
  
Stefan Ringel Feb. 2, 2010, 5:24 p.m. UTC | #9
Am 01.02.2010 23:52, schrieb Mauro Carvalho Chehab:
> Stefan Ringel wrote:
>   
>> add Terratec Cinergy Hybrid XE
>> bugfix i2c transfer
>> add frontend callback
>> add init for tm6010
>> add digital-init for tm6010
>> add callback for analog/digital switch
>> bugfix usb transfer in DVB-mode
>>
>> signed-off-by: Stefan Ringel <stefan.ringel@arcor.de>
>>     
> Devin is right with respect to the changes: you should break into small
> patches for us to better understand what you're doing. 
>
> In particular, some parts of the changes (like tuner-xc2028) are known 
> to be working fine with other drivers, so any change there should be done 
> with the enough care to not break other drivers.
>
>   
>> diff --git a/drivers/media/common/tuners/tuner-xc2028.c
>> b/drivers/media/common/tuners/tuner-xc2028.c
>> index ed50168..2297c00 100644
>> --- a/drivers/media/common/tuners/tuner-xc2028.c
>> +++ b/drivers/media/common/tuners/tuner-xc2028.c
>> @@ -15,6 +15,7 @@
>>  #include <linux/delay.h>
>>  #include <media/tuner.h>
>>  #include <linux/mutex.h>
>> +#include "compat.h"
>>  #include <asm/unaligned.h>
>>  #include "tuner-i2c.h"
>>  #include "tuner-xc2028.h"
>> @@ -994,6 +995,13 @@ static int generic_set_freq(struct dvb_frontend
>> *fe, u32 freq /* in HZ */,
>>             buf[0], buf[1], buf[2], buf[3],
>>             freq / 1000000, (freq % 1000000) / 1000);
>>  
>> +    if (priv->ctrl.switch_mode) {
>> +        if (new_mode == T_ANALOG_TV)
>> +            do_tuner_callback(fe, SWITCH_TV_MODE, 0);
>> +        if (new_mode == T_DIGITAL_TV)
>> +            do_tuner_callback(fe, SWITCH_TV_MODE, 1);
>> +    }
>> +   
>>      rc = 0;
>>     
> The decision taken at the driver were the opposite: the bridge driver should
> have the logic to reset the tuner. This works perfectly on em28xx and other
> drivers that use xc3028.
>
> I don't see a good reason to revert the logic here. Also, such change should
> be done on all drivers that use xc3028 and xc5000.
>
>   
>>  
>>  ret:
>> @@ -1114,7 +1122,11 @@ static int xc2028_set_params(struct dvb_frontend *fe,
>>  
>>      /* All S-code tables need a 200kHz shift */
>>      if (priv->ctrl.demod) {
>> -        demod = priv->ctrl.demod + 200;
>> +        if (priv->ctrl.fname == "xc3028L-v36.fw") {
>> +            demod = priv->ctrl.demod;
>> +        } else {
>> +            demod = priv->ctrl.demod + 200;
>> +        }
>>     
> Instead, you should be using the firmware version. 
>
> As the firmware version is written at the firmware file, it is easy to do the tests 
> based on the firmware version, even on devices like tm6000 where the version read
> method may fail.
>   
Not with the i2c patch, see down.
>  
> Yet, I suspect that the currently available v36 firmwares already take this into 
> consideration (or the drivers that use those firmwares do the offset internally).
>
> So, this change needs to be checked against the existing drivers.
>
>   
>>          /*
>>           * The DTV7 S-code table needs a 700 kHz shift.
>>           * Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this
>> @@ -1123,8 +1135,8 @@ static int xc2028_set_params(struct dvb_frontend *fe,
>>           * use this firmware after initialization, but a tune to a UHF
>>           * channel should then cause DTV78 to be used.
>>           */
>> -        if (type & DTV7)
>> -            demod += 500;
>> +        if (type  & DTV7)
>> +        demod += 500;
>>     
> This hunk is wrong.
>
>   
Why that generated the git diff, I cannot say. It must be the older once.
>>      }
>>  
>>      return generic_set_freq(fe, p->frequency,
>> @@ -1240,6 +1252,10 @@ static const struct dvb_tuner_ops
>> xc2028_dvb_tuner_ops = {
>>      .get_rf_strength   = xc2028_signal,
>>      .set_params        = xc2028_set_params,
>>      .sleep             = xc2028_sleep,
>> +#if 0
>> +    int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
>> +    int (*get_status)(struct dvb_frontend *fe, u32 *status);
>> +#endif
>>  };
>>  
>>  struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
>> diff --git a/drivers/media/common/tuners/tuner-xc2028.h
>> b/drivers/media/common/tuners/tuner-xc2028.h
>> index 9778c96..c9a4fb4 100644
>> --- a/drivers/media/common/tuners/tuner-xc2028.h
>> +++ b/drivers/media/common/tuners/tuner-xc2028.h
>> @@ -42,6 +42,7 @@ struct xc2028_ctrl {
>>      unsigned int        disable_power_mgmt:1;
>>      unsigned int            read_not_reliable:1;
>>      unsigned int        demod;
>> +    unsigned int        switch_mode:1;
>>     
> This struct is meant to pass static parameters to the driver. the analog/digital
> mode is dynamic, so, this is not the right place for doing it.
>
>   
Can you tell me how that work? Where would call it? Switch it after read
demodulator status or before? This switch switches the  tuner output to
the demodulator or adc input and if it read status before it switch
thoughts the apps  "no digital found".
>>      enum firmware_type    type:2;
>>  };
>>  
>> @@ -54,6 +55,7 @@ struct xc2028_config {
>>  /* xc2028 commands for callback */
>>  #define XC2028_TUNER_RESET    0
>>  #define XC2028_RESET_CLK    1
>> +#define SWITCH_TV_MODE        2
>>  
>>  #if defined(CONFIG_MEDIA_TUNER_XC2028) ||
>> (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
>>  extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
>> diff --git a/drivers/media/dvb/frontends/zl10353.h
>> b/drivers/media/dvb/frontends/zl10353.h
>> index 6e3ca9e..015bc36 100644
>> --- a/drivers/media/dvb/frontends/zl10353.h
>> +++ b/drivers/media/dvb/frontends/zl10353.h
>> @@ -45,6 +45,8 @@ struct zl10353_config
>>      /* clock control registers (0x51-0x54) */
>>      u8 clock_ctl_1;  /* default: 0x46 */
>>      u8 pll_0;        /* default: 0x15 */
>> +   
>> +    int tm6000:1;
>>     
> This doesn't make sense. The zl10353 doesn't need to know if the device is
> a tm6000 or not. If the tm6000 driver needs something special, then we need
> to discover what he is doing and name the zl10353 feature accordingly.
>
>
>   
that is for todo in next week, when I switch from hack.c to zl10353
kernel module, but it can remove if it don't use.
>>  };
>>  
>>  #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE)
>> && defined(MODULE))
>> diff --git a/drivers/staging/tm6000/hack.c b/drivers/staging/tm6000/hack.c
>> index f181fce..c1e1880 100644
>> --- a/drivers/staging/tm6000/hack.c
>> +++ b/drivers/staging/tm6000/hack.c
>> @@ -37,7 +37,6 @@ static inline int tm6000_snd_control_msg(struct
>> tm6000_core *dev, __u8 request,
>>     
> This "hack" file is a good candidate to be removed ;) It is, in fact a zl10353
> code with the tm6000 initialization, made by cloning the zl10353 parameters
> that the original driver does.
>
>   
>>  
>>  static int pseudo_zl10353_pll(struct tm6000_core *tm6000_dev, struct
>> dvb_frontend_parameters *p)
>>  {
>> -    int ret;
>>      u8 *data = kzalloc(50*sizeof(u8), GFP_KERNEL);
>>  
>>  printk(KERN_ALERT "should set frequency %u\n", p->frequency);
>> @@ -51,7 +50,7 @@ printk(KERN_ALERT "and bandwith %u\n",
>> p->u.ofdm.bandwidth);
>>      }
>>  
>>      // init ZL10353
>> -    data[0] = 0x0b;
>> +/*    data[0] = 0x0b;
>>      ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x501e, 0x00, data,
>> 0x1);
>>      msleep(15);
>>      data[0] = 0x80;
>> @@ -159,7 +158,7 @@ printk(KERN_ALERT "and bandwith %u\n",
>> p->u.ofdm.bandwidth);
>>              msleep(15);
>>              data[0] = 0x5a;
>>              ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e,
>> 0x00, data, 0x1);
>> -            msleep(15);
>> +            msleep(15)
>>              data[0] = 0xe9;
>>              ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e,
>> 0x00, data, 0x1);
>>              msleep(15);
>> @@ -189,7 +188,162 @@ printk(KERN_ALERT "and bandwith %u\n",
>> p->u.ofdm.bandwidth);
>>              msleep(15);
>>          break;
>>      }
>> -
>> +*/
>>     
> Please use #if 0 to temporarily remove a code that it is not needed. Yet, maybe
> removing this code will break tm6000 devices. tm6010 has some differences
> when compared with tm6000. So, if your device is tm6010, the better is to
> run the above code if is not a tm6010.
>
>   
o. k.
>> +    switch(p->u.ofdm.bandwidth) {
>> +        case BANDWIDTH_8_MHZ:
>> +            data[0] = 0x03;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x501e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x44;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x511e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x40;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x46;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x521e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x15;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x531e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x0f;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x541e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x80;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x01;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x00;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x8b;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x631e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x75;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xcc1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0xe6; //0x19;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6c1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x09; //0xf7;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6d1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x67;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x651e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0xe5;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x661e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x75;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5c1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x17;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5f1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x40;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5e1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x01;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x701e,0,data,1);
>> +            msleep(40);
>> +            break;
>> +        case BANDWIDTH_7_MHZ:
>> +            data[0] = 0x03;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x501e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x44;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x511e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x40;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x46;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x521e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x15;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x531e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x0f;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x541e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x80;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x01;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x00;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x83;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x631e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0xa3;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xcc1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0xe6; //0x19;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6c1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x09; //0xf7;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6d1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x5a;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x651e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0xe9;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x661e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x86;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5c1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x17;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5f1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x40;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5e1e,0,data,1);
>> +            msleep(40);
>> +            data[0] = 0x01;
>> +            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x701e,0,data,1);
>> +            msleep(40);
>> +            break;
>> +        default:
>> +            printk(KERN_ALERT "tm6000: bandwidth not supported\n");
>> +    }
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x0f1f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x091f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>> +   
>> +    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x0b1f,0,data,2);
>> +    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
>> +    msleep(40);
>>     
> The same comment here: maybe the above code only applies to tm6010.
>
>   
It little different to the other hack code. The lastest lines are
reading demod status.
>> +   
>>      kfree(data);
>>  
>>      return 0;
>> diff --git a/drivers/staging/tm6000/tm6000-cards.c
>> b/drivers/staging/tm6000/tm6000-cards.c
>> index 59fb505..652a54a 100644
>> --- a/drivers/staging/tm6000/tm6000-cards.c
>> +++ b/drivers/staging/tm6000/tm6000-cards.c
>> @@ -32,7 +32,7 @@
>>  #include "tm6000.h"
>>  #include "tm6000-regs.h"
>>  #include "tuner-xc2028.h"
>> -#include "tuner-xc5000.h"
>> +#include "xc5000.h"
>>     
> Please send this hunk on a separate patch. Since it fixes compilation, I'll
> need to apply it before the Kconfig changes, when tm6000 upstream.
>
>   
o.k. but I cannot know how. I have no idea with diff or something.
>>  
>>  #define TM6000_BOARD_UNKNOWN            0
>>  #define TM5600_BOARD_GENERIC            1
>> @@ -44,6 +44,10 @@
>>  #define TM6000_BOARD_FREECOM_AND_SIMILAR    7
>>  #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV    8
>>  #define TM6010_BOARD_HAUPPAUGE_900H        9
>> +#define TM6010_BOARD_BEHOLD_WANDER        10
>> +#define TM6010_BOARD_BEHOLD_VOYAGER        11
>> +#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE    12
>> +
>>  
>>  #define TM6000_MAXBOARDS        16
>>  static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
>> @@ -208,7 +212,21 @@ struct tm6000_board tm6000_boards[] = {
>>          },
>>          .gpio_addr_tun_reset = TM6000_GPIO_2,
>>      },
>> -
>> +    [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
>> +        .name         = "Terratec Cinergy Hybrid XE",
>> +        .tuner_type   = TUNER_XC2028, /* has a XC3028 */
>> +        .tuner_addr   = 0xc2 >> 1,
>> +        .demod_addr   = 0x1e >> 1,
>> +        .type         = TM6010,
>> +        .caps = {
>> +            .has_tuner    = 1,
>> +            .has_dvb      = 1,
>> +            .has_zl10353  = 1,
>> +            .has_eeprom   = 1,
>> +            .has_remote   = 1,
>> +        },
>> +        .gpio_addr_tun_reset = TM6010_GPIO_2,
>> +    }
>>  };
>>  
>>  /* table of devices that work with this driver */
>> @@ -221,12 +239,13 @@ struct usb_device_id tm6000_id_table [] = {
>>      { USB_DEVICE(0x2040, 0x6600), .driver_info =
>> TM6010_BOARD_HAUPPAUGE_900H },
>>      { USB_DEVICE(0x6000, 0xdec0), .driver_info =
>> TM6010_BOARD_BEHOLD_WANDER },
>>      { USB_DEVICE(0x6000, 0xdec1), .driver_info =
>> TM6010_BOARD_BEHOLD_VOYAGER },
>> +    { USB_DEVICE(0x0ccd, 0x0086), .driver_info =
>> TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
>>      { },
>>  };
>>     
> New board definition: please send this as a separate patch.
>
>   
>>  
>>  /* Tuner callback to provide the proper gpio changes needed for xc2028 */
>>  
>> -static int tm6000_tuner_callback(void *ptr, int component, int command,
>> int arg)
>> +int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
>>  {
>>      int rc=0;
>>      struct tm6000_core *dev = ptr;
>> @@ -252,11 +271,14 @@ static int tm6000_tuner_callback(void *ptr, int
>> component, int command, int arg)
>>          switch (arg) {
>>          case 0:
>>              tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>> +                    dev->tuner_reset_gpio, 0x01);
>> +            msleep(60);
>> +            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>>                      dev->tuner_reset_gpio, 0x00);
>> -            msleep(130);
>> +            msleep(75);
>>              tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>>                      dev->tuner_reset_gpio, 0x01);
>> -            msleep(130);
>> +            msleep(60);
>>              break;
>>          case 1:
>>              tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
>> @@ -269,13 +291,33 @@ static int tm6000_tuner_callback(void *ptr, int
>> component, int command, int arg)
>>                          TM6000_GPIO_CLK, 0);
>>              if (rc<0)
>>                  return rc;
>> -            msleep(100);
>> +            msleep(10);
>>              rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>>                          TM6000_GPIO_CLK, 1);
>> -            msleep(100);
>> +            msleep(10);
>> +            break;
>> +        }
>> +        break;
>> +       
>> +    case SWITCH_TV_MODE:
>> +        /* switch between analog and  digital */
>> +        switch (arg) {
>> +        case 0:
>> +            printk(KERN_INFO "switch to analog");
>> +            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>> +                    TM6010_GPIO_5, 1);
>> +            printk(KERN_INFO "analog");
>> +            break;
>> +        case 1:
>> +            printk(KERN_INFO "switch to digital");
>> +            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
>> +                    TM6010_GPIO_5, 0);
>> +            printk(KERN_INFO "digital");
>>              break;
>>          }
>> +    break;
>>      }
>>     
> Those tuner callback initializations are board-specific. So, it is better to test
> for your board model, if you need something different than what's currently done.
>
>   
This tuner reset works with my stick, but I think that can test with
other tm6000 based sticks and if it not works then I can say this as a
board-specific.
>> +   
>>      return (rc);
>>  }
>>  
>> @@ -290,7 +332,7 @@ static void tm6000_config_tuner (struct tm6000_core
>> *dev)
>>      memset(&tun_setup, 0, sizeof(tun_setup));
>>      tun_setup.type   = dev->tuner_type;
>>      tun_setup.addr   = dev->tuner_addr;
>> -    tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
>> +    tun_setup.mode_mask = T_ANALOG_TV | T_RADIO | T_DIGITAL_TV;
>>      tun_setup.tuner_callback = tm6000_tuner_callback;
>>  
>>      v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
>> &tun_setup);
>> @@ -302,15 +344,19 @@ static void tm6000_config_tuner (struct
>> tm6000_core *dev)
>>          memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
>>          memset (&ctl,0,sizeof(ctl));
>>  
>> -        ctl.mts   = 1;
>> -        ctl.read_not_reliable = 1;
>> +        ctl.input1 = 1;
>> +        ctl.read_not_reliable = 0;
>>          ctl.msleep = 10;
>> -
>> +        ctl.demod = XC3028_FE_ZARLINK456;
>> +        ctl.vhfbw7 = 1;
>> +        ctl.uhfbw8 = 1;
>> +        ctl.switch_mode = 1;
>>          xc2028_cfg.tuner = TUNER_XC2028;
>>          xc2028_cfg.priv  = &ctl;
>>  
>>          switch(dev->model) {
>>          case TM6010_BOARD_HAUPPAUGE_900H:
>> +        case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
>>              ctl.fname = "xc3028L-v36.fw";
>>              break;
>>          default:
>>     
>   
>> @@ -402,6 +448,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
>>          }
>>  #endif
>>      }
>> +    return 0;
>>  
>>  err2:
>>      v4l2_device_unregister(&dev->v4l2_dev);
>>     
> This hunk also looks a bug fix. If so, please submit as a separate patch.
>
>   
o. k.
>> @@ -459,13 +506,13 @@ static int tm6000_usb_probe(struct usb_interface
>> *interface,
>>      /* Check to see next free device and mark as used */
>>      nr=find_first_zero_bit(&tm6000_devused,TM6000_MAXBOARDS);
>>      if (nr >= TM6000_MAXBOARDS) {
>> -        printk ("tm6000: Supports only %i em28xx
>> boards.\n",TM6000_MAXBOARDS);
>> +        printk ("tm6000: Supports only %i tm60xx
>> boards.\n",TM6000_MAXBOARDS);
>>          usb_put_dev(usbdev);
>>          return -ENOMEM;
>>      }
>>     
> Also a typo bug fix. I don't really mind if you fold this with another patch,
> but the better would be to have a separate patch for it.
>
>   
o.k.
>>  
>>      /* Create and initialize dev struct */
>> -    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>> +    dev = kzalloc(sizeof(*(dev)), GFP_KERNEL);
>>     
> The extra parenthesis is uneeded here.
>
>   
o.k. I switch it to older once.
>>      if (dev == NULL) {
>>          printk ("tm6000" ": out of memory!\n");
>>          usb_put_dev(usbdev);
>> diff --git a/drivers/staging/tm6000/tm6000-core.c
>> b/drivers/staging/tm6000/tm6000-core.c
>> index d41af1d..33bbbd3 100644
>> --- a/drivers/staging/tm6000/tm6000-core.c
>> +++ b/drivers/staging/tm6000/tm6000-core.c
>> @@ -219,33 +219,53 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
>>  
>>  int tm6000_init_digital_mode (struct tm6000_core *dev)
>>  {
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
>> -
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
>> -    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
>> -    msleep(50);
>> -
>> -    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
>> -    msleep(50);
>> -    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
>> -    msleep(50);
>> -    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
>> -    msleep(100);
>> -
>> +    if (dev->dev_type == TM6010) {
>> +        int val;
>> +        u8 buf[2];
>> +       
>> +        /* digital init */
>> +        val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, 0);
>> +        val &= ~0x60;
>> +        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, val);
>> +        val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, 0);
>> +        val |= 0x40;
>> +        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, val);
>> +        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xfe, 0x28);
>> +        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xfc);
>> +        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xe6, 0xff);
>> +        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
>> +        printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
>> +       
>> +
>> +    } else  {
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
>> +
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
>> +        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
>> +        msleep(50);
>> +
>> +        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
>> +        msleep(50);
>> +        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
>> +        msleep(50);
>> +        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
>> +        msleep(100);
>> +    }
>>      return 0;
>>  }
>>  
>> @@ -394,7 +414,15 @@ struct reg_init tm6010_init_tab[] = {
>>      { REQ_07_SET_GET_AVREG, 0x3f, 0x00 },
>>  
>>      { REQ_05_SET_GET_USBREG, 0x18, 0x00 },
>> -
>> +   
>> +    /* additional from Terratec Cinergy Hybrid XE */
>> +    { REQ_07_SET_GET_AVREG, 0xdc, 0xaa },
>> +    { REQ_07_SET_GET_AVREG, 0xdd, 0x30 },
>> +    { REQ_07_SET_GET_AVREG, 0xde, 0x20 },
>> +    { REQ_07_SET_GET_AVREG, 0xdf, 0xd0 },
>> +    { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
>> +    { REQ_07_SET_GET_AVREG, 0xd8, 0x2f },
>> +   
>>      /* set remote wakeup key:any key wakeup */
>>      { REQ_07_SET_GET_AVREG,  0xe5,  0xfe },
>>      { REQ_07_SET_GET_AVREG,  0xda,  0xff },
>> @@ -404,6 +432,7 @@ int tm6000_init (struct tm6000_core *dev)
>>  {
>>      int board, rc=0, i, size;
>>      struct reg_init *tab;
>> +    u8 buf[40];
>>     
> Why "40" ? Please avoid using magic numbers here, especially if you're
> not checking at the logic if you're writing outside the buffer.
>
>   
It important for tm6010 init sequence to enable the demodulator, because
the demodulator haven't found after init tuner.
>>      if (dev->dev_type == TM6010) {
>>          tab = tm6010_init_tab;
>> @@ -424,61 +453,129 @@ int tm6000_init (struct tm6000_core *dev)
>>          }
>>      }
>>  
>> -    msleep(5); /* Just to be conservative */
>> -
>> -    /* Check board version - maybe 10Moons specific */
>> -    board=tm6000_get_reg16 (dev, 0x40, 0, 0);
>> -    if (board >=0) {
>> -        printk (KERN_INFO "Board version = 0x%04x\n",board);
>> -    } else {
>> -        printk (KERN_ERR "Error %i while retrieving board
>> version\n",board);
>> -    }
>> -
>> +    /* hack */
>>      if (dev->dev_type == TM6010) {
>> -        /* Turn xceive 3028 on */
>> -        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_3, 0x01);
>> -        msleep(11);
>> -    }
>> -
>> -    /* Reset GPIO1 and GPIO4. */
>> -    for (i=0; i< 2; i++) {
>> -        rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> -                    dev->tuner_reset_gpio, 0x00);
>> -        if (rc<0) {
>> -            printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
>> -            return rc;
>> -        }
>> -
>> -        msleep(10); /* Just to be conservative */
>> -        rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> -                    dev->tuner_reset_gpio, 0x01);
>> -        if (rc<0) {
>> -            printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
>> -            return rc;
>> -        }
>> -
>> -        msleep(10);
>> -        rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 0);
>> -        if (rc<0) {
>> -            printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
>> -            return rc;
>> -        }
>> -
>> -        msleep(10);
>> -        rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 1);
>> -        if (rc<0) {
>> -            printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
>> -            return rc;
>> -        }
>> -
>> -        if (!i) {
>> -            rc=tm6000_get_reg16(dev, 0x40,0,0);
>> -            if (rc>=0) {
>> -                printk ("board=%d\n", rc);
>> +       
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_4, 0);
>> +        msleep(15);
>> +               
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_1, 0);
>> +   
>> +        msleep(50);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_1, 1);
>> +       
>> +        msleep(15);
>>     
>
> The reset code are device dependent. Please don't remove the previous code, or you'll
> break the init for the other devices. Instead, add a switch above, checking for your
> specific model. The better is to have all those device-specific initializations inside
> tm6000-cards. Please take a look on how this is solved on em28xx driver.
>
>   
GPIO 1 is the demodulator reset and gpio 4 is lo when tm6010 initialize.
>> +        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x0010, 0x4400, buf, 2);
>> +       
>> +        msleep(15);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0xf432, 0x0000, buf, 2);
>> +   
>> +        msleep(15);
>> +        buf[0] = 0x12;
>> +        buf[1] = 0x34;
>> +        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf432, 0x0000, buf, 2);
>> +   
>> +        msleep(15);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0xf432, 0x0000, buf, 2);
>> +   
>> +        msleep(15);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x0032, 0x0000, buf, 2);
>> +
>> +        msleep(15);
>> +        buf[0] = 0x00;
>> +        buf[1] = 0x01;
>> +        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf332, 0x0000, buf, 2);
>> +   
>> +        msleep(15);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x00c0, 0x0000, buf, 39);
>> +   
>> +        msleep(15);
>> +        buf[0] = 0x00;
>> +        buf[1] = 0x00;
>> +        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf332, 0x0000, buf, 2);
>> +   
>> +        msleep(15);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x7f1f, 0x0000, buf, 2);
>> +//        printk(KERN_INFO "buf %#x %#x \n", buf[0], buf [1]);
>> +        msleep(15);
>>     
>
> Insead, use tm6000_get_reg() or tm6000_set_reg(). Passing the USB direction as
> 0x40/0xc0 is very ugly, and makes the code harder to understand.
>
>   
I cannot use it, because it is a i2c transfer! The reading or writing
data is in buf. (reading can it)
> Also,
> 	req=0x0e corresponds to REQ_14_SET_GET_I2C_WR2_RDN
> 	req=0x10 corresponds to REQ_16_SET_GET_I2C_WR1_RDN
>
> So, the above code is just reading/writing some data via I2C. It should be replaced
> by some changes at the corresponding i2c driver for the devices that the above
> code is controlling.
>
> As a temporary hack, you might do some initialization by calling i2c_master_send/
> i2c_master_recv. For example, em28xx driver has this hack:
>
> /* FIXME: Should be replaced by a proper mt9m001 driver */
> static int em28xx_initialize_mt9m001(struct em28xx *dev)
> {
>         int i;
>         unsigned char regs[][3] = {
>                 { 0x0d, 0x00, 0x01, },
>                 { 0x0d, 0x00, 0x00, },
>                 { 0x04, 0x05, 0x00, },  /* hres = 1280 */
>                 { 0x03, 0x04, 0x00, },  /* vres = 1024 */
>                 { 0x20, 0x11, 0x00, },
>                 { 0x06, 0x00, 0x10, },
>                 { 0x2b, 0x00, 0x24, },
>                 { 0x2e, 0x00, 0x24, },
>                 { 0x35, 0x00, 0x24, },
>                 { 0x2d, 0x00, 0x20, },
>                 { 0x2c, 0x00, 0x20, },
>                 { 0x09, 0x0a, 0xd4, },
>                 { 0x35, 0x00, 0x57, },
>         };
>
>         for (i = 0; i < ARRAY_SIZE(regs); i++)
>                 i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
>
>         return 0;
> }
>
>
>   
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_4, 1);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                    TM6010_GPIO_0, 1);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_7, 0);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_5, 1);
>> +   
>> +        msleep(15);
>>     
> Also, this is device-specific.
>   
after tm6000 initialize gpio 4 go to high (GPIO 4 is lo if it
initialze). I think when it device-specific is then for all tm6010!!
GPIO 0 and 7 ?? GPIO 5 a/d switch (from tuner to demodulator or adc).
>   
>> +   
>> +        for (i=0; i< size; i++) {
>> +            rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
>> +            if (rc<0) {
>> +                printk (KERN_ERR "Error %i while setting req %d, "
>> +                         "reg %d to value %d\n", rc,
>> +                         tab[i].req,tab[i].reg, tab[i].val);
>> +                return rc;
>>              }
>>          }
>> +           
>> +        msleep(15);
>>     
>
>   
>> +   
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_4, 0);
>> +        msleep(15);
>> +
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_1, 0);
>> +   
>> +        msleep(50);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_1, 1);
>> +       
>> +        msleep(15);
>> +        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
>> +//        printk(KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_2, 1);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_2, 0);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_2, 1);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_2, 1);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_2, 0);
>> +        msleep(15);
>> +        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
>> +                TM6010_GPIO_2, 1);
>> +        msleep(15);
>>      }
>> +    /* hack end */
>>     
> Idem. All GPIO's are  device-specific.
>
>   
GPIO 2 is tuner reset and can remove, I think.
>> +   
>> +    msleep(5); /* Just to be conservative */
>>  
>> +    /* Check board version - maybe 10Moons specific */
>> +    if (dev->dev_type == TM5600) {
>> +         board=tm6000_get_reg16 (dev, 0x40, 0, 0);
>> +        if (board >=0) {
>> +            printk (KERN_INFO "Board version = 0x%04x\n",board);
>> +        } else {
>> +            printk (KERN_ERR "Error %i while retrieving board
>> version\n",board);
>> +        }
>> +    }
>> +   
>>      msleep(50);
>>  
>>      return 0;
>> diff --git a/drivers/staging/tm6000/tm6000-dvb.c
>> b/drivers/staging/tm6000/tm6000-dvb.c
>> index e900d6d..31458d3 100644
>> --- a/drivers/staging/tm6000/tm6000-dvb.c
>> +++ b/drivers/staging/tm6000/tm6000-dvb.c
>> @@ -17,7 +17,9 @@
>>     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>>   */
>>  
>> +#include <linux/kernel.h>
>>  #include <linux/usb.h>
>> +#include <compat.h>
>>  
>>  #include "tm6000.h"
>>  #include "tm6000-regs.h"
>> @@ -30,17 +32,61 @@
>>  
>>  #include "tuner-xc2028.h"
>>  
>> +static void inline print_err_status (struct tm6000_core *dev,
>> +                     int packet, int status)
>> +{
>> +    char *errmsg = "Unknown";
>> +
>> +    switch(status) {
>> +    case -ENOENT:
>> +        errmsg = "unlinked synchronuously";
>> +        break;
>> +    case -ECONNRESET:
>> +        errmsg = "unlinked asynchronuously";
>> +        break;
>> +    case -ENOSR:
>> +        errmsg = "Buffer error (overrun)";
>> +        break;
>> +    case -EPIPE:
>> +        errmsg = "Stalled (device not responding)";
>> +        break;
>> +    case -EOVERFLOW:
>> +        errmsg = "Babble (bad cable?)";
>> +        break;
>> +    case -EPROTO:
>> +        errmsg = "Bit-stuff error (bad cable?)";
>> +        break;
>> +    case -EILSEQ:
>> +        errmsg = "CRC/Timeout (could be anything)";
>> +        break;
>> +    case -ETIME:
>> +        errmsg = "Device does not respond";
>> +        break;
>> +    }
>> +    if (packet<0) {
>> +        dprintk(dev, 1, "URB status %d [%s].\n",
>> +            status, errmsg);
>> +    } else {
>> +        dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
>> +            packet, status, errmsg);
>> +    }
>> +}
>> +
>> +
>> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
>> +static void tm6000_urb_received(struct urb *urb, struct pt_regs *ptregs)
>> +#else
>>  static void tm6000_urb_received(struct urb *urb)
>> +#endif
>>  {
>>      int ret;
>>      struct tm6000_core* dev = urb->context;
>>  
>> -    if(urb->status != 0){
>> -        printk(KERN_ERR "tm6000: status != 0\n");
>> +    if(urb->status != 0) {
>> +        print_err_status (dev,0,urb->status);
>>      }
>>      else if(urb->actual_length>0){
>> -        dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
>> -                           urb->actual_length);
>> +        dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
>> urb->actual_length);
>>      }
>>  
>>      if(dev->dvb->streams > 0) {
>> @@ -56,49 +102,37 @@ static void tm6000_urb_received(struct urb *urb)
>>  int tm6000_start_stream(struct tm6000_core *dev)
>>  {
>>      int ret;
>> -    unsigned int pipe, maxPaketSize;
>> +    unsigned int pipe, size;
>>      struct tm6000_dvb *dvb = dev->dvb;
>>  
>>      printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
>>  
>>      tm6000_init_digital_mode(dev);
>>  
>> -/*
>> -    ret = tm6000_set_led_status(tm6000_dev, 0x1);
>> -    if(ret < 0) {
>> -        return -1;
>> -    }
>> -*/
>> -
>>      dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
>>      if(dvb->bulk_urb == NULL) {
>>          printk(KERN_ERR "tm6000: couldn't allocate urb\n");
>>          return -ENOMEM;
>>      }
>>  
>> -    maxPaketSize = dev->bulk_in->desc.wMaxPacketSize;
>> +    pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
>> +                              & USB_ENDPOINT_NUMBER_MASK);
>> +                             
>> +    size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
>> +    size = size * 15; // 512 x 8 or 12 or 15
>>  
>> -    dvb->bulk_urb->transfer_buffer = kzalloc(maxPaketSize, GFP_KERNEL);
>> +    dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
>>      if(dvb->bulk_urb->transfer_buffer == NULL) {
>>          usb_free_urb(dvb->bulk_urb);
>>          printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
>>          return -ENOMEM;
>>      }
>> -
>> -    pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
>> -                              & USB_ENDPOINT_NUMBER_MASK);
>> -
>> +   
>>      usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
>>                           dvb->bulk_urb->transfer_buffer,
>> -                         maxPaketSize,
>> +                         size,
>>                           tm6000_urb_received, dev);
>>  
>> -    ret = usb_set_interface(dev->udev, 0, 1);
>> -    if(ret < 0) {
>> -        printk(KERN_ERR "tm6000: error %i in %s during set
>> interface\n", ret, __FUNCTION__);
>> -        return ret;
>> -    }
>> -
>>      ret = usb_clear_halt(dev->udev, pipe);
>>      if(ret < 0) {
>>          printk(KERN_ERR "tm6000: error %i in %s during pipe
>> reset\n",ret,__FUNCTION__);
>> @@ -107,15 +141,14 @@ int tm6000_start_stream(struct tm6000_core *dev)
>>      else {
>>          printk(KERN_ERR "tm6000: pipe resetted\n");
>>      }
>> -
>> -//     mutex_lock(&tm6000_driver.open_close_mutex);
>> +   
>> +//    mutex_lock(&tm6000_driver.open_close_mutex);
>>      ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
>>  
>> -
>> -//     mutex_unlock(&tm6000_driver.open_close_mutex);
>> +//    mutex_unlock(&tm6000_driver.open_close_mutex);
>>      if (ret) {
>>          printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
>> -
>> +       
>>          kfree(dvb->bulk_urb->transfer_buffer);
>>          usb_free_urb(dvb->bulk_urb);
>>          return ret;
>> @@ -126,18 +159,12 @@ int tm6000_start_stream(struct tm6000_core *dev)
>>  
>>  void tm6000_stop_stream(struct tm6000_core *dev)
>>  {
>> -    int ret;
>>      struct tm6000_dvb *dvb = dev->dvb;
>>  
>> -//     tm6000_set_led_status(tm6000_dev, 0x0);
>> -
>> -    ret = usb_set_interface(dev->udev, 0, 0);
>> -    if(ret < 0) {
>> -        printk(KERN_ERR "tm6000: error %i in %s during set
>> interface\n",ret,__FUNCTION__);
>> -    }
>> -
>>      if(dvb->bulk_urb) {
>> +        printk (KERN_INFO "urb killing\n");
>>          usb_kill_urb(dvb->bulk_urb);
>> +        printk (KERN_INFO "urb buffer free\n");
>>          kfree(dvb->bulk_urb->transfer_buffer);
>>          usb_free_urb(dvb->bulk_urb);
>>          dvb->bulk_urb = NULL;
>> @@ -154,7 +181,7 @@ int tm6000_start_feed(struct dvb_demux_feed *feed)
>>      mutex_lock(&dvb->mutex);
>>      if(dvb->streams == 0) {
>>          dvb->streams = 1;
>> -//         mutex_init(&tm6000_dev->streaming_mutex);
>> +//        mutex_init(&tm6000_dev->streming_mutex);
>>          tm6000_start_stream(dev);
>>      }
>>      else {
>> @@ -173,14 +200,17 @@ int tm6000_stop_feed(struct dvb_demux_feed *feed) {
>>      printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
>>  
>>      mutex_lock(&dvb->mutex);
>> -    --dvb->streams;
>>  
>> -    if(0 == dvb->streams) {
>> +    printk (KERN_INFO "stream %#x\n", dvb->streams);
>> +    --(dvb->streams);
>> +    if(dvb->streams == 0) {
>> +        printk (KERN_INFO "stop stream\n");
>>          tm6000_stop_stream(dev);
>> -//         mutex_destroy(&tm6000_dev->streaming_mutex);
>> +//        mutex_destroy(&tm6000_dev->streaming_mutex);
>>      }
>> +   
>>      mutex_unlock(&dvb->mutex);
>> -//     mutex_destroy(&tm6000_dev->streaming_mutex);
>> +//    mutex_destroy(&tm6000_dev->streaming_mutex);
>>  
>>      return 0;
>>  }
>> @@ -191,13 +221,16 @@ int tm6000_dvb_attach_frontend(struct tm6000_core
>> *dev)
>>  
>>      if(dev->caps.has_zl10353) {
>>          struct zl10353_config config =
>> -                    {.demod_address = dev->demod_addr >> 1,
>> +                    {.demod_address = dev->demod_addr,
>>                       .no_tuner = 1,
>> -//                      .input_frequency = 0x19e9,
>> -//                      .r56_agc_targets =  0x1c,
>> +                     .parallel_ts = 1,
>> +                     .if2 = 45700,
>> +                     .disable_i2c_gate_ctrl = 1,
>> +                     .tm6000 = 1,
>>                      };
>>  
>>          dvb->frontend = pseudo_zl10353_attach(dev, &config,
>> +//        dvb->frontend = dvb_attach (zl10353_attach, &config,
>>     
> Don't use C99 comments. Always comment with /* */
>
>   

all comments except frontend attach is don't from me, but I can convert it.

>   
>>                                 &dev->i2c_adap);
>>      }
>>      else {
>> @@ -235,7 +268,8 @@ int tm6000_dvb_register(struct tm6000_core *dev)
>>              .i2c_adap = &dev->i2c_adap,
>>              .i2c_addr = dev->tuner_addr,
>>          };
>> -
>> +       
>> +        dvb->frontend->callback = tm6000_tuner_callback;
>>          ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
>>          if (ret < 0) {
>>              printk(KERN_ERR
>> @@ -258,8 +292,8 @@ int tm6000_dvb_register(struct tm6000_core *dev)
>>      dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
>>                                  | DMX_MEMORY_BASED_FILTERING;
>>      dvb->demux.priv = dev;
>> -    dvb->demux.filternum = 256;
>> -    dvb->demux.feednum = 256;
>> +    dvb->demux.filternum = 5; //256;
>> +    dvb->demux.feednum = 5; //256;
>>     
> Don't use C99 comments. Always comment with /* */
>
>   

all comments except frontend attach is don't from me, but I can convert it.

>>      dvb->demux.start_feed = tm6000_start_feed;
>>      dvb->demux.stop_feed = tm6000_stop_feed;
>>      dvb->demux.write_to_decoder = NULL;
>> @@ -307,7 +341,7 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
>>          usb_free_urb(bulk_urb);
>>      }
>>  
>> -//     mutex_lock(&tm6000_driver.open_close_mutex);
>> +//    mutex_lock(&tm6000_driver.open_close_mutex);
>>      if(dvb->frontend) {
>>          dvb_frontend_detach(dvb->frontend);
>>          dvb_unregister_frontend(dvb->frontend);
>> @@ -317,6 +351,6 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
>>      dvb_dmx_release(&dvb->demux);
>>      dvb_unregister_adapter(&dvb->adapter);
>>      mutex_destroy(&dvb->mutex);
>> -//     mutex_unlock(&tm6000_driver.open_close_mutex);
>> +//    mutex_unlock(&tm6000_driver.open_close_mutex);
>>  
>>  }
>>     
> Please send a separate patch for the dvb fixes.
>
>   
o.k.
>> diff --git a/drivers/staging/tm6000/tm6000-i2c.c
>> b/drivers/staging/tm6000/tm6000-i2c.c
>> index 4da10f5..3e43ad7 100644
>> --- a/drivers/staging/tm6000/tm6000-i2c.c
>> +++ b/drivers/staging/tm6000/tm6000-i2c.c
>> @@ -86,6 +86,11 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
>>                  msgs[i].len == 1 ? 0 : msgs[i].buf[1],
>>                  msgs[i + 1].buf, msgs[i + 1].len);
>>              i++;
>> +           
>> +            if ((dev->dev_type == TM6010) && (addr == 0xc2)) {
>> +                tm6000_set_reg(dev, 0x32, 0,0);
>> +                tm6000_set_reg(dev, 0x33, 0,0);
>> +            }
>>              if (i2c_debug >= 2)
>>                  for (byte = 0; byte < msgs[i].len; byte++)
>>                      printk(" %02x", msgs[i].buf[byte]);
>> @@ -99,6 +104,12 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
>>                  REQ_16_SET_GET_I2C_WR1_RDN,
>>                  addr | msgs[i].buf[0] << 8, 0,
>>                  msgs[i].buf + 1, msgs[i].len - 1);
>> +               
>> +           
>> +            if ((dev->dev_type == TM6010) && (addr == 0xc2)) {
>> +                tm6000_set_reg(dev, 0x32, 0,0);
>> +                tm6000_set_reg(dev, 0x33, 0,0);
>> +            }
>>          }
>>     
> Please send a separate patch for the i2c fixes.
>
> On both logic, don't check for 0xc2, but for the i2c address of the tuner. I
> have here one device with a tm6000. After having this patch applied, 
> I'll test with it, and see if setting those two register values to 0 also fixes
> for tm6000.
>
>   
o.k.
can I use for the tuner address "dev->tuner_addr"? So it cannot use 0xc2.
>>          if (i2c_debug >= 2)
>>              printk("\n");
>> @@ -198,7 +209,7 @@ static struct i2c_algorithm tm6000_algo = {
>>  
>>  static struct i2c_adapter tm6000_adap_template = {
>>      .owner = THIS_MODULE,
>> -    .class = I2C_CLASS_TV_ANALOG,
>> +    .class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
>>      .name = "tm6000",
>>      .id = I2C_HW_B_TM6000,
>>      .algo = &tm6000_algo,
>> diff --git a/drivers/staging/tm6000/tm6000.h
>> b/drivers/staging/tm6000/tm6000.h
>> index 877cbf6..e403ca0 100644
>> --- a/drivers/staging/tm6000/tm6000.h
>> +++ b/drivers/staging/tm6000/tm6000.h
>> @@ -23,12 +23,15 @@
>>  // Use the tm6000-hack, instead of the proper initialization code
>>  //#define HACK 1
>>  
>> +#include "compat.h"
>>  #include <linux/videodev2.h>
>>  #include <media/v4l2-common.h>
>>  #include <media/videobuf-vmalloc.h>
>>  #include "tm6000-usb-isoc.h"
>>  #include <linux/i2c.h>
>> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
>>  #include <linux/mutex.h>
>> +#endif
>>  #include <media/v4l2-device.h>
>>  
>>  
>> @@ -78,6 +81,10 @@ struct tm6000_dmaqueue {
>>      /* thread for generating video stream*/
>>      struct task_struct         *kthread;
>>      wait_queue_head_t          wq;
>> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
>> +    struct semaphore           *notify;
>> +    int                        rmmod:1;
>> +#endif
>>     
> You may just drop the code for kernels < 2.6 (on a separate patch). The current
> backport starts with 2.6.16.
>
>   
What you mean. Should I send a patch?
>>      /* Counters to control fps rate */
>>      int                        frame;
>>      int                        ini_jiffies;
>> @@ -90,12 +97,14 @@ enum tm6000_core_state {
>>      DEV_MISCONFIGURED = 0x04,
>>  };
>>  
>> +#if 1
>>  /* io methods */
>>  enum tm6000_io_method {
>>      IO_NONE,
>>      IO_READ,
>>      IO_MMAP,
>>  };
>> +#endif
>>  
>>  enum tm6000_mode {
>>      TM6000_MODE_UNKNOWN=0,
>> @@ -202,6 +211,9 @@ struct tm6000_fh {
>>              V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
>>              V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
>>  
>> +/* In tm6000-cards.c */
>> +
>> +int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
>>  /* In tm6000-core.c */
>>  
>>  int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
>> @@ -209,7 +221,6 @@ int tm6000_read_write_usb (struct tm6000_core *dev,
>> u8 reqtype, u8 req,
>>  int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
>>  int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
>>  int tm6000_init (struct tm6000_core *dev);
>> -int tm6000_init_after_firmware (struct tm6000_core *dev);
>>  
>>  int tm6000_init_analog_mode (struct tm6000_core *dev);
>>  int tm6000_init_digital_mode (struct tm6000_core *dev);
>> @@ -231,7 +242,12 @@ int tm6000_set_standard (struct tm6000_core *dev,
>> v4l2_std_id *norm);
>>  int tm6000_i2c_register(struct tm6000_core *dev);
>>  int tm6000_i2c_unregister(struct tm6000_core *dev);
>>  
>> +#if 1
>>  /* In tm6000-queue.c */
>> +#if 0
>> +int tm6000_init_isoc(struct tm6000_core *dev, int max_packets);
>> +void tm6000_uninit_isoc(struct tm6000_core *dev);
>> +#endif
>>  
>>  int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
>>  
>> @@ -276,3 +292,4 @@ extern int tm6000_debug;
>>          __FUNCTION__ , ##arg); } while (0)
>>  
>>  
>> +#endif
>>
>>     
>
>   
Can you tell me how I generate a patch set (detailed once).

Cheers

Stefan Ringel
  
Stefan Ringel Feb. 2, 2010, 5:38 p.m. UTC | #10
Am 02.02.2010 17:44, schrieb Mauro Carvalho Chehab:
> Stefan Ringel wrote:
>
>   
>>> So, it will basically preserve bits 8,7,6,4 and 1 of register 8,
>>> and will clear bit 4 (EM_GPIO_4 is 1 << 4 - e. g. bit 4).
>>> After that, it will sleep for 10 miliseconds, and will then do a
>>> reset on bit 3 of Register 4 (writing 0, then 1 to the bit).
>>>   
>>>       
>> reset example :
>>
>> static struct tm6010_seq terratec[] = {
>>             {TM6010_GPIO_2,    1,    60},  /* GPIO 2 going to high */
>>             {TM6010_GPIO_2,    0,    75},  /* GPIO 2 going to lo */
>>             {TM6010_GPIO_2,    1,    60},  /* GPIO 2 going to high */
>>             { -1         ,    -1,    -1},
>> }
>>
>> Is that correct?
>>     
> Yes. In the case of tm6010, it has separate registers for each GPIO, so, you
> don't need a bitmask.
>
>   
>>> the hack.c needs to be validated against the zl10353, in order to identify
>>> what are the exact needs for tm6000. Some devices require serial mode, while
>>> others require parallel mode.
>>>
>>> I bet that playing with zl10353_config, we'll find the proper init values 
>>> required by tm6000.
>>>
>>>   
>>>       
>> I have separately write in the hack.c the value from terratec hybrid
>> stick. The older value I haven't clean.
>>     
> Ok, but maybe you missed my point: at the long term, we should get rid of hack.c, and
> be sure that all needed initializations are done by zl10353 driver or by tm6010-dvb.
>   
I think I all are done by zl10353 driver.

I thinbk all config param is usefull and ".tm6000" for tm6000 specific
once. For what is ".parallel_ts" ?

int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
{
    struct tm6000_dvb *dvb = dev->dvb;

    if(dev->caps.has_zl10353) {
        struct zl10353_config config =
                    {.demod_address = dev->demod_addr,
                     .no_tuner = 1,
                     .parallel_ts = 1,
                     .if2 = 45700,
                     .disable_i2c_gate_ctrl = 1,
                     .tm6000 = 1,
                    };

        dvb->frontend = pseudo_zl10353_attach(dev, &config,
//        dvb->frontend = dvb_attach (zl10353_attach, &config,
                               &dev->i2c_adap);
    }
    else {
        printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
        return -1;
    }

    return (!dvb->frontend) ? -1 : 0;
}
  
Mauro Carvalho Chehab Feb. 2, 2010, 8:05 p.m. UTC | #11
Stefan Ringel wrote:

>> Ok, but maybe you missed my point: at the long term, we should get rid of hack.c, and
>> be sure that all needed initializations are done by zl10353 driver or by tm6010-dvb.
>>   
> I think I all are done by zl10353 driver.
> 
> I thinbk all config param is usefull and ".tm6000" for tm6000 specific
> once. For what is ".parallel_ts" ?

zl10353 may be connected via a serial or via a parallel interface to the chip.
So, it basically depends on how the wiring between zl10353 and the bridge is done.

> 
> int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
> {
>     struct tm6000_dvb *dvb = dev->dvb;
> 
>     if(dev->caps.has_zl10353) {
>         struct zl10353_config config =
>                     {.demod_address = dev->demod_addr,
>                      .no_tuner = 1,
>                      .parallel_ts = 1,
>                      .if2 = 45700,
>                      .disable_i2c_gate_ctrl = 1,
>                      .tm6000 = 1,
>                     };
> 
>         dvb->frontend = pseudo_zl10353_attach(dev, &config,
> //        dvb->frontend = dvb_attach (zl10353_attach, &config,
>                                &dev->i2c_adap);
>     }
>     else {
>         printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
>         return -1;
>     }
> 
>     return (!dvb->frontend) ? -1 : 0;
> }
> 
>
  

Patch

diff --git a/drivers/media/common/tuners/tuner-xc2028.c
b/drivers/media/common/tuners/tuner-xc2028.c
index ed50168..2297c00 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -15,6 +15,7 @@ 
 #include <linux/delay.h>
 #include <media/tuner.h>
 #include <linux/mutex.h>
+#include "compat.h"
 #include <asm/unaligned.h>
 #include "tuner-i2c.h"
 #include "tuner-xc2028.h"
@@ -994,6 +995,13 @@  static int generic_set_freq(struct dvb_frontend
*fe, u32 freq /* in HZ */,
            buf[0], buf[1], buf[2], buf[3],
            freq / 1000000, (freq % 1000000) / 1000);
 
+    if (priv->ctrl.switch_mode) {
+        if (new_mode == T_ANALOG_TV)
+            do_tuner_callback(fe, SWITCH_TV_MODE, 0);
+        if (new_mode == T_DIGITAL_TV)
+            do_tuner_callback(fe, SWITCH_TV_MODE, 1);
+    }
+   
     rc = 0;
 
 ret:
@@ -1114,7 +1122,11 @@  static int xc2028_set_params(struct dvb_frontend *fe,
 
     /* All S-code tables need a 200kHz shift */
     if (priv->ctrl.demod) {
-        demod = priv->ctrl.demod + 200;
+        if (priv->ctrl.fname == "xc3028L-v36.fw") {
+            demod = priv->ctrl.demod;
+        } else {
+            demod = priv->ctrl.demod + 200;
+        }
         /*
          * The DTV7 S-code table needs a 700 kHz shift.
          * Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this
@@ -1123,8 +1135,8 @@  static int xc2028_set_params(struct dvb_frontend *fe,
          * use this firmware after initialization, but a tune to a UHF
          * channel should then cause DTV78 to be used.
          */
-        if (type & DTV7)
-            demod += 500;
+        if (type  & DTV7)
+        demod += 500;
     }
 
     return generic_set_freq(fe, p->frequency,
@@ -1240,6 +1252,10 @@  static const struct dvb_tuner_ops
xc2028_dvb_tuner_ops = {
     .get_rf_strength   = xc2028_signal,
     .set_params        = xc2028_set_params,
     .sleep             = xc2028_sleep,
+#if 0
+    int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+    int (*get_status)(struct dvb_frontend *fe, u32 *status);
+#endif
 };
 
 struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/common/tuners/tuner-xc2028.h
b/drivers/media/common/tuners/tuner-xc2028.h
index 9778c96..c9a4fb4 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -42,6 +42,7 @@  struct xc2028_ctrl {
     unsigned int        disable_power_mgmt:1;
     unsigned int            read_not_reliable:1;
     unsigned int        demod;
+    unsigned int        switch_mode:1;
     enum firmware_type    type:2;
 };
 
@@ -54,6 +55,7 @@  struct xc2028_config {
 /* xc2028 commands for callback */
 #define XC2028_TUNER_RESET    0
 #define XC2028_RESET_CLK    1
+#define SWITCH_TV_MODE        2
 
 #if defined(CONFIG_MEDIA_TUNER_XC2028) ||
(defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
 extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb/frontends/zl10353.h
b/drivers/media/dvb/frontends/zl10353.h
index 6e3ca9e..015bc36 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -45,6 +45,8 @@  struct zl10353_config
     /* clock control registers (0x51-0x54) */
     u8 clock_ctl_1;  /* default: 0x46 */
     u8 pll_0;        /* default: 0x15 */
+   
+    int tm6000:1;
 };
 
 #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE)
&& defined(MODULE))
diff --git a/drivers/staging/tm6000/hack.c b/drivers/staging/tm6000/hack.c
index f181fce..c1e1880 100644
--- a/drivers/staging/tm6000/hack.c
+++ b/drivers/staging/tm6000/hack.c
@@ -37,7 +37,6 @@  static inline int tm6000_snd_control_msg(struct
tm6000_core *dev, __u8 request,
 
 static int pseudo_zl10353_pll(struct tm6000_core *tm6000_dev, struct
dvb_frontend_parameters *p)
 {
-    int ret;
     u8 *data = kzalloc(50*sizeof(u8), GFP_KERNEL);
 
 printk(KERN_ALERT "should set frequency %u\n", p->frequency);
@@ -51,7 +50,7 @@  printk(KERN_ALERT "and bandwith %u\n",
p->u.ofdm.bandwidth);
     }
 
     // init ZL10353
-    data[0] = 0x0b;
+/*    data[0] = 0x0b;
     ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x501e, 0x00, data,
0x1);
     msleep(15);
     data[0] = 0x80;
@@ -159,7 +158,7 @@  printk(KERN_ALERT "and bandwith %u\n",
p->u.ofdm.bandwidth);
             msleep(15);
             data[0] = 0x5a;
             ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e,
0x00, data, 0x1);
-            msleep(15);
+            msleep(15)
             data[0] = 0xe9;
             ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e,
0x00, data, 0x1);
             msleep(15);
@@ -189,7 +188,162 @@  printk(KERN_ALERT "and bandwith %u\n",
p->u.ofdm.bandwidth);
             msleep(15);
         break;
     }
-
+*/
+    switch(p->u.ofdm.bandwidth) {
+        case BANDWIDTH_8_MHZ:
+            data[0] = 0x03;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x501e,0,data,1);
+            msleep(40);
+            data[0] = 0x44;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x511e,0,data,1);
+            msleep(40);
+            data[0] = 0x40;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
+            msleep(40);
+            data[0] = 0x46;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x521e,0,data,1);
+            msleep(40);
+            data[0] = 0x15;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x531e,0,data,1);
+            msleep(40);
+            data[0] = 0x0f;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x541e,0,data,1);
+            msleep(40);
+            data[0] = 0x80;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
+            msleep(40);
+            data[0] = 0x01;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
+            msleep(40);
+            data[0] = 0x00;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
+            msleep(40);
+            data[0] = 0x8b;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x631e,0,data,1);
+            msleep(40);
+            data[0] = 0x75;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xcc1e,0,data,1);
+            msleep(40);
+            data[0] = 0xe6; //0x19;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6c1e,0,data,1);
+            msleep(40);
+            data[0] = 0x09; //0xf7;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6d1e,0,data,1);
+            msleep(40);
+            data[0] = 0x67;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x651e,0,data,1);
+            msleep(40);
+            data[0] = 0xe5;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x661e,0,data,1);
+            msleep(40);
+            data[0] = 0x75;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5c1e,0,data,1);
+            msleep(40);
+            data[0] = 0x17;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5f1e,0,data,1);
+            msleep(40);
+            data[0] = 0x40;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5e1e,0,data,1);
+            msleep(40);
+            data[0] = 0x01;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x701e,0,data,1);
+            msleep(40);
+            break;
+        case BANDWIDTH_7_MHZ:
+            data[0] = 0x03;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x501e,0,data,1);
+            msleep(40);
+            data[0] = 0x44;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x511e,0,data,1);
+            msleep(40);
+            data[0] = 0x40;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
+            msleep(40);
+            data[0] = 0x46;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x521e,0,data,1);
+            msleep(40);
+            data[0] = 0x15;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x531e,0,data,1);
+            msleep(40);
+            data[0] = 0x0f;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x541e,0,data,1);
+            msleep(40);
+            data[0] = 0x80;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x551e,0,data,1);
+            msleep(40);
+            data[0] = 0x01;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
+            msleep(40);
+            data[0] = 0x00;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xea1e,0,data,1);
+            msleep(40);
+            data[0] = 0x83;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x631e,0,data,1);
+            msleep(40);
+            data[0] = 0xa3;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0xcc1e,0,data,1);
+            msleep(40);
+            data[0] = 0xe6; //0x19;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6c1e,0,data,1);
+            msleep(40);
+            data[0] = 0x09; //0xf7;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x6d1e,0,data,1);
+            msleep(40);
+            data[0] = 0x5a;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x651e,0,data,1);
+            msleep(40);
+            data[0] = 0xe9;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x661e,0,data,1);
+            msleep(40);
+            data[0] = 0x86;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5c1e,0,data,1);
+            msleep(40);
+            data[0] = 0x17;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5f1e,0,data,1);
+            msleep(40);
+            data[0] = 0x40;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x5e1e,0,data,1);
+            msleep(40);
+            data[0] = 0x01;
+            tm6000_read_write_usb(tm6000_dev,0x40,0x10,0x701e,0,data,1);
+            msleep(40);
+            break;
+        default:
+            printk(KERN_ALERT "tm6000: bandwidth not supported\n");
+    }
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x051f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x0f1f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x091f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
+    tm6000_read_write_usb(tm6000_dev,0xc0,0x10,0x0b1f,0,data,2);
+    printk(KERN_INFO "buf %#x %#x \n", data[0], data[1]);
+    msleep(40);
+   
     kfree(data);
 
     return 0;
diff --git a/drivers/staging/tm6000/tm6000-cards.c
b/drivers/staging/tm6000/tm6000-cards.c
index 59fb505..652a54a 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -32,7 +32,7 @@ 
 #include "tm6000.h"
 #include "tm6000-regs.h"
 #include "tuner-xc2028.h"
-#include "tuner-xc5000.h"
+#include "xc5000.h"
 
 #define TM6000_BOARD_UNKNOWN            0
 #define TM5600_BOARD_GENERIC            1
@@ -44,6 +44,10 @@ 
 #define TM6000_BOARD_FREECOM_AND_SIMILAR    7
 #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV    8
 #define TM6010_BOARD_HAUPPAUGE_900H        9
+#define TM6010_BOARD_BEHOLD_WANDER        10
+#define TM6010_BOARD_BEHOLD_VOYAGER        11
+#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE    12
+
 
 #define TM6000_MAXBOARDS        16
 static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
@@ -208,7 +212,21 @@  struct tm6000_board tm6000_boards[] = {
         },
         .gpio_addr_tun_reset = TM6000_GPIO_2,
     },
-
+    [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
+        .name         = "Terratec Cinergy Hybrid XE",
+        .tuner_type   = TUNER_XC2028, /* has a XC3028 */
+        .tuner_addr   = 0xc2 >> 1,
+        .demod_addr   = 0x1e >> 1,
+        .type         = TM6010,
+        .caps = {
+            .has_tuner    = 1,
+            .has_dvb      = 1,
+            .has_zl10353  = 1,
+            .has_eeprom   = 1,
+            .has_remote   = 1,
+        },
+        .gpio_addr_tun_reset = TM6010_GPIO_2,
+    }
 };
 
 /* table of devices that work with this driver */
@@ -221,12 +239,13 @@  struct usb_device_id tm6000_id_table [] = {
     { USB_DEVICE(0x2040, 0x6600), .driver_info =
TM6010_BOARD_HAUPPAUGE_900H },
     { USB_DEVICE(0x6000, 0xdec0), .driver_info =
TM6010_BOARD_BEHOLD_WANDER },
     { USB_DEVICE(0x6000, 0xdec1), .driver_info =
TM6010_BOARD_BEHOLD_VOYAGER },
+    { USB_DEVICE(0x0ccd, 0x0086), .driver_info =
TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
     { },
 };
 
 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
 
-static int tm6000_tuner_callback(void *ptr, int component, int command,
int arg)
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
 {
     int rc=0;
     struct tm6000_core *dev = ptr;
@@ -252,11 +271,14 @@  static int tm6000_tuner_callback(void *ptr, int
component, int command, int arg)
         switch (arg) {
         case 0:
             tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+                    dev->tuner_reset_gpio, 0x01);
+            msleep(60);
+            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
                     dev->tuner_reset_gpio, 0x00);
-            msleep(130);
+            msleep(75);
             tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
                     dev->tuner_reset_gpio, 0x01);
-            msleep(130);
+            msleep(60);
             break;
         case 1:
             tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
@@ -269,13 +291,33 @@  static int tm6000_tuner_callback(void *ptr, int
component, int command, int arg)
                         TM6000_GPIO_CLK, 0);
             if (rc<0)
                 return rc;
-            msleep(100);
+            msleep(10);
             rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
                         TM6000_GPIO_CLK, 1);
-            msleep(100);
+            msleep(10);
+            break;
+        }
+        break;
+       
+    case SWITCH_TV_MODE:
+        /* switch between analog and  digital */
+        switch (arg) {
+        case 0:
+            printk(KERN_INFO "switch to analog");
+            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+                    TM6010_GPIO_5, 1);
+            printk(KERN_INFO "analog");
+            break;
+        case 1:
+            printk(KERN_INFO "switch to digital");
+            tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+                    TM6010_GPIO_5, 0);
+            printk(KERN_INFO "digital");
             break;
         }
+    break;
     }
+   
     return (rc);
 }
 
@@ -290,7 +332,7 @@  static void tm6000_config_tuner (struct tm6000_core
*dev)
     memset(&tun_setup, 0, sizeof(tun_setup));
     tun_setup.type   = dev->tuner_type;
     tun_setup.addr   = dev->tuner_addr;
-    tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+    tun_setup.mode_mask = T_ANALOG_TV | T_RADIO | T_DIGITAL_TV;
     tun_setup.tuner_callback = tm6000_tuner_callback;
 
     v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
&tun_setup);
@@ -302,15 +344,19 @@  static void tm6000_config_tuner (struct
tm6000_core *dev)
         memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
         memset (&ctl,0,sizeof(ctl));
 
-        ctl.mts   = 1;
-        ctl.read_not_reliable = 1;
+        ctl.input1 = 1;
+        ctl.read_not_reliable = 0;
         ctl.msleep = 10;
-
+        ctl.demod = XC3028_FE_ZARLINK456;
+        ctl.vhfbw7 = 1;
+        ctl.uhfbw8 = 1;
+        ctl.switch_mode = 1;
         xc2028_cfg.tuner = TUNER_XC2028;
         xc2028_cfg.priv  = &ctl;
 
         switch(dev->model) {
         case TM6010_BOARD_HAUPPAUGE_900H:
+        case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
             ctl.fname = "xc3028L-v36.fw";
             break;
         default:
@@ -402,6 +448,7 @@  static int tm6000_init_dev(struct tm6000_core *dev)
         }
 #endif
     }
+    return 0;
 
 err2:
     v4l2_device_unregister(&dev->v4l2_dev);
@@ -459,13 +506,13 @@  static int tm6000_usb_probe(struct usb_interface
*interface,
     /* Check to see next free device and mark as used */
     nr=find_first_zero_bit(&tm6000_devused,TM6000_MAXBOARDS);
     if (nr >= TM6000_MAXBOARDS) {
-        printk ("tm6000: Supports only %i em28xx
boards.\n",TM6000_MAXBOARDS);
+        printk ("tm6000: Supports only %i tm60xx
boards.\n",TM6000_MAXBOARDS);
         usb_put_dev(usbdev);
         return -ENOMEM;
     }
 
     /* Create and initialize dev struct */
-    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+    dev = kzalloc(sizeof(*(dev)), GFP_KERNEL);
     if (dev == NULL) {
         printk ("tm6000" ": out of memory!\n");
         usb_put_dev(usbdev);
diff --git a/drivers/staging/tm6000/tm6000-core.c
b/drivers/staging/tm6000/tm6000-core.c
index d41af1d..33bbbd3 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -219,33 +219,53 @@  int tm6000_init_analog_mode (struct tm6000_core *dev)
 
 int tm6000_init_digital_mode (struct tm6000_core *dev)
 {
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
-
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
-    tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
-    msleep(50);
-
-    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
-    msleep(50);
-    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
-    msleep(50);
-    tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
-    msleep(100);
-
+    if (dev->dev_type == TM6010) {
+        int val;
+        u8 buf[2];
+       
+        /* digital init */
+        val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, 0);
+        val &= ~0x60;
+        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, val);
+        val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, 0);
+        val |= 0x40;
+        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, val);
+        tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xfe, 0x28);
+        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xfc);
+        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xe6, 0xff);
+        tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe);
+        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
+        printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
+       
+
+    } else  {
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
+
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
+        tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+        msleep(50);
+
+        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+        msleep(50);
+        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+        msleep(50);
+        tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+        msleep(100);
+    }
     return 0;
 }
 
@@ -394,7 +414,15 @@  struct reg_init tm6010_init_tab[] = {
     { REQ_07_SET_GET_AVREG, 0x3f, 0x00 },
 
     { REQ_05_SET_GET_USBREG, 0x18, 0x00 },
-
+   
+    /* additional from Terratec Cinergy Hybrid XE */
+    { REQ_07_SET_GET_AVREG, 0xdc, 0xaa },
+    { REQ_07_SET_GET_AVREG, 0xdd, 0x30 },
+    { REQ_07_SET_GET_AVREG, 0xde, 0x20 },
+    { REQ_07_SET_GET_AVREG, 0xdf, 0xd0 },
+    { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
+    { REQ_07_SET_GET_AVREG, 0xd8, 0x2f },
+   
     /* set remote wakeup key:any key wakeup */
     { REQ_07_SET_GET_AVREG,  0xe5,  0xfe },
     { REQ_07_SET_GET_AVREG,  0xda,  0xff },
@@ -404,6 +432,7 @@  int tm6000_init (struct tm6000_core *dev)
 {
     int board, rc=0, i, size;
     struct reg_init *tab;
+    u8 buf[40];
 
     if (dev->dev_type == TM6010) {
         tab = tm6010_init_tab;
@@ -424,61 +453,129 @@  int tm6000_init (struct tm6000_core *dev)
         }
     }
 
-    msleep(5); /* Just to be conservative */
-
-    /* Check board version - maybe 10Moons specific */
-    board=tm6000_get_reg16 (dev, 0x40, 0, 0);
-    if (board >=0) {
-        printk (KERN_INFO "Board version = 0x%04x\n",board);
-    } else {
-        printk (KERN_ERR "Error %i while retrieving board
version\n",board);
-    }
-
+    /* hack */
     if (dev->dev_type == TM6010) {
-        /* Turn xceive 3028 on */
-        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_3, 0x01);
-        msleep(11);
-    }
-
-    /* Reset GPIO1 and GPIO4. */
-    for (i=0; i< 2; i++) {
-        rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                    dev->tuner_reset_gpio, 0x00);
-        if (rc<0) {
-            printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
-            return rc;
-        }
-
-        msleep(10); /* Just to be conservative */
-        rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
-                    dev->tuner_reset_gpio, 0x01);
-        if (rc<0) {
-            printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
-            return rc;
-        }
-
-        msleep(10);
-        rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 0);
-        if (rc<0) {
-            printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
-            return rc;
-        }
-
-        msleep(10);
-        rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 1);
-        if (rc<0) {
-            printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
-            return rc;
-        }
-
-        if (!i) {
-            rc=tm6000_get_reg16(dev, 0x40,0,0);
-            if (rc>=0) {
-                printk ("board=%d\n", rc);
+       
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_4, 0);
+        msleep(15);
+               
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_1, 0);
+   
+        msleep(50);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_1, 1);
+       
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x0010, 0x4400, buf, 2);
+       
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x10, 0xf432, 0x0000, buf, 2);
+   
+        msleep(15);
+        buf[0] = 0x12;
+        buf[1] = 0x34;
+        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf432, 0x0000, buf, 2);
+   
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x10, 0xf432, 0x0000, buf, 2);
+   
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x0032, 0x0000, buf, 2);
+
+        msleep(15);
+        buf[0] = 0x00;
+        buf[1] = 0x01;
+        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf332, 0x0000, buf, 2);
+   
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x00c0, 0x0000, buf, 39);
+   
+        msleep(15);
+        buf[0] = 0x00;
+        buf[1] = 0x00;
+        tm6000_read_write_usb (dev, 0x40, 0x10, 0xf332, 0x0000, buf, 2);
+   
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x10, 0x7f1f, 0x0000, buf, 2);
+//        printk(KERN_INFO "buf %#x %#x \n", buf[0], buf [1]);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_4, 1);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                    TM6010_GPIO_0, 1);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_7, 0);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_5, 1);
+   
+        msleep(15);
+   
+        for (i=0; i< size; i++) {
+            rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
+            if (rc<0) {
+                printk (KERN_ERR "Error %i while setting req %d, "
+                         "reg %d to value %d\n", rc,
+                         tab[i].req,tab[i].reg, tab[i].val);
+                return rc;
             }
         }
+           
+        msleep(15);
+   
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_4, 0);
+        msleep(15);
+
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_1, 0);
+   
+        msleep(50);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_1, 1);
+       
+        msleep(15);
+        tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
+//        printk(KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_2, 1);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_2, 0);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_2, 1);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_2, 1);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_2, 0);
+        msleep(15);
+        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                TM6010_GPIO_2, 1);
+        msleep(15);
     }
+    /* hack end */
+   
+    msleep(5); /* Just to be conservative */
 
+    /* Check board version - maybe 10Moons specific */
+    if (dev->dev_type == TM5600) {
+         board=tm6000_get_reg16 (dev, 0x40, 0, 0);
+        if (board >=0) {
+            printk (KERN_INFO "Board version = 0x%04x\n",board);
+        } else {
+            printk (KERN_ERR "Error %i while retrieving board
version\n",board);
+        }
+    }
+   
     msleep(50);
 
     return 0;
diff --git a/drivers/staging/tm6000/tm6000-dvb.c
b/drivers/staging/tm6000/tm6000-dvb.c
index e900d6d..31458d3 100644
--- a/drivers/staging/tm6000/tm6000-dvb.c
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -17,7 +17,9 @@ 
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/kernel.h>
 #include <linux/usb.h>
+#include <compat.h>
 
 #include "tm6000.h"
 #include "tm6000-regs.h"
@@ -30,17 +32,61 @@ 
 
 #include "tuner-xc2028.h"
 
+static void inline print_err_status (struct tm6000_core *dev,
+                     int packet, int status)
+{
+    char *errmsg = "Unknown";
+
+    switch(status) {
+    case -ENOENT:
+        errmsg = "unlinked synchronuously";
+        break;
+    case -ECONNRESET:
+        errmsg = "unlinked asynchronuously";
+        break;
+    case -ENOSR:
+        errmsg = "Buffer error (overrun)";
+        break;
+    case -EPIPE:
+        errmsg = "Stalled (device not responding)";
+        break;
+    case -EOVERFLOW:
+        errmsg = "Babble (bad cable?)";
+        break;
+    case -EPROTO:
+        errmsg = "Bit-stuff error (bad cable?)";
+        break;
+    case -EILSEQ:
+        errmsg = "CRC/Timeout (could be anything)";
+        break;
+    case -ETIME:
+        errmsg = "Device does not respond";
+        break;
+    }
+    if (packet<0) {
+        dprintk(dev, 1, "URB status %d [%s].\n",
+            status, errmsg);
+    } else {
+        dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
+            packet, status, errmsg);
+    }
+}
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static void tm6000_urb_received(struct urb *urb, struct pt_regs *ptregs)
+#else
 static void tm6000_urb_received(struct urb *urb)
+#endif
 {
     int ret;
     struct tm6000_core* dev = urb->context;
 
-    if(urb->status != 0){
-        printk(KERN_ERR "tm6000: status != 0\n");
+    if(urb->status != 0) {
+        print_err_status (dev,0,urb->status);
     }
     else if(urb->actual_length>0){
-        dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
-                           urb->actual_length);
+        dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
urb->actual_length);
     }
 
     if(dev->dvb->streams > 0) {
@@ -56,49 +102,37 @@  static void tm6000_urb_received(struct urb *urb)
 int tm6000_start_stream(struct tm6000_core *dev)
 {
     int ret;
-    unsigned int pipe, maxPaketSize;
+    unsigned int pipe, size;
     struct tm6000_dvb *dvb = dev->dvb;
 
     printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
 
     tm6000_init_digital_mode(dev);
 
-/*
-    ret = tm6000_set_led_status(tm6000_dev, 0x1);
-    if(ret < 0) {
-        return -1;
-    }
-*/
-
     dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
     if(dvb->bulk_urb == NULL) {
         printk(KERN_ERR "tm6000: couldn't allocate urb\n");
         return -ENOMEM;
     }
 
-    maxPaketSize = dev->bulk_in->desc.wMaxPacketSize;
+    pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
+                              & USB_ENDPOINT_NUMBER_MASK);
+                             
+    size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+    size = size * 15; // 512 x 8 or 12 or 15
 
-    dvb->bulk_urb->transfer_buffer = kzalloc(maxPaketSize, GFP_KERNEL);
+    dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
     if(dvb->bulk_urb->transfer_buffer == NULL) {
         usb_free_urb(dvb->bulk_urb);
         printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
         return -ENOMEM;
     }
-
-    pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
-                              & USB_ENDPOINT_NUMBER_MASK);
-
+   
     usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
                          dvb->bulk_urb->transfer_buffer,
-                         maxPaketSize,
+                         size,
                          tm6000_urb_received, dev);
 
-    ret = usb_set_interface(dev->udev, 0, 1);
-    if(ret < 0) {
-        printk(KERN_ERR "tm6000: error %i in %s during set
interface\n", ret, __FUNCTION__);
-        return ret;
-    }
-
     ret = usb_clear_halt(dev->udev, pipe);
     if(ret < 0) {
         printk(KERN_ERR "tm6000: error %i in %s during pipe
reset\n",ret,__FUNCTION__);
@@ -107,15 +141,14 @@  int tm6000_start_stream(struct tm6000_core *dev)
     else {
         printk(KERN_ERR "tm6000: pipe resetted\n");
     }
-
-//     mutex_lock(&tm6000_driver.open_close_mutex);
+   
+//    mutex_lock(&tm6000_driver.open_close_mutex);
     ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
 
-
-//     mutex_unlock(&tm6000_driver.open_close_mutex);
+//    mutex_unlock(&tm6000_driver.open_close_mutex);
     if (ret) {
         printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
-
+       
         kfree(dvb->bulk_urb->transfer_buffer);
         usb_free_urb(dvb->bulk_urb);
         return ret;
@@ -126,18 +159,12 @@  int tm6000_start_stream(struct tm6000_core *dev)
 
 void tm6000_stop_stream(struct tm6000_core *dev)
 {
-    int ret;
     struct tm6000_dvb *dvb = dev->dvb;
 
-//     tm6000_set_led_status(tm6000_dev, 0x0);
-
-    ret = usb_set_interface(dev->udev, 0, 0);
-    if(ret < 0) {
-        printk(KERN_ERR "tm6000: error %i in %s during set
interface\n",ret,__FUNCTION__);
-    }
-
     if(dvb->bulk_urb) {
+        printk (KERN_INFO "urb killing\n");
         usb_kill_urb(dvb->bulk_urb);
+        printk (KERN_INFO "urb buffer free\n");
         kfree(dvb->bulk_urb->transfer_buffer);
         usb_free_urb(dvb->bulk_urb);
         dvb->bulk_urb = NULL;
@@ -154,7 +181,7 @@  int tm6000_start_feed(struct dvb_demux_feed *feed)
     mutex_lock(&dvb->mutex);
     if(dvb->streams == 0) {
         dvb->streams = 1;
-//         mutex_init(&tm6000_dev->streaming_mutex);
+//        mutex_init(&tm6000_dev->streming_mutex);
         tm6000_start_stream(dev);
     }
     else {
@@ -173,14 +200,17 @@  int tm6000_stop_feed(struct dvb_demux_feed *feed) {
     printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
 
     mutex_lock(&dvb->mutex);
-    --dvb->streams;
 
-    if(0 == dvb->streams) {
+    printk (KERN_INFO "stream %#x\n", dvb->streams);
+    --(dvb->streams);
+    if(dvb->streams == 0) {
+        printk (KERN_INFO "stop stream\n");
         tm6000_stop_stream(dev);
-//         mutex_destroy(&tm6000_dev->streaming_mutex);
+//        mutex_destroy(&tm6000_dev->streaming_mutex);
     }
+   
     mutex_unlock(&dvb->mutex);
-//     mutex_destroy(&tm6000_dev->streaming_mutex);
+//    mutex_destroy(&tm6000_dev->streaming_mutex);
 
     return 0;
 }
@@ -191,13 +221,16 @@  int tm6000_dvb_attach_frontend(struct tm6000_core
*dev)
 
     if(dev->caps.has_zl10353) {
         struct zl10353_config config =
-                    {.demod_address = dev->demod_addr >> 1,
+                    {.demod_address = dev->demod_addr,
                      .no_tuner = 1,
-//                      .input_frequency = 0x19e9,
-//                      .r56_agc_targets =  0x1c,
+                     .parallel_ts = 1,
+                     .if2 = 45700,
+                     .disable_i2c_gate_ctrl = 1,
+                     .tm6000 = 1,
                     };
 
         dvb->frontend = pseudo_zl10353_attach(dev, &config,
+//        dvb->frontend = dvb_attach (zl10353_attach, &config,
                                &dev->i2c_adap);
     }
     else {
@@ -235,7 +268,8 @@  int tm6000_dvb_register(struct tm6000_core *dev)
             .i2c_adap = &dev->i2c_adap,
             .i2c_addr = dev->tuner_addr,
         };
-
+       
+        dvb->frontend->callback = tm6000_tuner_callback;
         ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
         if (ret < 0) {
             printk(KERN_ERR
@@ -258,8 +292,8 @@  int tm6000_dvb_register(struct tm6000_core *dev)
     dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
                                 | DMX_MEMORY_BASED_FILTERING;
     dvb->demux.priv = dev;
-    dvb->demux.filternum = 256;
-    dvb->demux.feednum = 256;
+    dvb->demux.filternum = 5; //256;
+    dvb->demux.feednum = 5; //256;
     dvb->demux.start_feed = tm6000_start_feed;
     dvb->demux.stop_feed = tm6000_stop_feed;
     dvb->demux.write_to_decoder = NULL;
@@ -307,7 +341,7 @@  void tm6000_dvb_unregister(struct tm6000_core *dev)
         usb_free_urb(bulk_urb);
     }
 
-//     mutex_lock(&tm6000_driver.open_close_mutex);
+//    mutex_lock(&tm6000_driver.open_close_mutex);
     if(dvb->frontend) {
         dvb_frontend_detach(dvb->frontend);
         dvb_unregister_frontend(dvb->frontend);
@@ -317,6 +351,6 @@  void tm6000_dvb_unregister(struct tm6000_core *dev)
     dvb_dmx_release(&dvb->demux);
     dvb_unregister_adapter(&dvb->adapter);
     mutex_destroy(&dvb->mutex);
-//     mutex_unlock(&tm6000_driver.open_close_mutex);
+//    mutex_unlock(&tm6000_driver.open_close_mutex);
 
 }
diff --git a/drivers/staging/tm6000/tm6000-i2c.c
b/drivers/staging/tm6000/tm6000-i2c.c
index 4da10f5..3e43ad7 100644
--- a/drivers/staging/tm6000/tm6000-i2c.c
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -86,6 +86,11 @@  static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                 msgs[i].len == 1 ? 0 : msgs[i].buf[1],
                 msgs[i + 1].buf, msgs[i + 1].len);
             i++;
+           
+            if ((dev->dev_type == TM6010) && (addr == 0xc2)) {
+                tm6000_set_reg(dev, 0x32, 0,0);
+                tm6000_set_reg(dev, 0x33, 0,0);
+            }
             if (i2c_debug >= 2)
                 for (byte = 0; byte < msgs[i].len; byte++)
                     printk(" %02x", msgs[i].buf[byte]);
@@ -99,6 +104,12 @@  static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                 REQ_16_SET_GET_I2C_WR1_RDN,
                 addr | msgs[i].buf[0] << 8, 0,
                 msgs[i].buf + 1, msgs[i].len - 1);
+               
+           
+            if ((dev->dev_type == TM6010) && (addr == 0xc2)) {
+                tm6000_set_reg(dev, 0x32, 0,0);
+                tm6000_set_reg(dev, 0x33, 0,0);
+            }
         }
         if (i2c_debug >= 2)
             printk("\n");
@@ -198,7 +209,7 @@  static struct i2c_algorithm tm6000_algo = {
 
 static struct i2c_adapter tm6000_adap_template = {
     .owner = THIS_MODULE,
-    .class = I2C_CLASS_TV_ANALOG,
+    .class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
     .name = "tm6000",
     .id = I2C_HW_B_TM6000,
     .algo = &tm6000_algo,
diff --git a/drivers/staging/tm6000/tm6000.h
b/drivers/staging/tm6000/tm6000.h
index 877cbf6..e403ca0 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -23,12 +23,15 @@ 
 // Use the tm6000-hack, instead of the proper initialization code
 //#define HACK 1
 
+#include "compat.h"
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/videobuf-vmalloc.h>
 #include "tm6000-usb-isoc.h"
 #include <linux/i2c.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
 #include <linux/mutex.h>
+#endif
 #include <media/v4l2-device.h>
 
 
@@ -78,6 +81,10 @@  struct tm6000_dmaqueue {
     /* thread for generating video stream*/
     struct task_struct         *kthread;
     wait_queue_head_t          wq;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+    struct semaphore           *notify;
+    int                        rmmod:1;
+#endif
     /* Counters to control fps rate */
     int                        frame;
     int                        ini_jiffies;
@@ -90,12 +97,14 @@  enum tm6000_core_state {
     DEV_MISCONFIGURED = 0x04,
 };
 
+#if 1
 /* io methods */
 enum tm6000_io_method {
     IO_NONE,
     IO_READ,
     IO_MMAP,
 };
+#endif
 
 enum tm6000_mode {
     TM6000_MODE_UNKNOWN=0,
@@ -202,6 +211,9 @@  struct tm6000_fh {
             V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
             V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
 
+/* In tm6000-cards.c */
+
+int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
 /* In tm6000-core.c */
 
 int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
@@ -209,7 +221,6 @@  int tm6000_read_write_usb (struct tm6000_core *dev,
u8 reqtype, u8 req,
 int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_init (struct tm6000_core *dev);
-int tm6000_init_after_firmware (struct tm6000_core *dev);
 
 int tm6000_init_analog_mode (struct tm6000_core *dev);