solo6x10-v4l2.c 18.5 KB
Newer Older
1
/*
2 3 4 5 6 7 8
 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
 *
 * Original author:
 * Ben Collins <bcollins@ubuntu.com>
 *
 * Additional work by:
 * John Brooks <john.brooks@bluecherry.net>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
25

26 27
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
28
#include <media/v4l2-event.h>
29
#include <media/videobuf2-v4l2.h>
30
#include <media/videobuf2-dma-contig.h>
31

32
#include "solo6x10.h"
H
Hans Verkuil 已提交
33
#include "solo6x10-tw28.h"
34

35 36
/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */
#define SOLO_HW_BPL		2048
37 38 39 40 41
#define solo_vlines(__solo)	(__solo->video_vsize * 2)
#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
				 solo_vlines(__solo))
#define solo_bytesperline(__solo) (__solo->video_hsize * 2)

42
#define MIN_VID_BUFFERS		2
43

44
static inline void erase_on(struct solo_dev *solo_dev)
45 46 47 48 49 50
{
	solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
	solo_dev->erasing = 1;
	solo_dev->frame_blank = 0;
}

51
static inline int erase_off(struct solo_dev *solo_dev)
52 53 54 55 56 57 58 59 60 61 62 63 64 65
{
	if (!solo_dev->erasing)
		return 0;

	/* First time around, assert erase off */
	if (!solo_dev->frame_blank)
		solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
	/* Keep the erasing flag on for 8 frames minimum */
	if (solo_dev->frame_blank++ >= 8)
		solo_dev->erasing = 0;

	return 1;
}

66
void solo_video_in_isr(struct solo_dev *solo_dev)
67
{
68
	wake_up_interruptible_all(&solo_dev->disp_thread_wait);
69 70
}

71
static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
72 73 74 75 76 77 78 79 80 81 82 83
			   int sx, int sy, int ex, int ey, int scale)
{
	if (ch >= solo_dev->nr_chans)
		return;

	/* Here, we just keep window/channel the same */
	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
		       SOLO_VI_WIN_CHANNEL(ch) |
		       SOLO_VI_WIN_SX(sx) |
		       SOLO_VI_WIN_EX(ex) |
		       SOLO_VI_WIN_SCALE(scale));

84
	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
85 86 87 88
		       SOLO_VI_WIN_SY(sy) |
		       SOLO_VI_WIN_EY(ey));
}

89
static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
90 91 92 93 94 95 96 97
{
	u8 ch = idx * 4;

	if (ch >= solo_dev->nr_chans)
		return -EINVAL;

	if (!on) {
		u8 i;
98

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
		for (i = ch; i < ch + 4; i++)
			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
				       solo_vlines(solo_dev),
				       solo_dev->video_hsize,
				       solo_vlines(solo_dev), 0);
		return 0;
	}

	/* Row 1 */
	solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
		       solo_vlines(solo_dev) / 2, 3);
	solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
		       solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
	/* Row 2 */
	solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
		       solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
	solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
		       solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
		       solo_vlines(solo_dev), 3);

	return 0;
}

122
static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
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
{
	int sy, ysize, hsize, i;

	if (!on) {
		for (i = 0; i < 16; i++)
			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
				       solo_vlines(solo_dev),
				       solo_dev->video_hsize,
				       solo_vlines(solo_dev), 0);
		return 0;
	}

	ysize = solo_vlines(solo_dev) / 4;
	hsize = solo_dev->video_hsize / 4;

	for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
		solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
			       sy + ysize, 5);
		solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
			       hsize * 2, sy + ysize, 5);
		solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
			       hsize * 3, sy + ysize, 5);
		solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
			       solo_dev->video_hsize, sy + ysize, 5);
	}

	return 0;
}

152
static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
{
	u8 ext_ch;

	if (ch < solo_dev->nr_chans) {
		solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
			       on ? 0 : solo_vlines(solo_dev),
			       solo_dev->video_hsize, solo_vlines(solo_dev),
			       on ? 1 : 0);
		return 0;
	}

	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
		return -EINVAL;

	ext_ch = ch - solo_dev->nr_chans;

	/* 4up's first */
	if (ext_ch < 4)
		return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);

	/* Remaining case is 16up for 16-port */
	return solo_v4l2_ch_ext_16up(solo_dev, on);
}

177
static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
178 179 180 181 182 183 184 185 186 187 188 189 190 191
{
	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
		return -EINVAL;

	erase_on(solo_dev);

	solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
	solo_v4l2_ch(solo_dev, ch, 1);

	solo_dev->cur_disp_ch = ch;

	return 0;
}

