Linux Audio

Check our new training course

Loading...
  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);