solo6x10-v4l2.c 18.8 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 318
			   unsigned int *num_buffers, unsigned int *num_planes,
			   unsigned int sizes[], void *alloc_ctxs[])
319
{
320
	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
321

322 323 324
	sizes[0] = solo_image_size(solo_dev);
	alloc_ctxs[0] = solo_dev->alloc_ctx;
	*num_planes = 1;
325

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

329
	return 0;
330 331
}

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

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

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

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

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

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

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

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

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

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

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

395 396 397 398 399 400 401 402 403 404 405 406
	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)
	 */
407 408 409 410 411 412
	return 0;
}

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

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

418 419 420 421 422 423 424 425 426 427 428 429
		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;
430
	input->std = solo_dev->vfd->tvnorms;
431 432 433 434 435
	return 0;
}

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

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

444
	return ret;
445 446 447 448
}

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

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

	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)
{
471
	struct solo_dev *solo_dev = video_drvdata(file);
472 473 474
	struct v4l2_pix_format *pix = &f->fmt.pix;
	int image_size = solo_image_size(solo_dev);

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

478 479 480 481 482 483 484
	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;
485 486 487 488 489 490
	return 0;
}

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

493
	if (vb2_is_busy(&solo_dev->vidq))
494 495 496 497 498 499 500 501 502 503
		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)
{
504
	struct solo_dev *solo_dev = video_drvdata(file);
505 506 507 508 509
	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;
510
	pix->field = V4L2_FIELD_INTERLACED;
511 512 513
	pix->sizeimage = solo_image_size(solo_dev);
	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
	pix->bytesperline = solo_bytesperline(solo_dev);
514
	pix->priv = 0;
515 516 517 518

	return 0;
}

519
static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i)
520
{
521 522 523 524 525 526
	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;
527 528 529
	return 0;
}

530
int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz)
531 532 533 534 535 536 537 538 539
{
	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;
540 541
	solo_dev->video_type = is_50hz ? SOLO_VO_FMT_TYPE_PAL :
					 SOLO_VO_FMT_TYPE_NTSC;
542 543 544 545 546 547 548 549 550 551 552 553 554
	/* 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);

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

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

	switch (ctrl->id) {
	case V4L2_CID_MOTION_TRACE:
565
		if (ctrl->val) {
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
			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;
581 582
	default:
		break;
583 584 585 586 587 588
	}
	return -EINVAL;
}

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

static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
	.vidioc_querycap		= solo_querycap,
	.vidioc_s_std			= solo_s_std,
600
	.vidioc_g_std			= solo_g_std,
601 602 603 604 605 606 607 608 609 610
	/* 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 */
611 612 613 614 615 616
	.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,
617 618 619 620
	/* Logging and events */
	.vidioc_log_status		= v4l2_ctrl_log_status,
	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
621 622 623
};

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

632 633 634 635 636 637 638 639 640 641 642 643 644
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,
};

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

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

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

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

	video_set_drvdata(solo_dev->vfd, solo_dev);

673 674 675 676 677
	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;
678
	solo_dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
679
	solo_dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
680 681 682 683 684 685 686 687 688 689 690
	solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
	solo_dev->vidq.lock = &solo_dev->lock;
	ret = vb2_queue_init(&solo_dev->vidq);
	if (ret < 0)
		goto fail;

	solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev);
	if (IS_ERR(solo_dev->alloc_ctx)) {
		dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context");
		return PTR_ERR(solo_dev->alloc_ctx);
	}
691 692 693 694 695

	/* 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))
696
			/* Do nothing */;
697 698 699 700 701
	}

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

704
	ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
705 706
	if (ret < 0)
		goto fail;
707 708 709 710 711 712 713 714

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

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

715
	return 0;
716 717 718 719 720 721 722

fail:
	video_device_release(solo_dev->vfd);
	vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
	solo_dev->vfd = NULL;
	return ret;
723 724
}

725
void solo_v4l2_exit(struct solo_dev *solo_dev)
726
{
727 728 729 730
	if (solo_dev->vfd == NULL)
		return;

	video_unregister_device(solo_dev->vfd);
731
	vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
732
	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
733
	solo_dev->vfd = NULL;
734
}