VDR and Hybrid DVB Cards ( was "HVR 4000 drivers broken - adapter0/frontend1 busy" in linux-media list )

Message ID 4EC4403F.2040600@flensrocker.de
State New
Headers

Commit Message

L. Hanisch Nov. 16, 2011, 10:59 p.m. UTC
  Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
> On 16.11.2011 19:16, L. Hanisch wrote:
>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>> That is also my understanding of multi frontend devices.
>>> If an "adapter" has several "frontends" only one of them can
>>> be active at any given time. This has nothing to do with
>>> any "explosives" (excuse the pun ;-) and will be implemented
>>> in the core VDR code as time permits. Right now I'm cleaning up
>>> the "lnb sharing" (aka "device bonding") stuff and will hopefully
>>> find more time for VDR development by the end of the year (and
>>> thereafter).
>>
>> If you don't mind I would try to prefabricate something.
>> On a first guess: would you combine the multiple frontends of an adapter in one cDvbDevice? I think this would be
>> better than having multiple cDvbDevices which must interact somehow with each other.
>
> Sure there will be one cDvbDevice per adapter for a multi-frontend device
> where only one frontend can be active at any time.
> If (like on the TT-S2 6400) there are several frontends that can be
> active simultaneously, then there shall be separate adapters for each
> frontend, and thus a separate cDvbDevice for each adapter.

  Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived yet I tested with a DVB-T and DVB-C stick and 
sym-linked the devices within one adapter. I have no ca-devices in this setup.
  Switching between C and T channels works here, but it's not really tested with timers/recordings etc.

  I don't have a FF card, so the patches for the plugins are more of "remove compiler warnings" only. One have to think 
about cDvbDeviceProbe and the parameters. A frontend argument doesn't make much sense now.

> Note, though, that support for such devices will most likely not
> go into VDR for version 2. I'm trying to wrap things up in order
> to make a stable version 2, and after that will address new things
> like this.

  I'm fine with this and looking forward to it. A new stable release would be fine! Xmas is next door... :)

Lars.
  

Comments

Hawes, Mark Nov. 17, 2011, 10:02 a.m. UTC | #1
Hi Lars,

Thanks for the patch. 
Basically, it seems to work for the HVR 4000. Both front ends are
detected successfully, and both can be used. I'm using it with the
xineliboutput plugin and it seems to co-exist OK. 
Starting a recording on one prevents a channel switch to the other with
the "Channel not available message". However, when doing so the screen
goes black and its necessary to retune the recorded channel to get the
picture back. Not a big issue, more an annoyance.

I'll be playing with it in the next couple of days including introducing
a SD premium card into the mix to see what happens. Is there anything in
particular that you would like me to try? 

Thanks,

Mark.
-----Original Message-----
From: vdr-bounces@linuxtv.org [mailto:vdr-bounces@linuxtv.org] On Behalf
Of L. Hanisch
Sent: Thursday, 17 November 2011 9:59 AM
To: vdr@linuxtv.org
Subject: Re: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers
broken - adapter0/frontend1 busy" in linux-media list )

Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
> On 16.11.2011 19:16, L. Hanisch wrote:
>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>> That is also my understanding of multi frontend devices.
>>> If an "adapter" has several "frontends" only one of them can be 
>>> active at any given time. This has nothing to do with any 
>>> "explosives" (excuse the pun ;-) and will be implemented in the core

>>> VDR code as time permits. Right now I'm cleaning up the "lnb 
>>> sharing" (aka "device bonding") stuff and will hopefully find more 
>>> time for VDR development by the end of the year (and thereafter).
>>
>> If you don't mind I would try to prefabricate something.
>> On a first guess: would you combine the multiple frontends of an 
>> adapter in one cDvbDevice? I think this would be better than having
multiple cDvbDevices which must interact somehow with each other.
>
> Sure there will be one cDvbDevice per adapter for a multi-frontend 
> device where only one frontend can be active at any time.
> If (like on the TT-S2 6400) there are several frontends that can be 
> active simultaneously, then there shall be separate adapters for each 
> frontend, and thus a separate cDvbDevice for each adapter.

  Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived
yet I tested with a DVB-T and DVB-C stick and sym-linked the devices
within one adapter. I have no ca-devices in this setup.
  Switching between C and T channels works here, but it's not really
tested with timers/recordings etc.

  I don't have a FF card, so the patches for the plugins are more of
"remove compiler warnings" only. One have to think about cDvbDeviceProbe
and the parameters. A frontend argument doesn't make much sense now.

> Note, though, that support for such devices will most likely not go 
> into VDR for version 2. I'm trying to wrap things up in order to make 
> a stable version 2, and after that will address new things like this.

  I'm fine with this and looking forward to it. A new stable release
would be fine! Xmas is next door... :)

Lars.
  
L. Hanisch Nov. 17, 2011, 5:43 p.m. UTC | #2
Hi,

Am 17.11.2011 11:02, schrieb Hawes, Mark:
> Hi Lars,
>
> Thanks for the patch.
> Basically, it seems to work for the HVR 4000. Both front ends are
> detected successfully, and both can be used. I'm using it with the
> xineliboutput plugin and it seems to co-exist OK.

  Nice to hear.

> Starting a recording on one prevents a channel switch to the other with
> the "Channel not available message". However, when doing so the screen
> goes black and its necessary to retune the recorded channel to get the
> picture back. Not a big issue, more an annoyance.

  Ok, I will try to reproduce this. It may be (since the device hasn't changed) vdr is thinking that it's showing an 
available channel or something like this.

> I'll be playing with it in the next couple of days including introducing
> a SD premium card into the mix to see what happens. Is there anything in
> particular that you would like me to try?

  I haven't made too much thoughts about tests. Maybe we can work on a checklist together.

  use cases:
- live viewing with switching channels between frontends
- timer recording starts while viewing live tv on the other frontend
- timer conflicts with different priorities on the different frontends
- streamdev-client/-server?
- ...?

  It looks like the HVR 4000 has no CI. At the moment I don't have access to cards with decryption hardware, too.
  And I'm not too familiar with this part of the vdr (ci/cam etc.).

Lars.

>
> Thanks,
>
> Mark.
> -----Original Message-----
> From: vdr-bounces@linuxtv.org [mailto:vdr-bounces@linuxtv.org] On Behalf
> Of L. Hanisch
> Sent: Thursday, 17 November 2011 9:59 AM
> To: vdr@linuxtv.org
> Subject: Re: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers
> broken - adapter0/frontend1 busy" in linux-media list )
>
> Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
>> On 16.11.2011 19:16, L. Hanisch wrote:
>>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>>> That is also my understanding of multi frontend devices.
>>>> If an "adapter" has several "frontends" only one of them can be
>>>> active at any given time. This has nothing to do with any
>>>> "explosives" (excuse the pun ;-) and will be implemented in the core
>
>>>> VDR code as time permits. Right now I'm cleaning up the "lnb
>>>> sharing" (aka "device bonding") stuff and will hopefully find more
>>>> time for VDR development by the end of the year (and thereafter).
>>>
>>> If you don't mind I would try to prefabricate something.
>>> On a first guess: would you combine the multiple frontends of an
>>> adapter in one cDvbDevice? I think this would be better than having
> multiple cDvbDevices which must interact somehow with each other.
>>
>> Sure there will be one cDvbDevice per adapter for a multi-frontend
>> device where only one frontend can be active at any time.
>> If (like on the TT-S2 6400) there are several frontends that can be
>> active simultaneously, then there shall be separate adapters for each
>> frontend, and thus a separate cDvbDevice for each adapter.
>
>    Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived
> yet I tested with a DVB-T and DVB-C stick and sym-linked the devices
> within one adapter. I have no ca-devices in this setup.
>    Switching between C and T channels works here, but it's not really
> tested with timers/recordings etc.
>
>    I don't have a FF card, so the patches for the plugins are more of
> "remove compiler warnings" only. One have to think about cDvbDeviceProbe
> and the parameters. A frontend argument doesn't make much sense now.
>
>> Note, though, that support for such devices will most likely not go
>> into VDR for version 2. I'm trying to wrap things up in order to make
>> a stable version 2, and after that will address new things like this.
>
>    I'm fine with this and looking forward to it. A new stable release
> would be fine! Xmas is next door... :)
>
> Lars.
>
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
>
  
