saa7146_vbi.c 13.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
#include <media/saa7146_vv.h>

static int vbi_pixel_to_capture = 720 * 2;

static int vbi_workaround(struct saa7146_dev *dev)
{
	struct saa7146_vv *vv = dev->vv_data;

9 10
	u32          *cpu;
	dma_addr_t   dma_addr;
L
Linus Torvalds 已提交
11 12 13 14 15 16

	int count = 0;
	int i;

	DECLARE_WAITQUEUE(wait, current);

17
	DEB_VBI("dev:%p\n", dev);
L
Linus Torvalds 已提交
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

	/* once again, a bug in the saa7146: the brs acquisition
	   is buggy and especially the BXO-counter does not work
	   as specified. there is this workaround, but please
	   don't let me explain it. ;-) */

	cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr);
	if (NULL == cpu)
		return -ENOMEM;

	/* setup some basic programming, just for the workaround */
	saa7146_write(dev, BASE_EVEN3,	dma_addr);
	saa7146_write(dev, BASE_ODD3,	dma_addr+vbi_pixel_to_capture);
	saa7146_write(dev, PROT_ADDR3,	dma_addr+4096);
	saa7146_write(dev, PITCH3,	vbi_pixel_to_capture);
	saa7146_write(dev, BASE_PAGE3,	0x0);
	saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
	saa7146_write(dev, MC2, MASK_04|MASK_20);

	/* load brs-control register */
	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
	/* BXO = 1h, BRS to outbound */
	WRITE_RPS1(0xc000008c);
	/* wait for vbi_a or vbi_b*/
	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
43
		DEB_D("...using port b\n");
L
Linus Torvalds 已提交
44 45 46 47 48 49
		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
/*
		WRITE_RPS1(CMD_PAUSE | MASK_09);
*/
	} else {
50
		DEB_D("...using port a\n");
L
Linus Torvalds 已提交
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
		WRITE_RPS1(CMD_PAUSE | MASK_10);
	}
	/* upload brs */
	WRITE_RPS1(CMD_UPLOAD | MASK_08);
	/* load brs-control register */
	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
	/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
	WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
	/* wait for brs_done */
	WRITE_RPS1(CMD_PAUSE | MASK_08);
	/* upload brs */
	WRITE_RPS1(CMD_UPLOAD | MASK_08);
	/* load video-dma3 NumLines3 and NumBytes3 */
	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
	/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
	WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
	/* load brs-control register */
	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
	/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
	WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start
	/* wait for brs_done */
	WRITE_RPS1(CMD_PAUSE | MASK_08);
	/* upload brs and video-dma3*/
	WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
	/* load mc2 register: enable dma3 */
	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
	WRITE_RPS1(MASK_20 | MASK_04);
	/* generate interrupt */
	WRITE_RPS1(CMD_INTERRUPT);
	/* stop rps1 */
	WRITE_RPS1(CMD_STOP);

	/* we have to do the workaround twice to be sure that
	   everything is ok */
	for(i = 0; i < 2; i++) {

		/* indicate to the irq handler that we do the workaround */
		saa7146_write(dev, MC2, MASK_31|MASK_15);

		saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
		saa7146_write(dev, MC2, MASK_04|MASK_20);

		/* enable rps1 irqs */
		SAA7146_IER_ENABLE(dev,MASK_28);

		/* prepare to wait to be woken up by the irq-handler */
		add_wait_queue(&vv->vbi_wq, &wait);
		current->state = TASK_INTERRUPTIBLE;

		/* start rps1 to enable workaround */
		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
		saa7146_write(dev, MC1, (MASK_13 | MASK_29));

		schedule();

106
		DEB_VBI("brs bug workaround %d/1\n", i);
L
Linus Torvalds 已提交
107 108 109 110 111 112 113 114 115 116 117 118

		remove_wait_queue(&vv->vbi_wq, &wait);
		current->state = TASK_RUNNING;

		/* disable rps1 irqs */
		SAA7146_IER_DISABLE(dev,MASK_28);

		/* stop video-dma3 */
		saa7146_write(dev, MC1, MASK_20);

		if(signal_pending(current)) {

119 120
			DEB_VBI("aborted (rps:0x%08x)\n",
				saa7146_read(dev, RPS_ADDR1));
L
Linus Torvalds 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

			/* stop rps1 for sure */
			saa7146_write(dev, MC1, MASK_29);

			pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
			return -EINTR;
		}
	}

	pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
	return 0;
}

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

	struct saa7146_video_dma vdma3;

	int count = 0;
	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;

