Merge tag 'v4.0-rc1' into patchwork
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 23 Feb 2015 19:02:19 +0000 (16:02 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 23 Feb 2015 19:02:19 +0000 (16:02 -0300)
Linux 34.0-rc1

* tag 'v4.0-rc1': (8947 commits)
  Linux 4.0-rc1
  autofs4 copy_dev_ioctl(): keep the value of ->size we'd used for allocation
  procfs: fix race between symlink removals and traversals
  debugfs: leave freeing a symlink body until inode eviction
  Documentation/filesystems/Locking: ->get_sb() is long gone
  trylock_super(): replacement for grab_super_passive()
  fanotify: Fix up scripted S_ISDIR/S_ISREG/S_ISLNK conversions
  Cachefiles: Fix up scripted S_ISDIR/S_ISREG/S_ISLNK conversions
  VFS: (Scripted) Convert S_ISLNK/DIR/REG(dentry->d_inode) to d_is_*(dentry)
  SELinux: Use d_is_positive() rather than testing dentry->d_inode
  Smack: Use d_is_positive() rather than testing dentry->d_inode
  TOMOYO: Use d_is_dir() rather than d_inode and S_ISDIR()
  Apparmor: Use d_is_positive/negative() rather than testing dentry->d_inode
  Apparmor: mediated_filesystem() should use dentry->d_sb not inode->i_sb
  VFS: Split DCACHE_FILE_TYPE into regular and special types
  VFS: Add a fallthrough flag for marking virtual dentries
  VFS: Add a whiteout dentry type
  VFS: Introduce inode-getting helpers for layered/unioned fs environments
  kernel: make READ_ONCE() valid on const arguments
  blk-throttle: check stats_cpu before reading it from sysfs
  ...

22 files changed:
Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
Documentation/DocBook/media/v4l/v4l2.xml
drivers/media/Kconfig
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dvb_ca_en50221.c
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-core/dvb_net.c
drivers/media/dvb-core/dvbdev.c
drivers/media/dvb-core/dvbdev.h
drivers/media/i2c/cx25840/cx25840-core.c
drivers/media/i2c/cx25840/cx25840-core.h
drivers/media/rc/ir-hix5hd2.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-dvb.c
drivers/media/usb/cx231xx/cx231xx-video.c
drivers/media/usb/cx231xx/cx231xx.h
drivers/media/usb/gspca/topro.c
drivers/media/v4l2-core/tuner-core.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-device.c
include/media/media-entity.h
include/uapi/linux/media.h

index 116c301..cbf307f 100644 (file)
          <row>
            <entry></entry>
            <entry>struct</entry>
-           <entry><structfield>v4l</structfield></entry>
+           <entry><structfield>dev</structfield></entry>
            <entry></entry>
-           <entry>Valid for V4L sub-devices and nodes only.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>major</structfield></entry>
-           <entry>V4L device node major number. For V4L sub-devices with no
-           device node, set by the driver to 0.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>minor</structfield></entry>
-           <entry>V4L device node minor number. For V4L sub-devices with no
-           device node, set by the driver to 0.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-           <entry><structfield>fb</structfield></entry>
-           <entry></entry>
-           <entry>Valid for frame buffer nodes only.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>major</structfield></entry>
-           <entry>Frame buffer device node major number.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>minor</structfield></entry>
-           <entry>Frame buffer device node minor number.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-           <entry><structfield>alsa</structfield></entry>
-           <entry></entry>
-           <entry>Valid for ALSA devices only.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>card</structfield></entry>
-           <entry>ALSA card number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>device</structfield></entry>
-           <entry>ALSA device number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>subdevice</structfield></entry>
-           <entry>ALSA sub-device number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>int</entry>
-           <entry><structfield>dvb</structfield></entry>
-           <entry></entry>
-           <entry>DVB card number</entry>
+           <entry>Valid for (sub-)devices that create devnodes.</entry>
          </row>
          <row>
            <entry></entry>
            <entry>__u8</entry>
-           <entry><structfield>raw</structfield>[180]</entry>
+           <entry><structfield>raw</structfield>[184]</entry>
            <entry></entry>
            <entry></entry>
          </row>
            <entry>ALSA card</entry>
          </row>
          <row>
-           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry>
-           <entry>DVB card</entry>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_FE</constant></entry>
+           <entry>DVB frontend devnode</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_DEMUX</constant></entry>
+           <entry>DVB demux devnode</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_DVR</constant></entry>
+           <entry>DVB DVR devnode</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_CA</constant></entry>
+           <entry>DVB CAM devnode</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_NET</constant></entry>
+           <entry>DVB network devnode</entry>
          </row>
          <row>
            <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
            it in some digital video standard, with appropriate embedded timing
            signals.</entry>
          </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_TUNER</constant></entry>
+           <entry>TV and/or radio tuner</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
index ac0f8d9..e98caa1 100644 (file)
@@ -136,6 +136,7 @@ Remote Controller chapter.</contrib>
       <year>2012</year>
       <year>2013</year>
       <year>2014</year>
+      <year>2015</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
 Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
        Pawel Osciak</holder>
@@ -151,6 +152,14 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+       <revnumber>3.21</revnumber>
+       <date>2015-02-13</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>Fix documentation for media controller device nodes and add support for DVB device nodes.
+Add support for Tuner sub-device.
+       </revremark>
+      </revision>
       <revision>
        <revnumber>3.19</revnumber>
        <date>2014-12-05</date>
index 49cd308..3ef0f90 100644 (file)
@@ -87,13 +87,21 @@ config MEDIA_RC_SUPPORT
 
 config MEDIA_CONTROLLER
        bool "Media Controller API"
-       depends on MEDIA_CAMERA_SUPPORT
+       depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
        ---help---
          Enable the media controller API used to query media devices internal
          topology and configure it dynamically.
 
          This API is mostly used by camera interfaces in embedded platforms.
 
+config MEDIA_CONTROLLER_DVB
+       bool "Enable Media controller for DVB"
+       depends on MEDIA_CONTROLLER
+       ---help---
+         Enable the media controller API support for DVB.
+
+         This is currently experimental.
+
 #
 # Video4Linux support
 #      Only enables if one of the V4L2 types (ATV, webcam, radio) is selected
index abff803..2835924 100644 (file)
@@ -1136,10 +1136,13 @@ static const struct file_operations dvb_demux_fops = {
        .llseek = default_llseek,
 };
 
-static struct dvb_device dvbdev_demux = {
+static const struct dvb_device dvbdev_demux = {
        .priv = NULL,
        .users = 1,
        .writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       .name = "demux",
+#endif
        .fops = &dvb_demux_fops
 };
 
@@ -1209,13 +1212,15 @@ static const struct file_operations dvb_dvr_fops = {
        .llseek = default_llseek,
 };
 
-static struct dvb_device dvbdev_dvr = {
+static const struct dvb_device dvbdev_dvr = {
        .priv = NULL,
        .readers = 1,
        .users = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       .name = "dvr",
+#endif
        .fops = &dvb_dvr_fops
 };
-
 int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
        int i;
index 0aac309..2bf28eb 100644 (file)
@@ -1638,15 +1638,17 @@ static const struct file_operations dvb_ca_fops = {
        .llseek = noop_llseek,
 };
 
-static struct dvb_device dvbdev_ca = {
+static const struct dvb_device dvbdev_ca = {
        .priv = NULL,
        .users = 1,
        .readers = 1,
        .writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       .name = "ca_en50221",
+#endif
        .fops = &dvb_ca_fops,
 };
 
-
 /* ******************************************************************************** */
 /* Initialisation/shutdown functions */
 
index 2cf3057..aa53069 100644 (file)
@@ -131,6 +131,11 @@ struct dvb_frontend_private {
        int quality;
        unsigned int check_wrapped;
        enum dvbfe_search algo_status;
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       struct media_pipeline pipe;
+       struct media_entity *pipe_start_entity;
+#endif
 };
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe);
@@ -590,12 +595,104 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
        wake_up_interruptible(&fepriv->wait_queue);
 }
 
+/**
+ * dvb_enable_media_tuner() - tries to enable the DVB tuner
+ *
+ * @fe:                struct dvb_frontend pointer
+ *
+ * This function ensures that just one media tuner is enabled for a given
+ * frontend. It has two different behaviors:
+ * - For trivial devices with just one tuner:
+ *   it just enables the existing tuner->fe link
+ * - For devices with more than one tuner:
+ *   It is up to the driver to implement the logic that will enable one tuner
+ *   and disable the other ones. However, if more than one tuner is enabled for
+ *   the same frontend, it will print an error message and return -EINVAL.
+ *
+ * At return, it will return the error code returned by media_entity_setup_link,
+ * or 0 if everything is OK, if no tuner is linked to the frontend or if the
+ * mdev is NULL.
+ */
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+static int dvb_enable_media_tuner(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_adapter *adapter = fe->dvb;
+       struct media_device *mdev = adapter->mdev;
+       struct media_entity  *entity, *source;
+       struct media_link *link, *found_link = NULL;
+       int i, ret, n_links = 0, active_links = 0;
+
+       fepriv->pipe_start_entity = NULL;
+
+       if (!mdev)
+               return 0;
+
+       entity = fepriv->dvbdev->entity;
+       fepriv->pipe_start_entity = entity;
+
+       for (i = 0; i < entity->num_links; i++) {
+               link = &entity->links[i];
+               if (link->sink->entity == entity) {
+                       found_link = link;
+                       n_links++;
+                       if (link->flags & MEDIA_LNK_FL_ENABLED)
+                               active_links++;
+               }
+       }
+
+       if (!n_links || active_links == 1 || !found_link)
+               return 0;
+
+       /*
+        * If a frontend has more than one tuner linked, it is up to the driver
+        * to select with one will be the active one, as the frontend core can't
+        * guess. If the driver doesn't do that, it is a bug.
+        */
+       if (n_links > 1 && active_links != 1) {
+               dev_err(fe->dvb->device,
+                       "WARNING: there are %d active links among %d tuners. This is a driver's bug!\n",
+                       active_links, n_links);
+               return -EINVAL;
+       }
+
+       source = found_link->source->entity;
+       fepriv->pipe_start_entity = source;
+       for (i = 0; i < source->num_links; i++) {
+               struct media_entity *sink;
+               int flags = 0;
+
+               link = &source->links[i];
+               sink = link->sink->entity;
+
+               if (sink == entity)
+                       flags = MEDIA_LNK_FL_ENABLED;
+
+               ret = media_entity_setup_link(link, flags);
+               if (ret) {
+                       dev_err(fe->dvb->device,
+                               "Couldn't change link %s->%s to %s. Error %d\n",
+                               source->name, sink->name,
+                               flags ? "enabled" : "disabled",
+                               ret);
+                       return ret;
+               } else
+                       dev_dbg(fe->dvb->device,
+                               "link %s->%s was %s\n",
+                               source->name, sink->name,
+                               flags ? "ENABLED" : "disabled");
+       }
+       return 0;
+}
+#endif
+
 static int dvb_frontend_thread(void *data)
 {
        struct dvb_frontend *fe = data;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        fe_status_t s;
        enum dvbfe_algo algo;
+       int ret;
 
        bool re_tune = false;
        bool semheld = false;
@@ -609,6 +706,20 @@ static int dvb_frontend_thread(void *data)
        fepriv->wakeup = 0;
        fepriv->reinitialise = 0;
 
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+       ret = dvb_enable_media_tuner(fe);
+       if (ret) {
+               /* FIXME: return an error if it fails */
+               dev_info(fe->dvb->device,
+                       "proceeding with FE task\n");
+       } else {
+               ret = media_entity_pipeline_start(fepriv->pipe_start_entity,
+                                                 &fepriv->pipe);
+               if (ret)
+                       return ret;
+       }
+#endif
+
        dvb_frontend_init(fe);
 
        set_freezable();
@@ -718,6 +829,11 @@ restart:
                }
        }
 
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+       media_entity_pipeline_stop(fepriv->pipe_start_entity);
+       fepriv->pipe_start_entity = NULL;
+#endif
+
        if (dvb_powerdown_on_sleep) {
                if (fe->ops.set_voltage)
                        fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
@@ -2612,11 +2728,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
                          struct dvb_frontend* fe)
 {
        struct dvb_frontend_private *fepriv;
-       static const struct dvb_device dvbdev_template = {
+       const struct dvb_device dvbdev_template = {
                .users = ~0,
                .writers = 1,
                .readers = (~0)-1,
                .fops = &dvb_frontend_fops,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+               .name = fe->ops.info.name,
+#endif
                .kernel_ioctl = dvb_frontend_ioctl
        };
 
index 686d327..4099005 100644 (file)
@@ -1462,14 +1462,16 @@ static const struct file_operations dvb_net_fops = {
        .llseek = noop_llseek,
 };
 
-static struct dvb_device dvbdev_net = {
+static const struct dvb_device dvbdev_net = {
        .priv = NULL,
        .users = 1,
        .writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       .name = "dvb net",
+#endif
        .fops = &dvb_net_fops,
 };
 
-
 void dvb_net_release (struct dvb_net *dvbnet)
 {
        int i;
index 983db75..0af9d0c 100644 (file)
@@ -180,6 +180,93 @@ skip:
        return -ENFILE;
 }
 
+static void dvb_register_media_device(struct dvb_device *dvbdev,
+                                     int type, int minor)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       int ret = 0, npads;
+
+       if (!dvbdev->adapter->mdev)
+               return;
+
+       dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
+       if (!dvbdev->entity)
+               return;
+
+       dvbdev->entity->info.dev.major = DVB_MAJOR;
+       dvbdev->entity->info.dev.minor = minor;
+       dvbdev->entity->name = dvbdev->name;
+
+       switch (type) {
+       case DVB_DEVICE_CA:
+       case DVB_DEVICE_DEMUX:
+       case DVB_DEVICE_FRONTEND:
+               npads = 2;
+               break;
+       case DVB_DEVICE_NET:
+               npads = 0;
+               break;
+       default:
+               npads = 1;
+       }
+
+       if (npads) {
+               dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
+                                      GFP_KERNEL);
+               if (!dvbdev->pads) {
+                       kfree(dvbdev->entity);
+                       return;
+               }
+       }
+
+       switch (type) {
+       case DVB_DEVICE_FRONTEND:
+               dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE;
+               dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+               dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+               break;
+       case DVB_DEVICE_DEMUX:
+               dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX;
+               dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+               dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+               break;
+       case DVB_DEVICE_DVR:
+               dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR;
+               dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+               break;
+       case DVB_DEVICE_CA:
+               dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA;
+               dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+               dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+               break;
+       case DVB_DEVICE_NET:
+               dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET;
+               break;
+       default:
+               kfree(dvbdev->entity);
+               dvbdev->entity = NULL;
+               return;
+       }
+
+       if (npads)
+               ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0);
+       if (!ret)
+               ret = media_device_register_entity(dvbdev->adapter->mdev,
+                                                  dvbdev->entity);
+       if (ret < 0) {
+               printk(KERN_ERR
+                       "%s: media_device_register_entity failed for %s\n",
+                       __func__, dvbdev->entity->name);
+               kfree(dvbdev->pads);
+               kfree(dvbdev->entity);
+               dvbdev->entity = NULL;
+               return;
+       }
+
+       printk(KERN_DEBUG "%s: media device '%s' registered.\n",
+               __func__, dvbdev->entity->name);
+#endif
+}
 
 int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                        const struct dvb_device *template, void *priv, int type)