Hawes, Mark Nov. 18, 2011, 6:53 a.m. UTC | #3
Hi Lars,

Some results from further testing:

 - "live viewing with switching channels between frontends": Works OK,
with about a 3 second delay switching from terrestrial to satellite and
about 10 seconds going the other way. The timings are pretty consistent
and I put the difference down to the time to lock being significantly
longer for satellite. 

- "timer recording starts while viewing live TV on the other frontend":
Seems to behave reasonably. The screen goes blank and eventually the
picture is replaced with what appears to be that of the first channel on
the transponder that we are now recording. It stays there even after the
recording completes. The same behaviour is experienced when going either
way, e.g. viewing terrestrial when satellite recording starts or viewing
satellite when terrestrial recording starts.

Have not played with timer conflicts yet.

Now, the problem: It's broken a number of plugins which no longer
compile. These include dvbhddevice, dvbsddevice, dvd, osdpip, Rotorng,
sc and upnp which I use but I'm sure a number of others will be
affected. The primary reason appears to be the redefinition of
cDvbDevice, but some other errors are also reported. Is this
redefinition the 'dirty' part of this initial attempt, or is it
fundamental to the approach? If it's the latter I suspect it will be
very problematic for many users of affected plugins as these will need
to be modified to conform. 

Regards,

Mark.

-----Original Message-----
From: vdr-bounces@linuxtv.org [mailto:vdr-bounces@linuxtv.org] On Behalf
Of L. Hanisch
Sent: Friday, 18 November 2011 4:44 AM
To: vdr@linuxtv.org
Subject: Re: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers
broken - adapter0/frontend1 busy" in linux-media list )

Hi,

Am 17.11.2011 11:02, schrieb Hawes, Mark:
> Hi Lars,
>
> Thanks for the patch.
> Basically, it seems to work for the HVR 4000. Both front ends are 
> detected successfully, and both can be used. I'm using it with the 
> xineliboutput plugin and it seems to co-exist OK.

  Nice to hear.

> Starting a recording on one prevents a channel switch to the other 
> with the "Channel not available message". However, when doing so the 
> screen goes black and its necessary to retune the recorded channel to 
> get the picture back. Not a big issue, more an annoyance.

  Ok, I will try to reproduce this. It may be (since the device hasn't
changed) vdr is thinking that it's showing an available channel or
something like this.

> I'll be playing with it in the next couple of days including 
> introducing a SD premium card into the mix to see what happens. Is 
> there anything in particular that you would like me to try?

  I haven't made too much thoughts about tests. Maybe we can work on a
checklist together.

  use cases:
- live viewing with switching channels between frontends
- timer recording starts while viewing live tv on the other frontend
- timer conflicts with different priorities on the different frontends
- streamdev-client/-server?
- ...?

  It looks like the HVR 4000 has no CI. At the moment I don't have
access to cards with decryption hardware, too.
  And I'm not too familiar with this part of the vdr (ci/cam etc.).

Lars.

>
> Thanks,
>
> Mark.
> -----Original Message-----
> From: vdr-bounces@linuxtv.org [mailto:vdr-bounces@linuxtv.org] On 
> Behalf Of L. Hanisch
> Sent: Thursday, 17 November 2011 9:59 AM
> To: vdr@linuxtv.org
> Subject: Re: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers 
> broken - adapter0/frontend1 busy" in linux-media list )
>
> Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
>> On 16.11.2011 19:16, L. Hanisch wrote:
>>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>>> That is also my understanding of multi frontend devices.
>>>> If an "adapter" has several "frontends" only one of them can be 
>>>> active at any given time. This has nothing to do with any 
>>>> "explosives" (excuse the pun ;-) and will be implemented in the 
>>>> core
>
>>>> VDR code as time permits. Right now I'm cleaning up the "lnb 
>>>> sharing" (aka "device bonding") stuff and will hopefully find more 
>>>> time for VDR development by the end of the year (and thereafter).
>>>
>>> If you don't mind I would try to prefabricate something.
>>> On a first guess: would you combine the multiple frontends of an 
>>> adapter in one cDvbDevice? I think this would be better than having
> multiple cDvbDevices which must interact somehow with each other.
>>
>> Sure there will be one cDvbDevice per adapter for a multi-frontend 
>> device where only one frontend can be active at any time.
>> If (like on the TT-S2 6400) there are several frontends that can be 
>> active simultaneously, then there shall be separate adapters for each

>> frontend, and thus a separate cDvbDevice for each adapter.
>
>    Here's a first "quick'n'dirty" patch. Since my hardware hasn't 
> arrived yet I tested with a DVB-T and DVB-C stick and sym-linked the 
> devices within one adapter. I have no ca-devices in this setup.
>    Switching between C and T channels works here, but it's not really 
> tested with timers/recordings etc.
>
>    I don't have a FF card, so the patches for the plugins are more of 
> "remove compiler warnings" only. One have to think about 
> cDvbDeviceProbe and the parameters. A frontend argument doesn't make
much sense now.
>
>> Note, though, that support for such devices will most likely not go 
>> into VDR for version 2. I'm trying to wrap things up in order to make

>> a stable version 2, and after that will address new things like this.
>
>    I'm fine with this and looking forward to it. A new stable release 
> would be fine! Xmas is next door... :)
>
> Lars.
>
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
>
  
Hawes, Mark Nov. 18, 2011, 8:17 a.m. UTC | #4
My apologies - the dvbhddevice and dvbsddevice plugins are OK, I was
using versions I copied across and were unpatched.

Mark.

-----Original Message-----
From: Hawes, Mark 
Sent: Friday, 18 November 2011 5:54 PM
To: 'VDR Mailing List'
Subject: RE: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers
broken - adapter0/frontend1 busy" in linux-media list )

Hi Lars,

Some results from further testing:

 - "live viewing with switching channels between frontends": Works OK,
with about a 3 second delay switching from terrestrial to satellite and
about 10 seconds going the other way. The timings are pretty consistent
and I put the difference down to the time to lock being significantly
longer for satellite. 

- "timer recording starts while viewing live TV on the other frontend":
Seems to behave reasonably. The screen goes blank and eventually the
picture is replaced with what appears to be that of the first channel on
the transponder that we are now recording. It stays there even after the
recording completes. The same behaviour is experienced when going either
way, e.g. viewing terrestrial when satellite recording starts or viewing
satellite when terrestrial recording starts.

Have not played with timer conflicts yet.

Now, the problem: It's broken a number of plugins which no longer
compile. These include dvbhddevice, dvbsddevice, dvd, osdpip, Rotorng,
sc and upnp which I use but I'm sure a number of others will be
affected. The primary reason appears to be the redefinition of
cDvbDevice, but some other errors are also reported. Is this
redefinition the 'dirty' part of this initial attempt, or is it
fundamental to the approach? If it's the latter I suspect it will be
very problematic for many users of affected plugins as these will need
to be modified to conform. 

