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