/*
	vdma3.base_even	= 0xc8000000+2560*70;
	vdma3.base_odd	= 0xc8000000;
	vdma3.prot_addr	= 0xc8000000+2560*164;
	vdma3.pitch	= 2560;
	vdma3.base_page	= 0;
	vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
*/
	vdma3.base_even	= buf->pt[2].offset;
	vdma3.base_odd	= buf->pt[2].offset + 16 * vbi_pixel_to_capture;
	vdma3.prot_addr	= buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;
	vdma3.pitch	= vbi_pixel_to_capture;
	vdma3.base_page	= buf->pt[2].dma | ME1;
	vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;

	saa7146_write_out_dma(dev, 3, &vdma3);

	/* write beginning of rps-program */
	count = 0;

	/* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */

	/* we don't wait here for the first field anymore. this is different from the video
	   capture and might cause that the first buffer is only half filled (with only
	   one field). but since this is some sort of streaming data, this is not that negative.
169
	   but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208

/*
	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
*/
	/* set bit 1 */
	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
	WRITE_RPS1(MASK_28 | MASK_12);

	/* turn on video-dma3 */
	WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
	WRITE_RPS1(MASK_04 | MASK_20);			/* => mask */
	WRITE_RPS1(MASK_04 | MASK_20);			/* => values */

	/* wait for o_fid_a/b / e_fid_a/b toggle */
	WRITE_RPS1(CMD_PAUSE | o_wait);
	WRITE_RPS1(CMD_PAUSE | e_wait);

	/* generate interrupt */
	WRITE_RPS1(CMD_INTERRUPT);

	/* stop */
	WRITE_RPS1(CMD_STOP);

	/* enable rps1 irqs */
	SAA7146_IER_ENABLE(dev, MASK_28);

	/* write the address of the rps-program */
	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);

	/* turn on rps */
	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
}

static int buffer_activate(struct saa7146_dev *dev,
			   struct saa7146_buf *buf,
			   struct saa7146_buf *next)
{
	struct saa7146_vv *vv = dev->vv_data;
209
	buf->vb.state = VIDEOBUF_ACTIVE;
L
Linus Torvalds 已提交
210

211
	DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
L
Linus Torvalds 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
	saa7146_set_vbi_capture(dev,buf,next);

	mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
	return 0;
}

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_buf *buf = (struct saa7146_buf *)vb;

	int err = 0;
	int lines, llength, size;

	lines   = 16 * 2 ; /* 2 fields */
	llength = vbi_pixel_to_capture;
	size = lines * llength;

232
	DEB_VBI("vb:%p\n", vb);
L
Linus Torvalds 已提交
233 234

	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
235
		DEB_VBI("size mismatch\n");
L
Linus Torvalds 已提交
236 237 238 239
		return -EINVAL;
	}

	if (buf->vb.size != size)
240
		saa7146_dma_free(dev,q,buf);
L
Linus Torvalds 已提交
241

242
	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
243 244
		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);

L
Linus Torvalds 已提交
245 246 247 248 249 250 251 252
		buf->vb.width  = llength;
		buf->vb.height = lines;
		buf->vb.size   = size;
		buf->vb.field  = field;	// FIXME: check this

		saa7146_pgtable_free(dev->pci, &buf->pt[2]);
		saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);

253
		err = videobuf_iolock(q,&buf->vb, NULL);
L
Linus Torvalds 已提交
254 255
		if (err)
			goto oops;
256 257
		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
						 dma->sglist, dma->sglen);
