cd354f1ae7
After Al Viro (finally) succeeded in removing the sched.h #include in module.h recently, it makes sense again to remove other superfluous sched.h includes. There are quite a lot of files which include it but don't actually need anything defined in there. Presumably these includes were once needed for macros that used to live in sched.h, but moved to other header files in the course of cleaning it up. To ease the pain, this time I did not fiddle with any header files and only removed #includes from .c-files, which tend to cause less trouble. Compile tested against 2.6.20-rc2 and 2.6.20-rc2-mm2 (with offsets) on alpha, arm, i386, ia64, mips, powerpc, and x86_64 with allnoconfig, defconfig, allmodconfig, and allyesconfig as well as a few randconfigs on x86_64 and all configs in arch/arm/configs on arm. I also checked that no new warnings were introduced by the patch (actually, some warnings are removed that were emitted by unnecessarily included header files). Signed-off-by: Tim Schmielau <tim@physik3.uni-rostock.de> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
470 lines
10 KiB
C
470 lines
10 KiB
C
/*
|
|
* indycam.c - Silicon Graphics IndyCam digital camera driver
|
|
*
|
|
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
|
|
* Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
|
|
*
|
|
* 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/delay.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/major.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/videodev.h>
|
|
/* IndyCam decodes stream of photons into digital image representation ;-) */
|
|
#include <linux/video_decoder.h>
|
|
#include <linux/i2c.h>
|
|
|
|
#include "indycam.h"
|
|
|
|
#define INDYCAM_MODULE_VERSION "0.0.5"
|
|
|
|
MODULE_DESCRIPTION("SGI IndyCam driver");
|
|
MODULE_VERSION(INDYCAM_MODULE_VERSION);
|
|
MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
// #define INDYCAM_DEBUG
|
|
|
|
#ifdef INDYCAM_DEBUG
|
|
#define dprintk(x...) printk("IndyCam: " x);
|
|
#define indycam_regdump(client) indycam_regdump_debug(client)
|
|
#else
|
|
#define dprintk(x...)
|
|
#define indycam_regdump(client)
|
|
#endif
|
|
|
|
struct indycam {
|
|
struct i2c_client *client;
|
|
u8 version;
|
|
};
|
|
|
|
static struct i2c_driver i2c_driver_indycam;
|
|
|
|
static const u8 initseq[] = {
|
|
INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
|
|
INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */
|
|
INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
|
|
0x00, /* INDYCAM_BRIGHTNESS (read-only) */
|
|
INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
|
|
INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */
|
|
INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
|
|
INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
|
|
};
|
|
|
|
/* IndyCam register handling */
|
|
|
|
static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
|
|
{
|
|
int ret;
|
|
|
|
if (reg == INDYCAM_REG_RESET) {
|
|
dprintk("indycam_read_reg(): "
|
|
"skipping write-only register %d\n", reg);
|
|
*value = 0;
|
|
return 0;
|
|
}
|
|
|
|
ret = i2c_smbus_read_byte_data(client, reg);
|
|
|
|
if (ret < 0) {
|
|
printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
|
|
"register = 0x%02x\n", reg);
|
|
return ret;
|
|
}
|
|
|
|
*value = (u8)ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
|
|
{
|
|
int err;
|
|
|
|
if ((reg == INDYCAM_REG_BRIGHTNESS)
|
|
|| (reg == INDYCAM_REG_VERSION)) {
|
|
dprintk("indycam_write_reg(): "
|
|
"skipping read-only register %d\n", reg);
|
|
return 0;
|
|
}
|
|
|
|
dprintk("Writing Reg %d = 0x%02x\n", reg, value);
|
|
err = i2c_smbus_write_byte_data(client, reg, value);
|
|
|
|
if (err) {
|
|
printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
|
|
"register = 0x%02x, value = 0x%02x\n", reg, value);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static int indycam_write_block(struct i2c_client *client, u8 reg,
|
|
u8 length, u8 *data)
|
|
{
|
|
int i, err;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
err = indycam_write_reg(client, reg + i, data[i]);
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Helper functions */
|
|
|
|
#ifdef INDYCAM_DEBUG
|
|
static void indycam_regdump_debug(struct i2c_client *client)
|
|
{
|
|
int i;
|
|
u8 val;
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
indycam_read_reg(client, i, &val);
|
|
dprintk("Reg %d = 0x%02x\n", i, val);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int indycam_get_control(struct i2c_client *client,
|
|
struct indycam_control *ctrl)
|
|
{
|
|
struct indycam *camera = i2c_get_clientdata(client);
|
|
u8 reg;
|
|
int ret = 0;
|
|
|
|
switch (ctrl->type) {
|
|
case INDYCAM_CONTROL_AGC:
|
|
case INDYCAM_CONTROL_AWB:
|
|
ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
if (ctrl->type == INDYCAM_CONTROL_AGC)
|
|
ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
|
|
? 1 : 0;
|
|
else
|
|
ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
|
|
? 1 : 0;
|
|
break;
|
|
case INDYCAM_CONTROL_SHUTTER:
|
|
ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
|
|
break;
|
|
case INDYCAM_CONTROL_GAIN:
|
|
ret = indycam_read_reg(client, INDYCAM_REG_GAIN, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = (s32)reg;
|
|
break;
|
|
case INDYCAM_CONTROL_RED_BALANCE:
|
|
ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = (s32)reg;
|
|
break;
|
|
case INDYCAM_CONTROL_BLUE_BALANCE:
|
|
ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = (s32)reg;
|
|
break;
|
|
case INDYCAM_CONTROL_RED_SATURATION:
|
|
ret = indycam_read_reg(client,
|
|
INDYCAM_REG_RED_SATURATION, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = (s32)reg;
|
|
break;
|
|
case INDYCAM_CONTROL_BLUE_SATURATION:
|
|
ret = indycam_read_reg(client,
|
|
INDYCAM_REG_BLUE_SATURATION, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = (s32)reg;
|
|
break;
|
|
case INDYCAM_CONTROL_GAMMA:
|
|
if (camera->version == CAMERA_VERSION_MOOSE) {
|
|
ret = indycam_read_reg(client,
|
|
INDYCAM_REG_GAMMA, ®);
|
|
if (ret)
|
|
return -EIO;
|
|
ctrl->value = (s32)reg;
|
|
} else {
|
|
ctrl->value = INDYCAM_GAMMA_DEFAULT;
|
|
}
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int indycam_set_control(struct i2c_client *client,
|
|
struct indycam_control *ctrl)
|
|
{
|
|
struct indycam *camera = i2c_get_clientdata(client);
|
|
u8 reg;
|
|
int ret = 0;
|
|
|
|
switch (ctrl->type) {
|
|
case INDYCAM_CONTROL_AGC:
|
|
case INDYCAM_CONTROL_AWB:
|
|
ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®);
|
|
if (ret)
|
|
break;
|
|
|
|
if (ctrl->type == INDYCAM_CONTROL_AGC) {
|
|
if (ctrl->value)
|
|
reg |= INDYCAM_CONTROL_AGCENA;
|
|
else
|
|
reg &= ~INDYCAM_CONTROL_AGCENA;
|
|
} else {
|
|
if (ctrl->value)
|
|
reg |= INDYCAM_CONTROL_AWBCTL;
|
|
else
|
|
reg &= ~INDYCAM_CONTROL_AWBCTL;
|
|
}
|
|
|
|
ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg);
|
|
break;
|
|
case INDYCAM_CONTROL_SHUTTER:
|
|
reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
|
|
ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg);
|
|
break;
|
|
case INDYCAM_CONTROL_GAIN:
|
|
ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value);
|
|
break;
|
|
case INDYCAM_CONTROL_RED_BALANCE:
|
|
ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE,
|
|
ctrl->value);
|
|
break;
|
|
case INDYCAM_CONTROL_BLUE_BALANCE:
|
|
ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE,
|
|
ctrl->value);
|
|
break;
|
|
case INDYCAM_CONTROL_RED_SATURATION:
|
|
ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION,
|
|
ctrl->value);
|
|
break;
|
|
case INDYCAM_CONTROL_BLUE_SATURATION:
|
|
ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION,
|
|
ctrl->value);
|
|
break;
|
|
case INDYCAM_CONTROL_GAMMA:
|
|
if (camera->version == CAMERA_VERSION_MOOSE) {
|
|
ret = indycam_write_reg(client, INDYCAM_REG_GAMMA,
|
|
ctrl->value);
|
|
}
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* I2C-interface */
|
|
|
|
static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
|
|
{
|
|
int err = 0;
|
|
struct indycam *camera;
|
|
struct i2c_client *client;
|
|
|
|
printk(KERN_INFO "SGI IndyCam driver version %s\n",
|
|
INDYCAM_MODULE_VERSION);
|
|
|
|
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
|
if (!client)
|
|
return -ENOMEM;
|
|
camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
|
|
if (!camera) {
|
|
err = -ENOMEM;
|
|
goto out_free_client;
|
|
}
|
|
|
|
client->addr = addr;
|
|
client->adapter = adap;
|
|
client->driver = &i2c_driver_indycam;
|
|
client->flags = 0;
|
|
strcpy(client->name, "IndyCam client");
|
|
i2c_set_clientdata(client, camera);
|
|
|
|
camera->client = client;
|
|
|
|
err = i2c_attach_client(client);
|
|
if (err)
|
|
goto out_free_camera;
|
|
|
|
camera->version = i2c_smbus_read_byte_data(client,
|
|
INDYCAM_REG_VERSION);
|
|
if (camera->version != CAMERA_VERSION_INDY &&
|
|
camera->version != CAMERA_VERSION_MOOSE) {
|
|
err = -ENODEV;
|
|
goto out_detach_client;
|
|
}
|
|
printk(KERN_INFO "IndyCam v%d.%d detected\n",
|
|
INDYCAM_VERSION_MAJOR(camera->version),
|
|
INDYCAM_VERSION_MINOR(camera->version));
|
|
|
|
indycam_regdump(client);
|
|
|
|
// initialize
|
|
err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
|
|
if (err) {
|
|
printk(KERN_ERR "IndyCam initalization failed\n");
|
|
err = -EIO;
|
|
goto out_detach_client;
|
|
}
|
|
|
|
indycam_regdump(client);
|
|
|
|
// white balance
|
|
err = indycam_write_reg(client, INDYCAM_REG_CONTROL,
|
|
INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
|
|
if (err) {
|
|
printk(KERN_ERR "IndyCam: White balancing camera failed\n");
|
|
err = -EIO;
|
|
goto out_detach_client;
|
|
}
|
|
|
|
indycam_regdump(client);
|
|
|
|
printk(KERN_INFO "IndyCam initialized\n");
|
|
|
|
return 0;
|
|
|
|
out_detach_client:
|
|
i2c_detach_client(client);
|
|
out_free_camera:
|
|
kfree(camera);
|
|
out_free_client:
|
|
kfree(client);
|
|
return err;
|
|
}
|
|
|
|
static int indycam_probe(struct i2c_adapter *adap)
|
|
{
|
|
/* Indy specific crap */
|
|
if (adap->id == I2C_HW_SGI_VINO)
|
|
return indycam_attach(adap, INDYCAM_ADDR, 0);
|
|
/* Feel free to add probe here :-) */
|
|
return -ENODEV;
|
|
}
|
|
|
|
static int indycam_detach(struct i2c_client *client)
|
|
{
|
|
struct indycam *camera = i2c_get_clientdata(client);
|
|
|
|
i2c_detach_client(client);
|
|
kfree(camera);
|
|
kfree(client);
|
|
return 0;
|
|
}
|
|
|
|
static int indycam_command(struct i2c_client *client, unsigned int cmd,
|
|
void *arg)
|
|
{
|
|
// struct indycam *camera = i2c_get_clientdata(client);
|
|
|
|
/* The old video_decoder interface just isn't enough,
|
|
* so we'll use some custom commands. */
|
|
switch (cmd) {
|
|
case DECODER_GET_CAPABILITIES: {
|
|
struct video_decoder_capability *cap = arg;
|
|
|
|
cap->flags = VIDEO_DECODER_NTSC;
|
|
cap->inputs = 1;
|
|
cap->outputs = 1;
|
|
break;
|
|
}
|
|
case DECODER_GET_STATUS: {
|
|
int *iarg = arg;
|
|
|
|
*iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
|
|
DECODER_STATUS_COLOR;
|
|
break;
|
|
}
|
|
case DECODER_SET_NORM: {
|
|
int *iarg = arg;
|
|
|
|
switch (*iarg) {
|
|
case VIDEO_MODE_NTSC:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
}
|
|
case DECODER_SET_INPUT: {
|
|
int *iarg = arg;
|
|
|
|
if (*iarg != 0)
|
|
return -EINVAL;
|
|
break;
|
|
}
|
|
case DECODER_SET_OUTPUT: {
|
|
int *iarg = arg;
|
|
|
|
if (*iarg != 0)
|
|
return -EINVAL;
|
|
break;
|
|
}
|
|
case DECODER_ENABLE_OUTPUT: {
|
|
/* Always enabled */
|
|
break;
|
|
}
|
|
case DECODER_SET_PICTURE: {
|
|
// struct video_picture *pic = arg;
|
|
/* TODO: convert values for indycam_set_controls() */
|
|
break;
|
|
}
|
|
case DECODER_INDYCAM_GET_CONTROL: {
|
|
return indycam_get_control(client, arg);
|
|
}
|
|
case DECODER_INDYCAM_SET_CONTROL: {
|
|
return indycam_set_control(client, arg);
|
|
}
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct i2c_driver i2c_driver_indycam = {
|
|
.driver = {
|
|
.name = "indycam",
|
|
},
|
|
.id = I2C_DRIVERID_INDYCAM,
|
|
.attach_adapter = indycam_probe,
|
|
.detach_client = indycam_detach,
|
|
.command = indycam_command,
|
|
};
|
|
|
|
static int __init indycam_init(void)
|
|
{
|
|
return i2c_add_driver(&i2c_driver_indycam);
|
|
}
|
|
|
|
static void __exit indycam_exit(void)
|
|
{
|
|
i2c_del_driver(&i2c_driver_indycam);
|
|
}
|
|
|
|
module_init(indycam_init);
|
|
module_exit(indycam_exit);
|