Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[pandora-kernel.git] / drivers / media / video / uvc / uvc_driver.c
index 6459b8c..b6eae48 100644 (file)
@@ -83,6 +83,11 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_I420,
                .fcc            = V4L2_PIX_FMT_YUV420,
        },
+       {
+               .name           = "YUV 4:2:0 (M420)",
+               .guid           = UVC_GUID_FORMAT_M420,
+               .fcc            = V4L2_PIX_FMT_M420,
+       },
        {
                .name           = "YUV 4:2:2 (UYVY)",
                .guid           = UVC_GUID_FORMAT_UYVY,
@@ -103,6 +108,11 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_BY8,
                .fcc            = V4L2_PIX_FMT_SBGGR8,
        },
+       {
+               .name           = "RGB565",
+               .guid           = UVC_GUID_FORMAT_RGBP,
+               .fcc            = V4L2_PIX_FMT_RGB565,
+       },
 };
 
 /* ------------------------------------------------------------------------
@@ -238,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
  * Terminal and unit management
  */
 
-static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
 {
        struct uvc_entity *entity;
 
@@ -785,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
        struct uvc_entity *entity;
        unsigned int num_inputs;
        unsigned int size;
+       unsigned int i;
 
+       extra_size = ALIGN(extra_size, sizeof(*entity->pads));
        num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
-       size = sizeof(*entity) + extra_size + num_inputs;
+       size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
+            + num_inputs;
        entity = kzalloc(size, GFP_KERNEL);
        if (entity == NULL)
                return NULL;
@@ -795,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
        entity->id = id;
        entity->type = type;
 
+       entity->num_links = 0;
+       entity->num_pads = num_pads;
+       entity->pads = ((void *)(entity + 1)) + extra_size;
+
+       for (i = 0; i < num_inputs; ++i)
+               entity->pads[i].flags = MEDIA_PAD_FL_SINK;
+       if (!UVC_ENTITY_IS_OTERM(entity))
+               entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
+
        entity->bNrInPins = num_inputs;
-       entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size;
+       entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
 
        return entity;
 }
@@ -1575,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev)
        uvc_status_cleanup(dev);
        uvc_ctrl_cleanup_device(dev);
 
+       if (dev->vdev.dev)
+               v4l2_device_unregister(&dev->vdev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+       if (media_devnode_is_registered(&dev->mdev.devnode))
+               media_device_unregister(&dev->mdev);
+#endif
+
        list_for_each_safe(p, n, &dev->chains) {
                struct uvc_video_chain *chain;
                chain = list_entry(p, struct uvc_video_chain, list);
@@ -1584,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev)
        list_for_each_safe(p, n, &dev->entities) {
                struct uvc_entity *entity;
                entity = list_entry(p, struct uvc_entity, list);
+#ifdef CONFIG_MEDIA_CONTROLLER
+               uvc_mc_cleanup_entity(entity);
+#endif
+               if (entity->vdev) {
+                       video_device_release(entity->vdev);
+                       entity->vdev = NULL;
+               }
                kfree(entity);
        }
 
@@ -1606,8 +1642,6 @@ static void uvc_release(struct video_device *vdev)
        struct uvc_streaming *stream = video_get_drvdata(vdev);
        struct uvc_device *dev = stream->dev;
 
-       video_device_release(vdev);
-
        /* Decrement the registered streams count and delete the device when it
         * reaches zero.
         */
@@ -1672,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev,
         * unregistered before the reference is released, so we don't need to
         * get another one.
         */
-       vdev->parent = &dev->intf->dev;
+       vdev->v4l2_dev = &dev->vdev;
        vdev->fops = &uvc_fops;
        vdev->release = uvc_release;
        strlcpy(vdev->name, dev->name, sizeof vdev->name);
@@ -1721,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev,
                ret = uvc_register_video(dev, stream);
                if (ret < 0)
                        return ret;
+
+               term->vdev = stream->vdev;
        }
 
        return 0;
@@ -1735,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev)
                ret = uvc_register_terms(dev, chain);
                if (ret < 0)
                        return ret;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+               ret = uvc_mc_register_entities(chain);
+               if (ret < 0) {
+                       uvc_printk(KERN_INFO, "Failed to register entites "
+                               "(%d).\n", ret);
+               }
+#endif
        }
 
        return 0;
@@ -1804,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf,
                        "linux-uvc-devel mailing list.\n");
        }
 
+       /* Register the media and V4L2 devices. */
+#ifdef CONFIG_MEDIA_CONTROLLER
+       dev->mdev.dev = &intf->dev;
+       strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
+       if (udev->serial)
+               strlcpy(dev->mdev.serial, udev->serial,
+                       sizeof(dev->mdev.serial));
+       strcpy(dev->mdev.bus_info, udev->devpath);
+       dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+       dev->mdev.driver_version = DRIVER_VERSION_NUMBER;
+       if (media_device_register(&dev->mdev) < 0)
+               goto error;
+
+       dev->vdev.mdev = &dev->mdev;
+#endif
+       if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
+               goto error;
+
        /* Initialize controls. */
        if (uvc_ctrl_init_device(dev) < 0)
                goto error;
@@ -1812,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf,
        if (uvc_scan_device(dev) < 0)
                goto error;
 
-       /* Register video devices. */
+       /* Register video device nodes. */
        if (uvc_register_chains(dev) < 0)
                goto error;
 
@@ -2077,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Hercules Classic Silver */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x06f8,
+         .idProduct            = 0x300c,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
        /* ViMicro Vega */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2123,6 +2194,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* JMicron USB2.0 XGA WebCam */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x152d,
+         .idProduct            = 0x0310,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Syntek (HP Spartan) */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,