Commit a6c2ba28 authored by akpm@osdl.org's avatar akpm@osdl.org Committed by Linus Torvalds

[PATCH] v4l: 716: support for em28xx board family

- Added support for em28xx board family
Signed-off-by: default avatarLudovico Cavedon <cavedon@sssup.it>
Signed-off-by: default avatarMarkus Rechberger <mrechberger@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4b017415
/*
em2820-cards.c - driver for Empia EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/usb.h>
#include <media/tuner.h>
#include "audiochip.h"
#include "tveeprom.h"
#include "msp3400.h"
#include "em2820.h"
enum em2820_board_entry {
EM2820_BOARD_TERRATEC_CINERGY_250,
EM2820_BOARD_PINNACLE_USB_2,
EM2820_BOARD_HAUPPAUGE_WINTV_USB_2,
EM2820_BOARD_MSI_VOX_USB_2
};
struct em2820_board em2820_boards[] = {
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
.vchannels = 3,
.norm = VIDEO_MODE_PAL,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM2820_SAA7113,
.input = {{
.type = EM2820_VMUX_TELEVISION,
.vmux = 2,
.amux = 0,
},{
.type = EM2820_VMUX_COMPOSITE1,
.vmux = 0,
.amux = 1,
},{
.type = EM2820_VMUX_SVIDEO,
.vmux = 9,
.amux = 1,
}},
},
[EM2820_BOARD_PINNACLE_USB_2] = {
.name = "Pinnacle PCTV USB 2",
.vchannels = 3,
.norm = VIDEO_MODE_PAL,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM2820_SAA7113,
.input = {{
.type = EM2820_VMUX_TELEVISION,
.vmux = 2,
.amux = 0,
},{
.type = EM2820_VMUX_COMPOSITE1,
.vmux = 0,
.amux = 1,
},{
.type = EM2820_VMUX_SVIDEO,
.vmux = 9,
.amux = 1,
}},
},
[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
.name = "Hauppauge WinTV USB 2",
.vchannels = 3,
.norm = VIDEO_MODE_NTSC,
.tuner_type = TUNER_PHILIPS_FM1236_MK3,
.tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
.has_tuner = 1,
.decoder = EM2820_TVP5150,
.has_msp34xx = 1,
/*FIXME: S-Video not tested */
.input = {{
.type = EM2820_VMUX_TELEVISION,
.vmux = 0,
.amux = 0,
},{
.type = EM2820_VMUX_SVIDEO,
.vmux = 2,
.amux = 1,
}},
},
[EM2820_BOARD_MSI_VOX_USB_2] = {
.name = "MSI VOX USB 2.0",
.vchannels = 3,
.norm = VIDEO_MODE_PAL,
.tuner_type = TUNER_PHILIPS_PAL,
.tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
.has_tuner = 1,
.decoder = EM2820_SAA7114,
.input = {{
.type = EM2820_VMUX_TELEVISION,
.vmux = 2,
.amux = 0,
},{
.type = EM2820_VMUX_COMPOSITE1,
.vmux = 0,
.amux = 1,
},{
.type = EM2820_VMUX_SVIDEO,
.vmux = 9,
.amux = 1,
}},
},
{ } /* Terminating entry */
};
/* table of devices that work with this driver */
struct usb_device_id em2820_id_table [] = {
/* Terratec Cinerhy 200 USB: em2800 nor supported, at the moment */
/* { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_TERRATEC_CINERGY_200 }, */
{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
{ USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
{ },
};
void em2820_card_setup(struct em2820 *dev)
{
/* request some modules */
if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
struct tveeprom tv;
#ifdef CONFIG_MODULES
request_module("tveeprom");
#endif
/* Call first TVeeprom */
tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
dev->tuner_type= tv.tuner_type;
if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
dev->has_msp34xx=1;
} else dev->has_msp34xx=0;
}
}
EXPORT_SYMBOL(em2820_boards);
EXPORT_SYMBOL(em2820_id_table);
MODULE_DEVICE_TABLE (usb, em2820_id_table);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -35,6 +35,47 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
printk(format , ##args); \
} while (0)
/* supported controls */
static struct v4l2_queryctrl tvp5150_qctrl[] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
.maximum = 255,
.step = 1,
.default_value = 0,
.flags = 0,
}, {
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
.maximum = 255,
.step = 0x1,
.default_value = 0x10,
.flags = 0,
}, {
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Saturation",
.minimum = 0,
.maximum = 255,
.step = 0x1,
.default_value = 0x10,
.flags = 0,
}, {
.id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Hue",
.minimum = -128,
.maximum = 127,
.step = 0x1,
.default_value = 0x10,
.flags = 0,
}
};
struct tvp5150 {
struct i2c_client *client;
......@@ -73,7 +114,7 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
buffer[0] = addr;
buffer[1] = value;
dprintk(1,"tvp5150: writing 0x%02x 0x%02x\n",buffer[0],buffer[1]);
dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
if (2 != (rc = i2c_master_send(c, buffer, 2)))
dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
}
......@@ -398,28 +439,11 @@ static inline void tvp5150_selmux(struct i2c_client *c,
enum tvp5150_input input)
{
struct tvp5150 *decoder = i2c_get_clientdata(c);
int tvp_input;
/* FIXME: It is dependent of basic driver */
switch (input)
{
case 2:
tvp_input=TVP5150_ANALOG_CH0;
break;
case 0:
tvp_input=TVP5150_ANALOG_CH1;
break;
case 1:
tvp_input=TVP5150_SVIDEO;
break;
default:
tvp_input=TVP5150_BLACK_SCREEN;
}
if (!decoder->enable)
tvp_input|=TVP5150_BLACK_SCREEN;
input |= TVP5150_BLACK_SCREEN;
tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, tvp_input);
tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
};
static inline void tvp5150_reset(struct i2c_client *c)
......@@ -458,6 +482,50 @@ static inline void tvp5150_reset(struct i2c_client *c)
tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
};
static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
{
/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
return 0;
case V4L2_CID_CONTRAST:
ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
return 0;
case V4L2_CID_SATURATION:
ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
return 0;
case V4L2_CID_HUE:
ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
return 0;
default:
return -EINVAL;
}
}
static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
{
/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
return 0;
case V4L2_CID_CONTRAST:
tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
return 0;
case V4L2_CID_SATURATION:
tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
return 0;
case V4L2_CID_HUE:
tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
return 0;
default:
return -EINVAL;
}
}
/****************************************************************************
I2C Command
****************************************************************************/
......@@ -532,7 +600,7 @@ static int tvp5150_command(struct i2c_client *client,
return -EINVAL;
}
decoder->input=*iarg;
decoder->input = *iarg;
tvp5150_selmux(client, decoder->input);
break;
......@@ -557,28 +625,79 @@ static int tvp5150_command(struct i2c_client *client,
break;
}
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
u8 i, n;
dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
for (i = 0; i < n; i++)
if (qc->id && qc->id == tvp5150_qctrl[i].id) {
memcpy(qc, &(tvp5150_qctrl[i]),
sizeof(*qc));
return 0;
}
return -EINVAL;
}
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
return tvp5150_get_ctrl(client, ctrl);
}
case VIDIOC_S_CTRL_OLD: /* ??? */
case VIDIOC_S_CTRL:
{
struct v4l2_control *ctrl = arg;
u8 i, n;
dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
for (i = 0; i < n; i++)
if (ctrl->id == tvp5150_qctrl[i].id) {
if (ctrl->value <
tvp5150_qctrl[i].minimum
|| ctrl->value >
tvp5150_qctrl[i].maximum)
return -ERANGE;
dprintk(1,
KERN_DEBUG
"VIDIOC_S_CTRL: id=%d, value=%d",
ctrl->id, ctrl->value);
return tvp5150_set_ctrl(client, ctrl);
}
return -EINVAL;
}
case DECODER_SET_PICTURE:
{
struct video_picture *pic = arg;
if (decoder->bright != pic->brightness) {
/* We want 0 to 255 we get 0-65535 */
decoder->bright = pic->brightness;
tvp5150_write(client, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
tvp5150_write(client, TVP5150_BRIGHT_CTL,
decoder->bright >> 8);
}
if (decoder->contrast != pic->contrast) {
/* We want 0 to 255 we get 0-65535 */
decoder->contrast = pic->contrast;
tvp5150_write(client, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
tvp5150_write(client, TVP5150_CONTRAST_CTL,
decoder->contrast >> 8);
}
if (decoder->sat != pic->colour) {
/* We want 0 to 255 we get 0-65535 */
decoder->sat = pic->colour;
tvp5150_write(client, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
tvp5150_write(client, TVP5150_SATURATION_CTL,
decoder->contrast >> 8);
}
if (decoder->hue != pic->hue) {
/* We want -128 to 127 we get 0-65535 */
decoder->hue = pic->hue;
tvp5150_write(client, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
tvp5150_write(client, TVP5150_HUE_CTL,
(decoder->hue - 32768) >> 8);
}
break;
}
......@@ -594,14 +713,13 @@ static int tvp5150_command(struct i2c_client *client,
****************************************************************************/
static struct i2c_driver driver;
static struct i2c_client client_template =
{
static struct i2c_client client_template = {
.name = "(unset)",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
static int tvp5150_detect_client (struct i2c_adapter *adapter,
static int tvp5150_detect_client(struct i2c_adapter *adapter,
int address, int kind)
{
struct i2c_client *client;
......@@ -625,7 +743,7 @@ static int tvp5150_detect_client (struct i2c_adapter *adapter,
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (client == 0)
return -ENOMEM;
memcpy(client,&client_template,sizeof(struct i2c_client));
memcpy(client, &client_template, sizeof(struct i2c_client));
core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
if (core == 0) {
......@@ -651,13 +769,13 @@ static int tvp5150_detect_client (struct i2c_adapter *adapter,
return rv;
}
dump_reg (client);
if (debug > 1)
dump_reg(client);
return 0;
}
static int
tvp5150_attach_adapter (struct i2c_adapter *adapter)
static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
{
dprintk(1,
KERN_INFO
......@@ -666,8 +784,7 @@ tvp5150_attach_adapter (struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
}
static int
tvp5150_detach_client (struct i2c_client *client)
static int tvp5150_detach_client(struct i2c_client *client)
{
struct tvp5150 *decoder = i2c_get_clientdata(client);
int err;
......@@ -699,14 +816,12 @@ static struct i2c_driver driver = {
.command = tvp5150_command,
};
static int __init
tvp5150_init (void)
static int __init tvp5150_init(void)
{
return i2c_add_driver(&driver);
}
static void __exit
tvp5150_exit (void)
static void __exit tvp5150_exit(void)
{
i2c_del_driver(&driver);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment