saa7146_video.c 33.9 KB
Newer Older
1 2
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

3
#include <media/drv-intf/saa7146_vv.h>
4 5
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
6
#include <linux/module.h>
J
Jérémy Lefaure 已提交
7
#include <linux/kernel.h>
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

static int max_memory = 32;

module_param(max_memory, int, 0644);
MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");

#define IS_CAPTURE_ACTIVE(fh) \
	(((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))

#define IS_OVERLAY_ACTIVE(fh) \
	(((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))

/* format descriptions for capture and preview */
static struct saa7146_format formats[] = {
	{
		.name		= "RGB-8 (3-3-2)",
		.pixelformat	= V4L2_PIX_FMT_RGB332,
		.trans		= RGB08_COMPOSED,
		.depth		= 8,
		.flags		= 0,
	}, {
		.name		= "RGB-16 (5/B-6/G-5/R)",
		.pixelformat	= V4L2_PIX_FMT_RGB565,
		.trans		= RGB16_COMPOSED,
		.depth		= 16,
		.flags		= 0,
	}, {
		.name		= "RGB-24 (B-G-R)",
		.pixelformat	= V4L2_PIX_FMT_BGR24,
		.trans		= RGB24_COMPOSED,
		.depth		= 24,
		.flags		= 0,
	}, {
		.name		= "RGB-32 (B-G-R)",
		.pixelformat	= V4L2_PIX_FMT_BGR32,
		.trans		= RGB32_COMPOSED,
		.depth		= 32,
		.flags		= 0,
	}, {
		.name		= "RGB-32 (R-G-B)",
		.pixelformat	= V4L2_PIX_FMT_RGB32,
		.trans		= RGB32_COMPOSED,
		.depth		= 32,
		.flags		= 0,
		.swap		= 0x2,
	}, {
		.name		= "Greyscale-8",
		.pixelformat	= V4L2_PIX_FMT_GREY,
		.trans		= Y8,
		.depth		= 8,
		.flags		= 0,
	}, {
		.name		= "YUV 4:2:2 planar (Y-Cb-Cr)",
		.pixelformat	= V4L2_PIX_FMT_YUV422P,
		.trans		= YUV422_DECOMPOSED,
		.depth		= 16,
		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
	}, {
		.name		= "YVU 4:2:0 planar (Y-Cb-Cr)",
		.pixelformat	= V4L2_PIX_FMT_YVU420,
		.trans		= YUV420_DECOMPOSED,
		.depth		= 12,
		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
	}, {
		.name		= "YUV 4:2:0 planar (Y-Cb-Cr)",
		.pixelformat	= V4L2_PIX_FMT_YUV420,
		.trans		= YUV420_DECOMPOSED,
		.depth		= 12,
		.flags		= FORMAT_IS_PLANAR,
	}, {
		.name		= "YUV 4:2:2 (U-Y-V-Y)",
		.pixelformat	= V4L2_PIX_FMT_UYVY,
		.trans		= YUV422_COMPOSED,
		.depth		= 16,
		.flags		= 0,
	}
};

/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
   due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
   (like V4L2_PIX_FMT_YUYV) ... 8-( */

90
struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
L
Linus Torvalds 已提交
91
{
J
Jérémy Lefaure 已提交
92
	int i;
L
Linus Torvalds 已提交
93

J
Jérémy Lefaure 已提交
94
	for (i = 0; i < ARRAY_SIZE(formats); i++) {
L
Linus Torvalds 已提交
95 96 97 98 99
		if (formats[i].pixelformat == fourcc) {
			return formats+i;
		}
	}

100
	DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
L
Linus Torvalds 已提交
101 102 103
	return NULL;
}

104
static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
L
Linus Torvalds 已提交
105 106 107 108 109

int saa7146_start_preview(struct saa7146_fh *fh)
{
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
110
	struct v4l2_format fmt;
L
Linus Torvalds 已提交
111 112
	int ret = 0, err = 0;

113
	DEB_EE("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
114

115 116
	/* check if we have overlay information */
	if (vv->ov.fh == NULL) {
117
		DEB_D("no overlay data available. try S_FMT first.\n");
L
Linus Torvalds 已提交
118 119 120 121 122
		return -EAGAIN;
	}

	/* check if streaming capture is running */
	if (IS_CAPTURE_ACTIVE(fh) != 0) {
123
		DEB_D("streaming capture is active\n");
L
Linus Torvalds 已提交
124 125 126 127 128 129
		return -EBUSY;
	}

	/* check if overlay is running */
	if (IS_OVERLAY_ACTIVE(fh) != 0) {
		if (vv->video_fh == fh) {
130
			DEB_D("overlay is already active\n");
L
Linus Torvalds 已提交
131 132
			return 0;
		}
133
		DEB_D("overlay is already active in another open\n");
L
Linus Torvalds 已提交
134 135 136 137
		return -EBUSY;
	}

	if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
138
		DEB_D("cannot get necessary overlay resources\n");
L
Linus Torvalds 已提交
139 140 141
		return -EBUSY;
	}

142
	fmt.fmt.win = vv->ov.win;
143
	err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
L
Linus Torvalds 已提交
144 145 146 147
	if (0 != err) {
		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
		return -EBUSY;
	}
148
	vv->ov.win = fmt.fmt.win;
L
Linus Torvalds 已提交
149

150
	DEB_D("%dx%d+%d+%d %s field=%s\n",
151 152 153
	      vv->ov.win.w.width, vv->ov.win.w.height,
	      vv->ov.win.w.left, vv->ov.win.w.top,
	      vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
L
Linus Torvalds 已提交
154 155

	if (0 != (ret = saa7146_enable_overlay(fh))) {
156
		DEB_D("enabling overlay failed: %d\n", ret);
L
Linus Torvalds 已提交
157 158 159 160 161 162 163 164 165
		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
		return ret;
	}

	vv->video_status = STATUS_OVERLAY;
	vv->video_fh = fh;

	return 0;
}
166
EXPORT_SYMBOL_GPL(saa7146_start_preview);
L
Linus Torvalds 已提交
167 168 169 170 171 172

int saa7146_stop_preview(struct saa7146_fh *fh)
{
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;

173
	DEB_EE("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
174 175 176

	/* check if streaming capture is running */
	if (IS_CAPTURE_ACTIVE(fh) != 0) {
177
		DEB_D("streaming capture is active\n");
L
Linus Torvalds 已提交
178 179 180 181 182
		return -EBUSY;
	}

	/* check if overlay is running at all */
	if ((vv->video_status & STATUS_OVERLAY) == 0) {
183
		DEB_D("no active overlay\n");
L
Linus Torvalds 已提交
184 185 186 187
		return 0;
	}

	if (vv->video_fh != fh) {
188
		DEB_D("overlay is active, but in another open\n");
L
Linus Torvalds 已提交
189 190 191 192 193 194 195 196 197 198 199 200
		return -EBUSY;
	}

	vv->video_status = 0;
	vv->video_fh = NULL;

	saa7146_disable_overlay(fh);

	saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);

	return 0;
}
201
EXPORT_SYMBOL_GPL(saa7146_stop_preview);
L
Linus Torvalds 已提交
202 203 204 205 206 207 208

/********************************************************************************/
/* common pagetable functions */

static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
	struct pci_dev *pci = dev->pci;
209 210 211
	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
	struct scatterlist *list = dma->sglist;
	int length = dma->sglen;
212
	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
L
Linus Torvalds 已提交
213

214
	DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
L
Linus Torvalds 已提交
215 216 217 218 219

	if( 0 != IS_PLANAR(sfmt->trans)) {
		struct saa7146_pgtable *pt1 = &buf->pt[0];
		struct saa7146_pgtable *pt2 = &buf->pt[1];
		struct saa7146_pgtable *pt3 = &buf->pt[2];
220 221
		__le32  *ptr1, *ptr2, *ptr3;
		__le32 fill;
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229 230 231 232 233

		int size = buf->fmt->width*buf->fmt->height;
		int i,p,m1,m2,m3,o1,o2;

		switch( sfmt->depth ) {
			case 12: {
				/* create some offsets inside the page table */
				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
				m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
				m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
				o1 = size%PAGE_SIZE;
				o2 = (size+(size/4))%PAGE_SIZE;
234 235
				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
					size, m1, m2, m3, o1, o2);
L
Linus Torvalds 已提交
236 237 238 239 240 241 242 243 244
				break;
			}
			case 16: {
				/* create some offsets inside the page table */
				m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
				m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
				m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
				o1 = size%PAGE_SIZE;
				o2 = (size+(size/2))%PAGE_SIZE;
245 246
				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
					size, m1, m2, m3, o1, o2);
L
Linus Torvalds 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
				break;
			}
			default: {
				return -1;
			}
		}

		ptr1 = pt1->cpu;
		ptr2 = pt2->cpu;
		ptr3 = pt3->cpu;

		/* walk all pages, copy all page addresses to ptr1 */
		for (i = 0; i < length; i++, list++) {
			for (p = 0; p * 4096 < list->length; p++, ptr1++) {
				*ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
			}
		}
/*
		ptr1 = pt1->cpu;
		for(j=0;j<40;j++) {
			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
		}
*/

		/* if we have a user buffer, the first page may not be
		   aligned to a page boundary. */
273
		pt1->offset = dma->sglist->offset;
L
Linus Torvalds 已提交
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
		pt2->offset = pt1->offset+o1;
		pt3->offset = pt1->offset+o2;

		/* create video-dma2 page table */
		ptr1 = pt1->cpu;
		for(i = m1; i <= m2 ; i++, ptr2++) {
			*ptr2 = ptr1[i];
		}
		fill = *(ptr2-1);
		for(;i<1024;i++,ptr2++) {
			*ptr2 = fill;
		}
		/* create video-dma3 page table */
		ptr1 = pt1->cpu;
		for(i = m2; i <= m3; i++,ptr3++) {
			*ptr3 = ptr1[i];
		}
		fill = *(ptr3-1);
		for(;i<1024;i++,ptr3++) {
			*ptr3 = fill;
		}
		/* finally: finish up video-dma1 page table */
		ptr1 = pt1->cpu+m1;
		fill = pt1->cpu[m1];
		for(i=m1;i<1024;i++,ptr1++) {
			*ptr1 = fill;
		}
/*
		ptr1 = pt1->cpu;
		ptr2 = pt2->cpu;
		ptr3 = pt3->cpu;
		for(j=0;j<40;j++) {
			printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
		}
		for(j=0;j<40;j++) {
			printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
		}
		for(j=0;j<40;j++) {
			printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
		}
*/
	} else {
		struct saa7146_pgtable *pt = &buf->pt[0];
		return saa7146_pgtable_build_single(pci, pt, list, length);
	}

	return 0;
}


/********************************************************************************/
/* file operations */

static int video_begin(struct saa7146_fh *fh)
{
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	struct saa7146_format *fmt = NULL;
	unsigned int resource;
	int ret = 0, err = 0;

335
	DEB_EE("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
336 337 338

	if ((vv->video_status & STATUS_CAPTURE) != 0) {
		if (vv->video_fh == fh) {
339
			DEB_S("already capturing\n");
L
Linus Torvalds 已提交
340 341
			return 0;
		}
342
		DEB_S("already capturing in another open\n");
L
Linus Torvalds 已提交
343 344 345 346
		return -EBUSY;
	}

	if ((vv->video_status & STATUS_OVERLAY) != 0) {
347
		DEB_S("warning: suspending overlay video for streaming capture\n");
L
Linus Torvalds 已提交
348 349 350
		vv->ov_suspend = vv->video_fh;
		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
		if (0 != err) {
351
			DEB_D("suspending video failed. aborting\n");
L
Linus Torvalds 已提交
352 353 354 355
			return err;
		}
	}

356
	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
L
Linus Torvalds 已提交
357 358 359 360 361 362 363 364 365 366 367
	/* we need to have a valid format set here */
	BUG_ON(NULL == fmt);

	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
	} else {
		resource = RESOURCE_DMA1_HPS;
	}

	ret = saa7146_res_get(fh, resource);
	if (0 == ret) {
368
		DEB_S("cannot get capture resource %d\n", resource);
L
Linus Torvalds 已提交
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
		if (vv->ov_suspend != NULL) {
			saa7146_start_preview(vv->ov_suspend);
			vv->ov_suspend = NULL;
		}
		return -EBUSY;
	}

	/* clear out beginning of streaming bit (rps register 0)*/
	saa7146_write(dev, MC2, MASK_27 );

	/* enable rps0 irqs */
	SAA7146_IER_ENABLE(dev, MASK_27);

	vv->video_fh = fh;
	vv->video_status = STATUS_CAPTURE;

	return 0;
}

static int video_end(struct saa7146_fh *fh, struct file *file)
{
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
392
	struct saa7146_dmaqueue *q = &vv->video_dmaq;
L
Linus Torvalds 已提交
393 394 395 396
	struct saa7146_format *fmt = NULL;
	unsigned long flags;
	unsigned int resource;
	u32 dmas = 0;
397
	DEB_EE("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
398 399

	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
400
		DEB_S("not capturing\n");
L
Linus Torvalds 已提交
401 402 403 404
		return 0;
	}

	if (vv->video_fh != fh) {
405
		DEB_S("capturing, but in another open\n");
L
Linus Torvalds 已提交
406 407 408
		return -EBUSY;
	}

409
	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
L
Linus Torvalds 已提交
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
	/* we need to have a valid format set here */
	BUG_ON(NULL == fmt);

	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
		dmas = MASK_22 | MASK_21 | MASK_20;
	} else {
		resource = RESOURCE_DMA1_HPS;
		dmas = MASK_22;
	}
	spin_lock_irqsave(&dev->slock,flags);

	/* disable rps0  */
	saa7146_write(dev, MC1, MASK_28);

	/* disable rps0 irqs */
	SAA7146_IER_DISABLE(dev, MASK_27);

	/* shut down all used video dma transfers */
	saa7146_write(dev, MC1, dmas);

431 432 433
	if (q->curr)
		saa7146_buffer_finish(dev, q, VIDEOBUF_DONE);

L
Linus Torvalds 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
	spin_unlock_irqrestore(&dev->slock, flags);

	vv->video_fh = NULL;
	vv->video_status = 0;

	saa7146_res_free(fh, resource);

	if (vv->ov_suspend != NULL) {
		saa7146_start_preview(vv->ov_suspend);
		vv->ov_suspend = NULL;
	}

	return 0;
}

