dt3155.c 18.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/***************************************************************************
 *   Copyright (C) 2006-2010 by Marin Mitov                                *
 *   mitov@issp.bas.bg                                                     *
 *                                                                         *
 *   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.                          *
 *                                                                         *
 ***************************************************************************/

17
#include <linux/module.h>
18
#include <linux/stringify.h>
19
#include <linux/delay.h>
20
#include <linux/kthread.h>
21
#include <linux/slab.h>
22 23
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
24
#include <media/v4l2-common.h>
25
#include <media/videobuf2-dma-contig.h>
26

27
#include "dt3155.h"
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

#define DT3155_DEVICE_ID 0x1223

/**
 * read_i2c_reg - reads an internal i2c register
 *
 * @addr:	dt3155 mmio base address
 * @index:	index (internal address) of register to read
 * @data:	pointer to byte the read data will be placed in
 *
 * returns:	zero on success or error code
 *
 * This function starts reading the specified (by index) register
 * and busy waits for the process to finish. The result is placed
 * in a byte pointed by data.
 */
H
Hans Verkuil 已提交
44
static int read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
45 46 47
{
	u32 tmp = index;

H
Hans Verkuil 已提交
48
	iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2);
49 50
	mmiowb();
	udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
51 52
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		return -EIO; /* error: NEW_CYCLE not cleared */
53 54 55 56
	tmp = ioread32(addr + IIC_CSR1);
	if (tmp & DIRECT_ABORT) {
		/* reset DIRECT_ABORT bit */
		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
57
		return -EIO; /* error: DIRECT_ABORT set */
58
	}
H
Hans Verkuil 已提交
59
	*data = tmp >> 24;
60 61 62 63 64 65 66 67 68 69 70 71
	return 0;
}

/**
 * write_i2c_reg - writes to an internal i2c register
 *
 * @addr:	dt3155 mmio base address
 * @index:	index (internal address) of register to read
 * @data:	data to be written
 *
 * returns:	zero on success or error code
 *
H
Hans Verkuil 已提交
72
 * This function starts writing the specified (by index) register
73 74
 * and busy waits for the process to finish.
 */
H
Hans Verkuil 已提交
75
static int write_i2c_reg(void __iomem *addr, u8 index, u8 data)
76 77 78
{
	u32 tmp = index;

H
Hans Verkuil 已提交
79
	iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
80 81
	mmiowb();
	udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
82 83
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		return -EIO; /* error: NEW_CYCLE not cleared */
84 85 86
	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
		/* reset DIRECT_ABORT bit */
		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
87
		return -EIO; /* error: DIRECT_ABORT set */
88 89 90 91 92 93 94 95 96 97 98
	}
	return 0;
}

/**
 * write_i2c_reg_nowait - writes to an internal i2c register
 *
 * @addr:	dt3155 mmio base address
 * @index:	index (internal address) of register to read
 * @data:	data to be written
 *
H
Hans Verkuil 已提交
99
 * This function starts writing the specified (by index) register
100 101
 * and then returns.
 */
102
static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
103 104 105
{
	u32 tmp = index;

H
Hans Verkuil 已提交
106
	iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
107 108 109 110 111 112 113 114 115 116
	mmiowb();
}

/**
 * wait_i2c_reg - waits the read/write to finish
 *
 * @addr:	dt3155 mmio base address
 *
 * returns:	zero on success or error code
 *
H
Hans Verkuil 已提交
117
 * This function waits reading/writing to finish.
118
 */
119
static int wait_i2c_reg(void __iomem *addr)
120 121 122
{
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
123 124
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		return -EIO; /* error: NEW_CYCLE not cleared */
125 126 127
	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
		/* reset DIRECT_ABORT bit */
		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
128
		return -EIO; /* error: DIRECT_ABORT set */
129 130 131 132 133
	}
	return 0;
}

static int
134
dt3155_queue_setup(struct vb2_queue *vq,
135
		unsigned int *nbuffers, unsigned int *num_planes,
136 137
		unsigned int sizes[], void *alloc_ctxs[])

