diff options
Diffstat (limited to 'drivers/media/video/uvc/uvc_driver.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 66 |
1 files changed, 59 insertions, 7 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 823f4b389745..b6eae48d7fb8 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -248,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator) | |||
248 | * Terminal and unit management | 248 | * Terminal and unit management |
249 | */ | 249 | */ |
250 | 250 | ||
251 | static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) | 251 | struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) |
252 | { | 252 | { |
253 | struct uvc_entity *entity; | 253 | struct uvc_entity *entity; |
254 | 254 | ||
@@ -795,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | |||
795 | struct uvc_entity *entity; | 795 | struct uvc_entity *entity; |
796 | unsigned int num_inputs; | 796 | unsigned int num_inputs; |
797 | unsigned int size; | 797 | unsigned int size; |
798 | unsigned int i; | ||
798 | 799 | ||
800 | extra_size = ALIGN(extra_size, sizeof(*entity->pads)); | ||
799 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; | 801 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; |
800 | size = sizeof(*entity) + extra_size + num_inputs; | 802 | size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads |
803 | + num_inputs; | ||
801 | entity = kzalloc(size, GFP_KERNEL); | 804 | entity = kzalloc(size, GFP_KERNEL); |
802 | if (entity == NULL) | 805 | if (entity == NULL) |
803 | return NULL; | 806 | return NULL; |
@@ -805,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | |||
805 | entity->id = id; | 808 | entity->id = id; |
806 | entity->type = type; | 809 | entity->type = type; |
807 | 810 | ||
811 | entity->num_links = 0; | ||
812 | entity->num_pads = num_pads; | ||
813 | entity->pads = ((void *)(entity + 1)) + extra_size; | ||
814 | |||
815 | for (i = 0; i < num_inputs; ++i) | ||
816 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; | ||
817 | if (!UVC_ENTITY_IS_OTERM(entity)) | ||
818 | entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE; | ||
819 | |||
808 | entity->bNrInPins = num_inputs; | 820 | entity->bNrInPins = num_inputs; |
809 | entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size; | 821 | entity->baSourceID = (__u8 *)(&entity->pads[num_pads]); |
810 | 822 | ||
811 | return entity; | 823 | return entity; |
812 | } | 824 | } |
@@ -1585,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev) | |||
1585 | uvc_status_cleanup(dev); | 1597 | uvc_status_cleanup(dev); |
1586 | uvc_ctrl_cleanup_device(dev); | 1598 | uvc_ctrl_cleanup_device(dev); |
1587 | 1599 | ||
1600 | if (dev->vdev.dev) | ||
1601 | v4l2_device_unregister(&dev->vdev); | ||
1602 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1603 | if (media_devnode_is_registered(&dev->mdev.devnode)) | ||
1604 | media_device_unregister(&dev->mdev); | ||
1605 | #endif | ||
1606 | |||
1588 | list_for_each_safe(p, n, &dev->chains) { | 1607 | list_for_each_safe(p, n, &dev->chains) { |
1589 | struct uvc_video_chain *chain; | 1608 | struct uvc_video_chain *chain; |
1590 | chain = list_entry(p, struct uvc_video_chain, list); | 1609 | chain = list_entry(p, struct uvc_video_chain, list); |
@@ -1594,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev) | |||
1594 | list_for_each_safe(p, n, &dev->entities) { | 1613 | list_for_each_safe(p, n, &dev->entities) { |
1595 | struct uvc_entity *entity; | 1614 | struct uvc_entity *entity; |
1596 | entity = list_entry(p, struct uvc_entity, list); | 1615 | entity = list_entry(p, struct uvc_entity, list); |
1616 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1617 | uvc_mc_cleanup_entity(entity); | ||
1618 | #endif | ||
1619 | if (entity->vdev) { | ||
1620 | video_device_release(entity->vdev); | ||
1621 | entity->vdev = NULL; | ||
1622 | } | ||
1597 | kfree(entity); | 1623 | kfree(entity); |
1598 | } | 1624 | } |
1599 | 1625 | ||
@@ -1616,8 +1642,6 @@ static void uvc_release(struct video_device *vdev) | |||
1616 | struct uvc_streaming *stream = video_get_drvdata(vdev); | 1642 | struct uvc_streaming *stream = video_get_drvdata(vdev); |
1617 | struct uvc_device *dev = stream->dev; | 1643 | struct uvc_device *dev = stream->dev; |
1618 | 1644 | ||
1619 | video_device_release(vdev); | ||
1620 | |||
1621 | /* Decrement the registered streams count and delete the device when it | 1645 | /* Decrement the registered streams count and delete the device when it |
1622 | * reaches zero. | 1646 | * reaches zero. |
1623 | */ | 1647 | */ |
@@ -1682,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev, | |||
1682 | * unregistered before the reference is released, so we don't need to | 1706 | * unregistered before the reference is released, so we don't need to |
1683 | * get another one. | 1707 | * get another one. |
1684 | */ | 1708 | */ |
1685 | vdev->parent = &dev->intf->dev; | 1709 | vdev->v4l2_dev = &dev->vdev; |
1686 | vdev->fops = &uvc_fops; | 1710 | vdev->fops = &uvc_fops; |
1687 | vdev->release = uvc_release; | 1711 | vdev->release = uvc_release; |
1688 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | 1712 | strlcpy(vdev->name, dev->name, sizeof vdev->name); |
@@ -1731,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev, | |||
1731 | ret = uvc_register_video(dev, stream); | 1755 | ret = uvc_register_video(dev, stream); |
1732 | if (ret < 0) | 1756 | if (ret < 0) |
1733 | return ret; | 1757 | return ret; |
1758 | |||
1759 | term->vdev = stream->vdev; | ||
1734 | } | 1760 | } |
1735 | 1761 | ||
1736 | return 0; | 1762 | return 0; |
@@ -1745,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev) | |||
1745 | ret = uvc_register_terms(dev, chain); | 1771 | ret = uvc_register_terms(dev, chain); |
1746 | if (ret < 0) | 1772 | if (ret < 0) |
1747 | return ret; | 1773 | return ret; |
1774 | |||
1775 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1776 | ret = uvc_mc_register_entities(chain); | ||
1777 | if (ret < 0) { | ||
1778 | uvc_printk(KERN_INFO, "Failed to register entites " | ||
1779 | "(%d).\n", ret); | ||
1780 | } | ||
1781 | #endif | ||
1748 | } | 1782 | } |
1749 | 1783 | ||
1750 | return 0; | 1784 | return 0; |
@@ -1814,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf, | |||
1814 | "linux-uvc-devel mailing list.\n"); | 1848 | "linux-uvc-devel mailing list.\n"); |
1815 | } | 1849 | } |
1816 | 1850 | ||
1851 | /* Register the media and V4L2 devices. */ | ||
1852 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1853 | dev->mdev.dev = &intf->dev; | ||
1854 | strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); | ||
1855 | if (udev->serial) | ||
1856 | strlcpy(dev->mdev.serial, udev->serial, | ||
1857 | sizeof(dev->mdev.serial)); | ||
1858 | strcpy(dev->mdev.bus_info, udev->devpath); | ||
1859 | dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); | ||
1860 | dev->mdev.driver_version = DRIVER_VERSION_NUMBER; | ||
1861 | if (media_device_register(&dev->mdev) < 0) | ||
1862 | goto error; | ||
1863 | |||
1864 | dev->vdev.mdev = &dev->mdev; | ||
1865 | #endif | ||
1866 | if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) | ||
1867 | goto error; | ||
1868 | |||
1817 | /* Initialize controls. */ | 1869 | /* Initialize controls. */ |
1818 | if (uvc_ctrl_init_device(dev) < 0) | 1870 | if (uvc_ctrl_init_device(dev) < 0) |
1819 | goto error; | 1871 | goto error; |
@@ -1822,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf, | |||
1822 | if (uvc_scan_device(dev) < 0) | 1874 | if (uvc_scan_device(dev) < 0) |
1823 | goto error; | 1875 | goto error; |
1824 | 1876 | ||
1825 | /* Register video devices. */ | 1877 | /* Register video device nodes. */ |
1826 | if (uvc_register_chains(dev) < 0) | 1878 | if (uvc_register_chains(dev) < 0) |
1827 | goto error; | 1879 | goto error; |
1828 | 1880 | ||