@@ -258,10 +345,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
                return PTR_ERR(clsdev);
        }
-
        dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
                adap->num, dnames[type], id, minor, minor);
 
+       dvb_register_media_device(dvbdev, type, minor);
+
        return 0;
 }
 EXPORT_SYMBOL(dvb_register_device);
@@ -278,12 +366,65 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
 
        device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
 
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       if (dvbdev->entity) {
+               media_device_unregister_entity(dvbdev->entity);
+               kfree(dvbdev->entity);
+               kfree(dvbdev->pads);
+       }
+#endif
+
        list_del (&dvbdev->list_head);
        kfree (dvbdev->fops);
        kfree (dvbdev);
 }
 EXPORT_SYMBOL(dvb_unregister_device);
 
+
+void dvb_create_media_graph(struct media_device *mdev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+       struct media_entity *entity, *tuner = NULL, *fe = NULL;
+       struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL;
+
+       if (!mdev)
+               return;
+
+       media_device_for_each_entity(entity, mdev) {
+               switch (entity->type) {
+               case MEDIA_ENT_T_V4L2_SUBDEV_TUNER:
+                       tuner = entity;
+                       break;
+               case MEDIA_ENT_T_DEVNODE_DVB_FE:
+                       fe = entity;
+                       break;
+               case MEDIA_ENT_T_DEVNODE_DVB_DEMUX:
+                       demux = entity;
+                       break;
+               case MEDIA_ENT_T_DEVNODE_DVB_DVR:
+                       dvr = entity;
+                       break;
+               case MEDIA_ENT_T_DEVNODE_DVB_CA:
+                       ca = entity;
+                       break;
+               }
+       }
+
+       if (tuner && fe)
+               media_entity_create_link(tuner, 0, fe, 0, 0);
+
+       if (fe && demux)
+               media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED);
+
+       if (demux && dvr)
+               media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED);
+
+       if (demux && ca)
+               media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED);
+#endif
+}
+EXPORT_SYMBOL_GPL(dvb_create_media_graph);
+
 static int dvbdev_check_free_adapter_num(int num)
 {
        struct list_head *entry;
index f96b28e..467c131 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/list.h>
+#include <media/media-device.h>
 
 #define DVB_MAJOR 212
 
@@ -71,6 +72,10 @@ struct dvb_adapter {
        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 */
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       struct media_device *mdev;
+#endif
 };
 
 
@@ -92,6 +97,15 @@ struct dvb_device {
        /* don't really need those !? -- FIXME: use video_usercopy  */
        int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
 
+       /* Needed for media controller register/unregister */
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+       const char *name;
+
+       /* Allocated and filled inside dvbdev.c */
+       struct media_entity *entity;
+       struct media_pad *pads;
+#endif
+
        void *priv;
 };
 
@@ -108,6 +122,7 @@ extern int dvb_register_device (struct dvb_adapter *adap,
                                int type);
 
 extern void dvb_unregister_device (struct dvb_device *dvbdev);
+void dvb_create_media_graph(struct media_device *mdev);
 
 extern int dvb_generic_open (struct inode *inode, struct file *file);
 extern int dvb_generic_release (struct inode *inode, struct file *file);
index 573e088..bdb5bb6 100644 (file)
@@ -5137,6 +5137,9 @@ static int cx25840_probe(struct i2c_client *client,
        int default_volume;
        u32 id;
        u16 device_id;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       int ret;
+#endif
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -5178,6 +5181,21 @@ static int cx25840_probe(struct i2c_client *client,
 
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       /* TODO: need to represent analog inputs too */
+       state->pads[0].flags = MEDIA_PAD_FL_SINK;       /* Tuner or input */
+       state->pads[1].flags = MEDIA_PAD_FL_SOURCE;     /* Video */
+       state->pads[2].flags = MEDIA_PAD_FL_SOURCE;     /* VBI */
+       sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+
+       ret = media_entity_init(&sd->entity, ARRAY_SIZE(state->pads),
+                               state->pads, 0);
+       if (ret < 0) {
+               v4l_info(client, "failed to initialize media entity!\n");
+               kfree(state);
+               return -ENODEV;
+       }
+#endif
 
        switch (id) {
        case CX23885_AV:
index 37bc042..17b409f 100644 (file)
@@ -64,6 +64,9 @@ struct cx25840_state {
        wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
        struct work_struct fw_work;   /* work entry for fw load */
        struct cx25840_ir_state *ir_state;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_pad        pads[3];
+#endif
 };
 
 static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
index b0df629..58ec598 100644 (file)
 #include <linux/regmap.h>
 #include <media/rc-core.h>
 
-/* Allow the driver to compile on all architectures */
-#ifndef writel_relaxed
-# define writel_relaxed writel
-#endif
-#ifndef readl_relaxed
-# define readl_relaxed readl
-#endif
-
 #define IR_ENABLE              0x00
 #define IR_CONFIG              0x04
 #define CNT_LEADS              0x08
index da03733..dfc7010 100644 (file)
@@ -912,9 +912,6 @@ static inline void cx231xx_set_model(struct cx231xx *dev)
  */
 void cx231xx_pre_card_setup(struct cx231xx *dev)
 {
-
-       cx231xx_set_model(dev);
-
        dev_info(dev->dev, "Identified as %s (card=%d)\n",
                dev->board.name, dev->model);
 
@@ -1092,6 +1089,17 @@ void cx231xx_config_i2c(struct cx231xx *dev)
        call_all(dev, video, s_stream, 1);
 }
 
+static void cx231xx_unregister_media_device(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+       if (dev->media_dev) {
+               media_device_unregister(dev->media_dev);
+               kfree(dev->media_dev);
+               dev->media_dev = NULL;
+       }
+#endif
+}
+
 /*
  * cx231xx_realease_resources()
  * unregisters the v4l2,i2c and usb devices
@@ -1099,6 +1107,8 @@ void cx231xx_config_i2c(struct cx231xx *dev)
 */
 void cx231xx_release_resources(struct cx231xx *dev)
 {
+       cx231xx_unregister_media_device(dev);
+
        cx231xx_release_analog_resources(dev);
 
        cx231xx_remove_from_devlist(dev);
@@ -1117,6 +1127,74 @@ void cx231xx_release_resources(struct cx231xx *dev)
        clear_bit(dev->devno, &cx231xx_devused);
 }
 
+static void cx231xx_media_device_register(struct cx231xx *dev,
+                                         struct usb_device *udev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+       struct media_device *mdev;
+       int ret;
+
+       mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+       if (!mdev)
+               return;
+
+       mdev->dev = dev->dev;
+       strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
+       if (udev->serial)
+               strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+       strcpy(mdev->bus_info, udev->devpath);
+       mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+       mdev->driver_version = LINUX_VERSION_CODE;
+
+       ret = media_device_register(mdev);
+       if (ret) {
+               dev_err(dev->dev,
+                       "Couldn't create a media device. Error: %d\n",
+                       ret);
+               kfree(mdev);
+               return;
+       }
+
+       dev->media_dev = mdev;
+#endif
+}
+
+static void cx231xx_create_media_graph(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+       struct media_device *mdev = dev->media_dev;
+       struct media_entity *entity;
+       struct media_entity *tuner = NULL, *decoder = NULL;
+
+       if (!mdev)
+               return;
+
+       media_device_for_each_entity(entity, mdev) {
+               switch (entity->type) {
+               case MEDIA_ENT_T_V4L2_SUBDEV_TUNER:
+                       tuner = entity;
+                       break;
+               case MEDIA_ENT_T_V4L2_SUBDEV_DECODER:
+                       decoder = entity;
+                       break;
+               }
+       }
+
+       /* Analog setup, using tuner as a link */
+
+       if (!decoder)
+               return;
+
+       if (tuner)
+               media_entity_create_link(tuner, 0, decoder, 0,
+                                        MEDIA_LNK_FL_ENABLED);
+       media_entity_create_link(decoder, 1, &dev->vdev->entity, 0,
+                                MEDIA_LNK_FL_ENABLED);
+       media_entity_create_link(decoder, 2, &dev->vbi_dev->entity, 0,
+                                MEDIA_LNK_FL_ENABLED);
+#endif
+}
+
 /*
  * cx231xx_init_dev()
  * allocates and inits the device structs, registers i2c bus and v4l device
@@ -1225,10 +1303,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
        }
 
        retval = cx231xx_register_analog_devices(dev);
-       if (retval) {
-               cx231xx_release_analog_resources(dev);
+       if (retval)
                goto err_analog;
-       }
 
        cx231xx_ir_init(dev);
 
@@ -1236,6 +1312,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
 
        return 0;
 err_analog:
+       cx231xx_unregister_media_device(dev);
+       cx231xx_release_analog_resources(dev);
        cx231xx_remove_from_devlist(dev);
 err_dev_init:
        cx231xx_dev_uninit(dev);
@@ -1438,6 +1516,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        dev->video_mode.alt = -1;
        dev->dev = d;
 
+       cx231xx_set_model(dev);
+
        dev->interface_count++;
        /* reset gpio dir and value */
        dev->gpio_dir = 0;
@@ -1502,7 +1582,11 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        /* save our data pointer in this interface device */
        usb_set_intfdata(interface, dev);
 
+       /* Register the media controller */
+       cx231xx_media_device_register(dev, udev);
+
        /* Create v4l2 device */
+       dev->v4l2_dev.mdev = dev->media_dev;
        retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
        if (retval) {
                dev_err(d, "v4l2_device_register failed\n");
@@ -1568,6 +1652,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        /* load other modules required */
        request_modules(dev);
 
+       cx231xx_create_media_graph(dev);
+
        return 0;
 err_video_alt:
        /* cx231xx_uninit_dev: */
index dd600b9..e8c054c 100644 (file)
@@ -455,6 +455,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 
        mutex_init(&dvb->lock);
 
+
        /* register adapter */
        result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
                                      adapter_nr);
@@ -464,6 +465,9 @@ static int register_dvb(struct cx231xx_dvb *dvb,
                       dev->name, result);
                goto fail_adapter;
        }
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+       dvb->adapter.mdev = dev->media_dev;
+#endif
 
        /* Ensure all frontends negotiate bus access */
        dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
@@ -536,6 +540,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 
        /* register network adapter */
        dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+       dvb_create_media_graph(dev->media_dev);
        return 0;
 
 fail_fe_conn:
index ecea76f..6347635 100644 (file)
@@ -703,6 +703,74 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
+static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+       struct media_device *mdev = dev->media_dev;
+       struct media_entity  *entity, *decoder = NULL, *source;
+       struct media_link *link, *found_link = NULL;
+       int i, ret, active_links = 0;
+
+       if (!mdev)
+               return 0;
+
+/*
+ * This will find the tuner that it is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be using an
+ * analog input instead of the tuner. However, we can't use the DVB for dvb
+ * while the DMA engine is being used for V4L2.
+ */
+       media_device_for_each_entity(entity, mdev) {
+               if (entity->type == MEDIA_ENT_T_V4L2_SUBDEV_DECODER) {
+                       decoder = entity;
+                       break;
+               }
+       }
+       if (!decoder)
+               return 0;
+
+       for (i = 0; i < decoder->num_links; i++) {
+               link = &decoder->links[i];
+               if (link->sink->entity == decoder) {
+                       found_link = link;
+                       if (link->flags & MEDIA_LNK_FL_ENABLED)
+                               active_links++;
+                       break;
+               }
+       }
+
+       if (active_links == 1 || !found_link)
+               return 0;
+
+       source = found_link->source->entity;
+       for (i = 0; i < source->num_links; i++) {
+               struct media_entity *sink;
+               int flags = 0;
+
+               link = &source->links[i];
+               sink = link->sink->entity;
+
+               if (sink == entity)
+                       flags = MEDIA_LNK_FL_ENABLED;
+
+               ret = media_entity_setup_link(link, flags);
+               if (ret) {
+                       dev_err(dev->dev,
+                               "Couldn't change link %s->%s to %s. Error %d\n",
+                               source->name, sink->name,
+                               flags ? "enabled" : "disabled",
+                               ret);
+                       return ret;
+               } else
+                       dev_dbg(dev->dev,
+                               "link %s->%s was %s\n",
+                               source->name, sink->name,
+                               flags ? "ENABLED" : "disabled");
+       }
+#endif
+       return 0;
+}
+
 static int
 buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
               enum v4l2_field field)
@@ -756,6 +824,9 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        }
 
        buf->vb.state = VIDEOBUF_PREPARED;