138
{
139
	struct dt3155_priv *pd = vb2_get_drv_priv(vq);
140
	unsigned size = pd->width * pd->height;
141

142 143
	if (vq->num_buffers + *nbuffers < 2)
		*nbuffers = 2 - vq->num_buffers;
144 145 146 147
	if (*num_planes)
		return sizes[0] < size ? -EINVAL : 0;
	*num_planes = 1;
	sizes[0] = size;
148 149 150
	return 0;
}

H
Hans Verkuil 已提交
151
static int dt3155_buf_prepare(struct vb2_buffer *vb)
152
{
153 154 155
	struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);

	vb2_set_plane_payload(vb, 0, pd->width * pd->height);
156 157 158
	return 0;
}

159 160 161
static int dt3155_start_streaming(struct vb2_queue *q, unsigned count)
{
	struct dt3155_priv *pd = vb2_get_drv_priv(q);
162
	struct vb2_buffer *vb = &pd->curr_buf->vb2_buf;
163 164 165 166 167
	dma_addr_t dma_addr;

	pd->sequence = 0;
	dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
	iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
168 169 170
	iowrite32(dma_addr + pd->width, pd->regs + ODD_DMA_START);
	iowrite32(pd->width, pd->regs + EVEN_DMA_STRIDE);
	iowrite32(pd->width, pd->regs + ODD_DMA_STRIDE);
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	/* enable interrupts, clear all irq flags */
	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
			FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
		  FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
							pd->regs + CSR1);
	wait_i2c_reg(pd->regs);
	write_i2c_reg(pd->regs, CONFIG, pd->config);
	write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
	write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);

	/*  start the board  */
	write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
	return 0;
}

H
Hans Verkuil 已提交
187
static void dt3155_stop_streaming(struct vb2_queue *q)
188
{
189 190 191 192
	struct dt3155_priv *pd = vb2_get_drv_priv(q);
	struct vb2_buffer *vb;

	spin_lock_irq(&pd->lock);
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	/* stop the board */
	write_i2c_reg_nowait(pd->regs, CSR2, pd->csr2);
	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
		  FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
	/* disable interrupts, clear all irq flags */
	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
	spin_unlock_irq(&pd->lock);

	/*
	 * It is not clear whether the DMA stops at once or whether it
	 * will finish the current frame or field first. To be on the
	 * safe side we wait a bit.
	 */
	msleep(45);

	spin_lock_irq(&pd->lock);
	if (pd->curr_buf) {
210
		vb2_buffer_done(&pd->curr_buf->vb2_buf, VB2_BUF_STATE_ERROR);
211 212 213
		pd->curr_buf = NULL;
	}

214 215 216 217 218 219
	while (!list_empty(&pd->dmaq)) {
		vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
		list_del(&vb->done_entry);
		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
	}
	spin_unlock_irq(&pd->lock);
220 221
}

H
Hans Verkuil 已提交
222
static void dt3155_buf_queue(struct vb2_buffer *vb)
223
{
224
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
225 226
	struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);

227
	/*  pd->vidq.streaming = 1 when dt3155_buf_queue() is invoked  */
228 229 230
	spin_lock_irq(&pd->lock);
	if (pd->curr_buf)
		list_add_tail(&vb->done_entry, &pd->dmaq);
231
	else
232
		pd->curr_buf = vbuf;
233
	spin_unlock_irq(&pd->lock);
234 235
}

236
static const struct vb2_ops q_ops = {
237
	.queue_setup = dt3155_queue_setup,
238 239
	.wait_prepare = vb2_ops_wait_prepare,
	.wait_finish = vb2_ops_wait_finish,
240
	.buf_prepare = dt3155_buf_prepare,
241
	.start_streaming = dt3155_start_streaming,
242
	.stop_streaming = dt3155_stop_streaming,
243 244 245
	.buf_queue = dt3155_buf_queue,
};

H
Hans Verkuil 已提交
246
static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
247 248
{
	struct dt3155_priv *ipd = dev_id;
249
	struct vb2_buffer *ivb;
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
	dma_addr_t dma_addr;
	u32 tmp;

	tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
	if (!tmp)
		return IRQ_NONE;  /* not our irq */
	if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
		iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
							ipd->regs + INT_CSR);
		return IRQ_HANDLED; /* start of field irq */
	}
	tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
	if (tmp) {
		iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
						FLD_DN_ODD | FLD_DN_EVEN |
						CAP_CONT_EVEN | CAP_CONT_ODD,
							ipd->regs + CSR1);
		mmiowb();
	}

	spin_lock(&ipd->lock);