449 450
static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
451
	struct video_device *vdev = video_devdata(file);
452 453
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;

454
	strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));
455
	strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
456
	sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
457
	cap->device_caps =
458 459 460 461
		V4L2_CAP_VIDEO_CAPTURE |
		V4L2_CAP_VIDEO_OVERLAY |
		V4L2_CAP_READWRITE |
		V4L2_CAP_STREAMING;
462
	cap->device_caps |= dev->ext_vv_data->capabilities;
463
	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
464 465 466 467 468
	if (vdev->vfl_type == VFL_TYPE_GRABBER)
		cap->device_caps &=
			~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
	else
		cap->device_caps &=
469
			~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
470 471
	return 0;
}
L
Linus Torvalds 已提交
472

473
static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
L
Linus Torvalds 已提交
474
{
475
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
L
Linus Torvalds 已提交
476 477
	struct saa7146_vv *vv = dev->vv_data;

478 479
	*fb = vv->ov_fb;
	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
480
	fb->flags = V4L2_FBUF_FLAG_PRIMARY;
481 482
	return 0;
}
L
Linus Torvalds 已提交
483

484
static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb)
485 486 487 488
{
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;
	struct saa7146_format *fmt;
L
Linus Torvalds 已提交
489

490
	DEB_EE("VIDIOC_S_FBUF\n");
L
Linus Torvalds 已提交
491

492 493
	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
		return -EPERM;
L
Linus Torvalds 已提交
494

495
	/* check args */
496
	fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
497 498
	if (NULL == fmt)
		return -EINVAL;
L
Linus Torvalds 已提交
499

500 501
	/* planar formats are not allowed for overlay video, clipping and video dma would clash */
	if (fmt->flags & FORMAT_IS_PLANAR)
502 503
		DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
		      (char *)&fmt->pixelformat);
504 505 506 507

	/* check if overlay is running */
	if (IS_OVERLAY_ACTIVE(fh) != 0) {
		if (vv->video_fh != fh) {
M
Masanari Iida 已提交
508
			DEB_D("refusing to change framebuffer information while overlay is active in another open\n");
509 510
			return -EBUSY;
		}
L
Linus Torvalds 已提交
511 512
	}

513 514 515
	/* ok, accept it */
	vv->ov_fb = *fb;
	vv->ov_fmt = fmt;
516 517 518

	if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
		vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
519
		DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
520
	}
521 522 523 524 525
	return 0;
}

static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
J
Jérémy Lefaure 已提交
526
	if (f->index >= ARRAY_SIZE(formats))
527
		return -EINVAL;
528 529
	strscpy((char *)f->description, formats[f->index].name,
		sizeof(f->description));
530 531 532 533
	f->pixelformat = formats[f->index].pixelformat;
	return 0;
}

534
int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
535
{
536 537
	struct saa7146_dev *dev = container_of(ctrl->handler,
				struct saa7146_dev, ctrl_handler);
538
	struct saa7146_vv *vv = dev->vv_data;
539
	u32 val;
540

541
	switch (ctrl->id) {
542
	case V4L2_CID_BRIGHTNESS:
543 544 545 546
		val = saa7146_read(dev, BCS_CTRL);
		val &= 0x00ffffff;
		val |= (ctrl->val << 24);
		saa7146_write(dev, BCS_CTRL, val);
547 548
		saa7146_write(dev, MC2, MASK_22 | MASK_06);
		break;
549 550 551 552 553 554

	case V4L2_CID_CONTRAST:
		val = saa7146_read(dev, BCS_CTRL);
		val &= 0xff00ffff;
		val |= (ctrl->val << 16);
		saa7146_write(dev, BCS_CTRL, val);
555 556
		saa7146_write(dev, MC2, MASK_22 | MASK_06);
		break;
557 558 559 560 561 562

	case V4L2_CID_SATURATION:
		val = saa7146_read(dev, BCS_CTRL);
		val &= 0xffffff00;
		val |= (ctrl->val << 0);
		saa7146_write(dev, BCS_CTRL, val);
563 564
		saa7146_write(dev, MC2, MASK_22 | MASK_06);
		break;
565

566 567
	case V4L2_CID_HFLIP:
		/* fixme: we can support changing VFLIP and HFLIP here... */
568
		if ((vv->video_status & STATUS_CAPTURE))
569
			return -EBUSY;
570
		vv->hflip = ctrl->val;
571
		break;
572

573
	case V4L2_CID_VFLIP:
574
		if ((vv->video_status & STATUS_CAPTURE))
575
			return -EBUSY;
576
		vv->vflip = ctrl->val;
577
		break;
578

579 580 581
	default:
		return -EINVAL;
	}
L
Linus Torvalds 已提交
582

583 584 585
	if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
		struct saa7146_fh *fh = vv->video_fh;

586 587 588 589 590
		saa7146_stop_preview(fh);
		saa7146_start_preview(fh);
	}
	return 0;
}
L
Linus Torvalds 已提交
591

