@@ -86,15 +86,20 @@ EXPORT_SYMBOL_GPL(media_device_request_get);
static void media_device_request_release(struct kref *kref)
{
- struct media_entity_request_data *data, *next;
+ struct media_entity_request_data *data, *data_safe;
struct media_device_request *req =
container_of(kref, struct media_device_request, kref);
struct media_device *mdev = req->mdev;
+ struct media_request_link *rlnk, *rlnk_safe;
- list_for_each_entry_safe(data, next, &req->data, list) {
+ list_for_each_entry_safe(data, data_safe, &req->data, list) {
list_del(&data->list);
data->release(data);
}
+ list_for_each_entry_safe(rlnk, rlnk_safe, &req->links, list) {
+ list_del(&rlnk->list);
+ kfree(rlnk);
+ }
mdev->ops->req_free(mdev, req);
}
@@ -105,6 +110,19 @@ void media_device_request_put(struct media_device_request *req)
}
EXPORT_SYMBOL_GPL(media_device_request_put);
+struct media_request_link *media_device_request_link_find(
+ struct media_device_request *req, struct media_link *link)
+{
+ struct media_request_link *rlnk;
+
+ list_for_each_entry(rlnk, &req->links, list) {
+ if (rlnk->link == link)
+ return rlnk;
+ }
+
+ return NULL;
+}
+
/**
* media_device_request_get_entity_data - Get per-entity data
* @req: The request
@@ -182,6 +200,7 @@ static int media_device_request_alloc(struct media_device *mdev,
req->mdev = mdev;
kref_init(&req->kref);
+ INIT_LIST_HEAD(&req->links);
INIT_LIST_HEAD(&req->data);
spin_lock_irqsave(&mdev->req_lock, flags);
@@ -463,6 +482,7 @@ static long media_device_setup_link(struct media_device *mdev,
{
struct media_link *link = NULL;
struct media_link_desc ulink;
+ struct media_device_request *req = NULL;
struct media_entity *source;
struct media_entity *sink;
int ret = -EINVAL;
@@ -470,7 +490,13 @@ static long media_device_setup_link(struct media_device *mdev,
if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
return -EFAULT;
- mutex_lock(&dev->graph_mutex);
+ if (ulink.request) {
+ req = media_device_request_find(mdev, ulink.request);
+ if (!req)
+ return -ENOENT;
+ }
+
+ mutex_lock(&mdev->graph_mutex);
/* Find the source and sink entities and link.
*/
@@ -489,11 +515,33 @@ static long media_device_setup_link(struct media_device *mdev,
if (link == NULL)
goto out;
- /* Setup the link on both entities. */
- ret = __media_entity_setup_link(link, ulink.flags);
+ if (req) {
+ struct media_request_link *rlnk =
+ media_device_request_link_find(req, link);
+
+ if (rlnk) {
+ list_del(&rlnk->list);
+ } else {
+ rlnk = kmalloc(sizeof(*rlnk), GFP_KERNEL);
+ if (!rlnk) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ rlnk->link = link;
+ rlnk->enabled = ulink.flags & MEDIA_LNK_FL_ENABLED;
+ list_add(&rlnk->list, &req->links);
+ } else {
+ /* Setup the link on both entities. */
+ ret = __media_entity_setup_link(link, ulink.flags);
+ }
out:
- mutex_unlock(&dev->graph_mutex);
+ mutex_unlock(&mdev->graph_mutex);
+
+ if (req)
+ media_device_request_put(req);
if (!ret && copy_to_user(_ulink, &ulink, sizeof(ulink)))
ret = -EFAULT;
@@ -41,6 +41,8 @@ struct media_device;
* @kref: Reference count
* @list: List entry in the media device requests list
* @fh_list: List entry in the media file handle requests list
+ * @links: List of links state changes included in the request
+ * (struct media_request_link)
* @data: Per-entity data list
*/
struct media_device_request {
@@ -49,6 +51,7 @@ struct media_device_request {
struct kref kref;
struct list_head list;
struct list_head fh_list;
+ struct list_head links;
struct list_head data;
};
@@ -134,6 +134,18 @@ struct media_entity_graph {
};
/**
+ * struct media_request_link - Request link state changes
+ * @list: List head for the list in struct media_device_request.links
+ * @link: The link the state of which is to be changed
+ * @enabled: Whether the link is to be enabled or not
+ */
+struct media_request_link {
+ struct list_head list;
+ struct media_link *link;
+ bool enabled;
+};
+
+/**
* struct media_entity_request_data - Per-entity request data
* @entity: Entity this data belongs to
* @release: Release operation to free the data