cx88-video.c 45.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/*
 *
 * device driver for Conexant 2388x based TV cards
 * video4linux video interface
 *
 * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
 *
8 9 10 11 12
 * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
 *	- Multituner support
 *	- video_ioctl2 conversion
 *	- PAL/M fixes
 *
L
Linus Torvalds 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
A
Andrew Morton 已提交
35
#include <linux/dma-mapping.h>
L
Linus Torvalds 已提交
36 37 38 39 40
#include <linux/delay.h>
#include <linux/kthread.h>
#include <asm/div64.h>

#include "cx88.h"
41
#include <media/v4l2-common.h>
42
#include <media/v4l2-ioctl.h>
43
#include <media/v4l2-event.h>
44
#include <media/wm8775.h>
L
Linus Torvalds 已提交
45 46 47 48

MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
49
MODULE_VERSION(CX88_VERSION);
L
Linus Torvalds 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

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

static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[]   = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };

module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr,   int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);

MODULE_PARM_DESC(video_nr,"video device numbers");
MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
MODULE_PARM_DESC(radio_nr,"radio device numbers");

65
static unsigned int video_debug;
L
Linus Torvalds 已提交
66 67 68
module_param(video_debug,int,0644);
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");

69
static unsigned int irq_debug;
L
Linus Torvalds 已提交
70 71 72 73
module_param(irq_debug,int,0644);
MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");

#define dprintk(level,fmt, arg...)	if (video_debug >= level) \
74
	printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
L
Linus Torvalds 已提交
75 76 77 78

/* ------------------------------------------------------------------- */
/* static data                                                         */

79
static const struct cx8800_fmt formats[] = {
L
Linus Torvalds 已提交
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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	{
		.name     = "8 bpp, gray",
		.fourcc   = V4L2_PIX_FMT_GREY,
		.cxformat = ColorFormatY8,
		.depth    = 8,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "15 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_RGB555,
		.cxformat = ColorFormatRGB15,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "15 bpp RGB, be",
		.fourcc   = V4L2_PIX_FMT_RGB555X,
		.cxformat = ColorFormatRGB15 | ColorFormatBSWAP,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "16 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_RGB565,
		.cxformat = ColorFormatRGB16,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "16 bpp RGB, be",
		.fourcc   = V4L2_PIX_FMT_RGB565X,
		.cxformat = ColorFormatRGB16 | ColorFormatBSWAP,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "24 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_BGR24,
		.cxformat = ColorFormatRGB24,
		.depth    = 24,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "32 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_BGR32,
		.cxformat = ColorFormatRGB32,
		.depth    = 32,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "32 bpp RGB, be",
		.fourcc   = V4L2_PIX_FMT_RGB32,
		.cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP,
		.depth    = 32,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "4:2:2, packed, YUYV",
		.fourcc   = V4L2_PIX_FMT_YUYV,
		.cxformat = ColorFormatYUY2,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "4:2:2, packed, UYVY",
		.fourcc   = V4L2_PIX_FMT_UYVY,
		.cxformat = ColorFormatYUY2 | ColorFormatBSWAP,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},
};

143
static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
L
Linus Torvalds 已提交
144 145 146 147 148 149 150 151 152 153 154
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(formats); i++)
		if (formats[i].fourcc == fourcc)
			return formats+i;
	return NULL;
}

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

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
struct cx88_ctrl {
	/* control information */
	u32 id;
	s32 minimum;
	s32 maximum;
	u32 step;
	s32 default_value;

	/* control register information */
	u32 off;
	u32 reg;
	u32 sreg;
	u32 mask;
	u32 shift;
};

171
static const struct cx88_ctrl cx8800_vid_ctls[] = {
L
Linus Torvalds 已提交
172 173
	/* --- video --- */
	{
174 175 176 177 178 179 180 181 182
		.id            = V4L2_CID_BRIGHTNESS,
		.minimum       = 0x00,
		.maximum       = 0xff,
		.step          = 1,
		.default_value = 0x7f,
		.off           = 128,
		.reg           = MO_CONTR_BRIGHT,
		.mask          = 0x00ff,
		.shift         = 0,
L
Linus Torvalds 已提交
183
	},{
184 185 186 187 188 189 190 191 192
		.id            = V4L2_CID_CONTRAST,
		.minimum       = 0,
		.maximum       = 0xff,
		.step          = 1,
		.default_value = 0x3f,
		.off           = 0,
		.reg           = MO_CONTR_BRIGHT,
		.mask          = 0xff00,
		.shift         = 8,
L
Linus Torvalds 已提交
193
	},{
194 195 196 197 198 199 200 201 202
		.id            = V4L2_CID_HUE,
		.minimum       = 0,
		.maximum       = 0xff,
		.step          = 1,
		.default_value = 0x7f,
		.off           = 128,
		.reg           = MO_HUE,
		.mask          = 0x00ff,
		.shift         = 0,
L
Linus Torvalds 已提交
203 204 205 206
	},{
		/* strictly, this only describes only U saturation.
		 * V saturation is handled specially through code.
		 */
207 208 209 210 211 212 213 214 215
		.id            = V4L2_CID_SATURATION,
		.minimum       = 0,
		.maximum       = 0xff,
		.step          = 1,
		.default_value = 0x7f,
		.off           = 0,
		.reg           = MO_UV_SATURATION,
		.mask          = 0x00ff,
		.shift         = 0,
216
	}, {
217 218 219 220 221 222
		.id            = V4L2_CID_SHARPNESS,
		.minimum       = 0,
		.maximum       = 4,
		.step          = 1,
		.default_value = 0x0,
		.off           = 0,
223 224
		/* NOTE: the value is converted and written to both even
		   and odd registers in the code */
225 226 227
		.reg           = MO_FILTER_ODD,
		.mask          = 7 << 7,
		.shift         = 7,
228
	}, {
229 230 231 232 233 234 235
		.id            = V4L2_CID_CHROMA_AGC,
		.minimum       = 0,
		.maximum       = 1,
		.default_value = 0x1,
		.reg           = MO_INPUT_FORMAT,
		.mask          = 1 << 10,
		.shift         = 10,
236
	}, {
237 238 239 240 241 242 243
		.id            = V4L2_CID_COLOR_KILLER,
		.minimum       = 0,
		.maximum       = 1,
		.default_value = 0x1,
		.reg           = MO_INPUT_FORMAT,
		.mask          = 1 << 9,
		.shift         = 9,
244
	}, {
245 246 247 248 249 250 251 252 253
		.id            = V4L2_CID_BAND_STOP_FILTER,
		.minimum       = 0,
		.maximum       = 1,
		.step          = 1,
		.default_value = 0x0,
		.off           = 0,
		.reg           = MO_HTOTAL,
		.mask          = 3 << 11,
		.shift         = 11,
254 255 256 257 258
	}
};

static const struct cx88_ctrl cx8800_aud_ctls[] = {
	{
259 260 261 262 263 264 265 266 267
		/* --- audio --- */
		.id            = V4L2_CID_AUDIO_MUTE,
		.minimum       = 0,
		.maximum       = 1,
		.default_value = 1,
		.reg           = AUD_VOL_CTL,
		.sreg          = SHADOW_AUD_VOL_CTL,
		.mask          = (1 << 6),
		.shift         = 6,
L
Linus Torvalds 已提交
268
	},{
269 270 271 272 273 274 275 276 277
		.id            = V4L2_CID_AUDIO_VOLUME,
		.minimum       = 0,
		.maximum       = 0x3f,
		.step          = 1,
		.default_value = 0x3f,
		.reg           = AUD_VOL_CTL,
		.sreg          = SHADOW_AUD_VOL_CTL,
		.mask          = 0x3f,
		.shift         = 0,
L
Linus Torvalds 已提交
278
	},{
279 280 281 282 283 284 285 286 287
		.id            = V4L2_CID_AUDIO_BALANCE,
		.minimum       = 0,
		.maximum       = 0x7f,
		.step          = 1,
		.default_value = 0x40,
		.reg           = AUD_BAL_CTL,
		.sreg          = SHADOW_AUD_BAL_CTL,
		.mask          = 0x7f,
		.shift         = 0,
L
Linus Torvalds 已提交
288 289 290
	}
};

