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