592 593 594
static int vidioc_g_parm(struct file *file, void *fh,
		struct v4l2_streamparm *parm)
{
595 596 597
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;

598 599
	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
600
	parm->parm.capture.readbuffers = 1;
601 602
	v4l2_video_std_frame_period(vv->standard->id,
				    &parm->parm.capture.timeperframe);
603 604
	return 0;
}
L
Linus Torvalds 已提交
605

606 607
static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
608 609 610 611
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;

	f->fmt.pix = vv->video_fmt;
612 613
	return 0;
}
L
Linus Torvalds 已提交
614

615 616
static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
{
617 618 619 620
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;

	f->fmt.win = vv->ov.win;
621 622
	return 0;
}
L
Linus Torvalds 已提交
623

624 625
static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
{
626 627 628 629
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;

	f->fmt.vbi = vv->vbi_fmt;
630 631
	return 0;
}
L
Linus Torvalds 已提交
632

633 634 635 636 637 638 639 640 641
static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;
	struct saa7146_format *fmt;
	enum v4l2_field field;
	int maxw, maxh;
	int calc_bpl;

642
	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
643

644
	fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
	if (NULL == fmt)
		return -EINVAL;

	field = f->fmt.pix.field;
	maxw  = vv->standard->h_max_out;
	maxh  = vv->standard->v_max_out;

	if (V4L2_FIELD_ANY == field) {
		field = (f->fmt.pix.height > maxh / 2)
			? V4L2_FIELD_INTERLACED
			: V4L2_FIELD_BOTTOM;
	}
	switch (field) {
	case V4L2_FIELD_ALTERNATE:
		vv->last_field = V4L2_FIELD_TOP;
		maxh = maxh / 2;
		break;
	case V4L2_FIELD_TOP:
	case V4L2_FIELD_BOTTOM:
		vv->last_field = V4L2_FIELD_INTERLACED;
		maxh = maxh / 2;
		break;
	case V4L2_FIELD_INTERLACED:
		vv->last_field = V4L2_FIELD_INTERLACED;
		break;
	default:
671
		DEB_D("no known field mode '%d'\n", field);
672
		return -EINVAL;
L
Linus Torvalds 已提交
673 674
	}