192
static void solo_fillbuf(struct solo_dev *solo_dev,
193
			 struct vb2_buffer *vb)
194
{
195 196
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	dma_addr_t addr;
197
	unsigned int fdma_addr;
198
	int error = -1;
199 200
	int i;

201 202
	addr = vb2_dma_contig_plane_dma_addr(vb, 0);
	if (!addr)
203 204 205
		goto finish_buf;

	if (erase_off(solo_dev)) {
206
		void *p = vb2_plane_vaddr(vb, 0);
207
		int image_size = solo_image_size(solo_dev);
208

209 210 211
		for (i = 0; i < image_size; i += 2) {
			((u8 *)p)[i] = 0x80;
			((u8 *)p)[i + 1] = 0x00;
212 213
		}
		error = 0;
214
	} else {
215
		fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write *
216
				(SOLO_HW_BPL * solo_vlines(solo_dev)));
217

218
		error = solo_p2m_dma_t(solo_dev, 0, addr, fdma_addr,
219 220
				       solo_bytesperline(solo_dev),
				       solo_vlines(solo_dev), SOLO_HW_BPL);
221
	}
222

223
finish_buf:
224 225 226
	if (!error) {
		vb2_set_plane_payload(vb, 0,
			solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
227
		vbuf->sequence = solo_dev->sequence++;
228
		vb->timestamp = ktime_get_ns();
229 230
	}

231
	vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
232 233
}

234
static void solo_thread_try(struct solo_dev *solo_dev)
235
{
236
	struct solo_vb2_buf *vb;
237

238 239
	/* Only "break" from this loop if slock is held, otherwise
	 * just return. */
240
	for (;;) {
241 242 243
		unsigned int cur_write;

		cur_write = SOLO_VI_STATUS0_PAGE(
244 245
			solo_reg_read(solo_dev, SOLO_VI_STATUS0));
		if (cur_write == solo_dev->old_write)
246 247
			return;

248
		spin_lock(&solo_dev->slock);
249

250
		if (list_empty(&solo_dev->vidq_active))
251 252
			break;

253 254
		vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf,
				      list);
255

256
		solo_dev->old_write = cur_write;
257
		list_del(&vb->list);
258

259
		spin_unlock(&solo_dev->slock);
260

261
		solo_fillbuf(solo_dev, &vb->vb.vb2_buf);
262 263
	}

264 265
	assert_spin_locked(&solo_dev->slock);
	spin_unlock(&solo_dev->slock);
266 267 268 269
}

static int solo_thread(void *data)
{
270
	struct solo_dev *solo_dev = data;
271 272 273 274 275 276 277
	DECLARE_WAITQUEUE(wait, current);

	set_freezable();
	add_wait_queue(&solo_dev->disp_thread_wait, &wait);

	for (;;) {
		long timeout = schedule_timeout_interruptible(HZ);
278

279 280
		if (timeout == -ERESTARTSYS || kthread_should_stop())
			break;
281
		solo_thread_try(solo_dev);
282 283 284 285 286
		try_to_freeze();
	}

	remove_wait_queue(&solo_dev->disp_thread_wait, &wait);

287
	return 0;
288 289
}

290
static int solo_start_thread(struct solo_dev *solo_dev)
291
{
292 293
	int ret = 0;

294
	solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
295

296 297 298
	if (IS_ERR(solo_dev->kthread)) {
		ret = PTR_ERR(solo_dev->kthread);
		solo_dev->kthread = NULL;
299
		return ret;
300
	}
301
	solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
302 303

	return ret;
304 305
}

306
static void solo_stop_thread(struct solo_dev *solo_dev)
307
{
308
	if (!solo_dev->kthread)
309 310
		return;

311
	solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
312 313
	kthread_stop(solo_dev->kthread);
	solo_dev->kthread = NULL;
314 315
}

316
static int solo_queue_setup(struct vb2_queue *q,
317
			   unsigned int *num_buffers, unsigned int *num_planes,
318
			   unsigned int sizes[], struct device *alloc_devs[])
319
{
320
	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
321

322 323
	sizes[0] = solo_image_size(solo_dev);
	*num_planes = 1;
324

325 326
	if (*num_buffers < MIN_VID_BUFFERS)
		*num_buffers = MIN_VID_BUFFERS;
327

328
	return 0;
329 330
}

331
static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
332
{
333
	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
334

335
	solo_dev->sequence = 0;
336 337
	return solo_start_thread(solo_dev);
}
338

339
static void solo_stop_streaming(struct vb2_queue *q)
340 341
{
	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
342

343 344
	solo_stop_thread(solo_dev);
	INIT_LIST_HEAD(&solo_dev->vidq_active);
345 346
}

