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
26static 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
71static struct v4l2_subdev_ops uvc_subdev_ops = {
72};
73
74void 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
82static 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		if (entity->flags & UVC_ENTITY_FLAG_DEFAULT)
97			entity->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
98	} else
99		ret = 0;
100
101	return ret;
102}
103
104int uvc_mc_register_entities(struct uvc_video_chain *chain)
105{
106	struct uvc_entity *entity;
107	int ret;
108
109	list_for_each_entry(entity, &chain->entities, chain) {
110		ret = uvc_mc_init_entity(entity);
111		if (ret < 0) {
112			uvc_printk(KERN_INFO, "Failed to initialize entity for "
113				   "entity %u\n", entity->id);
114			return ret;
115		}
116	}
117
118	list_for_each_entry(entity, &chain->entities, chain) {
119		ret = uvc_mc_register_entity(chain, entity);
120		if (ret < 0) {
121			uvc_printk(KERN_INFO, "Failed to register entity for "
122				   "entity %u\n", entity->id);
123			return ret;
124		}
125	}
126
127	return 0;
128}
129