• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/media/video/
1/*
2 * Modified in order to keep it compatible both with new and old videotext IOCTLs by
3 * Michael Geng <linux@MichaelGeng.de>
4 *
5 *	Cleaned up to use existing videodev interface and allow the idea
6 *	of multiple teletext decoders on the video4linux iface. Changed i2c
7 *	to cover addressing clashes on device busses. It's also rebuilt so
8 *	you can add arbitary multiple teletext devices to Linux video4linux
9 *	now (well 32 anyway).
10 *
11 *	Alan Cox <alan@lxorguk.ukuu.org.uk>
12 *
13 *	The original driver was heavily modified to match the i2c interface
14 *	It was truncated to use the WinTV boards, too.
15 *
16 *	Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
17 *
18 *	Derived From
19 *
20 * vtx.c:
21 * This is a loadable character-device-driver for videotext-interfaces
22 * (aka teletext). Please check the Makefile/README for a list of supported
23 * interfaces.
24 *
25 * Copyright (c) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.de>
26 *
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
41 * USA.
42 */
43
44#include <linux/module.h>
45#include <linux/kernel.h>
46#include <linux/mm.h>
47#include <linux/init.h>
48#include <linux/i2c.h>
49#include <linux/mutex.h>
50#include <linux/delay.h>
51#include <linux/videotext.h>
52#include <linux/videodev2.h>
53#include <linux/slab.h>
54#include <media/v4l2-device.h>
55#include <media/v4l2-chip-ident.h>
56#include <media/v4l2-ioctl.h>
57#include <media/v4l2-i2c-drv.h>
58
59MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
60MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
61MODULE_LICENSE("GPL");
62
63
64#define VTX_VER_MAJ 1
65#define VTX_VER_MIN 8
66
67
68#define NUM_DAUS 4
69#define NUM_BUFS 8
70
71static const int disp_modes[8][3] =
72{
73	{ 0x46, 0x03, 0x03 },	/* DISPOFF */
74	{ 0x46, 0xcc, 0xcc },	/* DISPNORM */
75	{ 0x44, 0x0f, 0x0f },	/* DISPTRANS */
76	{ 0x46, 0xcc, 0x46 },	/* DISPINS */
77	{ 0x44, 0x03, 0x03 },	/* DISPOFF, interlaced */
78	{ 0x44, 0xcc, 0xcc },	/* DISPNORM, interlaced */
79	{ 0x44, 0x0f, 0x0f },	/* DISPTRANS, interlaced */
80	{ 0x44, 0xcc, 0x46 }	/* DISPINS, interlaced */
81};
82
83
84
85#define PAGE_WAIT    msecs_to_jiffies(300)	/* Time between requesting page and */
86						/* checking status bits */
87#define PGBUF_EXPIRE msecs_to_jiffies(15000)	/* Time to wait before retransmitting */
88						/* page regardless of infobits */
89typedef struct {
90	u8 pgbuf[VTX_VIRTUALSIZE];		/* Page-buffer */
91	u8 laststat[10];			/* Last value of infobits for DAU */
92	u8 sregs[7];				/* Page-request registers */
93	unsigned long expire;			/* Time when page will be expired */
94	unsigned clrfound : 1;			/* VTXIOCCLRFOUND has been called */
95	unsigned stopped : 1;			/* VTXIOCSTOPDAU has been called */
96} vdau_t;
97
98struct saa5249_device
99{
100	struct v4l2_subdev sd;
101	struct video_device *vdev;
102	vdau_t vdau[NUM_DAUS];			/* Data for virtual DAUs (the 5249 only has one */
103						/* real DAU, so we have to simulate some more) */
104	int vtx_use_count;
105	int is_searching[NUM_DAUS];
106	int disp_mode;
107	int virtual_mode;
108	unsigned long in_use;
109	struct mutex lock;
110};
111
112static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
113{
114	return container_of(sd, struct saa5249_device, sd);
115}
116
117
118#define CCTWR 34		/* I�C write/read-address of vtx-chip */
119#define CCTRD 35
120#define NOACK_REPEAT 10		/* Retry access this many times on failure */
121#define CLEAR_DELAY   msecs_to_jiffies(50)	/* Time required to clear a page */
122#define READY_TIMEOUT msecs_to_jiffies(30)	/* Time to wait for ready signal of I2C-bus interface */
123#define INIT_DELAY 500		/* Time in usec to wait at initialization of CEA interface */
124#define START_DELAY 10		/* Time in usec to wait before starting write-cycle (CEA) */
125
126#define VTX_DEV_MINOR 0
127
128static struct video_device saa_template;	/* Declared near bottom */
129
130/*
131 *	Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
132 *	delay may be longer.
133 */
134
135static void jdelay(unsigned long delay)
136{
137	sigset_t oldblocked = current->blocked;
138
139	spin_lock_irq(&current->sighand->siglock);
140	sigfillset(&current->blocked);
141	recalc_sigpending();
142	spin_unlock_irq(&current->sighand->siglock);
143	msleep_interruptible(jiffies_to_msecs(delay));
144
145	spin_lock_irq(&current->sighand->siglock);
146	current->blocked = oldblocked;
147	recalc_sigpending();
148	spin_unlock_irq(&current->sighand->siglock);
149}
150
151
152/*
153 *	I2C interfaces
154 */
155
156static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
157{
158	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
159	char buf[64];
160
161	buf[0] = reg;
162	memcpy(buf+1, data, count);
163
164	if (i2c_master_send(client, buf, count + 1) == count + 1)
165		return 0;
166	return -1;
167}
168
169static int i2c_senddata(struct saa5249_device *t, ...)
170{
171	unsigned char buf[64];
172	int v;
173	int ct = 0;
174	va_list argp;
175	va_start(argp,t);
176
177	while ((v = va_arg(argp, int)) != -1)
178		buf[ct++] = v;
179
180	va_end(argp);
181	return i2c_sendbuf(t, buf[0], ct-1, buf+1);
182}
183
184/* Get count number of bytes from I��C-device at address adr, store them in buf. Start & stop
185 * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
186 * sending of data. If uaccess is 'true', data is written to user-space with put_user.
187 * Returns -1 if I��C-device didn't send acknowledge, 0 otherwise
188 */
189
190static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
191{
192	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
193
194	if (i2c_master_recv(client, buf, count) != count)
195		return -1;
196	return 0;
197}
198
199
200/*
201 *	Standard character-device-driver functions
202 */
203
204static long do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg)
205{
206	static int virtual_mode = false;
207	struct saa5249_device *t = video_drvdata(file);
208
209	switch (cmd) {
210	case VTXIOCGETINFO:
211	{
212		vtx_info_t *info = arg;
213		info->version_major = VTX_VER_MAJ;
214		info->version_minor = VTX_VER_MIN;
215		info->numpages = NUM_DAUS;
216		/*info->cct_type = CCT_TYPE;*/
217		return 0;
218	}
219
220	case VTXIOCCLRPAGE:
221	{
222		vtx_pagereq_t *req = arg;
223
224		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
225			return -EINVAL;
226		memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
227		t->vdau[req->pgbuf].clrfound = true;
228		return 0;
229	}
230
231	case VTXIOCCLRFOUND:
232	{
233		vtx_pagereq_t *req = arg;
234
235		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
236			return -EINVAL;
237		t->vdau[req->pgbuf].clrfound = true;
238		return 0;
239	}
240
241	case VTXIOCPAGEREQ:
242	{
243		vtx_pagereq_t *req = arg;
244		if (!(req->pagemask & PGMASK_PAGE))
245			req->page = 0;
246		if (!(req->pagemask & PGMASK_HOUR))
247			req->hour = 0;
248		if (!(req->pagemask & PGMASK_MINUTE))
249			req->minute = 0;
250		if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
251			return -EINVAL;
252		req->page &= 0x7ff;
253		if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
254			req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
255			return -EINVAL;
256		t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
257		t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
258		t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
259		t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
260		t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
261		t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
262		t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
263		t->vdau[req->pgbuf].stopped = false;
264		t->vdau[req->pgbuf].clrfound = true;
265		t->is_searching[req->pgbuf] = true;
266		return 0;
267	}
268
269	case VTXIOCGETSTAT:
270	{
271		vtx_pagereq_t *req = arg;
272		u8 infobits[10];
273		vtx_pageinfo_t info;
274		int a;
275
276		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
277			return -EINVAL;
278		if (!t->vdau[req->pgbuf].stopped) {
279			if (i2c_senddata(t, 2, 0, -1) ||
280				i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
281				i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
282				i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
283				i2c_senddata(t, 8, 0, 25, 0, -1))
284				return -EIO;
285			jdelay(PAGE_WAIT);
286			if (i2c_getdata(t, 10, infobits))
287				return -EIO;
288
289			if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&	/* check FOUND-bit */
290				(memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
291				time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
292			{		/* check if new page arrived */
293				if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
294					i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
295					return -EIO;
296				t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
297				memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
298				if (t->virtual_mode) {
299					/* Packet X/24 */
300					if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
301						i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
302						return -EIO;
303					/* Packet X/27/0 */
304					if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
305						i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
306						return -EIO;
307					if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
308						i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
309						return -EIO;
310				}
311				t->vdau[req->pgbuf].clrfound = false;
312				memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
313			} else {
314				memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
315			}
316		} else {
317			memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
318		}
319
320		info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
321		if (info.pagenum < 0x100)
322			info.pagenum += 0x800;
323		info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
324		info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
325		info.charset = ((infobits[7] >> 1) & 7);
326		info.delete = !!(infobits[3] & 8);
327		info.headline = !!(infobits[5] & 4);
328		info.subtitle = !!(infobits[5] & 8);
329		info.supp_header = !!(infobits[6] & 1);
330		info.update = !!(infobits[6] & 2);
331		info.inter_seq = !!(infobits[6] & 4);
332		info.dis_disp = !!(infobits[6] & 8);
333		info.serial = !!(infobits[7] & 1);
334		info.notfound = !!(infobits[8] & 0x10);
335		info.pblf = !!(infobits[9] & 0x20);
336		info.hamming = 0;
337		for (a = 0; a <= 7; a++) {
338			if (infobits[a] & 0xf0) {
339				info.hamming = 1;
340				break;
341			}
342		}
343		if (t->vdau[req->pgbuf].clrfound)
344			info.notfound = 1;
345		if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
346			return -EFAULT;
347		if (!info.hamming && !info.notfound)
348			t->is_searching[req->pgbuf] = false;
349		return 0;
350	}
351
352	case VTXIOCGETPAGE:
353	{
354		vtx_pagereq_t *req = arg;
355		int start, end;
356
357		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
358			req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
359			return -EINVAL;
360		if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
361			return -EFAULT;
362
363		 /*
364		  *	Always read the time directly from SAA5249
365		  */
366
367		if (req->start <= 39 && req->end >= 32) {
368			int len;
369			char buf[16];
370			start = max(req->start, 32);
371			end = min(req->end, 39);
372			len = end - start + 1;
373			if (i2c_senddata(t, 8, 0, 0, start, -1) ||
374				i2c_getdata(t, len, buf))
375				return -EIO;
376			if (copy_to_user(req->buffer + start - req->start, buf, len))
377				return -EFAULT;
378		}
379		/* Insert the current header if DAU is still searching for a page */
380		if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {
381			char buf[32];
382			int len;
383
384			start = max(req->start, 7);
385			end = min(req->end, 31);
386			len = end - start + 1;
387			if (i2c_senddata(t, 8, 0, 0, start, -1) ||
388				i2c_getdata(t, len, buf))
389				return -EIO;
390			if (copy_to_user(req->buffer + start - req->start, buf, len))
391				return -EFAULT;
392		}
393		return 0;
394	}
395
396	case VTXIOCSTOPDAU:
397	{
398		vtx_pagereq_t *req = arg;
399
400		if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
401			return -EINVAL;
402		t->vdau[req->pgbuf].stopped = true;
403		t->is_searching[req->pgbuf] = false;
404		return 0;
405	}
406
407	case VTXIOCPUTPAGE:
408	case VTXIOCSETDISP:
409	case VTXIOCPUTSTAT:
410		return 0;
411
412	case VTXIOCCLRCACHE:
413	{
414		if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
415			' ', ' ', ' ', ' ', ' ', ' ',
416			' ', ' ', ' ', ' ', ' ', ' ',
417			' ', ' ', ' ', ' ', ' ', ' ',
418			' ', ' ', ' ', ' ', ' ', ' ',
419			-1))
420			return -EIO;
421		if (i2c_senddata(t, 3, 0x20, -1))
422			return -EIO;
423		jdelay(10 * CLEAR_DELAY);			/* I have no idea how long we have to wait here */
424		return 0;
425	}
426
427	case VTXIOCSETVIRT:
428	{
429		/* The SAA5249 has virtual-row reception turned on always */
430		t->virtual_mode = (int)(long)arg;
431		return 0;
432	}
433	}
434	return -EINVAL;
435}
436
437/*
438 * Translates old vtx IOCTLs to new ones
439 *
440 * This keeps new kernel versions compatible with old userspace programs.
441 */
442static inline unsigned int vtx_fix_command(unsigned int cmd)
443{
444	switch (cmd) {
445	case VTXIOCGETINFO_OLD:
446		cmd = VTXIOCGETINFO;
447		break;
448	case VTXIOCCLRPAGE_OLD:
449		cmd = VTXIOCCLRPAGE;
450		break;
451	case VTXIOCCLRFOUND_OLD:
452		cmd = VTXIOCCLRFOUND;
453		break;
454	case VTXIOCPAGEREQ_OLD:
455		cmd = VTXIOCPAGEREQ;
456		break;
457	case VTXIOCGETSTAT_OLD:
458		cmd = VTXIOCGETSTAT;
459		break;
460	case VTXIOCGETPAGE_OLD:
461		cmd = VTXIOCGETPAGE;
462		break;
463	case VTXIOCSTOPDAU_OLD:
464		cmd = VTXIOCSTOPDAU;
465		break;
466	case VTXIOCPUTPAGE_OLD:
467		cmd = VTXIOCPUTPAGE;
468		break;
469	case VTXIOCSETDISP_OLD:
470		cmd = VTXIOCSETDISP;
471		break;
472	case VTXIOCPUTSTAT_OLD:
473		cmd = VTXIOCPUTSTAT;
474		break;
475	case VTXIOCCLRCACHE_OLD:
476		cmd = VTXIOCCLRCACHE;
477		break;
478	case VTXIOCSETVIRT_OLD:
479		cmd = VTXIOCSETVIRT;
480		break;
481	}
482	return cmd;
483}
484
485/*
486 *	Handle the locking
487 */
488
489static long saa5249_ioctl(struct file *file,
490			 unsigned int cmd, unsigned long arg)
491{
492	struct saa5249_device *t = video_drvdata(file);
493	long err;
494
495	cmd = vtx_fix_command(cmd);
496	mutex_lock(&t->lock);
497	err = video_usercopy(file, cmd, arg, do_saa5249_ioctl);
498	mutex_unlock(&t->lock);
499	return err;
500}
501
502static int saa5249_open(struct file *file)
503{
504	struct saa5249_device *t = video_drvdata(file);
505	int pgbuf;
506
507	if (test_and_set_bit(0, &t->in_use))
508		return -EBUSY;
509
510	if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */
511		/* Turn off parity checks (we do this ourselves) */
512		i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
513		/* Display TV-picture, no virtual rows */
514		i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))
515		/* Set display to page 4 */
516	{
517		clear_bit(0, &t->in_use);
518		return -EIO;
519	}
520
521	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
522		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
523		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
524		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
525		t->vdau[pgbuf].expire = 0;
526		t->vdau[pgbuf].clrfound = true;
527		t->vdau[pgbuf].stopped = true;
528		t->is_searching[pgbuf] = false;
529	}
530	t->virtual_mode = false;
531	return 0;
532}
533
534
535
536static int saa5249_release(struct file *file)
537{
538	struct saa5249_device *t = video_drvdata(file);
539
540	i2c_senddata(t, 1, 0x20, -1);		/* Turn off CCT */
541	i2c_senddata(t, 5, 3, 3, -1);		/* Turn off TV-display */
542	clear_bit(0, &t->in_use);
543	return 0;
544}
545
546static const struct v4l2_file_operations saa_fops = {
547	.owner		= THIS_MODULE,
548	.open		= saa5249_open,
549	.release       	= saa5249_release,
550	.ioctl          = saa5249_ioctl,
551};
552
553static struct video_device saa_template =
554{
555	.name		= "saa5249",
556	.fops           = &saa_fops,
557	.release 	= video_device_release,
558};
559
560static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
561{
562	struct i2c_client *client = v4l2_get_subdevdata(sd);
563
564	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
565}
566
567static const struct v4l2_subdev_core_ops saa5249_core_ops = {
568	.g_chip_ident = saa5249_g_chip_ident,
569};
570
571static const struct v4l2_subdev_ops saa5249_ops = {
572	.core = &saa5249_core_ops,
573};
574
575static int saa5249_probe(struct i2c_client *client,
576			const struct i2c_device_id *id)
577{
578	int pgbuf;
579	int err;
580	struct saa5249_device *t;
581	struct v4l2_subdev *sd;
582
583	v4l_info(client, "chip found @ 0x%x (%s)\n",
584			client->addr << 1, client->adapter->name);
585	v4l_info(client, "VideoText version %d.%d\n",
586			VTX_VER_MAJ, VTX_VER_MIN);
587	t = kzalloc(sizeof(*t), GFP_KERNEL);
588	if (t == NULL)
589		return -ENOMEM;
590	sd = &t->sd;
591	v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
592	mutex_init(&t->lock);
593
594	/* Now create a video4linux device */
595	t->vdev = video_device_alloc();
596	if (t->vdev == NULL) {
597		kfree(t);
598		kfree(client);
599		return -ENOMEM;
600	}
601	memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
602
603	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
604		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
605		memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
606		memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
607		t->vdau[pgbuf].expire = 0;
608		t->vdau[pgbuf].clrfound = true;
609		t->vdau[pgbuf].stopped = true;
610		t->is_searching[pgbuf] = false;
611	}
612	video_set_drvdata(t->vdev, t);
613
614	/* Register it */
615	err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
616	if (err < 0) {
617		video_device_release(t->vdev);
618		kfree(t);
619		return err;
620	}
621	return 0;
622}
623
624static int saa5249_remove(struct i2c_client *client)
625{
626	struct v4l2_subdev *sd = i2c_get_clientdata(client);
627	struct saa5249_device *t = to_dev(sd);
628
629	video_unregister_device(t->vdev);
630	v4l2_device_unregister_subdev(sd);
631	kfree(t);
632	return 0;
633}
634
635static const struct i2c_device_id saa5249_id[] = {
636	{ "saa5249", 0 },
637	{ }
638};
639MODULE_DEVICE_TABLE(i2c, saa5249_id);
640
641static struct v4l2_i2c_driver_data v4l2_i2c_data = {
642	.name = "saa5249",
643	.probe = saa5249_probe,
644	.remove = saa5249_remove,
645	.id_table = saa5249_id,
646};
647