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->device_caps =
664		V4L2_CAP_VBI_CAPTURE |
665		V4L2_CAP_READWRITE |
666		V4L2_CAP_TUNER;
667
668	cap->capabilities = cap->device_caps |
669		V4L2_CAP_VIDEO_CAPTURE |
670		V4L2_CAP_DEVICE_CAPS;
671
672	return 0;
673}
674
675static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
676	struct v4l2_fmtdesc *f)
677{
678	if (f->index != 0)
679		return -EINVAL;
680
681	strlcpy(f->description, "VBI", sizeof(f->description));
682	f->pixelformat = V4L2_PIX_FMT_MPEG;
683
684	return 0;
685}
686
687static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
688				struct v4l2_format *f)
689{
690	struct saa7164_vbi_fh *fh = file->private_data;
691	struct saa7164_port *port = fh->port;
692	struct saa7164_dev *dev = port->dev;
693
694	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
695	f->fmt.pix.bytesperline = 0;
696	f->fmt.pix.sizeimage    =
697		port->ts_packet_size * port->ts_packet_count;
698	f->fmt.pix.colorspace   = 0;
699	f->fmt.pix.width        = port->width;
700	f->fmt.pix.height       = port->height;
701
702	dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n",
703		port->width, port->height);
704
705	return 0;
706}
707
708static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
709				struct v4l2_format *f)
710{
711	struct saa7164_vbi_fh *fh = file->private_data;
712	struct saa7164_port *port = fh->port;
713	struct saa7164_dev *dev = port->dev;
714
715	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
716	f->fmt.pix.bytesperline = 0;
717	f->fmt.pix.sizeimage    =
718		port->ts_packet_size * port->ts_packet_count;
719	f->fmt.pix.colorspace   = 0;
720	dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
721		port->width, port->height);
722	return 0;
723}
724
725static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
726				struct v4l2_format *f)
727{
728	struct saa7164_vbi_fh *fh = file->private_data;
729	struct saa7164_port *port = fh->port;
730	struct saa7164_dev *dev = port->dev;
731
732	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
733	f->fmt.pix.bytesperline = 0;
734	f->fmt.pix.sizeimage    =
735		port->ts_packet_size * port->ts_packet_count;
736	f->fmt.pix.colorspace   = 0;
737
738	dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
739		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
740
741	return 0;
742}
743
744static int fill_queryctrl(struct saa7164_vbi_params *params,
745	struct v4l2_queryctrl *c)
746{
747	switch (c->id) {
748	case V4L2_CID_BRIGHTNESS:
749		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
750	case V4L2_CID_CONTRAST:
751		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
752	case V4L2_CID_SATURATION:
753		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
754	case V4L2_CID_HUE:
755		return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
756	case V4L2_CID_SHARPNESS:
757		return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
758	case V4L2_CID_MPEG_AUDIO_MUTE:
759		return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
760	case V4L2_CID_AUDIO_VOLUME:
761		return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
762	case V4L2_CID_MPEG_STREAM_TYPE:
763		return v4l2_ctrl_query_fill(c,
764			V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
765			V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
766			1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
767	case V4L2_CID_MPEG_VIDEO_ASPECT:
768		return v4l2_ctrl_query_fill(c,
769			V4L2_MPEG_VIDEO_ASPECT_1x1,
770			V4L2_MPEG_VIDEO_ASPECT_221x100,
771			1, V4L2_MPEG_VIDEO_ASPECT_4x3);
772	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
773		return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
774	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
775		return v4l2_ctrl_query_fill(c,
776			1, 3, 1, 1);
777	default:
778		return -EINVAL;
779	}
780}
781
782static int vidioc_queryctrl(struct file *file, void *priv,
783	struct v4l2_queryctrl *c)
784{
785	struct saa7164_vbi_fh *fh = priv;
786	struct saa7164_port *port = fh->port;
787	int i, next;
788	u32 id = c->id;
789
790	memset(c, 0, sizeof(*c));
791
792	next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
793	c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
794
795	for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
796		if (next) {
797			if (c->id < saa7164_v4l2_ctrls[i])
798				c->id = saa7164_v4l2_ctrls[i];
799			else
800				continue;
801		}
802
803		if (c->id == saa7164_v4l2_ctrls[i])
804			return fill_queryctrl(&port->vbi_params, c);
805
806		if (c->id < saa7164_v4l2_ctrls[i])
807			break;
808	}
809
810	return -EINVAL;
811}
812
813static int saa7164_vbi_stop_port(struct saa7164_port *port)
814{
815	struct saa7164_dev *dev = port->dev;
816	int ret;
817
818	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
819	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
820		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
821			__func__, ret);
822		ret = -EIO;
823	} else {
824		dprintk(DBGLVL_VBI, "%s()    Stopped\n", __func__);
825		ret = 0;
826	}
827
828	return ret;
829}
830
831static int saa7164_vbi_acquire_port(struct saa7164_port *port)
832{
833	struct saa7164_dev *dev = port->dev;
834	int ret;
835
836	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
837	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
838		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
839			__func__, ret);
840		ret = -EIO;
841	} else {
842		dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);
843		ret = 0;
844	}
845
846	return ret;
847}
848
849static int saa7164_vbi_pause_port(struct saa7164_port *port)
850{
851	struct saa7164_dev *dev = port->dev;
852	int ret;
853
854	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
855	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
856		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
857			__func__, ret);
858		ret = -EIO;
859	} else {
860		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
861		ret = 0;
862	}
863
864	return ret;
865}
866
867/* Firmware is very windows centric, meaning you have to transition
868 * the part through AVStream / KS Windows stages, forwards or backwards.
869 * States are: stopped, acquired (h/w), paused, started.
870 * We have to leave here will all of the soft buffers on the free list,
871 * else the cfg_post() func won't have soft buffers to correctly configure.
872 */
873static int saa7164_vbi_stop_streaming(struct saa7164_port *port)
874{
875	struct saa7164_dev *dev = port->dev;
876	struct saa7164_buffer *buf;
877	struct saa7164_user_buffer *ubuf;
878	struct list_head *c, *n;
879	int ret;
880
881	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
882
883	ret = saa7164_vbi_pause_port(port);
884	ret = saa7164_vbi_acquire_port(port);
885	ret = saa7164_vbi_stop_port(port);
886
887	dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__,
888		port->nr);
889
890	/* Reset the state of any allocated buffer resources */
891	mutex_lock(&port->dmaqueue_lock);
892
893	/* Reset the hard and soft buffer state */
894	list_for_each_safe(c, n, &port->dmaqueue.list) {
895		buf = list_entry(c, struct saa7164_buffer, list);
896		buf->flags = SAA7164_BUFFER_FREE;
897		buf->pos = 0;
898	}
899
900	list_for_each_safe(c, n, &port->list_buf_used.list) {
901		ubuf = list_entry(c, struct saa7164_user_buffer, list);
902		ubuf->pos = 0;
903		list_move_tail(&ubuf->list, &port->list_buf_free.list);
904	}
905
906	mutex_unlock(&port->dmaqueue_lock);
907
908	/* Free any allocated resources */
909	saa7164_vbi_buffers_dealloc(port);
910
911	dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr);
912
913	return ret;
914}
915
916static int saa7164_vbi_start_streaming(struct saa7164_port *port)
917{
918	struct saa7164_dev *dev = port->dev;
919	int result, ret = 0;
920
921	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
922
923	port->done_first_interrupt = 0;
924
925	/* allocate all of the PCIe DMA buffer resources on the fly,
926	 * allowing switching between TS and PS payloads without
927	 * requiring a complete driver reload.
928	 */
929	saa7164_vbi_buffers_alloc(port);
930
931	/* Configure the encoder with any cache values */
932#if 0
933	saa7164_api_set_encoder(port);
934	saa7164_api_get_encoder(port);
935#endif
936
937	/* Place the empty buffers on the hardware */
938	saa7164_buffer_cfg_port(port);
939
940	/* Negotiate format */
941	if (saa7164_api_set_vbi_format(port) != SAA_OK) {
942		printk(KERN_ERR "%s() No supported VBI format\n", __func__);
943		ret = -EIO;
944		goto out;
945	}
946
947	/* Acquire the hardware */
948	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
949	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
950		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
951			__func__, result);
952
953		ret = -EIO;
954		goto out;
955	} else
956		dprintk(DBGLVL_VBI, "%s()   Acquired\n", __func__);
957
958	/* Pause the hardware */
959	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
960	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
961		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
962				__func__, result);
963
964		/* Stop the hardware, regardless */
965		result = saa7164_vbi_stop_port(port);
966		if (result != SAA_OK) {
967			printk(KERN_ERR "%s() pause/forced stop transition "
968				"failed, res = 0x%x\n", __func__, result);
969		}
970
971		ret = -EIO;
972		goto out;
973	} else
974		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);
975
976	/* Start the hardware */
977	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
978	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
979		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
980				__func__, result);
981
982		/* Stop the hardware, regardless */
983		result = saa7164_vbi_acquire_port(port);
984		result = saa7164_vbi_stop_port(port);
985		if (result != SAA_OK) {
986			printk(KERN_ERR "%s() run/forced stop transition "
987				"failed, res = 0x%x\n", __func__, result);
988		}
989
990		ret = -EIO;
991	} else
992		dprintk(DBGLVL_VBI, "%s()   Running\n", __func__);
993
994out:
995	return ret;
996}
997
998static int saa7164_vbi_fmt(struct file *file, void *priv,
999			   struct v4l2_format *f)
1000{
1001	/* ntsc */
1002	f->fmt.vbi.samples_per_line = 1600;
1003	f->fmt.vbi.samples_per_line = 1440;
1004	f->fmt.vbi.sampling_rate = 27000000;
1005	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
1006	f->fmt.vbi.offset = 0;
1007	f->fmt.vbi.flags = 0;
1008	f->fmt.vbi.start[0] = 10;
1009	f->fmt.vbi.count[0] = 18;
1010	f->fmt.vbi.start[1] = 263 + 10 + 1;
1011	f->fmt.vbi.count[1] = 18;
1012	return 0;
1013}
1014
1015static int fops_open(struct file *file)
1016{
1017	struct saa7164_dev *dev;
1018	struct saa7164_port *port;
1019	struct saa7164_vbi_fh *fh;
1020
1021	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
1022	if (!port)
1023		return -ENODEV;
1024
1025	dev = port->dev;
1026
1027	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1028
1029	/* allocate + initialize per filehandle data */
1030	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
1031	if (NULL == fh)
1032		return -ENOMEM;
1033
1034	file->private_data = fh;
1035	fh->port = port;
1036
1037	return 0;
1038}
1039
1040static int fops_release(struct file *file)
1041{
1042	struct saa7164_vbi_fh *fh = file->private_data;
1043	struct saa7164_port *port = fh->port;
1044	struct saa7164_dev *dev = port->dev;
1045
1046	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1047
1048	/* Shut device down on last close */
1049	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
1050		if (atomic_dec_return(&port->v4l_reader_count) == 0) {
1051			/* stop vbi capture then cancel buffers */
1052			saa7164_vbi_stop_streaming(port);
1053		}
1054	}
1055
1056	file->private_data = NULL;
1057	kfree(fh);
1058
1059	return 0;
1060}
1061
1062static struct
1063saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
1064{
1065	struct saa7164_user_buffer *ubuf = NULL;
1066	struct saa7164_dev *dev = port->dev;
1067	u32 crc;
1068
1069	mutex_lock(&port->dmaqueue_lock);
1070	if (!list_empty(&port->list_buf_used.list)) {
1071		ubuf = list_first_entry(&port->list_buf_used.list,
1072			struct saa7164_user_buffer, list);
1073
1074		if (crc_checking) {
1075			crc = crc32(0, ubuf->data, ubuf->actual_size);
1076			if (crc != ubuf->crc) {
1077				printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
1078					__func__,
1079					ubuf, ubuf->crc, crc);
1080			}
1081		}
1082
1083	}
1084	mutex_unlock(&port->dmaqueue_lock);
1085
1086	dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf);
1087
1088	return ubuf;
1089}
1090
1091static ssize_t fops_read(struct file *file, char __user *buffer,
1092	size_t count, loff_t *pos)
1093{
1094	struct saa7164_vbi_fh *fh = file->private_data;
1095	struct saa7164_port *port = fh->port;
1096	struct saa7164_user_buffer *ubuf = NULL;
1097	struct saa7164_dev *dev = port->dev;
1098	int ret = 0;
1099	int rem, cnt;
1100	u8 *p;
1101
1102	port->last_read_msecs_diff = port->last_read_msecs;
1103	port->last_read_msecs = jiffies_to_msecs(jiffies);
1104	port->last_read_msecs_diff = port->last_read_msecs -
1105		port->last_read_msecs_diff;
1106
1107	saa7164_histogram_update(&port->read_interval,
1108		port->last_read_msecs_diff);
1109
1110	if (*pos) {
1111		printk(KERN_ERR "%s() ESPIPE\n", __func__);
1112		return -ESPIPE;
1113	}
1114
1115	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
1116		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
1117
1118			if (saa7164_vbi_initialize(port) < 0) {
1119				printk(KERN_ERR "%s() EINVAL\n", __func__);
1120				return -EINVAL;
1121			}
1122
1123			saa7164_vbi_start_streaming(port);
1124			msleep(200);
1125		}
1126	}
1127
1128	/* blocking wait for buffer */
1129	if ((file->f_flags & O_NONBLOCK) == 0) {
1130		if (wait_event_interruptible(port->wait_read,
1131			saa7164_vbi_next_buf(port))) {
1132				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
1133				return -ERESTARTSYS;
1134		}
1135	}
1136
1137	/* Pull the first buffer from the used list */
1138	ubuf = saa7164_vbi_next_buf(port);
1139
1140	while ((count > 0) && ubuf) {
1141
1142		/* set remaining bytes to copy */
1143		rem = ubuf->actual_size - ubuf->pos;
1144		cnt = rem > count ? count : rem;
1145
1146		p = ubuf->data + ubuf->pos;
1147
1148		dprintk(DBGLVL_VBI,
1149			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
1150			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);
1151
1152		if (copy_to_user(buffer, p, cnt)) {
1153			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
1154			if (!ret) {
1155				printk(KERN_ERR "%s() EFAULT\n", __func__);
1156				ret = -EFAULT;
1157			}
1158			goto err;
1159		}
1160
1161		ubuf->pos += cnt;
1162		count -= cnt;
1163		buffer += cnt;
1164		ret += cnt;
1165
1166		if (ubuf->pos > ubuf->actual_size)
1167			printk(KERN_ERR "read() pos > actual, huh?\n");
1168
1169		if (ubuf->pos == ubuf->actual_size) {
1170
1171			/* finished with current buffer, take next buffer */
1172
1173			/* Requeue the buffer on the free list */
1174			ubuf->pos = 0;
1175
1176			mutex_lock(&port->dmaqueue_lock);
1177			list_move_tail(&ubuf->list, &port->list_buf_free.list);
1178			mutex_unlock(&port->dmaqueue_lock);
1179
1180			/* Dequeue next */
1181			if ((file->f_flags & O_NONBLOCK) == 0) {
1182				if (wait_event_interruptible(port->wait_read,
1183					saa7164_vbi_next_buf(port))) {
1184						break;
1185				}
1186			}
1187			ubuf = saa7164_vbi_next_buf(port);
1188		}
1189	}
1190err:
1191	if (!ret && !ubuf) {
1192		printk(KERN_ERR "%s() EAGAIN\n", __func__);
1193		ret = -EAGAIN;
1194	}
1195
1196	return ret;
1197}
1198
1199static unsigned int fops_poll(struct file *file, poll_table *wait)
1200{
1201	struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
1202	struct saa7164_port *port = fh->port;
1203	unsigned int mask = 0;
1204
1205	port->last_poll_msecs_diff = port->last_poll_msecs;
1206	port->last_poll_msecs = jiffies_to_msecs(jiffies);
1207	port->last_poll_msecs_diff = port->last_poll_msecs -
1208		port->last_poll_msecs_diff;
1209
1210	saa7164_histogram_update(&port->poll_interval,
1211		port->last_poll_msecs_diff);
1212
1213	if (!video_is_registered(port->v4l_device))
1214		return -EIO;
1215
1216	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
1217		if (atomic_inc_return(&port->v4l_reader_count) == 1) {
1218			if (saa7164_vbi_initialize(port) < 0)
1219				return -EINVAL;
1220			saa7164_vbi_start_streaming(port);
1221			msleep(200);
1222		}
1223	}
1224
1225	/* blocking wait for buffer */
1226	if ((file->f_flags & O_NONBLOCK) == 0) {
1227		if (wait_event_interruptible(port->wait_read,
1228			saa7164_vbi_next_buf(port))) {
1229				return -ERESTARTSYS;
1230		}
1231	}
1232
1233	/* Pull the first buffer from the used list */
1234	if (!list_empty(&port->list_buf_used.list))
1235		mask |= POLLIN | POLLRDNORM;
1236
1237	return mask;
1238}
1239static const struct v4l2_file_operations vbi_fops = {
1240	.owner		= THIS_MODULE,
1241	.open		= fops_open,
1242	.release	= fops_release,
1243	.read		= fops_read,
1244	.poll		= fops_poll,
1245	.unlocked_ioctl	= video_ioctl2,
1246};
1247
1248static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
1249	.vidioc_s_std		 = vidioc_s_std,
1250	.vidioc_g_std		 = vidioc_g_std,
1251	.vidioc_enum_input	 = vidioc_enum_input,
1252	.vidioc_g_input		 = vidioc_g_input,
1253	.vidioc_s_input		 = vidioc_s_input,
1254	.vidioc_g_tuner		 = vidioc_g_tuner,
1255	.vidioc_s_tuner		 = vidioc_s_tuner,
1256	.vidioc_g_frequency	 = vidioc_g_frequency,
1257	.vidioc_s_frequency	 = vidioc_s_frequency,
1258	.vidioc_s_ctrl		 = vidioc_s_ctrl,
1259	.vidioc_g_ctrl		 = vidioc_g_ctrl,
1260	.vidioc_querycap	 = vidioc_querycap,
1261	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1262	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
1263	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
1264	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
1265	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
1266	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
1267	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
1268	.vidioc_queryctrl	 = vidioc_queryctrl,
1269	.vidioc_g_fmt_vbi_cap	 = saa7164_vbi_fmt,
1270	.vidioc_try_fmt_vbi_cap	 = saa7164_vbi_fmt,
1271	.vidioc_s_fmt_vbi_cap	 = saa7164_vbi_fmt,
1272};
1273
1274static struct video_device saa7164_vbi_template = {
1275	.name          = "saa7164",
1276	.fops          = &vbi_fops,
1277	.ioctl_ops     = &vbi_ioctl_ops,
1278	.minor         = -1,
1279	.tvnorms       = SAA7164_NORMS,
1280};
1281
1282static struct video_device *saa7164_vbi_alloc(
1283	struct saa7164_port *port,
1284	struct pci_dev *pci,
1285	struct video_device *template,
1286	char *type)
1287{
1288	struct video_device *vfd;
1289	struct saa7164_dev *dev = port->dev;
1290
1291	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1292
1293	vfd = video_device_alloc();
1294	if (NULL == vfd)
1295		return NULL;
1296
1297	*vfd = *template;
1298	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
1299		type, saa7164_boards[dev->board].name);
1300
1301	vfd->v4l2_dev  = &dev->v4l2_dev;
1302	vfd->release = video_device_release;
1303	return vfd;
1304}
1305
1306int saa7164_vbi_register(struct saa7164_port *port)
1307{
1308	struct saa7164_dev *dev = port->dev;
1309	int result = -ENODEV;
1310
1311	dprintk(DBGLVL_VBI, "%s()\n", __func__);
1312
1313	if (port->type != SAA7164_MPEG_VBI)
1314		BUG();
1315
1316	/* Sanity check that the PCI configuration space is active */
1317	if (port->hwcfg.BARLocation == 0) {
1318		printk(KERN_ERR "%s() failed "
1319		       "(errno = %d), NO PCI configuration\n",
1320			__func__, result);
1321		result = -ENOMEM;
1322		goto failed;
1323	}
1324
1325	/* Establish VBI defaults here */
1326
1327	/* Allocate and register the video device node */
1328	port->v4l_device = saa7164_vbi_alloc(port,
1329		dev->pci, &saa7164_vbi_template, "vbi");
1330
1331	if (!port->v4l_device) {
1332		printk(KERN_INFO "%s: can't allocate vbi device\n",
1333			dev->name);
1334		result = -ENOMEM;
1335		goto failed;
1336	}
1337
1338	port->std = V4L2_STD_NTSC_M;
1339	video_set_drvdata(port->v4l_device, port);
1340	result = video_register_device(port->v4l_device,
1341		VFL_TYPE_VBI, -1);
1342	if (result < 0) {
1343		printk(KERN_INFO "%s: can't register vbi device\n",
1344			dev->name);
1345		/* TODO: We're going to leak here if we don't dealloc
1346		 The buffers above. The unreg function can't deal wit it.
1347		*/
1348		goto failed;
1349	}
1350
1351	printk(KERN_INFO "%s: registered device vbi%d [vbi]\n",
1352		dev->name, port->v4l_device->num);
1353
1354	/* Configure the hardware defaults */
1355
1356	result = 0;
1357failed:
1358	return result;
1359}
1360
1361void saa7164_vbi_unregister(struct saa7164_port *port)
1362{
1363	struct saa7164_dev *dev = port->dev;
1364
1365	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
1366
1367	if (port->type != SAA7164_MPEG_VBI)
1368		BUG();
1369
1370	if (port->v4l_device) {
1371		if (port->v4l_device->minor != -1)
1372			video_unregister_device(port->v4l_device);
1373		else
1374			video_device_release(port->v4l_device);
1375
1376		port->v4l_device = NULL;
1377	}
1378
1379}
1380