Commit 8e113595 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

V4L/DVB (12379): uvcvideo: Multiple streaming interfaces support

Restructure the UVC descriptors parsing code to handle multiple streaming
interfaces. The driver now creates a uvc_video_chain instance for each chain
detected in the UVC control interface descriptors, and tries to register one
video device per streaming endpoint.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 35f02a68
...@@ -729,7 +729,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, ...@@ -729,7 +729,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
} }
} }
struct uvc_control *uvc_find_control(struct uvc_video_device *video, struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping) __u32 v4l2_id, struct uvc_control_mapping **mapping)
{ {
struct uvc_control *ctrl = NULL; struct uvc_control *ctrl = NULL;
...@@ -742,17 +742,17 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video, ...@@ -742,17 +742,17 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video,
v4l2_id &= V4L2_CTRL_ID_MASK; v4l2_id &= V4L2_CTRL_ID_MASK;
/* Find the control. */ /* Find the control. */
__uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next); __uvc_find_control(chain->processing, v4l2_id, mapping, &ctrl, next);
if (ctrl && !next) if (ctrl && !next)
return ctrl; return ctrl;
list_for_each_entry(entity, &video->iterms, chain) { list_for_each_entry(entity, &chain->iterms, chain) {
__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
if (ctrl && !next) if (ctrl && !next)
return ctrl; return ctrl;
} }
list_for_each_entry(entity, &video->extensions, chain) { list_for_each_entry(entity, &chain->extensions, chain) {
__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
if (ctrl && !next) if (ctrl && !next)
return ctrl; return ctrl;
...@@ -765,7 +765,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video, ...@@ -765,7 +765,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video,
return ctrl; return ctrl;
} }
int uvc_query_v4l2_ctrl(struct uvc_video_device *video, int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl) struct v4l2_queryctrl *v4l2_ctrl)
{ {
struct uvc_control *ctrl; struct uvc_control *ctrl;
...@@ -775,7 +775,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, ...@@ -775,7 +775,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
__u8 *data; __u8 *data;
int ret; int ret;
ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
if (ctrl == NULL) if (ctrl == NULL)
return -EINVAL; return -EINVAL;
...@@ -793,9 +793,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, ...@@ -793,9 +793,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
ret = uvc_query_ctrl(video->dev, UVC_GET_DEF, ctrl->entity->id, ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector, data, chain->dev->intfnum, ctrl->info->selector,
ctrl->info->size); data, ctrl->info->size);
if (ret < 0) if (ret < 0)
goto out; goto out;
v4l2_ctrl->default_value = v4l2_ctrl->default_value =
...@@ -831,25 +831,25 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, ...@@ -831,25 +831,25 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
} }
if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
ret = uvc_query_ctrl(video->dev, UVC_GET_MIN, ctrl->entity->id, ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector, data, chain->dev->intfnum, ctrl->info->selector,
ctrl->info->size); data, ctrl->info->size);
if (ret < 0) if (ret < 0)
goto out; goto out;
v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data); v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
} }
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
ret = uvc_query_ctrl(video->dev, UVC_GET_MAX, ctrl->entity->id, ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector, data, chain->dev->intfnum, ctrl->info->selector,
ctrl->info->size); data, ctrl->info->size);
if (ret < 0) if (ret < 0)
goto out; goto out;
v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data); v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
} }
if (ctrl->info->flags & UVC_CONTROL_GET_RES) { if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
ret = uvc_query_ctrl(video->dev, UVC_GET_RES, ctrl->entity->id, ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector, data, chain->dev->intfnum, ctrl->info->selector,
ctrl->info->size); data, ctrl->info->size);
if (ret < 0) if (ret < 0)
goto out; goto out;
v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data); v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
...@@ -886,9 +886,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, ...@@ -886,9 +886,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
* (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
* control lock. * control lock.
*/ */
int uvc_ctrl_begin(struct uvc_video_device *video) int uvc_ctrl_begin(struct uvc_video_chain *chain)
{ {
return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0; return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
} }
static int uvc_ctrl_commit_entity(struct uvc_device *dev, static int uvc_ctrl_commit_entity(struct uvc_device *dev,
...@@ -938,34 +938,34 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, ...@@ -938,34 +938,34 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
return 0; return 0;
} }
int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback) int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
{ {
struct uvc_entity *entity; struct uvc_entity *entity;
int ret = 0; int ret = 0;
/* Find the control. */ /* Find the control. */
ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback); ret = uvc_ctrl_commit_entity(chain->dev, chain->processing, rollback);
if (ret < 0) if (ret < 0)
goto done; goto done;
list_for_each_entry(entity, &video->iterms, chain) { list_for_each_entry(entity, &chain->iterms, chain) {
ret = uvc_ctrl_commit_entity(video->dev, entity, rollback); ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
if (ret < 0) if (ret < 0)
goto done; goto done;
} }
list_for_each_entry(entity, &video->extensions, chain) { list_for_each_entry(entity, &chain->extensions, chain) {
ret = uvc_ctrl_commit_entity(video->dev, entity, rollback); ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
if (ret < 0) if (ret < 0)
goto done; goto done;
} }
done: done:
mutex_unlock(&video->ctrl_mutex); mutex_unlock(&chain->ctrl_mutex);
return ret; return ret;
} }
int uvc_ctrl_get(struct uvc_video_device *video, int uvc_ctrl_get(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl) struct v4l2_ext_control *xctrl)
{ {
struct uvc_control *ctrl; struct uvc_control *ctrl;
...@@ -974,13 +974,13 @@ int uvc_ctrl_get(struct uvc_video_device *video, ...@@ -974,13 +974,13 @@ int uvc_ctrl_get(struct uvc_video_device *video,
unsigned int i; unsigned int i;
int ret; int ret;
ctrl = uvc_find_control(video, xctrl->id, &mapping); ctrl = uvc_find_control(chain, xctrl->id, &mapping);
if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
return -EINVAL; return -EINVAL;
if (!ctrl->loaded) { if (!ctrl->loaded) {
ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, ctrl->entity->id, ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector, chain->dev->intfnum, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size); ctrl->info->size);
if (ret < 0) if (ret < 0)
...@@ -1005,7 +1005,7 @@ int uvc_ctrl_get(struct uvc_video_device *video, ...@@ -1005,7 +1005,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
return 0; return 0;
} }
int uvc_ctrl_set(struct uvc_video_device *video, int uvc_ctrl_set(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl) struct v4l2_ext_control *xctrl)
{ {
struct uvc_control *ctrl; struct uvc_control *ctrl;
...@@ -1013,7 +1013,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, ...@@ -1013,7 +1013,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
s32 value = xctrl->value; s32 value = xctrl->value;
int ret; int ret;
ctrl = uvc_find_control(video, xctrl->id, &mapping); ctrl = uvc_find_control(chain, xctrl->id, &mapping);
if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
return -EINVAL; return -EINVAL;
...@@ -1028,8 +1028,8 @@ int uvc_ctrl_set(struct uvc_video_device *video, ...@@ -1028,8 +1028,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
0, ctrl->info->size); 0, ctrl->info->size);
} else { } else {
ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
ctrl->entity->id, video->dev->intfnum, ctrl->entity->id, chain->dev->intfnum,
ctrl->info->selector, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size); ctrl->info->size);
...@@ -1058,7 +1058,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, ...@@ -1058,7 +1058,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
* Dynamic controls * Dynamic controls
*/ */
int uvc_xu_ctrl_query(struct uvc_video_device *video, int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control *xctrl, int set) struct uvc_xu_control *xctrl, int set)
{ {
struct uvc_entity *entity; struct uvc_entity *entity;
...@@ -1068,7 +1068,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, ...@@ -1068,7 +1068,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
int ret; int ret;
/* Find the extension unit. */ /* Find the extension unit. */
list_for_each_entry(entity, &video->extensions, chain) { list_for_each_entry(entity, &chain->extensions, chain) {
if (entity->id == xctrl->unit) if (entity->id == xctrl->unit)
break; break;
} }
...@@ -1107,7 +1107,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, ...@@ -1107,7 +1107,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
(!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR))) (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
return -EINVAL; return -EINVAL;
if (mutex_lock_interruptible(&video->ctrl_mutex)) if (mutex_lock_interruptible(&chain->ctrl_mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
...@@ -1120,8 +1120,8 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, ...@@ -1120,8 +1120,8 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
goto out; goto out;
} }
ret = uvc_query_ctrl(video->dev, set ? UVC_SET_CUR : UVC_GET_CUR, ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
xctrl->unit, video->dev->intfnum, xctrl->selector, xctrl->unit, chain->dev->intfnum, xctrl->selector,
data, xctrl->size); data, xctrl->size);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -1137,7 +1137,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, ...@@ -1137,7 +1137,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
xctrl->size); xctrl->size);
mutex_unlock(&video->ctrl_mutex); mutex_unlock(&chain->ctrl_mutex);
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* table for the controls that can be mapped directly, and handle the others * table for the controls that can be mapped directly, and handle the others
* manually. * manually.
*/ */
static int uvc_v4l2_query_menu(struct uvc_video_device *video, static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu) struct v4l2_querymenu *query_menu)
{ {
struct uvc_menu_info *menu_info; struct uvc_menu_info *menu_info;
...@@ -49,7 +49,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video, ...@@ -49,7 +49,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
u32 index = query_menu->index; u32 index = query_menu->index;
u32 id = query_menu->id; u32 id = query_menu->id;
ctrl = uvc_find_control(video, query_menu->id, &mapping); ctrl = uvc_find_control(chain, query_menu->id, &mapping);
if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
return -EINVAL; return -EINVAL;
...@@ -451,7 +451,7 @@ static int uvc_v4l2_open(struct file *file) ...@@ -451,7 +451,7 @@ static int uvc_v4l2_open(struct file *file)
} }
} }
handle->video = &stream->dev->video; handle->chain = stream->chain;
handle->stream = stream; handle->stream = stream;
handle->state = UVC_HANDLE_PASSIVE; handle->state = UVC_HANDLE_PASSIVE;
file->private_data = handle; file->private_data = handle;
...@@ -498,7 +498,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -498,7 +498,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data; struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
struct uvc_video_device *video = handle->video; struct uvc_video_chain *chain = handle->chain;
struct uvc_streaming *stream = handle->stream; struct uvc_streaming *stream = handle->stream;
long ret = 0; long ret = 0;
...@@ -525,7 +525,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -525,7 +525,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Get, Set & Query control */ /* Get, Set & Query control */
case VIDIOC_QUERYCTRL: case VIDIOC_QUERYCTRL:
return uvc_query_v4l2_ctrl(video, arg); return uvc_query_v4l2_ctrl(chain, arg);
case VIDIOC_G_CTRL: case VIDIOC_G_CTRL:
{ {
...@@ -535,12 +535,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -535,12 +535,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(&xctrl, 0, sizeof xctrl); memset(&xctrl, 0, sizeof xctrl);
xctrl.id = ctrl->id; xctrl.id = ctrl->id;
ret = uvc_ctrl_begin(video); ret = uvc_ctrl_begin(chain);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = uvc_ctrl_get(video, &xctrl); ret = uvc_ctrl_get(chain, &xctrl);
uvc_ctrl_rollback(video); uvc_ctrl_rollback(chain);
if (ret >= 0) if (ret >= 0)
ctrl->value = xctrl.value; ctrl->value = xctrl.value;
break; break;
...@@ -555,21 +555,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -555,21 +555,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
xctrl.id = ctrl->id; xctrl.id = ctrl->id;
xctrl.value = ctrl->value; xctrl.value = ctrl->value;
ret = uvc_ctrl_begin(video); uvc_ctrl_begin(chain);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = uvc_ctrl_set(video, &xctrl); ret = uvc_ctrl_set(chain, &xctrl);
if (ret < 0) { if (ret < 0) {
uvc_ctrl_rollback(video); uvc_ctrl_rollback(chain);
return ret; return ret;
} }
ret = uvc_ctrl_commit(video); ret = uvc_ctrl_commit(chain);
break; break;
} }
case VIDIOC_QUERYMENU: case VIDIOC_QUERYMENU:
return uvc_v4l2_query_menu(video, arg); return uvc_v4l2_query_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS: case VIDIOC_G_EXT_CTRLS:
{ {
...@@ -577,20 +577,20 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -577,20 +577,20 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_ext_control *ctrl = ctrls->controls; struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i; unsigned int i;
ret = uvc_ctrl_begin(video); ret = uvc_ctrl_begin(chain);
if (ret < 0) if (ret < 0)
return ret; return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) { for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_get(video, ctrl); ret = uvc_ctrl_get(chain, ctrl);
if (ret < 0) { if (ret < 0) {
uvc_ctrl_rollback(video); uvc_ctrl_rollback(chain);
ctrls->error_idx = i; ctrls->error_idx = i;
return ret; return ret;
} }
} }
ctrls->error_idx = 0; ctrls->error_idx = 0;
ret = uvc_ctrl_rollback(video); ret = uvc_ctrl_rollback(chain);
break; break;
} }
...@@ -601,14 +601,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -601,14 +601,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_ext_control *ctrl = ctrls->controls; struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i; unsigned int i;
ret = uvc_ctrl_begin(video); ret = uvc_ctrl_begin(chain);
if (ret < 0) if (ret < 0)
return ret; return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) { for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_set(video, ctrl); ret = uvc_ctrl_set(chain, ctrl);
if (ret < 0) { if (ret < 0) {
uvc_ctrl_rollback(video); uvc_ctrl_rollback(chain);
ctrls->error_idx = i; ctrls->error_idx = i;
return ret; return ret;
} }
...@@ -617,31 +617,31 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -617,31 +617,31 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
ctrls->error_idx = 0; ctrls->error_idx = 0;
if (cmd == VIDIOC_S_EXT_CTRLS) if (cmd == VIDIOC_S_EXT_CTRLS)
ret = uvc_ctrl_commit(video); ret = uvc_ctrl_commit(chain);
else else
ret = uvc_ctrl_rollback(video); ret = uvc_ctrl_rollback(chain);
break; break;
} }
/* Get, Set & Enum input */ /* Get, Set & Enum input */
case VIDIOC_ENUMINPUT: case VIDIOC_ENUMINPUT:
{ {
const struct uvc_entity *selector = video->selector; const struct uvc_entity *selector = chain->selector;
struct v4l2_input *input = arg; struct v4l2_input *input = arg;
struct uvc_entity *iterm = NULL; struct uvc_entity *iterm = NULL;
u32 index = input->index; u32 index = input->index;
int pin = 0; int pin = 0;
if (selector == NULL || if (selector == NULL ||
(video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (index != 0) if (index != 0)
return -EINVAL; return -EINVAL;
iterm = list_first_entry(&video->iterms, iterm = list_first_entry(&chain->iterms,
struct uvc_entity, chain); struct uvc_entity, chain);
pin = iterm->id; pin = iterm->id;
} else if (pin < selector->selector.bNrInPins) { } else if (pin < selector->selector.bNrInPins) {
pin = selector->selector.baSourceID[index]; pin = selector->selector.baSourceID[index];
list_for_each_entry(iterm, video->iterms.next, chain) { list_for_each_entry(iterm, chain->iterms.next, chain) {
if (iterm->id == pin) if (iterm->id == pin)
break; break;
} }
...@@ -662,14 +662,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -662,14 +662,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
u8 input; u8 input;
if (video->selector == NULL || if (chain->selector == NULL ||
(video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
*(int *)arg = 0; *(int *)arg = 0;
break; break;
} }
ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
video->selector->id, video->dev->intfnum, chain->selector->id, chain->dev->intfnum,
UVC_SU_INPUT_SELECT_CONTROL, &input, 1); UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -685,18 +685,18 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -685,18 +685,18 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0) if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret; return ret;
if (video->selector == NULL || if (chain->selector == NULL ||
(video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (input != 1) if (input != 1)
return -EINVAL; return -EINVAL;
break; break;
} }
if (input == 0 || input > video->selector->selector.bNrInPins) if (input == 0 || input > chain->selector->selector.bNrInPins)
return -EINVAL; return -EINVAL;
return uvc_query_ctrl(video->dev, UVC_SET_CUR, return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
video->selector->id, video->dev->intfnum, chain->selector->id, chain->dev->intfnum,
UVC_SU_INPUT_SELECT_CONTROL, &input, 1); UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
} }
...@@ -1019,10 +1019,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -1019,10 +1019,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
} }
case UVCIOC_CTRL_GET: case UVCIOC_CTRL_GET:
return uvc_xu_ctrl_query(video, arg, 0); return uvc_xu_ctrl_query(chain, arg, 0);
case UVCIOC_CTRL_SET: case UVCIOC_CTRL_SET:
return uvc_xu_ctrl_query(video, arg, 1); return uvc_xu_ctrl_query(chain, arg, 1);
default: default:
if ((ret = v4l_compat_translate_ioctl(file, cmd, arg, if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
......
...@@ -128,7 +128,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, ...@@ -128,7 +128,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
if ((video->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF)
return -EIO; return -EIO;
ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
......
...@@ -80,9 +80,11 @@ struct uvc_xu_control { ...@@ -80,9 +80,11 @@ struct uvc_xu_control {
#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0) #define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0) #define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
#define UVC_ENTITY_IS_ITERM(entity) \ #define UVC_ENTITY_IS_ITERM(entity) \
(((entity)->type & 0x8000) == UVC_TERM_INPUT) (UVC_ENTITY_IS_TERM(entity) && \
((entity)->type & 0x8000) == UVC_TERM_INPUT)
#define UVC_ENTITY_IS_OTERM(entity) \ #define UVC_ENTITY_IS_OTERM(entity) \
(((entity)->type & 0x8000) == UVC_TERM_OUTPUT) (UVC_ENTITY_IS_TERM(entity) && \
((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
...@@ -402,10 +404,24 @@ struct uvc_video_queue { ...@@ -402,10 +404,24 @@ struct uvc_video_queue {
struct list_head irqqueue; struct list_head irqqueue;
}; };
struct uvc_video_chain {
struct uvc_device *dev;
struct list_head list;
struct list_head iterms; /* Input terminals */
struct list_head oterms; /* Output terminals */
struct uvc_entity *processing; /* Processing unit */
struct uvc_entity *selector; /* Selector unit */
struct list_head extensions; /* Extension units */
struct mutex ctrl_mutex;
};
struct uvc_streaming { struct uvc_streaming {
struct list_head list; struct list_head list;
struct uvc_device *dev; struct uvc_device *dev;
struct video_device *vdev; struct video_device *vdev;
struct uvc_video_chain *chain;
atomic_t active; atomic_t active;
struct usb_interface *intf; struct usb_interface *intf;
...@@ -446,18 +462,6 @@ struct uvc_streaming { ...@@ -446,18 +462,6 @@ struct uvc_streaming {
__u8 last_fid; __u8 last_fid;
}; };
struct uvc_video_device {
struct uvc_device *dev;
struct list_head iterms; /* Input terminals */
struct uvc_entity *oterm; /* Output terminal */
struct uvc_entity *sterm; /* USB streaming terminal */
struct uvc_entity *processing;
struct uvc_entity *selector;
struct list_head extensions;
struct mutex ctrl_mutex;
};
enum uvc_device_state { enum uvc_device_state {
UVC_DEV_DISCONNECTED = 1, UVC_DEV_DISCONNECTED = 1,
}; };
...@@ -480,8 +484,7 @@ struct uvc_device { ...@@ -480,8 +484,7 @@ struct uvc_device {
__u32 clock_frequency; __u32 clock_frequency;
struct list_head entities; struct list_head entities;
struct list_head chains;
struct uvc_video_device video;
/* Video Streaming interfaces */ /* Video Streaming interfaces */
struct list_head streams; struct list_head streams;
...@@ -500,7 +503,7 @@ enum uvc_handle_state { ...@@ -500,7 +503,7 @@ enum uvc_handle_state {
}; };
struct uvc_fh { struct uvc_fh {
struct uvc_video_device *video; struct uvc_video_chain *chain;
struct uvc_streaming *stream; struct uvc_streaming *stream;
enum uvc_handle_state state; enum uvc_handle_state state;
}; };
...@@ -618,9 +621,9 @@ extern int uvc_status_suspend(struct uvc_device *dev); ...@@ -618,9 +621,9 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */ /* Controls */
extern struct uvc_control *uvc_find_control(struct uvc_video_device *video, extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping); __u32 v4l2_id, struct uvc_control_mapping **mapping);
extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video, extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl); struct v4l2_queryctrl *v4l2_ctrl);
extern int uvc_ctrl_add_info(struct uvc_control_info *info); extern int uvc_ctrl_add_info(struct uvc_control_info *info);
...@@ -630,23 +633,23 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); ...@@ -630,23 +633,23 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
extern int uvc_ctrl_resume_device(struct uvc_device *dev); extern int uvc_ctrl_resume_device(struct uvc_device *dev);
extern void uvc_ctrl_init(void); extern void uvc_ctrl_init(void);
extern int uvc_ctrl_begin(struct uvc_video_device *video); extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback); extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
static inline int uvc_ctrl_commit(struct uvc_video_device *video) static inline int uvc_ctrl_commit(struct uvc_video_chain *chain)
{ {
return __uvc_ctrl_commit(video, 0); return __uvc_ctrl_commit(chain, 0);
} }
static inline int uvc_ctrl_rollback(struct uvc_video_device *video) static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain)
{ {
return __uvc_ctrl_commit(video, 1); return __uvc_ctrl_commit(chain, 1);
} }
extern int uvc_ctrl_get(struct uvc_video_device *video, extern int uvc_ctrl_get(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl); struct v4l2_ext_control *xctrl);
extern int uvc_ctrl_set(struct uvc_video_device *video, extern int uvc_ctrl_set(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl); struct v4l2_ext_control *xctrl);
extern int uvc_xu_ctrl_query(struct uvc_video_device *video, extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control *ctrl, int set); struct uvc_xu_control *ctrl, int set);
/* Utility functions */ /* Utility functions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment