Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 219320
b: refs/heads/master
c: 52c58ad
h: refs/heads/master
v: v3
  • Loading branch information
Laurent Pinchart authored and Mauro Carvalho Chehab committed Oct 21, 2010
1 parent 144c954 commit c65be9b
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 88 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 071c8bb827c80a68510a1cdb7e8bebbda1a494d6
refs/heads/master: 52c58ad6f95ff60343bf0c517182d5f649ca0403
194 changes: 107 additions & 87 deletions trunk/drivers/media/video/uvc/uvc_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,90 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
* Dynamic controls
*/

/*
* Query control information (size and flags) for XU controls.
*/
static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
const struct uvc_control *ctrl, struct uvc_control_info *info)
{
u8 *data;
int ret;

data = kmalloc(2, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;

memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
sizeof(info->entity));
info->index = ctrl->index;
info->selector = ctrl->index + 1;

/* Query and verify the control length (GET_LEN) */
ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
info->selector, data, 2);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
"GET_LEN failed on control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
goto done;
}

info->size = le16_to_cpup((__le16 *)data);

/* Query the control information (GET_INFO) */
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
info->selector, data, 1);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
"GET_INFO failed on control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
goto done;
}

info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
| UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
| (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
UVC_CONTROL_AUTO_UPDATE : 0);

uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
"flags { get %u set %u auto %u }.\n",
info->entity, info->selector, info->size,
(info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
(info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
(info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);

done:
kfree(data);
return ret;
}

static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
const struct uvc_control_info *info);

static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
struct uvc_control *ctrl)
{
struct uvc_control_info info;
int ret;

if (ctrl->initialized)
return 0;

ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info);
if (ret < 0)
return ret;

ret = uvc_ctrl_add_info(dev, ctrl, &info);
if (ret < 0)
uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize control "
"%pUl/%u on device %s entity %u\n", info.entity,
info.selector, dev->udev->devpath, ctrl->entity->id);

return ret;
}

int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control *xctrl, int set)
{
Expand All @@ -1186,13 +1270,10 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
return -EINVAL;
}

/* Find the control. */
/* Find the control and perform delayed initialization if needed. */
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
if (!ctrl->initialized)
continue;

if (ctrl->info.selector == xctrl->selector) {
if (ctrl->index == xctrl->selector - 1) {
found = 1;
break;
}
Expand All @@ -1204,6 +1285,10 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
return -EINVAL;
}

ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl);
if (ret < 0)
return -ENOENT;

/* Validate control data size. */
if (ctrl->info.size != xctrl->size)
return -EINVAL;
Expand Down Expand Up @@ -1294,65 +1379,6 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
* Control and mapping handling
*/

/*
* Query control information (size and flags) for XU controls.
*/
static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
const struct uvc_control *ctrl, struct uvc_control_info *info)
{
u8 *data;
int ret;

data = kmalloc(2, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;

memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
sizeof(info->entity));
info->index = ctrl->index;
info->selector = ctrl->index + 1;

/* Query and verify the control length (GET_LEN) */
ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
info->selector, data, 2);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
"GET_LEN failed on control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
goto done;
}

info->size = le16_to_cpup((__le16 *)data);

/* Query the control information (GET_INFO) */
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
info->selector, data, 1);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
"GET_INFO failed on control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
goto done;
}

info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
| UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
| (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
UVC_CONTROL_AUTO_UPDATE : 0);

uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
"flags { get %u set %u auto %u }.\n",
info->entity, info->selector, info->size,
(info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
(info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
(info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);

done:
kfree(data);
return ret;
}

/*
* Add control information to a given control.
*/
Expand Down Expand Up @@ -1434,7 +1460,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,

if (mapping->id & ~V4L2_CTRL_ID_MASK) {
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', control "
"control id 0x%08x is invalid.\n", mapping->name,
"id 0x%08x is invalid.\n", mapping->name,
mapping->id);
return -EINVAL;
}
Expand All @@ -1443,13 +1469,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
list_for_each_entry(entity, &dev->entities, list) {
unsigned int i;

if (!uvc_entity_match_guid(entity, mapping->entity))
if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
!uvc_entity_match_guid(entity, mapping->entity))
continue;

for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
if (ctrl->initialized &&
ctrl->info.selector == mapping->selector) {
if (ctrl->index == mapping->selector - 1) {
found = 1;
break;
}
Expand All @@ -1464,6 +1490,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
if (mutex_lock_interruptible(&chain->ctrl_mutex))
return -ERESTARTSYS;

/* Perform delayed initialization of XU controls */
ret = uvc_ctrl_init_xu_ctrl(dev, ctrl);
if (ret < 0) {
ret = -ENOENT;
goto done;
}

list_for_each_entry(map, &ctrl->info.mappings, list) {
if (mapping->id == map->id) {
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
Expand Down Expand Up @@ -1567,26 +1600,13 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
const struct uvc_control_mapping *mend =
mapping + ARRAY_SIZE(uvc_ctrl_mappings);

/* Query XU controls for control information */
if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) {
struct uvc_control_info info;
int ret;

ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info);
if (ret < 0)
return;

ret = uvc_ctrl_add_info(dev, ctrl, &info);
if (ret < 0) {
/* Skip the control */
uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize "
"control %pUl/%u on device %s entity %u\n",
info.entity, info.selector, dev->udev->devpath,
ctrl->entity->id);
memset(ctrl, 0, sizeof(*ctrl));
}
/* XU controls initialization requires querying the device for control
* information. As some buggy UVC devices will crash when queried
* repeatedly in a tight loop, delay XU controls initialization until
* first use.
*/
if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT)
return;
}

for (; info < iend; ++info) {
if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
Expand Down

0 comments on commit c65be9b

Please sign in to comment.