Am Mittwoch, den 02.09.2009, 00:32 -0400 schrieb Michael Krufky:
> Over the course of the past year, a number of developers have
> expressed a need for giving the bridge drivers better control over
> dvb_frontend operations.  Specifically, there is a need for the bridge
> driver to receive a DVB frontend IOCTL and have the opportunity to
> allow or deny the IOCTL to proceed, as resources permit.
> 
> For instance, in the case of a hybrid device, only the bridge driver
> knows whether the analog functionality is presently being used.  If
> the driver is currently in analog mode, serving video frames, the
> driver will have a chance to deny the DVB frontend ioctl request
> before dvb-core passes the request on to the frontend driver,
> potentially damaging the analog video stream already in progress.
> 
> In some cases, the bridge driver might have to perform a setup
> operation to use a feature specific to the device.  For instance, the
> bridge device may be in a low powered state - this new capability
> allows the driver to wake up before passing the command on to the
> frontend driver.  This new feature will allow LinuxTV developers to
> finally get working on actual power management support within the
> v4l/dvb subsystem, without the fear of breaking devices with hybrid
> analog / digital functionality.
> 
> In other cases, there may be situations in which multiple RF
> connectors are available to the tuner, but only the bridge driver will
> be aware of this, as this type of thing is specific to the device's
> hardware implementation.  As there are many tuners capable of multiple
> RF spigots, not all devices actually employ this feature - only the
> bridge driver knows what implementations support such features, and
> how to enable / disable them.
> 
> The possibilities are endless.  I actually did all the heavy lifting
> involved in this a few months ago, but haven't had a moment to write
> up this RFC until now.
> 
> The change to dvb-core that allows this new functionality is posted to
> my development repository on kernellabs.com.  I have also included an
> example of how this can be used on a digital tuner board with multiple
> RF inputs.  The multiple RF input switching is already supported in
> today's code, but I promised Mauro that I would present a better
> method of doing this before the upcoming merge window.  For your
> review and comments, please take a look at the topmost changesets,
> starting with "create a standard method for dvb adapter drivers to
> override frontend ioctls":
> 
> http://kernellabs.com/hg/~mkrufky/fe_ioctl_override
> 
> For those that would prefer not to open up a web browser, here are the
> core changes (apologies if whitespace becomes broken):
> 
> --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c Tue Jun 16
> 16:08:17 2009 -0400
> +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c Sat May 23
> 17:00:59 2009 -0400
> @@ -1594,7 +1594,18 @@
>       struct dvb_device *dvbdev = file->private_data;
>       struct dvb_frontend *fe = dvbdev->priv;
>       struct dvb_frontend_private *fepriv = fe->frontend_priv;
> -     int err = -EOPNOTSUPP;
> +     int cb_err, err = -EOPNOTSUPP;
> +
> +     if (fe->dvb->fe_ioctl_override) {
> +             cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
> +                                                 DVB_FE_IOCTL_PRE);
> +             if (cb_err < 0)
> +                     return cb_err;
> +             if (cb_err > 0)
> +                     return 0;
> +             /* fe_ioctl_override returning 0 allows
> +              * dvb-core to continue handling the ioctl */
> +     }
> 
>       switch (cmd) {
>       case FE_GET_INFO: {
> @@ -1858,6 +1869,13 @@
>               err = 0;
>               break;
>       };
> +
> +     if (fe->dvb->fe_ioctl_override) {
> +             cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
> +                                                 DVB_FE_IOCTL_POST);
> +             if (cb_err < 0)
> +                     return cb_err;
> +     }
> 
>       return err;
>  }
> --- a/linux/drivers/media/dvb/dvb-core/dvbdev.h       Tue Jun 16 16:08:17 
> 2009 -0400
> +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h       Sat May 23 17:00:59 
> 2009 -0400
> @@ -51,6 +51,8 @@
>       module_param_array(adapter_nr, short, NULL, 0444); \
>       MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
> 
> +struct dvb_frontend;
> +
>  struct dvb_adapter {
>       int num;
>       struct list_head list_head;
> @@ -66,6 +68,32 @@
>       int mfe_shared;                 /* indicates mutually exclusive 
> frontends */
>       struct dvb_device *mfe_dvbdev;  /* frontend device in use */
>       struct mutex mfe_lock;          /* access lock for thread creation */
> +
> +     /* Allow the adapter/bridge driver to perform an action before and/or
> +      * after the core handles an ioctl:
> +      *
> +      * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled.
> +      * DVB_FE_IOCTL_POST indicates that the ioctl has been handled.
> +      *
> +      * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg:
> +      *
> +      * return 0 to allow dvb-core to handle the ioctl.
> +      * return a positive int to prevent dvb-core from handling the ioctl,
> +      *      and exit without error.
> +      * return a negative int to prevent dvb-core from handling the ioctl,
> +      *      and return that value as an error.
> +      *
> +      * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg:
> +      *
> +      * return 0 to allow the dvb_frontend ioctl handler to exit normally.
> +      * return a negative int to cause the dvb_frontend ioctl handler to
> +      *      return that value as an error.
> +      */
> +#define DVB_FE_IOCTL_PRE 0
> +#define DVB_FE_IOCTL_POST 1
> +     int (*fe_ioctl_override)(struct dvb_frontend *fe,
> +                              unsigned int cmd, void *parg,
> +                              unsigned int stage);
>  };
> 
> 
> 
> 
> 
> As you can see from the changeset, this allows the bridge to assert
> control both before and after the frontend driver itself handles the
> operation.  Depending on the value returned by the bridge driver,
> dvb-core can exit with error, proceed unchanged, or exit without
> error.
> 
> In order to allow some drivers to use the new feature, I had to make a
> small change to videobuf-dvb:
> 
> --- a/linux/drivers/media/video/videobuf-dvb.c        Tue Jun 16 16:08:17 
> 2009 -0400
> +++ b/linux/drivers/media/video/videobuf-dvb.c        Sat May 23 17:00:59 
> 2009 -0400
> @@ -144,7 +144,9 @@
>                         struct device *device,
>                         char *adapter_name,
>                         short *adapter_nr,
> -                       int mfe_shared)
> +                       int mfe_shared,
> +                       int (*fe_ioctl_override)(struct dvb_frontend *,
> +                                     unsigned int, void *, unsigned int))
>  {
>       int result;
> 
> @@ -159,6 +161,7 @@
>       }
>       fe->adapter.priv = adapter_priv;
>       fe->adapter.mfe_shared = mfe_shared;
> +     fe->adapter.fe_ioctl_override = fe_ioctl_override;
> 
>       return result;
>  }
> @@ -258,7 +261,9 @@
>                         void *adapter_priv,
>                         struct device *device,
>                         short *adapter_nr,
> -                       int mfe_shared)
> +                       int mfe_shared,
> +                       int (*fe_ioctl_override)(struct dvb_frontend *,
> +                                     unsigned int, void *, unsigned int))
>  {
>       struct list_head *list, *q;
>       struct videobuf_dvb_frontend *fe;
> @@ -272,7 +277,7 @@
> 
>       /* Bring up the adapter */
>       res = videobuf_dvb_register_adapter(f, module, adapter_priv, device,
> -             fe->dvb.name, adapter_nr, mfe_shared);
> +             fe->dvb.name, adapter_nr, mfe_shared, fe_ioctl_override);
>       if (res < 0) {
>               printk(KERN_WARNING "videobuf_dvb_register_adapter failed 
> (errno =
> %d)\n", res);
>               return res;
> --- a/linux/include/media/videobuf-dvb.h      Tue Jun 16 16:08:17 2009 -0400
> +++ b/linux/include/media/videobuf-dvb.h      Sat May 23 17:00:59 2009 -0400
> @@ -42,7 +42,9 @@
>                         void *adapter_priv,
>                         struct device *device,
>                         short *adapter_nr,
> -                       int mfe_shared);
> +                       int mfe_shared,
> +                       int (*fe_ioctl_override)(struct dvb_frontend *,
> +                                     unsigned int, void *, unsigned int));
> 
>  void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f);
> 
> --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c Tue Jun 16
> 16:08:17 2009 -0400
> +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c Sat May 23
> 17:00:59 2009 -0400
> @@ -856,7 +856,7 @@
> 
>       /* register everything */
>       ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
> -             &dev->pci->dev, adapter_nr, 0);
> +                                     &dev->pci->dev, adapter_nr, 0, NULL);
> 
>       /* init CI & MAC */
>       switch (dev->board) {
> --- a/linux/drivers/media/video/cx88/cx88-dvb.c       Tue Jun 16 16:08:17 
> 2009 -0400
> +++ b/linux/drivers/media/video/cx88/cx88-dvb.c       Sat May 23 17:00:59 
> 2009 -0400
> @@ -1180,7 +1180,7 @@
> 
>       /* register everything */
>       return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
> -             &dev->pci->dev, adapter_nr, mfe_shared);
> +                                      &dev->pci->dev, adapter_nr, 
> mfe_shared, NULL);
> 
>  frontend_detach:
>       core->gate_ctrl = NULL;
> --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c Tue Jun 16
> 16:08:17 2009 -0400
> +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c Sat May 23
> 17:00:59 2009 -0400
> @@ -1509,7 +1509,7 @@
> 
>       /* register everything else */
>       ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
> -             &dev->pci->dev, adapter_nr, 0);
> +                                     &dev->pci->dev, adapter_nr, 0, NULL);
> 
>       /* this sequence is necessary to make the tda1004x load its firmware
>        * and to enter analog mode of hybrid boards
> 
> 
> 
> 
> Finally, the actual implementation of this new feature in the cx23885
> driver for the sake of RF input switching:
> 
> --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c Sat May 23
> 17:00:59 2009 -0400
> +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c Fri May 08
> 21:39:24 2009 -0400
> @@ -484,9 +484,33 @@
>               }
>               break;
>       }
> -     return (port->set_frontend_save) ?
> -             port->set_frontend_save(fe, param) : -ENODEV;
> +     return 0;
>  }
> +
> +static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe,
> +                                      unsigned int cmd, void *parg,
> +                                      unsigned int stage)
> +{
> +     int err = 0;
> +
> +     switch (stage) {
> +     case DVB_FE_IOCTL_PRE:
> +
> +             switch (cmd) {
> +             case FE_SET_FRONTEND:
> +                     err = cx23885_dvb_set_frontend(fe,
> +                             (struct dvb_frontend_parameters *) parg);
> +                     break;
> +             }
> +             break;
> +
> +     case DVB_FE_IOCTL_POST:
> +             /* no post-ioctl handling required */
> +             break;
> +     }
> +     return err;
> +};
> +
> 
>  static int dvb_register(struct cx23885_tsport *port)
>  {
> @@ -527,12 +551,6 @@
>                                  0x60, &dev->i2c_bus[1].i2c_adap,
>                                  &hauppauge_hvr127x_config);
>               }
> -
> -             /* FIXME: temporary hack */
> -             /* define bridge override to set_frontend */
> -             port->set_frontend_save = fe0->dvb.frontend->ops.set_frontend;
> -             fe0->dvb.frontend->ops.set_frontend = cx23885_dvb_set_frontend;
> -
>               break;
>       case CX23885_BOARD_HAUPPAUGE_HVR1255:
>               i2c_bus = &dev->i2c_bus[0];
> @@ -856,7 +874,8 @@
> 
>       /* register everything */
>       ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
> -                                     &dev->pci->dev, adapter_nr, 0, NULL);
> +                                     &dev->pci->dev, adapter_nr, 0,
> +                                     cx23885_dvb_fe_ioctl_override);
> 
>       /* init CI & MAC */
>       switch (dev->board) {
> --- a/linux/drivers/media/video/cx23885/cx23885.h     Sat May 23 17:00:59 
> 2009 -0400
> +++ b/linux/drivers/media/video/cx23885/cx23885.h     Fri May 08 21:39:24 
> 2009 -0400
> @@ -289,10 +289,6 @@
>       /* Allow a single tsport to have multiple frontends */
>       u32                        num_frontends;
>       void                       *port_priv;
> -
> -     /* FIXME: temporary hack */
> -     int (*set_frontend_save) (struct dvb_frontend *,
> -                               struct dvb_frontend_parameters *);
>  };
> 
>  struct cx23885_dev {
> 
> 
> 
> 
> Again, the above changeset simply removes the old RF input path
> switching hack, and implements the feature using the new frontend
> ioctl override method instead.  This is a much cleaner and more more
> robust way to handle this, which actually opening doors for other
> drivers to handle similar problems in a much more efficient manner.
> 
> Please voice your comments about this particular change and any of its
> implications in this thread.  If all goes well, I'd like to merge this
> into the master repository in time for the next merge window.  Once
> this is in the master branch, I can start working on removing other
> similar hacks from other drivers in our tree, in favor of this better
> method.
> 
> Cheers,
> 
> Michael Krufky
> --

I'm all for it.

Cheers,
Hermann


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to