271
	if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
272
		ipd->curr_buf->vb2_buf.timestamp = ktime_get_ns();
273 274 275
		ipd->curr_buf->sequence = ipd->sequence++;
		ipd->curr_buf->field = V4L2_FIELD_NONE;
		vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE);
276 277 278

		ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
		list_del(&ivb->done_entry);
279
		ipd->curr_buf = to_vb2_v4l2_buffer(ivb);
280 281
		dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
		iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
282 283 284
		iowrite32(dma_addr + ipd->width, ipd->regs + ODD_DMA_START);
		iowrite32(ipd->width, ipd->regs + EVEN_DMA_STRIDE);
		iowrite32(ipd->width, ipd->regs + ODD_DMA_STRIDE);
285
		mmiowb();
286 287
	}

288 289 290 291 292 293 294 295 296
	/* enable interrupts, clear all irq flags */
	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
			FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
	spin_unlock(&ipd->lock);
	return IRQ_HANDLED;
}

static const struct v4l2_file_operations dt3155_fops = {
	.owner = THIS_MODULE,
297 298 299 300 301 302
	.open = v4l2_fh_open,
	.release = vb2_fop_release,
	.unlocked_ioctl = video_ioctl2,
	.read = vb2_fop_read,
	.mmap = vb2_fop_mmap,
	.poll = vb2_fop_poll
303 304
};

305 306
static int dt3155_querycap(struct file *filp, void *p,
			   struct v4l2_capability *cap)
307 308 309 310 311 312
{
	struct dt3155_priv *pd = video_drvdata(filp);

	strcpy(cap->driver, DT3155_NAME);
	strcpy(cap->card, DT3155_NAME " frame grabber");
	sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
H
Hans Verkuil 已提交
313
	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
314
		V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
H
Hans Verkuil 已提交
315
	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
316 317 318
	return 0;
}

319 320
static int dt3155_enum_fmt_vid_cap(struct file *filp,
				   void *p, struct v4l2_fmtdesc *f)
321
{
322
	if (f->index)
323
		return -EINVAL;
324 325
	f->pixelformat = V4L2_PIX_FMT_GREY;
	strcpy(f->description, "8-bit Greyscale");
326 327 328
	return 0;
}

329
static int dt3155_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
330
{
331 332 333 334
	struct dt3155_priv *pd = video_drvdata(filp);

	f->fmt.pix.width = pd->width;
	f->fmt.pix.height = pd->height;
335 336 337 338
	f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
	f->fmt.pix.field = V4L2_FIELD_NONE;
	f->fmt.pix.bytesperline = f->fmt.pix.width;
	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
339
	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
340 341 342
	return 0;
}

H
Hans Verkuil 已提交
343
static int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm)
344
{
345 346 347
	struct dt3155_priv *pd = video_drvdata(filp);

	*norm = pd->std;
348 349 350
	return 0;
}

H
Hans Verkuil 已提交
351
static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm)
352
{
353 354 355
	struct dt3155_priv *pd = video_drvdata(filp);

	if (pd->std == norm)
356
		return 0;
357 358 359 360 361 362 363 364 365 366 367 368 369
	if (vb2_is_busy(&pd->vidq))
		return -EBUSY;
	pd->std = norm;
	if (pd->std & V4L2_STD_525_60) {
		pd->csr2 = VT_60HZ;
		pd->width = 640;
		pd->height = 480;
	} else {
		pd->csr2 = VT_50HZ;
		pd->width = 768;
		pd->height = 576;
	}
	return 0;
370 371
}

372 373
static int dt3155_enum_input(struct file *filp, void *p,
			     struct v4l2_input *input)
374
{
375
	if (input->index > 3)
376
		return -EINVAL;
377
	if (input->index)
378 379
		snprintf(input->name, sizeof(input->name), "VID%d",
			 input->index);
380 381
	else
		strlcpy(input->name, "J2/VID0", sizeof(input->name));
382
	input->type = V4L2_INPUT_TYPE_CAMERA;
383 384
	input->std = V4L2_STD_ALL;
	input->status = 0;
385 386 387
	return 0;
}