L
Linus Torvalds 已提交
258 259 260
		if (0 != err)
			return err;
	}
261
	buf->vb.state = VIDEOBUF_PREPARED;
L
Linus Torvalds 已提交
262 263 264 265 266
	buf->activate = buffer_activate;

	return 0;

 oops:
267
	DEB_VBI("error out\n");
268
	saa7146_dma_free(dev,q,buf);
L
Linus Torvalds 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282

	return err;
}

static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
	int llength,lines;

	lines   = 16 * 2 ; /* 2 fields */
	llength = vbi_pixel_to_capture;

	*size = lines * llength;
	*count = 2;

283
	DEB_VBI("count:%d, size:%d\n", *count, *size);
L
Linus Torvalds 已提交
284 285 286 287 288 289 290 291 292 293 294 295

	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;

296
	DEB_VBI("vb:%p\n", vb);
L
Linus Torvalds 已提交
297 298 299 300 301 302 303 304 305 306
	saa7146_buffer_queue(dev,&vv->vbi_q,buf);
}

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;

307
	DEB_VBI("vb:%p\n", vb);
308
	saa7146_dma_free(dev,q,buf);
L
Linus Torvalds 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
}

static struct videobuf_queue_ops vbi_qops = {
	.buf_setup    = buffer_setup,
	.buf_prepare  = buffer_prepare,
	.buf_queue    = buffer_queue,
	.buf_release  = buffer_release,
};

/* ------------------------------------------------------------------ */

static void vbi_stop(struct saa7146_fh *fh, struct file *file)
{
	struct saa7146_dev *dev = fh->dev;
	struct saa7146_vv *vv = dev->vv_data;
	unsigned long flags;
325
	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338

	spin_lock_irqsave(&dev->slock,flags);

	/* disable rps1  */
	saa7146_write(dev, MC1, MASK_29);

	/* disable rps1 irqs */
	SAA7146_IER_DISABLE(dev, MASK_28);

	/* shut down dma 3 transfers */
	saa7146_write(dev, MC1, MASK_20);

	if (vv->vbi_q.curr) {
339
		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
L
Linus Torvalds 已提交
340 341 342 343 344 345 346
	}

	videobuf_queue_cancel(&fh->vbi_q);

	vv->vbi_streaming = NULL;

	del_timer(&vv->vbi_q.timeout);
347
	del_timer(&vv->vbi_read_timeout);
L
Linus Torvalds 已提交
348 349 350 351 352 353 354 355 356 357

	spin_unlock_irqrestore(&dev->slock, flags);
}

static void vbi_read_timeout(unsigned long data)
{
	struct file *file = (struct file*)data;
	struct saa7146_fh *fh = file->private_data;
	struct saa7146_dev *dev = fh->dev;

358
	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
359 360 361 362 363 364

	vbi_stop(fh, file);
}

static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
{
365
	DEB_VBI("dev:%p\n", dev);
L
Linus Torvalds 已提交
366 367 368 369 370 371 372 373 374 375 376 377 378

	INIT_LIST_HEAD(&vv->vbi_q.queue);

	init_timer(&vv->vbi_q.timeout);
	vv->vbi_q.timeout.function = saa7146_buffer_timeout;
	vv->vbi_q.timeout.data     = (unsigned long)(&vv->vbi_q);
	vv->vbi_q.dev              = dev;

	init_waitqueue_head(&vv->vbi_wq);
}

static int vbi_open(struct saa7146_dev *dev, struct file *file)
{
379
	struct saa7146_fh *fh = file->private_data;
380
	struct saa7146_vv *vv = fh->dev->vv_data;
L
Linus Torvalds 已提交
381 382 383 384

	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
	int ret = 0;

385
	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
386 387 388

	ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
	if (0 == ret) {
389
		DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
L
Linus Torvalds 已提交
390 391 392 393 394 395 396 397 398
		return -EBUSY;
	}

	/* adjust arbitrition control for video dma 3 */
	arbtr_ctrl &= ~0x1f0000;
	arbtr_ctrl |=  0x1d0000;
	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
	saa7146_write(dev, MC2, (MASK_04|MASK_20));

399 400
	videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
			    &dev->pci->dev, &dev->slock,
L
Linus Torvalds 已提交
401 402 403
			    V4L2_BUF_TYPE_VBI_CAPTURE,
			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
			    sizeof(struct saa7146_buf),
404
			    file, &dev->v4l2_lock);
