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