+
+       cx231xx_enable_analog_tuner(dev);
+
        return 0;
 
 fail:
@@ -2121,7 +2192,12 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
                dev_err(dev->dev, "cannot allocate video_device.\n");
                return -ENODEV;
        }
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       dev->video_pad.flags = MEDIA_PAD_FL_SINK;
+       ret = media_entity_init(&dev->vdev->entity, 1, &dev->video_pad, 0);
+       if (ret < 0)
+               dev_err(dev->dev, "failed to initialize video media entity!\n");
+#endif
        dev->vdev->ctrl_handler = &dev->ctrl_handler;
        /* register v4l2 video video_device */
        ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
@@ -2147,6 +2223,12 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
                dev_err(dev->dev, "cannot allocate video_device.\n");
                return -ENODEV;
        }
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+       ret = media_entity_init(&dev->vbi_dev->entity, 1, &dev->vbi_pad, 0);
+       if (ret < 0)
+               dev_err(dev->dev, "failed to initialize vbi media entity!\n");
+#endif
        dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
        /* register v4l2 vbi video_device */
        ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
index 6d6f3ee..e0d3106 100644 (file)
@@ -658,6 +658,11 @@ struct cx231xx {
        struct video_device *vbi_dev;
        struct video_device *radio_dev;
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_device *media_dev;
+       struct media_pad video_pad, vbi_pad;
+#endif
+
        unsigned char eedata[256];
 
        struct cx231xx_video_mode video_mode;
index 5fcd1ee..c70ff40 100644 (file)
@@ -969,7 +969,9 @@ static void jpeg_set_qual(u8 *jpeg_hdr,
 {
        int i, sc;
 
-       if (quality < 50)
+       if (quality <= 0)
+               sc = 5000;
+       else if (quality < 50)
                sc = 5000 / quality;
        else
                sc = 200 - quality * 2;
index 559f837..9a83b27 100644 (file)
@@ -134,6 +134,9 @@ struct tuner {
        unsigned int        type; /* chip type id */
        void                *config;
        const char          *name;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_pad        pad;
+#endif
 };
 
 /*
@@ -434,6 +437,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
                t->name = analog_ops->info.name;
        }
 
+       t->sd.entity.name = t->name;
+
        tuner_dbg("type set to %s\n", t->name);
 
        t->mode_mask = new_mode_mask;
@@ -592,6 +597,9 @@ static int tuner_probe(struct i2c_client *client,
        struct tuner *t;
        struct tuner *radio;
        struct tuner *tv;
+#ifdef CONFIG_MEDIA_CONTROLLER
+       int ret;
+#endif
 
        t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
        if (NULL == t)
@@ -684,6 +692,18 @@ static int tuner_probe(struct i2c_client *client,
 
        /* Should be just before return */
 register_client:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       t->pad.flags = MEDIA_PAD_FL_SOURCE;
+       t->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_TUNER;
+       t->sd.entity.name = t->name;
+
+       ret = media_entity_init(&t->sd.entity, 1, &t->pad, 0);
+       if (ret < 0) {
+               tuner_err("failed to initialize media entity!\n");
+               kfree(t);
+               return -ENODEV;
+       }
+#endif
        /* Sets a default mode */
        if (t->mode_mask & T_ANALOG_TV)
                t->mode = V4L2_TUNER_ANALOG_TV;
index 86bb93f..d89d5cb 100644 (file)
@@ -943,8 +943,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
            vdev->vfl_type != VFL_TYPE_SUBDEV) {
                vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
                vdev->entity.name = vdev->name;
-               vdev->entity.info.v4l.major = VIDEO_MAJOR;
-               vdev->entity.info.v4l.minor = vdev->minor;
+               vdev->entity.info.dev.major = VIDEO_MAJOR;
+               vdev->entity.info.dev.minor = vdev->minor;
                ret = media_device_register_entity(vdev->v4l2_dev->mdev,
                        &vdev->entity);
                if (ret < 0)
index 015f92a..204cc67 100644 (file)
@@ -248,8 +248,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
                        goto clean_up;
                }
 #if defined(CONFIG_MEDIA_CONTROLLER)
-               sd->entity.info.v4l.major = VIDEO_MAJOR;
-               sd->entity.info.v4l.minor = vdev->minor;
+               sd->entity.info.dev.major = VIDEO_MAJOR;
+               sd->entity.info.dev.minor = vdev->minor;
 #endif
                sd->devnode = vdev;
        }
index e004591..d6d74bc 100644 (file)
@@ -87,17 +87,7 @@ struct media_entity {
                struct {
                        u32 major;
                        u32 minor;
-               } v4l;
-               struct {
-                       u32 major;
-                       u32 minor;
-               } fb;
-               struct {
-                       u32 card;
-                       u32 device;
-                       u32 subdevice;
-               } alsa;
-               int dvb;
+               } dev;
 
                /* Sub-device specifications */
                /* Nothing needed yet */
index d847c76..52cc2a6 100644 (file)
@@ -50,7 +50,14 @@ struct media_device_info {
 #define MEDIA_ENT_T_DEVNODE_V4L                (MEDIA_ENT_T_DEVNODE + 1)
 #define MEDIA_ENT_T_DEVNODE_FB         (MEDIA_ENT_T_DEVNODE + 2)
 #define MEDIA_ENT_T_DEVNODE_ALSA       (MEDIA_ENT_T_DEVNODE + 3)
-#define MEDIA_ENT_T_DEVNODE_DVB                (MEDIA_ENT_T_DEVNODE + 4)
+#define MEDIA_ENT_T_DEVNODE_DVB_FE     (MEDIA_ENT_T_DEVNODE + 4)
+#define MEDIA_ENT_T_DEVNODE_DVB_DEMUX  (MEDIA_ENT_T_DEVNODE + 5)
+#define MEDIA_ENT_T_DEVNODE_DVB_DVR    (MEDIA_ENT_T_DEVNODE + 6)
+#define MEDIA_ENT_T_DEVNODE_DVB_CA     (MEDIA_ENT_T_DEVNODE + 7)
+#define MEDIA_ENT_T_DEVNODE_DVB_NET    (MEDIA_ENT_T_DEVNODE + 8)
+
+/* Legacy symbol. Use it to avoid userspace compilation breakages */
+#define MEDIA_ENT_T_DEVNODE_DVB                MEDIA_ENT_T_DEVNODE_DVB_FE
 
 #define MEDIA_ENT_T_V4L2_SUBDEV                (2 << MEDIA_ENT_TYPE_SHIFT)
 #define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1)
@@ -59,6 +66,8 @@ struct media_device_info {
 /* A converter of analogue video to its digital representation. */
 #define MEDIA_ENT_T_V4L2_SUBDEV_DECODER        (MEDIA_ENT_T_V4L2_SUBDEV + 4)
 
+#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER  (MEDIA_ENT_T_V4L2_SUBDEV + 5)
+
 #define MEDIA_ENT_FL_DEFAULT           (1 << 0)
 
 struct media_entity_desc {
@@ -75,6 +84,20 @@ struct media_entity_desc {
 
        union {
                /* Node specifications */
+               struct {
+                       __u32 major;
+                       __u32 minor;
+               } dev;
+
+#if 1
+               /*
+                * DEPRECATED: previous node specifications. Kept just to
+                * avoid breaking compilation, but media_entity_desc.dev
+                * should be used instead. In particular, alsa and dvb
+                * fields below are wrong: for all devnodes, there should
+                * be just major/minor inside the struct, as this is enough
+                * to represent any devnode, no matter what type.
+                */
                struct {
                        __u32 major;
                        __u32 minor;
@@ -89,6 +112,7 @@ struct media_entity_desc {
                        __u32 subdevice;
                } alsa;
                int dvb;
+#endif
 
                /* Sub-device specifications */
                /* Nothing needed yet */