brintos

brintos / linux-shallow public Read only

0
0
Text · 19.3 KiB · a6738ba Raw
769 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Driver for the NXP SAA7164 PCIe bridge4 *5 *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>6 */7 8#include "saa7164.h"9 10/* Take the encoder configuration from the port struct and11 * flush it to the hardware.12 */13static void saa7164_vbi_configure(struct saa7164_port *port)14{15	struct saa7164_dev *dev = port->dev;16	dprintk(DBGLVL_VBI, "%s()\n", __func__);17 18	port->vbi_params.width = port->enc_port->width;19	port->vbi_params.height = port->enc_port->height;20	port->vbi_params.is_50hz =21		(port->enc_port->encodernorm.id & V4L2_STD_625_50) != 0;22 23	/* Set up the DIF (enable it) for analog mode by default */24	saa7164_api_initialize_dif(port);25	dprintk(DBGLVL_VBI, "%s() ends\n", __func__);26}27 28static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port)29{30	struct list_head *c, *n, *p, *q, *l, *v;31	struct saa7164_dev *dev = port->dev;32	struct saa7164_buffer *buf;33	struct saa7164_user_buffer *ubuf;34 35	/* Remove any allocated buffers */36	mutex_lock(&port->dmaqueue_lock);37 38	dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr);39	list_for_each_safe(c, n, &port->dmaqueue.list) {40		buf = list_entry(c, struct saa7164_buffer, list);41		list_del(c);42		saa7164_buffer_dealloc(buf);43	}44 45	dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr);46	list_for_each_safe(p, q, &port->list_buf_used.list) {47		ubuf = list_entry(p, struct saa7164_user_buffer, list);48		list_del(p);49		saa7164_buffer_dealloc_user(ubuf);50	}51 52	dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr);53	list_for_each_safe(l, v, &port->list_buf_free.list) {54		ubuf = list_entry(l, struct saa7164_user_buffer, list);55		list_del(l);56		saa7164_buffer_dealloc_user(ubuf);57	}58 59	mutex_unlock(&port->dmaqueue_lock);60	dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr);61 62	return 0;63}64 65/* Dynamic buffer switch at vbi start time */66static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)67{68	struct saa7164_dev *dev = port->dev;69	struct saa7164_buffer *buf;70	struct saa7164_user_buffer *ubuf;71	struct tmHWStreamParameters *params = &port->hw_streamingparams;72	int result = -ENODEV, i;73	int len = 0;74 75	dprintk(DBGLVL_VBI, "%s()\n", __func__);76 77	/* TODO: NTSC SPECIFIC */78	/* Init and establish defaults */79	params->samplesperline = 1440;80	params->numberoflines = 12;81	params->numberoflines = 18;82	params->pitch = 1600;83	params->pitch = 1440;84	params->numpagetables = 2 +85		((params->numberoflines * params->pitch) / PAGE_SIZE);86	params->bitspersample = 8;87	params->linethreshold = 0;88	params->pagetablelistvirt = NULL;89	params->pagetablelistphys = NULL;90	params->numpagetableentries = port->hwcfg.buffercount;91 92	/* Allocate the PCI resources, buffers (hard) */93	for (i = 0; i < port->hwcfg.buffercount; i++) {94		buf = saa7164_buffer_alloc(port,95			params->numberoflines *96			params->pitch);97 98		if (!buf) {99			printk(KERN_ERR "%s() failed (errno = %d), unable to allocate buffer\n",100				__func__, result);101			result = -ENOMEM;102			goto failed;103		} else {104 105			mutex_lock(&port->dmaqueue_lock);106			list_add_tail(&buf->list, &port->dmaqueue.list);107			mutex_unlock(&port->dmaqueue_lock);108 109		}110	}111 112	/* Allocate some kernel buffers for copying113	 * to userpsace.114	 */115	len = params->numberoflines * params->pitch;116 117	if (vbi_buffers < 16)118		vbi_buffers = 16;119	if (vbi_buffers > 512)120		vbi_buffers = 512;121 122	for (i = 0; i < vbi_buffers; i++) {123 124		ubuf = saa7164_buffer_alloc_user(dev, len);125		if (ubuf) {126			mutex_lock(&port->dmaqueue_lock);127			list_add_tail(&ubuf->list, &port->list_buf_free.list);128			mutex_unlock(&port->dmaqueue_lock);129		}130 131	}132 133	result = 0;134 135failed:136	return result;137}138 139 140static int saa7164_vbi_initialize(struct saa7164_port *port)141{142	saa7164_vbi_configure(port);143	return 0;144}145 146/* -- V4L2 --------------------------------------------------------- */147static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)148{149	struct saa7164_vbi_fh *fh = file->private_data;150 151	return saa7164_s_std(fh->port->enc_port, id);152}153 154static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)155{156	struct saa7164_encoder_fh *fh = file->private_data;157 158	return saa7164_g_std(fh->port->enc_port, id);159}160 161static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)162{163	struct saa7164_vbi_fh *fh = file->private_data;164 165	return saa7164_g_input(fh->port->enc_port, i);166}167 168static int vidioc_s_input(struct file *file, void *priv, unsigned int i)169{170	struct saa7164_vbi_fh *fh = file->private_data;171 172	return saa7164_s_input(fh->port->enc_port, i);173}174 175static int vidioc_g_frequency(struct file *file, void *priv,176	struct v4l2_frequency *f)177{178	struct saa7164_vbi_fh *fh = file->private_data;179 180	return saa7164_g_frequency(fh->port->enc_port, f);181}182 183static int vidioc_s_frequency(struct file *file, void *priv,184	const struct v4l2_frequency *f)185{186	struct saa7164_vbi_fh *fh = file->private_data;187	int ret = saa7164_s_frequency(fh->port->enc_port, f);188 189	if (ret == 0)190		saa7164_vbi_initialize(fh->port);191	return ret;192}193 194static int vidioc_querycap(struct file *file, void  *priv,195	struct v4l2_capability *cap)196{197	struct saa7164_vbi_fh *fh = file->private_data;198	struct saa7164_port *port = fh->port;199	struct saa7164_dev *dev = port->dev;200 201	strscpy(cap->driver, dev->name, sizeof(cap->driver));202	strscpy(cap->card, saa7164_boards[dev->board].name,203		sizeof(cap->card));204	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |205			    V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |206			    V4L2_CAP_DEVICE_CAPS;207	return 0;208}209 210static int saa7164_vbi_stop_port(struct saa7164_port *port)211{212	struct saa7164_dev *dev = port->dev;213	int ret;214 215	ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);216	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {217		printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",218			__func__, ret);219		ret = -EIO;220	} else {221		dprintk(DBGLVL_VBI, "%s()    Stopped\n", __func__);222		ret = 0;223	}224 225	return ret;226}227 228static int saa7164_vbi_acquire_port(struct saa7164_port *port)229{230	struct saa7164_dev *dev = port->dev;231	int ret;232 233	ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);234	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {235		printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",236			__func__, ret);237		ret = -EIO;238	} else {239		dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);240		ret = 0;241	}242 243	return ret;244}245 246static int saa7164_vbi_pause_port(struct saa7164_port *port)247{248	struct saa7164_dev *dev = port->dev;249	int ret;250 251	ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);252	if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {253		printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",254			__func__, ret);255		ret = -EIO;256	} else {257		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);258		ret = 0;259	}260 261	return ret;262}263 264/* Firmware is very windows centric, meaning you have to transition265 * the part through AVStream / KS Windows stages, forwards or backwards.266 * States are: stopped, acquired (h/w), paused, started.267 * We have to leave here will all of the soft buffers on the free list,268 * else the cfg_post() func won't have soft buffers to correctly configure.269 */270static int saa7164_vbi_stop_streaming(struct saa7164_port *port)271{272	struct saa7164_dev *dev = port->dev;273	struct saa7164_buffer *buf;274	struct saa7164_user_buffer *ubuf;275	struct list_head *c, *n;276	int ret;277 278	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);279 280	ret = saa7164_vbi_pause_port(port);281	ret = saa7164_vbi_acquire_port(port);282	ret = saa7164_vbi_stop_port(port);283 284	dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__,285		port->nr);286 287	/* Reset the state of any allocated buffer resources */288	mutex_lock(&port->dmaqueue_lock);289 290	/* Reset the hard and soft buffer state */291	list_for_each_safe(c, n, &port->dmaqueue.list) {292		buf = list_entry(c, struct saa7164_buffer, list);293		buf->flags = SAA7164_BUFFER_FREE;294		buf->pos = 0;295	}296 297	list_for_each_safe(c, n, &port->list_buf_used.list) {298		ubuf = list_entry(c, struct saa7164_user_buffer, list);299		ubuf->pos = 0;300		list_move_tail(&ubuf->list, &port->list_buf_free.list);301	}302 303	mutex_unlock(&port->dmaqueue_lock);304 305	/* Free any allocated resources */306	saa7164_vbi_buffers_dealloc(port);307 308	dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr);309 310	return ret;311}312 313static int saa7164_vbi_start_streaming(struct saa7164_port *port)314{315	struct saa7164_dev *dev = port->dev;316	int result, ret = 0;317 318	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);319 320	port->done_first_interrupt = 0;321 322	/* allocate all of the PCIe DMA buffer resources on the fly,323	 * allowing switching between TS and PS payloads without324	 * requiring a complete driver reload.325	 */326	saa7164_vbi_buffers_alloc(port);327 328	/* Configure the encoder with any cache values */329#if 0330	saa7164_api_set_encoder(port);331	saa7164_api_get_encoder(port);332#endif333 334	/* Place the empty buffers on the hardware */335	saa7164_buffer_cfg_port(port);336 337	/* Negotiate format */338	if (saa7164_api_set_vbi_format(port) != SAA_OK) {339		printk(KERN_ERR "%s() No supported VBI format\n", __func__);340		ret = -EIO;341		goto out;342	}343 344	/* Acquire the hardware */345	result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);346	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {347		printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",348			__func__, result);349 350		ret = -EIO;351		goto out;352	} else353		dprintk(DBGLVL_VBI, "%s()   Acquired\n", __func__);354 355	/* Pause the hardware */356	result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);357	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {358		printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",359				__func__, result);360 361		/* Stop the hardware, regardless */362		result = saa7164_vbi_stop_port(port);363		if (result != SAA_OK) {364			printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n",365			       __func__, result);366		}367 368		ret = -EIO;369		goto out;370	} else371		dprintk(DBGLVL_VBI, "%s()   Paused\n", __func__);372 373	/* Start the hardware */374	result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);375	if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {376		printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",377				__func__, result);378 379		/* Stop the hardware, regardless */380		result = saa7164_vbi_acquire_port(port);381		result = saa7164_vbi_stop_port(port);382		if (result != SAA_OK) {383			printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n",384			       __func__, result);385		}386 387		ret = -EIO;388	} else389		dprintk(DBGLVL_VBI, "%s()   Running\n", __func__);390 391out:392	return ret;393}394 395static int saa7164_vbi_fmt(struct file *file, void *priv,396			   struct v4l2_format *f)397{398	/* ntsc */399	f->fmt.vbi.samples_per_line = 1440;400	f->fmt.vbi.sampling_rate = 27000000;401	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;402	f->fmt.vbi.offset = 0;403	f->fmt.vbi.flags = 0;404	f->fmt.vbi.start[0] = 10;405	f->fmt.vbi.count[0] = 18;406	f->fmt.vbi.start[1] = 263 + 10 + 1;407	f->fmt.vbi.count[1] = 18;408	memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));409	return 0;410}411 412static int fops_open(struct file *file)413{414	struct saa7164_dev *dev;415	struct saa7164_port *port;416	struct saa7164_vbi_fh *fh;417 418	port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));419	if (!port)420		return -ENODEV;421 422	dev = port->dev;423 424	dprintk(DBGLVL_VBI, "%s()\n", __func__);425 426	/* allocate + initialize per filehandle data */427	fh = kzalloc(sizeof(*fh), GFP_KERNEL);428	if (NULL == fh)429		return -ENOMEM;430 431	fh->port = port;432	v4l2_fh_init(&fh->fh, video_devdata(file));433	v4l2_fh_add(&fh->fh);434	file->private_data = fh;435 436	return 0;437}438 439static int fops_release(struct file *file)440{441	struct saa7164_vbi_fh *fh = file->private_data;442	struct saa7164_port *port = fh->port;443	struct saa7164_dev *dev = port->dev;444 445	dprintk(DBGLVL_VBI, "%s()\n", __func__);446 447	/* Shut device down on last close */448	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {449		if (atomic_dec_return(&port->v4l_reader_count) == 0) {450			/* stop vbi capture then cancel buffers */451			saa7164_vbi_stop_streaming(port);452		}453	}454 455	v4l2_fh_del(&fh->fh);456	v4l2_fh_exit(&fh->fh);457	kfree(fh);458 459	return 0;460}461 462static struct463saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)464{465	struct saa7164_user_buffer *ubuf = NULL;466	struct saa7164_dev *dev = port->dev;467	u32 crc;468 469	mutex_lock(&port->dmaqueue_lock);470	if (!list_empty(&port->list_buf_used.list)) {471		ubuf = list_first_entry(&port->list_buf_used.list,472			struct saa7164_user_buffer, list);473 474		if (crc_checking) {475			crc = crc32(0, ubuf->data, ubuf->actual_size);476			if (crc != ubuf->crc) {477				printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",478					__func__,479					ubuf, ubuf->crc, crc);480			}481		}482 483	}484	mutex_unlock(&port->dmaqueue_lock);485 486	dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf);487 488	return ubuf;489}490 491static ssize_t fops_read(struct file *file, char __user *buffer,492	size_t count, loff_t *pos)493{494	struct saa7164_vbi_fh *fh = file->private_data;495	struct saa7164_port *port = fh->port;496	struct saa7164_user_buffer *ubuf = NULL;497	struct saa7164_dev *dev = port->dev;498	int ret = 0;499	int rem, cnt;500	u8 *p;501 502	port->last_read_msecs_diff = port->last_read_msecs;503	port->last_read_msecs = jiffies_to_msecs(jiffies);504	port->last_read_msecs_diff = port->last_read_msecs -505		port->last_read_msecs_diff;506 507	saa7164_histogram_update(&port->read_interval,508		port->last_read_msecs_diff);509 510	if (*pos) {511		printk(KERN_ERR "%s() ESPIPE\n", __func__);512		return -ESPIPE;513	}514 515	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {516		if (atomic_inc_return(&port->v4l_reader_count) == 1) {517 518			if (saa7164_vbi_initialize(port) < 0) {519				printk(KERN_ERR "%s() EINVAL\n", __func__);520				return -EINVAL;521			}522 523			saa7164_vbi_start_streaming(port);524			msleep(200);525		}526	}527 528	/* blocking wait for buffer */529	if ((file->f_flags & O_NONBLOCK) == 0) {530		if (wait_event_interruptible(port->wait_read,531			saa7164_vbi_next_buf(port))) {532				printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);533				return -ERESTARTSYS;534		}535	}536 537	/* Pull the first buffer from the used list */538	ubuf = saa7164_vbi_next_buf(port);539 540	while ((count > 0) && ubuf) {541 542		/* set remaining bytes to copy */543		rem = ubuf->actual_size - ubuf->pos;544		cnt = rem > count ? count : rem;545 546		p = ubuf->data + ubuf->pos;547 548		dprintk(DBGLVL_VBI,549			"%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",550			__func__, (int)count, cnt, rem, ubuf, ubuf->pos);551 552		if (copy_to_user(buffer, p, cnt)) {553			printk(KERN_ERR "%s() copy_to_user failed\n", __func__);554			if (!ret) {555				printk(KERN_ERR "%s() EFAULT\n", __func__);556				ret = -EFAULT;557			}558			goto err;559		}560 561		ubuf->pos += cnt;562		count -= cnt;563		buffer += cnt;564		ret += cnt;565 566		if (ubuf->pos > ubuf->actual_size)567			printk(KERN_ERR "read() pos > actual, huh?\n");568 569		if (ubuf->pos == ubuf->actual_size) {570 571			/* finished with current buffer, take next buffer */572 573			/* Requeue the buffer on the free list */574			ubuf->pos = 0;575 576			mutex_lock(&port->dmaqueue_lock);577			list_move_tail(&ubuf->list, &port->list_buf_free.list);578			mutex_unlock(&port->dmaqueue_lock);579 580			/* Dequeue next */581			if ((file->f_flags & O_NONBLOCK) == 0) {582				if (wait_event_interruptible(port->wait_read,583					saa7164_vbi_next_buf(port))) {584						break;585				}586			}587			ubuf = saa7164_vbi_next_buf(port);588		}589	}590err:591	if (!ret && !ubuf) {592		printk(KERN_ERR "%s() EAGAIN\n", __func__);593		ret = -EAGAIN;594	}595 596	return ret;597}598 599static __poll_t fops_poll(struct file *file, poll_table *wait)600{601	struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;602	struct saa7164_port *port = fh->port;603	__poll_t mask = 0;604 605	port->last_poll_msecs_diff = port->last_poll_msecs;606	port->last_poll_msecs = jiffies_to_msecs(jiffies);607	port->last_poll_msecs_diff = port->last_poll_msecs -608		port->last_poll_msecs_diff;609 610	saa7164_histogram_update(&port->poll_interval,611		port->last_poll_msecs_diff);612 613	if (!video_is_registered(port->v4l_device))614		return EPOLLERR;615 616	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {617		if (atomic_inc_return(&port->v4l_reader_count) == 1) {618			if (saa7164_vbi_initialize(port) < 0)619				return EPOLLERR;620			saa7164_vbi_start_streaming(port);621			msleep(200);622		}623	}624 625	/* blocking wait for buffer */626	if ((file->f_flags & O_NONBLOCK) == 0) {627		if (wait_event_interruptible(port->wait_read,628			saa7164_vbi_next_buf(port))) {629				return EPOLLERR;630		}631	}632 633	/* Pull the first buffer from the used list */634	if (!list_empty(&port->list_buf_used.list))635		mask |= EPOLLIN | EPOLLRDNORM;636 637	return mask;638}639static const struct v4l2_file_operations vbi_fops = {640	.owner		= THIS_MODULE,641	.open		= fops_open,642	.release	= fops_release,643	.read		= fops_read,644	.poll		= fops_poll,645	.unlocked_ioctl	= video_ioctl2,646};647 648static const struct v4l2_ioctl_ops vbi_ioctl_ops = {649	.vidioc_s_std		 = vidioc_s_std,650	.vidioc_g_std		 = vidioc_g_std,651	.vidioc_enum_input	 = saa7164_enum_input,652	.vidioc_g_input		 = vidioc_g_input,653	.vidioc_s_input		 = vidioc_s_input,654	.vidioc_g_tuner		 = saa7164_g_tuner,655	.vidioc_s_tuner		 = saa7164_s_tuner,656	.vidioc_g_frequency	 = vidioc_g_frequency,657	.vidioc_s_frequency	 = vidioc_s_frequency,658	.vidioc_querycap	 = vidioc_querycap,659	.vidioc_g_fmt_vbi_cap	 = saa7164_vbi_fmt,660	.vidioc_try_fmt_vbi_cap	 = saa7164_vbi_fmt,661	.vidioc_s_fmt_vbi_cap	 = saa7164_vbi_fmt,662};663 664static struct video_device saa7164_vbi_template = {665	.name          = "saa7164",666	.fops          = &vbi_fops,667	.ioctl_ops     = &vbi_ioctl_ops,668	.minor         = -1,669	.tvnorms       = SAA7164_NORMS,670	.device_caps   = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE |671			 V4L2_CAP_TUNER,672};673 674static struct video_device *saa7164_vbi_alloc(675	struct saa7164_port *port,676	struct pci_dev *pci,677	struct video_device *template,678	char *type)679{680	struct video_device *vfd;681	struct saa7164_dev *dev = port->dev;682 683	dprintk(DBGLVL_VBI, "%s()\n", __func__);684 685	vfd = video_device_alloc();686	if (NULL == vfd)687		return NULL;688 689	*vfd = *template;690	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,691		type, saa7164_boards[dev->board].name);692 693	vfd->v4l2_dev  = &dev->v4l2_dev;694	vfd->release = video_device_release;695	return vfd;696}697 698int saa7164_vbi_register(struct saa7164_port *port)699{700	struct saa7164_dev *dev = port->dev;701	int result = -ENODEV;702 703	dprintk(DBGLVL_VBI, "%s()\n", __func__);704 705	BUG_ON(port->type != SAA7164_MPEG_VBI);706 707	/* Sanity check that the PCI configuration space is active */708	if (port->hwcfg.BARLocation == 0) {709		printk(KERN_ERR "%s() failed (errno = %d), NO PCI configuration\n",710			__func__, result);711		result = -ENOMEM;712		goto failed;713	}714 715	/* Establish VBI defaults here */716 717	/* Allocate and register the video device node */718	port->v4l_device = saa7164_vbi_alloc(port,719		dev->pci, &saa7164_vbi_template, "vbi");720 721	if (!port->v4l_device) {722		printk(KERN_INFO "%s: can't allocate vbi device\n",723			dev->name);724		result = -ENOMEM;725		goto failed;726	}727 728	port->enc_port = &dev->ports[port->nr - 2];729	video_set_drvdata(port->v4l_device, port);730	result = video_register_device(port->v4l_device,731		VFL_TYPE_VBI, -1);732	if (result < 0) {733		printk(KERN_INFO "%s: can't register vbi device\n",734			dev->name);735		/* TODO: We're going to leak here if we don't dealloc736		 The buffers above. The unreg function can't deal wit it.737		*/738		goto failed;739	}740 741	printk(KERN_INFO "%s: registered device vbi%d [vbi]\n",742		dev->name, port->v4l_device->num);743 744	/* Configure the hardware defaults */745 746	result = 0;747failed:748	return result;749}750 751void saa7164_vbi_unregister(struct saa7164_port *port)752{753	struct saa7164_dev *dev = port->dev;754 755	dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);756 757	BUG_ON(port->type != SAA7164_MPEG_VBI);758 759	if (port->v4l_device) {760		if (port->v4l_device->minor != -1)761			video_unregister_device(port->v4l_device);762		else763			video_device_release(port->v4l_device);764 765		port->v4l_device = NULL;766	}767 768}769