H
Hans Verkuil 已提交
388
static int dt3155_g_input(struct file *filp, void *p, unsigned int *i)
389
{
390 391 392
	struct dt3155_priv *pd = video_drvdata(filp);

	*i = pd->input;
393 394 395
	return 0;
}

H
Hans Verkuil 已提交
396
static int dt3155_s_input(struct file *filp, void *p, unsigned int i)
397
{
398 399 400
	struct dt3155_priv *pd = video_drvdata(filp);

	if (i > 3)
401
		return -EINVAL;
402 403 404
	pd->input = i;
	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
	write_i2c_reg(pd->regs, AD_CMD, (i << 6) | (i << 4) | SYNC_LVL_3);
405 406 407 408
	return 0;
}

static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
H
Hans Verkuil 已提交
409 410
	.vidioc_querycap = dt3155_querycap,
	.vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap,
411 412 413
	.vidioc_try_fmt_vid_cap = dt3155_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap = dt3155_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap = dt3155_fmt_vid_cap,
414 415 416 417 418 419 420 421
	.vidioc_reqbufs = vb2_ioctl_reqbufs,
	.vidioc_create_bufs = vb2_ioctl_create_bufs,
	.vidioc_querybuf = vb2_ioctl_querybuf,
	.vidioc_expbuf = vb2_ioctl_expbuf,
	.vidioc_qbuf = vb2_ioctl_qbuf,
	.vidioc_dqbuf = vb2_ioctl_dqbuf,
	.vidioc_streamon = vb2_ioctl_streamon,
	.vidioc_streamoff = vb2_ioctl_streamoff,
H
Hans Verkuil 已提交
422 423 424 425 426
	.vidioc_g_std = dt3155_g_std,
	.vidioc_s_std = dt3155_s_std,
	.vidioc_enum_input = dt3155_enum_input,
	.vidioc_g_input = dt3155_g_input,
	.vidioc_s_input = dt3155_s_input,
427 428
};

429
static int dt3155_init_board(struct dt3155_priv *pd)
430
{
431
	struct pci_dev *pdev = pd->pdev;
432
	int i;
433
	u8 tmp = 0;
434

435
	pci_set_master(pdev); /* dt3155 needs it */
436 437

	/*  resetting the adapter  */
438 439
	iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN |
			FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
440
	mmiowb();
441
	msleep(20);
442

H
Hans Verkuil 已提交
443
	/*  initializing adapter registers  */
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
	iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
	mmiowb();
	iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
	iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
	iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
	iowrite32(0x00000103, pd->regs + XFER_MODE);
	iowrite32(0, pd->regs + RETRY_WAIT_CNT);
	iowrite32(0, pd->regs + INT_CSR);
	iowrite32(1, pd->regs + EVEN_FLD_MASK);
	iowrite32(1, pd->regs + ODD_FLD_MASK);
	iowrite32(0, pd->regs + MASK_LENGTH);
	iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
	iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
	mmiowb();

	/* verifying that we have a DT3155 board (not just a SAA7116 chip) */
	read_i2c_reg(pd->regs, DT_ID, &tmp);
	if (tmp != DT3155_ID)
		return -ENODEV;

	/* initialize AD LUT */
	write_i2c_reg(pd->regs, AD_ADDR, 0);
	for (i = 0; i < 256; i++)
		write_i2c_reg(pd->regs, AD_LUT, i);

	/* initialize ADC references */
	/* FIXME: pos_ref & neg_ref depend on VT_50HZ */
	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
	write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
	write_i2c_reg(pd->regs, AD_CMD, 34);
	write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
	write_i2c_reg(pd->regs, AD_CMD, 0);

	/* initialize PM LUT */
	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
	for (i = 0; i < 256; i++) {
		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
	}
	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
	for (i = 0; i < 256; i++) {
		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
	}
	write_i2c_reg(pd->regs, CONFIG, pd->config); /*  ACQ_MODE_EVEN  */

491
	/* select channel 1 for input and set sync level */
492 493 494
	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);

495 496 497 498
	/* disable all irqs, clear all irq flags */
	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
			pd->regs + INT_CSR);

499 500 501 502 503 504 505 506
	return 0;
}

