Commit bf3a93ac authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] v4l: bttv driver update

From: Gerd Knorr <kraxel@bytesex.org>

bttv driver update.  Changes:

(1) Added a new, sysfs-based interface to allow access to the bt878 gpio
    lines from other kernel modules (new bttv-gpio.c file), which fixes alot
    of problems the old interface has (which still is in bttv-if.c, to be
    removed in 2.7).

(2) moved the i2c code from bttv-if.c to bttv-i2c.c.

(3) created a new "struct bttv_core" and moved some of the entries from
    "struct bttv" to the new one.  This is needed for (1) and makes the patch
    pretty big, althrough there is no actual code changes.

(4) first cut for suspend support (S1 works for me).

(5) usual batch of new/updated tv card list entries.

(6) minor fixes.
parent d336a87a
......@@ -3,7 +3,7 @@
#
bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
bttv-risc.o bttv-vbi.o
bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
......
......@@ -158,6 +158,9 @@
#define BT848_ADC_C_SLEEP (1<<1)
#define BT848_ADC_CRUSH (1<<0)
#define BT848_WC_UP 0x044
#define BT848_WC_DOWN 0x078
#define BT848_E_VTC 0x06C
#define BT848_O_VTC 0x0EC
#define BT848_VTC_HSFMT (1<<7)
......
This diff is collapsed.
This diff is collapsed.
/*
bttv-gpio.c -- gpio sub drivers
sysfs-based sub driver interface for bttv
mainly intented for gpio access
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
& Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
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/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/io.h>
#include "bttvp.h"
/* ----------------------------------------------------------------------- */
/* internal: the bttv "bus" */
static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
{
struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
int len = strlen(sub->wanted);
if (0 == strncmp(dev->bus_id, sub->wanted, len))
return 1;
return 0;
}
struct bus_type bttv_sub_bus_type = {
.name = "bttv-sub",
.match = &bttv_sub_bus_match,
};
EXPORT_SYMBOL(bttv_sub_bus_type);
static void release_sub_device(struct device *dev)
{
struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
kfree(sub);
}
int bttv_sub_add_device(struct bttv_core *core, char *name)
{
struct bttv_sub_device *sub;
sub = kmalloc(sizeof(*sub),GFP_KERNEL);
if (NULL == sub)
return -ENOMEM;
memset(sub,0,sizeof(*sub));
sub->core = core;
sub->dev.parent = &core->pci->dev;
sub->dev.bus = &bttv_sub_bus_type;
sub->dev.release = release_sub_device;
snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
name, core->nr);
printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
list_add_tail(&sub->list,&core->subs);
device_register(&sub->dev);
return 0;
}
int bttv_sub_del_devices(struct bttv_core *core)
{
struct bttv_sub_device *sub;
struct list_head *item,*save;
list_for_each_safe(item,save,&core->subs) {
sub = list_entry(item,struct bttv_sub_device,list);
device_unregister(&sub->dev);
}
return 0;
}
void bttv_gpio_irq(struct bttv_core *core)
{
struct bttv_sub_driver *drv;
struct bttv_sub_device *dev;
struct list_head *item;
list_for_each(item,&core->subs) {
dev = list_entry(item,struct bttv_sub_device,list);
drv = to_bttv_sub_drv(dev->dev.driver);
if (drv && drv->gpio_irq)
drv->gpio_irq(dev);
}
}
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
{
sub->drv.bus = &bttv_sub_bus_type;
snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
driver_register(&sub->drv);
return 0;
}
EXPORT_SYMBOL(bttv_sub_register);
int bttv_sub_unregister(struct bttv_sub_driver *sub)
{
driver_unregister(&sub->drv);
return 0;
}
EXPORT_SYMBOL(bttv_sub_unregister);
/* ----------------------------------------------------------------------- */
/* external: gpio access functions */
void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
{
struct bttv *btv = container_of(core, struct bttv, c);
unsigned long flags;
u32 data;
spin_lock_irqsave(&btv->gpio_lock,flags);
data = btread(BT848_GPIO_OUT_EN);
data = data & ~mask;
data = data | (mask & outbits);
btwrite(data,BT848_GPIO_OUT_EN);
spin_unlock_irqrestore(&btv->gpio_lock,flags);
}
EXPORT_SYMBOL(bttv_gpio_inout);
u32 bttv_gpio_read(struct bttv_core *core)
{
struct bttv *btv = container_of(core, struct bttv, c);
u32 value;
value = btread(BT848_GPIO_DATA);
return value;
}
EXPORT_SYMBOL(bttv_gpio_read);
void bttv_gpio_write(struct bttv_core *core, u32 value)
{
struct bttv *btv = container_of(core, struct bttv, c);
btwrite(value,BT848_GPIO_DATA);
}
EXPORT_SYMBOL(bttv_gpio_write);
void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
{
struct bttv *btv = container_of(core, struct bttv, c);
unsigned long flags;
u32 data;
spin_lock_irqsave(&btv->gpio_lock,flags);
data = btread(BT848_GPIO_DATA);
data = data & ~mask;
data = data | (mask & bits);
btwrite(data,BT848_GPIO_DATA);
spin_unlock_irqrestore(&btv->gpio_lock,flags);
}
EXPORT_SYMBOL(bttv_gpio_bits);
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
This diff is collapsed.
This diff is collapsed.
......@@ -5,7 +5,7 @@
- memory management
- generation
(c) 2000 Gerd Knorr <kraxel@bytesex.org>
(c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
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
......@@ -53,7 +53,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
one write per scan line + sync + jump (all 2 dwords) */
instructions = (bpl * lines) / PAGE_SIZE + lines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
return rc;
/* sync instruction */
......@@ -67,7 +67,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
if ((btv->opt_vcr_hack) &&
(line >= (lines - VCR_HACK_LINES)))
continue;
while (offset >= sg_dma_len(sg)) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
sg++;
}
......@@ -100,7 +100,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
}
offset += padding;
}
dprintk("bttv%d: risc planar: %d sglist elems\n", btv->nr, (int)(sg-sglist));
dprintk("bttv%d: risc planar: %d sglist elems\n", btv->c.nr, (int)(sg-sglist));
/* save pointer to jmp instruction address */
risc->jmp = rp;
......@@ -128,7 +128,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
plus sync + jump (2 dwords) */
instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0)
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
return rc;
/* sync instruction */
......@@ -152,15 +152,15 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
}
for (todo = ybpl; todo > 0; todo -= ylen) {
/* go to next sg entry if needed */
while (yoffset >= sg_dma_len(ysg)) {
while (yoffset && yoffset >= sg_dma_len(ysg)) {
yoffset -= sg_dma_len(ysg);
ysg++;
}
while (uoffset >= sg_dma_len(usg)) {
while (uoffset && uoffset >= sg_dma_len(usg)) {
uoffset -= sg_dma_len(usg);
usg++;
}
while (voffset >= sg_dma_len(vsg)) {
while (voffset && voffset >= sg_dma_len(vsg)) {
voffset -= sg_dma_len(vsg);
vsg++;
}
......@@ -227,7 +227,7 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
instructions = (ov->nclips + 1) *
((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height);
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) {
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) {
kfree(skips);
return rc;
}
......@@ -247,9 +247,6 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
if ((btv->opt_vcr_hack) &&
(line >= (ov->w.height - VCR_HACK_LINES)))
continue;
if ((line%2) == 0 && skip_even)
continue;
if ((line%2) == 1 && skip_odd)
if ((line%2) == 0 && skip_even)
continue;
if ((line%2) == 1 && skip_odd)
......@@ -310,7 +307,7 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int totalwidth = tvnorm->totalwidth;
int scaledtwidth = tvnorm->scaledtwidth;
if (bttv_tvcards[btv->type].muxsel[btv->input] < 0) {
if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
swidth = 720;
totalwidth = 858;
scaledtwidth = 858;
......@@ -391,7 +388,7 @@ bttv_set_dma(struct bttv *btv, int override, int irqflags)
d2printk(KERN_DEBUG
"bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
btv->nr,capctl,irqflags,
btv->c.nr,capctl,irqflags,
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->top.dma : 0,
btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->bottom.dma : 0,
......@@ -429,10 +426,10 @@ bttv_risc_init_main(struct bttv *btv)
{
int rc;
if ((rc = btcx_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0)
if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
return rc;
dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
btv->nr,(unsigned long long)btv->main.dma);
btv->c.nr,(unsigned long long)btv->main.dma);
btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
BT848_FIFO_STATUS_VRE);
......@@ -472,11 +469,11 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
if (NULL == risc) {
d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
btv->nr,risc,slot);
btv->c.nr,risc,slot);
btv->main.cpu[slot+1] = cpu_to_le32(next);
} else {
d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
btv->nr,risc,slot,(unsigned long long)risc->dma,irqflags);
btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
cmd = BT848_RISC_JUMP;
if (irqflags) {
cmd |= BT848_RISC_IRQ;
......@@ -496,10 +493,10 @@ bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
if (in_interrupt())
BUG();
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma);
videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma);
videobuf_dma_free(&buf->vb.dma);
btcx_riscmem_free(btv->dev,&buf->bottom);
btcx_riscmem_free(btv->dev,&buf->top);
btcx_riscmem_free(btv->c.pci,&buf->bottom);
btcx_riscmem_free(btv->c.pci,&buf->top);
buf->vb.state = STATE_NEEDS_INIT;
}
......@@ -577,7 +574,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
dprintk(KERN_DEBUG
"bttv%d: buffer field: %s format: %s size: %dx%d\n",
btv->nr, v4l2_field_names[buf->vb.field],
btv->c.nr, v4l2_field_names[buf->vb.field],
buf->fmt->name, buf->vb.width, buf->vb.height);
/* packed pixel modes */
......@@ -731,7 +728,7 @@ bttv_overlay_risc(struct bttv *btv,
/* check interleave, bottom+top fields */
dprintk(KERN_DEBUG
"bttv%d: overlay fields: %s format: %s size: %dx%d\n",
btv->nr, v4l2_field_names[buf->vb.field],
btv->c.nr, v4l2_field_names[buf->vb.field],
fmt->name,ov->w.width,ov->w.height);
/* calculate geometry */
......
......@@ -44,7 +44,7 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
# undef dprintk
#endif
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->nr, ## arg)
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
......@@ -87,7 +87,7 @@ static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb,
return -EINVAL;
if (STATE_NEEDS_INIT == buf->vb.state) {
if (0 != (rc = videobuf_iolock(btv->dev, &buf->vb, NULL)))
if (0 != (rc = videobuf_iolock(btv->c.pci, &buf->vb, NULL)))
goto fail;
if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
goto fail;
......
......@@ -14,6 +14,7 @@
#define _BTTV_H_
#include <linux/videodev.h>
#include <linux/i2c.h>
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
......@@ -117,6 +118,12 @@
#define BTTV_PV143 0x69
#define BTTV_IVC100 0x6e
#define BTTV_IVC120 0x6f
#define BTTV_PC_HDTV 0x70
#define BTTV_TWINHAN_DST 0x71
#define BTTV_WINFASTVC100 0x72
#define BTTV_SIMUS_GVC1100 0x74
#define BTTV_NGSTV_PLUS 0x75
#define BTTV_LMLBT4 0x76
/* i2c address list */
#define I2C_TSA5522 0xc2
......@@ -150,6 +157,18 @@
#define DIGITAL_MODE_VIDEO 1
#define DIGITAL_MODE_CAMERA 2
struct bttv_core {
/* device structs */
struct pci_dev *pci;
struct i2c_adapter i2c_adap;
struct list_head subs; /* struct bttv_sub_device */
/* device config */
unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
unsigned int type; /* card type (pointer into tvcards[]) */
char name[8]; /* dev name */
};
struct bttv;
struct tvcard
......@@ -173,7 +192,10 @@ struct tvcard
unsigned int msp34xx_alt:1;
/* flag: video pci function is unused */
unsigned int no_video;
unsigned int no_video:1;
unsigned int has_dvb:1;
unsigned int has_remote:1;
unsigned int no_gpioirq:1;
/* other settings */
unsigned int pll;
......@@ -208,7 +230,9 @@ extern int bttv_handle_chipset(struct bttv *btv);
/* ---------------------------------------------------------- */
/* exported by bttv-if.c */
/* interface for gpio access by other modules */
/* this obsolete -- please use the sysfs-based
interface below for new code */
/* returns card type + card ID (for bt878-based ones)
for possible values see lines below beginning with #define BTTV_UNKNOWN
......@@ -256,7 +280,43 @@ extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
/* ---------------------------------------------------------- */
/* sysfs/driver-moded based gpio access interface */
struct bttv_sub_device {
struct device dev;
struct bttv_core *core;
struct list_head list;
};
#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev)
struct bttv_sub_driver {
struct device_driver drv;
char wanted[BUS_ID_SIZE];
void (*gpio_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted);
int bttv_sub_unregister(struct bttv_sub_driver *drv);
/* gpio access functions */
void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits);
u32 bttv_gpio_read(struct bttv_core *core);
void bttv_gpio_write(struct bttv_core *core, u32 value);
void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits)
#define gpio_read() bttv_gpio_read(&btv->c)
#define gpio_write(value) bttv_gpio_write(&btv->c, value)
#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits)
/* ---------------------------------------------------------- */
/* i2c */
extern void bttv_bit_setscl(void *data, int state);
extern void bttv_bit_setsda(void *data, int state);
extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
......
......@@ -41,13 +41,11 @@
#include <media/video-buf.h>
#include <media/audiochip.h>
#include <media/tuner.h>
#include <media/ir-common.h>
#include "bt848.h"
#include "bttv.h"
#include "btcx-risc.h"
#ifdef CONFIG_VIDEO_IR
#include "ir-common.h"
#endif
#ifdef __KERNEL__
......@@ -219,11 +217,14 @@ void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
extern struct videobuf_queue_ops bttv_vbi_qops;
/* ---------------------------------------------------------- */
/* bttv-input.c */
/* bttv-gpio.c */
extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
void bttv_gpio_irq(struct bttv_core *core);
int bttv_input_init(struct bttv *btv);
void bttv_input_fini(struct bttv *btv);
void bttv_input_irq(struct bttv *btv);
/* ---------------------------------------------------------- */
/* bttv-driver.c */
......@@ -263,7 +264,6 @@ struct bttv_pll_info {
unsigned int pll_current; /* Currently programmed ofreq */
};
#ifdef CONFIG_VIDEO_IR
/* for gpio-connected remote control */
struct bttv_input {
struct input_dev dev;
......@@ -273,36 +273,46 @@ struct bttv_input {
u32 mask_keycode;
u32 mask_keydown;
};
#endif
struct bttv_suspend_state {
u32 pci_cfg[64 / sizeof(u32)];
u32 gpio_enable;
u32 gpio_data;
int disabled;
struct bttv_buffer_set set;
};
struct bttv {
struct bttv_core c;
/* pci device config */
struct pci_dev *dev;
unsigned short id;
unsigned char revision;
unsigned char *bt848_mmio; /* pointer to mmio */
/* card configuration info */
unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
char name[8]; /* dev name */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */
unsigned int type; /* card type (pointer into tvcards[]) */
unsigned int tuner_type; /* tuner chip type */
unsigned int pinnacle_id;
unsigned int svhs;
struct bttv_pll_info pll;
int triton1;
int gpioirq;
/* gpio interface */
/* old gpio interface */
wait_queue_head_t gpioq;
int shutdown;
void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
/* new gpio interface */
spinlock_t gpio_lock;
/* i2c layer */
struct i2c_adapter i2c_adap;
struct i2c_algo_bit_data i2c_algo;
struct i2c_client i2c_client;
int i2c_state, i2c_rc;
int i2c_done;
wait_queue_head_t i2c_queue;
/* video4linux (1) */
struct video_device *video_dev;
......@@ -311,9 +321,7 @@ struct bttv {
/* infrared remote */
int has_remote;
#ifdef CONFIG_VIDEO_IR
struct bttv_input *remote;
#endif
/* locking */
spinlock_t s_lock;
......@@ -339,6 +347,8 @@ struct bttv {
int opt_chroma_agc;
int opt_adc_crush;
int opt_vcr_hack;
int opt_whitecrush_upper;
int opt_whitecrush_lower;
/* radio data/state */
int has_radio;
......@@ -371,6 +381,11 @@ struct bttv {
unsigned long cap_ctl;
unsigned long dma_on;
struct timer_list timeout;
struct bttv_suspend_state state;
/* stats */
unsigned int irq_total;
unsigned int irq_me;
unsigned int errors;
unsigned int users;
......
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