347
static void solo_buf_queue(struct vb2_buffer *vb)
348
{
349
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
350 351 352
	struct vb2_queue *vq = vb->vb2_queue;
	struct solo_dev *solo_dev = vb2_get_drv_priv(vq);
	struct solo_vb2_buf *solo_vb =
353
		container_of(vbuf, struct solo_vb2_buf, vb);
354

355 356 357
	spin_lock(&solo_dev->slock);
	list_add_tail(&solo_vb->list, &solo_dev->vidq_active);
	spin_unlock(&solo_dev->slock);
358 359 360
	wake_up_interruptible(&solo_dev->disp_thread_wait);
}

361 362
static const struct vb2_ops solo_video_qops = {
	.queue_setup	= solo_queue_setup,
363
	.buf_queue	= solo_buf_queue,
364 365 366 367
	.start_streaming = solo_start_streaming,
	.stop_streaming = solo_stop_streaming,
	.wait_prepare	= vb2_ops_wait_prepare,
	.wait_finish	= vb2_ops_wait_finish,
368 369 370 371 372
};

static int solo_querycap(struct file *file, void  *priv,
			 struct v4l2_capability *cap)
{
373
	struct solo_dev *solo_dev = video_drvdata(file);
374

375 376
	strcpy(cap->driver, SOLO6X10_NAME);
	strcpy(cap->card, "Softlogic 6x10");
377
	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
378
		 pci_name(solo_dev->pdev));
379 380 381
	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
382 383 384
	return 0;
}

385
static int solo_enum_ext_input(struct solo_dev *solo_dev,
386 387
			       struct v4l2_input *input)
{
388 389
	int ext = input->index - solo_dev->nr_chans;
	unsigned int nup, first;
390

391 392
	if (ext >= solo_dev->nr_ext)
		return -EINVAL;
393

394 395 396 397 398 399 400 401 402 403 404 405
	nup   = (ext == 4) ? 16 : 4;
	first = (ext & 3) << 2; /* first channel in the n-up */
	snprintf(input->name, sizeof(input->name),
		 "Multi %d-up (cameras %d-%d)",
		 nup, first + 1, first + nup);
	/* Possible outputs:
	 *  Multi 4-up (cameras 1-4)
	 *  Multi 4-up (cameras 5-8)
	 *  Multi 4-up (cameras 9-12)
	 *  Multi 4-up (cameras 13-16)
	 *  Multi 16-up (cameras 1-16)
	 */
406 407 408 409 410 411
	return 0;
}

static int solo_enum_input(struct file *file, void *priv,
			   struct v4l2_input *input)
{
412
	struct solo_dev *solo_dev = video_drvdata(file);
413 414 415

	if (input->index >= solo_dev->nr_chans) {
		int ret = solo_enum_ext_input(solo_dev, input);
416

417 418 419 420 421 422 423 424 425 426 427 428
		if (ret < 0)
			return ret;
	} else {
		snprintf(input->name, sizeof(input->name), "Camera %d",
			 input->index + 1);

		/* We can only check this for normal inputs */
		if (!tw28_get_video_status(solo_dev, input->index))
			input->status = V4L2_IN_ST_NO_SIGNAL;
	}

	input->type = V4L2_INPUT_TYPE_CAMERA;
429
	input->std = solo_dev->vfd->tvnorms;
430 431 432 433 434
	return 0;
}

static int solo_set_input(struct file *file, void *priv, unsigned int index)
{
435 436
	struct solo_dev *solo_dev = video_drvdata(file);
	int ret = solo_v4l2_set_ch(solo_dev, index);
437 438

	if (!ret) {
439
		while (erase_off(solo_dev))
440 441
			/* Do nothing */;
	}
442

443
	return ret;
444 445 446 447
}

static int solo_get_input(struct file *file, void *priv, unsigned int *index)
{
448
	struct solo_dev *solo_dev = video_drvdata(file);
449

450
	*index = solo_dev->cur_disp_ch;
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

	return 0;
}

static int solo_enum_fmt_cap(struct file *file, void *priv,
			     struct v4l2_fmtdesc *f)
{
	if (f->index)
		return -EINVAL;

	f->pixelformat = V4L2_PIX_FMT_UYVY;
	strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));

	return 0;
}

