patch-2.4.25 linux-2.4.25/drivers/media/video/saa7191.c
Next file: linux-2.4.25/drivers/media/video/saa7191.h
Previous file: linux-2.4.25/drivers/media/video/saa7146.h
Back to the patch index
Back to the overall index
- Lines: 321
- Date:
2004-02-18 05:36:31.000000000 -0800
- Orig file:
linux-2.4.24/drivers/media/video/saa7191.c
- Orig date:
1969-12-31 16:00:00.000000000 -0800
diff -urN linux-2.4.24/drivers/media/video/saa7191.c linux-2.4.25/drivers/media/video/saa7191.c
@@ -0,0 +1,320 @@
+/*
+ * saa7191 - Philips SAA7191 video decoder driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "saa7191.h"
+
+#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct saa7191 {
+ struct i2c_client *client;
+ unsigned char reg[25];
+ unsigned char norm;
+ unsigned char input;
+ unsigned char bright;
+ unsigned char contrast;
+ unsigned char hue;
+ unsigned char sat;
+};
+
+static struct i2c_driver i2c_driver_saa7191;
+
+static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ static const unsigned char initseq[] = {
+ 0,
+ 0x50, /* SAA7191_REG_IDEL */
+ 0x30, /* SAA7191_REG_HSYB */
+ 0x00, /* SAA7191_REG_HSYS */
+ 0xe8, /* SAA7191_REG_HCLB */
+ 0xb6, /* SAA7191_REG_HCLS */
+ 0xf4, /* SAA7191_REG_HPHI */
+ 0x01, /* SAA7191_REG_LUMA */
+ 0x00, /* SAA7191_REG_HUEC */
+ 0xf8, /* SAA7191_REG_CKTQ */
+ 0xf8, /* SAA7191_REG_CKTS */
+ 0x90, /* SAA7191_REG_PLSE */
+ 0x90, /* SAA7191_REG_SESE */
+ 0x00, /* SAA7191_REG_GAIN */
+ 0x8c, /* SAA7191_REG_STDC */
+ 0x78, /* SAA7191_REG_IOCK */
+ 0x99, /* SAA7191_REG_CTL3 */
+ 0x00, /* SAA7191_REG_CTL4 */
+ 0x2c, /* SAA7191_REG_CHCV */
+ 0x00, /* unused */
+ 0x00, /* unused */
+ 0x34, /* SAA7191_REG_HS6B */
+ 0x0a, /* SAA7191_REG_HS6S */
+ 0xf4, /* SAA7191_REG_HC6B */
+ 0xce, /* SAA7191_REG_HC6S */
+ 0xf4, /* SAA7191_REG_HP6I */
+ };
+ int err = 0;
+ struct saa7191 *decoder;
+ struct i2c_client *client;
+
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder) {
+ err = -ENOMEM;
+ goto out_free_client;
+ }
+ client->data = decoder;
+ client->adapter = adap;
+ client->addr = addr;
+ client->driver = &i2c_driver_saa7191;
+ strcpy(client->name, "saa7191 client");
+ decoder->client = client;
+
+ err = i2c_attach_client(client);
+ if (err)
+ goto out_free_decoder;
+
+ decoder->norm = VIDEO_DECODER_PAL | VIDEO_MODE_NTSC |
+ VIDEO_DECODER_AUTO;
+ decoder->input = 0;
+ /* Registers are 8bit wide and we are storing shifted values */
+ decoder->bright = 128;
+ decoder->contrast = 128;
+ decoder->hue = 128;
+ decoder->sat = 128;
+
+ memcpy(decoder->reg, initseq, sizeof(initseq));
+ err = i2c_master_send(client, initseq, sizeof(initseq));
+ if (err)
+ printk(KERN_INFO "saa7191 initialization failed (%d)\n", err);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+
+out_free_decoder:
+ kfree(decoder);
+out_free_client:
+ kfree(client);
+ return err;
+}
+
+static int saa7191_probe(struct i2c_adapter *adap)
+{
+ /* Always connected to VINO */
+ if (adap->id == VINO_ADAPTER)
+ return saa7191_attach(adap, SAA7191_ADDR, 0);
+ /* Feel free to add probe here :-) */
+ return -ENODEV;
+}
+
+static int saa7191_detach(struct i2c_client *client)
+{
+ struct saa7191 *decoder = client->data;
+
+ i2c_detach_client(client);
+ kfree(decoder);
+ kfree(client);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static unsigned char saa7191_read(struct i2c_client *client,
+ unsigned char command)
+{
+ return ((struct saa7191 *)client->data)->reg[command];
+}
+
+static int saa7191_write(struct i2c_client *client, unsigned char command,
+ unsigned char value)
+{
+ ((struct saa7191 *)client->data)->reg[command] = value;
+ return i2c_smbus_write_byte_data(client, command, value);
+}
+
+static int vino_set_input(struct i2c_client *client, int val)
+{
+ unsigned char luma = saa7191_read(client, SAA7191_REG_LUMA);
+ unsigned char iock = saa7191_read(client, SAA7191_REG_IOCK);
+
+ switch (val) {
+ case 0: /* Set Composite input */
+ iock &= ~0x03;
+ /* Chrominance trap active */
+ luma |= ~SAA7191_LUMA_BYPS;
+ break;
+ case 1: /* Set S-Video input */
+ iock |= 2;
+ /* Chrominance trap bypassed */
+ luma |= SAA7191_LUMA_BYPS;
+ break;
+ default:
+ return -EINVAL;
+ }
+ saa7191_write(client, SAA7191_REG_LUMA, luma);
+ saa7191_write(client, SAA7191_REG_IOCK, iock);
+
+ return 0;
+}
+
+static int saa7191_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct saa7191 *decoder = client->data;
+
+ switch (cmd) {
+
+ case DECODER_GET_CAPABILITIES: {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_AUTO;
+ cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS: {
+ int *iarg = arg;
+ int status;
+ int res = 0;
+
+ status = i2c_smbus_read_byte_data(client, SAA7191_REG_STATUS);
+ if ((status & SAA7191_STATUS_HLCK) == 0)
+ res |= DECODER_STATUS_GOOD;
+ switch (decoder->norm) {
+ case VIDEO_MODE_NTSC:
+ res |= DECODER_STATUS_NTSC;
+ break;
+ case VIDEO_MODE_PAL:
+ res |= DECODER_STATUS_PAL;
+ break;
+ case VIDEO_MODE_AUTO:
+ default:
+ if (status & SAA7191_STATUS_FIDT)
+ res |= DECODER_STATUS_NTSC;
+ else
+ res |= DECODER_STATUS_PAL;
+ if (status & SAA7191_STATUS_CODE)
+ res |= DECODER_STATUS_COLOR;
+ break;
+ }
+ *iarg = res;
+ break;
+ }
+ case DECODER_SET_NORM: {
+ int *iarg = arg;
+
+ switch (*iarg) {
+ case VIDEO_MODE_NTSC:
+ break;
+ case VIDEO_MODE_PAL:
+ break;
+ default:
+ return -EINVAL;
+ }
+ decoder->norm = *iarg;
+ break;
+ }
+ case DECODER_SET_INPUT: {
+ int *iarg = arg;
+
+ switch (client->adapter->id) {
+ case VINO_ADAPTER:
+ return vino_set_input(client, *iarg);
+ default:
+ if (*iarg != 0)
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_OUTPUT: {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT: {
+ /* Always enabled */
+ break;
+ }
+ case DECODER_SET_PICTURE: {
+ struct video_picture *pic = arg;
+ unsigned val;
+#if 0
+ /* TODO */
+ val = pic->brightness >> 8;
+ if (decoder->bright != val) {
+ decoder->bright = val;
+ i2c_smbus_write_byte_data(client, XXX, val);
+ }
+ val = pic->contrast >> 8;
+ if (decoder->contrast != val) {
+ decoder->contrast = val;
+ i2c_smbus_write_byte_data(client, XXX, val);
+ }
+ val = pic->colour >> 8;
+ if (decoder->sat != val) {
+ decoder->sat = val;
+ i2c_smbus_write_byte_data(client, XXX, val);
+ }
+#endif
+ val = (pic->hue >> 8) - 0x80;
+ if (decoder->hue != val) {
+ decoder->hue = val;
+ i2c_smbus_write_byte_data(client, SAA7191_REG_HUEC,
+ val);
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver i2c_driver_saa7191 = {
+ .name = "saa7191",
+ .id = I2C_DRIVERID_SAA7191,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7191_probe,
+ .detach_client = saa7191_detach,
+ .command = saa7191_command
+};
+
+static int saa7191_init(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7191);
+}
+
+static void saa7191_exit(void)
+{
+ i2c_del_driver(&i2c_driver_saa7191);
+}
+
+module_init(saa7191_init);
+module_exit(saa7191_exit);
+
+MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
+MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
+MODULE_LICENSE("GPL");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)