blob: d331a777be5c6d2d150bc2e8e41e1cf2996a4295 [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
Ari Hausman-Cohen3841a7f2016-07-19 17:27:52 -070017#include "v4l2_wrapper.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070018
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
Ari Hausman-Cohen3841a7f2016-07-19 17:27:52 -070028#include "common.h"
29#include "stream.h"
30#include "stream_format.h"
31#include "v4l2_gralloc.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)
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -070049 : device_path_(std::move(device_path)),
50 gralloc_(std::move(gralloc)),
51 max_buffers_(0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070052 HAL_LOG_ENTER();
53}
54
55V4L2Wrapper::~V4L2Wrapper() { HAL_LOG_ENTER(); }
56
57int V4L2Wrapper::Connect() {
58 HAL_LOG_ENTER();
59 std::lock_guard<std::mutex> lock(device_lock_);
60
61 if (connected()) {
62 HAL_LOGE("Camera device %s is already connected. Close it first",
63 device_path_.c_str());
64 return -EIO;
65 }
66
67 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR));
68 if (fd < 0) {
69 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
70 return -errno;
71 }
72 device_fd_.reset(fd);
73
74 // Check if this connection has the extended control query capability.
75 v4l2_query_ext_ctrl query;
76 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070077 // Already holding the lock, so don't call IoctlLocked.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070078 int res = TEMP_FAILURE_RETRY(
79 ioctl(device_fd_.get(), VIDIOC_QUERY_EXT_CTRL, &query));
80 extended_query_supported_ = (res == 0);
81
82 // TODO(b/29185945): confirm this is a supported device.
83 // This is checked by the HAL, but the device at device_path_ may
84 // not be the same one that was there when the HAL was loaded.
85 // (Alternatively, better hotplugging support may make this unecessary
86 // by disabling cameras that get disconnected and checking newly connected
87 // cameras, so Connect() is never called on an unsupported camera)
88 return 0;
89}
90
91void V4L2Wrapper::Disconnect() {
92 HAL_LOG_ENTER();
93 std::lock_guard<std::mutex> lock(device_lock_);
94
95 device_fd_.reset(); // Includes close().
96 format_.reset();
97 max_buffers_ = 0;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070098 // Closing the device releases all queued buffers back to the user.
99 gralloc_->unlockAllBuffers();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700100}
101
102// Helper function. Should be used instead of ioctl throughout this class.
103template <typename T>
104int V4L2Wrapper::IoctlLocked(int request, T data) {
105 HAL_LOG_ENTER();
106 std::lock_guard<std::mutex> lock(device_lock_);
107
108 if (!connected()) {
109 HAL_LOGE("Device %s not connected.", device_path_.c_str());
110 return -ENODEV;
111 }
112 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
113}
114
115int V4L2Wrapper::StreamOn() {
116 HAL_LOG_ENTER();
117
118 if (!format_) {
119 HAL_LOGE("Stream format must be set before turning on stream.");
120 return -EINVAL;
121 }
122
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700123 int32_t type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700124 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
125 HAL_LOGE("STREAMON fails: %s", strerror(errno));
126 return -ENODEV;
127 }
128
129 return 0;
130}
131
132int V4L2Wrapper::StreamOff() {
133 HAL_LOG_ENTER();
134
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700135 if (!format_) {
136 HAL_LOGE("Stream format must be set to turn off stream.");
137 return -ENODEV;
138 }
139
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700140 int32_t type = format_->type();
141 int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
142 // Calling STREAMOFF releases all queued buffers back to the user.
143 int gralloc_res = gralloc_->unlockAllBuffers();
144 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700145 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
146 return -ENODEV;
147 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700148 if (gralloc_res < 0) {
149 HAL_LOGE("Failed to unlock all buffers after turning stream off.");
150 return gralloc_res;
151 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700152
153 return 0;
154}
155
156int V4L2Wrapper::QueryControl(uint32_t control_id,
157 v4l2_query_ext_ctrl* result) {
158 HAL_LOG_ENTER();
159 int res;
160
161 memset(result, 0, sizeof(*result));
162
163 if (extended_query_supported_) {
164 result->id = control_id;
165 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
166 // Assuming the operation was supported (not ENOTTY), no more to do.
167 if (errno != ENOTTY) {
168 if (res) {
169 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
170 return -ENODEV;
171 }
172 return 0;
173 }
174 }
175
176 // Extended control querying not supported, fall back to basic control query.
177 v4l2_queryctrl query;
178 query.id = control_id;
179 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
180 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
181 return -ENODEV;
182 }
183
184 // Convert the basic result to the extended result.
185 result->id = query.id;
186 result->type = query.type;
187 memcpy(result->name, query.name, sizeof(query.name));
188 result->minimum = query.minimum;
189 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
190 // According to the V4L2 documentation, when type is BITMASK,
191 // max and default should be interpreted as __u32. Practically,
192 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
193 result->maximum = static_cast<uint32_t>(query.maximum);
194 result->default_value = static_cast<uint32_t>(query.default_value);
195 } else {
196 result->maximum = query.maximum;
197 result->default_value = query.default_value;
198 }
199 result->step = static_cast<uint32_t>(query.step);
200 result->flags = query.flags;
201 result->elems = 1;
202 switch (result->type) {
203 case V4L2_CTRL_TYPE_INTEGER64:
204 result->elem_size = sizeof(int64_t);
205 break;
206 case V4L2_CTRL_TYPE_STRING:
207 result->elem_size = result->maximum + 1;
208 break;
209 default:
210 result->elem_size = sizeof(int32_t);
211 break;
212 }
213
214 return 0;
215}
216
217int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
218 HAL_LOG_ENTER();
219
220 v4l2_control control;
221 control.id = control_id;
222 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
223 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
224 return -ENODEV;
225 }
226 *value = control.value;
227 return 0;
228}
229
230int V4L2Wrapper::SetControl(uint32_t control_id, int32_t desired,
231 int32_t* result) {
232 HAL_LOG_ENTER();
233
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700234 // TODO(b/29334616): When async, this may need to check if the stream
235 // is on, and if so, lock it off while setting format. Need to look
236 // into if V4L2 supports adjusting controls while the stream is on.
237
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700238 v4l2_control control{control_id, desired};
239 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
240 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
241 return -ENODEV;
242 }
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700243 // If the caller wants to know the result, pass it back.
244 if (result != nullptr) {
245 *result = control.value;
246 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700247 return 0;
248}
249
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700250int V4L2Wrapper::SetFormat(const default_camera_hal::Stream& stream,
251 uint32_t* result_max_buffers) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700252 HAL_LOG_ENTER();
253
254 // Should be checked earlier; sanity check.
255 if (stream.isInputType()) {
256 HAL_LOGE("Input streams not supported.");
257 return -EINVAL;
258 }
259
260 StreamFormat desired_format(stream);
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700261 if (format_ && desired_format == *format_) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700262 HAL_LOGV("Already in correct format, skipping format setting.");
263 return 0;
264 }
265
266 // Not in the correct format, set our format.
267 v4l2_format new_format;
268 desired_format.FillFormatRequest(&new_format);
269 // TODO(b/29334616): When async, this will need to check if the stream
270 // is on, and if so, lock it off while setting format.
271 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
272 HAL_LOGE("S_FMT failed: %s", strerror(errno));
273 return -ENODEV;
274 }
275
276 // Check that the driver actually set to the requested values.
277 if (desired_format != new_format) {
278 HAL_LOGE("Device doesn't support desired stream configuration.");
279 return -EINVAL;
280 }
281
282 // Keep track of our new format.
283 format_.reset(new StreamFormat(new_format));
284
285 // Format changed, setup new buffers.
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700286 int res = SetupBuffers();
287 if (res) {
288 HAL_LOGE("Failed to set up buffers for new format.");
289 return res;
290 }
291 *result_max_buffers = max_buffers_;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700292 return 0;
293}
294
295int V4L2Wrapper::SetupBuffers() {
296 HAL_LOG_ENTER();
297
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700298 if (!format_) {
299 HAL_LOGE("Stream format must be set before setting up buffers.");
300 return -ENODEV;
301 }
302
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700303 // "Request" a buffer (since we're using a userspace buffer, this just
304 // tells V4L2 to switch into userspace buffer mode).
305 v4l2_requestbuffers req_buffers;
306 memset(&req_buffers, 0, sizeof(req_buffers));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700307 req_buffers.type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700308 req_buffers.memory = V4L2_MEMORY_USERPTR;
309 req_buffers.count = 1;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700310
311 int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
312 // Calling REQBUFS releases all queued buffers back to the user.
313 int gralloc_res = gralloc_->unlockAllBuffers();
314 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700315 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
316 return -ENODEV;
317 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700318 if (gralloc_res < 0) {
319 HAL_LOGE("Failed to unlock all buffers when setting up new buffers.");
320 return gralloc_res;
321 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700322
323 // V4L2 will set req_buffers.count to a number of buffers it can handle.
324 max_buffers_ = req_buffers.count;
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700325 // Sanity check.
326 if (max_buffers_ < 1) {
327 HAL_LOGE("REQBUFS claims it can't handle any buffers.");
328 return -ENODEV;
329 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700330 return 0;
331}
332
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700333int V4L2Wrapper::EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
334 HAL_LOG_ENTER();
335
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700336 if (!format_) {
337 HAL_LOGE("Stream format must be set before enqueuing buffers.");
338 return -ENODEV;
339 }
340
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700341 // Set up a v4l2 buffer struct.
342 v4l2_buffer device_buffer;
343 memset(&device_buffer, 0, sizeof(device_buffer));
344 device_buffer.type = format_->type();
345
346 // Use QUERYBUF to ensure our buffer/device is in good shape.
347 if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
348 HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
349 return -ENODEV;
350 }
351
352 // Configure the device buffer based on the stream buffer.
353 device_buffer.memory = V4L2_MEMORY_USERPTR;
354 // TODO(b/29334616): when this is async, actually limit the number
355 // of buffers used to the known max, and set this according to the
356 // queue length.
357 device_buffer.index = 0;
358 // Lock the buffer for writing.
359 int res =
360 gralloc_->lock(camera_buffer, format_->bytes_per_line(), &device_buffer);
361 if (res) {
362 HAL_LOGE("Gralloc failed to lock buffer.");
363 return res;
364 }
365 if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
366 HAL_LOGE("QBUF (%d) fails: %s", 0, strerror(errno));
367 gralloc_->unlock(&device_buffer);
368 return -ENODEV;
369 }
370
371 return 0;
372}
373
374int V4L2Wrapper::DequeueBuffer(v4l2_buffer* buffer) {
375 HAL_LOG_ENTER();
376
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700377 if (!format_) {
378 HAL_LOGE("Stream format must be set before dequeueing buffers.");
379 return -ENODEV;
380 }
381
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700382 memset(buffer, 0, sizeof(*buffer));
383 buffer->type = format_->type();
384 buffer->memory = V4L2_MEMORY_USERPTR;
385 if (IoctlLocked(VIDIOC_DQBUF, buffer) < 0) {
386 HAL_LOGE("DQBUF fails: %s", strerror(errno));
387 return -ENODEV;
388 }
389
390 // Now that we're done painting the buffer, we can unlock it.
391 int res = gralloc_->unlock(buffer);
392 if (res) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700393 HAL_LOGE("Gralloc failed to unlock buffer after dequeueing.");
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700394 return res;
395 }
396
397 return 0;
398}
399
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700400} // namespace v4l2_camera_hal