V4L2 subdev frame interval support
[media-ctl.git] / subdev.c
1 /*
2  * Media controller test application
3  *
4  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  */
19
20 #include <sys/ioctl.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <linux/v4l2-subdev.h>
31
32 #include "media.h"
33 #include "subdev.h"
34 #include "tools.h"
35
36 static struct {
37         const char *name;
38         enum v4l2_mbus_pixelcode code;
39 } mbus_formats[] = {
40         { "YUYV", V4L2_MBUS_FMT_YUYV16_1X16 },
41         { "UYVY", V4L2_MBUS_FMT_UYVY16_1X16 },
42         { "SGRBG10", V4L2_MBUS_FMT_SGRBG10_1X10 },
43         { "SGRBG10_DPCM8", V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 },
44 };
45
46 const char *pixelcode_to_string(enum v4l2_mbus_pixelcode code)
47 {
48         unsigned int i;
49
50         for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
51                 if (mbus_formats[i].code == code)
52                         return mbus_formats[i].name;
53         }
54
55         return "unknown";
56 }
57
58 enum v4l2_mbus_pixelcode string_to_pixelcode(const char *string,
59                                              unsigned int length)
60 {
61         unsigned int i;
62
63         for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
64                 if (strncmp(mbus_formats[i].name, string, length) == 0)
65                         break;
66         }
67
68         if (i == ARRAY_SIZE(mbus_formats))
69                 return (enum v4l2_mbus_pixelcode)-1;
70
71         return mbus_formats[i].code;
72 }
73
74 static int v4l2_subdev_open(struct media_entity *entity)
75 {
76         if (entity->fd != -1)
77                 return 0;
78
79         entity->fd = open(entity->devname, O_RDWR);
80         if (entity->fd == -1) {
81                 printf("%s: Failed to open subdev device node %s\n", __func__,
82                         entity->devname);
83                 return -errno;
84         }
85
86         return 0;
87 }
88
89 int v4l2_subdev_get_format(struct media_entity *entity,
90         struct v4l2_mbus_framefmt *format, unsigned int pad,
91         enum v4l2_subdev_format which)
92 {
93         struct v4l2_subdev_pad_format fmt;
94         int ret;
95
96         ret = v4l2_subdev_open(entity);
97         if (ret < 0)
98                 return ret;
99
100         memset(&fmt, 0, sizeof(fmt));
101         fmt.pad = pad;
102         fmt.which = which;
103
104         ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
105         if (ret < 0)
106                 return -errno;
107
108         *format = fmt.format;
109         return 0;
110 }
111
112 int v4l2_subdev_set_format(struct media_entity *entity,
113         struct v4l2_mbus_framefmt *format, unsigned int pad,
114         enum v4l2_subdev_format which)
115 {
116         struct v4l2_subdev_pad_format fmt;
117         int ret;
118
119         ret = v4l2_subdev_open(entity);
120         if (ret < 0)
121                 return ret;
122
123         memset(&fmt, 0, sizeof(fmt));
124         fmt.pad = pad;
125         fmt.which = which;
126         fmt.format = *format;
127
128         ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
129         if (ret < 0)
130                 return -errno;
131
132         *format = fmt.format;
133         return 0;
134 }
135
136 int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
137                          unsigned int pad, enum v4l2_subdev_format which)
138 {
139         struct v4l2_subdev_pad_crop crop;
140         int ret;
141
142         ret = v4l2_subdev_open(entity);
143         if (ret < 0)
144                 return ret;
145
146         memset(&crop, 0, sizeof(crop));
147         crop.pad = pad;
148         crop.which = which;
149
150         ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &crop);
151         if (ret < 0)
152                 return -errno;
153
154         *rect = crop.rect;
155         return 0;
156 }
157
158 int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
159                          unsigned int pad, enum v4l2_subdev_format which)
160 {
161         struct v4l2_subdev_pad_crop crop;
162         int ret;
163
164         ret = v4l2_subdev_open(entity);
165         if (ret < 0)
166                 return ret;
167
168         memset(&crop, 0, sizeof(crop));
169         crop.pad = pad;
170         crop.which = which;
171         crop.rect = *rect;
172
173         ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &crop);
174         if (ret < 0)
175                 return -errno;
176
177         *rect = crop.rect;
178         return 0;
179 }
180
181 int v4l2_subdev_set_frame_interval(struct media_entity *entity,
182                                    struct v4l2_fract *interval)
183 {
184         struct v4l2_subdev_frame_interval ival;
185         int ret;
186
187         ret = v4l2_subdev_open(entity);
188         if (ret < 0)
189                 return ret;
190
191         memset(&ival, 0, sizeof(ival));
192         ival.interval = *interval;
193
194         ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
195         if (ret < 0)
196                 return -errno;
197
198         *interval = ival.interval;
199         return 0;
200 }