blob: ec99a4cfa218ea56d1223ef854b6e8904ed5cf73 [file] [log] [blame]
Ari Hausman-Cohen73442152016-06-08 15:50:49 -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// Modified from hardware/libhardware/modules/camera/CameraHAL.cpp
18
19#include "V4L2CameraHAL.h"
20
Ari Hausman-Cohen63f69822016-06-10 11:40:35 -070021#include <dirent.h>
22#include <fcntl.h>
23#include <linux/videodev2.h>
24#include <sys/ioctl.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28
29#include <algorithm>
Ari Hausman-Cohen73442152016-06-08 15:50:49 -070030#include <cstdlib>
Ari Hausman-Cohen63f69822016-06-10 11:40:35 -070031#include <unordered_set>
Ari Hausman-Cohen73442152016-06-08 15:50:49 -070032
33#include "Common.h"
34#include "V4L2Camera.h"
35
36/*
37 * This file serves as the entry point to the HAL. It is modified from the
38 * example default HAL available in hardware/libhardware/modules/camera.
39 * It contains the module structure and functions used by the framework
40 * to load and interface to this HAL, as well as the handles to the individual
41 * camera devices.
42 */
43
44namespace v4l2_camera_hal {
45
46// Default global camera hal.
47static V4L2CameraHAL gCameraHAL;
48
49// Helper function for converting and validating string name to int id.
50// Returns either a non-negative camera id, or a negative error code.
51static int id_from_name(const char* name) {
52 if (name == NULL || *name == '\0') {
53 HAL_LOGE("Invalid camera id name is NULL");
54 return -EINVAL;
55 }
56 char* nameEnd;
57 int id = strtol(name, &nameEnd, 10);
58 if (*nameEnd != '\0' || id < 0) {
59 HAL_LOGE("Invalid camera id name %s", name);
60 return -EINVAL;
61 }
62 return id;
63}
64
65V4L2CameraHAL::V4L2CameraHAL() : mCameras(), mCallbacks(NULL) {
66 HAL_LOG_ENTER();
Ari Hausman-Cohen63f69822016-06-10 11:40:35 -070067 // Adds all available V4L2 devices.
68 // List /dev nodes.
69 DIR* dir = opendir("/dev");
70 if (dir == NULL) {
71 HAL_LOGE("Failed to open /dev");
72 return;
73 }
74 // Find /dev/video* nodes.
75 dirent* ent;
76 std::vector<std::string> nodes;
77 while ((ent = readdir(dir))) {
78 std::string desired = "video";
79 size_t len = desired.size();
80 if (strncmp(desired.c_str(), ent->d_name, len) == 0) {
81 if (strlen(ent->d_name) > len && isdigit(ent->d_name[len])) {
82 // ent is a numbered video node.
83 nodes.push_back(std::string("/dev/") + ent->d_name);
84 HAL_LOGV("Found video node %s.", nodes.back().c_str());
85 }
86 }
87 }
88 // Test each for V4L2 support and uniqueness.
89 std::unordered_set<std::string> buses;
90 std::string bus;
91 v4l2_capability cap;
92 int fd;
93 int id = 0;
94 for (const auto& node : nodes) {
95 // Open the node.
96 fd = TEMP_FAILURE_RETRY(open(node.c_str(), O_RDWR));
97 if (fd < 0) {
98 HAL_LOGE("failed to open %s (%s).", node.c_str(), strerror(errno));
99 continue;
100 }
101 // Read V4L2 capabilities.
102 if (TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_QUERYCAP, &cap)) != 0) {
103 HAL_LOGE("VIDIOC_QUERYCAP on %s fail: %s.", node.c_str(),
104 strerror(errno));
105 } else if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
106 HAL_LOGE("%s is not a V4L2 video capture device.", node.c_str());
107 } else {
108 // If the node is unique, add a camera for it.
109 bus = reinterpret_cast<char*>(cap.bus_info);
110 if (buses.insert(bus).second) {
111 HAL_LOGV("Found unique bus at %s.", node.c_str());
112 std::unique_ptr<V4L2Camera> cam(new V4L2Camera(id++, node));
113 mCameras.push_back(std::move(cam));
114 }
115 }
116 TEMP_FAILURE_RETRY(close(fd));
117 }
Ari Hausman-Cohen73442152016-06-08 15:50:49 -0700118}
119
120V4L2CameraHAL::~V4L2CameraHAL() {
121 HAL_LOG_ENTER();
122}
123
124int V4L2CameraHAL::getNumberOfCameras() {
125 HAL_LOGV("returns %d", mCameras.size());
126 return mCameras.size();
127}
128
129int V4L2CameraHAL::getCameraInfo(int id, camera_info_t* info) {
130 HAL_LOG_ENTER();
131 if (id < 0 || id >= mCameras.size()) {
132 return -EINVAL;
133 }
134 // TODO(b/29185945): Hotplugging: return -EINVAL if unplugged.
135 return mCameras[id]->getInfo(info);
136}
137
138int V4L2CameraHAL::setCallbacks(const camera_module_callbacks_t* callbacks) {
139 HAL_LOG_ENTER();
140 mCallbacks = callbacks;
141 return 0;
142}
143
144void V4L2CameraHAL::getVendorTagOps(vendor_tag_ops_t* ops) {
145 HAL_LOG_ENTER();
146 // No vendor ops for this HAL. From <hardware/camera_common.h>:
147 // "leave ops unchanged if no vendor tags are defined."
148}
149
150int V4L2CameraHAL::openLegacy(const hw_module_t* module, const char* id,
151 uint32_t halVersion, hw_device_t** device) {
152 HAL_LOG_ENTER();
153 // Not supported.
154 return -ENOSYS;
155}
156
157int V4L2CameraHAL::setTorchMode(const char* camera_id, bool enabled) {
158 HAL_LOG_ENTER();
159 // TODO(b/29158098): HAL is required to respond appropriately if
160 // the desired camera actually does support flash.
161 return -ENOSYS;
162}
163
Ari Hausman-Cohen63f69822016-06-10 11:40:35 -0700164int V4L2CameraHAL::openDevice(const hw_module_t* module, const char* name,
165 hw_device_t** device) {
Ari Hausman-Cohen73442152016-06-08 15:50:49 -0700166 HAL_LOG_ENTER();
167
168 if (module != &HAL_MODULE_INFO_SYM.common) {
169 HAL_LOGE("Invalid module %p expected %p", module,
170 &HAL_MODULE_INFO_SYM.common);
171 return -EINVAL;
172 }
173
174 int id = id_from_name(name);
175 if (id < 0) {
176 return id;
177 } else if (id < 0 || id >= mCameras.size()) {
178 return -EINVAL;
179 }
180 // TODO(b/29185945): Hotplugging: return -EINVAL if unplugged.
181 return mCameras[id]->open(module, device);
182}
183
184/*
185 * The framework calls the following wrappers, which in turn
186 * call the corresponding methods of the global HAL object.
187 */
188
189static int get_number_of_cameras() {
190 return gCameraHAL.getNumberOfCameras();
191}
192
193static int get_camera_info(int id, struct camera_info* info) {
194 return gCameraHAL.getCameraInfo(id, info);
195}
196
197static int set_callbacks(const camera_module_callbacks_t *callbacks) {
198 return gCameraHAL.setCallbacks(callbacks);
199}
200
201static void get_vendor_tag_ops(vendor_tag_ops_t* ops) {
202 return gCameraHAL.getVendorTagOps(ops);
203}
204
205static int open_legacy(const hw_module_t* module, const char* id,
206 uint32_t halVersion, hw_device_t** device) {
207 return gCameraHAL.openLegacy(module, id, halVersion, device);
208}
209
210static int set_torch_mode(const char* camera_id, bool enabled) {
211 return gCameraHAL.setTorchMode(camera_id, enabled);
212}
213
214static int open_dev(const hw_module_t* module, const char* name,
215 hw_device_t** device) {
Ari Hausman-Cohen63f69822016-06-10 11:40:35 -0700216 return gCameraHAL.openDevice(module, name, device);
Ari Hausman-Cohen73442152016-06-08 15:50:49 -0700217}
218
219} // namespace v4l2_camera_hal
220
221static hw_module_methods_t v4l2_module_methods = {
222 .open = v4l2_camera_hal::open_dev
223};
224
Ari Hausman-Cohen77db7d02016-06-13 17:15:06 -0700225camera_module_t HAL_MODULE_INFO_SYM __attribute__ ((visibility("default"))) = {
Ari Hausman-Cohen73442152016-06-08 15:50:49 -0700226 .common = {
227 .tag = HARDWARE_MODULE_TAG,
228 .module_api_version = CAMERA_MODULE_API_VERSION_2_4,
229 .hal_api_version = HARDWARE_HAL_API_VERSION,
230 .id = CAMERA_HARDWARE_MODULE_ID,
231 .name = "V4L2 Camera HAL v3",
232 .author = "The Android Open Source Project",
233 .methods = &v4l2_module_methods,
234 .dso = nullptr,
235 .reserved = {0},
236 },
237 .get_number_of_cameras = v4l2_camera_hal::get_number_of_cameras,
238 .get_camera_info = v4l2_camera_hal::get_camera_info,
239 .set_callbacks = v4l2_camera_hal::set_callbacks,
240 .get_vendor_tag_ops = v4l2_camera_hal::get_vendor_tag_ops,
241 .open_legacy = v4l2_camera_hal::open_legacy,
242 .set_torch_mode = v4l2_camera_hal::set_torch_mode,
243 .init = nullptr,
244 .reserved = {nullptr, nullptr, nullptr, nullptr, nullptr}
245};