Regards,

Mark.

-----Original Message-----
From: vdr-bounces@linuxtv.org [mailto:vdr-bounces@linuxtv.org] On Behalf
Of L. Hanisch
Sent: Friday, 18 November 2011 4:44 AM
To: vdr@linuxtv.org
Subject: Re: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers
broken - adapter0/frontend1 busy" in linux-media list )

Hi,

Am 17.11.2011 11:02, schrieb Hawes, Mark:
> Hi Lars,
>
> Thanks for the patch.
> Basically, it seems to work for the HVR 4000. Both front ends are 
> detected successfully, and both can be used. I'm using it with the 
> xineliboutput plugin and it seems to co-exist OK.

  Nice to hear.

> Starting a recording on one prevents a channel switch to the other 
> with the "Channel not available message". However, when doing so the 
> screen goes black and its necessary to retune the recorded channel to 
> get the picture back. Not a big issue, more an annoyance.

  Ok, I will try to reproduce this. It may be (since the device hasn't
changed) vdr is thinking that it's showing an available channel or
something like this.

> I'll be playing with it in the next couple of days including 
> introducing a SD premium card into the mix to see what happens. Is 
> there anything in particular that you would like me to try?

  I haven't made too much thoughts about tests. Maybe we can work on a
checklist together.

  use cases:
- live viewing with switching channels between frontends
- timer recording starts while viewing live tv on the other frontend
- timer conflicts with different priorities on the different frontends
- streamdev-client/-server?
- ...?

  It looks like the HVR 4000 has no CI. At the moment I don't have
access to cards with decryption hardware, too.
  And I'm not too familiar with this part of the vdr (ci/cam etc.).

Lars.

>
> Thanks,
>
> Mark.
> -----Original Message-----
> From: vdr-bounces@linuxtv.org [mailto:vdr-bounces@linuxtv.org] On 
> Behalf Of L. Hanisch
> Sent: Thursday, 17 November 2011 9:59 AM
> To: vdr@linuxtv.org
> Subject: Re: [vdr] VDR and Hybrid DVB Cards ( was "HVR 4000 drivers 
> broken - adapter0/frontend1 busy" in linux-media list )
>
> Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
>> On 16.11.2011 19:16, L. Hanisch wrote:
>>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>>> That is also my understanding of multi frontend devices.
>>>> If an "adapter" has several "frontends" only one of them can be 
>>>> active at any given time. This has nothing to do with any 
>>>> "explosives" (excuse the pun ;-) and will be implemented in the 
>>>> core
>
>>>> VDR code as time permits. Right now I'm cleaning up the "lnb 
>>>> sharing" (aka "device bonding") stuff and will hopefully find more 
>>>> time for VDR development by the end of the year (and thereafter).
>>>
>>> If you don't mind I would try to prefabricate something.
>>> On a first guess: would you combine the multiple frontends of an 
>>> adapter in one cDvbDevice? I think this would be better than having
> multiple cDvbDevices which must interact somehow with each other.
>>
>> Sure there will be one cDvbDevice per adapter for a multi-frontend 
>> device where only one frontend can be active at any time.
>> If (like on the TT-S2 6400) there are several frontends that can be 
>> active simultaneously, then there shall be separate adapters for each

>> frontend, and thus a separate cDvbDevice for each adapter.
>
>    Here's a first "quick'n'dirty" patch. Since my hardware hasn't 
> arrived yet I tested with a DVB-T and DVB-C stick and sym-linked the 
> devices within one adapter. I have no ca-devices in this setup.
>    Switching between C and T channels works here, but it's not really 
> tested with timers/recordings etc.
>
>    I don't have a FF card, so the patches for the plugins are more of 
> "remove compiler warnings" only. One have to think about 
> cDvbDeviceProbe and the parameters. A frontend argument doesn't make
much sense now.
>
>> Note, though, that support for such devices will most likely not go 
>> into VDR for version 2. I'm trying to wrap things up in order to make

>> a stable version 2, and after that will address new things like this.
>
>    I'm fine with this and looking forward to it. A new stable release 
> would be fine! Xmas is next door... :)
>
> Lars.
>
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
>
  
Klaus Schmidinger Nov. 18, 2011, 6:03 p.m. UTC | #5
On 16.11.2011 23:59, L. Hanisch wrote:
> Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
>> On 16.11.2011 19:16, L. Hanisch wrote:
>>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>>> That is also my understanding of multi frontend devices.
>>>> If an "adapter" has several "frontends" only one of them can
>>>> be active at any given time. This has nothing to do with
>>>> any "explosives" (excuse the pun ;-) and will be implemented
>>>> in the core VDR code as time permits. Right now I'm cleaning up
>>>> the "lnb sharing" (aka "device bonding") stuff and will hopefully
>>>> find more time for VDR development by the end of the year (and
>>>> thereafter).
>>>
>>> If you don't mind I would try to prefabricate something.
>>> On a first guess: would you combine the multiple frontends of an adapter in one cDvbDevice? I think this would be
>>> better than having multiple cDvbDevices which must interact somehow with each other.
>>
>> Sure there will be one cDvbDevice per adapter for a multi-frontend device
>> where only one frontend can be active at any time.
>> If (like on the TT-S2 6400) there are several frontends that can be
>> active simultaneously, then there shall be separate adapters for each
>> frontend, and thus a separate cDvbDevice for each adapter.
>
> Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived yet I tested with a DVB-T and DVB-C stick and sym-linked the devices within one adapter. I have no ca-devices in this setup.
> Switching between C and T channels works here, but it's not really tested with timers/recordings etc.
>
> I don't have a FF card, so the patches for the plugins are more of "remove compiler warnings" only. One have to think about cDvbDeviceProbe and the parameters. A frontend argument doesn't make much sense now.
>
>> Note, though, that support for such devices will most likely not
>> go into VDR for version 2. I'm trying to wrap things up in order
>> to make a stable version 2, and after that will address new things
>> like this.
>
> I'm fine with this and looking forward to it. A new stable release would be fine! Xmas is next door... :)

I've received an email from Manu Abraham, informing
me that he intends to change the driver in such a way that there will always
be only *one* frontend, even if it can handle multiple delivery systems.
So every frontend an adapter will provide will always be useable independent
of all other frontends of that adapter.
Personally, I like this method more than having separate frontends for
each delivery system, and having to manage access between them.

Just wanted to let you know that the official implementation in VDR
(most likely after version 2.0) will go a different way than your patch.

Klaus
  
Mika Laitio Nov. 18, 2011, 10:40 p.m. UTC | #6
> I've received an email from Manu Abraham, informing
> me that he intends to change the driver in such a way that there will
> always
> be only *one* frontend, even if it can handle multiple delivery systems.
> So every frontend an adapter will provide will always be useable
> independent
> of all other frontends of that adapter.
> Personally, I like this method more than having separate frontends for
> each delivery system, and having to manage access between them.
> 
> Just wanted to let you know that the official implementation in VDR
> (most likely after version 2.0) will go a different way than your patch.

I am wondering what's the reason of breaking this current rule as it
sounded so clear...So if cards all delivery systems are mapped as an
adapters under same frontend, there must be a some method for querying
which of those adapters are tied together. Did Manu say whether that
info can be get via dev tree, via sysfs or by using some new ioctl?

