Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc5 880 lines 21 kB view raw
1/* 2 * timblogiw.c timberdale FPGA LogiWin Video In driver 3 * Copyright (c) 2009-2010 Intel Corporation 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19/* Supports: 20 * Timberdale FPGA LogiWin Video In 21 */ 22 23#include <linux/platform_device.h> 24#include <linux/slab.h> 25#include <linux/dmaengine.h> 26#include <linux/scatterlist.h> 27#include <linux/interrupt.h> 28#include <linux/list.h> 29#include <linux/i2c.h> 30#include <linux/module.h> 31#include <media/v4l2-ioctl.h> 32#include <media/v4l2-device.h> 33#include <media/videobuf-dma-contig.h> 34#include <media/timb_video.h> 35 36#define DRIVER_NAME "timb-video" 37 38#define TIMBLOGIWIN_NAME "Timberdale Video-In" 39#define TIMBLOGIW_VERSION_CODE 0x04 40 41#define TIMBLOGIW_LINES_PER_DESC 44 42#define TIMBLOGIW_MAX_VIDEO_MEM 16 43 44#define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name) 45 46 47struct timblogiw { 48 struct video_device video_dev; 49 struct v4l2_device v4l2_dev; /* mutual exclusion */ 50 struct mutex lock; 51 struct device *dev; 52 struct timb_video_platform_data pdata; 53 struct v4l2_subdev *sd_enc; /* encoder */ 54 bool opened; 55}; 56 57struct timblogiw_tvnorm { 58 v4l2_std_id std; 59 u16 width; 60 u16 height; 61 u8 fps; 62}; 63 64struct timblogiw_fh { 65 struct videobuf_queue vb_vidq; 66 struct timblogiw_tvnorm const *cur_norm; 67 struct list_head capture; 68 struct dma_chan *chan; 69 spinlock_t queue_lock; /* mutual exclusion */ 70 unsigned int frame_count; 71}; 72 73struct timblogiw_buffer { 74 /* common v4l buffer stuff -- must be first */ 75 struct videobuf_buffer vb; 76 struct scatterlist sg[16]; 77 dma_cookie_t cookie; 78 struct timblogiw_fh *fh; 79}; 80 81const struct timblogiw_tvnorm timblogiw_tvnorms[] = { 82 { 83 .std = V4L2_STD_PAL, 84 .width = 720, 85 .height = 576, 86 .fps = 25 87 }, 88 { 89 .std = V4L2_STD_NTSC, 90 .width = 720, 91 .height = 480, 92 .fps = 30 93 } 94}; 95 96static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm) 97{ 98 return norm->width * 2; 99} 100 101 102static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm) 103{ 104 return norm->height * timblogiw_bytes_per_line(norm); 105} 106 107static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std) 108{ 109 int i; 110 for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) 111 if (timblogiw_tvnorms[i].std & std) 112 return timblogiw_tvnorms + i; 113 114 /* default to first element */ 115 return timblogiw_tvnorms; 116} 117 118static void timblogiw_dma_cb(void *data) 119{ 120 struct timblogiw_buffer *buf = data; 121 struct timblogiw_fh *fh = buf->fh; 122 struct videobuf_buffer *vb = &buf->vb; 123 124 spin_lock(&fh->queue_lock); 125 126 /* mark the transfer done */ 127 buf->cookie = -1; 128 129 fh->frame_count++; 130 131 if (vb->state != VIDEOBUF_ERROR) { 132 list_del(&vb->queue); 133 do_gettimeofday(&vb->ts); 134 vb->field_count = fh->frame_count * 2; 135 vb->state = VIDEOBUF_DONE; 136 137 wake_up(&vb->done); 138 } 139 140 if (!list_empty(&fh->capture)) { 141 vb = list_entry(fh->capture.next, struct videobuf_buffer, 142 queue); 143 vb->state = VIDEOBUF_ACTIVE; 144 } 145 146 spin_unlock(&fh->queue_lock); 147} 148 149static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param) 150{ 151 return chan->chan_id == (uintptr_t)filter_param; 152} 153 154/* IOCTL functions */ 155 156static int timblogiw_g_fmt(struct file *file, void *priv, 157 struct v4l2_format *format) 158{ 159 struct video_device *vdev = video_devdata(file); 160 struct timblogiw *lw = video_get_drvdata(vdev); 161 struct timblogiw_fh *fh = priv; 162 163 dev_dbg(&vdev->dev, "%s entry\n", __func__); 164 165 if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 166 return -EINVAL; 167 168 mutex_lock(&lw->lock); 169 170 format->fmt.pix.width = fh->cur_norm->width; 171 format->fmt.pix.height = fh->cur_norm->height; 172 format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 173 format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm); 174 format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm); 175 format->fmt.pix.field = V4L2_FIELD_NONE; 176 177 mutex_unlock(&lw->lock); 178 179 return 0; 180} 181 182static int timblogiw_try_fmt(struct file *file, void *priv, 183 struct v4l2_format *format) 184{ 185 struct video_device *vdev = video_devdata(file); 186 struct v4l2_pix_format *pix = &format->fmt.pix; 187 188 dev_dbg(&vdev->dev, 189 "%s - width=%d, height=%d, pixelformat=%d, field=%d\n" 190 "bytes per line %d, size image: %d, colorspace: %d\n", 191 __func__, 192 pix->width, pix->height, pix->pixelformat, pix->field, 193 pix->bytesperline, pix->sizeimage, pix->colorspace); 194 195 if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 196 return -EINVAL; 197 198 if (pix->field != V4L2_FIELD_NONE) 199 return -EINVAL; 200 201 if (pix->pixelformat != V4L2_PIX_FMT_UYVY) 202 return -EINVAL; 203 204 return 0; 205} 206 207static int timblogiw_s_fmt(struct file *file, void *priv, 208 struct v4l2_format *format) 209{ 210 struct video_device *vdev = video_devdata(file); 211 struct timblogiw *lw = video_get_drvdata(vdev); 212 struct timblogiw_fh *fh = priv; 213 struct v4l2_pix_format *pix = &format->fmt.pix; 214 int err; 215 216 mutex_lock(&lw->lock); 217 218 err = timblogiw_try_fmt(file, priv, format); 219 if (err) 220 goto out; 221 222 if (videobuf_queue_is_busy(&fh->vb_vidq)) { 223 dev_err(&vdev->dev, "%s queue busy\n", __func__); 224 err = -EBUSY; 225 goto out; 226 } 227 228 pix->width = fh->cur_norm->width; 229 pix->height = fh->cur_norm->height; 230 231out: 232 mutex_unlock(&lw->lock); 233 return err; 234} 235 236static int timblogiw_querycap(struct file *file, void *priv, 237 struct v4l2_capability *cap) 238{ 239 struct video_device *vdev = video_devdata(file); 240 241 dev_dbg(&vdev->dev, "%s: Entry\n", __func__); 242 memset(cap, 0, sizeof(*cap)); 243 strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1); 244 strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1); 245 strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info)); 246 cap->version = TIMBLOGIW_VERSION_CODE; 247 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | 248 V4L2_CAP_READWRITE; 249 250 return 0; 251} 252 253static int timblogiw_enum_fmt(struct file *file, void *priv, 254 struct v4l2_fmtdesc *fmt) 255{ 256 struct video_device *vdev = video_devdata(file); 257 258 dev_dbg(&vdev->dev, "%s, index: %d\n", __func__, fmt->index); 259 260 if (fmt->index != 0) 261 return -EINVAL; 262 memset(fmt, 0, sizeof(*fmt)); 263 fmt->index = 0; 264 fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 265 strncpy(fmt->description, "4:2:2, packed, YUYV", 266 sizeof(fmt->description)-1); 267 fmt->pixelformat = V4L2_PIX_FMT_UYVY; 268 269 return 0; 270} 271 272static int timblogiw_g_parm(struct file *file, void *priv, 273 struct v4l2_streamparm *sp) 274{ 275 struct timblogiw_fh *fh = priv; 276 struct v4l2_captureparm *cp = &sp->parm.capture; 277 278 cp->capability = V4L2_CAP_TIMEPERFRAME; 279 cp->timeperframe.numerator = 1; 280 cp->timeperframe.denominator = fh->cur_norm->fps; 281 282 return 0; 283} 284 285static int timblogiw_reqbufs(struct file *file, void *priv, 286 struct v4l2_requestbuffers *rb) 287{ 288 struct video_device *vdev = video_devdata(file); 289 struct timblogiw_fh *fh = priv; 290 291 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 292 293 return videobuf_reqbufs(&fh->vb_vidq, rb); 294} 295 296static int timblogiw_querybuf(struct file *file, void *priv, 297 struct v4l2_buffer *b) 298{ 299 struct video_device *vdev = video_devdata(file); 300 struct timblogiw_fh *fh = priv; 301 302 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 303 304 return videobuf_querybuf(&fh->vb_vidq, b); 305} 306 307static int timblogiw_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) 308{ 309 struct video_device *vdev = video_devdata(file); 310 struct timblogiw_fh *fh = priv; 311 312 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 313 314 return videobuf_qbuf(&fh->vb_vidq, b); 315} 316 317static int timblogiw_dqbuf(struct file *file, void *priv, 318 struct v4l2_buffer *b) 319{ 320 struct video_device *vdev = video_devdata(file); 321 struct timblogiw_fh *fh = priv; 322 323 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 324 325 return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); 326} 327 328static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std) 329{ 330 struct video_device *vdev = video_devdata(file); 331 struct timblogiw_fh *fh = priv; 332 333 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 334 335 *std = fh->cur_norm->std; 336 return 0; 337} 338 339static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std) 340{ 341 struct video_device *vdev = video_devdata(file); 342 struct timblogiw *lw = video_get_drvdata(vdev); 343 struct timblogiw_fh *fh = priv; 344 int err = 0; 345 346 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 347 348 mutex_lock(&lw->lock); 349 350 if (TIMBLOGIW_HAS_DECODER(lw)) 351 err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std); 352 353 if (!err) 354 fh->cur_norm = timblogiw_get_norm(*std); 355 356 mutex_unlock(&lw->lock); 357 358 return err; 359} 360 361static int timblogiw_enuminput(struct file *file, void *priv, 362 struct v4l2_input *inp) 363{ 364 struct video_device *vdev = video_devdata(file); 365 int i; 366 367 dev_dbg(&vdev->dev, "%s: Entry\n", __func__); 368 369 if (inp->index != 0) 370 return -EINVAL; 371 372 inp->index = 0; 373 374 strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1); 375 inp->type = V4L2_INPUT_TYPE_CAMERA; 376 377 inp->std = 0; 378 for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) 379 inp->std |= timblogiw_tvnorms[i].std; 380 381 return 0; 382} 383 384static int timblogiw_g_input(struct file *file, void *priv, 385 unsigned int *input) 386{ 387 struct video_device *vdev = video_devdata(file); 388 389 dev_dbg(&vdev->dev, "%s: Entry\n", __func__); 390 391 *input = 0; 392 393 return 0; 394} 395 396static int timblogiw_s_input(struct file *file, void *priv, unsigned int input) 397{ 398 struct video_device *vdev = video_devdata(file); 399 400 dev_dbg(&vdev->dev, "%s: Entry\n", __func__); 401 402 if (input != 0) 403 return -EINVAL; 404 return 0; 405} 406 407static int timblogiw_streamon(struct file *file, void *priv, unsigned int type) 408{ 409 struct video_device *vdev = video_devdata(file); 410 struct timblogiw_fh *fh = priv; 411 412 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 413 414 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { 415 dev_dbg(&vdev->dev, "%s - No capture device\n", __func__); 416 return -EINVAL; 417 } 418 419 fh->frame_count = 0; 420 return videobuf_streamon(&fh->vb_vidq); 421} 422 423static int timblogiw_streamoff(struct file *file, void *priv, 424 unsigned int type) 425{ 426 struct video_device *vdev = video_devdata(file); 427 struct timblogiw_fh *fh = priv; 428 429 dev_dbg(&vdev->dev, "%s entry\n", __func__); 430 431 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 432 return -EINVAL; 433 434 return videobuf_streamoff(&fh->vb_vidq); 435} 436 437static int timblogiw_querystd(struct file *file, void *priv, v4l2_std_id *std) 438{ 439 struct video_device *vdev = video_devdata(file); 440 struct timblogiw *lw = video_get_drvdata(vdev); 441 struct timblogiw_fh *fh = priv; 442 443 dev_dbg(&vdev->dev, "%s entry\n", __func__); 444 445 if (TIMBLOGIW_HAS_DECODER(lw)) 446 return v4l2_subdev_call(lw->sd_enc, video, querystd, std); 447 else { 448 *std = fh->cur_norm->std; 449 return 0; 450 } 451} 452 453static int timblogiw_enum_framesizes(struct file *file, void *priv, 454 struct v4l2_frmsizeenum *fsize) 455{ 456 struct video_device *vdev = video_devdata(file); 457 struct timblogiw_fh *fh = priv; 458 459 dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n", __func__, 460 fsize->index, fsize->pixel_format); 461 462 if ((fsize->index != 0) || 463 (fsize->pixel_format != V4L2_PIX_FMT_UYVY)) 464 return -EINVAL; 465 466 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 467 fsize->discrete.width = fh->cur_norm->width; 468 fsize->discrete.height = fh->cur_norm->height; 469 470 return 0; 471} 472 473/* Video buffer functions */ 474 475static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, 476 unsigned int *size) 477{ 478 struct timblogiw_fh *fh = vq->priv_data; 479 480 *size = timblogiw_frame_size(fh->cur_norm); 481 482 if (!*count) 483 *count = 32; 484 485 while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024) 486 (*count)--; 487 488 return 0; 489} 490 491static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, 492 enum v4l2_field field) 493{ 494 struct timblogiw_fh *fh = vq->priv_data; 495 struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, 496 vb); 497 unsigned int data_size = timblogiw_frame_size(fh->cur_norm); 498 int err = 0; 499 500 if (vb->baddr && vb->bsize < data_size) 501 /* User provided buffer, but it is too small */ 502 return -ENOMEM; 503 504 vb->size = data_size; 505 vb->width = fh->cur_norm->width; 506 vb->height = fh->cur_norm->height; 507 vb->field = field; 508 509 if (vb->state == VIDEOBUF_NEEDS_INIT) { 510 int i; 511 unsigned int size; 512 unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * 513 timblogiw_bytes_per_line(fh->cur_norm); 514 dma_addr_t addr; 515 516 sg_init_table(buf->sg, ARRAY_SIZE(buf->sg)); 517 518 err = videobuf_iolock(vq, vb, NULL); 519 if (err) 520 goto err; 521 522 addr = videobuf_to_dma_contig(vb); 523 for (i = 0, size = 0; size < data_size; i++) { 524 sg_dma_address(buf->sg + i) = addr + size; 525 size += bytes_per_desc; 526 sg_dma_len(buf->sg + i) = (size > data_size) ? 527 (bytes_per_desc - (size - data_size)) : 528 bytes_per_desc; 529 } 530 531 vb->state = VIDEOBUF_PREPARED; 532 buf->cookie = -1; 533 buf->fh = fh; 534 } 535 536 return 0; 537 538err: 539 videobuf_dma_contig_free(vq, vb); 540 vb->state = VIDEOBUF_NEEDS_INIT; 541 return err; 542} 543 544static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) 545{ 546 struct timblogiw_fh *fh = vq->priv_data; 547 struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, 548 vb); 549 struct dma_async_tx_descriptor *desc; 550 int sg_elems; 551 int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * 552 timblogiw_bytes_per_line(fh->cur_norm); 553 554 sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc; 555 sg_elems += 556 (timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0; 557 558 if (list_empty(&fh->capture)) 559 vb->state = VIDEOBUF_ACTIVE; 560 else 561 vb->state = VIDEOBUF_QUEUED; 562 563 list_add_tail(&vb->queue, &fh->capture); 564 565 spin_unlock_irq(&fh->queue_lock); 566 567 desc = dmaengine_prep_slave_sg(fh->chan, 568 buf->sg, sg_elems, DMA_DEV_TO_MEM, 569 DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); 570 if (!desc) { 571 spin_lock_irq(&fh->queue_lock); 572 list_del_init(&vb->queue); 573 vb->state = VIDEOBUF_PREPARED; 574 return; 575 } 576 577 desc->callback_param = buf; 578 desc->callback = timblogiw_dma_cb; 579 580 buf->cookie = desc->tx_submit(desc); 581 582 spin_lock_irq(&fh->queue_lock); 583} 584 585static void buffer_release(struct videobuf_queue *vq, 586 struct videobuf_buffer *vb) 587{ 588 struct timblogiw_fh *fh = vq->priv_data; 589 struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, 590 vb); 591 592 videobuf_waiton(vq, vb, 0, 0); 593 if (buf->cookie >= 0) 594 dma_sync_wait(fh->chan, buf->cookie); 595 596 videobuf_dma_contig_free(vq, vb); 597 vb->state = VIDEOBUF_NEEDS_INIT; 598} 599 600static struct videobuf_queue_ops timblogiw_video_qops = { 601 .buf_setup = buffer_setup, 602 .buf_prepare = buffer_prepare, 603 .buf_queue = buffer_queue, 604 .buf_release = buffer_release, 605}; 606 607/* Device Operations functions */ 608 609static int timblogiw_open(struct file *file) 610{ 611 struct video_device *vdev = video_devdata(file); 612 struct timblogiw *lw = video_get_drvdata(vdev); 613 struct timblogiw_fh *fh; 614 v4l2_std_id std; 615 dma_cap_mask_t mask; 616 int err = 0; 617 618 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 619 620 mutex_lock(&lw->lock); 621 if (lw->opened) { 622 err = -EBUSY; 623 goto out; 624 } 625 626 if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) { 627 struct i2c_adapter *adapt; 628 629 /* find the video decoder */ 630 adapt = i2c_get_adapter(lw->pdata.i2c_adapter); 631 if (!adapt) { 632 dev_err(&vdev->dev, "No I2C bus #%d\n", 633 lw->pdata.i2c_adapter); 634 err = -ENODEV; 635 goto out; 636 } 637 638 /* now find the encoder */ 639 lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt, 640 lw->pdata.encoder.info, NULL); 641 642 i2c_put_adapter(adapt); 643 644 if (!lw->sd_enc) { 645 dev_err(&vdev->dev, "Failed to get encoder: %s\n", 646 lw->pdata.encoder.module_name); 647 err = -ENODEV; 648 goto out; 649 } 650 } 651 652 fh = kzalloc(sizeof(*fh), GFP_KERNEL); 653 if (!fh) { 654 err = -ENOMEM; 655 goto out; 656 } 657 658 fh->cur_norm = timblogiw_tvnorms; 659 timblogiw_querystd(file, fh, &std); 660 fh->cur_norm = timblogiw_get_norm(std); 661 662 INIT_LIST_HEAD(&fh->capture); 663 spin_lock_init(&fh->queue_lock); 664 665 dma_cap_zero(mask); 666 dma_cap_set(DMA_SLAVE, mask); 667 dma_cap_set(DMA_PRIVATE, mask); 668 669 /* find the DMA channel */ 670 fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn, 671 (void *)(uintptr_t)lw->pdata.dma_channel); 672 if (!fh->chan) { 673 dev_err(&vdev->dev, "Failed to get DMA channel\n"); 674 kfree(fh); 675 err = -ENODEV; 676 goto out; 677 } 678 679 file->private_data = fh; 680 videobuf_queue_dma_contig_init(&fh->vb_vidq, 681 &timblogiw_video_qops, lw->dev, &fh->queue_lock, 682 V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, 683 sizeof(struct timblogiw_buffer), fh, NULL); 684 685 lw->opened = true; 686out: 687 mutex_unlock(&lw->lock); 688 689 return err; 690} 691 692static int timblogiw_close(struct file *file) 693{ 694 struct video_device *vdev = video_devdata(file); 695 struct timblogiw *lw = video_get_drvdata(vdev); 696 struct timblogiw_fh *fh = file->private_data; 697 698 dev_dbg(&vdev->dev, "%s: Entry\n", __func__); 699 700 videobuf_stop(&fh->vb_vidq); 701 videobuf_mmap_free(&fh->vb_vidq); 702 703 dma_release_channel(fh->chan); 704 705 kfree(fh); 706 707 mutex_lock(&lw->lock); 708 lw->opened = false; 709 mutex_unlock(&lw->lock); 710 return 0; 711} 712 713static ssize_t timblogiw_read(struct file *file, char __user *data, 714 size_t count, loff_t *ppos) 715{ 716 struct video_device *vdev = video_devdata(file); 717 struct timblogiw_fh *fh = file->private_data; 718 719 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 720 721 return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, 722 file->f_flags & O_NONBLOCK); 723} 724 725static unsigned int timblogiw_poll(struct file *file, 726 struct poll_table_struct *wait) 727{ 728 struct video_device *vdev = video_devdata(file); 729 struct timblogiw_fh *fh = file->private_data; 730 731 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 732 733 return videobuf_poll_stream(file, &fh->vb_vidq, wait); 734} 735 736static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma) 737{ 738 struct video_device *vdev = video_devdata(file); 739 struct timblogiw_fh *fh = file->private_data; 740 741 dev_dbg(&vdev->dev, "%s: entry\n", __func__); 742 743 return videobuf_mmap_mapper(&fh->vb_vidq, vma); 744} 745 746/* Platform device functions */ 747 748static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = { 749 .vidioc_querycap = timblogiw_querycap, 750 .vidioc_enum_fmt_vid_cap = timblogiw_enum_fmt, 751 .vidioc_g_fmt_vid_cap = timblogiw_g_fmt, 752 .vidioc_try_fmt_vid_cap = timblogiw_try_fmt, 753 .vidioc_s_fmt_vid_cap = timblogiw_s_fmt, 754 .vidioc_g_parm = timblogiw_g_parm, 755 .vidioc_reqbufs = timblogiw_reqbufs, 756 .vidioc_querybuf = timblogiw_querybuf, 757 .vidioc_qbuf = timblogiw_qbuf, 758 .vidioc_dqbuf = timblogiw_dqbuf, 759 .vidioc_g_std = timblogiw_g_std, 760 .vidioc_s_std = timblogiw_s_std, 761 .vidioc_enum_input = timblogiw_enuminput, 762 .vidioc_g_input = timblogiw_g_input, 763 .vidioc_s_input = timblogiw_s_input, 764 .vidioc_streamon = timblogiw_streamon, 765 .vidioc_streamoff = timblogiw_streamoff, 766 .vidioc_querystd = timblogiw_querystd, 767 .vidioc_enum_framesizes = timblogiw_enum_framesizes, 768}; 769 770static __devinitconst struct v4l2_file_operations timblogiw_fops = { 771 .owner = THIS_MODULE, 772 .open = timblogiw_open, 773 .release = timblogiw_close, 774 .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ 775 .mmap = timblogiw_mmap, 776 .read = timblogiw_read, 777 .poll = timblogiw_poll, 778}; 779 780static __devinitconst struct video_device timblogiw_template = { 781 .name = TIMBLOGIWIN_NAME, 782 .fops = &timblogiw_fops, 783 .ioctl_ops = &timblogiw_ioctl_ops, 784 .release = video_device_release_empty, 785 .minor = -1, 786 .tvnorms = V4L2_STD_PAL | V4L2_STD_NTSC 787}; 788 789static int __devinit timblogiw_probe(struct platform_device *pdev) 790{ 791 int err; 792 struct timblogiw *lw = NULL; 793 struct timb_video_platform_data *pdata = pdev->dev.platform_data; 794 795 if (!pdata) { 796 dev_err(&pdev->dev, "No platform data\n"); 797 err = -EINVAL; 798 goto err; 799 } 800 801 if (!pdata->encoder.module_name) 802 dev_info(&pdev->dev, "Running without decoder\n"); 803 804 lw = kzalloc(sizeof(*lw), GFP_KERNEL); 805 if (!lw) { 806 err = -ENOMEM; 807 goto err; 808 } 809 810 if (pdev->dev.parent) 811 lw->dev = pdev->dev.parent; 812 else 813 lw->dev = &pdev->dev; 814 815 memcpy(&lw->pdata, pdata, sizeof(lw->pdata)); 816 817 mutex_init(&lw->lock); 818 819 lw->video_dev = timblogiw_template; 820 821 strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name)); 822 err = v4l2_device_register(NULL, &lw->v4l2_dev); 823 if (err) 824 goto err_register; 825 826 lw->video_dev.v4l2_dev = &lw->v4l2_dev; 827 828 platform_set_drvdata(pdev, lw); 829 video_set_drvdata(&lw->video_dev, lw); 830 831 err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0); 832 if (err) { 833 dev_err(&pdev->dev, "Error reg video: %d\n", err); 834 goto err_request; 835 } 836 837 838 return 0; 839 840err_request: 841 platform_set_drvdata(pdev, NULL); 842 v4l2_device_unregister(&lw->v4l2_dev); 843err_register: 844 kfree(lw); 845err: 846 dev_err(&pdev->dev, "Failed to register: %d\n", err); 847 848 return err; 849} 850 851static int __devexit timblogiw_remove(struct platform_device *pdev) 852{ 853 struct timblogiw *lw = platform_get_drvdata(pdev); 854 855 video_unregister_device(&lw->video_dev); 856 857 v4l2_device_unregister(&lw->v4l2_dev); 858 859 kfree(lw); 860 861 platform_set_drvdata(pdev, NULL); 862 863 return 0; 864} 865 866static struct platform_driver timblogiw_platform_driver = { 867 .driver = { 868 .name = DRIVER_NAME, 869 .owner = THIS_MODULE, 870 }, 871 .probe = timblogiw_probe, 872 .remove = __devexit_p(timblogiw_remove), 873}; 874 875module_platform_driver(timblogiw_platform_driver); 876 877MODULE_DESCRIPTION(TIMBLOGIWIN_NAME); 878MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>"); 879MODULE_LICENSE("GPL v2"); 880MODULE_ALIAS("platform:"DRIVER_NAME);