291 292 293 294
enum {
	CX8800_VID_CTLS = ARRAY_SIZE(cx8800_vid_ctls),
	CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls),
};
295

L
Linus Torvalds 已提交
296 297
/* ------------------------------------------------------------------ */

298
int cx88_video_mux(struct cx88_core *core, unsigned int input)
L
Linus Torvalds 已提交
299
{
300
	/* struct cx88_core *core = dev->core; */
L
Linus Torvalds 已提交
301 302

	dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",
303 304 305
		input, INPUT(input).vmux,
		INPUT(input).gpio0,INPUT(input).gpio1,
		INPUT(input).gpio2,INPUT(input).gpio3);
306
	core->input = input;
307 308 309 310 311
	cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14);
	cx_write(MO_GP3_IO, INPUT(input).gpio3);
	cx_write(MO_GP0_IO, INPUT(input).gpio0);
	cx_write(MO_GP1_IO, INPUT(input).gpio1);
	cx_write(MO_GP2_IO, INPUT(input).gpio2);
L
Linus Torvalds 已提交
312

313
	switch (INPUT(input).type) {
L
Linus Torvalds 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326
	case CX88_VMUX_SVIDEO:
		cx_set(MO_AFECFG_IO,    0x00000001);
		cx_set(MO_INPUT_FORMAT, 0x00010010);
		cx_set(MO_FILTER_EVEN,  0x00002020);
		cx_set(MO_FILTER_ODD,   0x00002020);
		break;
	default:
		cx_clear(MO_AFECFG_IO,    0x00000001);
		cx_clear(MO_INPUT_FORMAT, 0x00010010);
		cx_clear(MO_FILTER_EVEN,  0x00002020);
		cx_clear(MO_FILTER_ODD,   0x00002020);
		break;
	}
327

328 329 330 331 332 333
	/* if there are audioroutes defined, we have an external
	   ADC to deal with audio */
	if (INPUT(input).audioroute) {
		/* The wm8775 module has the "2" route hardwired into
		   the initialization. Some boards may use different
		   routes for different inputs. HVR-1300 surely does */
334
		if (core->sd_wm8775) {
335
			call_all(core, audio, s_routing,
336
				 INPUT(input).audioroute, 0, 0);
337
		}
338 339 340
		/* cx2388's C-ADC is connected to the tuner only.
		   When used with S-Video, that ADC is busy dealing with
		   chroma, so an external must be used for baseband audio */
341 342
		if (INPUT(input).type != CX88_VMUX_TELEVISION &&
		    INPUT(input).type != CX88_VMUX_CABLE) {
343 344 345 346 347 348 349 350
			/* "I2S ADC mode" */
			core->tvaudio = WW_I2SADC;
			cx88_set_tvaudio(core);
		} else {
			/* Normal mode */
			cx_write(AUD_I2SCNTL, 0x0);
			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
		}
351
	}
352

L
Linus Torvalds 已提交
353 354
	return 0;
}
355
EXPORT_SYMBOL(cx88_video_mux);
L
Linus Torvalds 已提交
356 357 358 359 360 361 362 363 364 365

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

static int start_video_dma(struct cx8800_dev    *dev,
			   struct cx88_dmaqueue *q,
			   struct cx88_buffer   *buf)
{
	struct cx88_core *core = dev->core;

	/* setup fifo + format */
366
	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21],
L
Linus Torvalds 已提交
367
				buf->bpl, buf->risc.dma);
368
	cx88_set_scale(core, core->width, core->height, core->field);
369
	cx_write(MO_COLOR_CTRL, dev->fmt->cxformat | ColorFormatGamma);
L
Linus Torvalds 已提交
370 371 372 373 374 375

	/* reset counter */
	cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET);
	q->count = 1;

	/* enable irqs */
376
	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
377 378 379 380 381 382 383 384

	/* Enables corresponding bits at PCI_INT_STAT:
		bits 0 to 4: video, audio, transport stream, VIP, Host
		bit 7: timer
		bits 8 and 9: DMA complete for: SRC, DST
		bits 10 and 11: BERR signal asserted for RISC: RD, WR
		bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB
	 */
L
Linus Torvalds 已提交
385 386 387 388 389 390 391
	cx_set(MO_VID_INTMSK, 0x0f0011);

	/* enable capture */
	cx_set(VID_CAPTURE_CONTROL,0x06);

	/* start dma */
	cx_set(MO_DEV_CNTRL2, (1<<5));
392
	cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */
L
Linus Torvalds 已提交
393 394 395 396

	return 0;
}

397
#ifdef CONFIG_PM
L
Linus Torvalds 已提交
398 399 400 401 402 403 404 405 406 407 408
static int stop_video_dma(struct cx8800_dev    *dev)
{
	struct cx88_core *core = dev->core;

	/* stop dma */
	cx_clear(MO_VID_DMACNTRL, 0x11);

	/* disable capture */
	cx_clear(VID_CAPTURE_CONTROL,0x06);

	/* disable irqs */
409
	cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
L
Linus Torvalds 已提交
410 411 412
	cx_clear(MO_VID_INTMSK, 0x0f0011);
	return 0;
}
413
#endif
L
Linus Torvalds 已提交
414 415 416 417

static int restart_video_queue(struct cx8800_dev    *dev,
			       struct cx88_dmaqueue *q)
{
418
	struct cx88_core *core = dev->core;
419
	struct cx88_buffer *buf;
L
Linus Torvalds 已提交
420 421

	if (!list_empty(&q->active)) {
H
Hans Verkuil 已提交
422
		buf = list_entry(q->active.next, struct cx88_buffer, list);
L
Linus Torvalds 已提交
423
		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
H
Hans Verkuil 已提交
424
			buf, buf->vb.v4l2_buf.index);
L
Linus Torvalds 已提交
425
		start_video_dma(dev, q, buf);
H
Hans Verkuil 已提交
426
		list_for_each_entry(buf, &q->active, list)
427
			buf->count = q->count++;
L
Linus Torvalds 已提交
428
	}
429
	return 0;
L
Linus Torvalds 已提交
430 431 432 433
}

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

H
Hans Verkuil 已提交
434 435 436
static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
			   unsigned int *num_buffers, unsigned int *num_planes,
			   unsigned int sizes[], void *alloc_ctxs[])
L
Linus Torvalds 已提交
437
{
H
Hans Verkuil 已提交
438
	struct cx8800_dev *dev = q->drv_priv;
439
	struct cx88_core *core = dev->core;
H
Hans Verkuil 已提交
440 441

	*num_planes = 1;
442
	sizes[0] = (dev->fmt->depth * core->width * core->height) >> 3;
L
Linus Torvalds 已提交
443 444 445
	return 0;
}

H
Hans Verkuil 已提交
446
static int buffer_prepare(struct vb2_buffer *vb)
L
Linus Torvalds 已提交
447
{
H
Hans Verkuil 已提交
448
	struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
449
	struct cx88_core *core = dev->core;
H
Hans Verkuil 已提交
450 451
	struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
452
	int rc;
L
Linus Torvalds 已提交
453

454
	buf->bpl = core->width * dev->fmt->depth >> 3;
H
Hans Verkuil 已提交
455

456
	if (vb2_plane_size(vb, 0) < core->height * buf->bpl)
L
Linus Torvalds 已提交
457
		return -EINVAL;
458
	vb2_set_plane_payload(vb, 0, core->height * buf->bpl);
L
Linus Torvalds 已提交
459

H
Hans Verkuil 已提交
460 461 462
	rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
	if (!rc)
		return -EIO;
L
Linus Torvalds 已提交
463

464
	switch (core->field) {
465 466
	case V4L2_FIELD_TOP:
		cx88_risc_buffer(dev->pci, &buf->risc,
H
Hans Verkuil 已提交
467
				 sgt->sgl, 0, UNSET,
468
				 buf->bpl, 0, core->height);
469 470 471
		break;
	case V4L2_FIELD_BOTTOM:
		cx88_risc_buffer(dev->pci, &buf->risc,
H
Hans Verkuil 已提交
472
				 sgt->sgl, UNSET, 0,
473
				 buf->bpl, 0, core->height);
474 475 476
		break;
	case V4L2_FIELD_SEQ_TB:
		cx88_risc_buffer(dev->pci, &buf->risc,
H
Hans Verkuil 已提交
477
				 sgt->sgl,
478
				 0, buf->bpl * (core->height >> 1),
479
				 buf->bpl, 0,
480
				 core->height >> 1);
481 482 483
		break;
	case V4L2_FIELD_SEQ_BT:
		cx88_risc_buffer(dev->pci, &buf->risc,
H
Hans Verkuil 已提交
484
				 sgt->sgl,
485
				 buf->bpl * (core->height >> 1), 0,
486
				 buf->bpl, 0,
487
				 core->height >> 1);
488 489 490 491
		break;
	case V4L2_FIELD_INTERLACED:
	default:
		cx88_risc_buffer(dev->pci, &buf->risc,
H
Hans Verkuil 已提交
492
				 sgt->sgl, 0, buf->bpl,
493
				 buf->bpl, buf->bpl,
494
				 core->height >> 1);
495
		break;
L
Linus Torvalds 已提交
496 497
	}
	dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
H
Hans Verkuil 已提交
498
		buf, buf->vb.v4l2_buf.index,
499
		core->width, core->height, dev->fmt->depth, dev->fmt->name,
L
Linus Torvalds 已提交
500 501
		(unsigned long)buf->risc.dma);
	return 0;