static struct video_device dt3155_vdev = {
	.name = DT3155_NAME,
	.fops = &dt3155_fops,
	.ioctl_ops = &dt3155_ioctl_ops,
	.minor = -1,
507
	.release = video_device_release_empty,
508
	.tvnorms = V4L2_STD_ALL,
509 510
};

H
Hans Verkuil 已提交
511
static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
512
{
513
	int err;
514 515
	struct dt3155_priv *pd;

516
	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
517
	if (err)
518
		return -ENODEV;
519
	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
520
	if (!pd)
521
		return -ENOMEM;
522

523 524 525
	err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev);
	if (err)
		return err;
526
	pd->vdev = dt3155_vdev;
527
	pd->vdev.v4l2_dev = &pd->v4l2_dev;
528
	video_set_drvdata(&pd->vdev, pd);  /* for use in video_fops */
529
	pd->pdev = pdev;
530 531 532 533
	pd->std = V4L2_STD_625_50;
	pd->csr2 = VT_50HZ;
	pd->width = 768;
	pd->height = 576;
534 535
	INIT_LIST_HEAD(&pd->dmaq);
	mutex_init(&pd->mux);
536
	pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */
537 538 539 540 541 542 543
	pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
	pd->vidq.ops = &q_ops;
	pd->vidq.mem_ops = &vb2_dma_contig_memops;
	pd->vidq.drv_priv = pd;
	pd->vidq.min_buffers_needed = 2;
544
	pd->vidq.gfp_flags = GFP_DMA32;
545
	pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */
546
	pd->vidq.dev = &pdev->dev;
547 548 549 550
	pd->vdev.queue = &pd->vidq;
	err = vb2_queue_init(&pd->vidq);
	if (err < 0)
		goto err_v4l2_dev_unreg;
551
	spin_lock_init(&pd->lock);
552
	pd->config = ACQ_MODE_EVEN;
553
	err = pci_enable_device(pdev);
554
	if (err)
555
		goto err_v4l2_dev_unreg;
556
	err = pci_request_region(pdev, 0, pci_name(pdev));
557
	if (err)
558
		goto err_pci_disable;
559
	pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
560
	if (!pd->regs) {
561
		err = -ENOMEM;
562
		goto err_free_reg;
563
	}
564 565 566 567 568
	err = dt3155_init_board(pd);
	if (err)
		goto err_iounmap;
	err = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
					IRQF_SHARED, DT3155_NAME, pd);
569
	if (err)
570
		goto err_iounmap;
571
	err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1);
572
	if (err)
573
		goto err_free_irq;
574
	dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
575 576
	return 0;  /*   success   */

577 578 579
err_free_irq:
	free_irq(pd->pdev->irq, pd);
err_iounmap:
580
	pci_iounmap(pdev, pd->regs);
581
err_free_reg:
582
	pci_release_region(pdev, 0);
583
err_pci_disable:
584
	pci_disable_device(pdev);
585 586
err_v4l2_dev_unreg:
	v4l2_device_unregister(&pd->v4l2_dev);
587 588 589
	return err;
}

H
Hans Verkuil 已提交
590
static void dt3155_remove(struct pci_dev *pdev)
591
{
592
	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
593 594
	struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv,
					      v4l2_dev);
595

596
	video_unregister_device(&pd->vdev);
597
	free_irq(pd->pdev->irq, pd);
598
	vb2_queue_release(&pd->vidq);
599
	v4l2_device_unregister(&pd->v4l2_dev);
600 601 602
	pci_iounmap(pdev, pd->regs);
	pci_release_region(pdev, 0);
	pci_disable_device(pdev);
603 604
}

605
static const struct pci_device_id pci_ids[] = {
606
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) },
607 608 609 610 611 612 613 614
	{ 0, /* zero marks the end */ },
};
MODULE_DEVICE_TABLE(pci, pci_ids);

static struct pci_driver pci_driver = {
	.name = DT3155_NAME,
	.id_table = pci_ids,
	.probe = dt3155_probe,
615
	.remove = dt3155_remove,
616 617
};

618
module_pci_driver(pci_driver);
619 620 621 622 623

MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
MODULE_VERSION(DT3155_VERSION);
MODULE_LICENSE("GPL");