675
	f->fmt.pix.field = field;
676
	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
677 678 679 680
	if (f->fmt.pix.width > maxw)
		f->fmt.pix.width = maxw;
	if (f->fmt.pix.height > maxh)
		f->fmt.pix.height = maxh;
L
Linus Torvalds 已提交
681

682
	calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
L
Linus Torvalds 已提交
683

684 685 686 687 688 689 690
	if (f->fmt.pix.bytesperline < calc_bpl)
		f->fmt.pix.bytesperline = calc_bpl;

	if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
		f->fmt.pix.bytesperline = calc_bpl;

	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
691 692 693
	DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
	      f->fmt.pix.width, f->fmt.pix.height,
	      f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
694 695 696 697 698 699 700 701 702 703 704 705 706

	return 0;
}


static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
{
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;
	struct v4l2_window *win = &f->fmt.win;
	enum v4l2_field field;
	int maxw, maxh;

707
	DEB_EE("dev:%p\n", dev);
708 709

	if (NULL == vv->ov_fb.base) {
710
		DEB_D("no fb base set\n");
711
		return -EINVAL;
L
Linus Torvalds 已提交
712
	}
713
	if (NULL == vv->ov_fmt) {
714
		DEB_D("no fb fmt set\n");
715
		return -EINVAL;
L
Linus Torvalds 已提交
716
	}
717
	if (win->w.width < 48 || win->w.height < 32) {
718 719
		DEB_D("min width/height. (%d,%d)\n",
		      win->w.width, win->w.height);
720
		return -EINVAL;
L
Linus Torvalds 已提交
721
	}
722
	if (win->clipcount > 16) {
723
		DEB_D("clipcount too big\n");
724
		return -EINVAL;
725
	}
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744

	field = win->field;
	maxw  = vv->standard->h_max_out;
	maxh  = vv->standard->v_max_out;

	if (V4L2_FIELD_ANY == field) {
		field = (win->w.height > maxh / 2)
			? V4L2_FIELD_INTERLACED
			: V4L2_FIELD_TOP;
		}
	switch (field) {
	case V4L2_FIELD_TOP:
	case V4L2_FIELD_BOTTOM:
	case V4L2_FIELD_ALTERNATE:
		maxh = maxh / 2;
		break;
	case V4L2_FIELD_INTERLACED:
		break;
	default:
745
		DEB_D("no known field mode '%d'\n", field);
746
		return -EINVAL;
L
Linus Torvalds 已提交
747
	}
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764

	win->field = field;
	if (win->w.width > maxw)
		win->w.width = maxw;
	if (win->w.height > maxh)
		win->w.height = maxh;

	return 0;
}

static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
{
	struct saa7146_fh *fh = __fh;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	int err;

765
	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
766
	if (IS_CAPTURE_ACTIVE(fh) != 0) {
767
		DEB_EE("streaming capture is active\n");
768
		return -EBUSY;
L
Linus Torvalds 已提交
769
	}
770 771 772
	err = vidioc_try_fmt_vid_cap(file, fh, f);
	if (0 != err)
		return err;
773
	vv->video_fmt = f->fmt.pix;
774
	DEB_EE("set to pixelformat '%4.4s'\n",
775
	       (char *)&vv->video_fmt.pixelformat);
776 777 778 779 780 781 782 783 784 785
	return 0;
}

static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
{
	struct saa7146_fh *fh = __fh;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	int err;

786
	DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
787 788 789
	err = vidioc_try_fmt_vid_overlay(file, fh, f);
	if (0 != err)
		return err;
790 791 792 793 794 795
	vv->ov.win    = f->fmt.win;
	vv->ov.nclips = f->fmt.win.clipcount;
	if (vv->ov.nclips > 16)
		vv->ov.nclips = 16;
	if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
				sizeof(struct v4l2_clip) * vv->ov.nclips)) {
796
		return -EFAULT;
L
Linus Torvalds 已提交
797
	}
798

799
	/* vv->ov.fh is used to indicate that we have valid overlay information, too */
800
	vv->ov.fh = fh;
801 802 803 804 805

	/* check if our current overlay is active */
	if (IS_OVERLAY_ACTIVE(fh) != 0) {
		saa7146_stop_preview(fh);
		saa7146_start_preview(fh);
L
Linus Torvalds 已提交
806
	}
807 808 809 810 811 812 813 814 815 816 817 818
	return 0;
}

static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
{
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;

	*norm = vv->standard->id;
	return 0;
}

L
Linus Torvalds 已提交
819 820 821
	/* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
	   PAL / NTSC / SECAM. if your hardware does not (or does more)
	   -- override this function in your extension */
822
/*
L
Linus Torvalds 已提交
823 824 825 826 827 828
	case VIDIOC_ENUMSTD:
	{
		struct v4l2_standard *e = arg;
		if (e->index < 0 )
			return -EINVAL;
		if( e->index < dev->ext_vv_data->num_stds ) {
829
			DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
L
Linus Torvalds 已提交
830 831 832 833 834
			v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
			return 0;
		}
		return -EINVAL;
	}
835
	*/
L
Linus Torvalds 已提交
836

837
static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
838 839 840 841 842
{
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_vv *vv = dev->vv_data;
	int found = 0;
	int err, i;
L
Linus Torvalds 已提交
843

844
	DEB_EE("VIDIOC_S_STD\n");
L
Linus Torvalds 已提交
845

846
	if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
847
		DEB_D("cannot change video standard while streaming capture is active\n");
848 849
		return -EBUSY;
	}