static int solo_try_fmt_cap(struct file *file, void *priv,
			    struct v4l2_format *f)
{
470
	struct solo_dev *solo_dev = video_drvdata(file);
471 472 473
	struct v4l2_pix_format *pix = &f->fmt.pix;
	int image_size = solo_image_size(solo_dev);

474
	if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
475 476
		return -EINVAL;

477 478 479 480 481 482 483
	pix->width = solo_dev->video_hsize;
	pix->height = solo_vlines(solo_dev);
	pix->sizeimage = image_size;
	pix->field = V4L2_FIELD_INTERLACED;
	pix->pixelformat = V4L2_PIX_FMT_UYVY;
	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
	pix->priv = 0;
484 485 486 487 488 489
	return 0;
}

static int solo_set_fmt_cap(struct file *file, void *priv,
			    struct v4l2_format *f)
{
490
	struct solo_dev *solo_dev = video_drvdata(file);
491

492
	if (vb2_is_busy(&solo_dev->vidq))
493 494 495 496 497 498 499 500 501 502
		return -EBUSY;

	/* For right now, if it doesn't match our running config,
	 * then fail */
	return solo_try_fmt_cap(file, priv, f);
}

static int solo_get_fmt_cap(struct file *file, void *priv,
			    struct v4l2_format *f)
{
503
	struct solo_dev *solo_dev = video_drvdata(file);
504 505 506 507 508
	struct v4l2_pix_format *pix = &f->fmt.pix;

	pix->width = solo_dev->video_hsize;
	pix->height = solo_vlines(solo_dev);
	pix->pixelformat = V4L2_PIX_FMT_UYVY;
509
	pix->field = V4L2_FIELD_INTERLACED;
510 511 512
	pix->sizeimage = solo_image_size(solo_dev);
	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
	pix->bytesperline = solo_bytesperline(solo_dev);
513
	pix->priv = 0;
514 515 516 517

	return 0;
}

518
static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i)
519
{
520 521 522 523 524 525
	struct solo_dev *solo_dev = video_drvdata(file);

	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
		*i = V4L2_STD_NTSC_M;
	else
		*i = V4L2_STD_PAL;
526 527 528
	return 0;
}

529
int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz)
530 531 532 533 534 535 536 537 538
{
	int i;

	/* Make sure all video nodes are idle */
	if (vb2_is_busy(&solo_dev->vidq))
		return -EBUSY;
	for (i = 0; i < solo_dev->nr_chans; i++)
		if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq))
			return -EBUSY;
539 540
	solo_dev->video_type = is_50hz ? SOLO_VO_FMT_TYPE_PAL :
					 SOLO_VO_FMT_TYPE_NTSC;
541 542 543 544 545 546 547 548 549 550 551 552 553
	/* Reconfigure for the new standard */
	solo_disp_init(solo_dev);
	solo_enc_init(solo_dev);
	solo_tw28_init(solo_dev);
	for (i = 0; i < solo_dev->nr_chans; i++)
		solo_update_mode(solo_dev->v4l2_enc[i]);
	return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch);
}

static int solo_s_std(struct file *file, void *priv, v4l2_std_id std)
{
	struct solo_dev *solo_dev = video_drvdata(file);

554
	return solo_set_video_type(solo_dev, std & V4L2_STD_625_50);
555 556
}

557
static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
558
{
559 560
	struct solo_dev *solo_dev =
		container_of(ctrl->handler, struct solo_dev, disp_hdl);
561 562 563

	switch (ctrl->id) {
	case V4L2_CID_MOTION_TRACE:
564
		if (ctrl->val) {
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
					SOLO_VI_MOTION_Y_ADD |
					SOLO_VI_MOTION_Y_VALUE(0x20) |
					SOLO_VI_MOTION_CB_VALUE(0x10) |
					SOLO_VI_MOTION_CR_VALUE(0x10));
			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
					SOLO_VI_MOTION_CR_ADD |
					SOLO_VI_MOTION_Y_VALUE(0x10) |
					SOLO_VI_MOTION_CB_VALUE(0x80) |
					SOLO_VI_MOTION_CR_VALUE(0x10));
		} else {
			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
		}
		return 0;
580 581
	default:
		break;
582 583 584 585 586 587
	}
	return -EINVAL;
}

static const struct v4l2_file_operations solo_v4l2_fops = {
	.owner			= THIS_MODULE,
588
	.open			= v4l2_fh_open,
589 590 591 592 593
	.release		= vb2_fop_release,
	.read			= vb2_fop_read,
	.poll			= vb2_fop_poll,
	.mmap			= vb2_fop_mmap,
	.unlocked_ioctl		= video_ioctl2,
594 595 596 597 598
};

static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
	.vidioc_querycap		= solo_querycap,
	.vidioc_s_std			= solo_s_std,
599
	.vidioc_g_std			= solo_g_std,
