unsigned int processed_ctrls = 0;
struct uvc_control *ctrl;
unsigned int i;
- int ret;
+ int ret = 0;
if (entity == NULL)
return 0;
dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info.size);
- else
- ret = 0;
if (!ret)
processed_ctrls++;
ctrl->dirty = 0;
- if (ret < 0)
- return ret;
-
- if (!rollback && handle &&
+ if (!rollback && handle && !ret &&
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
uvc_ctrl_set_handle(handle, ctrl, handle);
+
+ if (ret < 0 && !rollback) {
+ /*
+ * If we fail to set a control, we need to rollback
+ * the next ones.
+ */
+ rollback = 1;
+ }
}
+ if (ret)
+ return ret;
+
return processed_ctrls;
}
{
struct uvc_video_chain *chain = handle->chain;
struct uvc_entity *entity;
- int ret = 0;
+ int ret_out = 0;
+ int ret;
/* Find the control. */
list_for_each_entry(entity, &chain->entities, chain) {
ret = uvc_ctrl_commit_entity(chain->dev, handle, entity,
rollback);
- if (ret < 0)
- goto done;
- else if (ret > 0 && !rollback)
+ if (ret < 0) {
+ /*
+ * When we fail to commit an entity, we need to
+ * restore the UVC_CTRL_DATA_BACKUP for all the
+ * controls in the other entities, otherwise our cache
+ * and the hardware will be out of sync.
+ */
+ rollback = 1;
+
+ ret_out = ret;
+ } else if (ret > 0 && !rollback) {
uvc_ctrl_send_events(handle, entity, xctrls,
xctrls_count);
+ }
}
- ret = 0;
-done:
mutex_unlock(&chain->ctrl_mutex);
- return ret;
+ return ret_out;
}
int uvc_ctrl_get(struct uvc_video_chain *chain,