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(¤t->sighand->siglock); 140 sigfillset(¤t->blocked); 141 recalc_sigpending(); 142 spin_unlock_irq(¤t->sighand->siglock); 143 msleep_interruptible(jiffies_to_msecs(delay)); 144 145 spin_lock_irq(¤t->sighand->siglock); 146 current->blocked = oldblocked; 147 recalc_sigpending(); 148 spin_unlock_irq(¤t->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