diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2010-01-21 03:39:52 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-05-25 18:50:58 -0400 |
commit | 4ffc2d89f38a7fbb3b24adb7fb066a159c351c11 (patch) | |
tree | e325f7ab0e917bd3bae8e7217107e7d0d0cceeeb /drivers/media | |
parent | 5a254d751e52e0f817090c29950d16cf18490d5b (diff) |
[media] uvcvideo: Register subdevices for each entity
Userspace applications can now discover the UVC device topology using
the media controller API.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/uvc/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 29 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_entity.c | 94 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 13 |
4 files changed, 136 insertions, 3 deletions
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile index 968c1994eda0..2071ca8a2f03 100644 --- a/drivers/media/video/uvc/Makefile +++ b/drivers/media/video/uvc/Makefile | |||
@@ -1,3 +1,6 @@ | |||
1 | uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ | 1 | uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ |
2 | uvc_status.o uvc_isight.o | 2 | uvc_status.o uvc_isight.o |
3 | ifeq ($(CONFIG_MEDIA_CONTROLLER),y) | ||
4 | uvcvideo-objs += uvc_entity.o | ||
5 | endif | ||
3 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o | 6 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o |
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 0e8cd1fd870f..0bf3413e8d37 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 | } |
@@ -1601,6 +1613,9 @@ static void uvc_delete(struct uvc_device *dev) | |||
1601 | list_for_each_safe(p, n, &dev->entities) { | 1613 | list_for_each_safe(p, n, &dev->entities) { |
1602 | struct uvc_entity *entity; | 1614 | struct uvc_entity *entity; |
1603 | 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 | ||
1604 | kfree(entity); | 1619 | kfree(entity); |
1605 | } | 1620 | } |
1606 | 1621 | ||
@@ -1752,6 +1767,14 @@ static int uvc_register_chains(struct uvc_device *dev) | |||
1752 | ret = uvc_register_terms(dev, chain); | 1767 | ret = uvc_register_terms(dev, chain); |
1753 | if (ret < 0) | 1768 | if (ret < 0) |
1754 | return ret; | 1769 | return ret; |
1770 | |||
1771 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1772 | ret = uvc_mc_register_entities(chain); | ||
1773 | if (ret < 0) { | ||
1774 | uvc_printk(KERN_INFO, "Failed to register entites " | ||
1775 | "(%d).\n", ret); | ||
1776 | } | ||
1777 | #endif | ||
1755 | } | 1778 | } |
1756 | 1779 | ||
1757 | return 0; | 1780 | return 0; |
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c new file mode 100644 index 000000000000..8e8e7efb4608 --- /dev/null +++ b/drivers/media/video/uvc/uvc_entity.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * uvc_entity.c -- USB Video Class driver | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 | ||
5 | * Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/videodev2.h> | ||
17 | |||
18 | #include <media/v4l2-common.h> | ||
19 | |||
20 | #include "uvcvideo.h" | ||
21 | |||
22 | /* ------------------------------------------------------------------------ | ||
23 | * Video subdevices registration and unregistration | ||
24 | */ | ||
25 | |||
26 | static int uvc_mc_register_entity(struct uvc_video_chain *chain, | ||
27 | struct uvc_entity *entity) | ||
28 | { | ||
29 | const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; | ||
30 | struct uvc_entity *remote; | ||
31 | unsigned int i; | ||
32 | u8 remote_pad; | ||
33 | int ret; | ||
34 | |||
35 | for (i = 0; i < entity->num_pads; ++i) { | ||
36 | if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) | ||
37 | continue; | ||
38 | |||
39 | remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); | ||
40 | if (remote == NULL) | ||
41 | return -EINVAL; | ||
42 | |||
43 | remote_pad = remote->num_pads - 1; | ||
44 | ret = media_entity_create_link(&remote->subdev.entity, | ||
45 | remote_pad, &entity->subdev.entity, i, flags); | ||
46 | if (ret < 0) | ||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev); | ||
51 | } | ||
52 | |||
53 | static struct v4l2_subdev_ops uvc_subdev_ops = { | ||
54 | }; | ||
55 | |||
56 | void uvc_mc_cleanup_entity(struct uvc_entity *entity) | ||
57 | { | ||
58 | media_entity_cleanup(&entity->subdev.entity); | ||
59 | } | ||
60 | |||
61 | static int uvc_mc_init_entity(struct uvc_entity *entity) | ||
62 | { | ||
63 | v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops); | ||
64 | strlcpy(entity->subdev.name, entity->name, sizeof(entity->subdev.name)); | ||
65 | |||
66 | return media_entity_init(&entity->subdev.entity, entity->num_pads, | ||
67 | entity->pads, 0); | ||
68 | } | ||
69 | |||
70 | int uvc_mc_register_entities(struct uvc_video_chain *chain) | ||
71 | { | ||
72 | struct uvc_entity *entity; | ||
73 | int ret; | ||
74 | |||
75 | list_for_each_entry(entity, &chain->entities, chain) { | ||
76 | ret = uvc_mc_init_entity(entity); | ||
77 | if (ret < 0) { | ||
78 | uvc_printk(KERN_INFO, "Failed to initialize entity for " | ||
79 | "entity %u\n", entity->id); | ||
80 | return ret; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | list_for_each_entry(entity, &chain->entities, chain) { | ||
85 | ret = uvc_mc_register_entity(chain, entity); | ||
86 | if (ret < 0) { | ||
87 | uvc_printk(KERN_INFO, "Failed to register entity for " | ||
88 | "entity %u\n", entity->id); | ||
89 | return ret; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | return 0; | ||
94 | } | ||
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index aab7508f2bd2..3906f6ed4061 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -98,6 +98,7 @@ struct uvc_xu_control { | |||
98 | #ifdef __KERNEL__ | 98 | #ifdef __KERNEL__ |
99 | 99 | ||
100 | #include <linux/poll.h> | 100 | #include <linux/poll.h> |
101 | #include <linux/usb.h> | ||
101 | #include <linux/usb/video.h> | 102 | #include <linux/usb/video.h> |
102 | #include <linux/uvcvideo.h> | 103 | #include <linux/uvcvideo.h> |
103 | #include <media/media-device.h> | 104 | #include <media/media-device.h> |
@@ -303,6 +304,12 @@ struct uvc_entity { | |||
303 | __u16 type; | 304 | __u16 type; |
304 | char name[64]; | 305 | char name[64]; |
305 | 306 | ||
307 | /* Media controller-related fields. */ | ||
308 | struct v4l2_subdev subdev; | ||
309 | unsigned int num_pads; | ||
310 | unsigned int num_links; | ||
311 | struct media_pad *pads; | ||
312 | |||
306 | union { | 313 | union { |
307 | struct { | 314 | struct { |
308 | __u16 wObjectiveFocalLengthMin; | 315 | __u16 wObjectiveFocalLengthMin; |
@@ -589,6 +596,8 @@ extern unsigned int uvc_timeout_param; | |||
589 | /* Core driver */ | 596 | /* Core driver */ |
590 | extern struct uvc_driver uvc_driver; | 597 | extern struct uvc_driver uvc_driver; |
591 | 598 | ||
599 | extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); | ||
600 | |||
592 | /* Video buffers queue management. */ | 601 | /* Video buffers queue management. */ |
593 | extern void uvc_queue_init(struct uvc_video_queue *queue, | 602 | extern void uvc_queue_init(struct uvc_video_queue *queue, |
594 | enum v4l2_buf_type type, int drop_corrupted); | 603 | enum v4l2_buf_type type, int drop_corrupted); |
@@ -622,6 +631,10 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) | |||
622 | /* V4L2 interface */ | 631 | /* V4L2 interface */ |
623 | extern const struct v4l2_file_operations uvc_fops; | 632 | extern const struct v4l2_file_operations uvc_fops; |
624 | 633 | ||
634 | /* Media controller */ | ||
635 | extern int uvc_mc_register_entities(struct uvc_video_chain *chain); | ||
636 | extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); | ||
637 | |||
625 | /* Video */ | 638 | /* Video */ |
626 | extern int uvc_video_init(struct uvc_streaming *stream); | 639 | extern int uvc_video_init(struct uvc_streaming *stream); |
627 | extern int uvc_video_suspend(struct uvc_streaming *stream); | 640 | extern int uvc_video_suspend(struct uvc_streaming *stream); |