xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/xcore/fake_v4l2_device.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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