Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / media / video / saa7111.c
index 4e43ba8..686fd47 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * saa7111 - Philips SAA7111A video decoder driver version 0.0.3
  *
  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
@@ -9,6 +9,9 @@
  * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
  *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
  *
+ * Changes by Michael Hunold <michael@mihu.de>
+ *    - implemented DECODER_SET_GPIO, DECODER_INIT, DECODER_SET_VBI_BYPASS
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -39,7 +42,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 
 #include <linux/videodev.h>
@@ -50,14 +52,13 @@ MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
 #include <linux/i2c.h>
-#include <linux/i2c-dev.h>
 
 #define I2C_NAME(s) (s)->name
 
 #include <linux/video_decoder.h>
 
 static int debug = 0;
-MODULE_PARM(debug, "i");
+module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 #define dprintk(num, format, args...) \
@@ -68,8 +69,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* ----------------------------------------------------------------------- */
 
+#define SAA7111_NR_REG         0x18
+
 struct saa7111 {
-       unsigned char reg[32];
+       unsigned char reg[SAA7111_NR_REG];
 
        int norm;
        int input;
@@ -108,24 +111,21 @@ saa7111_write_block (struct i2c_client *client,
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                /* do raw I2C, not smbus compatible */
                struct saa7111 *decoder = i2c_get_clientdata(client);
-               struct i2c_msg msg;
                u8 block_data[32];
+               int block_len;
 
-               msg.addr = client->addr;
-               msg.flags = client->flags;
                while (len >= 2) {
-                       msg.buf = (char *) block_data;
-                       msg.len = 0;
-                       block_data[msg.len++] = reg = data[0];
+                       block_len = 0;
+                       block_data[block_len++] = reg = data[0];
                        do {
-                               block_data[msg.len++] =
+                               block_data[block_len++] =
                                    decoder->reg[reg++] = data[1];
                                len -= 2;
                                data += 2;
                        } while (len >= 2 && data[0] == reg &&
-                                msg.len < 32);
-                       if ((ret = i2c_transfer(client->adapter,
-                                               &msg, 1)) < 0)
+                                block_len < 32);
+                       if ((ret = i2c_master_send(client, block_data,
+                                                  block_len)) < 0)
                                break;
                }
        } else {
@@ -142,6 +142,13 @@ saa7111_write_block (struct i2c_client *client,
        return ret;
 }
 
+static int
+saa7111_init_decoder (struct i2c_client *client,
+             struct video_decoder_init *init)
+{
+       return saa7111_write_block(client, init->data, init->len);
+}
+
 static inline int
 saa7111_read (struct i2c_client *client,
              u8                 reg)
@@ -151,7 +158,7 @@ saa7111_read (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-static const unsigned char init[] = {
+static const unsigned char saa7111_i2c_init[] = {
        0x00, 0x00,             /* 00 - ID byte */
        0x01, 0x00,             /* 01 - reserved */
 
@@ -201,18 +208,29 @@ saa7111_command (struct i2c_client *client,
        switch (cmd) {
 
        case 0:
-               //saa7111_write_block(client, init, sizeof(init));
                break;
+       case DECODER_INIT:
+       {
+               struct video_decoder_init *init = arg;
+               if (NULL != init)
+                       return saa7111_init_decoder(client, init);
+               else {
+                       struct video_decoder_init vdi;
+                       vdi.data = saa7111_i2c_init;
+                       vdi.len = sizeof(saa7111_i2c_init);
+                       return saa7111_init_decoder(client, &vdi);
+               }
+       }
 
        case DECODER_DUMP:
        {
                int i;
 
-               for (i = 0; i < 32; i += 16) {
+               for (i = 0; i < SAA7111_NR_REG; i += 16) {
                        int j;
 
                        printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
-                       for (j = 0; j < 16; ++j) {
+                       for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) {
                                printk(" %02x",
                                       saa7111_read(client, i + j));
                        }
@@ -274,6 +292,32 @@ saa7111_command (struct i2c_client *client,
        }
                break;
 
+       case DECODER_SET_GPIO:
+       {
+               int *iarg = arg;
+               if (0 != *iarg) {
+                       saa7111_write(client, 0x11,
+                               (decoder->reg[0x11] | 0x80));
+               } else {
+                       saa7111_write(client, 0x11,
+                               (decoder->reg[0x11] & 0x7f));
+               }
+               break;
+       }
+
+       case DECODER_SET_VBI_BYPASS:
+       {
+               int *iarg = arg;
+               if (0 != *iarg) {
+                       saa7111_write(client, 0x13,
+                               (decoder->reg[0x13] & 0xf0) | 0x0a);
+               } else {
+                       saa7111_write(client, 0x13,
+                               (decoder->reg[0x13] & 0xf0));
+               }
+               break;
+       }
+
        case DECODER_SET_NORM:
        {
                int *iarg = arg;
@@ -296,7 +340,7 @@ saa7111_command (struct i2c_client *client,
 
                case VIDEO_MODE_SECAM:
                        saa7111_write(client, 0x08,
-                                     (decoder->reg[0x0e] & 0x3f) | 0x00);
+                                     (decoder->reg[0x08] & 0x3f) | 0x00);
                        saa7111_write(client, 0x0e,
                                      (decoder->reg[0x0e] & 0x8f) | 0x50);
                        break;
@@ -436,25 +480,15 @@ saa7111_command (struct i2c_client *client,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
-                                                                                
+
+static unsigned short ignore = I2C_CLIENT_END;
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
-       .normal_i2c_range       = normal_i2c_range,
-       .probe                  = probe,
-       .probe_range            = probe_range,
-       .ignore                 = ignore,
-       .ignore_range           = ignore_range,
-       .force                  = force
+       .probe                  = &ignore,
+       .ignore                 = &ignore,
 };
 
-static int saa7111_i2c_id = 0;
 static struct i2c_driver i2c_driver_saa7111;
 
 static int
@@ -465,6 +499,7 @@ saa7111_detect_client (struct i2c_adapter *adapter,
        int i;
        struct i2c_client *client;
        struct saa7111 *decoder;
+       struct video_decoder_init vdi;
 
        dprintk(1,
                KERN_INFO
@@ -475,24 +510,19 @@ saa7111_detect_client (struct i2c_adapter *adapter,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return 0;
 
-       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
        if (client == 0)
                return -ENOMEM;
-       memset(client, 0, sizeof(struct i2c_client));
        client->addr = address;
        client->adapter = adapter;
        client->driver = &i2c_driver_saa7111;
-       client->flags = I2C_CLIENT_ALLOW_USE;
-       client->id = saa7111_i2c_id++;
-       snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
-               "saa7111[%d]", client->id);
+       strlcpy(I2C_NAME(client), "saa7111", sizeof(I2C_NAME(client)));
 
-       decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL);
+       decoder = kzalloc(sizeof(struct saa7111), GFP_KERNEL);
        if (decoder == NULL) {
                kfree(client);
                return -ENOMEM;
        }
-       memset(decoder, 0, sizeof(struct saa7111));
        decoder->norm = VIDEO_MODE_NTSC;
        decoder->input = 0;
        decoder->enable = 1;
@@ -509,7 +539,9 @@ saa7111_detect_client (struct i2c_adapter *adapter,
                return i;
        }
 
-       i = saa7111_write_block(client, init, sizeof(init));
+       vdi.data = saa7111_i2c_init;
+       vdi.len = sizeof(saa7111_i2c_init);
+       i = saa7111_init_decoder(client, &vdi);
        if (i < 0) {
                dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
                        I2C_NAME(client), i);
@@ -554,11 +586,11 @@ saa7111_detach_client (struct i2c_client *client)
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_driver i2c_driver_saa7111 = {
-       .owner = THIS_MODULE,
-       .name = "saa7111",
+       .driver = {
+               .name = "saa7111",
+       },
 
        .id = I2C_DRIVERID_SAA7111A,
-       .flags = I2C_DF_NOTIFY,
 
        .attach_adapter = saa7111_attach_adapter,
        .detach_client = saa7111_detach_client,