And if the patch wont go in, it means that hvr-4000 owners needs to
maintain in addition of the vdr-patch, also a patches for all plugins
that the patch breaks :-(. On the other hand, if the patch would be
accepted to vdr before 2.0, I am sure that all plugi-ns would be adapter
to work in couple of weeks to work with the new interfaces.

Mika
  
Klaus Schmidinger Nov. 18, 2011, 10:53 p.m. UTC | #7
On 18.11.2011 23:40, Mika Laitio wrote:
>> I've received an email from Manu Abraham, informing
>> me that he intends to change the driver in such a way that there will
>> always
>> be only *one* frontend, even if it can handle multiple delivery systems.
>> So every frontend an adapter will provide will always be useable
>> independent
>> of all other frontends of that adapter.
>> Personally, I like this method more than having separate frontends for
>> each delivery system, and having to manage access between them.
>>
>> Just wanted to let you know that the official implementation in VDR
>> (most likely after version 2.0) will go a different way than your patch.
>
> I am wondering what's the reason of breaking this current rule as it
> sounded so clear...So if cards all delivery systems are mapped as an
> adapters under same frontend, there must be a some method for querying
> which of those adapters are tied together. Did Manu say whether that
> info can be get via dev tree, via sysfs or by using some new ioctl?

That was my misunderstanding in the beginning, too, and it resulted
in a lengthy discussion with Manu ;-)

 From what I understood, every physical device (i.e. a DVB PCI card, a USB
receiver or whatever) will be exactly *one* adapter. If an adapter provides
several delivery systems (like, for instance, DVB-S and DVB-T) and only
one of these can be used at a time, there will be *one* frontend that needs
to be switched to the desired delivery system before tuning to a transponder.
A new ioctl() will allow the application to query which and how many
delivery systems a frontend provides.
If the adapter has like two DVB-S tuners that can be used simultaneously,
then it will have two separate frontends.

> And if the patch wont go in, it means that hvr-4000 owners needs to
> maintain in addition of the vdr-patch, also a patches for all plugins
> that the patch breaks :-(. On the other hand, if the patch would be
> accepted to vdr before 2.0, I am sure that all plugi-ns would be adapter
> to work in couple of weeks to work with the new interfaces.

 From what I understand at this time I don't see why implementing
multi-frontend support would break any plugins. Lars' patch apparently
does, but my goal would be to make this totally seemless, so plugins
wouldn't even notice.

Right now I have only very little (if any) time to work on VDR,
because my daytime job requires all my attention. This will change
by the end of the year, and then we'll see whether Manu's patch has
made it into the driver and whether this can be used for VDR 2.0.

Personally I hope Manu's implementation gets adopted, because I find
it very straightforward.

Klaus
  
Steffen Barszus Nov. 18, 2011, 11:10 p.m. UTC | #8
On Sat, 19 Nov 2011 00:40:30 +0200
Mika Laitio <lamikr@pilppa.org> wrote:

> > I've received an email from Manu Abraham, informing
> > me that he intends to change the driver in such a way that there
> > will always
> > be only *one* frontend, even if it can handle multiple delivery
> > systems. So every frontend an adapter will provide will always be
> > useable independent
> > of all other frontends of that adapter.
> > Personally, I like this method more than having separate frontends
> > for each delivery system, and having to manage access between them.
> > 
> > Just wanted to let you know that the official implementation in VDR
> > (most likely after version 2.0) will go a different way than your
> > patch.
> 
> I am wondering what's the reason of breaking this current rule as it
> sounded so clear...So if cards all delivery systems are mapped as an
> adapters under same frontend, there must be a some method for querying
> which of those adapters are tied together. Did Manu say whether that
> info can be get via dev tree, via sysfs or by using some new ioctl?

If Manu is successful in what he is trying (and existing driver
following other rules will be ported) then that sounds fine to me. I
dont care what solution , but i care for having one. 

> And if the patch wont go in, it means that hvr-4000 owners needs to
> maintain in addition of the vdr-patch, also a patches for all plugins
> that the patch breaks :-(. On the other hand, if the patch would be
> accepted to vdr before 2.0, I am sure that all plugi-ns would be
> adapter to work in couple of weeks to work with the new interfaces.

Its not a drama if on the other hand above happens. If above happens
than vdr needs only to adapt to shared ca devices (which are
implemented as i.e. caio0 & ca0 and need some special handling from vdr
side.
  
L. Hanisch Nov. 19, 2011, 4:15 p.m. UTC | #9
Am 18.11.2011 19:03, schrieb Klaus Schmidinger:
> On 16.11.2011 23:59, L. Hanisch wrote:
>> Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
>>> On 16.11.2011 19:16, L. Hanisch wrote:
>>>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>>>> That is also my understanding of multi frontend devices.
>>>>> If an "adapter" has several "frontends" only one of them can
>>>>> be active at any given time. This has nothing to do with
>>>>> any "explosives" (excuse the pun ;-) and will be implemented
>>>>> in the core VDR code as time permits. Right now I'm cleaning up
>>>>> the "lnb sharing" (aka "device bonding") stuff and will hopefully
>>>>> find more time for VDR development by the end of the year (and
>>>>> thereafter).
>>>>
>>>> If you don't mind I would try to prefabricate something.
>>>> On a first guess: would you combine the multiple frontends of an adapter in one cDvbDevice? I think this would be
>>>> better than having multiple cDvbDevices which must interact somehow with each other.
>>>
>>> Sure there will be one cDvbDevice per adapter for a multi-frontend device
>>> where only one frontend can be active at any time.
>>> If (like on the TT-S2 6400) there are several frontends that can be
>>> active simultaneously, then there shall be separate adapters for each
>>> frontend, and thus a separate cDvbDevice for each adapter.
>>
>> Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived yet I tested with a DVB-T and DVB-C stick and
>> sym-linked the devices within one adapter. I have no ca-devices in this setup.
>> Switching between C and T channels works here, but it's not really tested with timers/recordings etc.
>>
>> I don't have a FF card, so the patches for the plugins are more of "remove compiler warnings" only. One have to think
>> about cDvbDeviceProbe and the parameters. A frontend argument doesn't make much sense now.
>>
>>> Note, though, that support for such devices will most likely not
>>> go into VDR for version 2. I'm trying to wrap things up in order
>>> to make a stable version 2, and after that will address new things
>>> like this.
>>
>> I'm fine with this and looking forward to it. A new stable release would be fine! Xmas is next door... :)
>
> I've received an email from Manu Abraham, informing
> me that he intends to change the driver in such a way that there will always
> be only *one* frontend, even if it can handle multiple delivery systems.
> So every frontend an adapter will provide will always be useable independent
> of all other frontends of that adapter.
> Personally, I like this method more than having separate frontends for
> each delivery system, and having to manage access between them.
>
> Just wanted to let you know that the official implementation in VDR
> (most likely after version 2.0) will go a different way than your patch.

  I followed the discussion on linux-media. But since it's a new ioctl some kind of backport would be needed and also a 
workaround for drivers which doesn't provide the new ioctl.
  One frontend per adapter would be very nice. And in case of dual tuner cards I would expect two adapters since they 
are independent from each other. If they are combined in one adapter they cannot be distinguished from "old" adapters 
with mutually exclusive frontends - and things would be dirtier as is. :)

  In the meantime I will polish my patch a bit and rework on the changes which breaks existing plugins. It was just a 
first try anyway.

Lars.

>
> Klaus
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
>
  
Klaus Schmidinger Nov. 19, 2011, 5:17 p.m. UTC | #10
On 19.11.2011 17:15, L. Hanisch wrote:
> Am 18.11.2011 19:03, schrieb Klaus Schmidinger:
>> On 16.11.2011 23:59, L. Hanisch wrote:
>>> Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
>>>> On 16.11.2011 19:16, L. Hanisch wrote:
>>>>> Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
>>>>>> That is also my understanding of multi frontend devices.
>>>>>> If an "adapter" has several "frontends" only one of them can
>>>>>> be active at any given time. This has nothing to do with
>>>>>> any "explosives" (excuse the pun ;-) and will be implemented
>>>>>> in the core VDR code as time permits. Right now I'm cleaning up
>>>>>> the "lnb sharing" (aka "device bonding") stuff and will hopefully
>>>>>> find more time for VDR development by the end of the year (and
>>>>>> thereafter).
>>>>>
>>>>> If you don't mind I would try to prefabricate something.
>>>>> On a first guess: would you combine the multiple frontends of an adapter in one cDvbDevice? I think this would be
>>>>> better than having multiple cDvbDevices which must interact somehow with each other.
>>>>
>>>> Sure there will be one cDvbDevice per adapter for a multi-frontend device
>>>> where only one frontend can be active at any time.
>>>> If (like on the TT-S2 6400) there are several frontends that can be
>>>> active simultaneously, then there shall be separate adapters for each
>>>> frontend, and thus a separate cDvbDevice for each adapter.
>>>
>>> Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived yet I tested with a DVB-T and DVB-C stick and
>>> sym-linked the devices within one adapter. I have no ca-devices in this setup.
>>> Switching between C and T channels works here, but it's not really tested with timers/recordings etc.
>>>
>>> I don't have a FF card, so the patches for the plugins are more of "remove compiler warnings" only. One have to think
>>> about cDvbDeviceProbe and the parameters. A frontend argument doesn't make much sense now.
>>>
>>>> Note, though, that support for such devices will most likely not
>>>> go into VDR for version 2. I'm trying to wrap things up in order
>>>> to make a stable version 2, and after that will address new things
>>>> like this.
>>>
>>> I'm fine with this and looking forward to it. A new stable release would be fine! Xmas is next door... :)
>>
>> I've received an email from Manu Abraham, informing
>> me that he intends to change the driver in such a way that there will always
>> be only *one* frontend, even if it can handle multiple delivery systems.
>> So every frontend an adapter will provide will always be useable independent
>> of all other frontends of that adapter.
>> Personally, I like this method more than having separate frontends for
>> each delivery system, and having to manage access between them.
>>
>> Just wanted to let you know that the official implementation in VDR
>> (most likely after version 2.0) will go a different way than your patch.
>
> I followed the discussion on linux-media. But since it's a new ioctl some kind of backport would be needed and also a workaround for drivers which doesn't provide the new ioctl.
> One frontend per adapter would be very nice. And in case of dual tuner cards I would expect two adapters since they are independent from each other. If they are combined in one adapter they cannot be distinguished from "old" adapters with mutually exclusive frontends - and things would be dirtier as
> is. :)

Right now VDR considers every frontend to be available independently
of any other, be it an adapter with only a single frontend or one with
several ones. There is no handling for frontends with different delivery
systems (except for DVB-S/DVB-S2, but that's pretty much the same).

Support for frontends with several delivery systems will become available
once the driver supports them in the way Manu described. There is no need
for any backwards compatibility ;-) Those who want to use devices with
multi-delivery-system frontends will just have to use the new driver.
Of course VDR will continue to work with the current driver, but only
by considering all frontends "single delivery-system".

Klaus
  

Patch

diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
index ff3f953..e7fb935 100644
--- a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
+++ b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
@@ -26,7 +26,8 @@ 
 int cDvbHdFfDevice::devHdffOffset = -1;
 
 cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend)