L
Linus Torvalds 已提交
850

851 852 853 854
	if ((vv->video_status & STATUS_OVERLAY) != 0) {
		vv->ov_suspend = vv->video_fh;
		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
		if (0 != err) {
855
			DEB_D("suspending video failed. aborting\n");
856
			return err;
L
Linus Torvalds 已提交
857
		}
858
	}
L
Linus Torvalds 已提交
859

860
	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
861
		if (id & dev->ext_vv_data->stds[i].id)
862 863 864 865 866 867 868
			break;
	if (i != dev->ext_vv_data->num_stds) {
		vv->standard = &dev->ext_vv_data->stds[i];
		if (NULL != dev->ext_vv_data->std_callback)
			dev->ext_vv_data->std_callback(dev, vv->standard);
		found = 1;
	}
L
Linus Torvalds 已提交
869

870 871 872
	if (vv->ov_suspend != NULL) {
		saa7146_start_preview(vv->ov_suspend);
		vv->ov_suspend = NULL;
L
Linus Torvalds 已提交
873 874
	}

875
	if (!found) {
876
		DEB_EE("VIDIOC_S_STD: standard not found\n");
877
		return -EINVAL;
L
Linus Torvalds 已提交
878 879
	}

880
	DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
881 882
	return 0;
}
L
Linus Torvalds 已提交
883

884 885 886
static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
{
	int err;
L
Linus Torvalds 已提交
887

888
	DEB_D("VIDIOC_OVERLAY on:%d\n", on);
889 890 891 892 893 894
	if (on)
		err = saa7146_start_preview(fh);
	else
		err = saa7146_stop_preview(fh);
	return err;
}
L
Linus Torvalds 已提交
895

896 897 898
static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
{
	struct saa7146_fh *fh = __fh;
L
Linus Torvalds 已提交
899

900 901 902 903 904 905
	if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return videobuf_reqbufs(&fh->video_q, b);
	if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
		return videobuf_reqbufs(&fh->vbi_q, b);
	return -EINVAL;
}
L
Linus Torvalds 已提交
906

907 908 909
static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
{
	struct saa7146_fh *fh = __fh;
L
Linus Torvalds 已提交
910

911 912 913 914 915 916
	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return videobuf_querybuf(&fh->video_q, buf);
	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
		return videobuf_querybuf(&fh->vbi_q, buf);
	return -EINVAL;
}
L
Linus Torvalds 已提交
917

918 919 920 921 922 923 924 925 926 927
static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
{
	struct saa7146_fh *fh = __fh;

	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return videobuf_qbuf(&fh->video_q, buf);
	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
		return videobuf_qbuf(&fh->vbi_q, buf);
	return -EINVAL;
}
928

929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
{
	struct saa7146_fh *fh = __fh;

	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
	if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
		return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
	return -EINVAL;
}

static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
{
	struct saa7146_fh *fh = __fh;
	int err;

945
	DEB_D("VIDIOC_STREAMON, type:%d\n", type);
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963

	err = video_begin(fh);
	if (err)
		return err;
	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return videobuf_streamon(&fh->video_q);
	if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
		return videobuf_streamon(&fh->vbi_q);
	return -EINVAL;
}

static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
{
	struct saa7146_fh *fh = __fh;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	int err;

964
	DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
965 966 967 968 969

	/* ugly: we need to copy some checks from video_end(),
	   because videobuf_streamoff() relies on the capture running.
	   check and fix this */
	if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
970
		DEB_S("not capturing\n");
L
Linus Torvalds 已提交
971 972
		return 0;
	}
973 974

	if (vv->video_fh != fh) {
975
		DEB_S("capturing, but in another open\n");
976
		return -EBUSY;
L
Linus Torvalds 已提交
977
	}
978 979 980 981 982 983 984

	err = -EINVAL;
	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
		err = videobuf_streamoff(&fh->video_q);
	else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
		err = videobuf_streamoff(&fh->vbi_q);
	if (0 != err) {
985
		DEB_D("warning: videobuf_streamoff() failed\n");
986 987 988 989 990 991 992 993 994 995
		video_end(fh, file);
	} else {
		err = video_end(fh, file);
	}
	return err;
}

const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
	.vidioc_querycap             = vidioc_querycap,
	.vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,
996
	.vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
997 998 999 1000 1001 1002 1003
	.vidioc_g_fmt_vid_cap        = vidioc_g_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap      = vidioc_try_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap        = vidioc_s_fmt_vid_cap,
	.vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
	.vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
	.vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,

1004 1005 1006
	.vidioc_overlay		     = vidioc_overlay,
	.vidioc_g_fbuf		     = vidioc_g_fbuf,
	.vidioc_s_fbuf		     = vidioc_s_fbuf,
1007 1008 1009 1010 1011 1012 1013 1014
	.vidioc_reqbufs              = vidioc_reqbufs,
	.vidioc_querybuf             = vidioc_querybuf,
	.vidioc_qbuf                 = vidioc_qbuf,
	.vidioc_dqbuf                = vidioc_dqbuf,
	.vidioc_g_std                = vidioc_g_std,
	.vidioc_s_std                = vidioc_s_std,
	.vidioc_streamon             = vidioc_streamon,
	.vidioc_streamoff            = vidioc_streamoff,
1015
	.vidioc_g_parm		     = vidioc_g_parm,
1016 1017
	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
1018
};
L
Linus Torvalds 已提交
1019

