aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/uvc/uvc_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc/uvc_driver.c')
-rw-r--r--drivers/media/video/uvc/uvc_driver.c94
1 files changed, 87 insertions, 7 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 6459b8cba22..b6eae48d7fb 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -84,6 +84,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.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,
.fcc = V4L2_PIX_FMT_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,