H
Hans Verkuil 已提交
502 503 504 505 506 507 508
}

static void buffer_finish(struct vb2_buffer *vb)
{
	struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
	struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
509
	struct cx88_riscmem *risc = &buf->risc;
L
Linus Torvalds 已提交
510

511 512 513
	if (risc->cpu)
		pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
	memset(risc, 0, sizeof(*risc));
H
Hans Verkuil 已提交
514 515

	dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
L
Linus Torvalds 已提交
516 517
}

H
Hans Verkuil 已提交
518
static void buffer_queue(struct vb2_buffer *vb)
L
Linus Torvalds 已提交
519
{
H
Hans Verkuil 已提交
520 521
	struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
	struct cx88_buffer    *buf = container_of(vb, struct cx88_buffer, vb);
L
Linus Torvalds 已提交
522
	struct cx88_buffer    *prev;
523
	struct cx88_core      *core = dev->core;
L
Linus Torvalds 已提交
524 525
	struct cx88_dmaqueue  *q    = &dev->vidq;

H
Hans Verkuil 已提交
526 527 528 529
	/* add jump to start */
	buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 8);
	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 8);
L
Linus Torvalds 已提交
530

531
	if (list_empty(&q->active)) {
H
Hans Verkuil 已提交
532
		list_add_tail(&buf->list, &q->active);
L
Linus Torvalds 已提交
533 534 535
		start_video_dma(dev, q, buf);
		buf->count    = q->count++;
		dprintk(2,"[%p/%d] buffer_queue - first active\n",
H
Hans Verkuil 已提交
536
			buf, buf->vb.v4l2_buf.index);
L
Linus Torvalds 已提交
537 538

	} else {
H
Hans Verkuil 已提交
539 540 541
		buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
		prev = list_entry(q->active.prev, struct cx88_buffer, list);
		list_add_tail(&buf->list, &q->active);
542 543 544
		buf->count    = q->count++;
		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
H
Hans Verkuil 已提交
545
			buf, buf->vb.v4l2_buf.index);
L
Linus Torvalds 已提交
546 547 548
	}
}

H
Hans Verkuil 已提交
549
static int start_streaming(struct vb2_queue *q, unsigned int count)
L
Linus Torvalds 已提交
550
{
H
Hans Verkuil 已提交
551 552 553 554
	struct cx8800_dev *dev = q->drv_priv;
	struct cx88_dmaqueue *dmaq = &dev->vidq;
	struct cx88_buffer *buf = list_entry(dmaq->active.next,
			struct cx88_buffer, list);
L
Linus Torvalds 已提交
555

H
Hans Verkuil 已提交
556 557
	start_video_dma(dev, dmaq, buf);
	return 0;
L
Linus Torvalds 已提交
558 559
}

H
Hans Verkuil 已提交
560 561 562 563 564 565
static void stop_streaming(struct vb2_queue *q)
{
	struct cx8800_dev *dev = q->drv_priv;
	struct cx88_core *core = dev->core;
	struct cx88_dmaqueue *dmaq = &dev->vidq;
	unsigned long flags;
L
Linus Torvalds 已提交
566

H
Hans Verkuil 已提交
567 568 569 570 571 572
	cx_clear(MO_VID_DMACNTRL, 0x11);
	cx_clear(VID_CAPTURE_CONTROL, 0x06);
	spin_lock_irqsave(&dev->slock, flags);
	while (!list_empty(&dmaq->active)) {
		struct cx88_buffer *buf = list_entry(dmaq->active.next,
			struct cx88_buffer, list);
573

H
Hans Verkuil 已提交
574 575
		list_del(&buf->list);
		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
L
Linus Torvalds 已提交
576
	}
H
Hans Verkuil 已提交
577
	spin_unlock_irqrestore(&dev->slock, flags);
L
Linus Torvalds 已提交
578 579
}

H
Hans Verkuil 已提交
580 581 582 583 584 585 586 587 588 589
static struct vb2_ops cx8800_video_qops = {
	.queue_setup    = queue_setup,
	.buf_prepare  = buffer_prepare,
	.buf_finish = buffer_finish,
	.buf_queue    = buffer_queue,
	.wait_prepare = vb2_ops_wait_prepare,
	.wait_finish = vb2_ops_wait_finish,
	.start_streaming = start_streaming,
	.stop_streaming = stop_streaming,
};
590

H
Hans Verkuil 已提交
591
/* ------------------------------------------------------------------ */
L
Linus Torvalds 已提交
592

H
Hans Verkuil 已提交
593
static int radio_open(struct file *file)
L
Linus Torvalds 已提交
594
{
595
	struct cx8800_dev *dev = video_drvdata(file);
596
	struct cx88_core *core = dev->core;
H
Hans Verkuil 已提交
597
	int ret = v4l2_fh_open(file);
L
Linus Torvalds 已提交
598

H
Hans Verkuil 已提交
599 600
	if (ret)
		return ret;
L
Linus Torvalds 已提交
601

H
Hans Verkuil 已提交
602 603 604 605 606 607 608
	cx_write(MO_GP3_IO, core->board.radio.gpio3);
	cx_write(MO_GP0_IO, core->board.radio.gpio0);
	cx_write(MO_GP1_IO, core->board.radio.gpio1);
	cx_write(MO_GP2_IO, core->board.radio.gpio2);
	if (core->board.radio.audioroute) {
		if (core->sd_wm8775) {
			call_all(core, audio, s_routing,
609
					core->board.radio.audioroute, 0, 0);
610
		}
H
Hans Verkuil 已提交
611 612 613
		/* "I2S ADC mode" */
		core->tvaudio = WW_I2SADC;
		cx88_set_tvaudio(core);
L
Linus Torvalds 已提交
614
	} else {
H
Hans Verkuil 已提交
615 616 617 618
		/* FM Mode */
		core->tvaudio = WW_FM;
		cx88_set_tvaudio(core);
		cx88_set_stereo(core, V4L2_TUNER_MODE_STEREO, 1);
L
Linus Torvalds 已提交
619
	}
H
Hans Verkuil 已提交
620
	call_all(core, tuner, s_radio);
L
Linus Torvalds 已提交
621 622 623 624
	return 0;
}

/* ------------------------------------------------------------------ */
625
/* VIDEO CTRL IOCTLS                                                  */
L
Linus Torvalds 已提交
626

627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 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 671 672 673
static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl)
{
	struct cx88_core *core =
		container_of(ctrl->handler, struct cx88_core, video_hdl);
	const struct cx88_ctrl *cc = ctrl->priv;
	u32 value, mask;

	mask = cc->mask;
	switch (ctrl->id) {
	case V4L2_CID_SATURATION:
		/* special v_sat handling */

		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;

		if (core->tvnorm & V4L2_STD_SECAM) {
			/* For SECAM, both U and V sat should be equal */
			value = value << 8 | value;
		} else {
			/* Keeps U Saturation proportional to V Sat */
			value = (value * 0x5a) / 0x7f << 8 | value;
		}
		mask = 0xffff;
		break;
	case V4L2_CID_SHARPNESS:
		/* 0b000, 0b100, 0b101, 0b110, or 0b111 */
		value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7));
		/* needs to be set for both fields */
		cx_andor(MO_FILTER_EVEN, mask, value);
		break;
	case V4L2_CID_CHROMA_AGC:
		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
		break;
	default:
		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
		break;
	}
	dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
				ctrl->id, ctrl->name, ctrl->val, cc->reg, value,
				mask, cc->sreg ? " [shadowed]" : "");
	if (cc->sreg)
		cx_sandor(cc->sreg, cc->reg, mask, value);
	else
		cx_andor(cc->reg, mask, value);
	return 0;
}