1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
	.vidioc_querycap             = vidioc_querycap,
	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,

	.vidioc_reqbufs              = vidioc_reqbufs,
	.vidioc_querybuf             = vidioc_querybuf,
	.vidioc_qbuf                 = vidioc_qbuf,
	.vidioc_dqbuf                = vidioc_dqbuf,
	.vidioc_g_std                = vidioc_g_std,
	.vidioc_s_std                = vidioc_s_std,
	.vidioc_streamon             = vidioc_streamon,
	.vidioc_streamoff            = vidioc_streamoff,
	.vidioc_g_parm		     = vidioc_g_parm,
	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
};

L
Linus Torvalds 已提交
1037 1038 1039 1040 1041 1042 1043 1044 1045
/*********************************************************************************/
/* buffer handling functions                                                  */

static int buffer_activate (struct saa7146_dev *dev,
		     struct saa7146_buf *buf,
		     struct saa7146_buf *next)
{
	struct saa7146_vv *vv = dev->vv_data;

1046
	buf->vb.state = VIDEOBUF_ACTIVE;
L
Linus Torvalds 已提交
1047 1048
	saa7146_set_capture(dev,buf,next);

1049
	mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
L
Linus Torvalds 已提交
1050 1051 1052
	return 0;
}

1053 1054 1055 1056 1057 1058 1059
static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
	saa7146_pgtable_free(dev->pci, &buf->pt[0]);
	saa7146_pgtable_free(dev->pci, &buf->pt[1]);
	saa7146_pgtable_free(dev->pci, &buf->pt[2]);
}

L
Linus Torvalds 已提交
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
static int buffer_prepare(struct videobuf_queue *q,
			  struct videobuf_buffer *vb, enum v4l2_field field)
{
	struct file *file = q->priv_data;
	struct saa7146_fh *fh = file->private_data;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
	int size,err = 0;

1070
	DEB_CAP("vbuf:%p\n", vb);
L
Linus Torvalds 已提交
1071 1072

	/* sanity checks */
1073 1074 1075 1076
	if (vv->video_fmt.width  < 48 ||
	    vv->video_fmt.height < 32 ||
	    vv->video_fmt.width  > vv->standard->h_max_out ||
	    vv->video_fmt.height > vv->standard->v_max_out) {
1077
		DEB_D("w (%d) / h (%d) out of bounds\n",
1078
		      vv->video_fmt.width, vv->video_fmt.height);
L
Linus Torvalds 已提交
1079 1080 1081
		return -EINVAL;
	}

1082
	size = vv->video_fmt.sizeimage;
L
Linus Torvalds 已提交
1083
	if (0 != buf->vb.baddr && buf->vb.bsize < size) {
1084
		DEB_D("size mismatch\n");
L
Linus Torvalds 已提交
1085 1086 1087
		return -EINVAL;
	}

1088
	DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
1089 1090 1091 1092 1093
		vv->video_fmt.width, vv->video_fmt.height,
		size, v4l2_field_names[vv->video_fmt.field]);
	if (buf->vb.width  != vv->video_fmt.width  ||
	    buf->vb.bytesperline != vv->video_fmt.bytesperline ||
	    buf->vb.height != vv->video_fmt.height ||
L
Linus Torvalds 已提交
1094 1095
	    buf->vb.size   != size ||
	    buf->vb.field  != field      ||
1096 1097
	    buf->vb.field  != vv->video_fmt.field  ||
	    buf->fmt       != &vv->video_fmt) {
1098
		saa7146_dma_free(dev,q,buf);
L
Linus Torvalds 已提交
1099 1100
	}

1101
	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
L
Linus Torvalds 已提交
1102 1103
		struct saa7146_format *sfmt;

1104 1105 1106
		buf->vb.bytesperline  = vv->video_fmt.bytesperline;
		buf->vb.width  = vv->video_fmt.width;
		buf->vb.height = vv->video_fmt.height;
L
Linus Torvalds 已提交
1107 1108
		buf->vb.size   = size;
		buf->vb.field  = field;
1109 1110
		buf->fmt       = &vv->video_fmt;
		buf->vb.field  = vv->video_fmt.field;
L
Linus Torvalds 已提交
1111

1112
		sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
L
Linus Torvalds 已提交
1113

1114
		release_all_pagetables(dev, buf);
L
Linus Torvalds 已提交
1115 1116 1117 1118 1119 1120 1121 1122
		if( 0 != IS_PLANAR(sfmt->trans)) {
			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
			saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
			saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
		} else {
			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
		}

1123
		err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
L
Linus Torvalds 已提交
1124 1125 1126 1127 1128 1129
		if (err)
			goto oops;
		err = saa7146_pgtable_build(dev,buf);
		if (err)
			goto oops;
	}
1130
	buf->vb.state = VIDEOBUF_PREPARED;
L
Linus Torvalds 已提交
1131 1132 1133 1134 1135
	buf->activate = buffer_activate;

	return 0;

 oops:
1136
	DEB_D("error out\n");
1137
	saa7146_dma_free(dev,q,buf);
L
Linus Torvalds 已提交
1138 1139 1140 1141 1142 1143 1144 1145

	return err;
}

static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
	struct file *file = q->priv_data;
	struct saa7146_fh *fh = file->private_data;
1146
	struct saa7146_vv *vv = fh->dev->vv_data;
L
Linus Torvalds 已提交
1147 1148 1149 1150

	if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
		*count = MAX_SAA7146_CAPTURE_BUFFERS;

