diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/uvc/uvc_entity.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/media/video/uvc/uvc_entity.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_entity.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c new file mode 100644 index 00000000000..29e239911d0 --- /dev/null +++ b/drivers/media/video/uvc/uvc_entity.c | |||
@@ -0,0 +1,126 @@ | |||
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 media_entity *sink; | ||
31 | unsigned int i; | ||
32 | int ret; | ||
33 | |||
34 | sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) | ||
35 | ? (entity->vdev ? &entity->vdev->entity : NULL) | ||
36 | : &entity->subdev.entity; | ||
37 | if (sink == NULL) | ||
38 | return 0; | ||
39 | |||
40 | for (i = 0; i < entity->num_pads; ++i) { | ||
41 | struct media_entity *source; | ||
42 | struct uvc_entity *remote; | ||
43 | u8 remote_pad; | ||
44 | |||
45 | if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) | ||
46 | continue; | ||
47 | |||
48 | remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); | ||
49 | if (remote == NULL) | ||
50 | return -EINVAL; | ||
51 | |||
52 | source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) | ||
53 | ? (remote->vdev ? &remote->vdev->entity : NULL) | ||
54 | : &remote->subdev.entity; | ||
55 | if (source == NULL) | ||
56 | continue; | ||
57 | |||
58 | remote_pad = remote->num_pads - 1; | ||
59 | ret = media_entity_create_link(source, remote_pad, | ||
60 | sink, i, flags); | ||
61 | if (ret < 0) | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) | ||
66 | return 0; | ||
67 | |||
68 | return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev); | ||
69 | } | ||
70 | |||
71 | static struct v4l2_subdev_ops uvc_subdev_ops = { | ||
72 | }; | ||
73 | |||
74 | void uvc_mc_cleanup_entity(struct uvc_entity *entity) | ||
75 | { | ||
76 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) | ||
77 | media_entity_cleanup(&entity->subdev.entity); | ||
78 | else if (entity->vdev != NULL) | ||
79 | media_entity_cleanup(&entity->vdev->entity); | ||
80 | } | ||
81 | |||
82 | static int uvc_mc_init_entity(struct uvc_entity *entity) | ||
83 | { | ||
84 | int ret; | ||
85 | |||
86 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) { | ||
87 | v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops); | ||
88 | strlcpy(entity->subdev.name, entity->name, | ||
89 | sizeof(entity->subdev.name)); | ||
90 | |||
91 | ret = media_entity_init(&entity->subdev.entity, | ||
92 | entity->num_pads, entity->pads, 0); | ||
93 | } else if (entity->vdev != NULL) { | ||
94 | ret = media_entity_init(&entity->vdev->entity, | ||
95 | entity->num_pads, entity->pads, 0); | ||
96 | } else | ||
97 | ret = 0; | ||
98 | |||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | int uvc_mc_register_entities(struct uvc_video_chain *chain) | ||
103 | { | ||
104 | struct uvc_entity *entity; | ||
105 | int ret; | ||
106 | |||
107 | list_for_each_entry(entity, &chain->entities, chain) { | ||
108 | ret = uvc_mc_init_entity(entity); | ||
109 | if (ret < 0) { | ||
110 | uvc_printk(KERN_INFO, "Failed to initialize entity for " | ||
111 | "entity %u\n", entity->id); | ||
112 | return ret; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | list_for_each_entry(entity, &chain->entities, chain) { | ||
117 | ret = uvc_mc_register_entity(chain, entity); | ||
118 | if (ret < 0) { | ||
119 | uvc_printk(KERN_INFO, "Failed to register entity for " | ||
120 | "entity %u\n", entity->id); | ||
121 | return ret; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||