blob: 495467a0dcaea1a065d35f741d99215bd364da21 [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"
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070031#include "V4L2Gralloc.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070032
33namespace v4l2_camera_hal {
34
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070035V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
36 HAL_LOG_ENTER();
37
38 std::unique_ptr<V4L2Gralloc> gralloc(V4L2Gralloc::NewV4L2Gralloc());
39 if (!gralloc) {
40 HAL_LOGE("Failed to initialize gralloc helper.");
41 return nullptr;
42 }
43
44 return new V4L2Wrapper(device_path, std::move(gralloc));
45}
46
47V4L2Wrapper::V4L2Wrapper(const std::string device_path,
48 std::unique_ptr<V4L2Gralloc> gralloc)
49 : device_path_(device_path), gralloc_(std::move(gralloc)), max_buffers_(0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070050 HAL_LOG_ENTER();
51}
52
53V4L2Wrapper::~V4L2Wrapper() { HAL_LOG_ENTER(); }
54
55int V4L2Wrapper::Connect() {
56 HAL_LOG_ENTER();
57 std::lock_guard<std::mutex> lock(device_lock_);
58
59 if (connected()) {
60 HAL_LOGE("Camera device %s is already connected. Close it first",
61 device_path_.c_str());
62 return -EIO;
63 }
64
65 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR));
66 if (fd < 0) {
67 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
68 return -errno;
69 }
70 device_fd_.reset(fd);
71
72 // Check if this connection has the extended control query capability.
73 v4l2_query_ext_ctrl query;
74 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070075 // Already holding the lock, so don't call IoctlLocked.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070076 int res = TEMP_FAILURE_RETRY(
77 ioctl(device_fd_.get(), VIDIOC_QUERY_EXT_CTRL, &query));
78 extended_query_supported_ = (res == 0);
79
80 // TODO(b/29185945): confirm this is a supported device.
81 // This is checked by the HAL, but the device at device_path_ may
82 // not be the same one that was there when the HAL was loaded.
83 // (Alternatively, better hotplugging support may make this unecessary
84 // by disabling cameras that get disconnected and checking newly connected
85 // cameras, so Connect() is never called on an unsupported camera)
86 return 0;
87}
88
89void V4L2Wrapper::Disconnect() {
90 HAL_LOG_ENTER();
91 std::lock_guard<std::mutex> lock(device_lock_);
92
93 device_fd_.reset(); // Includes close().
94 format_.reset();
95 max_buffers_ = 0;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070096 // Closing the device releases all queued buffers back to the user.
97 gralloc_->unlockAllBuffers();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070098}
99
100// Helper function. Should be used instead of ioctl throughout this class.
101template <typename T>
102int V4L2Wrapper::IoctlLocked(int request, T data) {
103 HAL_LOG_ENTER();
104 std::lock_guard<std::mutex> lock(device_lock_);
105
106 if (!connected()) {
107 HAL_LOGE("Device %s not connected.", device_path_.c_str());
108 return -ENODEV;
109 }
110 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
111}
112
113int V4L2Wrapper::StreamOn() {
114 HAL_LOG_ENTER();
115
116 if (!format_) {
117 HAL_LOGE("Stream format must be set before turning on stream.");
118 return -EINVAL;
119 }
120
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700121 int32_t type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700122 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
123 HAL_LOGE("STREAMON fails: %s", strerror(errno));
124 return -ENODEV;
125 }
126
127 return 0;
128}
129
130int V4L2Wrapper::StreamOff() {
131 HAL_LOG_ENTER();
132
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700133 int32_t type = format_->type();
134 int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
135 // Calling STREAMOFF releases all queued buffers back to the user.
136 int gralloc_res = gralloc_->unlockAllBuffers();
137 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700138 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
139 return -ENODEV;
140 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700141 if (gralloc_res < 0) {
142 HAL_LOGE("Failed to unlock all buffers after turning stream off.");
143 return gralloc_res;
144 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700145
146 return 0;
147}
148
149int V4L2Wrapper::QueryControl(uint32_t control_id,
150 v4l2_query_ext_ctrl* result) {
151 HAL_LOG_ENTER();
152 int res;
153
154 memset(result, 0, sizeof(*result));
155
156 if (extended_query_supported_) {
157 result->id = control_id;
158 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
159 // Assuming the operation was supported (not ENOTTY), no more to do.
160 if (errno != ENOTTY) {
161 if (res) {
162 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
163 return -ENODEV;
164 }
165 return 0;
166 }
167 }
168
169 // Extended control querying not supported, fall back to basic control query.
170 v4l2_queryctrl query;
171 query.id = control_id;
172 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
173 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
174 return -ENODEV;
175 }
176
177 // Convert the basic result to the extended result.
178 result->id = query.id;
179 result->type = query.type;
180 memcpy(result->name, query.name, sizeof(query.name));
181 result->minimum = query.minimum;
182 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
183 // According to the V4L2 documentation, when type is BITMASK,
184 // max and default should be interpreted as __u32. Practically,
185 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
186 result->maximum = static_cast<uint32_t>(query.maximum);
187 result->default_value = static_cast<uint32_t>(query.default_value);
188 } else {
189 result->maximum = query.maximum;
190 result->default_value = query.default_value;
191 }
192 result->step = static_cast<uint32_t>(query.step);
193 result->flags = query.flags;
194 result->elems = 1;
195 switch (result->type) {
196 case V4L2_CTRL_TYPE_INTEGER64:
197 result->elem_size = sizeof(int64_t);
198 break;
199 case V4L2_CTRL_TYPE_STRING:
200 result->elem_size = result->maximum + 1;
201 break;
202 default:
203 result->elem_size = sizeof(int32_t);
204 break;
205 }
206
207 return 0;
208}
209
210int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
211 HAL_LOG_ENTER();
212
213 v4l2_control control;
214 control.id = control_id;
215 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
216 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
217 return -ENODEV;
218 }
219 *value = control.value;
220 return 0;
221}
222
223int V4L2Wrapper::SetControl(uint32_t control_id, int32_t desired,
224 int32_t* result) {
225 HAL_LOG_ENTER();
226
227 v4l2_control control{control_id, desired};
228 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
229 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
230 return -ENODEV;
231 }
232 *result = control.value;
233 return 0;
234}
235
236int V4L2Wrapper::SetFormat(const default_camera_hal::Stream& stream) {
237 HAL_LOG_ENTER();
238
239 // Should be checked earlier; sanity check.
240 if (stream.isInputType()) {
241 HAL_LOGE("Input streams not supported.");
242 return -EINVAL;
243 }
244
245 StreamFormat desired_format(stream);
246 if (desired_format == *format_) {
247 HAL_LOGV("Already in correct format, skipping format setting.");
248 return 0;
249 }
250
251 // Not in the correct format, set our format.
252 v4l2_format new_format;
253 desired_format.FillFormatRequest(&new_format);
254 // TODO(b/29334616): When async, this will need to check if the stream
255 // is on, and if so, lock it off while setting format.
256 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
257 HAL_LOGE("S_FMT failed: %s", strerror(errno));
258 return -ENODEV;
259 }
260
261 // Check that the driver actually set to the requested values.
262 if (desired_format != new_format) {
263 HAL_LOGE("Device doesn't support desired stream configuration.");
264 return -EINVAL;
265 }
266
267 // Keep track of our new format.
268 format_.reset(new StreamFormat(new_format));
269
270 // Format changed, setup new buffers.
271 SetupBuffers();
272 return 0;
273}
274
275int V4L2Wrapper::SetupBuffers() {
276 HAL_LOG_ENTER();
277
278 // "Request" a buffer (since we're using a userspace buffer, this just
279 // tells V4L2 to switch into userspace buffer mode).
280 v4l2_requestbuffers req_buffers;
281 memset(&req_buffers, 0, sizeof(req_buffers));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700282 req_buffers.type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700283 req_buffers.memory = V4L2_MEMORY_USERPTR;
284 req_buffers.count = 1;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700285
286 int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
287 // Calling REQBUFS releases all queued buffers back to the user.
288 int gralloc_res = gralloc_->unlockAllBuffers();
289 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700290 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
291 return -ENODEV;
292 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700293 if (gralloc_res < 0) {
294 HAL_LOGE("Failed to unlock all buffers when setting up new buffers.");
295 return gralloc_res;
296 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700297
298 // V4L2 will set req_buffers.count to a number of buffers it can handle.
299 max_buffers_ = req_buffers.count;
300 return 0;
301}
302
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700303int V4L2Wrapper::EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
304 HAL_LOG_ENTER();
305
306 // Set up a v4l2 buffer struct.
307 v4l2_buffer device_buffer;
308 memset(&device_buffer, 0, sizeof(device_buffer));
309 device_buffer.type = format_->type();
310
311 // Use QUERYBUF to ensure our buffer/device is in good shape.
312 if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
313 HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
314 return -ENODEV;
315 }
316
317 // Configure the device buffer based on the stream buffer.
318 device_buffer.memory = V4L2_MEMORY_USERPTR;
319 // TODO(b/29334616): when this is async, actually limit the number
320 // of buffers used to the known max, and set this according to the
321 // queue length.
322 device_buffer.index = 0;
323 // Lock the buffer for writing.
324 int res =
325 gralloc_->lock(camera_buffer, format_->bytes_per_line(), &device_buffer);
326 if (res) {
327 HAL_LOGE("Gralloc failed to lock buffer.");
328 return res;
329 }
330 if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
331 HAL_LOGE("QBUF (%d) fails: %s", 0, strerror(errno));
332 gralloc_->unlock(&device_buffer);
333 return -ENODEV;
334 }
335
336 return 0;
337}
338
339int V4L2Wrapper::DequeueBuffer(v4l2_buffer* buffer) {
340 HAL_LOG_ENTER();
341
342 memset(buffer, 0, sizeof(*buffer));
343 buffer->type = format_->type();
344 buffer->memory = V4L2_MEMORY_USERPTR;
345 if (IoctlLocked(VIDIOC_DQBUF, buffer) < 0) {
346 HAL_LOGE("DQBUF fails: %s", strerror(errno));
347 return -ENODEV;
348 }
349
350 // Now that we're done painting the buffer, we can unlock it.
351 int res = gralloc_->unlock(buffer);
352 if (res) {
353 return res;
354 }
355
356 return 0;
357}
358
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700359} // namespace v4l2_camera_hal