static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl)
L
Linus Torvalds 已提交
674
{
675
	struct cx88_core *core =
676
		container_of(ctrl->handler, struct cx88_core, audio_hdl);
677
	const struct cx88_ctrl *cc = ctrl->priv;
678
	u32 value,mask;
679 680

	/* Pass changes onto any WM8775 */
681
	if (core->sd_wm8775) {
682
		switch (ctrl->id) {
683
		case V4L2_CID_AUDIO_MUTE:
684
			wm8775_s_ctrl(core, ctrl->id, ctrl->val);
685 686
			break;
		case V4L2_CID_AUDIO_VOLUME:
687 688
			wm8775_s_ctrl(core, ctrl->id, (ctrl->val) ?
						(0x90 + ctrl->val) << 8 : 0);
689 690
			break;
		case V4L2_CID_AUDIO_BALANCE:
691
			wm8775_s_ctrl(core, ctrl->id, ctrl->val << 9);
692 693 694 695 696 697
			break;
		default:
			break;
		}
	}

698 699
	mask = cc->mask;
	switch (ctrl->id) {
L
Linus Torvalds 已提交
700
	case V4L2_CID_AUDIO_BALANCE:
701
		value = (ctrl->val < 0x40) ? (0x7f - ctrl->val) : (ctrl->val - 0x40);
L
Linus Torvalds 已提交
702 703
		break;
	case V4L2_CID_AUDIO_VOLUME:
704
		value = 0x3f - (ctrl->val & 0x3f);
L
Linus Torvalds 已提交
705 706
		break;
	default:
707
		value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
L
Linus Torvalds 已提交
708 709
		break;
	}
710
	dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
711 712 713 714 715 716
				ctrl->id, ctrl->name, ctrl->val, cc->reg, value,
				mask, cc->sreg ? " [shadowed]" : "");
	if (cc->sreg)
		cx_sandor(cc->sreg, cc->reg, mask, value);
	else
		cx_andor(cc->reg, mask, value);
L
Linus Torvalds 已提交
717 718 719 720
	return 0;
}

/* ------------------------------------------------------------------ */
721
/* VIDEO IOCTLS                                                       */
L
Linus Torvalds 已提交
722

723
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
724
					struct v4l2_format *f)
L
Linus Torvalds 已提交
725
{
H
Hans Verkuil 已提交
726
	struct cx8800_dev *dev = video_drvdata(file);
727
	struct cx88_core *core = dev->core;
728

729 730 731
	f->fmt.pix.width        = core->width;
	f->fmt.pix.height       = core->height;
	f->fmt.pix.field        = core->field;
732
	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
733
	f->fmt.pix.bytesperline =
734
		(f->fmt.pix.width * dev->fmt->depth) >> 3;
735 736
	f->fmt.pix.sizeimage =
		f->fmt.pix.height * f->fmt.pix.bytesperline;
737
	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
738
	return 0;
L
Linus Torvalds 已提交
739 740
}

741
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
742
			struct v4l2_format *f)
L
Linus Torvalds 已提交
743
{
H
Hans Verkuil 已提交
744 745
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
746
	const struct cx8800_fmt *fmt;
747 748
	enum v4l2_field   field;
	unsigned int      maxw, maxh;
749

750 751 752
	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
	if (NULL == fmt)
		return -EINVAL;
L
Linus Torvalds 已提交
753

754 755
	maxw = norm_maxw(core->tvnorm);
	maxh = norm_maxh(core->tvnorm);
L
Linus Torvalds 已提交
756

757
	field = f->fmt.pix.field;
758 759 760 761 762

	switch (field) {
	case V4L2_FIELD_TOP:
	case V4L2_FIELD_BOTTOM:
	case V4L2_FIELD_INTERLACED:
763 764
	case V4L2_FIELD_SEQ_BT:
	case V4L2_FIELD_SEQ_TB:
765
		break;
L
Linus Torvalds 已提交
766
	default:
767 768 769 770
		field = (f->fmt.pix.height > maxh / 2)
			? V4L2_FIELD_INTERLACED
			: V4L2_FIELD_BOTTOM;
		break;
L
Linus Torvalds 已提交
771
	}
772 773
	if (V4L2_FIELD_HAS_T_OR_B(field))
		maxh /= 2;
774

775 776
	v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
			      &f->fmt.pix.height, 32, maxh, 0, 0);
777
	f->fmt.pix.field = field;
778 779 780 781 782 783
	f->fmt.pix.bytesperline =
		(f->fmt.pix.width * fmt->depth) >> 3;
	f->fmt.pix.sizeimage =
		f->fmt.pix.height * f->fmt.pix.bytesperline;

	return 0;
L
Linus Torvalds 已提交
784 785
}

786
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
787
					struct v4l2_format *f)
L
Linus Torvalds 已提交
788
{
H
Hans Verkuil 已提交
789
	struct cx8800_dev *dev = video_drvdata(file);
790
	struct cx88_core *core = dev->core;
791
	int err = vidioc_try_fmt_vid_cap (file,priv,f);
792 793 794

	if (0 != err)
		return err;
795 796 797 798
	if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq))
		return -EBUSY;
	if (core->dvbdev && vb2_is_busy(&core->dvbdev->vb2_mpegq))
		return -EBUSY;
799 800 801 802
	dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
	core->width = f->fmt.pix.width;
	core->height = f->fmt.pix.height;
	core->field = f->fmt.pix.field;
803
	return 0;
L
Linus Torvalds 已提交
804 805
}

H
Hans Verkuil 已提交
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
void cx88_querycap(struct file *file, struct cx88_core *core,
		struct v4l2_capability *cap)
{
	struct video_device *vdev = video_devdata(file);

	strlcpy(cap->card, core->board.name, sizeof(cap->card));
	cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
	if (UNSET != core->board.tuner_type)
		cap->device_caps |= V4L2_CAP_TUNER;
	switch (vdev->vfl_type) {
	case VFL_TYPE_RADIO:
		cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
		break;
	case VFL_TYPE_GRABBER:
		cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
		break;
	case VFL_TYPE_VBI:
		cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
		break;
	}
	cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE |
		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
	if (core->board.radio.type == CX88_RADIO)
		cap->capabilities |= V4L2_CAP_RADIO;
}
EXPORT_SYMBOL(cx88_querycap);

static int vidioc_querycap(struct file *file, void  *priv,
834
					struct v4l2_capability *cap)
L
Linus Torvalds 已提交
835
{
H
Hans Verkuil 已提交
836 837
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
L
Linus Torvalds 已提交
838

839
	strcpy(cap->driver, "cx8800");
H
Hans Verkuil 已提交
840 841
	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
	cx88_querycap(file, core, cap);
842 843
	return 0;
}
844

845
static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
846 847 848 849 850 851 852 853 854 855
					struct v4l2_fmtdesc *f)
{
	if (unlikely(f->index >= ARRAY_SIZE(formats)))
		return -EINVAL;

	strlcpy(f->description,formats[f->index].name,sizeof(f->description));
	f->pixelformat = formats[f->index].fourcc;

	return 0;
}
L
Linus Torvalds 已提交
856

857 858
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
{
H
Hans Verkuil 已提交
859 860
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
861 862 863 864 865

	*tvnorm = core->tvnorm;
	return 0;
}

866
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
867
{
H
Hans Verkuil 已提交
868 869
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
870

871
	return cx88_set_tvnorm(core, tvnorms);
872
}
L
Linus Torvalds 已提交
873

