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