600 601 602 603 604 605 606 607 608 609
	/* Input callbacks */
	.vidioc_enum_input		= solo_enum_input,
	.vidioc_s_input			= solo_set_input,
	.vidioc_g_input			= solo_get_input,
	/* Video capture format callbacks */
	.vidioc_enum_fmt_vid_cap	= solo_enum_fmt_cap,
	.vidioc_try_fmt_vid_cap		= solo_try_fmt_cap,
	.vidioc_s_fmt_vid_cap		= solo_set_fmt_cap,
	.vidioc_g_fmt_vid_cap		= solo_get_fmt_cap,
	/* Streaming I/O */
610 611 612 613 614 615
	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
	.vidioc_querybuf		= vb2_ioctl_querybuf,
	.vidioc_qbuf			= vb2_ioctl_qbuf,
	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
	.vidioc_streamon		= vb2_ioctl_streamon,
	.vidioc_streamoff		= vb2_ioctl_streamoff,
616 617 618 619
	/* Logging and events */
	.vidioc_log_status		= v4l2_ctrl_log_status,
	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
620 621 622
};

static struct video_device solo_v4l2_template = {
623
	.name			= SOLO6X10_NAME,
624 625 626 627
	.fops			= &solo_v4l2_fops,
	.ioctl_ops		= &solo_v4l2_ioctl_ops,
	.minor			= -1,
	.release		= video_device_release,
628
	.tvnorms		= V4L2_STD_NTSC_M | V4L2_STD_PAL,
629 630
};

631 632 633 634 635 636 637 638 639 640 641 642 643
static const struct v4l2_ctrl_ops solo_ctrl_ops = {
	.s_ctrl = solo_s_ctrl,
};

static const struct v4l2_ctrl_config solo_motion_trace_ctrl = {
	.ops = &solo_ctrl_ops,
	.id = V4L2_CID_MOTION_TRACE,
	.name = "Motion Detection Trace",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.max = 1,
	.step = 1,
};

644
int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
645 646 647 648 649
{
	int ret;
	int i;

	init_waitqueue_head(&solo_dev->disp_thread_wait);
650 651 652
	spin_lock_init(&solo_dev->slock);
	mutex_init(&solo_dev->lock);
	INIT_LIST_HEAD(&solo_dev->vidq_active);
653 654 655 656 657 658

	solo_dev->vfd = video_device_alloc();
	if (!solo_dev->vfd)
		return -ENOMEM;

	*solo_dev->vfd = solo_v4l2_template;
H
Hans Verkuil 已提交
659
	solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
660 661
	solo_dev->vfd->queue = &solo_dev->vidq;
	solo_dev->vfd->lock = &solo_dev->lock;
662 663
	v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
	v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
664 665 666 667
	if (solo_dev->disp_hdl.error) {
		ret = solo_dev->disp_hdl.error;
		goto fail;
	}
668
	solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
669 670 671

	video_set_drvdata(solo_dev->vfd, solo_dev);

672 673 674 675 676
	solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
	solo_dev->vidq.ops = &solo_video_qops;
	solo_dev->vidq.mem_ops = &vb2_dma_contig_memops;
	solo_dev->vidq.drv_priv = solo_dev;
677
	solo_dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
678
	solo_dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
679 680
	solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
	solo_dev->vidq.lock = &solo_dev->lock;
681
	solo_dev->vidq.dev = &solo_dev->pdev->dev;
682 683 684 685
	ret = vb2_queue_init(&solo_dev->vidq);
	if (ret < 0)
		goto fail;

686 687 688 689
	/* Cycle all the channels and clear */
	for (i = 0; i < solo_dev->nr_chans; i++) {
		solo_v4l2_set_ch(solo_dev, i);
		while (erase_off(solo_dev))
690
			/* Do nothing */;
691 692 693 694 695
	}

	/* Set the default display channel */
	solo_v4l2_set_ch(solo_dev, 0);
	while (erase_off(solo_dev))
696
		/* Do nothing */;
697

698
	ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
699 700
	if (ret < 0)
		goto fail;
701 702 703 704

	snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
		 SOLO6X10_NAME, solo_dev->vfd->num);

705 706
	dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with %d inputs (%d extended)\n",
		 solo_dev->vfd->num,
707 708
		 solo_dev->nr_chans, solo_dev->nr_ext);

709
	return 0;
710 711 712 713 714 715

fail:
	video_device_release(solo_dev->vfd);
	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
	solo_dev->vfd = NULL;
	return ret;
716 717
}

718
void solo_v4l2_exit(struct solo_dev *solo_dev)
719
{
720 721 722 723
	if (solo_dev->vfd == NULL)
		return;

	video_unregister_device(solo_dev->vfd);
724
	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
725
	solo_dev->vfd = NULL;
726
}