874
/* only one input in this sample driver */
875
int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
876
{
877
	static const char * const iname[] = {
878 879 880 881 882 883 884 885 886 887
		[ CX88_VMUX_COMPOSITE1 ] = "Composite1",
		[ CX88_VMUX_COMPOSITE2 ] = "Composite2",
		[ CX88_VMUX_COMPOSITE3 ] = "Composite3",
		[ CX88_VMUX_COMPOSITE4 ] = "Composite4",
		[ CX88_VMUX_SVIDEO     ] = "S-Video",
		[ CX88_VMUX_TELEVISION ] = "Television",
		[ CX88_VMUX_CABLE      ] = "Cable TV",
		[ CX88_VMUX_DVB        ] = "DVB",
		[ CX88_VMUX_DEBUG      ] = "for debug only",
	};
888
	unsigned int n = i->index;
L
Linus Torvalds 已提交
889

890 891
	if (n >= 4)
		return -EINVAL;
892
	if (0 == INPUT(n).type)
893 894
		return -EINVAL;
	i->type  = V4L2_INPUT_TYPE_CAMERA;
895 896
	strcpy(i->name,iname[INPUT(n).type]);
	if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
897
	    (CX88_VMUX_CABLE      == INPUT(n).type)) {
898
		i->type = V4L2_INPUT_TYPE_TUNER;
899
	}
900
	i->std = CX88_NORMS;
901 902
	return 0;
}
903 904 905 906 907
EXPORT_SYMBOL(cx88_enum_input);

static int vidioc_enum_input (struct file *file, void *priv,
				struct v4l2_input *i)
{
H
Hans Verkuil 已提交
908 909
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
910 911
	return cx88_enum_input (core,i);
}
L
Linus Torvalds 已提交
912

913 914
static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
{
H
Hans Verkuil 已提交
915 916
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
L
Linus Torvalds 已提交
917

918 919 920
	*i = core->input;
	return 0;
}
L
Linus Torvalds 已提交
921

922 923
static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
{
H
Hans Verkuil 已提交
924 925
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
L
Linus Torvalds 已提交
926

927 928
	if (i >= 4)
		return -EINVAL;
929 930
	if (0 == INPUT(i).type)
		return -EINVAL;
L
Linus Torvalds 已提交
931

932
	cx88_newstation(core);
933
	cx88_video_mux(core,i);
934 935
	return 0;
}
L
Linus Torvalds 已提交
936

937 938 939
static int vidioc_g_tuner (struct file *file, void *priv,
				struct v4l2_tuner *t)
{
H
Hans Verkuil 已提交
940 941
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
942
	u32 reg;
L
Linus Torvalds 已提交
943

944
	if (unlikely(UNSET == core->board.tuner_type))
945
		return -EINVAL;
946 947
	if (0 != t->index)
		return -EINVAL;
M
Mauro Carvalho Chehab 已提交
948

949 950 951
	strcpy(t->name, "Television");
	t->capability = V4L2_TUNER_CAP_NORM;
	t->rangehigh  = 0xffffffffUL;
952
	call_all(core, tuner, g_tuner, t);
M
Mauro Carvalho Chehab 已提交
953

954 955 956 957 958
	cx88_get_stereo(core ,t);
	reg = cx_read(MO_DEVICE_STATUS);
	t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
	return 0;
}
M
Mauro Carvalho Chehab 已提交
959

960
static int vidioc_s_tuner (struct file *file, void *priv,
961
				const struct v4l2_tuner *t)
962
{
H
Hans Verkuil 已提交
963 964
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
M
Mauro Carvalho Chehab 已提交
965

966
	if (UNSET == core->board.tuner_type)
967 968 969
		return -EINVAL;
	if (0 != t->index)
		return -EINVAL;
970

971 972 973
	cx88_set_stereo(core, t->audmode, 1);
	return 0;
}
974

975 976 977
static int vidioc_g_frequency (struct file *file, void *priv,
				struct v4l2_frequency *f)
{
H
Hans Verkuil 已提交
978 979
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
980

981
	if (unlikely(UNSET == core->board.tuner_type))
982
		return -EINVAL;
983 984
	if (f->tuner)
		return -EINVAL;
985 986 987

	f->frequency = core->freq;

988
	call_all(core, tuner, g_frequency, f);
L
Linus Torvalds 已提交
989 990 991 992

	return 0;
}

993
int cx88_set_freq (struct cx88_core  *core,
994
				const struct v4l2_frequency *f)
L
Linus Torvalds 已提交
995
{
996 997
	struct v4l2_frequency new_freq = *f;

998
	if (unlikely(UNSET == core->board.tuner_type))
999 1000 1001
		return -EINVAL;
	if (unlikely(f->tuner != 0))
		return -EINVAL;
1002

1003
	cx88_newstation(core);
1004
	call_all(core, tuner, s_frequency, f);
1005 1006
	call_all(core, tuner, g_frequency, &new_freq);
	core->freq = new_freq.frequency;
1007

1008 1009 1010
	/* When changing channels it is required to reset TVAUDIO */
	msleep (10);
	cx88_set_tvaudio(core);
1011

1012
	return 0;
L
Linus Torvalds 已提交
1013
}
1014 1015 1016
EXPORT_SYMBOL(cx88_set_freq);

static int vidioc_s_frequency (struct file *file, void *priv,
1017
				const struct v4l2_frequency *f)
1018
{
H
Hans Verkuil 已提交
1019 1020
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
1021

1022
	return cx88_set_freq(core, f);
1023
}
L
Linus Torvalds 已提交
1024

1025 1026
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *fh,
1027
				struct v4l2_dbg_register *reg)
1028
{
H
Hans Verkuil 已提交
1029 1030
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
1031 1032

	/* cx2388x has a 24-bit register space */
H
Hans Verkuil 已提交
1033
	reg->val = cx_read(reg->reg & 0xfffffc);
1034
	reg->size = 4;
1035 1036 1037 1038
	return 0;
}

static int vidioc_s_register (struct file *file, void *fh,
1039
				const struct v4l2_dbg_register *reg)
1040
{
H
Hans Verkuil 已提交
1041 1042
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
1043

H
Hans Verkuil 已提交
1044
	cx_write(reg->reg & 0xfffffc, reg->val);
1045 1046 1047
	return 0;
}
#endif
1048 1049 1050

/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS                                      */
L
Linus Torvalds 已提交
1051 1052
/* ----------------------------------------------------------- */

1053 1054 1055
static int radio_g_tuner (struct file *file, void *priv,
				struct v4l2_tuner *t)
{
H
Hans Verkuil 已提交
1056 1057
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
L
Linus Torvalds 已提交
1058

1059 1060
	if (unlikely(t->index > 0))
		return -EINVAL;
L
Linus Torvalds 已提交
1061

1062
	strcpy(t->name, "Radio");
L
Linus Torvalds 已提交
1063

1064
	call_all(core, tuner, g_tuner, t);
1065 1066
	return 0;
}
L
Linus Torvalds 已提交
1067

1068
static int radio_s_tuner (struct file *file, void *priv,
1069
				const struct v4l2_tuner *t)
1070
{
H
Hans Verkuil 已提交
1071 1072
	struct cx8800_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
M
Mauro Carvalho Chehab 已提交
1073

1074 1075
	if (0 != t->index)
		return -EINVAL;
L
Linus Torvalds 已提交
1076

1077
	call_all(core, tuner, s_tuner, t);
1078 1079
	return 0;
}
L
Linus Torvalds 已提交
1080 1081 1082

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

1083
static const char *cx88_vid_irqs[32] = {
M
Mauro Carvalho Chehab 已提交
1084 1085 1086 1087 1088 1089 1090
	"y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
	"y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
	"y_oflow",  "u_oflow",  "v_oflow",  "vbi_oflow",
	"y_sync",   "u_sync",   "v_sync",   "vbi_sync",
	"opc_err",  "par_err",  "rip_err",  "pci_abort",
};

L
Linus Torvalds 已提交
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
static void cx8800_vid_irq(struct cx8800_dev *dev)
{
	struct cx88_core *core = dev->core;
	u32 status, mask, count;

	status = cx_read(MO_VID_INTSTAT);
	mask   = cx_read(MO_VID_INTMSK);
	if (0 == (status & mask))
		return;
	cx_write(MO_VID_INTSTAT, status);
	if (irq_debug  ||  (status & mask & ~0xff))
		cx88_print_irqbits(core->name, "irq vid",
1103 1104
				   cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs),
				   status, mask);
