1 /*
2 * v4l2_device.cpp - v4l2 device
3 *
4 * Copyright (c) 2014-2015 Intel Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Wind Yuan <feng.yuan@intel.com>
19 * Author: John Ye <john.ye@intel.com>
20 */
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <poll.h>
25 #include <sys/mman.h>
26 #include "fake_v4l2_device.h"
27 #include "v4l2_buffer_proxy.h"
28
29 namespace XCam {
30
31
32 XCamReturn
open(bool nonblock)33 FakeV4l2Device::open (bool nonblock)
34 {
35 struct v4l2_streamparm param;
36
37 if (is_opened()) {
38 XCAM_LOG_DEBUG ("device(%s) was already opened", XCAM_STR(_name));
39 return XCAM_RETURN_NO_ERROR;
40 }
41
42 if (!_name) {
43 XCAM_LOG_DEBUG ("v4l2 device open failed, there's no device name");
44 return XCAM_RETURN_ERROR_PARAM;
45 }
46 _fd = ::open (_name, O_RDWR);
47 if (_fd == -1) {
48 XCAM_LOG_ERROR ("open device(%s) failed", _name);
49 return XCAM_RETURN_ERROR_IOCTL;
50 } else {
51 XCAM_LOG_DEBUG ("open device(%s) successed, fd: %d", _name, _fd);
52 }
53
54 if (create_notify_pipe () < 0) {
55 XCAM_LOG_ERROR ("create virtual tx pipe failed");
56 return XCAM_RETURN_ERROR_PARAM;
57 }
58
59
60 return XCAM_RETURN_NO_ERROR;
61 }
62
63 XCamReturn
close()64 FakeV4l2Device::close ()
65 {
66
67 if (!is_opened())
68 return XCAM_RETURN_NO_ERROR;
69 ::close (_fd);
70 _fd = -1;
71 destroy_notify_pipe ();
72 XCAM_LOG_INFO ("device(%s) closed", XCAM_STR (_name));
73 return XCAM_RETURN_NO_ERROR;
74 }
75
76 XCamReturn
start(bool prepared)77 FakeV4l2Device::start (bool prepared) {
78 (void)prepared;
79 _active = true;
80
81 return XCAM_RETURN_NO_ERROR;
82 }
83
84 XCamReturn
stop()85 FakeV4l2Device::stop () {
86 _active = false;
87 _buf_list.clear();
88 return XCAM_RETURN_NO_ERROR;
89 }
90
91 int
create_notify_pipe()92 FakeV4l2Device::create_notify_pipe ()
93 {
94 int status = 0;
95
96 destroy_notify_pipe ();
97 status = pipe(_pipe_fd);
98 if (status < 0) {
99 XCAM_LOG_ERROR("Failed to create virtual tx notify poll pipe: %s", strerror(errno));
100 goto exit_error;
101 }
102 status = fcntl(_pipe_fd[0], F_SETFL, O_NONBLOCK);
103 if (status < 0) {
104 XCAM_LOG_ERROR("Fail to set event virtual tx notify pipe flag: %s", strerror(errno));
105 goto exit_error;
106 }
107 status = fcntl(_pipe_fd[1], F_SETFL, O_NONBLOCK);
108 if (status < 0) {
109 XCAM_LOG_ERROR("Fail to set event virtual tx notify pipe flag: %s", strerror(errno));
110 goto exit_error;
111 }
112 return status;
113 exit_error:
114 destroy_notify_pipe();
115 return status;
116 }
117
destroy_notify_pipe()118 void FakeV4l2Device::destroy_notify_pipe () {
119 if (_pipe_fd[0] != -1 || _pipe_fd[1] != -1) {
120 ::close(_pipe_fd[0]);
121 ::close(_pipe_fd[1]);
122 _pipe_fd[0] = -1;
123 _pipe_fd[1] = -1;
124 }
125 }
126
127 int
io_control(unsigned long cmd,void * arg)128 FakeV4l2Device::io_control (unsigned long cmd, void *arg)
129 {
130 if (_fd <= 0)
131 return -1;
132
133 if (VIDIOC_DQBUF == cmd) {
134 struct v4l2_buffer *v4l2_buf = (struct v4l2_buffer *)arg;
135 v4l2_buf->index = get_available_buffer_index();
136 _mutex.lock();
137 struct rk_aiq_vbuf_info vb_info;
138 if(!_buf_list.empty()) {
139 vb_info = _buf_list.front();
140 _buf_list.pop_front();
141 v4l2_buf->m.planes[0].length = vb_info.data_length;
142 v4l2_buf->m.planes[0].bytesused = vb_info.data_length;
143 v4l2_buf->sequence = vb_info.frame_id;
144 v4l2_buf->m.planes[0].m.userptr = (unsigned long)vb_info.data_addr;
145 v4l2_buf->reserved = vb_info.data_fd;
146 gettimeofday(&v4l2_buf->timestamp, NULL);
147 }
148 _mutex.unlock();
149 }
150 return 0;
151 }
152
get_format(struct v4l2_format & format)153 XCamReturn FakeV4l2Device::get_format (struct v4l2_format &format)
154 {
155 format = _format;
156 return XCAM_RETURN_NO_ERROR;
157 }
158
159 int
poll_event(int timeout_msec,int stop_fd)160 FakeV4l2Device::poll_event (int timeout_msec, int stop_fd)
161 {
162 int num_fds = stop_fd == -1 ? 1 : 2;
163 struct pollfd poll_fds[num_fds];
164 int ret = 0;
165
166 XCAM_ASSERT (_fd > 0);
167
168 memset(poll_fds, 0, sizeof(poll_fds));
169 poll_fds[0].fd = _pipe_fd[0];
170 poll_fds[0].events = (POLLPRI | POLLIN | POLLOUT);
171
172 if (stop_fd != -1) {
173 poll_fds[1].fd = stop_fd;
174 poll_fds[1].events = POLLPRI | POLLIN | POLLOUT;
175 poll_fds[1].revents = 0;
176 }
177
178 ret = poll (poll_fds, num_fds, timeout_msec);
179 if (ret > 0) {
180 if (stop_fd != -1) {
181 if (poll_fds[1].revents & (POLLIN | POLLPRI)) {
182 XCAM_LOG_DEBUG ("%s: Poll returning from flush", __FUNCTION__);
183 return POLL_STOP_RET;
184 }
185 }
186
187 if (poll_fds[0].revents & (POLLIN | POLLPRI)) {
188 char buf[8];
189 read(_pipe_fd[0], buf, sizeof(buf));
190 XCAM_LOG_DEBUG ("%s: Poll returning timer pipe", __FUNCTION__);
191 }
192
193 }
194
195 return ret;
196 }
197
198 XCamReturn
dequeue_buffer(SmartPtr<V4l2Buffer> & buf)199 FakeV4l2Device::dequeue_buffer(SmartPtr<V4l2Buffer> &buf)
200 {
201 struct v4l2_buffer v4l2_buf;
202 struct v4l2_plane planes[FMT_NUM_PLANES];
203
204 if (!is_activated()) {
205 XCAM_LOG_ERROR (
206 "device(%s) dequeue buffer failed since not activated", XCAM_STR (_name));
207 return XCAM_RETURN_ERROR_PARAM;
208 }
209
210 xcam_mem_clear (v4l2_buf);
211 v4l2_buf.type = _buf_type;
212 v4l2_buf.memory = _memory_type;
213
214 if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type ||
215 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) {
216 memset(planes, 0, sizeof(struct v4l2_plane) * FMT_NUM_PLANES);
217 v4l2_buf.m.planes = planes;
218 v4l2_buf.length = FMT_NUM_PLANES;
219 }
220
221 if (this->io_control (VIDIOC_DQBUF, &v4l2_buf) < 0) {
222 XCAM_LOG_ERROR ("device(%s) fail to dequeue buffer.", XCAM_STR (_name));
223 return XCAM_RETURN_ERROR_IOCTL;
224 }
225
226 if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type ||
227 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) {
228 XCAM_LOG_DEBUG ("device(%s) dequeue buffer index:%d, memory:%d, type:%d, multiply planar:%d, length:%d, fd:%d,ptr:%p",
229 XCAM_STR (_name), v4l2_buf.index, v4l2_buf.memory,
230 v4l2_buf.type, v4l2_buf.length, v4l2_buf.m.planes[0].length, v4l2_buf.m.planes[0].m.fd, v4l2_buf.m.planes[0].m.userptr);
231
232 if (V4L2_MEMORY_DMABUF == _memory_type) {
233 XCAM_LOG_DEBUG ("device(%s) multi planar index:%d, fd: %d",
234 XCAM_STR (_name), v4l2_buf.index, v4l2_buf.m.planes[0].m.fd);
235 }
236 } else {
237 XCAM_LOG_DEBUG ("device(%s) dequeue buffer index:%d, length: %d",
238 XCAM_STR (_name), v4l2_buf.index, v4l2_buf.length);
239 }
240
241 if (v4l2_buf.index >= _buf_count) {
242 XCAM_LOG_ERROR (
243 "device(%s) dequeue wrong buffer index:%d",
244 XCAM_STR (_name), v4l2_buf.index);
245 return XCAM_RETURN_ERROR_ISP;
246 }
247
248 SmartLock auto_lock(_buf_mutex);
249
250 buf = _buf_pool [v4l2_buf.index];
251 buf->set_timestamp (v4l2_buf.timestamp);
252 buf->set_timecode (v4l2_buf.timecode);
253 buf->set_sequence (v4l2_buf.sequence);
254 if (!V4L2_TYPE_IS_OUTPUT(buf->get_buf ().type))
255 buf->set_queued(false);
256 if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type ||
257 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) {
258 buf->set_length (v4l2_buf.m.planes[0].length);
259 // if (_use_type != 2) {
260 buf->set_expbuf_usrptr(v4l2_buf.m.planes[0].m.userptr);
261 buf->set_expbuf_fd(v4l2_buf.reserved);
262 // }
263 } else {
264 buf->set_length (v4l2_buf.length);
265 }
266 _queued_bufcnt--;
267
268 return XCAM_RETURN_NO_ERROR;
269 }
270
271 uint32_t
get_available_buffer_index()272 FakeV4l2Device::get_available_buffer_index ()
273 {
274 uint32_t idx = 0;
275 SmartPtr<V4l2Buffer> buf;
276 _buf_mutex.lock();
277 for (; idx<_buf_count; idx++) {
278 buf = _buf_pool[idx];
279 if (buf->get_queued()) {
280 break;
281 }
282 }
283 _buf_mutex.unlock();
284 return idx;
285 }
286
287 void
enqueue_rawbuffer(struct rk_aiq_vbuf_info * vbinfo)288 FakeV4l2Device::enqueue_rawbuffer(struct rk_aiq_vbuf_info *vbinfo)
289 {
290 if (vbinfo != NULL) {
291 _mutex.lock();
292 _buf_list.push_back(*vbinfo);
293 _mutex.unlock();
294 }
295 }
296 static int icnt = 0;
297 void
on_timer_proc()298 FakeV4l2Device::on_timer_proc ()
299 {
300 if (!_buf_list.empty() && _queued_bufcnt) {
301 if (_pipe_fd[1] != -1) {
302 char buf = 0xf; // random value to write to flush fd.
303 unsigned int size = write(_pipe_fd[1], &buf, sizeof(char));
304 if (size != sizeof(char))
305 XCAM_LOG_ERROR("Flush write not completed");
306 }
307 }
308 }
309
310 }
311