L
Linus Torvalds 已提交
405

406 407
	vv->vbi_read_timeout.function = vbi_read_timeout;
	vv->vbi_read_timeout.data = (unsigned long)file;
L
Linus Torvalds 已提交
408 409 410 411 412 413 414 415

	/* initialize the brs */
	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
		saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
	} else {
		saa7146_write(dev, BRS_CTRL, 0x00000001);

		if (0 != (ret = vbi_workaround(dev))) {
416
			DEB_VBI("vbi workaround failed!\n");
L
Linus Torvalds 已提交
417 418 419 420 421 422 423 424 425 426 427
			/* return ret;*/
		}
	}

	/* upload brs register */
	saa7146_write(dev, MC2, (MASK_08|MASK_24));
	return 0;
}

static void vbi_close(struct saa7146_dev *dev, struct file *file)
{
428
	struct saa7146_fh *fh = file->private_data;
L
Linus Torvalds 已提交
429
	struct saa7146_vv *vv = dev->vv_data;
430
	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443

	if( fh == vv->vbi_streaming ) {
		vbi_stop(fh, file);
	}
	saa7146_res_free(fh, RESOURCE_DMA3_BRS);
}

static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
{
	struct saa7146_vv *vv = dev->vv_data;
	spin_lock(&dev->slock);

	if (vv->vbi_q.curr) {
444
		DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_q.curr);
L
Linus Torvalds 已提交
445 446 447
		/* this must be += 2, one count for each field */
		vv->vbi_fieldcount+=2;
		vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
448
		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
L
Linus Torvalds 已提交
449
	} else {
450
		DEB_VBI("dev:%p\n", dev);
L
Linus Torvalds 已提交
451 452 453 454 455 456 457 458 459 460 461 462 463
	}
	saa7146_buffer_next(dev,&vv->vbi_q,1);

	spin_unlock(&dev->slock);
}

static ssize_t vbi_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;

464
	DEB_VBI("dev:%p, fh:%p\n", dev, fh);
L
Linus Torvalds 已提交
465 466 467 468 469 470 471 472

	if( NULL == vv->vbi_streaming ) {
		// fixme: check if dma3 is available
		// fixme: activate vbi engine here if necessary. (really?)
		vv->vbi_streaming = fh;
	}

	if( fh != vv->vbi_streaming ) {
473 474
		DEB_VBI("open %p is already using vbi capture\n",
			vv->vbi_streaming);
L
Linus Torvalds 已提交
475 476 477
		return -EBUSY;
	}

478
	mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
L
Linus Torvalds 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
	ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
				   file->f_flags & O_NONBLOCK);
/*
	printk("BASE_ODD3:      0x%08x\n", saa7146_read(dev, BASE_ODD3));
	printk("BASE_EVEN3:     0x%08x\n", saa7146_read(dev, BASE_EVEN3));
	printk("PROT_ADDR3:     0x%08x\n", saa7146_read(dev, PROT_ADDR3));
	printk("PITCH3:         0x%08x\n", saa7146_read(dev, PITCH3));
	printk("BASE_PAGE3:     0x%08x\n", saa7146_read(dev, BASE_PAGE3));
	printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));
	printk("BRS_CTRL:       0x%08x\n", saa7146_read(dev, BRS_CTRL));
*/
	return ret;
}

struct saa7146_use_ops saa7146_vbi_uops = {
494 495
	.init		= vbi_init,
	.open		= vbi_open,
L
Linus Torvalds 已提交
496 497
	.release	= vbi_close,
	.irq_done	= vbi_irq_done,
498
	.read		= vbi_read,
L
Linus Torvalds 已提交
499
};