L
Linus Torvalds 已提交
1105 1106 1107 1108 1109 1110

	/* risc op code error */
	if (status & (1 << 16)) {
		printk(KERN_WARNING "%s/0: video risc op code error\n",core->name);
		cx_clear(MO_VID_DMACNTRL, 0x11);
		cx_clear(VID_CAPTURE_CONTROL, 0x06);
1111
		cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]);
L
Linus Torvalds 已提交
1112 1113 1114 1115 1116 1117
	}

	/* risc1 y */
	if (status & 0x01) {
		spin_lock(&dev->slock);
		count = cx_read(MO_VIDY_GPCNT);
1118
		cx88_wakeup(core, &dev->vidq, count);
L
Linus Torvalds 已提交
1119 1120 1121 1122 1123 1124 1125
		spin_unlock(&dev->slock);
	}

	/* risc1 vbi */
	if (status & 0x08) {
		spin_lock(&dev->slock);
		count = cx_read(MO_VBI_GPCNT);
1126
		cx88_wakeup(core, &dev->vbiq, count);
L
Linus Torvalds 已提交
1127 1128 1129 1130
		spin_unlock(&dev->slock);
	}
}

1131
static irqreturn_t cx8800_irq(int irq, void *dev_id)
L
Linus Torvalds 已提交
1132 1133 1134 1135 1136 1137 1138
{
	struct cx8800_dev *dev = dev_id;
	struct cx88_core *core = dev->core;
	u32 status;
	int loop, handled = 0;

	for (loop = 0; loop < 10; loop++) {
1139 1140
		status = cx_read(MO_PCI_INTSTAT) &
			(core->pci_irqmask | PCI_INT_VIDINT);
L
Linus Torvalds 已提交
1141 1142 1143 1144 1145 1146 1147
		if (0 == status)
			goto out;
		cx_write(MO_PCI_INTSTAT, status);
		handled = 1;

		if (status & core->pci_irqmask)
			cx88_core_irq(core,status);
1148
		if (status & PCI_INT_VIDINT)
L
Linus Torvalds 已提交
1149
			cx8800_vid_irq(dev);
1150
	}
L
Linus Torvalds 已提交
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
	if (10 == loop) {
		printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
		       core->name);
		cx_write(MO_PCI_INTMSK,0);
	}

 out:
	return IRQ_RETVAL(handled);
}

/* ----------------------------------------------------------- */
/* exported stuff                                              */

1164
static const struct v4l2_file_operations video_fops =
L
Linus Torvalds 已提交
1165 1166
{
	.owner	       = THIS_MODULE,
H
Hans Verkuil 已提交
1167 1168 1169 1170 1171
	.open	       = v4l2_fh_open,
	.release       = vb2_fop_release,
	.read	       = vb2_fop_read,
	.poll          = vb2_fop_poll,
	.mmap	       = vb2_fop_mmap,
1172
	.unlocked_ioctl = video_ioctl2,
L
Linus Torvalds 已提交
1173 1174
};

1175
static const struct v4l2_ioctl_ops video_ioctl_ops = {
1176
	.vidioc_querycap      = vidioc_querycap,
1177 1178 1179 1180
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
	.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,
H
Hans Verkuil 已提交
1181 1182 1183 1184
	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
	.vidioc_querybuf      = vb2_ioctl_querybuf,
	.vidioc_qbuf          = vb2_ioctl_qbuf,
	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
1185
	.vidioc_g_std         = vidioc_g_std,
1186 1187 1188 1189
	.vidioc_s_std         = vidioc_s_std,
	.vidioc_enum_input    = vidioc_enum_input,
	.vidioc_g_input       = vidioc_g_input,
	.vidioc_s_input       = vidioc_s_input,
H
Hans Verkuil 已提交
1190 1191
	.vidioc_streamon      = vb2_ioctl_streamon,
	.vidioc_streamoff     = vb2_ioctl_streamoff,
1192 1193 1194 1195
	.vidioc_g_tuner       = vidioc_g_tuner,
	.vidioc_s_tuner       = vidioc_s_tuner,
	.vidioc_g_frequency   = vidioc_g_frequency,
	.vidioc_s_frequency   = vidioc_s_frequency,
1196 1197
	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
1198 1199 1200 1201
#ifdef CONFIG_VIDEO_ADV_DEBUG
	.vidioc_g_register    = vidioc_g_register,
	.vidioc_s_register    = vidioc_s_register,
#endif
1202 1203
};

1204
static const struct video_device cx8800_video_template = {
1205 1206 1207
	.name                 = "cx8800-video",
	.fops                 = &video_fops,
	.ioctl_ops 	      = &video_ioctl_ops,
1208
	.tvnorms              = CX88_NORMS,
L
Linus Torvalds 已提交
1209 1210
};

1211 1212 1213 1214 1215
static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
	.vidioc_querycap      = vidioc_querycap,
	.vidioc_g_fmt_vbi_cap     = cx8800_vbi_fmt,
	.vidioc_try_fmt_vbi_cap   = cx8800_vbi_fmt,
	.vidioc_s_fmt_vbi_cap     = cx8800_vbi_fmt,
H
Hans Verkuil 已提交
1216 1217 1218 1219
	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
	.vidioc_querybuf      = vb2_ioctl_querybuf,
	.vidioc_qbuf          = vb2_ioctl_qbuf,
	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
1220
	.vidioc_g_std         = vidioc_g_std,
1221 1222 1223 1224
	.vidioc_s_std         = vidioc_s_std,
	.vidioc_enum_input    = vidioc_enum_input,
	.vidioc_g_input       = vidioc_g_input,
	.vidioc_s_input       = vidioc_s_input,
H
Hans Verkuil 已提交
1225 1226
	.vidioc_streamon      = vb2_ioctl_streamon,
	.vidioc_streamoff     = vb2_ioctl_streamoff,
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
	.vidioc_g_tuner       = vidioc_g_tuner,
	.vidioc_s_tuner       = vidioc_s_tuner,
	.vidioc_g_frequency   = vidioc_g_frequency,
	.vidioc_s_frequency   = vidioc_s_frequency,
#ifdef CONFIG_VIDEO_ADV_DEBUG
	.vidioc_g_register    = vidioc_g_register,
	.vidioc_s_register    = vidioc_s_register,
#endif
};

static const struct video_device cx8800_vbi_template = {
	.name                 = "cx8800-vbi",
	.fops                 = &video_fops,
	.ioctl_ops	      = &vbi_ioctl_ops,
	.tvnorms              = CX88_NORMS,
};

1244
static const struct v4l2_file_operations radio_fops =
L
Linus Torvalds 已提交
1245 1246
{
	.owner         = THIS_MODULE,
H
Hans Verkuil 已提交
1247
	.open          = radio_open,
1248
	.poll          = v4l2_ctrl_poll,
H
Hans Verkuil 已提交
1249
	.release       = v4l2_fh_release,
1250
	.unlocked_ioctl = video_ioctl2,
L
Linus Torvalds 已提交
1251 1252
};

1253
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
H
Hans Verkuil 已提交
1254
	.vidioc_querycap      = vidioc_querycap,
1255 1256 1257 1258
	.vidioc_g_tuner       = radio_g_tuner,
	.vidioc_s_tuner       = radio_s_tuner,
	.vidioc_g_frequency   = vidioc_g_frequency,
	.vidioc_s_frequency   = vidioc_s_frequency,
1259 1260
	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
1261 1262 1263 1264
#ifdef CONFIG_VIDEO_ADV_DEBUG
	.vidioc_g_register    = vidioc_g_register,
	.vidioc_s_register    = vidioc_s_register,
#endif
L
Linus Torvalds 已提交
1265 1266
};

1267
static const struct video_device cx8800_radio_template = {
1268 1269 1270 1271 1272
	.name                 = "cx8800-radio",
	.fops                 = &radio_fops,
	.ioctl_ops 	      = &radio_ioctl_ops,
};

1273 1274 1275 1276 1277 1278
static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = {
	.s_ctrl = cx8800_s_vid_ctrl,
};

static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = {
	.s_ctrl = cx8800_s_aud_ctrl,
1279 1280
};

