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 (at) intel.com> 19 * Author: John Ye <john.ye (at) intel.com> 20 */ 21 22 #include "v4l2_device.h" 23 #include <sys/ioctl.h> 24 #include <stdlib.h> 25 #include <unistd.h> 26 #include <fcntl.h> 27 #include <poll.h> 28 #include <errno.h> 29 #include <sys/mman.h> 30 31 #include "v4l2_buffer_proxy.h" 32 33 namespace XCam { 34 35 #define XCAM_V4L2_DEFAULT_BUFFER_COUNT 6 36 37 V4l2Device::V4l2Device (const char *name) 38 : _name (NULL) 39 , _fd (-1) 40 , _sensor_id (0) 41 , _capture_mode (0) 42 , _capture_buf_type (V4L2_BUF_TYPE_VIDEO_CAPTURE) 43 , _memory_type (V4L2_MEMORY_MMAP) 44 , _fps_n (0) 45 , _fps_d (0) 46 , _active (false) 47 , _buf_count (XCAM_V4L2_DEFAULT_BUFFER_COUNT) 48 { 49 if (name) 50 _name = strndup (name, XCAM_MAX_STR_SIZE); 51 xcam_mem_clear (_format); 52 } 53 54 V4l2Device::~V4l2Device () 55 { 56 close(); 57 if (_name) 58 xcam_free (_name); 59 } 60 61 bool 62 V4l2Device::set_device_name (const char *name) 63 { 64 XCAM_ASSERT (name); 65 66 if (is_opened()) { 67 XCAM_LOG_WARNING ("can't set device name since device opened"); 68 return false; 69 } 70 if (_name) 71 xcam_free (_name); 72 _name = strndup (name, XCAM_MAX_STR_SIZE); 73 return true; 74 } 75 76 bool 77 V4l2Device::set_sensor_id (int id) 78 { 79 if (is_opened()) { 80 XCAM_LOG_WARNING ("can't set sensor id since device opened"); 81 return false; 82 } 83 _sensor_id = id; 84 return true; 85 } 86 87 bool 88 V4l2Device::set_capture_mode (uint32_t capture_mode) 89 { 90 if (is_opened()) { 91 XCAM_LOG_WARNING ("can't set sensor id since device opened"); 92 return false; 93 } 94 _capture_mode = capture_mode; 95 return true; 96 } 97 98 bool 99 V4l2Device::set_framerate (uint32_t n, uint32_t d) 100 { 101 if (_format.fmt.pix.pixelformat) { 102 XCAM_LOG_WARNING ("device(%s) set framerate failed since formatted was already set.", XCAM_STR(_name)); 103 return false; 104 } 105 106 _fps_n = n; 107 _fps_d = d; 108 109 return true; 110 } 111 112 void 113 V4l2Device::get_framerate (uint32_t &n, uint32_t &d) 114 { 115 n = _fps_n; 116 d = _fps_d; 117 } 118 119 bool 120 V4l2Device::set_mem_type (enum v4l2_memory type) { 121 if (is_activated ()) { 122 XCAM_LOG_WARNING ("device(%s) set mem type failed", XCAM_STR (_name)); 123 return false; 124 } 125 _memory_type = type; 126 return true; 127 } 128 129 bool 130 V4l2Device::set_buffer_count (uint32_t buf_count) 131 { 132 if (is_activated ()) { 133 XCAM_LOG_WARNING ("device(%s) set buffer count failed", XCAM_STR (_name)); 134 return false; 135 } 136 _buf_count = buf_count; 137 return true; 138 } 139 140 141 XCamReturn 142 V4l2Device::open () 143 { 144 struct v4l2_streamparm param; 145 146 if (is_opened()) { 147 XCAM_LOG_DEBUG ("device(%s) was already opened", XCAM_STR(_name)); 148 return XCAM_RETURN_NO_ERROR; 149 } 150 151 if (!_name) { 152 XCAM_LOG_DEBUG ("v4l2 device open failed, there's no device name"); 153 return XCAM_RETURN_ERROR_PARAM; 154 } 155 _fd = ::open (_name, O_RDWR); 156 if (_fd == -1) { 157 XCAM_LOG_DEBUG ("open device(%s) failed", _name); 158 return XCAM_RETURN_ERROR_IOCTL; 159 } 160 161 // set sensor id 162 if (io_control (VIDIOC_S_INPUT, &_sensor_id) < 0) { 163 XCAM_LOG_WARNING ("set sensor id(%d) failed but continue", _sensor_id); 164 } 165 166 // set capture mode 167 xcam_mem_clear (param); 168 param.type = _capture_buf_type; 169 param.parm.capture.capturemode = _capture_mode; 170 if (io_control (VIDIOC_S_PARM, ¶m) < 0) { 171 XCAM_LOG_WARNING ("set capture mode(0x%08x) failed but continue", _capture_mode); 172 } 173 174 return XCAM_RETURN_NO_ERROR; 175 } 176 177 XCamReturn 178 V4l2Device::close () 179 { 180 if (!is_opened()) 181 return XCAM_RETURN_NO_ERROR; 182 ::close (_fd); 183 _fd = -1; 184 return XCAM_RETURN_NO_ERROR; 185 } 186 187 int 188 V4l2Device::io_control (int cmd, void *arg) 189 190 { 191 if (_fd <= 0) 192 return -1; 193 194 return xcam_device_ioctl (_fd, cmd, arg); 195 } 196 197 int 198 V4l2Device::poll_event (int timeout_msec) 199 { 200 struct pollfd poll_fd; 201 int ret = 0; 202 203 XCAM_ASSERT (_fd > 0); 204 205 xcam_mem_clear (poll_fd); 206 poll_fd.fd = _fd; 207 poll_fd.events = (POLLPRI | POLLIN | POLLERR | POLLNVAL | POLLHUP); 208 209 ret = poll (&poll_fd, 1, timeout_msec); 210 if (ret > 0 && (poll_fd.revents & (POLLERR | POLLNVAL | POLLHUP))) { 211 XCAM_LOG_DEBUG ("v4l2 subdev(%s) polled error", XCAM_STR(_name)); 212 return -1; 213 } 214 return ret; 215 216 } 217 218 XCamReturn 219 V4l2Device::set_format (struct v4l2_format &format) 220 { 221 XCamReturn ret = XCAM_RETURN_NO_ERROR; 222 223 XCAM_FAIL_RETURN (ERROR, !is_activated (), XCAM_RETURN_ERROR_PARAM, 224 "Cannot set format to v4l2 device while it is active."); 225 226 XCAM_FAIL_RETURN (ERROR, is_opened (), XCAM_RETURN_ERROR_FILE, 227 "Cannot set format to v4l2 device while it is closed."); 228 229 struct v4l2_format tmp_format = format; 230 231 ret = pre_set_format (format); 232 if (ret != XCAM_RETURN_NO_ERROR) { 233 XCAM_LOG_WARNING ("device(%s) pre_set_format failed", XCAM_STR (_name)); 234 return ret; 235 } 236 237 if (io_control (VIDIOC_S_FMT, &format) < 0) { 238 if (errno == EBUSY) { 239 // TODO log device name 240 XCAM_LOG_ERROR("Video device is busy, fail to set format."); 241 } else { 242 // TODO log format details and errno 243 XCAM_LOG_ERROR("Fail to set format: %s", strerror(errno)); 244 } 245 246 return XCAM_RETURN_ERROR_IOCTL; 247 } 248 249 if (tmp_format.fmt.pix.width != format.fmt.pix.width || tmp_format.fmt.pix.height != format.fmt.pix.height) { 250 XCAM_LOG_ERROR ( 251 "device(%s) set v4l2 format failed, supported format: width:%d, height:%d", 252 XCAM_STR (_name), 253 format.fmt.pix.width, 254 format.fmt.pix.height); 255 256 return XCAM_RETURN_ERROR_PARAM; 257 } 258 259 while (_fps_n && _fps_d) { 260 struct v4l2_streamparm param; 261 xcam_mem_clear (param); 262 param.type = _capture_buf_type; 263 if (io_control (VIDIOC_G_PARM, ¶m) < 0) { 264 XCAM_LOG_WARNING ("device(%s) set framerate failed on VIDIOC_G_PARM but continue", XCAM_STR (_name)); 265 break; 266 } 267 268 if (!(param.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) 269 break; 270 271 param.parm.capture.timeperframe.numerator = _fps_d; 272 param.parm.capture.timeperframe.denominator = _fps_n; 273 274 if (io_control (VIDIOC_S_PARM, ¶m) < 0) { 275 XCAM_LOG_WARNING ("device(%s) set framerate failed on VIDIOC_S_PARM but continue", XCAM_STR (_name)); 276 break; 277 } 278 _fps_n = param.parm.capture.timeperframe.denominator; 279 _fps_d = param.parm.capture.timeperframe.numerator; 280 XCAM_LOG_INFO ("device(%s) set framerate(%d/%d)", XCAM_STR (_name), _fps_n, _fps_d); 281 282 // exit here, otherwise it is an infinite loop 283 break; 284 } 285 286 ret = post_set_format (format); 287 if (ret != XCAM_RETURN_NO_ERROR) { 288 XCAM_LOG_WARNING ("device(%s) post_set_format failed", XCAM_STR (_name)); 289 return ret; 290 } 291 292 _format = format; 293 XCAM_LOG_INFO ( 294 "device(%s) set format(w:%d, h:%d, pixelformat:%s, bytesperline:%d,image_size:%d)", 295 XCAM_STR (_name), 296 format.fmt.pix.width, format.fmt.pix.height, 297 xcam_fourcc_to_string (format.fmt.pix.pixelformat), 298 format.fmt.pix.bytesperline, 299 format.fmt.pix.sizeimage); 300 301 return XCAM_RETURN_NO_ERROR; 302 } 303 304 /*! \brief v4l2 set format 305 * 306 * \param[in] width format width 307 * \param[in] height format height 308 * \param[in] pixelformat fourcc 309 * \param[in] field V4L2_FIELD_INTERLACED or V4L2_FIELD_NONE 310 */ 311 XCamReturn 312 V4l2Device::set_format ( 313 uint32_t width, uint32_t height, 314 uint32_t pixelformat, enum v4l2_field field, uint32_t bytes_perline) 315 { 316 317 struct v4l2_format format; 318 xcam_mem_clear (format); 319 320 format.type = _capture_buf_type; 321 format.fmt.pix.width = width; 322 format.fmt.pix.height = height; 323 format.fmt.pix.pixelformat = pixelformat; 324 format.fmt.pix.field = field; 325 326 if (bytes_perline != 0) 327 format.fmt.pix.bytesperline = bytes_perline; 328 return set_format (format); 329 } 330 331 XCamReturn 332 V4l2Device::pre_set_format (struct v4l2_format &format) 333 { 334 XCAM_UNUSED (format); 335 return XCAM_RETURN_NO_ERROR; 336 } 337 338 XCamReturn 339 V4l2Device::post_set_format (struct v4l2_format &format) 340 { 341 XCAM_UNUSED (format); 342 return XCAM_RETURN_NO_ERROR; 343 } 344 345 std::list<struct v4l2_fmtdesc> 346 V4l2Device::enum_formats () 347 { 348 std::list<struct v4l2_fmtdesc> formats; 349 struct v4l2_fmtdesc format; 350 uint32_t i = 0; 351 352 while (1) { 353 xcam_mem_clear (format); 354 format.index = i++; 355 format.type = _capture_buf_type; 356 if (this->io_control (VIDIOC_ENUM_FMT, &format) < 0) { 357 if (errno == EINVAL) 358 break; 359 else { // error 360 XCAM_LOG_DEBUG ("enum formats failed"); 361 return formats; 362 } 363 } 364 formats.push_back (format); 365 } 366 367 return formats; 368 } 369 370 XCamReturn 371 V4l2Device::get_format (struct v4l2_format &format) 372 { 373 if (is_activated ()) { 374 format = _format; 375 return XCAM_RETURN_NO_ERROR; 376 } 377 378 if (!is_opened ()) 379 return XCAM_RETURN_ERROR_IOCTL; 380 381 xcam_mem_clear (format); 382 format.type = _capture_buf_type; 383 384 if (this->io_control (VIDIOC_G_FMT, &format) < 0) { 385 // FIXME: also log the device name? 386 XCAM_LOG_ERROR("Fail to get format via ioctl VIDVIO_G_FMT."); 387 return XCAM_RETURN_ERROR_IOCTL; 388 } 389 390 return XCAM_RETURN_NO_ERROR; 391 } 392 393 XCamReturn 394 V4l2Device::start () 395 { 396 XCamReturn ret = XCAM_RETURN_NO_ERROR; 397 // request buffer first 398 ret = request_buffer (); 399 XCAM_FAIL_RETURN ( 400 ERROR, ret == XCAM_RETURN_NO_ERROR, ret, 401 "device(%s) start failed", XCAM_STR (_name)); 402 403 //alloc buffers 404 ret = init_buffer_pool (); 405 XCAM_FAIL_RETURN ( 406 ERROR, ret == XCAM_RETURN_NO_ERROR, ret, 407 "device(%s) start failed", XCAM_STR (_name)); 408 409 //queue all buffers 410 for (uint32_t i = 0; i < _buf_count; ++i) { 411 SmartPtr<V4l2Buffer> &buf = _buf_pool [i]; 412 XCAM_ASSERT (buf.ptr()); 413 XCAM_ASSERT (buf->get_buf().index == i); 414 ret = queue_buffer (buf); 415 if (ret != XCAM_RETURN_NO_ERROR) { 416 XCAM_LOG_ERROR ( 417 "device(%s) start failed on queue index:%d", 418 XCAM_STR (_name), i); 419 stop (); 420 return ret; 421 } 422 } 423 424 // stream on 425 if (io_control (VIDIOC_STREAMON, &_capture_buf_type) < 0) { 426 XCAM_LOG_ERROR ( 427 "device(%s) start failed on VIDIOC_STREAMON", 428 XCAM_STR (_name)); 429 stop (); 430 return XCAM_RETURN_ERROR_IOCTL; 431 } 432 _active = true; 433 XCAM_LOG_INFO ("device(%s) started successfully", XCAM_STR (_name)); 434 return XCAM_RETURN_NO_ERROR; 435 } 436 437 XCamReturn 438 V4l2Device::stop () 439 { 440 // stream off 441 if (_active) { 442 if (io_control (VIDIOC_STREAMOFF, &_capture_buf_type) < 0) { 443 XCAM_LOG_WARNING ("device(%s) steamoff failed", XCAM_STR (_name)); 444 } 445 _active = false; 446 } 447 448 fini_buffer_pool (); 449 450 XCAM_LOG_INFO ("device(%s) stopped", XCAM_STR (_name)); 451 return XCAM_RETURN_NO_ERROR; 452 } 453 454 XCamReturn 455 V4l2Device::request_buffer () 456 { 457 struct v4l2_requestbuffers request_buf; 458 459 XCAM_ASSERT (!is_activated()); 460 461 xcam_mem_clear (request_buf); 462 request_buf.type = _capture_buf_type; 463 request_buf.count = _buf_count; 464 request_buf.memory = _memory_type; 465 466 if (io_control (VIDIOC_REQBUFS, &request_buf) < 0) { 467 XCAM_LOG_INFO ("device(%s) starts failed on VIDIOC_REQBUFS", XCAM_STR (_name)); 468 return XCAM_RETURN_ERROR_IOCTL; 469 } 470 471 if (request_buf.count != _buf_count) { 472 XCAM_LOG_DEBUG ( 473 "device(%s) request buffer count doesn't match user settings, reset buffer count to %d", 474 XCAM_STR (_name), request_buf.count); 475 _buf_count = request_buf.count; 476 } 477 return XCAM_RETURN_NO_ERROR; 478 } 479 480 XCamReturn 481 V4l2Device::allocate_buffer ( 482 SmartPtr<V4l2Buffer> &buf, 483 const struct v4l2_format &format, 484 const uint32_t index) 485 { 486 struct v4l2_buffer v4l2_buf; 487 488 xcam_mem_clear (v4l2_buf); 489 v4l2_buf.index = index; 490 v4l2_buf.type = _capture_buf_type; 491 v4l2_buf.memory = _memory_type; 492 493 switch (_memory_type) { 494 case V4L2_MEMORY_DMABUF: 495 { 496 struct v4l2_exportbuffer expbuf; 497 xcam_mem_clear (expbuf); 498 expbuf.type = _capture_buf_type; 499 expbuf.index = index; 500 expbuf.flags = O_CLOEXEC; 501 if (io_control (VIDIOC_EXPBUF, &expbuf) < 0) { 502 XCAM_LOG_WARNING ("device(%s) get dma buf(%d) failed", XCAM_STR (_name), index); 503 return XCAM_RETURN_ERROR_MEM; 504 } 505 v4l2_buf.m.fd = expbuf.fd; 506 v4l2_buf.length = format.fmt.pix.sizeimage; 507 } 508 break; 509 case V4L2_MEMORY_MMAP: 510 { 511 void *pointer; 512 int map_flags = MAP_SHARED; 513 #ifdef NEED_MAP_32BIT 514 map_flags |= MAP_32BIT; 515 #endif 516 if (io_control (VIDIOC_QUERYBUF, &v4l2_buf) < 0) { 517 XCAM_LOG_WARNING("device(%s) query MMAP buf(%d) failed", XCAM_STR(_name), index); 518 return XCAM_RETURN_ERROR_MEM; 519 } 520 pointer = mmap (0, v4l2_buf.length, PROT_READ | PROT_WRITE, map_flags, _fd, v4l2_buf.m.offset); 521 if (pointer == MAP_FAILED) { 522 XCAM_LOG_WARNING("device(%s) mmap buf(%d) failed", XCAM_STR(_name), index); 523 return XCAM_RETURN_ERROR_MEM; 524 } 525 v4l2_buf.m.userptr = (uintptr_t) pointer; 526 } 527 break; 528 case V4L2_MEMORY_USERPTR: 529 default: 530 XCAM_ASSERT (false); 531 XCAM_LOG_WARNING ( 532 "device(%s) allocated buffer mem_type(%d) doesn't support", 533 XCAM_STR (_name), _memory_type); 534 return XCAM_RETURN_ERROR_MEM; 535 } 536 537 buf = new V4l2Buffer (v4l2_buf, _format); 538 539 return XCAM_RETURN_NO_ERROR; 540 } 541 542 XCamReturn 543 V4l2Device::init_buffer_pool () 544 { 545 XCamReturn ret = XCAM_RETURN_NO_ERROR; 546 uint32_t i = 0; 547 548 _buf_pool.clear (); 549 _buf_pool.reserve (_buf_count); 550 551 for (; i < _buf_count; i++) { 552 SmartPtr<V4l2Buffer> new_buf; 553 ret = allocate_buffer (new_buf, _format, i); 554 if (ret != XCAM_RETURN_NO_ERROR) { 555 break; 556 } 557 _buf_pool.push_back (new_buf); 558 } 559 560 if (_buf_pool.empty()) { 561 XCAM_LOG_ERROR ("No bufer allocated in device(%s)", XCAM_STR (_name)); 562 return XCAM_RETURN_ERROR_MEM; 563 } 564 565 if (i != _buf_count) { 566 XCAM_LOG_WARNING ( 567 "device(%s) allocate buffer count:%d failback to %d", 568 XCAM_STR (_name), _buf_count, i); 569 _buf_count = i; 570 } 571 572 return XCAM_RETURN_NO_ERROR; 573 } 574 575 XCamReturn 576 V4l2Device::fini_buffer_pool() 577 { 578 _buf_pool.clear (); 579 return XCAM_RETURN_NO_ERROR; 580 } 581 582 XCamReturn 583 V4l2Device::dequeue_buffer(SmartPtr<V4l2Buffer> &buf) 584 { 585 struct v4l2_buffer v4l2_buf; 586 587 if (!is_activated()) { 588 XCAM_LOG_DEBUG ( 589 "device(%s) dequeue buffer failed since not activated", XCAM_STR (_name)); 590 return XCAM_RETURN_ERROR_PARAM; 591 } 592 593 xcam_mem_clear (v4l2_buf); 594 v4l2_buf.type = _capture_buf_type; 595 v4l2_buf.memory = _memory_type; 596 597 if (this->io_control (VIDIOC_DQBUF, &v4l2_buf) < 0) { 598 XCAM_LOG_ERROR ("device(%s) fail to dequeue buffer.", XCAM_STR (_name)); 599 return XCAM_RETURN_ERROR_IOCTL; 600 } 601 602 XCAM_LOG_DEBUG ("device(%s) dequeue buffer index:%d", XCAM_STR (_name), v4l2_buf.index); 603 604 if (v4l2_buf.index > _buf_count) { 605 XCAM_LOG_ERROR ( 606 "device(%s) dequeue wrong buffer index:%d", 607 XCAM_STR (_name), v4l2_buf.index); 608 return XCAM_RETURN_ERROR_ISP; 609 } 610 buf = _buf_pool [v4l2_buf.index]; 611 buf->set_timestamp (v4l2_buf.timestamp); 612 buf->set_timecode (v4l2_buf.timecode); 613 buf->set_sequence (v4l2_buf.sequence); 614 //buf.set_length (v4l2_buf.length); // not necessary to set length 615 return XCAM_RETURN_NO_ERROR; 616 } 617 618 XCamReturn 619 V4l2Device::queue_buffer (SmartPtr<V4l2Buffer> &buf) 620 { 621 XCAM_ASSERT (buf.ptr()); 622 buf->reset (); 623 624 struct v4l2_buffer v4l2_buf = buf->get_buf (); 625 XCAM_ASSERT (v4l2_buf.index < _buf_count); 626 627 XCAM_LOG_DEBUG ("device(%s) queue buffer index:%d", XCAM_STR (_name), v4l2_buf.index); 628 if (io_control (VIDIOC_QBUF, &v4l2_buf) < 0) { 629 XCAM_LOG_ERROR("fail to enqueue buffer index:%d.", v4l2_buf.index); 630 return XCAM_RETURN_ERROR_IOCTL; 631 } 632 return XCAM_RETURN_NO_ERROR; 633 } 634 635 V4l2SubDevice::V4l2SubDevice (const char *name) 636 : V4l2Device (name) 637 { 638 } 639 640 XCamReturn 641 V4l2SubDevice::subscribe_event (int event) 642 { 643 struct v4l2_event_subscription sub; 644 int ret = 0; 645 646 XCAM_ASSERT (is_opened()); 647 648 xcam_mem_clear (sub); 649 sub.type = event; 650 651 ret = this->io_control (VIDIOC_SUBSCRIBE_EVENT, &sub); 652 if (ret < 0) { 653 XCAM_LOG_DEBUG ("subdev(%s) subscribe event(%d) failed", XCAM_STR(_name), event); 654 return XCAM_RETURN_ERROR_IOCTL; 655 } 656 return XCAM_RETURN_NO_ERROR; 657 } 658 659 XCamReturn 660 V4l2SubDevice::unsubscribe_event (int event) 661 { 662 struct v4l2_event_subscription sub; 663 int ret = 0; 664 665 XCAM_ASSERT (is_opened()); 666 667 xcam_mem_clear (sub); 668 sub.type = event; 669 670 ret = this->io_control (VIDIOC_UNSUBSCRIBE_EVENT, &sub); 671 if (ret < 0) { 672 XCAM_LOG_DEBUG ("subdev(%s) unsubscribe event(%d) failed", XCAM_STR(_name), event); 673 return XCAM_RETURN_ERROR_IOCTL; 674 } 675 return XCAM_RETURN_NO_ERROR; 676 } 677 678 XCamReturn 679 V4l2SubDevice::dequeue_event (struct v4l2_event &event) 680 { 681 int ret = 0; 682 XCAM_ASSERT (is_opened()); 683 684 ret = this->io_control (VIDIOC_DQEVENT, &event); 685 if (ret < 0) { 686 XCAM_LOG_DEBUG ("subdev(%s) dequeue event failed", XCAM_STR(_name)); 687 return XCAM_RETURN_ERROR_IOCTL; 688 } 689 690 return XCAM_RETURN_NO_ERROR; 691 } 692 693 XCamReturn V4l2SubDevice::start () 694 { 695 if (!is_opened()) 696 return XCAM_RETURN_ERROR_PARAM; 697 698 _active = true; 699 return XCAM_RETURN_NO_ERROR; 700 } 701 702 XCamReturn V4l2SubDevice::stop () 703 { 704 if (_active) 705 _active = false; 706 707 return XCAM_RETURN_NO_ERROR; 708 } 709 710 }; 711