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