L
Linus Torvalds 已提交
1281 1282 1283 1284 1285
/* ----------------------------------------------------------- */

static void cx8800_unregister_video(struct cx8800_dev *dev)
{
	if (dev->radio_dev) {
1286
		if (video_is_registered(dev->radio_dev))
L
Linus Torvalds 已提交
1287 1288 1289 1290 1291 1292
			video_unregister_device(dev->radio_dev);
		else
			video_device_release(dev->radio_dev);
		dev->radio_dev = NULL;
	}
	if (dev->vbi_dev) {
1293
		if (video_is_registered(dev->vbi_dev))
L
Linus Torvalds 已提交
1294 1295 1296 1297 1298 1299
			video_unregister_device(dev->vbi_dev);
		else
			video_device_release(dev->vbi_dev);
		dev->vbi_dev = NULL;
	}
	if (dev->video_dev) {
1300
		if (video_is_registered(dev->video_dev))
L
Linus Torvalds 已提交
1301 1302 1303 1304 1305 1306 1307
			video_unregister_device(dev->video_dev);
		else
			video_device_release(dev->video_dev);
		dev->video_dev = NULL;
	}
}

1308 1309
static int cx8800_initdev(struct pci_dev *pci_dev,
			  const struct pci_device_id *pci_id)
L
Linus Torvalds 已提交
1310 1311 1312
{
	struct cx8800_dev *dev;
	struct cx88_core *core;
H
Hans Verkuil 已提交
1313
	struct vb2_queue *q;
L
Linus Torvalds 已提交
1314
	int err;
1315
	int i;
L
Linus Torvalds 已提交
1316

P
 
Panagiotis Issaris 已提交
1317
	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
L
Linus Torvalds 已提交
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
	if (NULL == dev)
		return -ENOMEM;

	/* pci init */
	dev->pci = pci_dev;
	if (pci_enable_device(pci_dev)) {
		err = -EIO;
		goto fail_free;
	}
	core = cx88_core_get(dev->pci);
	if (NULL == core) {
		err = -EINVAL;
		goto fail_free;
	}
	dev->core = core;

	/* print pci info */
B
Bjørn Mork 已提交
1335
	dev->pci_rev = pci_dev->revision;
1336 1337
	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
1338
	       "latency: %d, mmio: 0x%llx\n", core->name,
L
Linus Torvalds 已提交
1339
	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
1340
	       dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
L
Linus Torvalds 已提交
1341 1342

	pci_set_master(pci_dev);
1343
	if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) {
L
Linus Torvalds 已提交
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
		printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name);
		err = -EIO;
		goto fail_core;
	}

	/* initialize driver struct */
	spin_lock_init(&dev->slock);

	/* init video dma queues */
	INIT_LIST_HEAD(&dev->vidq.active);

	/* init vbi dma queues */
	INIT_LIST_HEAD(&dev->vbiq.active);

	/* get irq */
	err = request_irq(pci_dev->irq, cx8800_irq,
1360
			  IRQF_SHARED, core->name, dev);
L
Linus Torvalds 已提交
1361
	if (err < 0) {
1362
		printk(KERN_ERR "%s/0: can't get IRQ %d\n",
L
Linus Torvalds 已提交
1363 1364 1365 1366 1367
		       core->name,pci_dev->irq);
		goto fail_core;
	}
	cx_set(MO_PCI_INTMSK, core->pci_irqmask);

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
	for (i = 0; i < CX8800_AUD_CTLS; i++) {
		const struct cx88_ctrl *cc = &cx8800_aud_ctls[i];
		struct v4l2_ctrl *vc;

		vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops,
			cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value);
		if (vc == NULL) {
			err = core->audio_hdl.error;
			goto fail_core;
		}
		vc->priv = (void *)cc;
	}

	for (i = 0; i < CX8800_VID_CTLS; i++) {
		const struct cx88_ctrl *cc = &cx8800_vid_ctls[i];
1383 1384
		struct v4l2_ctrl *vc;

1385
		vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops,
1386 1387
			cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value);
		if (vc == NULL) {
1388
			err = core->video_hdl.error;
1389 1390 1391
			goto fail_core;
		}
		vc->priv = (void *)cc;
1392 1393
		if (vc->id == V4L2_CID_CHROMA_AGC)
			core->chroma_agc = vc;
1394
	}
1395
	v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl, NULL);
1396

L
Linus Torvalds 已提交
1397
	/* load and configure helper modules */
1398

H
Hans Verkuil 已提交
1399
	if (core->board.audio_chip == CX88_AUDIO_WM8775) {
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413
		struct i2c_board_info wm8775_info = {
			.type = "wm8775",
			.addr = 0x36 >> 1,
			.platform_data = &core->wm8775_data,
		};
		struct v4l2_subdev *sd;

		if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1)
			core->wm8775_data.is_nova_s = true;
		else
			core->wm8775_data.is_nova_s = false;

		sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap,
				&wm8775_info, NULL);
1414 1415
		if (sd != NULL) {
			core->sd_wm8775 = sd;
1416
			sd->grp_id = WM8775_GID;
1417
		}
1418
	}
1419

H
Hans Verkuil 已提交
1420
	if (core->board.audio_chip == CX88_AUDIO_TVAUDIO) {
1421 1422
		/* This probes for a tda9874 as is used on some
		   Pixelview Ultra boards. */
1423 1424
		v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
				"tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
1425
	}
1426

1427 1428
	switch (core->boardnr) {
	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
1429
	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
1430
		static const struct i2c_board_info rtc_info = {
1431 1432 1433
			I2C_BOARD_INFO("isl1208", 0x6f)
		};

1434
		request_module("rtc-isl1208");
1435 1436
		core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
	}
1437 1438 1439
		/* break intentionally omitted */
	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
		request_module("ir-kbd-i2c");
1440 1441
	}

1442 1443 1444
	/* Sets device info at pci_dev */
	pci_set_drvdata(pci_dev, dev);

1445
	dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
1446

1447 1448 1449
	/* Maintain a reference so cx88-blackbird can query the 8800 device. */
	core->v4ldev = dev;

1450 1451 1452
	/* initial device configuration */
	mutex_lock(&core->lock);
	cx88_set_tvnorm(core, core->tvnorm);
1453 1454
	v4l2_ctrl_handler_setup(&core->video_hdl);
	v4l2_ctrl_handler_setup(&core->audio_hdl);
1455 1456
	cx88_video_mux(core, 0);

H
Hans Verkuil 已提交
1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488
	q = &dev->vb2_vidq;
	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
	q->gfp_flags = GFP_DMA32;
	q->min_buffers_needed = 2;
	q->drv_priv = dev;
	q->buf_struct_size = sizeof(struct cx88_buffer);
	q->ops = &cx8800_video_qops;
	q->mem_ops = &vb2_dma_sg_memops;
	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	q->lock = &core->lock;

	err = vb2_queue_init(q);
	if (err < 0)
		goto fail_unreg;

	q = &dev->vb2_vbiq;
	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
	q->gfp_flags = GFP_DMA32;
	q->min_buffers_needed = 2;
	q->drv_priv = dev;
	q->buf_struct_size = sizeof(struct cx88_buffer);
	q->ops = &cx8800_vbi_qops;
	q->mem_ops = &vb2_dma_sg_memops;
	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	q->lock = &core->lock;

	err = vb2_queue_init(q);
	if (err < 0)
		goto fail_unreg;

L
Linus Torvalds 已提交
1489 1490 1491
	/* register v4l devices */
	dev->video_dev = cx88_vdev_init(core,dev->pci,
					&cx8800_video_template,"video");
1492
	video_set_drvdata(dev->video_dev, dev);
1493
	dev->video_dev->ctrl_handler = &core->video_hdl;
H
Hans Verkuil 已提交
1494
	dev->video_dev->queue = &dev->vb2_vidq;
L
Linus Torvalds 已提交
1495 1496 1497
	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
				    video_nr[core->nr]);
	if (err < 0) {
1498
		printk(KERN_ERR "%s/0: can't register video device\n",
L
Linus Torvalds 已提交
1499 1500 1501
		       core->name);
		goto fail_unreg;
	}
