[go: nahoru, domu]

1/*
2 *  Driver for the NXP SAA7164 PCIe bridge
3 *
4 *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to the Free Software
19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "saa7164.h"
23
24static struct saa7164_tvnorm saa7164_tvnorms[] = {
25	{
26		.name      = "NTSC-M",
27		.id        = V4L2_STD_NTSC_M,
28	}, {
29		.name      = "NTSC-JP",
30		.id        = V4L2_STD_NTSC_M_JP,
31	}
32};
33
34static const u32 saa7164_v4l2_ctrls[] = {
35	0
36};
37
38/* Take the encoder configuration from the port struct and
39 * flush it to the hardware.
40 */
41static void saa7164_vbi_configure(struct saa7164_port *port)
42{
43	struct saa7164_dev *dev = port->dev;
44	dprintk(DBGLVL_VBI, "%s()\n", __func__);
45
46	port->vbi_params.width = port->width;
47	port->vbi_params.height = port->height;
48	port->vbi_params.is_50hz =
49		(port->encodernorm.id & V4L2_STD_625_50) != 0;
50
51	/* Set up the DIF (enable it) for analog mode by default */
52	saa7164_api_initialize_dif(port);
53
54	/* Configure the correct video standard */
55#if 0
56	saa7164_api_configure_dif(port, port->encodernorm.id);
57#endif
58
59#if 0
60	/* Ensure the audio decoder is correct configured */
61	saa7164_api_set_audio_std(port);
62#endif
63	dprintk(DBGLVL_VBI, "%s() ends\n", __func__);
64}
65
66static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port)
67{
68	struct list_head *c, *n, *p, *q, *l, *v;
69	struct saa7164_dev *dev = port->dev;
70	struct saa7164_buffer *buf;
71	struct saa7164_user_buffer *ubuf;
72
73	/* Remove any allocated buffers */
74	mutex_lock(&port->dmaqueue_lock);
75
76	dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr);
77	list_for_each_safe(c, n, &port->dmaqueue.list) {
78		buf = list_entry(c, struct saa7164_buffer, list);
79		list_del(c);
80		saa7164_buffer_dealloc(buf);
81	}
82
83	dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr);
84	list_for_each_safe(p, q, &port->list_buf_used.list) {
85		ubuf = list_entry(p, struct saa7164_user_buffer, list);
86		list_del(p);
87		saa7164_buffer_dealloc_user(ubuf);
88	}
89
90	dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr);
91	list_for_each_safe(l, v, &port->list_buf_free.list) {
92		ubuf = list_entry(l, struct saa7164_user_buffer, list);
93		list_del(l);
94		saa7164_buffer_dealloc_user(ubuf);
95	}
96
97	mutex_unlock(&port->dmaqueue_lock);
98	dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr);
99
100	return 0;
101}
102
103/* Dynamic buffer switch at vbi start time */
104static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
105{
106	struct saa7164_dev *dev = port->dev;
107	struct saa7164_buffer *buf;
108	struct saa7164_user_buffer *ubuf;
109	struct tmHWStreamParameters *params = &port->hw_streamingparams;
110	int result = -ENODEV, i;
111	int len = 0;
112
113	dprintk(DBGLVL_VBI, "%s()\n", __func__);
114
115	/* TODO: NTSC SPECIFIC */
116	/* Init and establish defaults */
117	params->samplesperline = 1440;
118	params->numberoflines = 12;
119	params->numberoflines = 18;
120	params->pitch = 1600;
121	params->pitch = 1440;
122	params->numpagetables = 2 +
123		((params->numberoflines * params->pitch) / PAGE_SIZE);
124	params->bitspersample = 8;
125	params->linethreshold = 0;
126	params->pagetablelistvirt = NULL;
127	params->pagetablelistphys = NULL;
128	params->numpagetableentries = port->hwcfg.buffercount;
129
130	/* Allocate the PCI resources, buffers (hard) */
131	for (i = 0; i < port->hwcfg.buffercount; i++) {
132		buf = saa7164_buffer_alloc(port,
133			params->numberoflines *
134			params->pitch);
135
136		if (!buf) {
137			printk(KERN_ERR "%s() failed "
138			       "(errno = %d), unable to allocate buffer\n",
139				__func__, result);
140			result = -ENOMEM;
141			goto failed;
142		} else {
143
144			mutex_lock(&port->dmaqueue_lock);
145			list_add_tail(&buf->list, &port->dmaqueue.list);
146			mutex_unlock(&port->dmaqueue_lock);
147
148		}
149	}
150
151	/* Allocate some kernel buffers for copying
152	 * to userpsace.
153	 */
154	len = params->numberoflines * params->pitch;
155
156	if (vbi_buffers < 16)
157		vbi_buffers = 16;
158	if (vbi_buffers > 512)
159		vbi_buffers = 512;
160
161	for (i = 0; i < vbi_buffers; i++) {
162
163		ubuf = saa7164_buffer_alloc_user(dev, len);
164		if (ubuf) {
165			mutex_lock(&port->dmaqueue_lock);
166			list_add_tail(&ubuf->list, &port->list_buf_free.list);
167			mutex_unlock(&port->dmaqueue_lock);
168		}
169
170	}
171
172	result = 0;
173
174failed:
175	return result;
176}
177
178
179static int saa7164_vbi_initialize(struct saa7164_port *port)
180{
181	saa7164_vbi_configure(port);
182	return 0;
183}
184
185/* -- V4L2 --------------------------------------------------------- */
186static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
187{
188	struct saa7164_vbi_fh *fh = file->private_data;
189	struct saa7164_port *port = fh->port;
190	struct saa7164_dev *dev = port->dev;
191	unsigned int i;
192
193	dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)id);
194
195	for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
196		if (id & saa7164_tvnorms[i].id)
197			break;
198	}
199	if (i == ARRAY_SIZE(saa7164_tvnorms))
200		return -EINVAL;
201
202	port->encodernorm = saa7164_tvnorms[i];
203	port->std = id;
204
205	/* Update the audio decoder while is not running in
206	 * auto detect mode.
207	 */
208	saa7164_api_set_audio_std(port);
209
210	dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)id);
211
212	return 0;
213}
214
215static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
216{
217	struct saa7164_encoder_fh *fh = file->private_data;
218	struct saa7164_port *port = fh->port;
219
220	*id = port->std;
221	return 0;
222}
223
224static int vidioc_enum_input(struct file *file, void *priv,
225	struct v4l2_input *i)
226{
227	int n;
228
229	char *inputs[] = { "tuner", "composite", "svideo", "aux",
230		"composite 2", "svideo 2", "aux 2" };
231
232	if (i->index >= 7)
233		return -EINVAL;
234
235	strcpy(i->name, inputs[i->index]);
236
237	if (i->index == 0)
238		i->type = V4L2_INPUT_TYPE_TUNER;
239	else
240		i->type  = V4L2_INPUT_TYPE_CAMERA;
241
242	for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
243		i->std |= saa7164_tvnorms[n].id;
244
245	return 0;
246}
247
248static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
249{
250	struct saa7164_vbi_fh *fh = file->private_data;
251	struct saa7164_port *port = fh->port;
252	struct saa7164_dev *dev = port->dev;
253
254	if (saa7164_api_get_videomux(port) != SAA_OK)
255		return -EIO;
256
257	*i = (port->mux_input - 1);
258
259	dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i);
260
261	return 0;
262}
263
264static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
265{
266	struct saa7164_vbi_fh *fh = file->private_data;
267	struct saa7164_port *port = fh->port;
268	struct saa7164_dev *dev = port->dev;
269
270	dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i);
271
272	if (i >= 7)
273		return -EINVAL;
274
275	port->mux_input = i + 1;
276
277	if (saa7164_api_set_videomux(port) != SAA_OK)
278		return -EIO;
279
280	return 0;
281}
282
283static int vidioc_g_tuner(struct file *file, void *priv,
284	struct v4l2_tuner *t)
285{
286	struct saa7164_vbi_fh *fh = file->private_data;
287	struct saa7164_port *port = fh->port;
288	struct saa7164_dev *dev = port->dev;
289
290	if (0 != t->index)
291		return -EINVAL;
292
293	strcpy(t->name, "tuner");
294	t->type = V4L2_TUNER_ANALOG_TV;
295	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
296
297	dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
298
299	return 0;
300}
301
302static int vidioc_s_tuner(struct file *file, void *priv,
303	const struct v4l2_tuner *t)
304{
305	/* Update the A/V core */
306	return 0;
307}
308
309static int vidioc_g_frequency(struct file *file, void *priv,
310	struct v4l2_frequency *f)
311{
312	struct saa7164_vbi_fh *fh = file->private_data;
313	struct saa7164_port *port = fh->port;
314
315	f->type = V4L2_TUNER_ANALOG_TV;
316	f->frequency = port->freq;
317
318	return 0;
319}
320
321static int vidioc_s_frequency(struct file *file, void *priv,
322	const struct v4l2_frequency *f)
323{
324	struct saa7164_vbi_fh *fh = file->private_data;
325	struct saa7164_port *port = fh->port;
326	struct saa7164_dev *dev = port->dev;
327	struct saa7164_port *tsport;
328	struct dvb_frontend *fe;
329
330	/* TODO: Pull this for the std */
331	struct analog_parameters params = {
332		.mode      = V4L2_TUNER_ANALOG_TV,
333		.audmode   = V4L2_TUNER_MODE_STEREO,
334		.std       = port->encodernorm.id,
335		.frequency = f->frequency
336	};
337
338	/* Stop the encoder */
339	dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__,
340		f->frequency, f->tuner);
341
342	if (f->tuner != 0)
343		return -EINVAL;
344
345	if (f->type != V4L2_TUNER_ANALOG_TV)
346		return -EINVAL;
347
348	port->freq = f->frequency;
349
350	/* Update the hardware */
351	if (port->nr == SAA7164_PORT_VBI1)
352		tsport = &dev->ports[SAA7164_PORT_TS1];
353	else
354	if (port->nr == SAA7164_PORT_VBI2)
355		tsport = &dev->ports[SAA7164_PORT_TS2];
356	else
357		BUG();
358
359	fe = tsport->dvb.frontend;
360
361	if (fe && fe->ops.tuner_ops.set_analog_params)
362		fe->ops.tuner_ops.set_analog_params(fe, &params);
363	else
364		printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
365
366	saa7164_vbi_initialize(port);
367
368	return 0;
369}
370
371static int vidioc_g_ctrl(struct file *file, void *priv,
372	struct v4l2_control *ctl)
373{
374	struct saa7164_vbi_fh *fh = file->private_data;
375	struct saa7164_port *port = fh->port;
376	struct saa7164_dev *dev = port->dev;
377
378	dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
379		ctl->id, ctl->value);
380
381	switch (ctl->id) {
382	case V4L2_CID_BRIGHTNESS:
383		ctl->value = port->ctl_brightness;
384		break;
385	case V4L2_CID_CONTRAST:
386		ctl->value = port->ctl_contrast;
387		break;
388	case V4L2_CID_SATURATION:
389		ctl->value = port->ctl_saturation;
390		break;
391	case V4L2_CID_HUE:
392		ctl->value = port->ctl_hue;
393		break;
394	case V4L2_CID_SHARPNESS:
395		ctl->value = port->ctl_sharpness;
396		break;
397	case V4L2_CID_AUDIO_VOLUME:
398		ctl->value = port->ctl_volume;
399		break;
400	default:
401		return -EINVAL;
402	}
403
404	return 0;
405}
406
407static int vidioc_s_ctrl(struct file *file, void *priv,
408	struct v4l2_control *ctl)
409{
410	struct saa7164_vbi_fh *fh = file->private_data;
411	struct saa7164_port *port = fh->port;
412	struct saa7164_dev *dev = port->dev;
413	int ret = 0;
414
415	dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
416		ctl->id, ctl->value);
417
418	switch (ctl->id) {
419	case V4L2_CID_BRIGHTNESS:
420		if ((ctl->value >= 0) && (ctl->value <= 255)) {
421			port->ctl_brightness = ctl->value;
422			saa7164_api_set_usercontrol(port,
423				PU_BRIGHTNESS_CONTROL);
424		} else
425			ret = -EINVAL;
426		break;
427	case V4L2_CID_CONTRAST:
428		if ((ctl->value >= 0) && (ctl->value <= 255)) {
429			port->ctl_contrast = ctl->value;
430			saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
431		} else
432			ret = -EINVAL;
433		break;
434	case V4L2_CID_SATURATION:
435		if ((ctl->value >= 0) && (ctl->value <= 255)) {
436			port->ctl_saturation = ctl->value;
437			saa7164_api_set_usercontrol(port,
438				PU_SATURATION_CONTROL);
439		} else
440			ret = -EINVAL;
441		break;
442	case V4L2_CID_HUE:
443		if ((ctl->value >= 0) && (ctl->value <= 255)) {
444			port->ctl_hue = ctl->value;
445			saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
446		} else
447			ret = -EINVAL;
448		break;
449	case V4L2_CID_SHARPNESS:
450		if ((ctl->value >= 0) && (ctl->value <= 255)) {
451			port->ctl_sharpness = ctl->value;
452			saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
453		} else
454			ret = -EINVAL;
455		break;
456	case V4L2_CID_AUDIO_VOLUME:
457		if ((ctl->value >= -83) && (ctl->value <= 24)) {
458			port->ctl_volume = ctl->value;
459			saa7164_api_set_audio_volume(port, port->ctl_volume);
460		} else
461			ret = -EINVAL;
462		break;
463	default:
464		ret = -EINVAL;
465	}
466
467	return ret;
468}
469
470static int saa7164_get_ctrl(struct saa7164_port *port,
471	struct v4l2_ext_control *ctrl)
472{
473	struct saa7164_vbi_params *params = &port->vbi_params;
474
475	switch (ctrl->id) {
476	case V4L2_CID_MPEG_STREAM_TYPE:
477		ctrl->value = params->stream_type;
478		break;
479	case V4L2_CID_MPEG_AUDIO_MUTE:
480		ctrl->value = params->ctl_mute;
481		break;
482	case V4L2_CID_MPEG_VIDEO_ASPECT:
483		ctrl->value = params->ctl_aspect;
484		break;
485	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
486		ctrl->value = params->refdist;
487		break;
488	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
489		ctrl->value = params->gop_size;
490		break;
491	default:
492		return -EINVAL;
493	}
494	return 0;
495}
496
497static int vidioc_g_ext_ctrls(struct file *file, void *priv,
498	struct v4l2_ext_controls *ctrls)
499{
500	struct saa7164_vbi_fh *fh = file->private_data;
501	struct saa7164_port *port = fh->port;
502	int i, err = 0;
503
504	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
505		for (i = 0; i < ctrls->count; i++) {
506			struct v4l2_ext_control *ctrl = ctrls->controls + i;
507
508			err = saa7164_get_ctrl(port, ctrl);
509			if (err) {
510				ctrls->error_idx = i;
511				break;
512			}
513		}
514		return err;
515
516	}
517
518	return -EINVAL;
519}
520
521static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
522{
523	int ret = -EINVAL;
524
525	switch (ctrl->id) {
526	case V4L2_CID_MPEG_STREAM_TYPE:
527		if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
528			(ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
529			ret = 0;
530		break;
531	case V4L2_CID_MPEG_AUDIO_MUTE:
532		if ((ctrl->value >= 0) &&
533			(ctrl->value <= 1))
534			ret = 0;
535		break;
536	case V4L2_CID_MPEG_VIDEO_ASPECT:
537		if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
538			(ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
539			ret = 0;
540		break;
541	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
542		if ((ctrl->value >= 0) &&
543			(ctrl->value <= 255))
544			ret = 0;
545		break;
546	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
547		if ((ctrl->value >= 1) &&
548			(ctrl->value <= 3))
549			ret = 0;
550		break;
551	default:
552		ret = -EINVAL;
553	}
554
555	return ret;
556}
557
558static int vidioc_try_ext_ctrls(struct file *file, void *priv,
559	struct v4l2_ext_controls *ctrls)
560{
561	int i, err = 0;
562
563	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
564		for (i = 0; i < ctrls->count; i++) {
565			struct v4l2_ext_control *ctrl = ctrls->controls + i;
566
567			err = saa7164_try_ctrl(ctrl, 0);
568			if (err) {
569				ctrls->error_idx = i;
570				break;
571			}
572		}
573		return err;
574	}
575
576	return -EINVAL;
577}
578
579static int saa7164_set_ctrl(struct saa7164_port *port,
580	struct v4l2_ext_control *ctrl)
581{
582	struct saa7164_vbi_params *params = &port->vbi_params;
583	int ret = 0;
584
585	switch (ctrl->id) {
586	case V4L2_CID_MPEG_STREAM_TYPE:
587		params->stream_type = ctrl->value;
588		break;
589	case V4L2_CID_MPEG_AUDIO_MUTE:
590		params->ctl_mute = ctrl->value;
591		ret = saa7164_api_audio_mute(port, params->ctl_mute);
592		if (ret != SAA_OK) {
593			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
594				ret);
595			ret = -EIO;
596		}
597		break;
598	case V4L2_CID_MPEG_VIDEO_ASPECT:
599		params->ctl_aspect = ctrl->value;
600		ret = saa7164_api_set_aspect_ratio(port);
601		if (ret != SAA_OK) {
602			printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
603				ret);
604			ret = -EIO;
605		}
606		break;
607	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
608		params->refdist = ctrl->value;
609		break;
610	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
611		params->gop_size = ctrl->value;
612		break;
613	default:
614		return -EINVAL;
615	}
616
617	/* TODO: Update the hardware */
618
619	return ret;
620}
621
622static int vidioc_s_ext_ctrls(struct file *file, void *priv,
623	struct v4l2_ext_controls *ctrls)
624{
625	struct saa7164_vbi_fh *fh = file->private_data;
626	struct saa7164_port *port = fh->port;
627	int i, err = 0;
628
629	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
630		for (i = 0; i < ctrls->count; i++) {
631			struct v4l2_ext_control *ctrl = ctrls->controls + i;
632
633			err = saa7164_try_ctrl(ctrl, 0);
634			if (err) {
635				ctrls->error_idx = i;
636				break;
637			}
638			err = saa7164_set_ctrl(port, ctrl);
639			if (err) {
640				ctrls->error_idx = i;
641				break;
642			}
643		}
644		return err;
645
646	}
647
648	return -EINVAL;
649}
650
651static int vidioc_querycap(struct file *file, void  *priv,
652	struct v4l2_capability *cap)
653{
654	struct saa7164_vbi_fh *fh = file->private_data;
655	struct saa7164_port *port = fh->port;
656	struct saa7164_dev *dev = port->dev;
657
658	strcpy(cap->driver, dev->name);
659	strlcpy(cap->card, saa7164_boards[dev->board].name,
660		sizeof(cap->card));
661	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
662
663	cap->capabilities =
664		V4L2_CAP_VBI_CAPTURE |
665		V4L2_CAP_READWRITE     |
666		0;
667
668	cap->capabilities |= V4L2_CAP_TUNER;
669	cap->version = 0;
670
671	return 0;
672}
673
674static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
675	struct v4l2_fmtdesc *f)
676{
677	if (f->index != 0)
678		return -EINVAL;
679
680	strlcpy(f->description, "VBI", sizeof(f->description));
681	f->pixelformat = V4L2_PIX_FMT_MPEG;
682
683	return 0;
684}
685
686static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
687				struct v4l2_format *f)
688{
689	struct saa7164_vbi_fh *fh = file->private_data;
690	struct saa7164_port *port = fh->port;
691	struct saa7164_dev *dev = port->dev;
692
693	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
694	f->fmt.pix.bytesperline = 0;
695	f->fmt.pix.sizeimage    =
696		port->ts_packet_size * port->ts_packet_count;
697	f->fmt.pix.colorspace   = 0;
698	f->fmt.pix.width        = port->width;
699	f->fmt.pix.height       = port->height;
700
701	dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n",
702		port->width, port->height);
703
704	return 0;
705}
706
707static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
708				struct v4l2_format *f)
709{
710	struct saa7164_vbi_fh *fh = file->private_data;
711	struct saa7164_port *port = fh->port;
712	struct saa7164_dev *dev = port->dev;
713
714	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
715	f->fmt.pix.bytesperline = 0;
716	f->fmt.pix.sizeimage    =
717		port->ts_packet_size * port->ts_packet_count;
718	f->fmt.pix.colorspace   = 0;
719	dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
720		port->width, port->height);
721	return 0;
722}
723
724static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
725				struct v4l2_format *f)
726{
727	struct saa7164_vbi_fh *fh = file->private_data;
728	struct saa7164_port *port = fh->port;
729	struct saa7164_dev *dev = port->dev;
730
731	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
732	f->fmt.pix.bytesperline = 0;
733	f->fmt.pix.sizeimage    =
734		port->ts_packet_size * port->ts_packet_count;
735	f->fmt.pix.colorspace   = 0;
736
737	dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
738		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
739
740	return 0;
741}
742
743static int fill_queryctrl(struct saa7164_vbi_params *params,
744	struct v4l2_queryctrl *c)
745{
746	switch (c->id) {
747	case V4L2_CID_BRIGHTNESS:
748		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
749	case V4L2_CID_CONTRAST:
750		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
751	case V4L2_CID_SATURATION:
752		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
753	case V4L2_CID_HUE:
754		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
755	case V4L2_CID_SHARPNESS:
756		return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
757	case V4L2_CID_MPEG_AUDIO_MUTE:
758		return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
759	case V4L2_CID_AUDIO_VOLUME:
760		return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
761	case V4L2_CID_MPEG_STREAM_TYPE:
762		return v4l2_ctrl_query_fill(c,
763			V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
764			V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
765			1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
766	case V4L2_CID_MPEG_VIDEO_ASPECT:
767		return v4l2_ctrl_query_fill(c,
768			V4L2_MPEG_VIDEO_ASPECT_1x1,
769			V4L2_MPEG_VIDEO_ASPECT_221x100,
770			1, V4L2_MPEG_VIDEO_ASPECT_4x3);
771	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
772		return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
773	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
774		return v4l2_ctrl_query_fill(c,
775			1, 3, 1, 1);
776	default:
777		return -EINVAL;
778	}
779}
780
781static int vidioc_queryctrl(struct file *file, void *priv,
782	struct v4l2_queryctrl *c)
783{
784	struct saa7164_vbi_fh *fh = priv;
785	struct saa7164_port *port = fh->port;
786	int i, next;
787	u32 id = c->id;
788
789	memset(c, 0, sizeof(*c));
790
791	next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
792	c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
793
794	for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
795		if (next) {
796			if (c->id < saa7164_v4l2_ctrls[i])
797				c->id = saa7164_v4l2_ctrls[i];
798			else
799				continue;
800		}
801
802		if (c->id == saa7164_v4l2_ctrls[i])
803			return fill_queryctrl(&port->vbi_params, c);
804
805		if (c->id < saa7164_v4l2_ctrls[i])
806			break;
807	}
808
809	return -EINVAL;
810}
811
812static int saa7164_vbi_stop_port(struct saa7164_port *port)
813{
814	struct saa7164_dev *dev = port->dev;
815	int ret;
816
817	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
818	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
819		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
820			__func__, ret);
821		ret = -EIO;
822	} else {
823		dprintk(DBGLVL_VBI, "%s()    Stopped\n", __func__);
824		ret = 0;
825	}
826
827	return ret;
828}
829
830static int saa7164_vbi_acquire_port(struct saa7164_port *port)
831{
832	struct saa7164_dev *dev = port->dev;
833	int ret;
834
835	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
836	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
837		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
838			__func__, ret);
839		ret = -EIO;
840	} else {
841		dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);
842		ret = 0;
843	}
844
845	return ret;
846}
847
848static int saa7164_vbi_pause_port(struct saa7164_port *port)
849{
850	struct saa7164_dev *dev = port->dev;
851	int ret;
852
853	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
854	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
855		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
856			__func__, ret);
857		ret = -EIO;
858	} else {
859		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
860		ret = 0;
861	}
862
863	return ret;
864}
865
866/* Firmware is very windows centric, meaning you have to transition
867 * the part through AVStream / KS Windows stages, forwards or backwards.
868 * States are: stopped, acquired (h/w), paused, started.
869 * We have to leave here will all of the soft buffers on the free list,
870 * else the cfg_post() func won't have soft buffers to correctly configure.
871 */
872static int saa7164_vbi_stop_streaming(struct saa7164_port *port)
873{
874	struct saa7164_dev *dev = port->dev;
875	struct saa7164_buffer *buf;
876	struct saa7164_user_buffer *ubuf;
877	struct list_head *c, *n;
878	int ret;
879
880	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
881
882	ret = saa7164_vbi_pause_port(port);
883	ret = saa7164_vbi_acquire_port(port);
884	ret = saa7164_vbi_stop_port(port);
885
886	dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__,
887		port->nr);
888
889	/* Reset the state of any allocated buffer resources */
890	mutex_lock(&port->dmaqueue_lock);
891
892	/* Reset the hard and soft buffer state */
893	list_for_each_safe(c, n, &port->dmaqueue.list) {
894		buf = list_entry(c, struct saa7164_buffer, list);
895		buf->flags = SAA7164_BUFFER_FREE;
896		buf->pos = 0;
897	}
898
899	list_for_each_safe(c, n, &port->list_buf_used.list) {
900		ubuf = list_entry(c, struct saa7164_user_buffer, list);
901		ubuf->pos = 0;
902		list_move_tail(&ubuf->list, &port->list_buf_free.list);
903	}
904
905	mutex_unlock(&port->dmaqueue_lock);
906
907	/* Free any allocated resources */
908	saa7164_vbi_buffers_dealloc(port);
909
910	dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr);
911
912	return ret;
913}
914
915static int saa7164_vbi_start_streaming(struct saa7164_port *port)
916{
917	struct saa7164_dev *dev = port->dev;
918	int result, ret = 0;
919
920	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
921
922	port->done_first_interrupt = 0;
923
924	/* allocate all of the PCIe DMA buffer resources on the fly,
925	 * allowing switching between TS and PS payloads without
926	 * requiring a complete driver reload.
927	 */
928	saa7164_vbi_buffers_alloc(port);
929
930	/* Configure the encoder with any cache values */
931#if 0
932	saa7164_api_set_encoder(port);
933	saa7164_api_get_encoder(port);
934#endif
935
936	/* Place the empty buffers on the hardware */
937	saa7164_buffer_cfg_port(port);
938
939	/* Negotiate format */
940	if (saa7164_api_set_vbi_format(port) != SAA_OK) {
941		printk(KERN_ERR "%s() No supported VBI format\n", __func__);
942		ret = -EIO;
943		goto out;
944	}
945
946	/* Acquire the hardware */
947	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
948	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
949		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
950			__func__, result);
951
952		ret = -EIO;
953		goto out;
954	} else
955		dprintk(DBGLVL_VBI, "%s()   Acquired\n", __func__);
956
957	/* Pause the hardware */
958	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
959	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
960		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
961				__func__, result);
962
963		/* Stop the hardware, regardless */
964		result = saa7164_vbi_stop_port(port);
965		if (result != SAA_OK) {
966			printk(KERN_ERR "%s() pause/forced stop transition "
967				"failed, res = 0x%x\n", __func__, result);
968		}
969
970		ret = -EIO;
971		goto out;
972	} else
973		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
974
975	/* Start the hardware */
976	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
977	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
978		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
979				__func__, result);
980
981		/* Stop the hardware, regardless */
982		result = saa7164_vbi_acquire_port(port);
983		result = saa7164_vbi_stop_port(port);
984		if (result != SAA_OK) {
985			printk(KERN_ERR "%s() run/forced stop transition "
986				"failed, res = 0x%x\n", __func__, result);
987		}
988
989		ret = -EIO;
990	} else
991		dprintk(DBGLVL_VBI, "%s()   Running\n", __func__);
992
993out:
994	return ret;
995}
996
997static int saa7164_vbi_fmt(struct file *file, void *priv,
998			   struct v4l2_format *f)
999{
1000	/* ntsc */
1001	f->fmt.vbi.samples_per_line = 1600;
1002	f->fmt.vbi.samples_per_line = 1440;
1003	f->fmt.vbi.sampling_rate = 27000000;
1004	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
1005	f->fmt.vbi.offset = 0;
1006	f->fmt.vbi.flags = 0;
1007	f->fmt.vbi.start[0] = 10;
1008	f->fmt.vbi.count[0] = 18;
1009	f->fmt.vbi.start[1] = 263 + 10 + 1;
1010	f->fmt.vbi.count[1] = 18;
1011	return 0;
1012}
1013
1014static int fops_open(struct file *file)
1015{
1016	struct saa7164_dev *dev;
1017	struct saa7164_port *port;
1018	struct saa7164_vbi_fh *fh;
1019
1020	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
1021	if (!port)
1022		return -ENODEV;
1023
1024	dev = port->dev;
1025
1026	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1027
1028	/* allocate + initialize per filehandle data */
1029	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
1030	if (NULL == fh)
1031		return -ENOMEM;
1032
1033	file->private_data = fh;
1034	fh->port = port;
1035
1036	return 0;
1037}
1038
1039static int fops_release(struct file *file)
1040{
1041	struct saa7164_vbi_fh *fh = file->private_data;
1042	struct saa7164_port *port = fh->port;
1043	struct saa7164_dev *dev = port->dev;
1044
1045	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1046
1047	/* Shut device down on last close */
1048	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
1049		if (atomic_dec_return(&port->v4l_reader_count) == 0) {
1050			/* stop vbi capture then cancel buffers */
1051			saa7164_vbi_stop_streaming(port);
1052		}
1053	}
1054
1055	file->private_data = NULL;
1056	kfree(fh);
1057
1058	return 0;
1059}
1060
1061static struct
1062saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
1063{
1064	struct saa7164_user_buffer *ubuf = NULL;
1065	struct saa7164_dev *dev = port->dev;
1066	u32 crc;
1067
1068	mutex_lock(&port->dmaqueue_lock);
1069	if (!list_empty(&port->list_buf_used.list)) {
1070		ubuf = list_first_entry(&port->list_buf_used.list,
1071			struct saa7164_user_buffer, list);
1072
1073		if (crc_checking) {
1074			crc = crc32(0, ubuf->data, ubuf->actual_size);
1075			if (crc != ubuf->crc) {
1076				printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
1077					__func__,
1078					ubuf, ubuf->crc, crc);
1079			}
1080		}
1081
1082	}
1083	mutex_unlock(&port->dmaqueue_lock);
1084
1085	dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf);
1086
1087	return ubuf;
1088}
1089
1090static ssize_t fops_read(struct file *file, char __user *buffer,
1091	size_t count, loff_t *pos)
1092{
1093	struct saa7164_vbi_fh *fh = file->private_data;
1094	struct saa7164_port *port = fh->port;
1095	struct saa7164_user_buffer *ubuf = NULL;
1096	struct saa7164_dev *dev = port->dev;
1097	int ret = 0;
1098	int rem, cnt;
1099	u8 *p;
1100
1101	port->last_read_msecs_diff = port->last_read_msecs;
1102	port->last_read_msecs = jiffies_to_msecs(jiffies);
1103	port->last_read_msecs_diff = port->last_read_msecs -
1104		port->last_read_msecs_diff;
1105
1106	saa7164_histogram_update(&port->read_interval,
1107		port->last_read_msecs_diff);
1108
1109	if (*pos) {
1110		printk(KERN_ERR "%s() ESPIPE\n", __func__);
1111		return -ESPIPE;
1112	}
1113
1114	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
1115		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
1116
1117			if (saa7164_vbi_initialize(port) < 0) {
1118				printk(KERN_ERR "%s() EINVAL\n", __func__);
1119				return -EINVAL;
1120			}
1121
1122			saa7164_vbi_start_streaming(port);
1123			msleep(200);
1124		}
1125	}
1126
1127	/* blocking wait for buffer */
1128	if ((file->f_flags & O_NONBLOCK) == 0) {
1129		if (wait_event_interruptible(port->wait_read,
1130			saa7164_vbi_next_buf(port))) {
1131				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
1132				return -ERESTARTSYS;
1133		}
1134	}
1135
1136	/* Pull the first buffer from the used list */
1137	ubuf = saa7164_vbi_next_buf(port);
1138
1139	while ((count > 0) && ubuf) {
1140
1141		/* set remaining bytes to copy */
1142		rem = ubuf->actual_size - ubuf->pos;
1143		cnt = rem > count ? count : rem;
1144
1145		p = ubuf->data + ubuf->pos;
1146
1147		dprintk(DBGLVL_VBI,
1148			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
1149			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);
1150
1151		if (copy_to_user(buffer, p, cnt)) {
1152			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
1153			if (!ret) {
1154				printk(KERN_ERR "%s() EFAULT\n", __func__);
1155				ret = -EFAULT;
1156			}
1157			goto err;
1158		}
1159
1160		ubuf->pos += cnt;
1161		count -= cnt;
1162		buffer += cnt;
1163		ret += cnt;
1164
1165		if (ubuf->pos > ubuf->actual_size)
1166			printk(KERN_ERR "read() pos > actual, huh?\n");
1167
1168		if (ubuf->pos == ubuf->actual_size) {
1169
1170			/* finished with current buffer, take next buffer */
1171
1172			/* Requeue the buffer on the free list */
1173			ubuf->pos = 0;
1174
1175			mutex_lock(&port->dmaqueue_lock);
1176			list_move_tail(&ubuf->list, &port->list_buf_free.list);
1177			mutex_unlock(&port->dmaqueue_lock);
1178
1179			/* Dequeue next */
1180			if ((file->f_flags & O_NONBLOCK) == 0) {
1181				if (wait_event_interruptible(port->wait_read,
1182					saa7164_vbi_next_buf(port))) {
1183						break;
1184				}
1185			}
1186			ubuf = saa7164_vbi_next_buf(port);
1187		}
1188	}
1189err:
1190	if (!ret && !ubuf) {
1191		printk(KERN_ERR "%s() EAGAIN\n", __func__);
1192		ret = -EAGAIN;
1193	}
1194
1195	return ret;
1196}
1197
1198static unsigned int fops_poll(struct file *file, poll_table *wait)
1199{
1200	struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
1201	struct saa7164_port *port = fh->port;
1202	unsigned int mask = 0;
1203
1204	port->last_poll_msecs_diff = port->last_poll_msecs;
1205	port->last_poll_msecs = jiffies_to_msecs(jiffies);
1206	port->last_poll_msecs_diff = port->last_poll_msecs -
1207		port->last_poll_msecs_diff;
1208
1209	saa7164_histogram_update(&port->poll_interval,
1210		port->last_poll_msecs_diff);
1211
1212	if (!video_is_registered(port->v4l_device))
1213		return -EIO;
1214
1215	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
1216		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
1217			if (saa7164_vbi_initialize(port) < 0)
1218				return -EINVAL;
1219			saa7164_vbi_start_streaming(port);
1220			msleep(200);
1221		}
1222	}
1223
1224	/* blocking wait for buffer */
1225	if ((file->f_flags & O_NONBLOCK) == 0) {
1226		if (wait_event_interruptible(port->wait_read,
1227			saa7164_vbi_next_buf(port))) {
1228				return -ERESTARTSYS;
1229		}
1230	}
1231
1232	/* Pull the first buffer from the used list */
1233	if (!list_empty(&port->list_buf_used.list))
1234		mask |= POLLIN | POLLRDNORM;
1235
1236	return mask;
1237}
1238static const struct v4l2_file_operations vbi_fops = {
1239	.owner		= THIS_MODULE,
1240	.open		= fops_open,
1241	.release	= fops_release,
1242	.read		= fops_read,
1243	.poll		= fops_poll,
1244	.unlocked_ioctl	= video_ioctl2,
1245};
1246
1247static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
1248	.vidioc_s_std		 = vidioc_s_std,
1249	.vidioc_g_std		 = vidioc_g_std,
1250	.vidioc_enum_input	 = vidioc_enum_input,
1251	.vidioc_g_input		 = vidioc_g_input,
1252	.vidioc_s_input		 = vidioc_s_input,
1253	.vidioc_g_tuner		 = vidioc_g_tuner,
1254	.vidioc_s_tuner		 = vidioc_s_tuner,
1255	.vidioc_g_frequency	 = vidioc_g_frequency,
1256	.vidioc_s_frequency	 = vidioc_s_frequency,
1257	.vidioc_s_ctrl		 = vidioc_s_ctrl,
1258	.vidioc_g_ctrl		 = vidioc_g_ctrl,
1259	.vidioc_querycap	 = vidioc_querycap,
1260	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1261	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
1262	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
1263	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
1264	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
1265	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
1266	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
1267	.vidioc_queryctrl	 = vidioc_queryctrl,
1268	.vidioc_g_fmt_vbi_cap	 = saa7164_vbi_fmt,
1269	.vidioc_try_fmt_vbi_cap	 = saa7164_vbi_fmt,
1270	.vidioc_s_fmt_vbi_cap	 = saa7164_vbi_fmt,
1271};
1272
1273static struct video_device saa7164_vbi_template = {
1274	.name          = "saa7164",
1275	.fops          = &vbi_fops,
1276	.ioctl_ops     = &vbi_ioctl_ops,
1277	.minor         = -1,
1278	.tvnorms       = SAA7164_NORMS,
1279};
1280
1281static struct video_device *saa7164_vbi_alloc(
1282	struct saa7164_port *port,
1283	struct pci_dev *pci,
1284	struct video_device *template,
1285	char *type)
1286{
1287	struct video_device *vfd;
1288	struct saa7164_dev *dev = port->dev;
1289
1290	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1291
1292	vfd = video_device_alloc();
1293	if (NULL == vfd)
1294		return NULL;
1295
1296	*vfd = *template;
1297	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
1298		type, saa7164_boards[dev->board].name);
1299
1300	vfd->v4l2_dev  = &dev->v4l2_dev;
1301	vfd->release = video_device_release;
1302	return vfd;
1303}
1304
1305int saa7164_vbi_register(struct saa7164_port *port)
1306{
1307	struct saa7164_dev *dev = port->dev;
1308	int result = -ENODEV;
1309
1310	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1311
1312	if (port->type != SAA7164_MPEG_VBI)
1313		BUG();
1314
1315	/* Sanity check that the PCI configuration space is active */
1316	if (port->hwcfg.BARLocation == 0) {
1317		printk(KERN_ERR "%s() failed "
1318		       "(errno = %d), NO PCI configuration\n",
1319			__func__, result);
1320		result = -ENOMEM;
1321		goto failed;
1322	}
1323
1324	/* Establish VBI defaults here */
1325
1326	/* Allocate and register the video device node */
1327	port->v4l_device = saa7164_vbi_alloc(port,
1328		dev->pci, &saa7164_vbi_template, "vbi");
1329
1330	if (!port->v4l_device) {
1331		printk(KERN_INFO "%s: can't allocate vbi device\n",
1332			dev->name);
1333		result = -ENOMEM;
1334		goto failed;
1335	}
1336
1337	port->std = V4L2_STD_NTSC_M;
1338	video_set_drvdata(port->v4l_device, port);
1339	result = video_register_device(port->v4l_device,
1340		VFL_TYPE_VBI, -1);
1341	if (result < 0) {
1342		printk(KERN_INFO "%s: can't register vbi device\n",
1343			dev->name);
1344		/* TODO: We're going to leak here if we don't dealloc
1345		 The buffers above. The unreg function can't deal wit it.
1346		*/
1347		goto failed;
1348	}
1349
1350	printk(KERN_INFO "%s: registered device vbi%d [vbi]\n",
1351		dev->name, port->v4l_device->num);
1352
1353	/* Configure the hardware defaults */
1354
1355	result = 0;
1356failed:
1357	return result;
1358}
1359
1360void saa7164_vbi_unregister(struct saa7164_port *port)
1361{
1362	struct saa7164_dev *dev = port->dev;
1363
1364	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
1365
1366	if (port->type != SAA7164_MPEG_VBI)
1367		BUG();
1368
1369	if (port->v4l_device) {
1370		if (port->v4l_device->minor != -1)
1371			video_unregister_device(port->v4l_device);
1372		else
1373			video_device_release(port->v4l_device);
1374
1375		port->v4l_device = NULL;
1376	}
1377
1378}
1379