File Index
Files and directories
Sign in
FILE

saa7164-vbi.c

File preview with syntax highlighting.

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