blob: fdcd1790f63e4fa1b7893d00c632c0213ca2a5fe [file] [log] [blame]
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -07001/*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "V4L2Wrapper.h"
18
19#include <fcntl.h>
20#include <linux/videodev2.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23
24#include <mutex>
25
26#include <nativehelper/ScopedFd.h>
27
28#include "Common.h"
29#include "Stream.h"
30#include "StreamFormat.h"
31
32namespace v4l2_camera_hal {
33
34V4L2Wrapper::V4L2Wrapper(const std::string device_path)
35 : device_path_(device_path), max_buffers_(0) {
36 HAL_LOG_ENTER();
37}
38
39V4L2Wrapper::~V4L2Wrapper() { HAL_LOG_ENTER(); }
40
41int V4L2Wrapper::Connect() {
42 HAL_LOG_ENTER();
43 std::lock_guard<std::mutex> lock(device_lock_);
44
45 if (connected()) {
46 HAL_LOGE("Camera device %s is already connected. Close it first",
47 device_path_.c_str());
48 return -EIO;
49 }
50
51 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR));
52 if (fd < 0) {
53 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
54 return -errno;
55 }
56 device_fd_.reset(fd);
57
58 // Check if this connection has the extended control query capability.
59 v4l2_query_ext_ctrl query;
60 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
61 // Already holding the lock, so don't call ioctlLocked.
62 int res = TEMP_FAILURE_RETRY(
63 ioctl(device_fd_.get(), VIDIOC_QUERY_EXT_CTRL, &query));
64 extended_query_supported_ = (res == 0);
65
66 // TODO(b/29185945): confirm this is a supported device.
67 // This is checked by the HAL, but the device at device_path_ may
68 // not be the same one that was there when the HAL was loaded.
69 // (Alternatively, better hotplugging support may make this unecessary
70 // by disabling cameras that get disconnected and checking newly connected
71 // cameras, so Connect() is never called on an unsupported camera)
72 return 0;
73}
74
75void V4L2Wrapper::Disconnect() {
76 HAL_LOG_ENTER();
77 std::lock_guard<std::mutex> lock(device_lock_);
78
79 device_fd_.reset(); // Includes close().
80 format_.reset();
81 max_buffers_ = 0;
82}
83
84// Helper function. Should be used instead of ioctl throughout this class.
85template <typename T>
86int V4L2Wrapper::IoctlLocked(int request, T data) {
87 HAL_LOG_ENTER();
88 std::lock_guard<std::mutex> lock(device_lock_);
89
90 if (!connected()) {
91 HAL_LOGE("Device %s not connected.", device_path_.c_str());
92 return -ENODEV;
93 }
94 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
95}
96
97int V4L2Wrapper::StreamOn() {
98 HAL_LOG_ENTER();
99
100 if (!format_) {
101 HAL_LOGE("Stream format must be set before turning on stream.");
102 return -EINVAL;
103 }
104
105 int32_t type = format_->get_type();
106 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
107 HAL_LOGE("STREAMON fails: %s", strerror(errno));
108 return -ENODEV;
109 }
110
111 return 0;
112}
113
114int V4L2Wrapper::StreamOff() {
115 HAL_LOG_ENTER();
116
117 int32_t type = format_->get_type();
118 if (IoctlLocked(VIDIOC_STREAMOFF, &type) < 0) {
119 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
120 return -ENODEV;
121 }
122
123 return 0;
124}
125
126int V4L2Wrapper::QueryControl(uint32_t control_id,
127 v4l2_query_ext_ctrl* result) {
128 HAL_LOG_ENTER();
129 int res;
130
131 memset(result, 0, sizeof(*result));
132
133 if (extended_query_supported_) {
134 result->id = control_id;
135 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
136 // Assuming the operation was supported (not ENOTTY), no more to do.
137 if (errno != ENOTTY) {
138 if (res) {
139 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
140 return -ENODEV;
141 }
142 return 0;
143 }
144 }
145
146 // Extended control querying not supported, fall back to basic control query.
147 v4l2_queryctrl query;
148 query.id = control_id;
149 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
150 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
151 return -ENODEV;
152 }
153
154 // Convert the basic result to the extended result.
155 result->id = query.id;
156 result->type = query.type;
157 memcpy(result->name, query.name, sizeof(query.name));
158 result->minimum = query.minimum;
159 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
160 // According to the V4L2 documentation, when type is BITMASK,
161 // max and default should be interpreted as __u32. Practically,
162 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
163 result->maximum = static_cast<uint32_t>(query.maximum);
164 result->default_value = static_cast<uint32_t>(query.default_value);
165 } else {
166 result->maximum = query.maximum;
167 result->default_value = query.default_value;
168 }
169 result->step = static_cast<uint32_t>(query.step);
170 result->flags = query.flags;
171 result->elems = 1;
172 switch (result->type) {
173 case V4L2_CTRL_TYPE_INTEGER64:
174 result->elem_size = sizeof(int64_t);
175 break;
176 case V4L2_CTRL_TYPE_STRING:
177 result->elem_size = result->maximum + 1;
178 break;
179 default:
180 result->elem_size = sizeof(int32_t);
181 break;
182 }
183
184 return 0;
185}
186
187int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
188 HAL_LOG_ENTER();
189
190 v4l2_control control;
191 control.id = control_id;
192 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
193 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
194 return -ENODEV;
195 }
196 *value = control.value;
197 return 0;
198}
199
200int V4L2Wrapper::SetControl(uint32_t control_id, int32_t desired,
201 int32_t* result) {
202 HAL_LOG_ENTER();
203
204 v4l2_control control{control_id, desired};
205 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
206 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
207 return -ENODEV;
208 }
209 *result = control.value;
210 return 0;
211}
212
213int V4L2Wrapper::SetFormat(const default_camera_hal::Stream& stream) {
214 HAL_LOG_ENTER();
215
216 // Should be checked earlier; sanity check.
217 if (stream.isInputType()) {
218 HAL_LOGE("Input streams not supported.");
219 return -EINVAL;
220 }
221
222 StreamFormat desired_format(stream);
223 if (desired_format == *format_) {
224 HAL_LOGV("Already in correct format, skipping format setting.");
225 return 0;
226 }
227
228 // Not in the correct format, set our format.
229 v4l2_format new_format;
230 desired_format.FillFormatRequest(&new_format);
231 // TODO(b/29334616): When async, this will need to check if the stream
232 // is on, and if so, lock it off while setting format.
233 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
234 HAL_LOGE("S_FMT failed: %s", strerror(errno));
235 return -ENODEV;
236 }
237
238 // Check that the driver actually set to the requested values.
239 if (desired_format != new_format) {
240 HAL_LOGE("Device doesn't support desired stream configuration.");
241 return -EINVAL;
242 }
243
244 // Keep track of our new format.
245 format_.reset(new StreamFormat(new_format));
246
247 // Format changed, setup new buffers.
248 SetupBuffers();
249 return 0;
250}
251
252int V4L2Wrapper::SetupBuffers() {
253 HAL_LOG_ENTER();
254
255 // "Request" a buffer (since we're using a userspace buffer, this just
256 // tells V4L2 to switch into userspace buffer mode).
257 v4l2_requestbuffers req_buffers;
258 memset(&req_buffers, 0, sizeof(req_buffers));
259 req_buffers.type = format_->get_type();
260 req_buffers.memory = V4L2_MEMORY_USERPTR;
261 req_buffers.count = 1;
262 if (IoctlLocked(VIDIOC_REQBUFS, &req_buffers) < 0) {
263 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
264 return -ENODEV;
265 }
266
267 // V4L2 will set req_buffers.count to a number of buffers it can handle.
268 max_buffers_ = req_buffers.count;
269 return 0;
270}
271
272} // namespace v4l2_camera_hal