2 * timblogiw.c timberdale FPGA LogiWin Video In driver
3 * Copyright (c) 2009-2010 Intel Corporation
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.
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.
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.
20 * Timberdale FPGA LogiWin Video In
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>
36 #define DRIVER_NAME "timb-video"
38 #define TIMBLOGIWIN_NAME "Timberdale Video-In"
39 #define TIMBLOGIW_VERSION_CODE 0x04
41 #define TIMBLOGIW_LINES_PER_DESC 44
42 #define TIMBLOGIW_MAX_VIDEO_MEM 16
44 #define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name)
48 struct video_device video_dev
;
49 struct v4l2_device v4l2_dev
; /* mutual exclusion */
52 struct timb_video_platform_data pdata
;
53 struct v4l2_subdev
*sd_enc
; /* encoder */
57 struct timblogiw_tvnorm
{
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
;
73 struct timblogiw_buffer
{
74 /* common v4l buffer stuff -- must be first */
75 struct videobuf_buffer vb
;
76 struct scatterlist sg
[16];
78 struct timblogiw_fh
*fh
;
81 const struct timblogiw_tvnorm timblogiw_tvnorms
[] = {
96 static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm
*norm
)
98 return norm
->width
* 2;
102 static int timblogiw_frame_size(const struct timblogiw_tvnorm
*norm
)
104 return norm
->height
* timblogiw_bytes_per_line(norm
);
107 static const struct timblogiw_tvnorm
*timblogiw_get_norm(const v4l2_std_id std
)
110 for (i
= 0; i
< ARRAY_SIZE(timblogiw_tvnorms
); i
++)
111 if (timblogiw_tvnorms
[i
].std
& std
)
112 return timblogiw_tvnorms
+ i
;
114 /* default to first element */
115 return timblogiw_tvnorms
;
118 static void timblogiw_dma_cb(void *data
)
120 struct timblogiw_buffer
*buf
= data
;
121 struct timblogiw_fh
*fh
= buf
->fh
;
122 struct videobuf_buffer
*vb
= &buf
->vb
;
124 spin_lock(&fh
->queue_lock
);
126 /* mark the transfer done */
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
;
140 if (!list_empty(&fh
->capture
)) {
141 vb
= list_entry(fh
->capture
.next
, struct videobuf_buffer
,
143 vb
->state
= VIDEOBUF_ACTIVE
;
146 spin_unlock(&fh
->queue_lock
);
149 static bool timblogiw_dma_filter_fn(struct dma_chan
*chan
, void *filter_param
)
151 return chan
->chan_id
== (uintptr_t)filter_param
;
154 /* IOCTL functions */
156 static int timblogiw_g_fmt(struct file
*file
, void *priv
,
157 struct v4l2_format
*format
)
159 struct video_device
*vdev
= video_devdata(file
);
160 struct timblogiw
*lw
= video_get_drvdata(vdev
);
161 struct timblogiw_fh
*fh
= priv
;
163 dev_dbg(&vdev
->dev
, "%s entry\n", __func__
);
165 if (format
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
168 mutex_lock(&lw
->lock
);
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
;
177 mutex_unlock(&lw
->lock
);
182 static int timblogiw_try_fmt(struct file
*file
, void *priv
,
183 struct v4l2_format
*format
)
185 struct video_device
*vdev
= video_devdata(file
);
186 struct v4l2_pix_format
*pix
= &format
->fmt
.pix
;
189 "%s - width=%d, height=%d, pixelformat=%d, field=%d\n"
190 "bytes per line %d, size image: %d, colorspace: %d\n",
192 pix
->width
, pix
->height
, pix
->pixelformat
, pix
->field
,
193 pix
->bytesperline
, pix
->sizeimage
, pix
->colorspace
);
195 if (format
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
198 if (pix
->field
!= V4L2_FIELD_NONE
)
201 if (pix
->pixelformat
!= V4L2_PIX_FMT_UYVY
)
207 static int timblogiw_s_fmt(struct file
*file
, void *priv
,
208 struct v4l2_format
*format
)
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
;
216 mutex_lock(&lw
->lock
);
218 err
= timblogiw_try_fmt(file
, priv
, format
);
222 if (videobuf_queue_is_busy(&fh
->vb_vidq
)) {
223 dev_err(&vdev
->dev
, "%s queue busy\n", __func__
);
228 pix
->width
= fh
->cur_norm
->width
;
229 pix
->height
= fh
->cur_norm
->height
;
232 mutex_unlock(&lw
->lock
);
236 static int timblogiw_querycap(struct file
*file
, void *priv
,
237 struct v4l2_capability
*cap
)
239 struct video_device
*vdev
= video_devdata(file
);
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
|
253 static int timblogiw_enum_fmt(struct file
*file
, void *priv
,
254 struct v4l2_fmtdesc
*fmt
)
256 struct video_device
*vdev
= video_devdata(file
);
258 dev_dbg(&vdev
->dev
, "%s, index: %d\n", __func__
, fmt
->index
);
262 memset(fmt
, 0, sizeof(*fmt
));
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
;
272 static int timblogiw_g_parm(struct file
*file
, void *priv
,
273 struct v4l2_streamparm
*sp
)
275 struct timblogiw_fh
*fh
= priv
;
276 struct v4l2_captureparm
*cp
= &sp
->parm
.capture
;
278 cp
->capability
= V4L2_CAP_TIMEPERFRAME
;
279 cp
->timeperframe
.numerator
= 1;
280 cp
->timeperframe
.denominator
= fh
->cur_norm
->fps
;
285 static int timblogiw_reqbufs(struct file
*file
, void *priv
,
286 struct v4l2_requestbuffers
*rb
)
288 struct video_device
*vdev
= video_devdata(file
);
289 struct timblogiw_fh
*fh
= priv
;
291 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
293 return videobuf_reqbufs(&fh
->vb_vidq
, rb
);
296 static int timblogiw_querybuf(struct file
*file
, void *priv
,
297 struct v4l2_buffer
*b
)
299 struct video_device
*vdev
= video_devdata(file
);
300 struct timblogiw_fh
*fh
= priv
;
302 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
304 return videobuf_querybuf(&fh
->vb_vidq
, b
);
307 static int timblogiw_qbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*b
)
309 struct video_device
*vdev
= video_devdata(file
);
310 struct timblogiw_fh
*fh
= priv
;
312 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
314 return videobuf_qbuf(&fh
->vb_vidq
, b
);
317 static int timblogiw_dqbuf(struct file
*file
, void *priv
,
318 struct v4l2_buffer
*b
)
320 struct video_device
*vdev
= video_devdata(file
);
321 struct timblogiw_fh
*fh
= priv
;
323 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
325 return videobuf_dqbuf(&fh
->vb_vidq
, b
, file
->f_flags
& O_NONBLOCK
);
328 static int timblogiw_g_std(struct file
*file
, void *priv
, v4l2_std_id
*std
)
330 struct video_device
*vdev
= video_devdata(file
);
331 struct timblogiw_fh
*fh
= priv
;
333 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
335 *std
= fh
->cur_norm
->std
;
339 static int timblogiw_s_std(struct file
*file
, void *priv
, v4l2_std_id
*std
)
341 struct video_device
*vdev
= video_devdata(file
);
342 struct timblogiw
*lw
= video_get_drvdata(vdev
);
343 struct timblogiw_fh
*fh
= priv
;
346 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
348 mutex_lock(&lw
->lock
);
350 if (TIMBLOGIW_HAS_DECODER(lw
))
351 err
= v4l2_subdev_call(lw
->sd_enc
, core
, s_std
, *std
);
354 fh
->cur_norm
= timblogiw_get_norm(*std
);
356 mutex_unlock(&lw
->lock
);
361 static int timblogiw_enuminput(struct file
*file
, void *priv
,
362 struct v4l2_input
*inp
)
364 struct video_device
*vdev
= video_devdata(file
);
367 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
374 strncpy(inp
->name
, "Timb input 1", sizeof(inp
->name
) - 1);
375 inp
->type
= V4L2_INPUT_TYPE_CAMERA
;
378 for (i
= 0; i
< ARRAY_SIZE(timblogiw_tvnorms
); i
++)
379 inp
->std
|= timblogiw_tvnorms
[i
].std
;
384 static int timblogiw_g_input(struct file
*file
, void *priv
,
387 struct video_device
*vdev
= video_devdata(file
);
389 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
396 static int timblogiw_s_input(struct file
*file
, void *priv
, unsigned int input
)
398 struct video_device
*vdev
= video_devdata(file
);
400 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
407 static int timblogiw_streamon(struct file
*file
, void *priv
, unsigned int type
)
409 struct video_device
*vdev
= video_devdata(file
);
410 struct timblogiw_fh
*fh
= priv
;
412 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
414 if (type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
415 dev_dbg(&vdev
->dev
, "%s - No capture device\n", __func__
);
420 return videobuf_streamon(&fh
->vb_vidq
);
423 static int timblogiw_streamoff(struct file
*file
, void *priv
,
426 struct video_device
*vdev
= video_devdata(file
);
427 struct timblogiw_fh
*fh
= priv
;
429 dev_dbg(&vdev
->dev
, "%s entry\n", __func__
);
431 if (type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
434 return videobuf_streamoff(&fh
->vb_vidq
);
437 static int timblogiw_querystd(struct file
*file
, void *priv
, v4l2_std_id
*std
)
439 struct video_device
*vdev
= video_devdata(file
);
440 struct timblogiw
*lw
= video_get_drvdata(vdev
);
441 struct timblogiw_fh
*fh
= priv
;
443 dev_dbg(&vdev
->dev
, "%s entry\n", __func__
);
445 if (TIMBLOGIW_HAS_DECODER(lw
))
446 return v4l2_subdev_call(lw
->sd_enc
, video
, querystd
, std
);
448 *std
= fh
->cur_norm
->std
;
453 static int timblogiw_enum_framesizes(struct file
*file
, void *priv
,
454 struct v4l2_frmsizeenum
*fsize
)
456 struct video_device
*vdev
= video_devdata(file
);
457 struct timblogiw_fh
*fh
= priv
;
459 dev_dbg(&vdev
->dev
, "%s - index: %d, format: %d\n", __func__
,
460 fsize
->index
, fsize
->pixel_format
);
462 if ((fsize
->index
!= 0) ||
463 (fsize
->pixel_format
!= V4L2_PIX_FMT_UYVY
))
466 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
467 fsize
->discrete
.width
= fh
->cur_norm
->width
;
468 fsize
->discrete
.height
= fh
->cur_norm
->height
;
473 /* Video buffer functions */
475 static int buffer_setup(struct videobuf_queue
*vq
, unsigned int *count
,
478 struct timblogiw_fh
*fh
= vq
->priv_data
;
480 *size
= timblogiw_frame_size(fh
->cur_norm
);
485 while (*size
* *count
> TIMBLOGIW_MAX_VIDEO_MEM
* 1024 * 1024)
491 static int buffer_prepare(struct videobuf_queue
*vq
, struct videobuf_buffer
*vb
,
492 enum v4l2_field field
)
494 struct timblogiw_fh
*fh
= vq
->priv_data
;
495 struct timblogiw_buffer
*buf
= container_of(vb
, struct timblogiw_buffer
,
497 unsigned int data_size
= timblogiw_frame_size(fh
->cur_norm
);
500 if (vb
->baddr
&& vb
->bsize
< data_size
)
501 /* User provided buffer, but it is too small */
504 vb
->size
= data_size
;
505 vb
->width
= fh
->cur_norm
->width
;
506 vb
->height
= fh
->cur_norm
->height
;
509 if (vb
->state
== VIDEOBUF_NEEDS_INIT
) {
512 unsigned int bytes_per_desc
= TIMBLOGIW_LINES_PER_DESC
*
513 timblogiw_bytes_per_line(fh
->cur_norm
);
516 sg_init_table(buf
->sg
, ARRAY_SIZE(buf
->sg
));
518 err
= videobuf_iolock(vq
, vb
, NULL
);
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
)) :
531 vb
->state
= VIDEOBUF_PREPARED
;
539 videobuf_dma_contig_free(vq
, vb
);
540 vb
->state
= VIDEOBUF_NEEDS_INIT
;
544 static void buffer_queue(struct videobuf_queue
*vq
, struct videobuf_buffer
*vb
)
546 struct timblogiw_fh
*fh
= vq
->priv_data
;
547 struct timblogiw_buffer
*buf
= container_of(vb
, struct timblogiw_buffer
,
549 struct dma_async_tx_descriptor
*desc
;
551 int bytes_per_desc
= TIMBLOGIW_LINES_PER_DESC
*
552 timblogiw_bytes_per_line(fh
->cur_norm
);
554 sg_elems
= timblogiw_frame_size(fh
->cur_norm
) / bytes_per_desc
;
556 (timblogiw_frame_size(fh
->cur_norm
) % bytes_per_desc
) ? 1 : 0;
558 if (list_empty(&fh
->capture
))
559 vb
->state
= VIDEOBUF_ACTIVE
;
561 vb
->state
= VIDEOBUF_QUEUED
;
563 list_add_tail(&vb
->queue
, &fh
->capture
);
565 spin_unlock_irq(&fh
->queue_lock
);
567 desc
= fh
->chan
->device
->device_prep_slave_sg(fh
->chan
,
568 buf
->sg
, sg_elems
, DMA_DEV_TO_MEM
,
569 DMA_PREP_INTERRUPT
| DMA_COMPL_SKIP_SRC_UNMAP
);
571 spin_lock_irq(&fh
->queue_lock
);
572 list_del_init(&vb
->queue
);
573 vb
->state
= VIDEOBUF_PREPARED
;
577 desc
->callback_param
= buf
;
578 desc
->callback
= timblogiw_dma_cb
;
580 buf
->cookie
= desc
->tx_submit(desc
);
582 spin_lock_irq(&fh
->queue_lock
);
585 static void buffer_release(struct videobuf_queue
*vq
,
586 struct videobuf_buffer
*vb
)
588 struct timblogiw_fh
*fh
= vq
->priv_data
;
589 struct timblogiw_buffer
*buf
= container_of(vb
, struct timblogiw_buffer
,
592 videobuf_waiton(vq
, vb
, 0, 0);
593 if (buf
->cookie
>= 0)
594 dma_sync_wait(fh
->chan
, buf
->cookie
);
596 videobuf_dma_contig_free(vq
, vb
);
597 vb
->state
= VIDEOBUF_NEEDS_INIT
;
600 static 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
,
607 /* Device Operations functions */
609 static int timblogiw_open(struct file
*file
)
611 struct video_device
*vdev
= video_devdata(file
);
612 struct timblogiw
*lw
= video_get_drvdata(vdev
);
613 struct timblogiw_fh
*fh
;
618 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
620 mutex_lock(&lw
->lock
);
626 if (TIMBLOGIW_HAS_DECODER(lw
) && !lw
->sd_enc
) {
627 struct i2c_adapter
*adapt
;
629 /* find the video decoder */
630 adapt
= i2c_get_adapter(lw
->pdata
.i2c_adapter
);
632 dev_err(&vdev
->dev
, "No I2C bus #%d\n",
633 lw
->pdata
.i2c_adapter
);
638 /* now find the encoder */
639 lw
->sd_enc
= v4l2_i2c_new_subdev_board(&lw
->v4l2_dev
, adapt
,
640 lw
->pdata
.encoder
.info
, NULL
);
642 i2c_put_adapter(adapt
);
645 dev_err(&vdev
->dev
, "Failed to get encoder: %s\n",
646 lw
->pdata
.encoder
.module_name
);
652 fh
= kzalloc(sizeof(*fh
), GFP_KERNEL
);
658 fh
->cur_norm
= timblogiw_tvnorms
;
659 timblogiw_querystd(file
, fh
, &std
);
660 fh
->cur_norm
= timblogiw_get_norm(std
);
662 INIT_LIST_HEAD(&fh
->capture
);
663 spin_lock_init(&fh
->queue_lock
);
666 dma_cap_set(DMA_SLAVE
, mask
);
667 dma_cap_set(DMA_PRIVATE
, mask
);
669 /* find the DMA channel */
670 fh
->chan
= dma_request_channel(mask
, timblogiw_dma_filter_fn
,
671 (void *)(uintptr_t)lw
->pdata
.dma_channel
);
673 dev_err(&vdev
->dev
, "Failed to get DMA channel\n");
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
);
687 mutex_unlock(&lw
->lock
);
692 static int timblogiw_close(struct file
*file
)
694 struct video_device
*vdev
= video_devdata(file
);
695 struct timblogiw
*lw
= video_get_drvdata(vdev
);
696 struct timblogiw_fh
*fh
= file
->private_data
;
698 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
700 videobuf_stop(&fh
->vb_vidq
);
701 videobuf_mmap_free(&fh
->vb_vidq
);
703 dma_release_channel(fh
->chan
);
707 mutex_lock(&lw
->lock
);
709 mutex_unlock(&lw
->lock
);
713 static ssize_t
timblogiw_read(struct file
*file
, char __user
*data
,
714 size_t count
, loff_t
*ppos
)
716 struct video_device
*vdev
= video_devdata(file
);
717 struct timblogiw_fh
*fh
= file
->private_data
;
719 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
721 return videobuf_read_stream(&fh
->vb_vidq
, data
, count
, ppos
, 0,
722 file
->f_flags
& O_NONBLOCK
);
725 static unsigned int timblogiw_poll(struct file
*file
,
726 struct poll_table_struct
*wait
)
728 struct video_device
*vdev
= video_devdata(file
);
729 struct timblogiw_fh
*fh
= file
->private_data
;
731 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
733 return videobuf_poll_stream(file
, &fh
->vb_vidq
, wait
);
736 static int timblogiw_mmap(struct file
*file
, struct vm_area_struct
*vma
)
738 struct video_device
*vdev
= video_devdata(file
);
739 struct timblogiw_fh
*fh
= file
->private_data
;
741 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
743 return videobuf_mmap_mapper(&fh
->vb_vidq
, vma
);
746 /* Platform device functions */
748 static __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
,
770 static __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
,
780 static __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
,
786 .tvnorms
= V4L2_STD_PAL
| V4L2_STD_NTSC
789 static int __devinit
timblogiw_probe(struct platform_device
*pdev
)
792 struct timblogiw
*lw
= NULL
;
793 struct timb_video_platform_data
*pdata
= pdev
->dev
.platform_data
;
796 dev_err(&pdev
->dev
, "No platform data\n");
801 if (!pdata
->encoder
.module_name
)
802 dev_info(&pdev
->dev
, "Running without decoder\n");
804 lw
= kzalloc(sizeof(*lw
), GFP_KERNEL
);
810 if (pdev
->dev
.parent
)
811 lw
->dev
= pdev
->dev
.parent
;
813 lw
->dev
= &pdev
->dev
;
815 memcpy(&lw
->pdata
, pdata
, sizeof(lw
->pdata
));
817 mutex_init(&lw
->lock
);
819 lw
->video_dev
= timblogiw_template
;
821 strlcpy(lw
->v4l2_dev
.name
, DRIVER_NAME
, sizeof(lw
->v4l2_dev
.name
));
822 err
= v4l2_device_register(NULL
, &lw
->v4l2_dev
);
826 lw
->video_dev
.v4l2_dev
= &lw
->v4l2_dev
;
828 platform_set_drvdata(pdev
, lw
);
829 video_set_drvdata(&lw
->video_dev
, lw
);
831 err
= video_register_device(&lw
->video_dev
, VFL_TYPE_GRABBER
, 0);
833 dev_err(&pdev
->dev
, "Error reg video: %d\n", err
);
841 platform_set_drvdata(pdev
, NULL
);
842 v4l2_device_unregister(&lw
->v4l2_dev
);
846 dev_err(&pdev
->dev
, "Failed to register: %d\n", err
);
851 static int __devexit
timblogiw_remove(struct platform_device
*pdev
)
853 struct timblogiw
*lw
= platform_get_drvdata(pdev
);
855 video_unregister_device(&lw
->video_dev
);
857 v4l2_device_unregister(&lw
->v4l2_dev
);
861 platform_set_drvdata(pdev
, NULL
);
866 static struct platform_driver timblogiw_platform_driver
= {
869 .owner
= THIS_MODULE
,
871 .probe
= timblogiw_probe
,
872 .remove
= __devexit_p(timblogiw_remove
),
875 module_platform_driver(timblogiw_platform_driver
);
877 MODULE_DESCRIPTION(TIMBLOGIWIN_NAME
);
878 MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
879 MODULE_LICENSE("GPL v2");
880 MODULE_ALIAS("platform:"DRIVER_NAME
);