1/* 2 * 3 * Copyright (C) 2008-2009 QUALCOMM Incorporated. 4 * 5 */ 6 7#include <linux/workqueue.h> 8#include <linux/delay.h> 9#include <linux/types.h> 10#include <linux/list.h> 11#include <linux/ioctl.h> 12#include <linux/spinlock.h> 13#include <linux/videodev2.h> 14#include <linux/proc_fs.h> 15#include <linux/slab.h> 16#include <media/v4l2-dev.h> 17#include <media/msm_camera.h> 18#include <mach/camera.h> 19#include <media/v4l2-ioctl.h> 20/*#include <linux/platform_device.h>*/ 21 22#define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \ 23 struct v4l2_buffer) 24 25#define MSM_V4L2_GET_PICTURE _IOWR('V', BASE_VIDIOC_PRIVATE+2, \ 26 struct v4l2_buffer) 27 28#define MSM_V4L2_DEVICE_NAME "msm_v4l2" 29 30#define MSM_V4L2_PROC_NAME "msm_v4l2" 31 32#define MSM_V4L2_DEVNUM_MPEG2 0 33#define MSM_V4L2_DEVNUM_YUV 20 34 35/* HVGA-P (portrait) and HVGA-L (landscape) */ 36#define MSM_V4L2_WIDTH 480 37#define MSM_V4L2_HEIGHT 320 38 39#define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args) 40 41#define PREVIEW_FRAMES_NUM 4 42 43struct msm_v4l2_device { 44 struct list_head read_queue; 45 struct v4l2_format current_cap_format; 46 struct v4l2_format current_pix_format; 47 struct video_device *pvdev; 48 struct msm_v4l2_driver *drv; 49 uint8_t opencnt; 50 51 spinlock_t read_queue_lock; 52}; 53 54static struct msm_v4l2_device *g_pmsm_v4l2_dev; 55 56 57static DEFINE_MUTEX(msm_v4l2_opencnt_lock); 58 59static int msm_v4l2_open(struct file *f) 60{ 61 int rc = 0; 62 D("%s\n", __func__); 63 mutex_lock(&msm_v4l2_opencnt_lock); 64 if (!g_pmsm_v4l2_dev->opencnt) { 65 rc = g_pmsm_v4l2_dev->drv->open( 66 g_pmsm_v4l2_dev->drv->sync, 67 MSM_APPS_ID_V4L2); 68 } 69 g_pmsm_v4l2_dev->opencnt++; 70 mutex_unlock(&msm_v4l2_opencnt_lock); 71 return rc; 72} 73 74static int msm_v4l2_release(struct file *f) 75{ 76 int rc = 0; 77 D("%s\n", __func__); 78 mutex_lock(&msm_v4l2_opencnt_lock); 79 if (!g_pmsm_v4l2_dev->opencnt) { 80 g_pmsm_v4l2_dev->opencnt--; 81 if (!g_pmsm_v4l2_dev->opencnt) { 82 rc = g_pmsm_v4l2_dev->drv->release( 83 g_pmsm_v4l2_dev->drv->sync); 84 } 85 } 86 mutex_unlock(&msm_v4l2_opencnt_lock); 87 return rc; 88} 89 90static unsigned int msm_v4l2_poll(struct file *f, struct poll_table_struct *w) 91{ 92 return g_pmsm_v4l2_dev->drv->drv_poll(g_pmsm_v4l2_dev->drv->sync, f, w); 93} 94 95static long msm_v4l2_ioctl(struct file *filep, 96 unsigned int cmd, unsigned long arg) 97{ 98 struct msm_ctrl_cmd *ctrlcmd; 99 100 D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd, __LINE__); 101 102 switch (cmd) { 103 case MSM_V4L2_START_SNAPSHOT: 104 105 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 106 if (!ctrlcmd) { 107 CDBG("msm_v4l2_ioctl: cannot allocate buffer\n"); 108 return -ENOMEM; 109 } 110 111 ctrlcmd->length = 0; 112 ctrlcmd->value = NULL; 113 ctrlcmd->timeout_ms = 10000; 114 115 D("msm_v4l2_ioctl, MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n", 116 cmd); 117 ctrlcmd->type = MSM_V4L2_SNAPSHOT; 118 return g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, 119 ctrlcmd); 120 121 case MSM_V4L2_GET_PICTURE: 122 D("msm_v4l2_ioctl, MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd); 123 ctrlcmd = (struct msm_ctrl_cmd *)arg; 124 return g_pmsm_v4l2_dev->drv->get_pict( 125 g_pmsm_v4l2_dev->drv->sync, ctrlcmd); 126 127 default: 128 D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd); 129 return video_ioctl2(filep, cmd, arg); 130 } 131} 132 133static void msm_v4l2_release_dev(struct video_device *d) 134{ 135 D("%s\n", __func__); 136} 137 138static int msm_v4l2_querycap(struct file *f, 139 void *pctx, struct v4l2_capability *pcaps) 140{ 141 D("%s\n", __func__); 142 strncpy(pcaps->driver, MSM_APPS_ID_V4L2, sizeof(pcaps->driver)); 143 strncpy(pcaps->card, 144 MSM_V4L2_DEVICE_NAME, sizeof(pcaps->card)); 145 pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 146 return 0; 147} 148 149static int msm_v4l2_s_std(struct file *f, void *pctx, v4l2_std_id *pnorm) 150{ 151 D("%s\n", __func__); 152 return 0; 153} 154 155static int msm_v4l2_queryctrl(struct file *f, 156 void *pctx, struct v4l2_queryctrl *pqctrl) 157{ 158 int rc = 0; 159 struct msm_ctrl_cmd *ctrlcmd; 160 161 D("%s\n", __func__); 162 163 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 164 if (!ctrlcmd) { 165 CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n"); 166 return -ENOMEM; 167 } 168 169 ctrlcmd->type = MSM_V4L2_QUERY_CTRL; 170 ctrlcmd->length = sizeof(struct v4l2_queryctrl); 171 ctrlcmd->value = pqctrl; 172 ctrlcmd->timeout_ms = 10000; 173 174 rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); 175 if (rc < 0) 176 return -1; 177 178 return ctrlcmd->status; 179} 180 181static int msm_v4l2_g_ctrl(struct file *f, void *pctx, struct v4l2_control *c) 182{ 183 int rc = 0; 184 struct msm_ctrl_cmd *ctrlcmd; 185 186 D("%s\n", __func__); 187 188 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 189 if (!ctrlcmd) { 190 CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n"); 191 return -ENOMEM; 192 } 193 194 ctrlcmd->type = MSM_V4L2_GET_CTRL; 195 ctrlcmd->length = sizeof(struct v4l2_control); 196 ctrlcmd->value = c; 197 ctrlcmd->timeout_ms = 10000; 198 199 rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); 200 if (rc < 0) 201 return -1; 202 203 return ctrlcmd->status; 204} 205 206static int msm_v4l2_s_ctrl(struct file *f, void *pctx, struct v4l2_control *c) 207{ 208 int rc = 0; 209 struct msm_ctrl_cmd *ctrlcmd; 210 211 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 212 if (!ctrlcmd) { 213 CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n"); 214 return -ENOMEM; 215 } 216 217 ctrlcmd->type = MSM_V4L2_SET_CTRL; 218 ctrlcmd->length = sizeof(struct v4l2_control); 219 ctrlcmd->value = c; 220 ctrlcmd->timeout_ms = 10000; 221 222 D("%s\n", __func__); 223 224 rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); 225 if (rc < 0) 226 return -1; 227 228 return ctrlcmd->status; 229} 230 231static int msm_v4l2_reqbufs(struct file *f, 232 void *pctx, struct v4l2_requestbuffers *b) 233{ 234 D("%s\n", __func__); 235 return 0; 236} 237 238static int msm_v4l2_querybuf(struct file *f, void *pctx, struct v4l2_buffer *pb) 239{ 240 struct msm_pmem_info pmem_buf; 241 242 __u32 y_pad = pb->bytesused % 4; 243 244 /* V4L2 videodev will do the copy_from_user. */ 245 246 memset(&pmem_buf, 0, sizeof(struct msm_pmem_info)); 247 pmem_buf.type = MSM_PMEM_OUTPUT2; 248 pmem_buf.vaddr = (void *)pb->m.userptr; 249 pmem_buf.y_off = 0; 250 pmem_buf.fd = (int)pb->reserved; 251 /* pmem_buf.cbcr_off = (y_size + y_pad); */ 252 pmem_buf.cbcr_off = (pb->bytesused + y_pad); 253 254 g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, &pmem_buf); 255 256 return 0; 257} 258 259static int msm_v4l2_qbuf(struct file *f, void *pctx, struct v4l2_buffer *pb) 260{ 261 /* 262 __u32 y_size = 0; 263 __u32 y_pad = 0; 264 __u32 width = 0; 265 __u32 height = 0; 266 */ 267 268 __u32 y_pad = 0; 269 270 struct msm_pmem_info meminfo; 271 struct msm_frame frame; 272 static int cnt; 273 274 if ((pb->flags >> 16) & 0x0001) { 275 /* this is for previwe */ 276 277 y_pad = pb->bytesused % 4; 278 279 if (pb->type == V4L2_BUF_TYPE_PRIVATE) { 280 /* this qbuf is actually for releasing */ 281 282 frame.buffer = pb->m.userptr; 283 frame.y_off = 0; 284 /* frame.cbcr_off = (y_size + y_pad); */ 285 frame.cbcr_off = (pb->bytesused + y_pad); 286 frame.fd = pb->reserved; 287 288 D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n", 289 pb->bytesused); 290 291 g_pmsm_v4l2_dev->drv->put_frame( 292 g_pmsm_v4l2_dev->drv->sync, 293 &frame); 294 295 return 0; 296 } 297 298 D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n", 299 pb->bytesused); 300 301 meminfo.type = MSM_PMEM_OUTPUT2; 302 meminfo.fd = (int)pb->reserved; 303 meminfo.vaddr = (void *)pb->m.userptr; 304 meminfo.y_off = 0; 305 /* meminfo.cbcr_off = (y_size + y_pad); */ 306 meminfo.cbcr_off = (pb->bytesused + y_pad); 307 if (cnt == PREVIEW_FRAMES_NUM - 1) 308 meminfo.active = 0; 309 else 310 meminfo.active = 1; 311 cnt++; 312 g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, 313 &meminfo); 314 } else if ((pb->flags) & 0x0001) { 315 /* this is for snapshot */ 316 317 __u32 y_size = 0; 318 319 if ((pb->flags >> 8) & 0x01) { 320 321 y_size = pb->bytesused; 322 323 meminfo.type = MSM_PMEM_THUMBAIL; 324 } else if ((pb->flags >> 9) & 0x01) { 325 326 y_size = pb->bytesused; 327 328 meminfo.type = MSM_PMEM_MAINIMG; 329 } 330 331 y_pad = y_size % 4; 332 333 meminfo.fd = (int)pb->reserved; 334 meminfo.vaddr = (void *)pb->m.userptr; 335 meminfo.y_off = 0; 336 /* meminfo.cbcr_off = (y_size + y_pad); */ 337 meminfo.cbcr_off = (y_size + y_pad); 338 meminfo.active = 1; 339 g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, 340 &meminfo); 341 } 342 343 return 0; 344} 345 346static int msm_v4l2_dqbuf(struct file *f, void *pctx, struct v4l2_buffer *pb) 347{ 348 struct msm_frame frame; 349 D("%s\n", __func__); 350 351 /* V4L2 videodev will do the copy_to_user. */ 352 if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 353 354 D("%s, %d\n", __func__, __LINE__); 355 356 g_pmsm_v4l2_dev->drv->get_frame( 357 g_pmsm_v4l2_dev->drv->sync, 358 &frame); 359 360 pb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 361 pb->m.userptr = (unsigned long)frame.buffer; 362 pb->reserved = (int)frame.fd; 363 /* pb->length = (int)frame.cbcr_off; */ 364 365 pb->bytesused = frame.cbcr_off; 366 367 } else if (pb->type == V4L2_BUF_TYPE_PRIVATE) { 368 __u32 y_pad = pb->bytesused % 4; 369 370 frame.buffer = pb->m.userptr; 371 frame.y_off = 0; 372 /* frame.cbcr_off = (y_size + y_pad); */ 373 frame.cbcr_off = (pb->bytesused + y_pad); 374 frame.fd = pb->reserved; 375 376 g_pmsm_v4l2_dev->drv->put_frame( 377 g_pmsm_v4l2_dev->drv->sync, 378 &frame); 379 } 380 381 return 0; 382} 383 384static int msm_v4l2_streamon(struct file *f, void *pctx, enum v4l2_buf_type i) 385{ 386 struct msm_ctrl_cmd *ctrlcmd; 387 388 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 389 if (!ctrlcmd) { 390 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n"); 391 return -ENOMEM; 392 } 393 394 ctrlcmd->type = MSM_V4L2_STREAM_ON; 395 ctrlcmd->timeout_ms = 10000; 396 ctrlcmd->length = 0; 397 ctrlcmd->value = NULL; 398 399 D("%s\n", __func__); 400 401 g_pmsm_v4l2_dev->drv->ctrl( 402 g_pmsm_v4l2_dev->drv->sync, 403 ctrlcmd); 404 405 D("%s after drv->ctrl \n", __func__); 406 407 return 0; 408} 409 410static int msm_v4l2_streamoff(struct file *f, void *pctx, enum v4l2_buf_type i) 411{ 412 struct msm_ctrl_cmd *ctrlcmd; 413 414 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 415 if (!ctrlcmd) { 416 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n"); 417 return -ENOMEM; 418 } 419 420 ctrlcmd->type = MSM_V4L2_STREAM_OFF; 421 ctrlcmd->timeout_ms = 10000; 422 ctrlcmd->length = 0; 423 ctrlcmd->value = NULL; 424 425 426 D("%s\n", __func__); 427 428 g_pmsm_v4l2_dev->drv->ctrl( 429 g_pmsm_v4l2_dev->drv->sync, 430 ctrlcmd); 431 432 return 0; 433} 434 435static int msm_v4l2_enum_fmt_overlay(struct file *f, 436 void *pctx, struct v4l2_fmtdesc *pfmtdesc) 437{ 438 D("%s\n", __func__); 439 return 0; 440} 441 442static int msm_v4l2_enum_fmt_cap(struct file *f, 443 void *pctx, struct v4l2_fmtdesc *pfmtdesc) 444{ 445 D("%s\n", __func__); 446 447 switch (pfmtdesc->index) { 448 case 0: 449 pfmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 450 pfmtdesc->flags = 0; 451 strncpy(pfmtdesc->description, "YUV 4:2:0", 452 sizeof(pfmtdesc->description)); 453 pfmtdesc->pixelformat = V4L2_PIX_FMT_YVU420; 454 break; 455 default: 456 return -EINVAL; 457 } 458 459 return 0; 460} 461 462static int msm_v4l2_g_fmt_cap(struct file *f, 463 void *pctx, struct v4l2_format *pfmt) 464{ 465 D("%s\n", __func__); 466 pfmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 467 pfmt->fmt.pix.width = MSM_V4L2_WIDTH; 468 pfmt->fmt.pix.height = MSM_V4L2_HEIGHT; 469 pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420; 470 pfmt->fmt.pix.field = V4L2_FIELD_ANY; 471 pfmt->fmt.pix.bytesperline = 0; 472 pfmt->fmt.pix.sizeimage = 0; 473 pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 474 pfmt->fmt.pix.priv = 0; 475 return 0; 476} 477 478static int msm_v4l2_s_fmt_cap(struct file *f, 479 void *pctx, struct v4l2_format *pfmt) 480{ 481 struct msm_ctrl_cmd *ctrlcmd; 482 483 D("%s\n", __func__); 484 485 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC); 486 if (!ctrlcmd) { 487 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n"); 488 return -ENOMEM; 489 } 490 491 ctrlcmd->type = MSM_V4L2_VID_CAP_TYPE; 492 ctrlcmd->length = sizeof(struct v4l2_format); 493 ctrlcmd->value = pfmt; 494 ctrlcmd->timeout_ms = 10000; 495 496 if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { 497 kfree(ctrlcmd); 498 return -1; 499 } 500 501 502 /* Ok, but check other params, too. */ 503 504 505 g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd); 506 507 return 0; 508} 509 510static int msm_v4l2_g_fmt_overlay(struct file *f, 511 void *pctx, struct v4l2_format *pfmt) 512{ 513 D("%s\n", __func__); 514 pfmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 515 pfmt->fmt.pix.width = MSM_V4L2_WIDTH; 516 pfmt->fmt.pix.height = MSM_V4L2_HEIGHT; 517 pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420; 518 pfmt->fmt.pix.field = V4L2_FIELD_ANY; 519 pfmt->fmt.pix.bytesperline = 0; 520 pfmt->fmt.pix.sizeimage = 0; 521 pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 522 pfmt->fmt.pix.priv = 0; 523 return 0; 524} 525 526static int msm_v4l2_s_fmt_overlay(struct file *f, 527 void *pctx, struct v4l2_format *pfmt) 528{ 529 D("%s\n", __func__); 530 return 0; 531} 532 533static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i) 534{ 535 D("%s\n", __func__); 536 return 0; 537} 538 539static int msm_v4l2_g_jpegcomp(struct file *f, 540 void *pctx, struct v4l2_jpegcompression *pcomp) 541{ 542 D("%s\n", __func__); 543 return 0; 544} 545 546static int msm_v4l2_s_jpegcomp(struct file *f, 547 void *pctx, struct v4l2_jpegcompression *pcomp) 548{ 549 D("%s\n", __func__); 550 return 0; 551} 552 553#ifdef CONFIG_PROC_FS 554int msm_v4l2_read_proc(char *pbuf, char **start, off_t offset, 555 int count, int *eof, void *data) 556{ 557 int len = 0; 558 len += snprintf(pbuf, strlen("stats\n") + 1, "stats\n"); 559 560 if (g_pmsm_v4l2_dev) { 561 len += snprintf(pbuf, strlen("mode: ") + 1, "mode: "); 562 563 if (g_pmsm_v4l2_dev->current_cap_format.type 564 == V4L2_BUF_TYPE_VIDEO_CAPTURE) 565 len += snprintf(pbuf, strlen("capture\n") + 1, 566 "capture\n"); 567 else 568 len += snprintf(pbuf, strlen("unknown\n") + 1, 569 "unknown\n"); 570 571 len += snprintf(pbuf, 21, "resolution: %dx%d\n", 572 g_pmsm_v4l2_dev->current_cap_format.fmt.pix. 573 width, 574 g_pmsm_v4l2_dev->current_cap_format.fmt.pix. 575 height); 576 577 len += snprintf(pbuf, 578 strlen("pixel format: ") + 1, "pixel format: "); 579 if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.pixelformat 580 == V4L2_PIX_FMT_YVU420) 581 len += snprintf(pbuf, strlen("yvu420\n") + 1, 582 "yvu420\n"); 583 else 584 len += snprintf(pbuf, strlen("unknown\n") + 1, 585 "unknown\n"); 586 587 len += snprintf(pbuf, strlen("colorspace: ") + 1, 588 "colorspace: "); 589 if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.colorspace 590 == V4L2_COLORSPACE_JPEG) 591 len += snprintf(pbuf, strlen("jpeg\n") + 1, "jpeg\n"); 592 else 593 len += snprintf(pbuf, strlen("unknown\n") + 1, 594 "unknown\n"); 595 } 596 597 *eof = 1; 598 return len; 599} 600#endif 601 602static const struct v4l2_file_operations msm_v4l2_fops = { 603 .owner = THIS_MODULE, 604 .open = msm_v4l2_open, 605 .poll = msm_v4l2_poll, 606 .release = msm_v4l2_release, 607 .ioctl = msm_v4l2_ioctl, 608}; 609 610static void msm_v4l2_dev_init(struct msm_v4l2_device *pmsm_v4l2_dev) 611{ 612 pmsm_v4l2_dev->read_queue_lock = 613 __SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev->read_queue_lock); 614 INIT_LIST_HEAD(&pmsm_v4l2_dev->read_queue); 615} 616 617static int msm_v4l2_try_fmt_cap(struct file *file, 618 void *fh, struct v4l2_format *f) 619{ 620 return 0; 621} 622 623static int mm_v4l2_try_fmt_type_private(struct file *file, 624 void *fh, struct v4l2_format *f) 625{ 626 return 0; 627} 628 629/* 630 * should the following structure be used instead of the code in the function? 631 * static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = { 632 * .vidioc_querycap = .... 633 * } 634 */ 635static const struct v4l2_ioctl_ops msm_ioctl_ops = { 636 .vidioc_querycap = msm_v4l2_querycap, 637 .vidioc_s_std = msm_v4l2_s_std, 638 639 .vidioc_queryctrl = msm_v4l2_queryctrl, 640 .vidioc_g_ctrl = msm_v4l2_g_ctrl, 641 .vidioc_s_ctrl = msm_v4l2_s_ctrl, 642 643 .vidioc_reqbufs = msm_v4l2_reqbufs, 644 .vidioc_querybuf = msm_v4l2_querybuf, 645 .vidioc_qbuf = msm_v4l2_qbuf, 646 .vidioc_dqbuf = msm_v4l2_dqbuf, 647 648 .vidioc_streamon = msm_v4l2_streamon, 649 .vidioc_streamoff = msm_v4l2_streamoff, 650 651 .vidioc_enum_fmt_vid_overlay = msm_v4l2_enum_fmt_overlay, 652 .vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt_cap, 653 654 .vidioc_try_fmt_vid_cap = msm_v4l2_try_fmt_cap, 655 .vidioc_try_fmt_type_private = mm_v4l2_try_fmt_type_private, 656 657 .vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt_cap, 658 .vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt_cap, 659 .vidioc_g_fmt_vid_overlay = msm_v4l2_g_fmt_overlay, 660 .vidioc_s_fmt_vid_overlay = msm_v4l2_s_fmt_overlay, 661 .vidioc_overlay = msm_v4l2_overlay, 662 663 .vidioc_g_jpegcomp = msm_v4l2_g_jpegcomp, 664 .vidioc_s_jpegcomp = msm_v4l2_s_jpegcomp, 665}; 666 667static int msm_v4l2_video_dev_init(struct video_device *pvd) 668{ 669 strncpy(pvd->name, MSM_APPS_ID_V4L2, sizeof(pvd->name)); 670 pvd->vfl_type = 1; 671 pvd->fops = &msm_v4l2_fops; 672 pvd->release = msm_v4l2_release_dev; 673 pvd->minor = -1; 674 pvd->ioctl_ops = &msm_ioctl_ops; 675 return msm_v4l2_register(g_pmsm_v4l2_dev->drv); 676} 677 678static int __init msm_v4l2_init(void) 679{ 680 int rc = -ENOMEM; 681 struct video_device *pvdev = NULL; 682 struct msm_v4l2_device *pmsm_v4l2_dev = NULL; 683 D("%s\n", __func__); 684 685 pvdev = video_device_alloc(); 686 if (pvdev == NULL) 687 return rc; 688 689 pmsm_v4l2_dev = 690 kzalloc(sizeof(struct msm_v4l2_device), GFP_KERNEL); 691 if (pmsm_v4l2_dev == NULL) { 692 video_device_release(pvdev); 693 return rc; 694 } 695 696 msm_v4l2_dev_init(pmsm_v4l2_dev); 697 698 g_pmsm_v4l2_dev = pmsm_v4l2_dev; 699 g_pmsm_v4l2_dev->pvdev = pvdev; 700 701 g_pmsm_v4l2_dev->drv = 702 kzalloc(sizeof(struct msm_v4l2_driver), GFP_KERNEL); 703 if (!g_pmsm_v4l2_dev->drv) { 704 video_device_release(pvdev); 705 kfree(pmsm_v4l2_dev); 706 return rc; 707 } 708 709 rc = msm_v4l2_video_dev_init(pvdev); 710 if (rc < 0) { 711 video_device_release(pvdev); 712 kfree(g_pmsm_v4l2_dev->drv); 713 kfree(pmsm_v4l2_dev); 714 return rc; 715 } 716 717 if (video_register_device(pvdev, VFL_TYPE_GRABBER, 718 MSM_V4L2_DEVNUM_YUV)) { 719 D("failed to register device\n"); 720 video_device_release(pvdev); 721 kfree(g_pmsm_v4l2_dev); 722 g_pmsm_v4l2_dev = NULL; 723 return -ENOENT; 724 } 725#ifdef CONFIG_PROC_FS 726 create_proc_read_entry(MSM_V4L2_PROC_NAME, 727 0, NULL, msm_v4l2_read_proc, NULL); 728#endif 729 730 return 0; 731} 732 733static void __exit msm_v4l2_exit(void) 734{ 735 struct video_device *pvdev = g_pmsm_v4l2_dev->pvdev; 736 D("%s\n", __func__); 737#ifdef CONFIG_PROC_FS 738 remove_proc_entry(MSM_V4L2_PROC_NAME, NULL); 739#endif 740 video_unregister_device(pvdev); 741 video_device_release(pvdev); 742 743 msm_v4l2_unregister(g_pmsm_v4l2_dev->drv); 744 745 kfree(g_pmsm_v4l2_dev->drv); 746 g_pmsm_v4l2_dev->drv = NULL; 747 748 kfree(g_pmsm_v4l2_dev); 749 g_pmsm_v4l2_dev = NULL; 750} 751 752module_init(msm_v4l2_init); 753module_exit(msm_v4l2_exit); 754 755MODULE_DESCRIPTION("MSM V4L2 driver"); 756MODULE_LICENSE("GPL v2"); 757