-:cDvbDevice(Adapter, Frontend)
+:cDvbDevice(Adapter)
+,frontend(Frontend)
 {
   spuDecoder = NULL;
   audioChannel = 0;
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
index 4dcfb6a..62540da 100644
--- a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
+++ b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
@@ -17,12 +17,13 @@ 
 
 class cDvbHdFfDevice : public cDvbDevice {
 private:
+  int frontend;
   int fd_osd, fd_audio, fd_video;
 protected:
   virtual void MakePrimaryDevice(bool On);
 public:
   static bool Probe(int Adapter, int Frontend);
-  cDvbHdFfDevice(int Adapter, int Frontend);
+  cDvbHdFfDevice(int Adapter, int Frontend = 0);
   virtual ~cDvbHdFfDevice();
   virtual bool HasDecoder(void) const;
 
diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
index 17f842b..68031b5 100644
--- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
+++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
@@ -24,7 +24,8 @@ 
 int cDvbSdFfDevice::devVideoOffset = -1;
 
 cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly)
-:cDvbDevice(Adapter, Frontend)
+:cDvbDevice(Adapter)
+,frontend(Frontend)
 {
   spuDecoder = NULL;
   digitalAudio = false;
diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h
index bd74cde..c060859 100644
--- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h
+++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h
@@ -16,6 +16,7 @@ 
 
 class cDvbSdFfDevice : public cDvbDevice {
 private:
+  int frontend;
   int fd_osd, fd_audio, fd_video, fd_stc;
   bool outputOnly;
 protected:
diff --git a/dvbci.c b/dvbci.c
index 5289bbd..66dddc8 100644
--- a/dvbci.c
+++ b/dvbci.c
@@ -10,15 +10,18 @@ 
 #include "dvbci.h"
 #include <linux/dvb/ca.h>
 #include <sys/ioctl.h>
-#include "device.h"
+#include "dvbdevice.h"
 
 // --- cDvbCiAdapter ---------------------------------------------------------
 
-cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd)
+cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd, int Adapter, int Ca)
 {
   device = Device;
   SetDescription("CI adapter on device %d", device->DeviceNumber());
   fd = Fd;
+  adapter = Adapter;
+  ca = Ca;
+  OpenCa();
   ca_caps_t Caps;
   if (ioctl(fd, CA_GET_CAP, &Caps) == 0) {
      if ((Caps.slot_type & CA_CI_LINK) != 0) {
@@ -41,10 +44,29 @@  cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd)
 cDvbCiAdapter::~cDvbCiAdapter()
 {
   Cancel(3);
+  CloseCa();
+}
+
+bool cDvbCiAdapter::OpenCa(void)
+{
+  if (fd >= 0)
+     return true;
+  fd = cDvbDevice::DvbOpen(DEV_DVB_CA, adapter, ca, O_RDWR);
+  return (fd >= 0);
+}
+
+void cDvbCiAdapter::CloseCa(void)
+{
+  if (fd < 0)
+     return;
+  close(fd);
+  fd = -1;
 }
 
 int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength)
 {
+  if (fd < 0)
+     return 0;
   if (Buffer && MaxLength > 0) {
      struct pollfd pfd[1];
      pfd[0].fd = fd;
@@ -61,6 +83,8 @@  int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength)
 
 void cDvbCiAdapter::Write(const uint8_t *Buffer, int Length)
 {
+  if (fd < 0)
+     return;
   if (Buffer && Length > 0) {
      if (safe_write(fd, Buffer, Length) != Length)
         esyslog("ERROR: can't write to CI adapter on device %d: %m", device->DeviceNumber());
@@ -69,6 +93,8 @@  void cDvbCiAdapter::Write(const uint8_t *Buffer, int Length)
 
 bool cDvbCiAdapter::Reset(int Slot)
 {
+  if (fd < 0)
+     return false;
   if (ioctl(fd, CA_RESET, 1 << Slot) != -1)
      return true;
   else
@@ -78,6 +104,8 @@  bool cDvbCiAdapter::Reset(int Slot)
 
 eModuleStatus cDvbCiAdapter::ModuleStatus(int Slot)
 {
+  if (fd < 0)
+     return msNone;
   ca_slot_info_t sinfo;
   sinfo.num = Slot;
   if (ioctl(fd, CA_GET_SLOT_INFO, &sinfo) != -1) {
@@ -99,10 +127,10 @@  bool cDvbCiAdapter::Assign(cDevice *Device, bool Query)
   return true;
 }
 
-cDvbCiAdapter *cDvbCiAdapter::CreateCiAdapter(cDevice *Device, int Fd)
+cDvbCiAdapter *cDvbCiAdapter::CreateCiAdapter(cDevice *Device, int Fd, int Adapter, int Ca)
 {
   // TODO check whether a CI is actually present?
   if (Device)
-     return new cDvbCiAdapter(Device, Fd);
+     return new cDvbCiAdapter(Device, Fd, Adapter, Ca);
   return NULL;
 }
diff --git a/dvbci.h b/dvbci.h
index adbe40d..988ecca 100644
--- a/dvbci.h
+++ b/dvbci.h
@@ -16,16 +16,22 @@  class cDvbCiAdapter : public cCiAdapter {
 private:
   cDevice *device;
   int fd;
+  int adapter;
+  int ca;
+  bool idle;
+
+  bool OpenCa(void);
+  void CloseCa(void);
 protected:
   virtual int Read(uint8_t *Buffer, int MaxLength);
   virtual void Write(const uint8_t *Buffer, int Length);
   virtual bool Reset(int Slot);
   virtual eModuleStatus ModuleStatus(int Slot);
   virtual bool Assign(cDevice *Device, bool Query = false);
-  cDvbCiAdapter(cDevice *Device, int Fd);
+  cDvbCiAdapter(cDevice *Device, int Fd, int Adapter = -1, int Ca = -1);
 public:
   virtual ~cDvbCiAdapter();
-  static cDvbCiAdapter *CreateCiAdapter(cDevice *Device, int Fd);
+  static cDvbCiAdapter *CreateCiAdapter(cDevice *Device, int Fd, int Adapter = -1, int Ca = -1);
   };
 
 #endif //__DVBCI_H
diff --git a/dvbdevice.c b/dvbdevice.c
index a97f274..24cefc9 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -276,8 +276,10 @@  private:
   bool GetFrontendStatus(fe_status_t &Status) const;
   bool SetFrontend(void);
   virtual void Action(void);
+  bool OpenFrontend(void);
+  bool CloseFrontend(void);
 public:
-  cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType);
+  cDvbTuner(int Device, int Adapter, int Frontend, fe_delivery_system FrontendType);
   virtual ~cDvbTuner();
   const cChannel *GetTransponder(void) const { return &channel; }
   uint32_t SubsystemId(void) const { return subsystemId; }
@@ -288,10 +290,10 @@  public:
   int GetSignalQuality(void) const;
   };
 
-cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType)
+cDvbTuner::cDvbTuner(int Device, int Adapter, int Frontend, fe_delivery_system FrontendType)
 {
   device = Device;
-  fd_frontend = Fd_Frontend;
+  fd_frontend = -1;
   adapter = Adapter;
   frontend = Frontend;
   frontendType = FrontendType;
@@ -301,8 +303,7 @@  cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_
   lastTimeoutReport = 0;
   diseqcCommands = NULL;
   tunerStatus = tsIdle;
-  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
-     CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
+  OpenFrontend();
   SetDescription("tuner on frontend %d/%d", adapter, frontend);
   Start();
 }
@@ -313,6 +314,7 @@  cDvbTuner::~cDvbTuner()
   newSet.Broadcast();
   locked.Broadcast();
   Cancel(3);
+  CloseFrontend();
 }
 
 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
@@ -698,6 +700,34 @@  void cDvbTuner::Action(void)
         }
 }
 
+bool cDvbTuner::OpenFrontend(void)
+{
+  if (fd_frontend >= 0)
+     return true;
+  cMutexLock MutexLock(&mutex);
+  fd_frontend = cDvbDevice::DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
+  if (fd_frontend < 0)
+     return false;
+  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
+#ifdef LNB_SHARING_VERSION
+     if (lnbSendSignals)
+#endif
+     CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
+  return true;
+}
+
+bool cDvbTuner::CloseFrontend(void)
+{
+  if (fd_frontend < 0)
+     return true;
+  cMutexLock MutexLock(&mutex);
+  tunerStatus = tsIdle;
+  newSet.Broadcast();
+  close(fd_frontend);
+  fd_frontend = -1;
+  return true;
+}
+
 // --- cDvbSourceParam -------------------------------------------------------
 
 class cDvbSourceParam : public cSourceParam {
@@ -778,69 +808,98 @@  const char *DeliverySystems[] = {
   NULL
   };
 
-cDvbDevice::cDvbDevice(int Adapter, int Frontend)
+cDvbDevice::cDvbDevice(int Adapter)
 {
+  numFrontends = 0;
+  currentFrontend = 0;
   adapter = Adapter;
-  frontend = Frontend;
   ciAdapter = NULL;
   dvbTuner = NULL;
-  frontendType = SYS_UNDEFINED;
   numProvidedSystems = 0;
-
-  // Devices that are present on all card types:
-
-  int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
-
-  // Common Interface:
-
-  fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
-  if (fd_ca >= 0)
-     ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca);
-
+  int fd_frontend = -1;
   // The DVR device (will be opened and closed as needed):
-
   fd_dvr = -1;
 
-  // We only check the devices that must be present - the others will be checked before accessing them://XXX
-
-  if (fd_frontend >= 0) {
-     if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) >= 0) {
-        switch (frontendInfo.type) {
-          case FE_QPSK: frontendType = (frontendInfo.caps & FE_CAN_2G_MODULATION) ? SYS_DVBS2 : SYS_DVBS; break;
-          case FE_OFDM: frontendType = SYS_DVBT; break;
-          case FE_QAM:  frontendType = SYS_DVBC_ANNEX_AC; break;
-          case FE_ATSC: frontendType = SYS_ATSC; break;
-          default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
-          }
-        }
-     else
-        LOG_ERROR;
-     if (frontendType != SYS_UNDEFINED) {
-        numProvidedSystems++;
-        if (frontendType == SYS_DVBS2)
-           numProvidedSystems++;
-        char Modulations[64];
-        char *p = Modulations;
-        if (frontendInfo.caps & FE_CAN_QPSK)    { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QPSK, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_16)  { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_16, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_32)  { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_32, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_64)  { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_64, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_128) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_128, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_256) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_256, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_8VSB)    { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_8, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_16VSB)   { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_16, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_TURBO_FEC){numProvidedSystems++; p += sprintf(p, ",%s", "TURBO_FEC"); }
-        if (p != Modulations)
-           p = Modulations + 1; // skips first ','
-        else
-           p = (char *)"unknown modulations";
-        isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], p, frontendInfo.name);
-        dvbTuner = new cDvbTuner(CardIndex() + 1, fd_frontend, adapter, frontend, frontendType);
-        }
+  for (int f = 0; (numFrontends < MAXDVBFRONTENDS) && Exists(adapter, f); f++) {
+      frontends[numFrontends].frontend = f;
+      frontends[numFrontends].demux = frontends[numFrontends].frontend;
+      frontends[numFrontends].dvr = frontends[numFrontends].frontend;
+      frontends[numFrontends].ca = frontends[numFrontends].frontend;
+      frontends[numFrontends].frontendType = SYS_UNDEFINED;
+
+      // Devices that are present on all card types:
+
+      fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontends[numFrontends].frontend, O_RDWR | O_NONBLOCK);
+
+      if (fd_frontend >= 0) {
+         // Look for the right devices
+         while ((frontends[numFrontends].demux >= 0) && !Exists(DEV_DVB_DEMUX, adapter, frontends[numFrontends].demux))
+               frontends[numFrontends].demux--;
+         if (frontends[numFrontends].demux < 0) {
+            frontends[numFrontends].demux = frontends[numFrontends].frontend;
+            esyslog("frontend %d/%d has no demux device", adapter, frontends[numFrontends].frontend);
+            }
+         else if (frontends[numFrontends].demux != frontends[numFrontends].frontend)
+            isyslog("frontend %d/%d will use demux%d", adapter, frontends[numFrontends].frontend, frontends[numFrontends].demux);
+
+         while ((frontends[numFrontends].dvr >= 0) && !Exists(DEV_DVB_DVR, adapter, frontends[numFrontends].dvr))
+               frontends[numFrontends].dvr--;
+         if (frontends[numFrontends].dvr < 0) {
+            frontends[numFrontends].dvr = frontends[numFrontends].frontend;
+            esyslog("frontend %d/%d has no dvr device", adapter, frontends[numFrontends].frontend);
+            }
+         else if (frontends[numFrontends].dvr != frontends[numFrontends].frontend)
+            isyslog("frontend %d/%d will use dvr%d", adapter, frontends[numFrontends].frontend, frontends[numFrontends].dvr);
+
+         while ((frontends[numFrontends].ca >= 0) && !Exists(DEV_DVB_CA, adapter, frontends[numFrontends].ca))
+               frontends[numFrontends].ca--;
+         if ((frontends[numFrontends].ca >= 0) && (frontends[numFrontends].ca != frontends[numFrontends].frontend))
+            isyslog("frontend %d/%d will use ca%d", adapter, frontends[numFrontends].frontend, frontends[numFrontends].ca);
+
+         if (ioctl(fd_frontend, FE_GET_INFO, &frontends[numFrontends].frontendInfo) >= 0) {
+            switch (frontends[numFrontends].frontendInfo.type) {
+              case FE_QPSK: frontends[numFrontends].frontendType = (frontends[numFrontends].frontendInfo.caps & FE_CAN_2G_MODULATION) ? SYS_DVBS2 : SYS_DVBS; break;
+              case FE_OFDM: frontends[numFrontends].frontendType = SYS_DVBT; break;
+              case FE_QAM:  frontends[numFrontends].frontendType = SYS_DVBC_ANNEX_AC; break;
+              case FE_ATSC: frontends[numFrontends].frontendType = SYS_ATSC; break;
+              default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontends[numFrontends].frontendInfo.type, adapter, frontends[numFrontends].frontend);
+              }
+            }
+         else
+            LOG_ERROR;
+         if (frontends[numFrontends].frontendType != SYS_UNDEFINED) {
+            numProvidedSystems++;
+            if (frontends[numFrontends].frontendType == SYS_DVBS2)
+               numProvidedSystems++;
+            char Modulations[64];
+            char *p = Modulations;
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QPSK)    { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QPSK, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_16)  { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_16, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_32)  { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_32, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_64)  { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_64, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_128) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_128, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_256) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_256, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_8VSB)    { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_8, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_16VSB)   { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_16, ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_TURBO_FEC){numProvidedSystems++; p += sprintf(p, ",%s", "TURBO_FEC"); }
+            if (p != Modulations)
+               p = Modulations + 1; // skips first ','
+            else
+               p = (char *)"unknown modulations";
+            isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontends[numFrontends].frontend, DeliverySystems[frontends[numFrontends].frontendType], p, frontends[numFrontends].frontendInfo.name);
+            numFrontends++;
+            }
+         close (fd_frontend);
+         }
+      else
+         esyslog("ERROR: can't open DVB device %d/%d", adapter, frontends[numFrontends].frontend);
+      }
+  if (numFrontends > 0) {
+     dvbTuner = new cDvbTuner(CardIndex() + 1, adapter, frontends[currentFrontend].frontend, frontends[currentFrontend].frontendType);
+     // Common Interface:
+     if (frontends[currentFrontend].ca >= 0)
+        ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, -1, adapter, frontends[currentFrontend].ca);
      }
