V4L2 - Custom Subdev IOCTLs
Overview
Custom IOCTLs can be added to a subdevice, this document show you how.
Create IOCTLs
In order to add a custom IOCTL on the subdevice you need the following:
- Define your custom ioctls
- Create you ioctl method handling, it be called when you call those defined IOCTLs
- Assign ioctl on Subdev-Core-Ops callbacks.
Check the example below:
#define D43X_VIDIOC_SET_VAL _IOWR('V', BASE_VIDIOC_PRIVATE, unsigned int)
#define D43X_VIDIOC_SHIFT_VAL _IOWR('V', BASE_VIDIOC_PRIVATE + 1, unsigned int)
static long d43x_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int *val;
switch (cmd) {
case D43X_VIDIOC_SET_VAL:
val = arg;
dev_info(&client->dev, "%s: custom ioctl 1, value=%d\n", __func__, *val);
break;
case D43X_VIDIOC_SHIFT_VAL:
val = arg;
dev_info(&client->dev, "%s: custom ioctl 2, value=%d\n", __func__, *val);
*val = *val << 1;
arg = val;
break;
default:
dev_err(&client->dev, "Wrong IOCTL cmd\n");
break;
}
return 0;
}
static const struct v4l2_subdev_core_ops d43x_core_ops = {
.ioctl = d43x_ioctl,
};
Test IOCTLs
IOCTLs can be called either from KERNEL or user spaces.
KERNEL
IOCTL can be trigger using v4l2_subdev_call(), check example below:
unsigned int val = 2;
ret = v4l2_subdev_call(sd, core, ioctl,
D43X_VIDIOC_SET_VALUE,
&val);
if (ret)
return ret;
pr_info ("Value: %d\n", val)
ret = v4l2_subdev_call(sd, core, ioctl,
D43X_VIDIOC_SHIFT_VALUE,
&val);
if (ret)
return ret;
pr_info ("Value: %d\n", val)
Userspace
From the user application side, those IOCTLs can be triggered by calling ioctl() after opening the specific subdevice. Check example below:
#include <linux/ioctl.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/videodev2.h>
#define D43X_VIDIOC_SET_VALUE _IOWR('V', BASE_VIDIOC_PRIVATE, unsigned int)
#define D43X_VIDIOC_SHIFT_VALUE _IOWR('V', BASE_VIDIOC_PRIVATE + 1, unsigned int)
int main ( ) {
int fd;
int ret;
unsigned int val = 2;
printf("IOCTL Debug test\n");
/* Open Device */
fd = open("/dev/v4l-subdev0", O_RDWR);
if (fd == -1) {
printf("Error in opening file\n");
exit(-1);
}
/* Test custom IOCTL set value */
if (ioctl(fd, D43X_VIDIOC_SET_VALUE, (unsigned int *) &val) < 0) {
perror("custom ioctl error");
return 1;
}
printf("Value = %d\n", val);
/* Test custom IOCTL shift value */
if (ioctl(fd, D43X_VIDIOC_SHIFT_VALUE, (unsigned int *) &val) < 0) {
perror("custom ioctl error");
return 1;
}
printf("Value = %d\n", val);
printf("---> End of test\n");
close(fd);
return 0;
}