Commit b0a83f3c authored by Gerd Knorr's avatar Gerd Knorr Committed by Linus Torvalds

[PATCH] v4l: cx88 driver update

This is a major update of the cx88 driver.  Main new feature is support
for the MPEG PCI function of the cx2388x chips.  The changes in detail:

  * A bunch of code restructions, to allow multiple modules (one per PCI
    function) work on top of the core module.
  * Add a new module with common code for the mpeg PCI function.
  * Add a new module to support mpeg encoder cards (connexant
    "blackbird" reference design).  That one is not much tested yet and
    may have bugs.  They can be easily workarounded by not loading the
    module through, it isn't needed to capture uncompressed video.
  * Add a new module to support DVB cards.  That one is better tested
    than the blackbird one, but it needs additional cutting-edge stuff
    from the dvb project, thats why it is disabled in Kconfig for now.
  * Several cleanups along the way: use kthread, use msleep(), drop some
    2.4.x compatibility code, move insmod options to 2.6 style, ...
  * adapt code to the video-buf changes.
  * suspend fixes.
  * as usual some new tv cards.
Signed-off-by: default avatarGerd Knorr <kraxel@bytesex.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e87c3d55
......@@ -295,6 +295,13 @@ config VIDEO_CX88
To compile this driver as a module, choose M here: the
module will be called cx8800
#config VIDEO_CX88_DVB
# tristate "DVB Support for cx2388x based TV cards"
# depends on VIDEO_CX88 && DVB_CORE
# ---help---
# This adds support for DVB cards based on the
# Connexant 2388x chip.
config VIDEO_OVCAMCHIP
tristate "OmniVision Camera Chip support"
depends on VIDEO_DEV && I2C
......
cx88xx-objs := cx88-cards.o cx88-core.o
cx8800-objs := cx88-video.o cx88-tvaudio.o cx88-i2c.o cx88-vbi.o
cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o
cx8800-objs := cx88-video.o cx88-vbi.o
cx8802-objs := cx88-mpeg.o
obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
EXTRA_CFLAGS = -I$(src)/..
EXTRA_CFLAGS = -I $(src)/.. -I $(srctree)/drivers/media/dvb/dvb-core
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
$Id: cx88-i2c.c,v 1.17 2004/10/11 13:45:51 kraxel Exp $
cx88-i2c.c -- all the i2c code is here
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
......@@ -29,35 +31,46 @@
#include "cx88.h"
static unsigned int i2c_debug = 0;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
static unsigned int i2c_scan = 0;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \
printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
/* ----------------------------------------------------------------------- */
void cx8800_bit_setscl(void *data, int state)
{
struct cx8800_dev *dev = data;
struct cx88_core *core = data;
if (state)
dev->i2c_state |= 0x02;
core->i2c_state |= 0x02;
else
dev->i2c_state &= ~0x02;
cx_write(MO_I2C, dev->i2c_state);
core->i2c_state &= ~0x02;
cx_write(MO_I2C, core->i2c_state);
cx_read(MO_I2C);
}
void cx8800_bit_setsda(void *data, int state)
{
struct cx8800_dev *dev = data;
struct cx88_core *core = data;
if (state)
dev->i2c_state |= 0x01;
core->i2c_state |= 0x01;
else
dev->i2c_state &= ~0x01;
cx_write(MO_I2C, dev->i2c_state);
core->i2c_state &= ~0x01;
cx_write(MO_I2C, core->i2c_state);
cx_read(MO_I2C);
}
static int cx8800_bit_getscl(void *data)
{
struct cx8800_dev *dev = data;
struct cx88_core *core = data;
u32 state;
state = cx_read(MO_I2C);
......@@ -66,7 +79,7 @@ static int cx8800_bit_getscl(void *data)
static int cx8800_bit_getsda(void *data)
{
struct cx8800_dev *dev = data;
struct cx88_core *core = data;
u32 state;
state = cx_read(MO_I2C);
......@@ -75,36 +88,35 @@ static int cx8800_bit_getsda(void *data)
/* ----------------------------------------------------------------------- */
#ifndef I2C_PEC
static void cx8800_inc_use(struct i2c_adapter *adap)
{
MOD_INC_USE_COUNT;
}
static void cx8800_dec_use(struct i2c_adapter *adap)
static int attach_inform(struct i2c_client *client)
{
MOD_DEC_USE_COUNT;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
dprintk(1, "i2c attach [addr=0x%x,client=%s]\n",
client->addr, i2c_clientname(client));
if (!client->driver->command)
return 0;
if (core->tuner_type != UNSET)
client->driver->command(client, TUNER_SET_TYPE, &core->tuner_type);
if (core->tda9887_conf)
client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
return 0;
}
#endif
static int attach_inform(struct i2c_client *client)
static int detach_inform(struct i2c_client *client)
{
struct cx8800_dev *dev = i2c_get_adapdata(client->adapter);
if (dev->tuner_type != UNSET)
cx8800_call_i2c_clients(dev,TUNER_SET_TYPE,&dev->tuner_type);
struct cx88_core *core = i2c_get_adapdata(client->adapter);
if (1 /* fixme: debug */)
printk("%s: i2c attach [client=%s]\n",
dev->name, i2c_clientname(client));
return 0;
dprintk(1, "i2c detach [client=%s]\n", i2c_clientname(client));
return 0;
}
void cx8800_call_i2c_clients(struct cx8800_dev *dev, unsigned int cmd, void *arg)
void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
{
if (0 != dev->i2c_rc)
if (0 != core->i2c_rc)
return;
i2c_clients_command(&dev->i2c_adap, cmd, arg);
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
......@@ -120,18 +132,11 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
/* ----------------------------------------------------------------------- */
static struct i2c_adapter cx8800_i2c_adap_template = {
#ifdef I2C_PEC
.owner = THIS_MODULE,
#else
.inc_use = cx8800_inc_use,
.dec_use = cx8800_dec_use,
#endif
#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
#endif
I2C_DEVNAME("cx2388x"),
.owner = THIS_MODULE,
.id = I2C_HW_B_BT848,
.client_register = attach_inform,
.client_unregister = detach_inform,
};
static struct i2c_client cx8800_i2c_client_template = {
......@@ -139,32 +144,68 @@ static struct i2c_client cx8800_i2c_client_template = {
.id = -1,
};
static char *i2c_devs[128] = {
[ 0x86 >> 1 ] = "tda9887/cx22702",
[ 0xa0 >> 1 ] = "eeprom",
[ 0xc0 >> 1 ] = "tuner (analog)",
[ 0xc2 >> 1 ] = "tuner (analog/dvb)",
};
static void do_i2c_scan(char *name, struct i2c_client *c)
{
unsigned char buf;
int i,rc;
for (i = 0; i < 128; i++) {
c->addr = i;
rc = i2c_master_recv(c,&buf,0);
if (rc < 0)
continue;
printk("%s: i2c scan: found device @ 0x%x [%s]\n",
name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
}
}
/* init + register i2c algo-bit adapter */
int __devinit cx8800_i2c_init(struct cx8800_dev *dev)
int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
{
memcpy(&dev->i2c_adap, &cx8800_i2c_adap_template,
sizeof(dev->i2c_adap));
memcpy(&dev->i2c_algo, &cx8800_i2c_algo_template,
sizeof(dev->i2c_algo));
memcpy(&dev->i2c_client, &cx8800_i2c_client_template,
sizeof(dev->i2c_client));
dev->i2c_adap.dev.parent = &dev->pci->dev;
strlcpy(dev->i2c_adap.name,dev->name,sizeof(dev->i2c_adap.name));
dev->i2c_algo.data = dev;
i2c_set_adapdata(&dev->i2c_adap,dev);
dev->i2c_adap.algo_data = &dev->i2c_algo;
dev->i2c_client.adapter = &dev->i2c_adap;
cx8800_bit_setscl(dev,1);
cx8800_bit_setsda(dev,1);
dev->i2c_rc = i2c_bit_add_bus(&dev->i2c_adap);
printk("%s: i2c register %s\n", dev->name,
(0 == dev->i2c_rc) ? "ok" : "FAILED");
return dev->i2c_rc;
memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
sizeof(core->i2c_adap));
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo));
memcpy(&core->i2c_client, &cx8800_i2c_client_template,
sizeof(core->i2c_client));
if (core->tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
if (cx88_boards[core->board].dvb)
core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap,core);
core->i2c_adap.algo_data = &core->i2c_algo;
core->i2c_client.adapter = &core->i2c_adap;
cx8800_bit_setscl(core,1);
cx8800_bit_setsda(core,1);
core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap);
if (0 == core->i2c_rc) {
dprintk(1, "i2c register ok\n");
if (i2c_scan)
do_i2c_scan(core->name,&core->i2c_client);
} else
printk("%s: i2c register FAILED\n", core->name);
return core->i2c_rc;
}
/* ----------------------------------------------------------------------- */
EXPORT_SYMBOL(cx88_call_i2c_clients);
EXPORT_SYMBOL(cx88_i2c_init);
/*
* Local variables:
* c-basic-offset: 8
......
This diff is collapsed.
/*
$Id: cx88-reg.h,v 1.5 2004/09/15 16:15:24 kraxel Exp $
cx88x-hw.h - CX2388x register offsets
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
......@@ -502,12 +504,6 @@
#define MO_GPHSTD_DMA 0x350000 // {64}RWp Host downstream
#define MO_GPHSTU_DMA 0x350008 // {64}RWp Host upstream
#define MO_GPHSTD_GPCNT 0x35C020 // Host down general purpose counter
#define MO_GPHSTU_GPCNT 0x35C024 // Host up general purpose counter
#define MO_GPHSTD_GPCNTRL 0x38C030 // Host down general purpose control
#define MO_GPHSTU_GPCNTRL 0x38C034 // Host up general purpose control
#define MO_GPHST_DMACNTRL 0x38C040 // Host DMA control
#define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status
#define MO_GPHSTU_CNTRL 0x380048 // Host upstream control #1
#define MO_GPHSTD_CNTRL 0x38004C // Host downstream control #2
#define MO_GPHSTD_LNGTH 0x380050 // Host downstream line length
......@@ -518,6 +514,14 @@
#define MO_GPHST_MUX16 0x380064 // Host muxed 16-bit transfer parameters
#define MO_GPHST_MODE 0x380068 // Host mode select
#define MO_GPHSTD_GPCNT 0x35C020 // Host down general purpose counter
#define MO_GPHSTU_GPCNT 0x35C024 // Host up general purpose counter
#define MO_GPHSTD_GPCNTRL 0x38C030 // Host down general purpose control
#define MO_GPHSTU_GPCNTRL 0x38C034 // Host up general purpose control
#define MO_GPHST_DMACNTRL 0x38C040 // Host DMA control
#define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status
#define MO_GPHST_SOFT_RST 0x38C06C // Host software reset
/* ---------------------------------------------------------------------- */
/* RISC instructions */
......
This diff is collapsed.
/*
* $Id: cx88-vbi.c,v 1.12 2004/10/11 13:45:51 kraxel Exp $
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
......@@ -6,15 +9,15 @@
#include "cx88.h"
static unsigned int vbibufs = 4;
MODULE_PARM(vbibufs,"i");
module_param(vbibufs,int,0644);
MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
static unsigned int vbi_debug = 0;
MODULE_PARM(vbi_debug,"i");
MODULE_PARM_DESC(vbi_debug,"enable debug messages [video]");
module_param(vbi_debug,int,0644);
MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \
printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
/* ------------------------------------------------------------------ */
......@@ -28,13 +31,13 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
if (dev->tvnorm->id & V4L2_STD_525_60) {
if (dev->core->tvnorm->id & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
f->fmt.vbi.start[0] = 10 -1;
f->fmt.vbi.start[1] = 273 -1;
} else if (V4L2_STD_625_50) {
} else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
/* pal */
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.start[0] = 7 -1;
......@@ -46,8 +49,10 @@ int cx8800_start_vbi_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
struct cx88_buffer *buf)
{
struct cx88_core *core = dev->core;
/* setup fifo + format */
cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH24],
cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24],
buf->vb.width, buf->risc.dma);
cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup
......@@ -55,7 +60,7 @@ int cx8800_start_vbi_dma(struct cx8800_dev *dev,
(1 << 11) ));
/* reset counter */
cx_write(MO_VBI_GPCNTRL,0x3);
cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET);
q->count = 1;
/* enable irqs */
......@@ -72,6 +77,22 @@ int cx8800_start_vbi_dma(struct cx8800_dev *dev,
return 0;
}
int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
{
struct cx88_core *core = dev->core;
/* stop dma */
cx_clear(MO_VID_DMACNTRL, 0x88);
/* disable capture */
cx_clear(VID_CAPTURE_CONTROL,0x18);
/* disable irqs */
cx_clear(MO_PCI_INTMSK, 0x000001);
cx_clear(MO_VID_INTMSK, 0x0f0088);
return 0;
}
int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
{
......@@ -96,11 +117,12 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
void cx8800_vbi_timeout(unsigned long data)
{
struct cx8800_dev *dev = (struct cx8800_dev*)data;
struct cx88_core *core = dev->core;
struct cx88_dmaqueue *q = &dev->vbiq;
struct cx88_buffer *buf;
unsigned long flags;
cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH24]);
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]);
cx_clear(MO_VID_DMACNTRL, 0x88);
cx_clear(VID_CAPTURE_CONTROL, 0x18);
......@@ -111,7 +133,7 @@ void cx8800_vbi_timeout(unsigned long data)
list_del(&buf->vb.queue);
buf->vb.state = STATE_ERROR;
wake_up(&buf->vb.done);
printk("%s: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
buf, buf->vb.i, (unsigned long)buf->risc.dma);
}
cx8800_restart_vbi_queue(dev,q);
......@@ -121,7 +143,7 @@ void cx8800_vbi_timeout(unsigned long data)
/* ------------------------------------------------------------------ */
static int
vbi_setup(struct file *file, unsigned int *count, unsigned int *size)
vbi_setup(void *priv, unsigned int *count, unsigned int *size)
{
*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
if (0 == *count)
......@@ -134,10 +156,10 @@ vbi_setup(struct file *file, unsigned int *count, unsigned int *size)
}
static int
vbi_prepare(struct file *file, struct videobuf_buffer *vb,
vbi_prepare(void *priv, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct cx8800_fh *fh = file->private_data;
struct cx8800_fh *fh = priv;
struct cx8800_dev *dev = fh->dev;
struct cx88_buffer *buf = (struct cx88_buffer*)vb;
unsigned int size;
......@@ -170,16 +192,16 @@ vbi_prepare(struct file *file, struct videobuf_buffer *vb,
}
static void
vbi_queue(struct file *file, struct videobuf_buffer *vb)
vbi_queue(void *priv, struct videobuf_buffer *vb)
{
struct cx88_buffer *buf = (struct cx88_buffer*)vb;
struct cx88_buffer *prev;
struct cx8800_fh *fh = file->private_data;
struct cx8800_fh *fh = priv;
struct cx8800_dev *dev = fh->dev;
struct cx88_dmaqueue *q = &dev->vbiq;
/* add jump to stopper */
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | 0x10000);
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
if (list_empty(&q->active)) {
......@@ -202,10 +224,10 @@ vbi_queue(struct file *file, struct videobuf_buffer *vb)
}
}
static void vbi_release(struct file *file, struct videobuf_buffer *vb)
static void vbi_release(void *priv, struct videobuf_buffer *vb)
{
struct cx88_buffer *buf = (struct cx88_buffer*)vb;
struct cx8800_fh *fh = file->private_data;
struct cx8800_fh *fh = priv;
cx88_free_buffer(fh->dev->pci,buf);
}
......
This diff is collapsed.
This diff is collapsed.
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