return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
}
+static struct device_attribute video_device_attrs[] = {
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR(index, S_IRUGO, show_index, NULL),
+ __ATTR_NULL
+};
+
struct video_device *video_device_alloc(void)
{
struct video_device *vfd;
vfd->release(vfd);
}
-static struct device_attribute video_device_attrs[] = {
- __ATTR(name, S_IRUGO, show_name, NULL),
- __ATTR(index, S_IRUGO, show_index, NULL),
- __ATTR_NULL
-};
-
static struct class video_class = {
.name = VIDEO_NAME,
.dev_attrs = video_device_attrs,
printk(KERN_CONT "\n");
};
-static inline int check_ext_ctrls(struct v4l2_ext_controls *c)
+static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
{
__u32 i;
c->controls[i].reserved2[1] = 0;
}
/* V4L2_CID_PRIVATE_BASE cannot be used as control class
- * when using extended controls. */
- if (c->ctrl_class == V4L2_CID_PRIVATE_BASE)
+ when using extended controls.
+ Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
+ is it allowed for backwards compatibility.
+ */
+ if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)
return 0;
/* Check that all controls are from the same control class. */
for (i = 0; i < c->count; i++) {
ctrls.controls = &ctrl;
ctrl.id = p->id;
ctrl.value = p->value;
- if (check_ext_ctrls(&ctrls)) {
+ if (check_ext_ctrls(&ctrls, 1)) {
ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls);
if (ret == 0)
p->value = ctrl.value;
ctrls.controls = &ctrl;
ctrl.id = p->id;
ctrl.value = p->value;
- if (check_ext_ctrls(&ctrls))
+ if (check_ext_ctrls(&ctrls, 1))
ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls);
break;
}
p->error_idx = p->count;
if (!vfd->vidioc_g_ext_ctrls)
break;
- if (check_ext_ctrls(p))
+ if (check_ext_ctrls(p, 0))
ret = vfd->vidioc_g_ext_ctrls(file, fh, p);
v4l_print_ext_ctrls(cmd, vfd, p, !ret);
break;
if (!vfd->vidioc_s_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
- if (check_ext_ctrls(p))
+ if (check_ext_ctrls(p, 0))
ret = vfd->vidioc_s_ext_ctrls(file, fh, p);
break;
}
if (!vfd->vidioc_try_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
- if (check_ext_ctrls(p))
+ if (check_ext_ctrls(p, 0))
ret = vfd->vidioc_try_ext_ctrls(file, fh, p);
break;
}
}
EXPORT_SYMBOL(video_ioctl2);
-struct index_info {
- struct device *dev;
- unsigned int used[VIDEO_NUM_DEVICES];
-};
-
-static int __fill_index_info(struct device *cd, void *data)
-{
- struct index_info *info = data;
- struct video_device *vfd = container_of(cd, struct video_device,
- class_dev);
-
- if (info->dev == vfd->dev)
- info->used[vfd->index] = 1;
-
- return 0;
-}
-
/**
- * assign_index - assign stream number based on parent device
+ * get_index - assign stream number based on parent device
* @vdev: video_device to assign index number to, vdev->dev should be assigned
* @num: -1 if auto assign, requested number otherwise
*
*/
static int get_index(struct video_device *vdev, int num)
{
- struct index_info *info;
+ u32 used = 0;
+ const int max_index = sizeof(used) * 8 - 1;
int i;
- int ret = 0;
- if (num >= VIDEO_NUM_DEVICES)
+ /* Currently a single v4l driver instance cannot create more than
+ 32 devices.
+ Increase to u64 or an array of u32 if more are needed. */
+ if (num > max_index) {
+ printk(KERN_ERR "videodev: %s num is too large\n", __func__);
return -EINVAL;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->dev = vdev->dev;
-
- ret = class_for_each_device(&video_class, info,
- __fill_index_info);
-
- if (ret < 0)
- goto out;
-
- if (num >= 0) {
- if (!info->used[num])
- ret = num;
- else
- ret = -ENFILE;
-
- goto out;
}
for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
- if (info->used[i])
- continue;
- ret = i;
- goto out;
+ if (video_device[i] != NULL &&
+ video_device[i] != vdev &&
+ video_device[i]->dev == vdev->dev) {
+ used |= 1 << video_device[i]->index;
+ }
}
-out:
- kfree(info);
- return ret;
+ if (num >= 0) {
+ if (used & (1 << num))
+ return -ENFILE;
+ return num;
+ }
+
+ i = ffz(used);
+ return i > max_index ? -ENFILE : i;
}
static const struct file_operations video_fops;
vfd->minor=i;
ret = get_index(vfd, index);
+ vfd->index = ret;
+
+ mutex_unlock(&videodev_lock);
+
if (ret < 0) {
- printk(KERN_ERR "%s: get_index failed\n",
- __func__);
+ printk(KERN_ERR "%s: get_index failed\n", __func__);
goto fail_minor;
}
- vfd->index = ret;
-
- mutex_unlock(&videodev_lock);
mutex_init(&vfd->lock);
/* sysfs class */
memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
- if (vfd->dev)
- vfd->class_dev.parent = vfd->dev;
vfd->class_dev.class = &video_class;
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
+ if (vfd->dev)
+ vfd->class_dev.parent = vfd->dev;
sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
ret = device_register(&vfd->class_dev);
if (ret < 0) {
- printk(KERN_ERR "%s: device_register failed\n",
- __func__);
+ printk(KERN_ERR "%s: device_register failed\n", __func__);
goto fail_minor;
}