Commit 66332b52 authored by Gerd Knorr's avatar Gerd Knorr Committed by Linus Torvalds

[PATCH] v4l: bttv driver update

 * the usual pile of tv card database updates.
 * various signed/unsigned fixups (fix gcc 3.3 warnings)
   and releated cleanups (use ARRAY_SIZE macro, ...).
 * moved some code which can be shared with the new,
   upcoming cx2388x driver to a separate module.
 * split the irq handler into smaller functions.
 * some new features (field rate capture support for example).
 * simplified i2c code a bit by removing redundant
   bookkeeping of attached i2c clients.
 * merged i2c changes back into my tree, there are some no-op
   changes due to this.
 * various other bugfixes.
 * fix build failure with CONFIG_FW_LOADER enabled
parent d0c54b7a
......@@ -38,4 +38,4 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o
obj-$(CONFIG_VIDEO_BUF) += video-buf.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
......@@ -204,6 +204,9 @@
#define BT848_COLOR_FMT_YCrCb411 0x99
#define BT848_COLOR_FMT_RAW 0xee
#define BT848_VTOTAL_LO 0xB0
#define BT848_VTOTAL_HI 0xB4
#define BT848_COLOR_CTL 0x0D8
#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7)
#define BT848_COLOR_CTL_COLOR_BARS (1<<6)
......@@ -311,29 +314,28 @@
/* WRITE and SKIP */
/* disable which bytes of each DWORD */
#define BT848_RISC_BYTE0 (1<<12)
#define BT848_RISC_BYTE1 (1<<13)
#define BT848_RISC_BYTE2 (1<<14)
#define BT848_RISC_BYTE3 (1<<15)
#define BT848_RISC_BYTE_ALL (0x0f<<12)
#define BT848_RISC_BYTE0 (1U<<12)
#define BT848_RISC_BYTE1 (1U<<13)
#define BT848_RISC_BYTE2 (1U<<14)
#define BT848_RISC_BYTE3 (1U<<15)
#define BT848_RISC_BYTE_ALL (0x0fU<<12)
#define BT848_RISC_BYTE_NONE 0
/* cause RISCI */
#define BT848_RISC_IRQ (1<<24)
#define BT848_RISC_IRQ (1U<<24)
/* RISC command is last one in this line */
#define BT848_RISC_EOL (1<<26)
#define BT848_RISC_EOL (1U<<26)
/* RISC command is first one in this line */
#define BT848_RISC_SOL (1<<27)
#define BT848_RISC_WRITE (0x01<<28)
#define BT848_RISC_SKIP (0x02<<28)
#define BT848_RISC_WRITEC (0x05<<28)
#define BT848_RISC_JUMP (0x07<<28)
#define BT848_RISC_SYNC (0x08<<28)
#define BT848_RISC_SOL (1U<<27)
#define BT848_RISC_WRITE123 (0x09<<28)
#define BT848_RISC_SKIP123 (0x0a<<28)
#define BT848_RISC_WRITE1S23 (0x0b<<28)
#define BT848_RISC_WRITE (0x01U<<28)
#define BT848_RISC_SKIP (0x02U<<28)
#define BT848_RISC_WRITEC (0x05U<<28)
#define BT848_RISC_JUMP (0x07U<<28)
#define BT848_RISC_SYNC (0x08U<<28)
#define BT848_RISC_WRITE123 (0x09U<<28)
#define BT848_RISC_SKIP123 (0x0aU<<28)
#define BT848_RISC_WRITE1S23 (0x0bU<<28)
/* Bt848A and higher only !! */
......
/*
btcx-risc.c
bt848/bt878/cx2388x risc code generator.
(c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
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/pci.h>
#include <linux/interrupt.h>
#include <linux/videodev2.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include "btcx-risc.h"
MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers");
MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL");
static unsigned int debug = 0;
MODULE_PARM(debug,"i");
MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
/* ---------------------------------------------------------- */
/* allocate/free risc memory */
static int memcnt;
int btcx_riscmem_alloc(struct pci_dev *pci,
struct btcx_riscmem *risc,
unsigned int size)
{
u32 *cpu;
dma_addr_t dma;
cpu = pci_alloc_consistent(pci, size, &dma);
if (NULL == cpu)
return -ENOMEM;
memset(cpu,0,size);
#if 0
if (risc->cpu && risc->size < size) {
/* realloc (enlarge buffer) -- copy old stuff */
memcpy(cpu,risc->cpu,risc->size);
btcx_riscmem_free(pci,risc);
}
#else
BUG_ON(NULL != risc->cpu);
#endif
risc->cpu = cpu;
risc->dma = dma;
risc->size = size;
if (debug) {
memcnt++;
printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt);
}
return 0;
}
void btcx_riscmem_free(struct pci_dev *pci,
struct btcx_riscmem *risc)
{
if (NULL == risc->cpu)
return;
pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
memset(risc,0,sizeof(*risc));
if (debug) {
memcnt--;
printk("btcx: riscmem free [%d]\n",memcnt);
}
}
/* ---------------------------------------------------------- */
/* screen overlay helpers */
int
btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, unsigned int n)
{
if (win->left < 0) {
/* left */
clips[n].c.left = 0;
clips[n].c.top = 0;
clips[n].c.width = -win->left;
clips[n].c.height = win->height;
n++;
}
if (win->left + win->width > swidth) {
/* right */
clips[n].c.left = swidth - win->left;
clips[n].c.top = 0;
clips[n].c.width = win->width - clips[n].c.left;
clips[n].c.height = win->height;
n++;
}
if (win->top < 0) {
/* top */
clips[n].c.left = 0;
clips[n].c.top = 0;
clips[n].c.width = win->width;
clips[n].c.height = -win->top;
n++;
}
if (win->top + win->height > sheight) {
/* bottom */
clips[n].c.left = 0;
clips[n].c.top = sheight - win->top;
clips[n].c.width = win->width;
clips[n].c.height = win->height - clips[n].c.top;
n++;
}
return n;
}
int
btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
{
s32 nx,nw,dx;
unsigned int i;
/* fixup window */
nx = (win->left + mask) & ~mask;
nw = (win->width) & ~mask;
if (nx + nw > win->left + win->width)
nw -= mask+1;
dx = nx - win->left;
win->left = nx;
win->width = nw;
if (debug)
printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
win->width, win->height, win->left, win->top, dx);
/* fixup clips */
for (i = 0; i < n; i++) {
nx = (clips[i].c.left-dx) & ~mask;
nw = (clips[i].c.width) & ~mask;
if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
nw += mask+1;
clips[i].c.left = nx;
clips[i].c.width = nw;
if (debug)
printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n",
clips[i].c.width, clips[i].c.height,
clips[i].c.left, clips[i].c.top);
}
return 0;
}
void
btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
{
struct v4l2_clip swap;
int i,j,n;
if (nclips < 2)
return;
for (i = nclips-2; i >= 0; i--) {
for (n = 0, j = 0; j <= i; j++) {
if (clips[j].c.left > clips[j+1].c.left) {
swap = clips[j];
clips[j] = clips[j+1];
clips[j+1] = swap;
n++;
}
}
if (0 == n)
break;
}
}
void
btcx_calc_skips(int line, int width, unsigned int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips)
{
unsigned int clip,skip;
int end,maxline;
skip=0;
maxline = 9999;
for (clip = 0; clip < nclips; clip++) {
/* sanity checks */
if (clips[clip].c.left + clips[clip].c.width <= 0)
continue;
if (clips[clip].c.left > (signed)width)
break;
/* vertical range */
if (line > clips[clip].c.top+clips[clip].c.height-1)
continue;
if (line < clips[clip].c.top) {
if (maxline > clips[clip].c.top-1)
maxline = clips[clip].c.top-1;
continue;
}
if (maxline > clips[clip].c.top+clips[clip].c.height-1)
maxline = clips[clip].c.top+clips[clip].c.height-1;
/* horizontal range */
if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
/* new one */
skips[skip].start = clips[clip].c.left;
if (skips[skip].start < 0)
skips[skip].start = 0;
skips[skip].end = clips[clip].c.left + clips[clip].c.width;
if (skips[skip].end > width)
skips[skip].end = width;
skip++;
} else {
/* overlaps -- expand last one */
end = clips[clip].c.left + clips[clip].c.width;
if (skips[skip-1].end < end)
skips[skip-1].end = end;
if (skips[skip-1].end > width)
skips[skip-1].end = width;
}
}
*nskips = skip;
*maxy = maxline;
if (debug) {
printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
for (skip = 0; skip < *nskips; skip++) {
printk(" %d-%d",skips[skip].start,skips[skip].end);
}
printk("\n");
}
}
/* ---------------------------------------------------------- */
EXPORT_SYMBOL(btcx_riscmem_alloc);
EXPORT_SYMBOL(btcx_riscmem_free);
EXPORT_SYMBOL(btcx_screen_clips);
EXPORT_SYMBOL(btcx_align);
EXPORT_SYMBOL(btcx_sort_clips);
EXPORT_SYMBOL(btcx_calc_skips);
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
struct btcx_riscmem {
unsigned int size;
u32 *cpu;
u32 *jmp;
dma_addr_t dma;
};
struct btcx_skiplist {
int start;
int end;
};
int btcx_riscmem_alloc(struct pci_dev *pci,
struct btcx_riscmem *risc,
unsigned int size);
void btcx_riscmem_free(struct pci_dev *pci,
struct btcx_riscmem *risc);
int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, unsigned int n);
int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
unsigned int n, int mask);
void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
void btcx_calc_skips(int line, int width, unsigned int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips);
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
......@@ -25,12 +25,14 @@
*/
#include <linux/version.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/firmware.h>
#include <asm/io.h>
......@@ -56,32 +58,34 @@ static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
static void rv605_muxsel(struct bttv *btv, unsigned int input);
static void eagle_muxsel(struct bttv *btv, unsigned int input);
static void xguard_muxsel(struct bttv *btv, unsigned int input);
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
int is_MM20xPCTV(unsigned char eeprom_data[256]);
static void identify_by_eeprom(struct bttv *btv,
unsigned char eeprom_data[256]);
/* config variables */
static int triton1=0;
static int vsfx=0;
static int no_overlay=-1;
static int latency = -1;
static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
static unsigned int triton1=0;
static unsigned int vsfx=0;
static unsigned int latency = UNSET;
unsigned int no_overlay=-1;
static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
#ifdef MODULE
static unsigned int autoload = 1;
#else
static unsigned int autoload = 0;
#endif
static unsigned int gpiomask = -1;
static unsigned int audioall = -1;
static unsigned int audiomux[5] = { -1, -1, -1, -1, -1 };
static unsigned int gpiomask = UNSET;
static unsigned int audioall = UNSET;
static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
/* insmod options */
MODULE_PARM(triton1,"i");
......@@ -150,13 +154,16 @@ static struct CARD {
{ 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
{ 0x6607107d, BTTV_WINFAST2000, "Leadtek WinFast VC 100" },
{ 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
{ 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
{ 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
{ 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
{ 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
{ 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" },
{ 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
{ 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" },
// some cards ship with byteswapped IDs ...
{ 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
{ 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
{ 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
{ 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" },
......@@ -164,6 +171,7 @@ static struct CARD {
{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
{ 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
{ 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
{ 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" },
{ 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
{ 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" },
......@@ -193,6 +201,30 @@ static struct CARD {
{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
{ 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
{ 0x1430aa00, BTTV_PV143, "Provideo PV143A" },
{ 0x1431aa00, BTTV_PV143, "Provideo PV143B" },
{ 0x1432aa00, BTTV_PV143, "Provideo PV143C" },
{ 0x1433aa00, BTTV_PV143, "Provideo PV143D" },
{ 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" },
{ 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" },
{ 0x1462aa02, BTTV_PV150, "Provideo PV150A-3" },
{ 0x1463aa03, BTTV_PV150, "Provideo PV150A-4" },
{ 0x1464aa04, BTTV_PV150, "Provideo PV150B-1" },
{ 0x1465aa05, BTTV_PV150, "Provideo PV150B-2" },
{ 0x1466aa06, BTTV_PV150, "Provideo PV150B-3" },
{ 0x1467aa07, BTTV_PV150, "Provideo PV150B-4" },
{ 0xa1550000, BTTV_IVC200, "IVC-200" },
{ 0xa1550001, BTTV_IVC200, "IVC-200" },
{ 0xa1550002, BTTV_IVC200, "IVC-200" },
{ 0xa1550003, BTTV_IVC200, "IVC-200" },
{ 0x41424344, BTTV_GRANDTEC, "GrandTec Multi Capture" },
{ 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" },
{ 0x010115cb, BTTV_GMV1, "AG GMV1" },
{ 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
{ 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
......@@ -203,7 +235,10 @@ static struct CARD {
{ 0x03116000, BTTV_SENSORAY311, "Sensoray 311" },
{ 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" },
{ 0xa0fca1a0, BTTV_ZOLTRIX, "Face to Face Tvmax" },
{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" },
{ 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
// likely broken, vendor id doesn't match the other magic views ...
//{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" },
{ 0, -1, NULL }
};
......@@ -308,7 +343,7 @@ struct tvcard bttv_tvcards[] = {
},{
/* ---- card 0x08 ---------------------------------- */
.name = "Lifeview FlyVideo II (Bt848) LR26",
.name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
......@@ -377,6 +412,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 3, 1, 1},
.audiomux = { 13, 14, 11, 7, 0, 0},
.needs_tvaudio = 1,
.msp34xx_alt = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
},{
......@@ -614,7 +650,7 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.tuner_type = -1,
},{
.name = "Formac iProTV",
.name = "Formac iProTV, Formac ProTV I (bt848)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
......@@ -722,7 +758,7 @@ struct tvcard bttv_tvcards[] = {
.audiomux = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
.tuner_type = 1,
},{
.name = "Pinnacle PCTV Studio/Rave",
.video_inputs = 3,
......@@ -764,6 +800,7 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.tuner_type = -1,
.has_radio = 1,
.audio_hook = avermedia_tvphone_audio,
},{
.name = "ProVideo PV951", /* pic16c54 */
.video_inputs = 3,
......@@ -905,10 +942,10 @@ struct tvcard bttv_tvcards[] = {
/* ---- card 0x34 ---------------------------------- */
/* David Hrdeman <david@2gen.com> */
.name = "Pinnacle PCTV Studio Pro",
.video_inputs = 3,
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.svhs = 3,
.gpiomask = 0x03000F,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 1, 0xd0001, 0, 0, 10},
......@@ -1532,11 +1569,13 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.gpiomask = 0x01,
.audiomux = { 0, 0, 0, 0, 1 },
.muxsel = { 3, 0, 1, 2},
.needs_tvaudio = 0,
.pll = PLL_28,
},{
.name = "Formac ProTV II",
.name = "Formac ProTV II (bt878)",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
......@@ -1555,8 +1594,8 @@ struct tvcard bttv_tvcards[] = {
not soldered here, though unknown wiring.
Card lacks: external audio in, pci subsystem id.
*/
},{
/* ---- card 0x60 ---------------------------------- */
.name = "MachTV",
.video_inputs = 3,
......@@ -1581,9 +1620,190 @@ struct tvcard bttv_tvcards[] = {
.no_tda7432 = 1,
.muxsel = { 2, 0, 1},
.pll = PLL_28,
},{
/* Luc Van Hoeylandt <luc@e-magic.be> */
.name = "ProVideo PV150", /* 0x4f */
.video_inputs = 2,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0,
.muxsel = { 2, 3 },
.audiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* Hiroshi Takekawa <sian@big.or.jp> */
/* This card lacks subsystem ID */
.name = "AD-TVK503", /* 0x63 */
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x001e8007,
.muxsel = { 2, 3, 1, 0 },
/* Tuner, Radio, external, internal, off, on */
.audiomux = { 0x08, 0x0f, 0x0a, 0x08, 0x0f, 0x08 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 2,
.audio_hook = adtvk503_audio,
},{
/* ---- card 0x64 ---------------------------------- */
.name = "Hercules Smart TV Stereo",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1 },
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = 5,
/* Notes:
- card lacks subsystem ID
- stereo variant w/ daughter board with tda9874a @0xb0
- Audio Routing:
always from tda9874 independent of GPIO (?)
external line in: unknown
- Other chips: em78p156elp @ 0x96 (probably IR remote control)
hef4053 (instead 4052) for unknown function
*/
},{
.name = "Pace TV & Radio Card",
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1}, // Tuner, CVid, SVid, CVid over SVid connector
.gpiomask = 0,
.no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = 1,
.has_radio = 1,
.pll = PLL_28,
/* Bt878, Bt832, FI1246 tuner; no pci subsystem id
only internal line out: (4pin header) RGGL
Radio must be decoded by msp3410d (not routed through)*/
// .digital_mode = DIGITAL_MODE_CAMERA, // todo!
},{
/* Chris Willing <chris@vislab.usyd.edu.au> */
.name = "IVC-200",
.video_inputs = 1,
.audio_inputs = 0,
.tuner = -1,
.tuner_type = -1,
.svhs = -1,
.gpiomask = 0xdf,
.muxsel = { 2 },
.pll = PLL_28,
},{
.name = "Grand X-Guard / Trust 814PCI",
.video_inputs = 16,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.tuner_type = 4,
.gpiomask2 = 0xff,
.muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
.muxsel_hook = xguard_muxsel,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
},{
/* ---- card 0x68 ---------------------------------- */
.name = "Nebula Electronics DigiTV",
.video_inputs = 0,
.audio_inputs = 0,
.svhs = -1,
.muxsel = { 2, 3, 1, 0},
.needs_tvaudio = 0,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
.name = "ProVideo PV143",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1,
.svhs = -1,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.audiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* M.Klahr@phytec.de */
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 0},
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
.name = "PHYTEC VD-009-X1 Combi (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1},
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
/* ---- card 0x6c ---------------------------------- */
.name = "PHYTEC VD-009 MiniDIN (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
via the upper nibble of muxsel. here: used for
xternal video-mux */
.muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
},{
.name = "PHYTEC VD-009 Combi (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
.tuner = -1, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
via the upper nibble of muxsel. here: used for
xternal video-mux */
.muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
.audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
}};
const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
/* ----------------------------------------------------------------------- */
......@@ -1615,19 +1835,21 @@ void __devinit bttv_idcard(struct bttv *btv)
printk(KERN_INFO "bttv%d: detected: %s [card=%d], "
"PCI subsystem ID is %04x:%04x\n",
btv->nr,cards[type].name,cards[type].cardnr,
btv->cardid & 0xffff, btv->cardid >> 16);
btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
btv->type = cards[type].cardnr;
} else {
/* 404 */
printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
btv->nr, btv->cardid&0xffff, btv->cardid>>16);
btv->nr, btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
printk(KERN_DEBUG "please mail id, board name and "
"the correct card= insmod option to kraxel@bytesex.org\n");
}
}
/* let the user override the autodetected type */
if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards)
if (card[btv->nr] < bttv_num_tvcards)
btv->type=card[btv->nr];
/* print which card config we are using */
......@@ -1637,14 +1859,14 @@ void __devinit bttv_idcard(struct bttv *btv)
bttv_tvcards[btv->type].name);
printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr,
btv->video_dev.name,btv->type,
(card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
"insmod option" : "autodetected");
card[btv->nr] < bttv_num_tvcards
? "insmod option" : "autodetected");
/* overwrite gpio stuff ?? */
if (-1 == audioall && -1 == audiomux[0])
if (UNSET == audioall && UNSET == audiomux[0])
return;
if (-1 != audiomux[0]) {
if (UNSET != audiomux[0]) {
gpiobits = 0;
for (i = 0; i < 5; i++) {
bttv_tvcards[btv->type].audiomux[i] = audiomux[i];
......@@ -1656,7 +1878,7 @@ void __devinit bttv_idcard(struct bttv *btv)
bttv_tvcards[btv->type].audiomux[i] = audioall;
}
}
bttv_tvcards[btv->type].gpiomask = (-1 != gpiomask) ? gpiomask : gpiobits;
bttv_tvcards[btv->type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
btv->nr,bttv_tvcards[btv->type].gpiomask);
for (i = 0; i < 5; i++) {
......@@ -1670,13 +1892,22 @@ void __devinit bttv_idcard(struct bttv *btv)
*/
/* Some Modular Technology cards have an eeprom, but no subsystem ID */
int is_MM20xPCTV(unsigned char eeprom_data[256])
void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
{
if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13)) {
printk("bttv: GET.MM20xPCTV found\n");
return 1; // found
int type = -1;
if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13))
type = BTTV_MODTEC_205;
else if (0 == strncmp(eeprom_data+20,"Picolo",7))
type = BTTV_EURESYS_PICOLO;
else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
type = BTTV_HAUPPAUGE; /* old bt848 */
if (-1 != type) {
btv->type = type;
printk("bttv%d: detected by eeprom: %s [card=%d]\n",
btv->nr, bttv_tvcards[btv->type].name, btv->type);
}
return 0;
}
static void flyvideo_gpio(struct bttv *btv)
......@@ -1780,7 +2011,8 @@ static void miro_pinnacle_gpio(struct bttv *btv)
if (btv->type == BTTV_PINNACLE)
btv->type = BTTV_PINNACLEPRO;
}
printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
printk(KERN_INFO
"bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
btv->nr, id+1, btv->tuner_type,
!btv->has_radio ? "no" :
(btv->has_matchbox ? "matchbox" : "fmtuner"),
......@@ -1814,13 +2046,13 @@ static void miro_pinnacle_gpio(struct bttv *btv)
info = "oops: unknown card";
break;
}
if (-1 != msp)
btv->type = BTTV_PINNACLEPRO;
printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->nr, id, info, btv->has_radio ? "yes" : "no");
btv->tuner_type = 33;
if (autoload)
request_module("tda9887");
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,&id);
btv->pinnacle_id = id;
}
}
......@@ -1886,6 +2118,9 @@ void __devinit bttv_init_card1(struct bttv *btv)
case BTTV_VOODOOTV_FM:
boot_msp34xx(btv,20);
break;
case BTTV_AVERMEDIA98:
boot_msp34xx(btv,11);
break;
case BTTV_HAUPPAUGEPVR:
pvr_boot(btv);
break;
......@@ -1898,13 +2133,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->tuner_type = -1;
if (BTTV_UNKNOWN == btv->type) {
printk("bttv%d: Looking for eeprom\n",btv->nr);
bttv_readee(btv,eeprom_data,0xa0);
if(is_MM20xPCTV(eeprom_data)) {
btv->type = BTTV_MODTEC_205;
printk("bttv%d: Autodetect by eeprom:(%s) [card=%d]\n",
btv->nr, bttv_tvcards[btv->type].name, btv->type);
}
identify_by_eeprom(btv,eeprom_data);
}
switch (btv->type) {
......@@ -2028,18 +2258,20 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->pll.pll_current = -1;
/* tuner configuration (from card list / autodetect / insmod option) */
if (-1 != bttv_tvcards[btv->type].tuner_type)
if( -1 == btv->tuner_type)
if (UNSET != bttv_tvcards[btv->type].tuner_type)
if(UNSET == btv->tuner_type)
btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
if (-1 != tuner[btv->nr])
if (UNSET != tuner[btv->nr])
btv->tuner_type = tuner[btv->nr];
if (btv->tuner_type != -1)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type);
if (btv->pinnacle_id != UNSET)
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
&btv->pinnacle_id);
if (btv->tuner_type != UNSET)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
if (bttv_tvcards[btv->type].has_radio)
btv->has_radio=1;
if (bttv_tvcards[btv->type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
......@@ -2057,6 +2289,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
request_module("msp3400");
}
if (bttv_tvcards[btv->type].msp34xx_alt &&
bttv_I2CRead(btv, I2C_MSP3400_ALT, "MSP34xx (alternate address)") >=0) {
if (autoload)
request_module("msp3400");
}
if (!bttv_tvcards[btv->type].no_tda9875 &&
bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
if (autoload)
......@@ -2074,7 +2312,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
request_module("tvaudio");
}
if (bttv_tvcards[btv->type].tuner != -1) {
/* tuner modules */
if (btv->pinnacle_id != UNSET) {
if (autoload)
request_module("tda9887");
}
if (btv->tuner_type != UNSET) {
if (autoload)
request_module("tuner");
}
......@@ -2137,9 +2380,9 @@ hauppauge_tuner[] __devinitdata =
{ TUNER_TEMIC_4046FM5, "Temic 4046FM5" },
{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
{ TUNER_ABSENT, "Philips TD1536D_FH_44"},
{ TUNER_LG_NTSC_FM, "LG TP18NSR01F"},
{ TUNER_LG_PAL_FM, "LG TP18PSB01D"},
{ TUNER_LG_PAL, "LG TP18PSB11D"},
{ TUNER_LG_NTSC_FM, "LG TPI8NSR01F"},
{ TUNER_LG_PAL_FM, "LG TPI8PSB01D"},
{ TUNER_LG_PAL, "LG TPI8PSB11D"},
{ TUNER_LG_PAL_I_FM, "LG TAPC-I001D"},
{ TUNER_LG_PAL_I, "LG TAPC-I701D"}
};
......@@ -2148,15 +2391,17 @@ static void modtec_eeprom(struct bttv *btv)
{
if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
printk("bttv Modtec: Tuner autodetected %s\n",&eeprom_data[0x1e]);
printk("bttv Modtec: Tuner autodetected %s\n",
&eeprom_data[0x1e]);
} else {
printk("bttv Modtec: Unknown TunerString:%s\n",
&eeprom_data[0x1e]);
}
else
printk("bttv Modtec: Unknown TunerString:%s\n",&eeprom_data[0x1e]);
}
static void __devinit hauppauge_eeprom(struct bttv *btv)
{
int blk2,tuner,radio,model;
unsigned int blk2,tuner,radio,model;
if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0)
printk(KERN_WARNING "bttv%d: Hauppauge eeprom: invalid\n",
......@@ -2170,8 +2415,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
tuner = eeprom_data[9];
radio = eeprom_data[blk2-1] & 0x01;
if (tuner >= ARRAY_SIZE(hauppauge_tuner))
tuner = 0;
if (tuner < ARRAY_SIZE(hauppauge_tuner))
btv->tuner_type = hauppauge_tuner[tuner].id;
if (radio)
btv->has_radio = 1;
......@@ -2223,14 +2467,6 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
* a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
* unpacked with unzip).
*/
static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf";
MODULE_PARM(firm_altera,"s");
MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware "
"(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)");
/* drivers/sound/sound_firmware.c => soundcore.o */
extern int mod_firmware_load(const char *fn, char **fp);
#define PVR_GPIO_DELAY 10
#define BTTV_ALT_DATA 0x000001
......@@ -2275,6 +2511,16 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
return 0;
}
#ifndef CONFIG_FW_LOADER
/* old 2.4.x way -- via soundcore's mod_firmware_load */
static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf";
MODULE_PARM(firm_altera,"s");
MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware "
"(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)");
extern int mod_firmware_load(const char *fn, char **fp);
int __devinit pvr_boot(struct bttv *btv)
{
u32 microlen;
......@@ -2282,8 +2528,11 @@ int __devinit pvr_boot(struct bttv *btv)
int result;
microlen = mod_firmware_load(firm_altera, (char**) &micro);
if (!microlen)
if (!microlen) {
printk(KERN_WARNING "bttv%d: altera firmware not found [%s]\n",
btv->nr, firm_altera);
return -1;
}
printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n",
btv->nr, firm_altera);
......@@ -2293,6 +2542,28 @@ int __devinit pvr_boot(struct bttv *btv)
vfree(micro);
return result;
}
#else
/* new 2.5.x way -- via hotplug firmware loader */
int __devinit pvr_boot(struct bttv *btv)
{
const struct firmware *fw_entry;
struct device *dev = &btv->dev->dev;
int rc;
rc = request_firmware(&fw_entry, "hcwamc.rbf", dev);
if (rc != 0) {
printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
btv->nr);
return rc;
}
rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
btv->nr, (rc < 0) ? "failed" : "ok");
release_firmware(fw_entry);
return rc;
}
#endif
/* ----------------------------------------------------------------------- */
/* some osprey specific stuff */
......@@ -2541,7 +2812,9 @@ static void __devinit init_PXC200(struct bttv *btv)
static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x00 };
int i,tmp;
unsigned int i;
int tmp;
u32 val;
/* Initialise GPIO-connevted stuff */
btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */
......@@ -2561,6 +2834,7 @@ static void __devinit init_PXC200(struct bttv *btv)
setting BT848_ADC_AGC_EN disable the AGC
tboult@eecs.lehigh.edu
*/
btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
/* Initialise MAX517 DAC */
......@@ -2572,16 +2846,36 @@ static void __devinit init_PXC200(struct bttv *btv)
* same chips - but the R/W bit is included in the address
* argument so the numbers are different */
printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
for (i = 0; i < sizeof(vals)/sizeof(int); i++) {
tmp=bttv_I2CWrite(btv,0x1E,vals[i],0,1);
printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",
tmp,bttv_I2CRead(btv,0x1F,NULL));
/* First of all, enable the clock line. This is used in the PXC200-F */
val = btread(BT848_GPIO_DMA_CTL);
val |= BT848_GPIO_DMA_CTL_GPCLKMODE;
btwrite(val, BT848_GPIO_DMA_CTL);
/* Then, push to 0 the reset pin long enough to reset the *
* device same as above for the reset line, but not the same
* value sent to the GPIO-connected stuff
* which one is the good one? */
btwrite( (1<<2), BT848_GPIO_OUT_EN); /* only the reset pin */
btwrite(0, BT848_GPIO_DATA);
udelay(10);
btwrite(1<<2, BT848_GPIO_DATA);
for (i = 0; i < ARRAY_SIZE(vals); i++) {
tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
if (tmp != -1) {
printk(KERN_INFO
"I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL));
}
}
printk(KERN_INFO "PXC200 Initialised.\n");
}
/* ----------------------------------------------------------------------- */
/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */
/*
......@@ -2671,8 +2965,8 @@ int bus_in(struct bttv *btv, int bit)
/* Low-level stuff */
static int tea5757_read(struct bttv *btv)
{
int value = 0;
unsigned long timeout;
int value = 0;
int i;
/* better safe than sorry */
......@@ -2755,12 +3049,13 @@ static int tea5757_write(struct bttv *btv, int value)
void tea5757_set_freq(struct bttv *btv, unsigned short freq)
{
int value;
dprintk("tea5757_set_freq %d\n",freq);
tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
#if 0
/* breaks Miro PCTV */
value = tea5757_read(btv);
dprintk("bttv%d: tea5757 readback =0x%x\n",btv->nr,value);
dprintk("bttv%d: tea5757 readback=0x%x\n",btv->nr,value);
#endif
}
......@@ -3052,6 +3347,38 @@ windvr_audio(struct bttv *btv, struct video_audio *v, int set)
}
}
/*
* sound control for AD-TVK503
* Hiroshi Takekawa <sian@big.or.jp>
*/
static void
adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
{
unsigned int con = 0xffffff;
//btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN);
if (set) {
//btor(***, BT848_GPIO_OUT_EN);
if (v->mode & VIDEO_SOUND_LANG1)
con = 0x00000000;
if (v->mode & VIDEO_SOUND_LANG2)
con = 0x00180000;
if (v->mode & VIDEO_SOUND_STEREO)
con = 0x00000000;
if (v->mode & VIDEO_SOUND_MONO)
con = 0x00060000;
if (con != 0xffffff) {
btaor(con, ~0x1e0000, BT848_GPIO_DATA);
if (bttv_gpio)
bttv_gpio_tracking(btv, "adtvk503");
}
} else {
v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
}
}
/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
*
* This is needed because rv605 don't use a normal multiplex, but a crosspoint
......@@ -3092,6 +3419,34 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input)
mdelay(1);
}
// The Grandtec X-Guard framegrabber card uses two Dual 4-channel
// video multiplexers to provide up to 16 video inputs. These
// multiplexers are controlled by the lower 8 GPIO pins of the
// bt878. The multiplexers probably Pericom PI5V331Q or similar.
// xxx0 is pin xxx of multiplexer U5,
// yyy1 is pin yyy of multiplexer U2
#define ENA0 0x01
#define ENB0 0x02
#define ENA1 0x04
#define ENB1 0x08
#define IN10 0x10
#define IN00 0x20
#define IN11 0x40
#define IN01 0x80
static void xguard_muxsel(struct bttv *btv, unsigned int input)
{
static const int masks[] = {
ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
};
btwrite(masks[input%16], BT848_GPIO_DATA);
}
/* ----------------------------------------------------------------------- */
/* motherboard chipset specific stuff */
......@@ -3123,12 +3478,12 @@ void __devinit bttv_check_chipset(void)
printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
if (pcipci_fail) {
printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
if (-1 == no_overlay) {
if (UNSET == no_overlay) {
printk(KERN_WARNING "bttv: going to disable overlay.\n");
no_overlay = 1;
}
}
if (-1 != latency)
if (UNSET != latency)
printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
......@@ -3145,7 +3500,7 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
{
unsigned char command;
if (!triton1 && !vsfx && -1 == latency)
if (!triton1 && !vsfx && UNSET == latency)
return 0;
if (bttv_verbose) {
......@@ -3153,7 +3508,7 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr);
if (vsfx && btv->id >= 878)
printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->nr);
if (-1 != latency)
if (UNSET != latency)
printk(KERN_INFO "bttv%d: setting pci timer to %d\n",
btv->nr,latency);
}
......@@ -3171,7 +3526,7 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
command |= BT878_EN_VSFX;
pci_write_config_byte(btv->dev, BT878_DEVCTRL, command);
}
if (-1 != latency)
if (UNSET != latency)
pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
return 0;
}
......
......@@ -24,7 +24,6 @@
*/
#include <linux/init.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
......@@ -35,10 +34,11 @@
#include <linux/kdev_t.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include "bttvp.h"
int bttv_num; /* number of Bt848s in use */
unsigned int bttv_num; /* number of Bt848s in use */
struct bttv bttvs[BTTV_MAX];
unsigned int bttv_debug = 0;
......@@ -46,12 +46,12 @@ unsigned int bttv_verbose = 1;
unsigned int bttv_gpio = 0;
/* config variables */
#if defined(__sparc__) || defined(__powerpc__) || defined(__hppa__)
#ifdef __BIG_ENDIAN
static unsigned int bigendian=1;
#else
static unsigned int bigendian=0;
#endif
static unsigned int radio[4];
static unsigned int radio[BTTV_MAX];
static unsigned int irq_debug = 0;
static unsigned int gbuffers = 8;
static unsigned int gbufsize = 0x208000;
......@@ -275,9 +275,29 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
},{
/* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC
* tape on a PAL TV ... */
.v4l2_id = V4L2_STD_PAL_60,
.name = "PAL-60",
.Fsc = 35468950,
.swidth = 924,
.sheight = 480,
.totalwidth = 1135,
.adelay = 0x7f,
.bdelay = 0x72,
.iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
.scaledtwidth = 1135,
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x1a,
.vbipack = 255,
.vtotal = 524,
.sram = -1,
}
};
const int BTTV_TVNORMS = (sizeof(bttv_tvnorms)/sizeof(struct bttv_tvnorm));
const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
/* ----------------------------------------------------------------------- */
/* bttv format list
......@@ -434,7 +454,7 @@ const struct bttv_format bttv_formats[] = {
.flags = FORMAT_FLAGS_RAW,
}
};
const int BTTV_FORMATS = (sizeof(bttv_formats)/sizeof(struct bttv_format));
const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
/* ----------------------------------------------------------------------- */
......@@ -557,7 +577,7 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
.type = V4L2_CTRL_TYPE_BOOLEAN,
}
};
const int BTTV_CTLS = (sizeof(bttv_ctls)/sizeof(struct v4l2_queryctrl));
const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
/* ----------------------------------------------------------------------- */
/* resource management */
......@@ -1002,7 +1022,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
break;
case V4L2_CID_AUDIO_MUTE:
c->value = (VIDEO_AUDIO_MUTE == va.flags) ? 1 : 0;
c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
break;
case V4L2_CID_AUDIO_VOLUME:
c->value = va.volume;
......@@ -1159,7 +1179,7 @@ void bttv_field_count(struct bttv *btv)
static const struct bttv_format*
format_by_palette(int palette)
{
int i;
unsigned int i;
for (i = 0; i < BTTV_FORMATS; i++) {
if (-1 == bttv_formats[i].palette)
......@@ -1173,7 +1193,7 @@ format_by_palette(int palette)
static const struct bttv_format*
format_by_fourcc(int fourcc)
{
int i;
unsigned int i;
for (i = 0; i < BTTV_FORMATS; i++) {
if (-1 == bttv_formats[i].fourcc)
......@@ -1195,6 +1215,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
unsigned long flags;
int retval = 0;
dprintk("switch_overlay: enter [new=%p]\n",new);
if (new)
new->vb.state = STATE_DONE;
spin_lock_irqsave(&btv->s_lock,flags);
......@@ -1204,8 +1225,12 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
spin_unlock_irqrestore(&btv->s_lock,flags);
if (NULL == new)
free_btres(btv,fh,RESOURCE_OVERLAY);
if (NULL != old)
if (NULL != old) {
dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
bttv_dma_free(btv, old);
kfree(old);
}
dprintk("switch_overlay: done\n");
return retval;
}
......@@ -1214,7 +1239,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
const struct bttv_format *fmt,
int width, int height,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
int redo_dma_risc = 0;
......@@ -1252,13 +1277,6 @@ static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
redo_dma_risc = 1;
}
#if 0
if (STATE_NEEDS_INIT == buf->vb.state) {
if (redo_dma_risc)
bttv_dma_free(btv,buf);
}
#endif
/* alloc risc memory */
if (STATE_NEEDS_INIT == buf->vb.state) {
redo_dma_risc = 1;
......@@ -1334,7 +1352,7 @@ static const char *v4l1_ioctls[] = {
"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
"SMICROCODE", "GVBIFMT", "SVBIFMT" };
#define V4L1_IOCTLS (sizeof(v4l1_ioctls)/sizeof(char*))
#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
......@@ -1365,7 +1383,7 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
struct video_tuner *v = arg;
if (-1 == bttv_tvcards[btv->type].tuner)
if (UNSET == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (v->tuner) /* Only tuner 0 */
return -EINVAL;
......@@ -1397,37 +1415,38 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
case VIDIOCGCHAN:
{
struct video_channel *v = arg;
unsigned int channel = v->channel;
if (v->channel >= bttv_tvcards[btv->type].video_inputs)
if (channel >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
v->tuners=0;
v->flags = VIDEO_VC_AUDIO;
v->type = VIDEO_TYPE_CAMERA;
v->norm = btv->tvnorm;
if(v->channel == bttv_tvcards[btv->type].tuner) {
if (channel == bttv_tvcards[btv->type].tuner) {
strcpy(v->name,"Television");
v->flags|=VIDEO_VC_TUNER;
v->type=VIDEO_TYPE_TV;
v->tuners=1;
} else if (v->channel == bttv_tvcards[btv->type].svhs) {
} else if (channel == bttv_tvcards[btv->type].svhs) {
strcpy(v->name,"S-Video");
} else {
sprintf(v->name,"Composite%d",v->channel);
sprintf(v->name,"Composite%d",channel);
}
return 0;
}
case VIDIOCSCHAN:
{
struct video_channel *v = arg;
unsigned int channel = v->channel;
if (v->channel < 0 ||
v->channel >= bttv_tvcards[btv->type].video_inputs)
if (channel >= bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
if (v->norm >= BTTV_TVNORMS)
return -EINVAL;
down(&btv->lock);
if (v->channel == btv->input &&
if (channel == btv->input &&
v->norm == btv->tvnorm) {
/* nothing to do */
up(&btv->lock);
......@@ -1462,9 +1481,9 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
unsigned int audio = v->audio;
if(v->audio < 0 ||
v->audio >= bttv_tvcards[btv->type].audio_inputs)
if (audio >= bttv_tvcards[btv->type].audio_inputs)
return -EINVAL;
down(&btv->lock);
......@@ -1483,11 +1502,13 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *e = arg;
unsigned int index = e->index;
if (e->index < 0 || e->index >= BTTV_TVNORMS)
if (index >= BTTV_TVNORMS)
return -EINVAL;
v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
bttv_tvnorms[e->index].name);
e->index = index;
return 0;
}
case VIDIOC_G_STD:
......@@ -1499,7 +1520,7 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg;
int i;
unsigned int i;
for (i = 0; i < BTTV_TVNORMS; i++)
if (*id & bttv_tvnorms[i].v4l2_id)
......@@ -1527,7 +1548,7 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
int n;
unsigned int n;
n = i->index;
if (n >= bttv_tvcards[btv->type].video_inputs)
......@@ -1564,9 +1585,9 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
}
case VIDIOC_S_INPUT:
{
int *i = arg;
unsigned int *i = arg;
if (*i < 0 || *i > bttv_tvcards[btv->type].video_inputs)
if (*i > bttv_tvcards[btv->type].video_inputs)
return -EINVAL;
down(&btv->lock);
set_input(btv,*i);
......@@ -1579,7 +1600,7 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
struct v4l2_tuner *t = arg;
if (-1 == bttv_tvcards[btv->type].tuner)
if (UNSET == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
......@@ -1587,8 +1608,8 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
memset(t,0,sizeof(*t));
strcpy(t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
t->capability = V4L2_TUNER_CAP_NORM;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
t->signal = 0xffff;
......@@ -1599,12 +1620,15 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (btv->audio_hook)
btv->audio_hook(btv,&va,0);
if(va.mode & VIDEO_SOUND_STEREO)
if(va.mode & VIDEO_SOUND_STEREO) {
t->audmode = V4L2_TUNER_MODE_STEREO;
t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
if(va.mode & VIDEO_SOUND_LANG1)
t->rxsubchans |= V4L2_TUNER_SUB_LANG1;
if(va.mode & VIDEO_SOUND_LANG2)
t->rxsubchans |= V4L2_TUNER_SUB_LANG2;
}
if(va.mode & VIDEO_SOUND_LANG1) {
t->audmode = V4L2_TUNER_MODE_LANG1;
t->rxsubchans = V4L2_TUNER_SUB_LANG1
| V4L2_TUNER_SUB_LANG2;
}
}
/* FIXME: fill capability+audmode */
up(&btv->lock);
......@@ -1614,7 +1638,7 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
struct v4l2_tuner *t = arg;
if (-1 == bttv_tvcards[btv->type].tuner)
if (UNSET == bttv_tvcards[btv->type].tuner)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
......@@ -1622,6 +1646,7 @@ int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
struct video_audio va;
memset(&va, 0, sizeof(struct video_audio));
bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
if (t->audmode == V4L2_TUNER_MODE_MONO)
va.mode = VIDEO_SOUND_MONO;
else if (t->audmode == V4L2_TUNER_MODE_STEREO)
......@@ -1705,15 +1730,6 @@ static int verify_window(const struct bttv_tvnorm *tvn,
if (!fixup && (win->w.width > maxw || win->w.height > maxh))
return -EINVAL;
if (1 /* depth < 4bpp */) {
/* adjust and align writes */
int left = (win->w.left + 3) & ~3;
int width = win->w.width & ~3;
while (left + width > win->w.left + win->w.width)
width -= 4;
win->w.left = left;
win->w.width = width;
}
if (win->w.width > maxw)
win->w.width = maxw;
if (win->w.height > maxh)
......@@ -1728,6 +1744,8 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_clip *clips = NULL;
int n,size,retval = 0;
if (NULL == fh->ovfmt)
return -EINVAL;
retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
if (0 != retval)
return retval;
......@@ -1735,22 +1753,37 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
/* copy clips -- luckily v4l1 + v4l2 are binary
compatible here ...*/
n = win->clipcount;
size = sizeof(struct video_clip)*(n+4);
size = sizeof(*clips)*(n+4);
clips = kmalloc(size,GFP_KERNEL);
if (NULL == clips)
return -ENOMEM;
if (n > 0) {
if (copy_from_user(clips,win->clips,
sizeof(struct v4l2_clip)*win->clipcount)) {
if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
kfree(clips);
return -EFAULT;
}
}
/* clip against screen */
if (NULL != btv->fbuf.base)
n = bttv_screen_clips(btv->fbuf.width, btv->fbuf.width,
n = btcx_screen_clips(btv->fbuf.width, btv->fbuf.width,
&win->w, clips, n);
bttv_sort_clips(clips,n);
btcx_sort_clips(clips,n);
/* 4-byte alignments */
switch (fh->ovfmt->depth) {
case 8:
case 24:
btcx_align(&win->w, clips, n, 3);
break;
case 16:
btcx_align(&win->w, clips, n, 1);
break;
case 32:
/* no alignment fixups needed */
break;
default:
BUG();
}
down(&fh->cap.lock);
if (fh->ov.clips)
......@@ -1760,8 +1793,10 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
fh->ov.w = win->w;
fh->ov.field = win->field;
fh->ov.setup_ok = 1;
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
btv->init.ov.field = win->field;
/* update overlay if needed */
retval = 0;
......@@ -1834,8 +1869,10 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.pix.height = fh->height;
f->fmt.pix.field = fh->cap.field;
f->fmt.pix.pixelformat = fh->fmt->fourcc;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fh->fmt->depth) >> 3;
f->fmt.pix.sizeimage =
(fh->width * fh->height * fh->fmt->depth)/8;
f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
memset(&f->fmt.win,0,sizeof(struct v4l2_window));
......@@ -1843,7 +1880,7 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.win.field = fh->ov.field;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
bttv_vbi_fmt(fh,f);
bttv_vbi_get_fmt(fh,f);
return 0;
default:
return -EINVAL;
......@@ -1858,14 +1895,11 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
{
const struct bttv_format *fmt;
enum v4l2_field field;
int maxw,maxh;
unsigned int maxw,maxh;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
if (0 != f->fmt.pix.bytesperline)
/* FIXME -- not implemented yet */
return -EINVAL;
/* fixup format */
maxw = bttv_tvnorms[btv->tvnorm].swidth;
......@@ -1880,6 +1914,7 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
maxh = maxh/2;
break;
case V4L2_FIELD_INTERLACED:
......@@ -1887,6 +1922,7 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
case V4L2_FIELD_SEQ_TB:
if (fmt->flags & FORMAT_FLAGS_PLANAR)
return -EINVAL;
break;
default:
return -EINVAL;
}
......@@ -1901,25 +1937,19 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
f->fmt.pix.height = maxh;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
(fh->width * fh->height * fmt->depth)/8;
f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
return verify_window(&bttv_tvnorms[btv->tvnorm],
&f->fmt.win, 1);
#if 0
case V4L2_BUF_TYPE_VBI_CAPTURE:
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
if (fh->vbi.reading || fh->vbi.streaming)
return -EBUSY;
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_fmt(fh,f);
bttv_vbi_try_fmt(fh,f);
return 0;
#endif
default:
return -EINVAL;
}
......@@ -1947,6 +1977,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
down(&fh->cap.lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
btv->init.fmt = fmt;
......@@ -1962,10 +1993,11 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
if (fh->vbi.reading || fh->vbi.streaming)
if (locked_btres(fh->btv, RESOURCE_VBI))
return -EBUSY;
bttv_vbi_try_fmt(fh,f);
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_fmt(fh,f);
bttv_vbi_get_fmt(fh,f);
return 0;
default:
return -EINVAL;
......@@ -1978,7 +2010,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
unsigned long flags;
int retval;
int retval = 0;
if (bttv_debug > 1) {
switch (_IOC_TYPE(cmd)) {
......@@ -2052,9 +2084,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (NULL == fmt)
return -EINVAL;
down(&fh->cap.lock);
if (fmt->depth != pic->depth && !sloppy) {
retval = -EINVAL;
if (fmt->depth != pic->depth && !sloppy)
goto fh_unlock_and_return;
}
fh->ovfmt = fmt;
fh->fmt = fmt;
btv->init.ovfmt = fmt;
......@@ -2181,13 +2214,11 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
/* verify args */
if (NULL == btv->fbuf.base)
return -EINVAL;
if (fh->ov.w.width <48 ||
fh->ov.w.height<32 ||
fh->ov.w.width >bttv_tvnorms[btv->tvnorm].swidth ||
fh->ov.w.height>bttv_tvnorms[btv->tvnorm].sheight||
NULL == fh->ovfmt)
if (!fh->ov.setup_ok) {
dprintk("bttv%d: overlay: !setup_ok\n",btv->nr);
return -EINVAL;
}
}
if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
return -EBUSY;
......@@ -2210,7 +2241,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
int i;
unsigned int i;
down(&fh->cap.lock);
retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize);
......@@ -2290,6 +2321,56 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return retval;
}
case VIDIOCGVBIFMT:
{
struct vbi_format *fmt = (void *) arg;
struct v4l2_format fmt2;
if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
}
bttv_vbi_get_fmt(fh, &fmt2);
memset(fmt,0,sizeof(*fmt));
fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
fmt->sample_format = VIDEO_PALETTE_RAW;
fmt->start[0] = fmt2.fmt.vbi.start[0];
fmt->count[0] = fmt2.fmt.vbi.count[0];
fmt->start[1] = fmt2.fmt.vbi.start[1];
fmt->count[1] = fmt2.fmt.vbi.count[1];
if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
fmt->flags |= V4L2_VBI_UNSYNC;
if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
fmt->flags |= V4L2_VBI_INTERLACED;
return 0;
}
case VIDIOCSVBIFMT:
{
struct vbi_format *fmt = (void *) arg;
struct v4l2_format fmt2;
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
bttv_vbi_get_fmt(fh, &fmt2);
if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
fmt->sample_format != VIDEO_PALETTE_RAW ||
fmt->start[0] != fmt2.fmt.vbi.start[0] ||
fmt->start[1] != fmt2.fmt.vbi.start[1] ||
fmt->count[0] != fmt->count[1] ||
fmt->count[0] < 1 ||
fmt->count[0] > 32 /* VBI_MAXLINES */)
return -EINVAL;
bttv_vbi_setlines(fh,btv,fmt->count[0]);
return 0;
}
case BTTV_VERSION:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
......@@ -2326,7 +2407,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_fmtdesc *f = arg;
enum v4l2_buf_type type;
int i, index;
unsigned int i;
int index;
type = f->type;
if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
......@@ -2347,7 +2429,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
for (i = 0; i < BTTV_FORMATS; i++) {
if (bttv_formats[i].fourcc != -1)
index++;
if (index == f->index)
if ((unsigned int)index == f->index)
break;
}
if (BTTV_FORMATS == i)
......@@ -2604,8 +2686,8 @@ static ssize_t bttv_read(struct file *file, char *data,
if (fh->btv->errors)
bttv_reinit_bt848(fh->btv);
dprintk("read count=%d type=%s\n",
(int)count,v4l2_type_names[fh->type]);
dprintk("bttv%d: read count=%d type=%s\n",
fh->btv->nr,(int)count,v4l2_type_names[fh->type]);
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
......@@ -2628,6 +2710,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
{
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
enum v4l2_field field;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
......@@ -2654,7 +2737,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
up(&fh->cap.lock);
return POLLERR;
}
if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,fh->cap.field)) {
field = videobuf_next_field(&fh->cap);
if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,field)) {
up(&fh->cap.lock);
return POLLERR;
}
......@@ -2674,11 +2758,11 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
static int bttv_open(struct inode *inode, struct file *file)
{
unsigned int minor = minor(inode->i_rdev);
int minor = minor(inode->i_rdev);
struct bttv *btv = NULL;
struct bttv_fh *fh;
enum v4l2_buf_type type = 0;
int i;
unsigned int i;
dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
......@@ -2707,6 +2791,7 @@ static int bttv_open(struct inode *inode, struct file *file)
file->private_data = fh;
*fh = btv->init;
fh->type = type;
fh->ov.setup_ok = 0;
videobuf_queue_init(&fh->cap, &bttv_video_qops,
btv->dev, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
......@@ -2720,6 +2805,8 @@ static int bttv_open(struct inode *inode, struct file *file)
i2c_vidiocschan(btv);
btv->users++;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
bttv_vbi_setlines(fh,btv,16);
bttv_field_count(btv);
return 0;
}
......@@ -2807,10 +2894,10 @@ struct video_device bttv_vbi_template =
static int radio_open(struct inode *inode, struct file *file)
{
unsigned int minor = minor(inode->i_rdev);
int minor = minor(inode->i_rdev);
struct bttv *btv = NULL;
unsigned long v = 400*16;
int i;
u32 v = 400*16;
unsigned int i;
dprintk("bttv: open minor=%d\n",minor);
......@@ -2934,10 +3021,10 @@ static char *irq_name[] = { "FMTCHG", "VSYNC", "HSYNC", "OFLOW", "HLOCK",
static void bttv_print_irqbits(u32 print, u32 mark)
{
int i;
unsigned int i;
printk("bits:");
for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
if (print & (1 << i))
printk(" %s",irq_name[i]);
if (mark & (1 << i))
......@@ -2950,132 +3037,53 @@ static void bttv_print_riscaddr(struct bttv *btv)
printk(" main: %08Lx\n",
(unsigned long long)btv->main.dma);
printk(" vbi : o=%08Lx e=%08Lx\n",
btv->vcurr ? (unsigned long long)btv->vcurr->top.dma : 0,
btv->vcurr ? (unsigned long long)btv->vcurr->bottom.dma : 0);
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->top.dma : 0,
btv->curr.vbi ? (unsigned long long)btv->curr.vbi->bottom.dma : 0);
printk(" cap : o=%08Lx e=%08Lx\n",
btv->top ? (unsigned long long)btv->top->top.dma : 0,
btv->bottom ? (unsigned long long)btv->bottom->bottom.dma : 0);
btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
printk(" scr : o=%08Lx e=%08Lx\n",
btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
}
static void bttv_irq_timeout(unsigned long data)
{
struct bttv *btv = (struct bttv *)data;
struct bttv_buffer *o_bottom,*o_top,*o_vcurr;
struct bttv_buffer *capture;
if (bttv_verbose) {
printk(KERN_INFO "bttv%d: timeout: risc=%08x, ",
btv->nr,btread(BT848_RISC_COUNT));
bttv_print_irqbits(btread(BT848_INT_STAT),0);
printk("\n");
}
spin_lock(&btv->s_lock);
o_top = btv->top;
o_bottom = btv->bottom;
o_vcurr = btv->vcurr;
btv->top = NULL;
btv->bottom = NULL;
btv->vcurr = NULL;
/* deactivate stuff */
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
bttv_set_dma(btv, 0, 0);
/* wake up + free */
if (o_top == o_bottom) {
if (NULL != o_top) {
o_top->vb.state = STATE_ERROR;
wake_up(&o_top->vb.done);
}
} else {
if (NULL != o_top) {
o_top->vb.state = STATE_ERROR;
wake_up(&o_top->vb.done);
}
if (NULL != o_bottom) {
o_bottom->vb.state = STATE_ERROR;
wake_up(&o_bottom->vb.done);
}
}
if (NULL != o_vcurr) {
o_vcurr->vb.state = STATE_ERROR;
wake_up(&o_vcurr->vb.done);
}
/* cancel all outstanding capture / vbi requests */
while (!list_empty(&btv->capture)) {
capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
list_del(&capture->vb.queue);
capture->vb.state = STATE_ERROR;
wake_up(&capture->vb.done);
}
while (!list_empty(&btv->vcapture)) {
capture = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
list_del(&capture->vb.queue);
capture->vb.state = STATE_ERROR;
wake_up(&capture->vb.done);
}
btv->errors++;
spin_unlock(&btv->s_lock);
}
static void
bttv_irq_switch_fields(struct bttv *btv)
static int
bttv_irq_next_set(struct bttv *btv, struct bttv_buffer_set *set)
{
struct bttv_buffer *o_bottom,*o_top,*o_vcurr;
struct bttv_buffer *capture;
dma_addr_t rc;
int irqflags = 0;
struct timeval ts;
struct bttv_buffer *item;
spin_lock(&btv->s_lock);
o_top = btv->top;
o_bottom = btv->bottom;
o_vcurr = btv->vcurr;
btv->top = NULL;
btv->bottom = NULL;
btv->vcurr = NULL;
memset(set,0,sizeof(*set));
/* vbi request ? */
if (!list_empty(&btv->vcapture)) {
irqflags = 1;
btv->vcurr = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
list_del(&btv->vcurr->vb.queue);
set->irqflags = 1;
set->vbi = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
}
/* capture request ? */
if (!list_empty(&btv->capture)) {
irqflags = 1;
capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
list_del(&capture->vb.queue);
if (V4L2_FIELD_HAS_TOP(capture->vb.field))
btv->top = capture;
if (V4L2_FIELD_HAS_BOTTOM(capture->vb.field))
btv->bottom = capture;
set->irqflags = 1;
item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
if (V4L2_FIELD_HAS_TOP(item->vb.field))
set->top = item;
if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
set->bottom = item;
/* capture request for other field ? */
if (!V4L2_FIELD_HAS_BOTH(capture->vb.field) &&
!list_empty(&btv->capture)) {
capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
if (!V4L2_FIELD_HAS_BOTH(capture->vb.field)) {
if (NULL == btv->top &&
V4L2_FIELD_TOP == capture->vb.field) {
btv->top = capture;
list_del(&capture->vb.queue);
if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
(item->vb.queue.next != &btv->capture)) {
item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
if (NULL == set->top &&
V4L2_FIELD_TOP == item->vb.field) {
set->top = item;
}
if (NULL == btv->bottom &&
V4L2_FIELD_BOTTOM == capture->vb.field) {
btv->bottom = capture;
list_del(&capture->vb.queue);
if (NULL == set->bottom &&
V4L2_FIELD_BOTTOM == item->vb.field) {
set->bottom = item;
}
if (NULL != set->top && NULL != set->bottom)
set->topirq = 2;
}
}
}
......@@ -3083,76 +3091,163 @@ bttv_irq_switch_fields(struct bttv *btv)
/* screen overlay ? */
if (NULL != btv->screen) {
if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
if (NULL == btv->top && NULL == btv->bottom) {
btv->top = btv->screen;
btv->bottom = btv->screen;
if (NULL == set->top && NULL == set->bottom) {
set->top = btv->screen;
set->bottom = btv->screen;
}
} else {
if (V4L2_FIELD_TOP == btv->screen->vb.field &&
NULL == btv->top) {
btv->top = btv->screen;
NULL == set->top) {
set->top = btv->screen;
}
if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
NULL == btv->bottom) {
btv->bottom = btv->screen;
NULL == set->bottom) {
set->bottom = btv->screen;
}
}
}
if (irq_debug)
printk(KERN_DEBUG "bttv%d: irq top=0x%08x bottom=0x%08x"
" vbi=0x%08x/0x%08x\n", btv->nr,
btv->top ? btv->top->top.dma : 0,
btv->bottom ? btv->bottom->bottom.dma : 0,
btv->vcurr ? btv->vcurr->top.dma : 0,
btv->vcurr ? btv->vcurr->bottom.dma : 0);
dprintk("bttv%d: next set: top=%p bottom=%p vbi=%p "
"[screen=%p,irq=%d,%d]\n",
btv->nr,set->top, set->bottom, set->vbi,
btv->screen,set->irqflags,set->topirq);
return 0;
}
rc = btread(BT848_RISC_COUNT);
if (rc < btv->main.dma || rc > btv->main.dma + 0x100)
printk("bttv%d: Huh? IRQ latency? main=0x%x rc=0x%x\n",
btv->nr,btv->main.dma,rc);
/* activate new fields */
bttv_buffer_activate(btv,btv->top,btv->bottom);
if (btv->vcurr) {
btv->vcurr->vb.state = STATE_ACTIVE;
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &btv->vcurr->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &btv->vcurr->bottom, 0);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
}
bttv_set_dma(btv, 0, irqflags);
static void
bttv_irq_wakeup_set(struct bttv *btv, struct bttv_buffer_set *wakeup,
struct bttv_buffer_set *curr, unsigned int state)
{
struct timeval ts;
/* wake up + free */
do_gettimeofday(&ts);
if (o_top == o_bottom) {
if (NULL != o_top && btv->top != o_top) {
o_top->vb.ts = ts;
o_top->vb.field_count = btv->field_count;
o_top->vb.state = STATE_DONE;
wake_up(&o_top->vb.done);
if (NULL != wakeup->vbi) {
wakeup->vbi->vb.ts = ts;
wakeup->vbi->vb.field_count = btv->field_count;
wakeup->vbi->vb.state = state;
wake_up(&wakeup->vbi->vb.done);
}
if (wakeup->top == wakeup->bottom) {
if (NULL != wakeup->top && curr->top != wakeup->top) {
if (irq_debug)
printk("bttv%d: wakeup: both=%p\n",btv->nr,wakeup->top);
wakeup->top->vb.ts = ts;
wakeup->top->vb.field_count = btv->field_count;
wakeup->top->vb.state = state;
wake_up(&wakeup->top->vb.done);
}
} else {
if (NULL != o_top && btv->top != o_top) {
o_top->vb.ts = ts;
o_top->vb.field_count = btv->field_count;
o_top->vb.state = STATE_DONE;
wake_up(&o_top->vb.done);
if (NULL != wakeup->top && curr->top != wakeup->top) {
if (irq_debug)
printk("bttv%d: wakeup: top=%p\n",btv->nr,wakeup->top);
wakeup->top->vb.ts = ts;
wakeup->top->vb.field_count = btv->field_count;
wakeup->top->vb.state = state;
wake_up(&wakeup->top->vb.done);
}
if (NULL != o_bottom && btv->bottom != o_bottom) {
o_bottom->vb.ts = ts;
o_bottom->vb.field_count = btv->field_count;
o_bottom->vb.state = STATE_DONE;
wake_up(&o_bottom->vb.done);
if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
if (irq_debug)
printk("bttv%d: wakeup: bottom=%p\n",btv->nr,wakeup->bottom);
wakeup->bottom->vb.ts = ts;
wakeup->bottom->vb.field_count = btv->field_count;
wakeup->bottom->vb.state = state;
wake_up(&wakeup->bottom->vb.done);
}
}
if (NULL != o_vcurr) {
o_vcurr->vb.ts = ts;
o_vcurr->vb.field_count = btv->field_count;
o_vcurr->vb.state = STATE_DONE;
wake_up(&o_vcurr->vb.done);
}
static void bttv_irq_timeout(unsigned long data)
{
struct bttv *btv = (struct bttv *)data;
struct bttv_buffer_set old,new;
struct bttv_buffer *item;
if (bttv_verbose) {
printk(KERN_INFO "bttv%d: timeout: risc=%08x, ",
btv->nr,btread(BT848_RISC_COUNT));
bttv_print_irqbits(btread(BT848_INT_STAT),0);
printk("\n");
}
spin_lock(&btv->s_lock);
/* deactivate stuff */
memset(&new,0,sizeof(new));
old = btv->curr;
btv->curr = new;
bttv_buffer_set_activate(btv, &new);
bttv_set_dma(btv, 0, 0);
/* wake up */
bttv_irq_wakeup_set(btv, &old, &new, STATE_ERROR);
/* cancel all outstanding capture / vbi requests */
while (!list_empty(&btv->capture)) {
item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
list_del(&item->vb.queue);
item->vb.state = STATE_ERROR;
wake_up(&item->vb.done);
}
while (!list_empty(&btv->vcapture)) {
item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
list_del(&item->vb.queue);
item->vb.state = STATE_ERROR;
wake_up(&item->vb.done);
}
btv->errors++;
spin_unlock(&btv->s_lock);
}
static void
bttv_irq_wakeup_top(struct bttv *btv)
{
struct bttv_buffer *wakeup = btv->curr.top;
if (NULL == wakeup)
return;
spin_lock(&btv->s_lock);
btv->curr.topirq = 0;
btv->curr.top = NULL;
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
do_gettimeofday(&wakeup->vb.ts);
wakeup->vb.field_count = btv->field_count;
wakeup->vb.state = STATE_DONE;
wake_up(&wakeup->vb.done);
spin_unlock(&btv->s_lock);
}
static void
bttv_irq_switch_fields(struct bttv *btv)
{
struct bttv_buffer_set new;
struct bttv_buffer_set old;
dma_addr_t rc;
spin_lock(&btv->s_lock);
/* new buffer set */
bttv_irq_next_set(btv, &new);
rc = btread(BT848_RISC_COUNT);
if (rc < btv->main.dma || rc > btv->main.dma + 0x100) {
if (1 /* irq_debug */)
printk("bttv%d: skipped frame. no signal? high irq latency?\n",
btv->nr);
spin_unlock(&btv->s_lock);
return;
}
/* switch over */
old = btv->curr;
btv->curr = new;
bttv_buffer_set_activate(btv, &new);
bttv_set_dma(btv, 0, new.irqflags);
/* wake up finished buffers */
bttv_irq_wakeup_set(btv, &old, &new, STATE_DONE);
spin_unlock(&btv->s_lock);
}
......@@ -3178,7 +3273,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
/* get device status bits */
dstat=btread(BT848_DSTATUS);
if (irq_debug) {
if (0 /*irq_debug*/) {
printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
"riscs=%x, riscc=%08x, ",
btv->nr, count, btv->field_count,
......@@ -3202,6 +3297,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (astat & BT848_INT_GPINT)
wake_up(&btv->gpioq);
if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
bttv_irq_wakeup_top(btv);
if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
bttv_irq_switch_fields(btv);
......@@ -3308,7 +3406,8 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->timeout.data = (unsigned long)btv;
btv->i2c_rc = -1;
btv->tuner_type = -1;
btv->tuner_type = UNSET;
btv->pinnacle_id = UNSET;
memcpy(&btv->video_dev, &bttv_video_template, sizeof(bttv_video_template));
memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template));
......@@ -3485,7 +3584,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
video_unregister_device(&btv->vbi_dev);
/* free allocated memory */
bttv_riscmem_free(btv->dev,&btv->main);
btcx_riscmem_free(btv->dev,&btv->main);
/* free ressources */
free_irq(btv->dev->irq,btv);
......@@ -3519,6 +3618,7 @@ static struct pci_driver bttv_pci_driver = {
static int bttv_init_module(void)
{
int rc;
bttv_num = 0;
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
......@@ -3536,7 +3636,13 @@ static int bttv_init_module(void)
bttv_check_chipset();
return pci_module_init(&bttv_pci_driver);
rc = pci_module_init(&bttv_pci_driver);
if (-ENODEV == rc) {
/* plenty of people trying to use bttv for the cx2388x ... */
if (NULL != pci_find_device(0x14f1, 0x8800, NULL))
printk("bttv doesn't support your Conexant 2388x card.\n");
}
return rc;
}
static void bttv_cleanup_module(void)
......
......@@ -25,7 +25,6 @@
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
......@@ -198,6 +197,9 @@ static int attach_inform(struct i2c_client *client)
if (btv->tuner_type != UNSET)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
if (btv->pinnacle_id != UNSET)
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
&btv->pinnacle_id);
if (bttv_debug)
printk("bttv%d: i2c attach [client=%s]\n",
......@@ -231,9 +233,9 @@ static struct i2c_algo_bit_data bttv_i2c_algo_template = {
static struct i2c_adapter bttv_i2c_adap_template = {
.owner = THIS_MODULE,
.class = I2C_ADAP_CLASS_TV_ANALOG,
I2C_DEVNAME("bt848"),
.id = I2C_HW_B_BT848,
.class = I2C_ADAP_CLASS_TV_ANALOG,
.client_register = attach_inform,
};
......@@ -314,6 +316,7 @@ int __devinit init_bttv_i2c(struct bttv *btv)
sizeof(struct i2c_client));
sprintf(btv->i2c_adap.dev.name, "bt848 #%d", btv->nr);
btv->i2c_adap.dev.parent = &btv->dev->dev;
btv->i2c_algo.data = btv;
i2c_set_adapdata(&btv->i2c_adap, btv);
......
......@@ -23,7 +23,6 @@
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
......@@ -34,59 +33,25 @@
#include "bttvp.h"
/* ---------------------------------------------------------- */
/* allocate/free risc memory */
int bttv_riscmem_alloc(struct pci_dev *pci,
struct bttv_riscmem *risc,
unsigned int size)
{
u32 *cpu;
dma_addr_t dma;
cpu = pci_alloc_consistent(pci, size, &dma);
if (NULL == cpu)
return -ENOMEM;
memset(cpu,0,size);
if (risc->cpu && risc->size < size) {
/* realloc (enlarge buffer) -- copy old stuff */
memcpy(cpu,risc->cpu,risc->size);
bttv_riscmem_free(pci,risc);
}
risc->cpu = cpu;
risc->dma = dma;
risc->size = size;
return 0;
}
void bttv_riscmem_free(struct pci_dev *pci,
struct bttv_riscmem *risc)
{
if (NULL == risc->cpu)
return;
pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
memset(risc,0,sizeof(*risc));
}
/* ---------------------------------------------------------- */
/* risc code generators */
int
bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc,
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
int offset, int bpl, int padding, int lines)
unsigned int offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
{
int instructions,rc,line,todo;
u32 instructions,line,todo;
struct scatterlist *sg;
u32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + sync + jump (all 2 dwords) */
instructions = (bpl * lines) / PAGE_SIZE + lines;
instructions += 2;
if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
return rc;
/* sync instruction */
......@@ -130,6 +95,7 @@ bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc,
}
offset += padding;
}
dprintk("bttv%d: risc planar: %d sglist elems\n", btv->nr, (int)(sg-sglist));
/* save pointer to jmp instruction address */
risc->jmp = rp;
......@@ -137,24 +103,27 @@ bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc,
}
int
bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc,
bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
int yoffset, int ybpl, int ypadding, int ylines,
int uoffset, int voffset, int hshift, int vshift,
int cpadding)
unsigned int yoffset, unsigned int ybpl,
unsigned int ypadding, unsigned int ylines,
unsigned int uoffset, unsigned int voffset,
unsigned int hshift, unsigned int vshift,
unsigned int cpadding)
{
int instructions,rc,line,todo,ylen,chroma;
unsigned int instructions,line,todo,ylen,chroma;
u32 *rp,ri;
struct scatterlist *ysg;
struct scatterlist *usg;
struct scatterlist *vsg;
int rc;
/* estimate risc mem: worst case is one write per page border +
one write per scan line (5 dwords)
plus sync + jump (2 dwords) */
instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
instructions += 2;
if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0)
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0)
return rc;
/* sync instruction */
......@@ -231,138 +200,13 @@ bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc,
return 0;
}
/* ---------------------------------------------------------- */
struct SKIPLIST {
int start;
int end;
};
int
bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, int n)
{
if (win->left < 0) {
/* left */
clips[n].c.left = 0;
clips[n].c.top = 0;
clips[n].c.width = -win->left;
clips[n].c.height = win->height;
n++;
}
if (win->left + win->width > swidth) {
/* right */
clips[n].c.left = swidth - win->left;
clips[n].c.top = 0;
clips[n].c.width = win->width - clips[n].c.left;
clips[n].c.height = win->height;
n++;
}
if (win->top < 0) {
/* top */
clips[n].c.left = 0;
clips[n].c.top = 0;
clips[n].c.width = win->width;
clips[n].c.height = -win->top;
n++;
}
if (win->top + win->height > sheight) {
/* bottom */
clips[n].c.left = 0;
clips[n].c.top = sheight - win->top;
clips[n].c.width = win->width;
clips[n].c.height = win->height - clips[n].c.top;
n++;
}
return n;
}
void
bttv_sort_clips(struct v4l2_clip *clips, int nclips)
{
struct v4l2_clip swap;
int i,j,n;
for (i = nclips-2; i >= 0; i--) {
for (n = 0, j = 0; j <= i; j++) {
if (clips[j].c.left > clips[j+1].c.left) {
swap = clips[j];
clips[j] = clips[j+1];
clips[j+1] = swap;
n++;
}
}
if (0 == n)
break;
}
}
static void
calc_skips(int line, int width, int *maxy,
struct SKIPLIST *skips, int *nskips,
const struct v4l2_clip *clips, int nclips)
{
int clip,skip,maxline,end;
skip=0;
maxline = 9999;
for (clip = 0; clip < nclips; clip++) {
/* sanity checks */
if (clips[clip].c.left + clips[clip].c.width <= 0)
continue;
if (clips[clip].c.left > width)
break;
/* vertical range */
if (line > clips[clip].c.top+clips[clip].c.height-1)
continue;
if (line < clips[clip].c.top) {
if (maxline > clips[clip].c.top-1)
maxline = clips[clip].c.top-1;
continue;
}
if (maxline > clips[clip].c.top+clips[clip].c.height-1)
maxline = clips[clip].c.top+clips[clip].c.height-1;
/* horizontal range */
if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
/* new one */
skips[skip].start = clips[clip].c.left;
if (skips[skip].start < 0)
skips[skip].start = 0;
skips[skip].end = clips[clip].c.left + clips[clip].c.width;
if (skips[skip].end > width)
skips[skip].end = width;
skip++;
} else {
/* overlaps -- expand last one */
end = clips[clip].c.left + clips[clip].c.width;
if (skips[skip-1].end < end)
skips[skip-1].end = end;
if (skips[skip-1].end > width)
skips[skip-1].end = width;
}
}
*nskips = skip;
*maxy = maxline;
if (bttv_debug) {
printk(KERN_DEBUG "bttv: skips line %d-%d:",line,maxline);
for (skip = 0; skip < *nskips; skip++) {
printk(" %d-%d",skips[skip].start,skips[skip].end);
}
printk("\n");
}
}
int
bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt, struct bttv_overlay *ov,
int skip_even, int skip_odd)
{
int instructions,rc,line,maxy,start,end,skip,nskips;
struct SKIPLIST *skips;
struct btcx_skiplist *skips;
u32 *rp,ri,ra;
u32 addr;
......@@ -375,7 +219,7 @@ bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
instructions = (ov->nclips + 1) *
((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height);
instructions += 2;
if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0)
return rc;
/* sync instruction */
......@@ -397,7 +241,7 @@ bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
/* calculate clipping */
if (line > maxy)
calc_skips(line, ov->w.width, &maxy,
btcx_calc_skips(line, ov->w.width, &maxy,
skips, &nskips, ov->clips, ov->nclips);
/* write out risc code */
......@@ -432,7 +276,6 @@ bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
kfree(skips);
return 0;
}
......@@ -476,6 +319,7 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
geo->vdelay = vdelay;
geo->width = width;
geo->sheight = tvnorm->sheight;
geo->vtotal = tvnorm->vtotal;
if (btv->opt_combfilter) {
geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
......@@ -506,6 +350,8 @@ bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
btwrite(geo->crop, BT848_E_CROP+off);
btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
}
/* ---------------------------------------------------------- */
......@@ -518,9 +364,9 @@ bttv_set_dma(struct bttv *btv, int override, int irqflags)
int capctl;
btv->cap_ctl = 0;
if (NULL != btv->top) btv->cap_ctl |= 0x02;
if (NULL != btv->bottom) btv->cap_ctl |= 0x01;
if (NULL != btv->vcurr) btv->cap_ctl |= 0x0c;
if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
if (NULL != btv->curr.vbi) btv->cap_ctl |= 0x0c;
capctl = 0;
capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
......@@ -530,14 +376,16 @@ 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->vcurr ? (unsigned long long)btv->vcurr->top.dma : 0,
btv->top ? (unsigned long long)btv->top->top.dma : 0,
btv->vcurr ? (unsigned long long)btv->vcurr->bottom.dma : 0,
btv->bottom ? (unsigned long long)btv->bottom->bottom.dma : 0);
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,
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
cmd = BT848_RISC_JUMP;
if (irqflags) {
cmd |= BT848_RISC_IRQ | (irqflags << 16);
cmd |= BT848_RISC_IRQ;
cmd |= (irqflags & 0x0f) << 16;
cmd |= (~irqflags & 0x0f) << 20;
mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
} else {
del_timer(&btv->timeout);
......@@ -565,7 +413,7 @@ bttv_risc_init_main(struct bttv *btv)
{
int rc;
if ((rc = bttv_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0)
if ((rc = btcx_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0)
return rc;
dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
btv->nr,(unsigned long long)btv->main.dma);
......@@ -600,7 +448,7 @@ bttv_risc_init_main(struct bttv *btv)
}
int
bttv_risc_hook(struct bttv *btv, int slot, struct bttv_riscmem *risc,
bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
int irqflags)
{
unsigned long cmd;
......@@ -614,8 +462,11 @@ bttv_risc_hook(struct bttv *btv, int slot, struct bttv_riscmem *risc,
d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
btv->nr,risc,slot,(unsigned long long)risc->dma,irqflags);
cmd = BT848_RISC_JUMP;
if (irqflags)
cmd |= BT848_RISC_IRQ | (irqflags << 16);
if (irqflags) {
cmd |= BT848_RISC_IRQ;
cmd |= (irqflags & 0x0f) << 16;
cmd |= (~irqflags & 0x0f) << 20;
}
risc->jmp[0] = cpu_to_le32(cmd);
risc->jmp[1] = cpu_to_le32(next);
btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
......@@ -631,43 +482,68 @@ bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma);
videobuf_dma_free(&buf->vb.dma);
bttv_riscmem_free(btv->dev,&buf->bottom);
bttv_riscmem_free(btv->dev,&buf->top);
btcx_riscmem_free(btv->dev,&buf->bottom);
btcx_riscmem_free(btv->dev,&buf->top);
buf->vb.state = STATE_NEEDS_INIT;
}
int
bttv_buffer_activate(struct bttv *btv,
struct bttv_buffer *top,
struct bttv_buffer *bottom)
bttv_buffer_set_activate(struct bttv *btv,
struct bttv_buffer_set *set)
{
if (NULL != top && NULL != bottom) {
top->vb.state = STATE_ACTIVE;
bottom->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &top->geo, 1);
bttv_apply_geo(btv, &bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0);
btaor((top->btformat & 0xf0) | (bottom->btformat & 0x0f),
/* vbi capture */
if (set->vbi) {
set->vbi->vb.state = STATE_ACTIVE;
list_del(&set->vbi->vb.queue);
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &set->vbi->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &set->vbi->bottom, 0);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
}
/* video capture */
if (NULL != set->top && NULL != set->bottom) {
if (set->top == set->bottom) {
set->top->vb.state = STATE_ACTIVE;
if (set->top->vb.queue.next)
list_del(&set->top->vb.queue);
} else {
set->top->vb.state = STATE_ACTIVE;
set->bottom->vb.state = STATE_ACTIVE;
if (set->top->vb.queue.next)
list_del(&set->top->vb.queue);
if (set->bottom->vb.queue.next)
list_del(&set->bottom->vb.queue);
}
bttv_apply_geo(btv, &set->top->geo, 1);
bttv_apply_geo(btv, &set->bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, set->topirq);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 0);
btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
~0xff, BT848_COLOR_FMT);
btaor((top->btswap & 0x0a) | (bottom->btswap & 0x05),
btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
~0x0f, BT848_COLOR_CTL);
} else if (NULL != top) {
top->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &top->geo,1);
bttv_apply_geo(btv, &top->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0);
} else if (NULL != set->top) {
set->top->vb.state = STATE_ACTIVE;
if (set->top->vb.queue.next)
list_del(&set->top->vb.queue);
bttv_apply_geo(btv, &set->top->geo,1);
bttv_apply_geo(btv, &set->top->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
btaor(top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else if (NULL != bottom) {
bottom->vb.state = STATE_ACTIVE;
bttv_apply_geo(btv, &bottom->geo,1);
bttv_apply_geo(btv, &bottom->geo,0);
btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else if (NULL != set->bottom) {
set->bottom->vb.state = STATE_ACTIVE;
if (set->bottom->vb.queue.next)
list_del(&set->bottom->vb.queue);
bttv_apply_geo(btv, &set->bottom->geo,1);
bttv_apply_geo(btv, &set->bottom->geo,0);
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0);
btaor(bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 0);
btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
} else {
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
......@@ -781,6 +657,29 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
buf->fmt->vshift,
cpadding);
break;
case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,1,buf->tvnorm);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
buf->vb.dma.sglist,
0,buf->vb.width,0,lines,
uoffset >> 1,
voffset >> 1,
buf->fmt->hshift,
buf->fmt->vshift,
0);
bttv_risc_planar(btv,&buf->bottom,
buf->vb.dma.sglist,
lines * ypadding,buf->vb.width,0,lines,
lines * ypadding + (uoffset >> 1),
lines * ypadding + (voffset >> 1),
buf->fmt->hshift,
buf->fmt->vshift,
0);
break;
default:
BUG();
}
......
......@@ -19,7 +19,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
......@@ -155,11 +154,53 @@ void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
}
}
void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f)
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
const struct bttv_tvnorm *tvnorm;
u32 start0,start1;
s32 count0,count1,count;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244;
f->fmt.vbi.flags = 0;
switch (fh->btv->tvnorm) {
case 1: /* NTSC */
start0 = 10;
start1 = 273;
break;
case 0: /* PAL */
case 2: /* SECAM */
default:
start0 = 7;
start1 = 319;
}
count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0;
count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1;
count = max(count0,count1);
if (count > VBI_MAXLINES)
count = VBI_MAXLINES;
if (count < 1)
count = 1;
f->fmt.vbi.start[0] = start0;
f->fmt.vbi.start[1] = start1;
f->fmt.vbi.count[0] = count;
f->fmt.vbi.count[1] = count;
}
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
{
const struct bttv_tvnorm *tvnorm;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
memset(f,0,sizeof(*f));
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
f->fmt.vbi.samples_per_line = 2048;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244;
......
......@@ -90,6 +90,7 @@
#define BTTV_SENSORAY311 0x49
#define BTTV_RV605 0x4a
#define BTTV_WINDVR 0x4c
#define BTTV_GRANDTEC 0x4d
#define BTTV_KWORLD 0x4e
#define BTTV_HAUPPAUGEPVR 0x50
#define BTTV_GVBCTV5PCI 0x51
......@@ -108,6 +109,12 @@
#define BTTV_PINNACLESAT 0x5e
#define BTTV_FORMAC_PROTV 0x5f
#define BTTV_EURESYS_PICOLO 0x61
#define BTTV_PV150 0x62
#define BTTV_AD_TVK503 0x63
#define BTTV_IVC200 0x66
#define BTTV_XGUARD 0x67
#define BTTV_NEBULA_DIGITV 0x68
#define BTTV_PV143 0x69
/* i2c address list */
#define I2C_TSA5522 0xc2
......@@ -123,6 +130,7 @@
#define I2C_STBEE 0xae
#define I2C_VHX 0xc0
#define I2C_MSP3400 0x80
#define I2C_MSP3400_ALT 0x88
#define I2C_TEA6300 0x80
#define I2C_DPL3518 0x84
#define I2C_TDA9887 0x86
......@@ -145,36 +153,37 @@ struct bttv;
struct tvcard
{
char *name;
int video_inputs;
int audio_inputs;
int tuner;
int svhs;
int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
unsigned int video_inputs;
unsigned int audio_inputs;
unsigned int tuner;
unsigned int svhs;
unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
u32 gpiomask;
u32 muxsel[16];
u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
u32 gpiomask2; /* GPIO MUX mask */
/* i2c audio flags */
int no_msp34xx:1;
int no_tda9875:1;
int no_tda7432:1;
int needs_tvaudio:1;
unsigned int no_msp34xx:1;
unsigned int no_tda9875:1;
unsigned int no_tda7432:1;
unsigned int needs_tvaudio:1;
unsigned int msp34xx_alt:1;
/* other settings */
int pll;
unsigned int pll;
#define PLL_NONE 0
#define PLL_28 1
#define PLL_35 2
int tuner_type;
int has_radio;
unsigned int tuner_type;
unsigned int has_radio;
void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
void (*muxsel_hook)(struct bttv *btv, unsigned int input);
};
extern struct tvcard bttv_tvcards[];
extern const int bttv_num_tvcards;
extern const unsigned int bttv_num_tvcards;
/* identification / initialization of the card */
extern void bttv_idcard(struct bttv *btv);
......
......@@ -24,7 +24,8 @@
#ifndef _BTTVP_H_
#define _BTTVP_H_
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,4)
#include <linux/version.h>
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,11)
#include <linux/types.h>
#include <linux/wait.h>
......@@ -41,6 +42,7 @@
#include "bt848.h"
#include "bttv.h"
#include "btcx-risc.h"
#ifdef __KERNEL__
......@@ -67,8 +69,7 @@
/* ---------------------------------------------------------- */
struct bttv_tvnorm
{
struct bttv_tvnorm {
int v4l2_id;
char *name;
u32 Fsc;
......@@ -79,10 +80,11 @@ struct bttv_tvnorm
u16 hdelayx1, hactivex1;
u16 vdelay;
u8 vbipack;
u16 vtotal;
int sram;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
extern const int BTTV_TVNORMS;
extern const unsigned int BTTV_TVNORMS;
struct bttv_format {
char *name;
......@@ -95,21 +97,14 @@ struct bttv_format {
int hshift,vshift; /* for planar modes */
};
extern const struct bttv_format bttv_formats[];
extern const int BTTV_FORMATS;
extern const unsigned int BTTV_FORMATS;
/* ---------------------------------------------------------- */
struct bttv_geometry {
u8 vtc,crop,comb;
u16 width,hscale,hdelay;
u16 sheight,vscale,vdelay;
};
struct bttv_riscmem {
unsigned int size;
u32 *cpu;
u32 *jmp;
dma_addr_t dma;
u16 sheight,vscale,vdelay,vtotal;
};
struct bttv_buffer {
......@@ -122,8 +117,16 @@ struct bttv_buffer {
int btformat;
int btswap;
struct bttv_geometry geo;
struct bttv_riscmem top;
struct bttv_riscmem bottom;
struct btcx_riscmem top;
struct btcx_riscmem bottom;
};
struct bttv_buffer_set {
struct bttv_buffer *top; /* top field buffer */
struct bttv_buffer *bottom; /* bottom field buffer */
struct bttv_buffer *vbi; /* vbi buffer */
unsigned int irqflags;
unsigned int topirq;
};
struct bttv_overlay {
......@@ -132,6 +135,7 @@ struct bttv_overlay {
enum v4l2_field field;
struct v4l2_clip *clips;
int nclips;
int setup_ok;
};
struct bttv_fh {
......@@ -141,7 +145,6 @@ struct bttv_fh {
/* video capture */
struct videobuf_queue cap;
/* struct bttv_buffer buf; */
const struct bttv_format *fmt;
int width;
int height;
......@@ -158,28 +161,19 @@ struct bttv_fh {
/* ---------------------------------------------------------- */
/* bttv-risc.c */
/* alloc/free memory */
int bttv_riscmem_alloc(struct pci_dev *pci,
struct bttv_riscmem *risc,
unsigned int size);
void bttv_riscmem_free(struct pci_dev *pci,
struct bttv_riscmem *risc);
/* risc code generators - capture */
int bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc,
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
int offset, int bpl, int pitch, int lines);
int bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc,
unsigned int offset, unsigned int bpl,
unsigned int pitch, unsigned int lines);
int bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
int yoffset, int ybpl, int ypadding, int ylines,
int uoffset, int voffset, int hshift, int vshift,
int cpadding);
/* risc code generator + helpers - screen overlay */
int bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
struct v4l2_clip *clips, int n);
void bttv_sort_clips(struct v4l2_clip *clips, int nclips);
int bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc,
unsigned int yoffset, unsigned int ybpl,
unsigned int ypadding, unsigned int ylines,
unsigned int uoffset, unsigned int voffset,
unsigned int hshift, unsigned int vshift,
unsigned int cpadding);
int bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt,
struct bttv_overlay *ov,
int skip_top, int skip_bottom);
......@@ -192,13 +186,13 @@ void bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int top);
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override, int irqflags);
int bttv_risc_init_main(struct bttv *btv);
int bttv_risc_hook(struct bttv *btv, int slot, struct bttv_riscmem *risc,
int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
int irqflags);
/* capture buffer handling */
int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
int bttv_buffer_activate(struct bttv *btv, struct bttv_buffer *top,
struct bttv_buffer *bottom);
int bttv_buffer_set_activate(struct bttv *btv,
struct bttv_buffer_set *set);
void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf);
/* overlay handling */
......@@ -210,7 +204,8 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
extern struct videobuf_queue_ops bttv_vbi_qops;
......@@ -236,8 +231,8 @@ extern void bttv_field_count(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
/* our devices */
#define BTTV_MAX 4
extern int bttv_num;
#define BTTV_MAX 16
extern unsigned int bttv_num;
extern struct bttv bttvs[BTTV_MAX];
#define BTTV_MAX_FBUF 0x208000
......@@ -264,8 +259,9 @@ struct bttv {
unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
char name[8]; /* dev name */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */
int type; /* card type (pointer into tvcards[]) */
int tuner_type; /* tuner chip type */
unsigned int type; /* card type (pointer into tvcards[]) */
unsigned int tuner_type; /* tuner chip type */
unsigned int pinnacle_id;
struct bttv_pll_info pll;
int triton1;
......@@ -292,12 +288,12 @@ struct bttv {
struct semaphore reslock;
/* video state */
int input;
int audio;
unsigned int input;
unsigned int audio;
unsigned long freq;
int tvnorm,hue,contrast,bright,saturation;
struct video_buffer fbuf;
int field_count;
unsigned int field_count;
/* various options */
int opt_combfilter;
......@@ -326,21 +322,19 @@ struct bttv {
/* risc memory management data
- must aquire s_lock before changing these
- only the irq handler is supported to touch odd + even */
struct bttv_riscmem main;
struct bttv_buffer *top; /* current active top field */
struct bttv_buffer *bottom; /* current active bottom field */
- only the irq handler is supported to touch top + bottom + vcurr */
struct btcx_riscmem main;
struct bttv_buffer *screen; /* overlay */
struct list_head capture; /* capture buffer queue */
struct bttv_buffer *vcurr;
struct list_head vcapture;
struct list_head capture; /* video capture queue */
struct list_head vcapture; /* vbi capture queue */
struct bttv_buffer_set curr; /* active buffers */
unsigned long cap_ctl;
unsigned long dma_on;
struct timer_list timeout;
int errors;
unsigned int errors;
int users;
unsigned int users;
struct bttv_fh init;
};
......
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