1151
	*size = vv->video_fmt.sizeimage;
L
Linus Torvalds 已提交
1152 1153 1154 1155 1156 1157

	/* check if we exceed the "max_memory" parameter */
	if( (*count * *size) > (max_memory*1048576) ) {
		*count = (max_memory*1048576) / *size;
	}

1158
	DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
L
Linus Torvalds 已提交
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170

	return 0;
}

static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
	struct file *file = q->priv_data;
	struct saa7146_fh *fh = file->private_data;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	struct saa7146_buf *buf = (struct saa7146_buf *)vb;

1171
	DEB_CAP("vbuf:%p\n", vb);
1172
	saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
L
Linus Torvalds 已提交
1173 1174 1175 1176 1177 1178 1179 1180 1181
}

static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
	struct file *file = q->priv_data;
	struct saa7146_fh *fh = file->private_data;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_buf *buf = (struct saa7146_buf *)vb;

1182
	DEB_CAP("vbuf:%p\n", vb);
1183

1184
	saa7146_dma_free(dev,q,buf);
1185 1186

	release_all_pagetables(dev, buf);
L
Linus Torvalds 已提交
1187 1188
}

1189
static const struct videobuf_queue_ops video_qops = {
L
Linus Torvalds 已提交
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
	.buf_setup    = buffer_setup,
	.buf_prepare  = buffer_prepare,
	.buf_queue    = buffer_queue,
	.buf_release  = buffer_release,
};

/********************************************************************************/
/* file operations */

static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
{
1201
	INIT_LIST_HEAD(&vv->video_dmaq.queue);
L
Linus Torvalds 已提交
1202

1203
	timer_setup(&vv->video_dmaq.timeout, saa7146_buffer_timeout, 0);
1204
	vv->video_dmaq.dev              = dev;
L
Linus Torvalds 已提交
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216

	/* set some default values */
	vv->standard = &dev->ext_vv_data->stds[0];

	/* FIXME: what's this? */
	vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
	vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
}


static int video_open(struct saa7146_dev *dev, struct file *file)
{
1217
	struct saa7146_fh *fh = file->private_data;
L
Linus Torvalds 已提交
1218

1219 1220
	videobuf_queue_sg_init(&fh->video_q, &video_qops,
			    &dev->pci->dev, &dev->slock,
L
Linus Torvalds 已提交
1221 1222 1223
			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
			    V4L2_FIELD_INTERLACED,
			    sizeof(struct saa7146_buf),
1224
			    file, &dev->v4l2_lock);
L
Linus Torvalds 已提交
1225 1226 1227 1228 1229 1230 1231

	return 0;
}


static void video_close(struct saa7146_dev *dev, struct file *file)
{
1232
	struct saa7146_fh *fh = file->private_data;
L
Linus Torvalds 已提交
1233
	struct saa7146_vv *vv = dev->vv_data;
1234
	struct videobuf_queue *q = &fh->video_q;
L
Linus Torvalds 已提交
1235

1236 1237 1238 1239
	if (IS_CAPTURE_ACTIVE(fh) != 0)
		video_end(fh, file);
	else if (IS_OVERLAY_ACTIVE(fh) != 0)
		saa7146_stop_preview(fh);
L
Linus Torvalds 已提交
1240

1241
	videobuf_stop(q);
L
Linus Torvalds 已提交
1242 1243 1244 1245 1246 1247 1248
	/* hmm, why is this function declared void? */
}


static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
{
	struct saa7146_vv *vv = dev->vv_data;
1249
	struct saa7146_dmaqueue *q = &vv->video_dmaq;
L
Linus Torvalds 已提交
1250 1251

	spin_lock(&dev->slock);
1252
	DEB_CAP("called\n");
L
Linus Torvalds 已提交
1253 1254 1255

	/* only finish the buffer if we have one... */
	if( NULL != q->curr ) {
1256
		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
L
Linus Torvalds 已提交
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
	}
	saa7146_buffer_next(dev,q,0);

	spin_unlock(&dev->slock);
}

static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
	struct saa7146_fh *fh = file->private_data;
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	ssize_t ret = 0;

1270
	DEB_EE("called\n");
L
Linus Torvalds 已提交
1271 1272 1273 1274

	if ((vv->video_status & STATUS_CAPTURE) != 0) {
		/* fixme: should we allow read() captures while streaming capture? */
		if (vv->video_fh == fh) {
1275
			DEB_S("already capturing\n");
L
Linus Torvalds 已提交
1276 1277
			return -EBUSY;
		}
1278
		DEB_S("already capturing in another open\n");
L
Linus Torvalds 已提交
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
		return -EBUSY;
	}

	ret = video_begin(fh);
	if( 0 != ret) {
		goto out;
	}

	ret = videobuf_read_one(&fh->video_q , data, count, ppos,
				file->f_flags & O_NONBLOCK);
	if (ret != 0) {
		video_end(fh, file);
	} else {
		ret = video_end(fh, file);
	}
out:
	/* restart overlay if it was active before */
	if (vv->ov_suspend != NULL) {
		saa7146_start_preview(vv->ov_suspend);
		vv->ov_suspend = NULL;
	}

	return ret;
}

1304
const struct saa7146_use_ops saa7146_video_uops = {
L
Linus Torvalds 已提交
1305 1306 1307 1308 1309 1310
	.init = video_init,
	.open = video_open,
	.release = video_close,
	.irq_done = video_irq_done,
	.read = video_read,
};