-  else
-     esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
-
   StartSectionHandler();
 }
 
@@ -869,7 +928,12 @@  int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, b
 
 bool cDvbDevice::Exists(int Adapter, int Frontend)
 {
-  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
+  return Exists(DEV_DVB_FRONTEND, Adapter, Frontend);
+}
+
+bool cDvbDevice::Exists(const char *Name, int Adapter, int Frontend)
+{
+  cString FileName = DvbName(Name, Adapter, Frontend);
   if (access(FileName, F_OK) == 0) {
      int f = open(FileName, O_RDONLY);
      if (f >= 0) {
@@ -884,16 +948,16 @@  bool cDvbDevice::Exists(int Adapter, int Frontend)
   return false;
 }
 
-bool cDvbDevice::Probe(int Adapter, int Frontend)
+bool cDvbDevice::Probe(int Adapter)
 {
-  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
-  dsyslog("probing %s", *FileName);
+  cString adapterName = cString::sprintf("%s%d", DEV_DVB_ADAPTER, Adapter);
+  dsyslog("probing %s", *adapterName);
   for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
-      if (dp->Probe(Adapter, Frontend))
+      if (dp->Probe(Adapter, 0))
          return true; // a plugin has created the actual device
       }
   dsyslog("creating cDvbDevice");
-  new cDvbDevice(Adapter, Frontend); // it's a "budget" device
+  new cDvbDevice(Adapter); // it's a "budget" device
   return true;
 }
 
@@ -906,23 +970,18 @@  bool cDvbDevice::Initialize(void)
   int Checked = 0;
   int Found = 0;
   for (int Adapter = 0; ; Adapter++) {
-      for (int Frontend = 0; ; Frontend++) {
-          if (Exists(Adapter, Frontend)) {
-             if (Checked++ < MAXDVBDEVICES) {
-                if (UseDevice(NextCardIndex())) {
-                   if (Probe(Adapter, Frontend))
-                      Found++;
-                   }
-                else
-                   NextCardIndex(1); // skips this one
-                }
-             }
-          else if (Frontend == 0)
-             goto LastAdapter;
-          else
-             goto NextAdapter;
-          }
-      NextAdapter: ;
+      if (Exists(DEV_DVB_FRONTEND, Adapter, 0)) {
+         if (Checked++ < MAXDVBDEVICES) {
+            if (UseDevice(NextCardIndex())) {
+               if (Probe(Adapter))
+                  Found++;
+               }
+            else
+               NextCardIndex(1); // skips this one
+            }
+         }
+         else
+            goto LastAdapter;
       }
 LastAdapter:
   NextCardIndex(MAXDVBDEVICES - Checked); // skips the rest
@@ -952,7 +1011,7 @@  bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
      memset(&pesFilterParams, 0, sizeof(pesFilterParams));
      if (On) {
         if (Handle->handle < 0) {
-           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
+           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontends[currentFrontend].demux, O_RDWR | O_NONBLOCK, true);
            if (Handle->handle < 0) {
               LOG_ERROR;
               return false;
@@ -987,7 +1046,7 @@  bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
 
 int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
 {
-  cString FileName = DvbName(DEV_DVB_DEMUX, adapter, frontend);
+  cString FileName = DvbName(DEV_DVB_DEMUX, adapter, frontends[currentFrontend].demux);
   int f = open(FileName, O_RDWR | O_NONBLOCK);
   if (f >= 0) {
      dmx_sct_filter_params sctFilterParams;
@@ -1014,32 +1073,43 @@  void cDvbDevice::CloseFilter(int Handle)
   close(Handle);
 }
 
-bool cDvbDevice::ProvidesSource(int Source) const
+int cDvbDevice::GetFrontend(int Source) const
 {
   int type = Source & cSource::st_Mask;
-  return type == cSource::stNone
-      || type == cSource::stAtsc  && (frontendType == SYS_ATSC)
-      || type == cSource::stCable && (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B)
-      || type == cSource::stSat   && (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
-      || type == cSource::stTerr  && (frontendType == SYS_DVBT);
+  if (type == cSource::stNone)
+     return 0; // can this happen?
+  for (int f = 0; f < numFrontends; f++) {
+      if (type == cSource::stAtsc  && (frontends[f].frontendType == SYS_ATSC)
+          || type == cSource::stCable && (frontends[f].frontendType == SYS_DVBC_ANNEX_AC || frontends[f].frontendType == SYS_DVBC_ANNEX_B)
+          || type == cSource::stSat   && (frontends[f].frontendType == SYS_DVBS || frontends[f].frontendType == SYS_DVBS2)
+          || type == cSource::stTerr  && (frontends[f].frontendType == SYS_DVBT))
+         return f;
+      }
+  return -1;
+}
+
+bool cDvbDevice::ProvidesSource(int Source) const
+{
+  return (GetFrontend(Source) >= 0);
 }
 
 bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
 {
-  if (!ProvidesSource(Channel->Source()))
+  int f = GetFrontend(Channel->Source());
+  if (f < 0)
      return false; // doesn't provide source
   cDvbTransponderParameters dtp(Channel->Parameters());
-  if (dtp.System() == SYS_DVBS2 && frontendType == SYS_DVBS ||
-     dtp.Modulation() == QPSK     && !(frontendInfo.caps & FE_CAN_QPSK) ||
-     dtp.Modulation() == QAM_16   && !(frontendInfo.caps & FE_CAN_QAM_16) ||
-     dtp.Modulation() == QAM_32   && !(frontendInfo.caps & FE_CAN_QAM_32) ||
-     dtp.Modulation() == QAM_64   && !(frontendInfo.caps & FE_CAN_QAM_64) ||
-     dtp.Modulation() == QAM_128  && !(frontendInfo.caps & FE_CAN_QAM_128) ||
-     dtp.Modulation() == QAM_256  && !(frontendInfo.caps & FE_CAN_QAM_256) ||
-     dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
-     dtp.Modulation() == VSB_8    && !(frontendInfo.caps & FE_CAN_8VSB) ||
-     dtp.Modulation() == VSB_16   && !(frontendInfo.caps & FE_CAN_16VSB) ||
-     dtp.Modulation() == PSK_8    && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition
+  if (dtp.System() == SYS_DVBS2 && frontends[f].frontendType == SYS_DVBS ||
+     dtp.Modulation() == QPSK     && !(frontends[f].frontendInfo.caps & FE_CAN_QPSK) ||
+     dtp.Modulation() == QAM_16   && !(frontends[f].frontendInfo.caps & FE_CAN_QAM_16) ||
+     dtp.Modulation() == QAM_32   && !(frontends[f].frontendInfo.caps & FE_CAN_QAM_32) ||
+     dtp.Modulation() == QAM_64   && !(frontends[f].frontendInfo.caps & FE_CAN_QAM_64) ||
+     dtp.Modulation() == QAM_128  && !(frontends[f].frontendInfo.caps & FE_CAN_QAM_128) ||
+     dtp.Modulation() == QAM_256  && !(frontends[f].frontendInfo.caps & FE_CAN_QAM_256) ||
+     dtp.Modulation() == QAM_AUTO && !(frontends[f].frontendInfo.caps & FE_CAN_QAM_AUTO) ||
+     dtp.Modulation() == VSB_8    && !(frontends[f].frontendInfo.caps & FE_CAN_8VSB) ||
+     dtp.Modulation() == VSB_16   && !(frontends[f].frontendInfo.caps & FE_CAN_16VSB) ||
+     dtp.Modulation() == PSK_8    && !(frontends[f].frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition
      return false; // requires modulation system which frontend doesn't provide
   if (!cSource::IsSat(Channel->Source()) ||
      !Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization()))
@@ -1113,6 +1183,28 @@  bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel)
 
 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 {
+  if (numFrontends > 1) {
+     int f = GetFrontend(Channel->Source());
+     if (f < 0)
+        return false;
+     if (currentFrontend != f) {
+        isyslog("switching frontend on adapter %d from %d to %d", adapter, frontends[currentFrontend].frontend, frontends[f].frontend);
+        StopSectionHandler();
+        if (dvbTuner) {
+           delete dvbTuner;
+           dvbTuner = NULL;
+           }
+        if (ciAdapter) {
+           delete ciAdapter;
+           ciAdapter = NULL;
+           }
+        currentFrontend = f;
+        dvbTuner = new cDvbTuner(CardIndex() + 1, adapter, frontends[currentFrontend].frontend, frontends[currentFrontend].frontendType);
+        if (frontends[currentFrontend].ca >= 0)
+           ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, -1, adapter, frontends[currentFrontend].ca);
+        StartSectionHandler();
+        }
+     }
   if (dvbTuner)
      dvbTuner->Set(Channel);
   return true;
@@ -1131,7 +1223,7 @@  void cDvbDevice::SetTransferModeForDolbyDigital(int Mode)
 bool cDvbDevice::OpenDvr(void)
 {
   CloseDvr();
-  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
+  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontends[currentFrontend].dvr, O_RDONLY | O_NONBLOCK, true);
   if (fd_dvr >= 0)
      tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1);
   return fd_dvr >= 0;
diff --git a/dvbdevice.h b/dvbdevice.h
index e1842b7..a127da7 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -20,6 +20,7 @@ 
 #endif
 
 #define MAXDVBDEVICES  8
+#define MAXDVBFRONTENDS 8
 
 #define DEV_VIDEO         "/dev/video"
 #define DEV_DVB_ADAPTER   "/dev/dvb/adapter"
@@ -101,14 +102,25 @@  class cDvbTuner;
 
 /// The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API.
 
+struct tDvbFrontend {
+  int frontend;
+  int demux;
+  int dvr;
+  int ca;
+
+  dvb_frontend_info frontendInfo;
+  fe_delivery_system frontendType;
+  };
+
 class cDvbDevice : public cDevice {
-protected:
+public:
   static cString DvbName(const char *Name, int Adapter, int Frontend);
   static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError = false);
 private:
   static bool Exists(int Adapter, int Frontend);
+  static bool Exists(const char *Name, int Adapter, int Frontend);
          ///< Checks whether the given adapter/frontend exists.
-  static bool Probe(int Adapter, int Frontend);
+  static bool Probe(int Adapter);
          ///< Probes for existing DVB devices.
 public:
   static bool Initialize(void);
@@ -116,14 +128,17 @@  public:
          ///< Must be called before accessing any DVB functions.
          ///< \return True if any devices are available.
 protected:
-  int adapter, frontend;
+  int adapter;
 private:
-  dvb_frontend_info frontendInfo;
+  tDvbFrontend frontends[MAXDVBFRONTENDS];
+  int numFrontends;
+  int currentFrontend;
+  int GetFrontend(int Source) const;
+
   int numProvidedSystems;
-  fe_delivery_system frontendType;
-  int fd_dvr, fd_ca;
+  int fd_dvr;
 public:
-  cDvbDevice(int Adapter, int Frontend);
+  cDvbDevice(int Adapter);
   virtual ~cDvbDevice();
   virtual bool Ready(void);