1502 1503
	printk(KERN_INFO "%s/0: registered device %s [v4l2]\n",
	       core->name, video_device_node_name(dev->video_dev));
L
Linus Torvalds 已提交
1504 1505

	dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi");
1506
	video_set_drvdata(dev->vbi_dev, dev);
H
Hans Verkuil 已提交
1507
	dev->vbi_dev->queue = &dev->vb2_vbiq;
L
Linus Torvalds 已提交
1508 1509 1510
	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
				    vbi_nr[core->nr]);
	if (err < 0) {
1511
		printk(KERN_ERR "%s/0: can't register vbi device\n",
L
Linus Torvalds 已提交
1512 1513 1514
		       core->name);
		goto fail_unreg;
	}
1515 1516
	printk(KERN_INFO "%s/0: registered device %s\n",
	       core->name, video_device_node_name(dev->vbi_dev));
L
Linus Torvalds 已提交
1517

1518
	if (core->board.radio.type == CX88_RADIO) {
L
Linus Torvalds 已提交
1519 1520
		dev->radio_dev = cx88_vdev_init(core,dev->pci,
						&cx8800_radio_template,"radio");
1521
		video_set_drvdata(dev->radio_dev, dev);
1522
		dev->radio_dev->ctrl_handler = &core->audio_hdl;
L
Linus Torvalds 已提交
1523 1524 1525
		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
					    radio_nr[core->nr]);
		if (err < 0) {
1526
			printk(KERN_ERR "%s/0: can't register radio device\n",
L
Linus Torvalds 已提交
1527 1528 1529
			       core->name);
			goto fail_unreg;
		}
1530 1531
		printk(KERN_INFO "%s/0: registered device %s\n",
		       core->name, video_device_node_name(dev->radio_dev));
L
Linus Torvalds 已提交
1532 1533 1534
	}

	/* start tvaudio thread */
1535
	if (core->board.tuner_type != TUNER_ABSENT) {
L
Linus Torvalds 已提交
1536
		core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
1537 1538
		if (IS_ERR(core->kthread)) {
			err = PTR_ERR(core->kthread);
1539 1540
			printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n",
			       core->name, err);
1541 1542
		}
	}
1543 1544
	mutex_unlock(&core->lock);

L
Linus Torvalds 已提交
1545 1546 1547 1548 1549
	return 0;

fail_unreg:
	cx8800_unregister_video(dev);
	free_irq(pci_dev->irq, dev);
1550
	mutex_unlock(&core->lock);
L
Linus Torvalds 已提交
1551
fail_core:
1552
	core->v4ldev = NULL;
L
Linus Torvalds 已提交
1553 1554 1555 1556 1557 1558
	cx88_core_put(core,dev->pci);
fail_free:
	kfree(dev);
	return err;
}

1559
static void cx8800_finidev(struct pci_dev *pci_dev)
L
Linus Torvalds 已提交
1560
{
1561
	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
1562
	struct cx88_core *core = dev->core;
L
Linus Torvalds 已提交
1563 1564

	/* stop thread */
1565 1566 1567
	if (core->kthread) {
		kthread_stop(core->kthread);
		core->kthread = NULL;
L
Linus Torvalds 已提交
1568 1569
	}

1570
	if (core->ir)
1571
		cx88_ir_stop(core);
1572

1573
	cx88_shutdown(core); /* FIXME */
L
Linus Torvalds 已提交
1574 1575 1576 1577 1578 1579 1580
	pci_disable_device(pci_dev);

	/* unregister stuff */

	free_irq(pci_dev->irq, dev);
	cx8800_unregister_video(dev);

1581 1582
	core->v4ldev = NULL;

L
Linus Torvalds 已提交
1583
	/* free memory */
1584
	cx88_core_put(core,dev->pci);
L
Linus Torvalds 已提交
1585 1586 1587
	kfree(dev);
}

1588
#ifdef CONFIG_PM
L
Linus Torvalds 已提交
1589 1590
static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
1591
	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
L
Linus Torvalds 已提交
1592
	struct cx88_core *core = dev->core;
1593
	unsigned long flags;
L
Linus Torvalds 已提交
1594 1595

	/* stop video+vbi capture */
1596
	spin_lock_irqsave(&dev->slock, flags);
L
Linus Torvalds 已提交
1597
	if (!list_empty(&dev->vidq.active)) {
1598
		printk("%s/0: suspend video\n", core->name);
L
Linus Torvalds 已提交
1599 1600 1601
		stop_video_dma(dev);
	}
	if (!list_empty(&dev->vbiq.active)) {
1602
		printk("%s/0: suspend vbi\n", core->name);
L
Linus Torvalds 已提交
1603 1604
		cx8800_stop_vbi_dma(dev);
	}
1605
	spin_unlock_irqrestore(&dev->slock, flags);
L
Linus Torvalds 已提交
1606

1607
	if (core->ir)
1608
		cx88_ir_stop(core);
L
Linus Torvalds 已提交
1609
	/* FIXME -- shutdown device */
1610
	cx88_shutdown(core);
L
Linus Torvalds 已提交
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621

	pci_save_state(pci_dev);
	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
		pci_disable_device(pci_dev);
		dev->state.disabled = 1;
	}
	return 0;
}

static int cx8800_resume(struct pci_dev *pci_dev)
{
1622
	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
L
Linus Torvalds 已提交
1623
	struct cx88_core *core = dev->core;
1624
	unsigned long flags;
1625
	int err;
L
Linus Torvalds 已提交
1626 1627

	if (dev->state.disabled) {
1628 1629
		err=pci_enable_device(pci_dev);
		if (err) {
1630 1631
			printk(KERN_ERR "%s/0: can't enable device\n",
			       core->name);
1632 1633 1634
			return err;
		}

L
Linus Torvalds 已提交
1635 1636
		dev->state.disabled = 0;
	}
1637 1638
	err= pci_set_power_state(pci_dev, PCI_D0);
	if (err) {
1639
		printk(KERN_ERR "%s/0: can't set power state\n", core->name);
1640 1641 1642 1643 1644
		pci_disable_device(pci_dev);
		dev->state.disabled = 1;

		return err;
	}
L
Linus Torvalds 已提交
1645 1646 1647
	pci_restore_state(pci_dev);

	/* FIXME: re-initialize hardware */
1648
	cx88_reset(core);
1649
	if (core->ir)
1650
		cx88_ir_start(core);
1651 1652

	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
L
Linus Torvalds 已提交
1653 1654

	/* restart video+vbi capture */
1655
	spin_lock_irqsave(&dev->slock, flags);
L
Linus Torvalds 已提交
1656
	if (!list_empty(&dev->vidq.active)) {
1657
		printk("%s/0: resume video\n", core->name);
L
Linus Torvalds 已提交
1658 1659 1660
		restart_video_queue(dev,&dev->vidq);
	}
	if (!list_empty(&dev->vbiq.active)) {
1661
		printk("%s/0: resume vbi\n", core->name);
L
Linus Torvalds 已提交
1662 1663
		cx8800_restart_vbi_queue(dev,&dev->vbiq);
	}
1664
	spin_unlock_irqrestore(&dev->slock, flags);
L
Linus Torvalds 已提交
1665 1666 1667

	return 0;
}
1668
#endif
L
Linus Torvalds 已提交
1669 1670 1671

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

1672
static const struct pci_device_id cx8800_pci_tbl[] = {
L
Linus Torvalds 已提交
1673 1674 1675
	{
		.vendor       = 0x14f1,
		.device       = 0x8800,
1676 1677
		.subvendor    = PCI_ANY_ID,
		.subdevice    = PCI_ANY_ID,
L
Linus Torvalds 已提交
1678 1679 1680 1681 1682 1683 1684
	},{
		/* --- end of list --- */
	}
};
MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);

static struct pci_driver cx8800_pci_driver = {
1685 1686 1687
	.name     = "cx8800",
	.id_table = cx8800_pci_tbl,
	.probe    = cx8800_initdev,
1688
	.remove   = cx8800_finidev,
1689
#ifdef CONFIG_PM
L
Linus Torvalds 已提交
1690 1691
	.suspend  = cx8800_suspend,
	.resume   = cx8800_resume,
1692
#endif
L
Linus Torvalds 已提交
1693 1694
};

1695
module_pci_driver(cx8800_pci_driver);