linux/drivers/media/video/saa5249.c
<<
>>
Prefs
   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 1998/03/30 22:23:23 alan 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    msecs_to_jiffies(300)      /* Time between requesting page and */
  90                                                /* checking status bits */
  91#define PGBUF_EXPIRE msecs_to_jiffies(15000)    /* 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   msecs_to_jiffies(50)      /* Time required to clear a page */
 119#define READY_TIMEOUT msecs_to_jiffies(30)      /* Time to wait for ready signal of I2C-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(&current->sighand->siglock);
 253        sigfillset(&current->blocked);
 254        recalc_sigpending();
 255        spin_unlock_irq(&current->sighand->siglock);
 256        msleep_interruptible(jiffies_to_msecs(delay));
 257
 258        spin_lock_irq(&current->sighand->siglock);
 259        current->blocked = oldblocked;
 260        recalc_sigpending();
 261        spin_unlock_irq(&current->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
 292        va_end(argp);
 293        return i2c_sendbuf(t, buf[0], ct-1, buf+1);
 294}
 295
 296/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
 297 * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
 298 * sending of data. If uaccess is 'true', data is written to user-space with put_user.
 299 * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
 300 */
 301
 302static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
 303{
 304        if(i2c_master_recv(t->client, buf, count)!=count)
 305                return -1;
 306        return 0;
 307}
 308
 309
 310/*
 311 *      Standard character-device-driver functions
 312 */
 313
 314static int do_saa5249_ioctl(struct inode *inode, struct file *file,
 315                            unsigned int cmd, void *arg)
 316{
 317        static int virtual_mode = false;
 318        struct video_device *vd = video_devdata(file);
 319        struct saa5249_device *t=vd->priv;
 320
 321        switch(cmd)
 322        {
 323                case VTXIOCGETINFO:
 324                {
 325                        vtx_info_t *info = arg;
 326                        info->version_major = VTX_VER_MAJ;
 327                        info->version_minor = VTX_VER_MIN;
 328                        info->numpages = NUM_DAUS;
 329                        /*info->cct_type = CCT_TYPE;*/
 330                        return 0;
 331                }
 332
 333                case VTXIOCCLRPAGE:
 334                {
 335                        vtx_pagereq_t *req = arg;
 336
 337                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
 338                                return -EINVAL;
 339                        memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
 340                        t->vdau[req->pgbuf].clrfound = true;
 341                        return 0;
 342                }
 343
 344                case VTXIOCCLRFOUND:
 345                {
 346                        vtx_pagereq_t *req = arg;
 347
 348                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
 349                                return -EINVAL;
 350                        t->vdau[req->pgbuf].clrfound = true;
 351                        return 0;
 352                }
 353
 354                case VTXIOCPAGEREQ:
 355                {
 356                        vtx_pagereq_t *req = arg;
 357                        if (!(req->pagemask & PGMASK_PAGE))
 358                                req->page = 0;
 359                        if (!(req->pagemask & PGMASK_HOUR))
 360                                req->hour = 0;
 361                        if (!(req->pagemask & PGMASK_MINUTE))
 362                                req->minute = 0;
 363                        if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
 364                                return -EINVAL;
 365                        req->page &= 0x7ff;
 366                        if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
 367                                req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
 368                                return -EINVAL;
 369                        t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
 370                        t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
 371                        t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
 372                        t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
 373                        t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
 374                        t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
 375                        t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
 376                        t->vdau[req->pgbuf].stopped = false;
 377                        t->vdau[req->pgbuf].clrfound = true;
 378                        t->is_searching[req->pgbuf] = true;
 379                        return 0;
 380                }
 381
 382                case VTXIOCGETSTAT:
 383                {
 384                        vtx_pagereq_t *req = arg;
 385                        u8 infobits[10];
 386                        vtx_pageinfo_t info;
 387                        int a;
 388
 389                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
 390                                return -EINVAL;
 391                        if (!t->vdau[req->pgbuf].stopped)
 392                        {
 393                                if (i2c_senddata(t, 2, 0, -1) ||
 394                                        i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
 395                                        i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
 396                                        i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
 397                                        i2c_senddata(t, 8, 0, 25, 0, -1))
 398                                        return -EIO;
 399                                jdelay(PAGE_WAIT);
 400                                if (i2c_getdata(t, 10, infobits))
 401                                        return -EIO;
 402
 403                                if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&   /* check FOUND-bit */
 404                                        (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
 405                                        time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
 406                                {               /* check if new page arrived */
 407                                        if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
 408                                                i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
 409                                                return -EIO;
 410                                        t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
 411                                        memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
 412                                        if (t->virtual_mode)
 413                                        {
 414                                                /* Packet X/24 */
 415                                                if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
 416                                                        i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
 417                                                        return -EIO;
 418                                                /* Packet X/27/0 */
 419                                                if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
 420                                                        i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
 421                                                        return -EIO;
 422                                                /* Packet 8/30/0...8/30/15
 423                                                 * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
 424                                                 *        so we should undo this here.
 425                                                 */
 426                                                if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
 427                                                        i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
 428                                                        return -EIO;
 429                                        }
 430                                        t->vdau[req->pgbuf].clrfound = false;
 431                                        memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
 432                                }
 433                                else
 434                                {
 435                                        memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
 436                                }
 437                        }
 438                        else
 439                        {
 440                                memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
 441                        }
 442
 443                        info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
 444                        if (info.pagenum < 0x100)
 445                                info.pagenum += 0x800;
 446                        info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
 447                        info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
 448                        info.charset = ((infobits[7] >> 1) & 7);
 449                        info.delete = !!(infobits[3] & 8);
 450                        info.headline = !!(infobits[5] & 4);
 451                        info.subtitle = !!(infobits[5] & 8);
 452                        info.supp_header = !!(infobits[6] & 1);
 453                        info.update = !!(infobits[6] & 2);
 454                        info.inter_seq = !!(infobits[6] & 4);
 455                        info.dis_disp = !!(infobits[6] & 8);
 456                        info.serial = !!(infobits[7] & 1);
 457                        info.notfound = !!(infobits[8] & 0x10);
 458                        info.pblf = !!(infobits[9] & 0x20);
 459                        info.hamming = 0;
 460                        for (a = 0; a <= 7; a++)
 461                        {
 462                                if (infobits[a] & 0xf0)
 463                                {
 464                                        info.hamming = 1;
 465                                        break;
 466                                }
 467                        }
 468                        if (t->vdau[req->pgbuf].clrfound)
 469                                info.notfound = 1;
 470                        if(copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
 471                                return -EFAULT;
 472                        if (!info.hamming && !info.notfound)
 473                        {
 474                                t->is_searching[req->pgbuf] = false;
 475                        }
 476                        return 0;
 477                }
 478
 479                case VTXIOCGETPAGE:
 480                {
 481                        vtx_pagereq_t *req = arg;
 482                        int start, end;
 483
 484                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
 485                                req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
 486                                return -EINVAL;
 487                        if(copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
 488                                return -EFAULT;
 489
 490                         /*
 491                          *     Always read the time directly from SAA5249
 492                          */
 493
 494                        if (req->start <= 39 && req->end >= 32)
 495                        {
 496                                int len;
 497                                char buf[16];
 498                                start = max(req->start, 32);
 499                                end = min(req->end, 39);
 500                                len=end-start+1;
 501                                if (i2c_senddata(t, 8, 0, 0, start, -1) ||
 502                                        i2c_getdata(t, len, buf))
 503                                        return -EIO;
 504                                if(copy_to_user(req->buffer+start-req->start, buf, len))
 505                                        return -EFAULT;
 506                        }
 507                        /* Insert the current header if DAU is still searching for a page */
 508                        if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf])
 509                        {
 510                                char buf[32];
 511                                int len;
 512                                start = max(req->start, 7);
 513                                end = min(req->end, 31);
 514                                len=end-start+1;
 515                                if (i2c_senddata(t, 8, 0, 0, start, -1) ||
 516                                        i2c_getdata(t, len, buf))
 517                                        return -EIO;
 518                                if(copy_to_user(req->buffer+start-req->start, buf, len))
 519                                        return -EFAULT;
 520                        }
 521                        return 0;
 522                }
 523
 524                case VTXIOCSTOPDAU:
 525                {
 526                        vtx_pagereq_t *req = arg;
 527
 528                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
 529                                return -EINVAL;
 530                        t->vdau[req->pgbuf].stopped = true;
 531                        t->is_searching[req->pgbuf] = false;
 532                        return 0;
 533                }
 534
 535                case VTXIOCPUTPAGE:
 536                case VTXIOCSETDISP:
 537                case VTXIOCPUTSTAT:
 538                        return 0;
 539
 540                case VTXIOCCLRCACHE:
 541                {
 542                        if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
 543                                ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
 544                                ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1))
 545                                return -EIO;
 546                        if (i2c_senddata(t, 3, 0x20, -1))
 547                                return -EIO;
 548                        jdelay(10 * CLEAR_DELAY);                       /* I have no idea how long we have to wait here */
 549                        return 0;
 550                }
 551
 552                case VTXIOCSETVIRT:
 553                {
 554                        /* The SAA5249 has virtual-row reception turned on always */
 555                        t->virtual_mode = (int)(long)arg;
 556                        return 0;
 557                }
 558        }
 559        return -EINVAL;
 560}
 561
 562/*
 563 * Translates old vtx IOCTLs to new ones
 564 *
 565 * This keeps new kernel versions compatible with old userspace programs.
 566 */
 567static inline unsigned int vtx_fix_command(unsigned int cmd)
 568{
 569        switch (cmd) {
 570        case VTXIOCGETINFO_OLD:
 571                cmd = VTXIOCGETINFO;
 572                break;
 573        case VTXIOCCLRPAGE_OLD:
 574                cmd = VTXIOCCLRPAGE;
 575                break;
 576        case VTXIOCCLRFOUND_OLD:
 577                cmd = VTXIOCCLRFOUND;
 578                break;
 579        case VTXIOCPAGEREQ_OLD:
 580                cmd = VTXIOCPAGEREQ;
 581                break;
 582        case VTXIOCGETSTAT_OLD:
 583                cmd = VTXIOCGETSTAT;
 584                break;
 585        case VTXIOCGETPAGE_OLD:
 586                cmd = VTXIOCGETPAGE;
 587                break;
 588        case VTXIOCSTOPDAU_OLD:
 589                cmd = VTXIOCSTOPDAU;
 590                break;
 591        case VTXIOCPUTPAGE_OLD:
 592                cmd = VTXIOCPUTPAGE;
 593                break;
 594        case VTXIOCSETDISP_OLD:
 595                cmd = VTXIOCSETDISP;
 596                break;
 597        case VTXIOCPUTSTAT_OLD:
 598                cmd = VTXIOCPUTSTAT;
 599                break;
 600        case VTXIOCCLRCACHE_OLD:
 601                cmd = VTXIOCCLRCACHE;
 602                break;
 603        case VTXIOCSETVIRT_OLD:
 604                cmd = VTXIOCSETVIRT;
 605                break;
 606        }
 607        return cmd;
 608}
 609
 610/*
 611 *      Handle the locking
 612 */
 613
 614static int saa5249_ioctl(struct inode *inode, struct file *file,
 615                         unsigned int cmd, unsigned long arg)
 616{
 617        struct video_device *vd = video_devdata(file);
 618        struct saa5249_device *t=vd->priv;
 619        int err;
 620
 621        cmd = vtx_fix_command(cmd);
 622        mutex_lock(&t->lock);
 623        err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
 624        mutex_unlock(&t->lock);
 625        return err;
 626}
 627
 628static int saa5249_open(struct inode *inode, struct file *file)
 629{
 630        struct video_device *vd = video_devdata(file);
 631        struct saa5249_device *t=vd->priv;
 632        int err,pgbuf;
 633
 634        err = video_exclusive_open(inode,file);
 635        if (err < 0)
 636                return err;
 637
 638        if (t->client==NULL) {
 639                err = -ENODEV;
 640                goto fail;
 641        }
 642
 643        if (i2c_senddata(t, 0, 0, -1) ||                /* Select R11 */
 644                                                /* Turn off parity checks (we do this ourselves) */
 645                i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
 646                                                /* Display TV-picture, no virtual rows */
 647                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 */
 648
 649        {
 650                err = -EIO;
 651                goto fail;
 652        }
 653
 654        for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
 655        {
 656                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
 657                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
 658                memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
 659                t->vdau[pgbuf].expire = 0;
 660                t->vdau[pgbuf].clrfound = true;
 661                t->vdau[pgbuf].stopped = true;
 662                t->is_searching[pgbuf] = false;
 663        }
 664        t->virtual_mode = false;
 665        return 0;
 666
 667 fail:
 668        video_exclusive_release(inode,file);
 669        return err;
 670}
 671
 672
 673
 674static int saa5249_release(struct inode *inode, struct file *file)
 675{
 676        struct video_device *vd = video_devdata(file);
 677        struct saa5249_device *t=vd->priv;
 678        i2c_senddata(t, 1, 0x20, -1);           /* Turn off CCT */
 679        i2c_senddata(t, 5, 3, 3, -1);           /* Turn off TV-display */
 680        video_exclusive_release(inode,file);
 681        return 0;
 682}
 683
 684static int __init init_saa_5249 (void)
 685{
 686        printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n",
 687                        VTX_VER_MAJ, VTX_VER_MIN);
 688        return i2c_add_driver(&i2c_driver_videotext);
 689}
 690
 691static void __exit cleanup_saa_5249 (void)
 692{
 693        i2c_del_driver(&i2c_driver_videotext);
 694}
 695
 696module_init(init_saa_5249);
 697module_exit(cleanup_saa_5249);
 698
 699static const struct file_operations saa_fops = {
 700        .owner          = THIS_MODULE,
 701        .open           = saa5249_open,
 702        .release        = saa5249_release,
 703        .ioctl          = saa5249_ioctl,
 704        .compat_ioctl   = v4l_compat_ioctl32,
 705        .llseek         = no_llseek,
 706};
 707
 708static struct video_device saa_template =
 709{
 710        .owner          = THIS_MODULE,
 711        .name           = IF_NAME,
 712        .type           = VID_TYPE_TELETEXT,    /*| VID_TYPE_TUNER ?? */
 713        .fops           = &saa_fops,
 714};
 715
 716MODULE_LICENSE("GPL");
 717