2005-04-17 06:20:36 +08:00
/*
zr36120 . c - Zoran 36120 / 36125 based framegrabbers
Copyright ( C ) 1998 - 1999 Pauline Middelink < middelin @ polyware . nl >
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 0213 9 , USA .
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/kernel.h>
# include <linux/major.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/mm.h>
# include <linux/pci.h>
# include <linux/signal.h>
# include <linux/wait.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/page.h>
# include <linux/sched.h>
# include <linux/video_decoder.h>
# include <asm/uaccess.h>
# include "tuner.h"
# include "zr36120.h"
# include "zr36120_mem.h"
/* mark an required function argument unused - lintism */
# define UNUSED(x) (void)(x)
/* sensible default */
# ifndef CARDTYPE
# define CARDTYPE 0
# endif
/* Anybody who uses more than four? */
# define ZORAN_MAX 4
static unsigned int triton1 = 0 ; /* triton1 chipset? */
static unsigned int cardtype [ ZORAN_MAX ] = { [ 0 . . . ZORAN_MAX - 1 ] = CARDTYPE } ;
static int video_nr = - 1 ;
static int vbi_nr = - 1 ;
static struct pci_device_id zr36120_pci_tbl [ ] = {
{ PCI_VENDOR_ID_ZORAN , PCI_DEVICE_ID_ZORAN_36120 ,
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( pci , zr36120_pci_tbl ) ;
MODULE_AUTHOR ( " Pauline Middelink <middelin@polyware.nl> " ) ;
MODULE_DESCRIPTION ( " Zoran ZR36120 based framegrabber " ) ;
MODULE_LICENSE ( " GPL " ) ;
2006-03-25 19:07:05 +08:00
module_param ( triton1 , uint , 0 ) ;
module_param_array ( cardtype , uint , NULL , 0 ) ;
module_param ( video_nr , int , 0 ) ;
module_param ( vbi_nr , int , 0 ) ;
2005-04-17 06:20:36 +08:00
static int zoran_cards ;
static struct zoran zorans [ ZORAN_MAX ] ;
/*
* the meaning of each element can be found in zr36120 . h
* Determining the value of gpdir / gpval can be tricky . The
* best way is to run the card under the original software
* and read the values from the general purpose registers
* 0x28 and 0x2C . How you do that is left as an exercise
* to the impatient reader : )
*/
# define T 1 /* to separate the bools from the ints */
# define F 0
static struct tvcard tvcards [ ] = {
/* reported working by <middelin@polyware.nl> */
/*0*/ { " Trust Victor II " ,
2 , 0 , T , T , T , T , 0x7F , 0x80 , { 1 , SVHS ( 6 ) } , { 0 } } ,
/* reported working by <Michael.Paxton@aihw.gov.au> */
/*1*/ { " Aitech WaveWatcher TV-PCI " ,
3 , 0 , T , F , T , T , 0x7F , 0x80 , { 1 , TUNER ( 3 ) , SVHS ( 6 ) } , { 0 } } ,
/* reported working by ? */
/*2*/ { " Genius Video Wonder PCI Video Capture Card " ,
2 , 0 , T , T , T , T , 0x7F , 0x80 , { 1 , SVHS ( 6 ) } , { 0 } } ,
/* reported working by <Pascal.Gabriel@wanadoo.fr> */
/*3*/ { " Guillemot Maxi-TV PCI " ,
2 , 0 , T , T , T , T , 0x7F , 0x80 , { 1 , SVHS ( 6 ) } , { 0 } } ,
/* reported working by "Craig Whitmore <lennon@igrin.co.nz> */
/*4*/ { " Quadrant Buster " ,
3 , 3 , T , F , T , T , 0x7F , 0x80 , { SVHS ( 1 ) , TUNER ( 2 ) , 3 } , { 1 , 2 , 3 } } ,
/* a debug entry which has all inputs mapped */
/*5*/ { " ZR36120 based framegrabber (all inputs enabled) " ,
6 , 0 , T , T , T , T , 0x7F , 0x80 , { 1 , 2 , 3 , 4 , 5 , 6 } , { 0 } }
} ;
# undef T
# undef F
# define NRTVCARDS (sizeof(tvcards) / sizeof(tvcards[0]))
# ifdef __sparc__
# define ENDIANESS 0
# else
# define ENDIANESS ZORAN_VFEC_LE
# endif
static struct { const char name [ 8 ] ; uint mode ; uint bpp ; } palette2fmt [ ] = {
/* n/a */ { " n/a " , 0 , 0 } ,
/* GREY */ { " GRAY " , 0 , 0 } ,
/* HI240 */ { " HI240 " , 0 , 0 } ,
/* RGB565 */ { " RGB565 " , ZORAN_VFEC_RGB_RGB565 | ENDIANESS , 2 } ,
/* RGB24 */ { " RGB24 " , ZORAN_VFEC_RGB_RGB888 | ENDIANESS | ZORAN_VFEC_PACK24 , 3 } ,
/* RGB32 */ { " RGB32 " , ZORAN_VFEC_RGB_RGB888 | ENDIANESS , 4 } ,
/* RGB555 */ { " RGB555 " , ZORAN_VFEC_RGB_RGB555 | ENDIANESS , 2 } ,
/* YUV422 */ { " YUV422 " , ZORAN_VFEC_RGB_YUV422 | ENDIANESS , 2 } ,
/* YUYV */ { " YUYV " , 0 , 0 } ,
/* UYVY */ { " UYVY " , 0 , 0 } ,
/* YUV420 */ { " YUV420 " , 0 , 0 } ,
/* YUV411 */ { " YUV411 " , 0 , 0 } ,
/* RAW */ { " RAW " , 0 , 0 } ,
/* YUV422P */ { " YUV422P " , 0 , 0 } ,
/* YUV411P */ { " YUV411P " , 0 , 0 } } ;
# define NRPALETTES (sizeof(palette2fmt) / sizeof(palette2fmt[0]))
# undef ENDIANESS
/* ----------------------------------------------------------------------- */
/* ZORAN chipset detector */
/* shamelessly stolen from bttv.c */
/* Reason for beeing here: we need to detect if we are running on a */
/* Triton based chipset, and if so, enable a certain bit */
/* ----------------------------------------------------------------------- */
static
void __init handle_chipset ( void )
{
/* Just in case some nut set this to something dangerous */
if ( triton1 )
triton1 = ZORAN_VDC_TRICOM ;
if ( pci_pci_problems & PCIPCI_TRITON ) {
printk ( KERN_INFO " zoran: Host bridge 82437FX Triton PIIX \n " ) ;
triton1 = ZORAN_VDC_TRICOM ;
}
}
/* ----------------------------------------------------------------------- */
/* ZORAN functions */
/* ----------------------------------------------------------------------- */
static void zoran_set_geo ( struct zoran * ztv , struct vidinfo * i ) ;
#if 0 /* unused */
static
void zoran_dump ( struct zoran * ztv )
{
char str [ 256 ] ;
char * p = str ; /* shut up, gcc! */
int i ;
for ( i = 0 ; i < 0x60 ; i + = 4 ) {
if ( ( i % 16 ) = = 0 ) {
if ( i ) printk ( " %s \n " , str ) ;
p = str ;
p + = sprintf ( str , KERN_DEBUG " %04x: " , i ) ;
}
p + = sprintf ( p , " %08x " , zrread ( i ) ) ;
}
}
# endif /* unused */
static
void reap_states ( struct zoran * ztv )
{
/* count frames */
ztv - > fieldnr + + ;
/*
* Are we busy at all ?
* This depends on if there is a workqueue AND the
* videotransfer is enabled on the chip . . .
*/
if ( ztv - > workqueue & & ( zrread ( ZORAN_VDC ) & ZORAN_VDC_VIDEN ) )
{
struct vidinfo * newitem ;
/* did we get a complete frame? */
if ( zrread ( ZORAN_VSTR ) & ZORAN_VSTR_GRAB )
return ;
DEBUG ( printk ( CARD_DEBUG " completed %s at %p \n " , CARD , ztv - > workqueue - > kindof = = FBUFFER_GRAB ? " grab " : " read " , ztv - > workqueue ) ) ;
/* we are done with this buffer, tell everyone */
ztv - > workqueue - > status = FBUFFER_DONE ;
ztv - > workqueue - > fieldnr = ztv - > fieldnr ;
/* not good, here for BTTV_FIELDNR reasons */
ztv - > lastfieldnr = ztv - > fieldnr ;
switch ( ztv - > workqueue - > kindof ) {
case FBUFFER_GRAB :
wake_up_interruptible ( & ztv - > grabq ) ;
break ;
case FBUFFER_VBI :
wake_up_interruptible ( & ztv - > vbiq ) ;
break ;
default :
printk ( CARD_INFO " somebody killed the workqueue (kindof=%d)! \n " , CARD , ztv - > workqueue - > kindof ) ;
}
/* item completed, skip to next item in queue */
write_lock ( & ztv - > lock ) ;
newitem = ztv - > workqueue - > next ;
ztv - > workqueue - > next = 0 ; /* mark completed */
ztv - > workqueue = newitem ;
write_unlock ( & ztv - > lock ) ;
}
/*
* ok , so it seems we have nothing in progress right now .
* Lets see if we can find some work .
*/
if ( ztv - > workqueue )
{
struct vidinfo * newitem ;
again :
DEBUG ( printk ( CARD_DEBUG " starting %s at %p \n " , CARD , ztv - > workqueue - > kindof = = FBUFFER_GRAB ? " grab " : " read " , ztv - > workqueue ) ) ;
/* loadup the frame settings */
read_lock ( & ztv - > lock ) ;
zoran_set_geo ( ztv , ztv - > workqueue ) ;
read_unlock ( & ztv - > lock ) ;
switch ( ztv - > workqueue - > kindof ) {
case FBUFFER_GRAB :
case FBUFFER_VBI :
zrand ( ~ ZORAN_OCR_OVLEN , ZORAN_OCR ) ;
zror ( ZORAN_VSTR_SNAPSHOT , ZORAN_VSTR ) ;
zror ( ZORAN_VDC_VIDEN , ZORAN_VDC ) ;
/* start single-shot grab */
zror ( ZORAN_VSTR_GRAB , ZORAN_VSTR ) ;
break ;
default :
printk ( CARD_INFO " what is this doing on the queue? (kindof=%d) \n " , CARD , ztv - > workqueue - > kindof ) ;
write_lock ( & ztv - > lock ) ;
newitem = ztv - > workqueue - > next ;
ztv - > workqueue - > next = 0 ;
ztv - > workqueue = newitem ;
write_unlock ( & ztv - > lock ) ;
if ( newitem )
goto again ; /* yeah, sure.. */
}
/* bye for now */
return ;
}
DEBUG ( printk ( CARD_DEBUG " nothing in queue \n " , CARD ) ) ;
/*
* What ? Even the workqueue is empty ? Am i really here
* for nothing ? Did i come all that way to . . . do nothing ?
*/
/* do we need to overlay? */
if ( test_bit ( STATE_OVERLAY , & ztv - > state ) )
{
/* are we already overlaying? */
if ( ! ( zrread ( ZORAN_OCR ) & ZORAN_OCR_OVLEN ) | |
! ( zrread ( ZORAN_VDC ) & ZORAN_VDC_VIDEN ) )
{
DEBUG ( printk ( CARD_DEBUG " starting overlay \n " , CARD ) ) ;
read_lock ( & ztv - > lock ) ;
zoran_set_geo ( ztv , & ztv - > overinfo ) ;
read_unlock ( & ztv - > lock ) ;
zror ( ZORAN_OCR_OVLEN , ZORAN_OCR ) ;
zrand ( ~ ZORAN_VSTR_SNAPSHOT , ZORAN_VSTR ) ;
zror ( ZORAN_VDC_VIDEN , ZORAN_VDC ) ;
}
/*
* leave overlaying on , but turn interrupts off .
*/
zrand ( ~ ZORAN_ICR_EN , ZORAN_ICR ) ;
return ;
}
/* do we have any VBI idle time processing? */
if ( test_bit ( STATE_VBI , & ztv - > state ) )
{
struct vidinfo * item ;
struct vidinfo * lastitem ;
/* protect the workqueue */
write_lock ( & ztv - > lock ) ;
lastitem = ztv - > workqueue ;
if ( lastitem )
while ( lastitem - > next ) lastitem = lastitem - > next ;
for ( item = ztv - > readinfo ; item ! = ztv - > readinfo + ZORAN_VBI_BUFFERS ; item + + )
if ( item - > next = = 0 & & item - > status = = FBUFFER_FREE )
{
DEBUG ( printk ( CARD_DEBUG " %p added to queue \n " , CARD , item ) ) ;
item - > status = FBUFFER_BUSY ;
if ( ! lastitem )
ztv - > workqueue = item ;
2006-03-25 20:19:53 +08:00
else
2005-04-17 06:20:36 +08:00
lastitem - > next = item ;
lastitem = item ;
}
write_unlock ( & ztv - > lock ) ;
if ( ztv - > workqueue )
goto again ; /* hey, _i_ graduated :) */
}
/*
* Then we must be realy IDLE
*/
DEBUG ( printk ( CARD_DEBUG " turning off \n " , CARD ) ) ;
/* nothing further to do, disable DMA and further IRQs */
zrand ( ~ ZORAN_VDC_VIDEN , ZORAN_VDC ) ;
zrand ( ~ ZORAN_ICR_EN , ZORAN_ICR ) ;
}
static
void zoran_irq ( int irq , void * dev_id , struct pt_regs * regs )
{
u32 stat , estat ;
int count = 0 ;
struct zoran * ztv = dev_id ;
UNUSED ( irq ) ; UNUSED ( regs ) ;
for ( ; ; ) {
/* get/clear interrupt status bits */
stat = zrread ( ZORAN_ISR ) ;
estat = stat & zrread ( ZORAN_ICR ) ;
if ( ! estat )
return ;
zrwrite ( estat , ZORAN_ISR ) ;
IDEBUG ( printk ( CARD_DEBUG " estat %08x \n " , CARD , estat ) ) ;
IDEBUG ( printk ( CARD_DEBUG " stat %08x \n " , CARD , stat ) ) ;
if ( estat & ZORAN_ISR_CODE )
{
IDEBUG ( printk ( CARD_DEBUG " CodReplIRQ \n " , CARD ) ) ;
}
if ( estat & ZORAN_ISR_GIRQ0 )
{
IDEBUG ( printk ( CARD_DEBUG " GIRQ0 \n " , CARD ) ) ;
if ( ! ztv - > card - > usegirq1 )
reap_states ( ztv ) ;
}
if ( estat & ZORAN_ISR_GIRQ1 )
{
IDEBUG ( printk ( CARD_DEBUG " GIRQ1 \n " , CARD ) ) ;
if ( ztv - > card - > usegirq1 )
reap_states ( ztv ) ;
}
count + + ;
if ( count > 10 )
printk ( CARD_ERR " irq loop %d (%x) \n " , CARD , count , estat ) ;
if ( count > 20 )
{
zrwrite ( 0 , ZORAN_ICR ) ;
printk ( CARD_ERR " IRQ lockup, cleared int mask \n " , CARD ) ;
}
}
}
static
int zoran_muxsel ( struct zoran * ztv , int channel , int norm )
{
int rv ;
/* set the new video norm */
rv = i2c_control_device ( & ( ztv - > i2c ) , I2C_DRIVERID_VIDEODECODER , DECODER_SET_NORM , & norm ) ;
if ( rv )
return rv ;
ztv - > norm = norm ;
/* map the given channel to the cards decoder's channel */
channel = ztv - > card - > video_mux [ channel ] & CHANNEL_MASK ;
/* set the new channel */
rv = i2c_control_device ( & ( ztv - > i2c ) , I2C_DRIVERID_VIDEODECODER , DECODER_SET_INPUT , & channel ) ;
return rv ;
}
/* Tell the interrupt handler what to to. */
static
void zoran_cap ( struct zoran * ztv , int on )
{
DEBUG ( printk ( CARD_DEBUG " zoran_cap(%d) state=%x \n " , CARD , on , ztv - > state ) ) ;
if ( on ) {
ztv - > running = 1 ;
/*
* turn interrupts ( back ) on . The DMA will be enabled
* inside the irq handler when it detects a restart .
*/
zror ( ZORAN_ICR_EN , ZORAN_ICR ) ;
}
else {
/*
* turn both interrupts and DMA off
*/
zrand ( ~ ZORAN_VDC_VIDEN , ZORAN_VDC ) ;
zrand ( ~ ZORAN_ICR_EN , ZORAN_ICR ) ;
ztv - > running = 0 ;
}
}
static ulong dmask [ ] = {
0xFFFFFFFF , 0xFFFFFFFE , 0xFFFFFFFC , 0xFFFFFFF8 ,
0xFFFFFFF0 , 0xFFFFFFE0 , 0xFFFFFFC0 , 0xFFFFFF80 ,
0xFFFFFF00 , 0xFFFFFE00 , 0xFFFFFC00 , 0xFFFFF800 ,
0xFFFFF000 , 0xFFFFE000 , 0xFFFFC000 , 0xFFFF8000 ,
0xFFFF0000 , 0xFFFE0000 , 0xFFFC0000 , 0xFFF80000 ,
0xFFF00000 , 0xFFE00000 , 0xFFC00000 , 0xFF800000 ,
0xFF000000 , 0xFE000000 , 0xFC000000 , 0xF8000000 ,
0xF0000000 , 0xE0000000 , 0xC0000000 , 0x80000000
} ;
static
void zoran_built_overlay ( struct zoran * ztv , int count , struct video_clip * vcp )
{
ulong * mtop ;
int ystep = ( ztv - > vidXshift + ztv - > vidWidth + 31 ) / 32 ; /* next DWORD */
int i ;
DEBUG ( printk ( KERN_DEBUG " overlay at %p, ystep=%d, clips=%d \n " , ztv - > overinfo . overlay , ystep , count ) ) ;
for ( i = 0 ; i < count ; i + + ) {
struct video_clip * vp = vcp + i ;
UNUSED ( vp ) ;
DEBUG ( printk ( KERN_DEBUG " %d: clip(%d,%d,%d,%d) \n " , i , vp - > x , vp - > y , vp - > width , vp - > height ) ) ;
}
/*
* activate the visible portion of the screen
* Note we take some shortcuts here , because we
* know the width can never be < 32. ( I . e . a DWORD )
* We also assume the overlay starts somewhere in
* the FIRST dword .
*/
{
int start = ztv - > vidXshift ;
ulong firstd = dmask [ start ] ;
ulong lastd = ~ dmask [ ( start + ztv - > overinfo . w ) & 31 ] ;
mtop = ztv - > overinfo . overlay ;
for ( i = 0 ; i < ztv - > overinfo . h ; i + + ) {
int w = ztv - > vidWidth ;
ulong * line = mtop ;
if ( start & 31 ) {
* line + + = firstd ;
w - = 32 - ( start & 31 ) ;
}
memset ( line , ~ 0 , w / 8 ) ;
if ( w & 31 )
line [ w / 32 ] = lastd ;
mtop + = ystep ;
}
}
/* process clipping regions */
for ( i = 0 ; i < count ; i + + ) {
int h ;
if ( vcp - > x < 0 | | ( uint ) vcp - > x > ztv - > overinfo . w | |
vcp - > y < 0 | | vcp - > y > ztv - > overinfo . h | |
vcp - > width < 0 | | ( uint ) ( vcp - > x + vcp - > width ) > ztv - > overinfo . w | |
vcp - > height < 0 | | ( vcp - > y + vcp - > height ) > ztv - > overinfo . h )
{
DEBUG ( printk ( CARD_DEBUG " invalid clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting \n " , CARD , vcp - > x , vcp - > y , vcp - > width , vcp - > height , ztv - > overinfo . w , ztv - > overinfo . h ) ) ;
if ( vcp - > x < 0 ) vcp - > x = 0 ;
if ( ( uint ) vcp - > x > ztv - > overinfo . w ) vcp - > x = ztv - > overinfo . w ;
if ( vcp - > y < 0 ) vcp - > y = 0 ;
if ( vcp - > y > ztv - > overinfo . h ) vcp - > y = ztv - > overinfo . h ;
if ( vcp - > width < 0 ) vcp - > width = 0 ;
if ( ( uint ) ( vcp - > x + vcp - > width ) > ztv - > overinfo . w ) vcp - > width = ztv - > overinfo . w - vcp - > x ;
if ( vcp - > height < 0 ) vcp - > height = 0 ;
if ( vcp - > y + vcp - > height > ztv - > overinfo . h ) vcp - > height = ztv - > overinfo . h - vcp - > y ;
// continue;
}
mtop = & ztv - > overinfo . overlay [ vcp - > y * ystep ] ;
for ( h = 0 ; h < = vcp - > height ; h + + ) {
int w ;
int x = ztv - > vidXshift + vcp - > x ;
for ( w = 0 ; w < = vcp - > width ; w + + ) {
clear_bit ( x & 31 , & mtop [ x / 32 ] ) ;
x + + ;
}
mtop + = ystep ;
}
+ + vcp ;
}
mtop = ztv - > overinfo . overlay ;
zrwrite ( virt_to_bus ( mtop ) , ZORAN_MTOP ) ;
zrwrite ( virt_to_bus ( mtop + ystep ) , ZORAN_MBOT ) ;
zraor ( ( ztv - > vidInterlace * ystep ) < < 0 , ~ ZORAN_OCR_MASKSTRIDE , ZORAN_OCR ) ;
}
2006-03-25 20:19:53 +08:00
struct tvnorm
2005-04-17 06:20:36 +08:00
{
u16 Wt , Wa , Ht , Ha , HStart , VStart ;
} ;
static struct tvnorm tvnorms [ ] = {
/* PAL-BDGHI */
/* { 864, 720, 625, 576, 131, 21 },*/
/*00*/ { 864 , 768 , 625 , 576 , 81 , 17 } ,
/* NTSC */
/*01*/ { 858 , 720 , 525 , 480 , 121 , 10 } ,
/* SECAM */
/*02*/ { 864 , 720 , 625 , 576 , 131 , 21 } ,
/* BW50 */
/*03*/ { 864 , 720 , 625 , 576 , 131 , 21 } ,
/* BW60 */
/*04*/ { 858 , 720 , 525 , 480 , 121 , 10 }
} ;
# define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm))
/*
* Program the chip for a setup as described in the vidinfo struct .
*
* Side - effects : calculates vidXshift , vidInterlace ,
* vidHeight , vidWidth which are used in a later stage
* to calculate the overlay mask
*
* This is an internal function , as such it does not check the
* validity of the struct members . . . Spectaculair crashes will
* follow / very / quick when you ' re wrong and the chip right : )
*/
static
void zoran_set_geo ( struct zoran * ztv , struct vidinfo * i )
{
ulong top , bot ;
int stride ;
int winWidth , winHeight ;
int maxWidth , maxHeight , maxXOffset , maxYOffset ;
long vfec ;
DEBUG ( printk ( CARD_DEBUG " set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p) \n " , CARD , i - > x , i - > y , i - > w , i - > h , ztv - > norm , i - > format , i - > bpp , i - > bpl , i - > busadr , i - > overlay ) ) ;
/*
* make sure the DMA transfers are inhibited during our
* reprogramming of the chip
*/
zrand ( ~ ZORAN_VDC_VIDEN , ZORAN_VDC ) ;
maxWidth = tvnorms [ ztv - > norm ] . Wa ;
maxHeight = tvnorms [ ztv - > norm ] . Ha / 2 ;
maxXOffset = tvnorms [ ztv - > norm ] . HStart ;
maxYOffset = tvnorms [ ztv - > norm ] . VStart ;
/* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */
vfec = ( zrread ( ZORAN_VFEC ) & ( ZORAN_VFEC_EXTFL | ZORAN_VFEC_TOPFIELD | ZORAN_VFEC_VCLKPOL ) ) |
( palette2fmt [ i - > format ] . mode & ( ZORAN_VFEC_RGB | ZORAN_VFEC_ERRDIF | ZORAN_VFEC_LE | ZORAN_VFEC_PACK24 ) ) ;
/*
* Set top , bottom ptrs . Since these must be DWORD aligned ,
* possible adjust the x and the width of the window .
* so the endposition stay the same . The vidXshift will make
* sure we are not writing pixels before the requested x .
*/
ztv - > vidXshift = 0 ;
winWidth = i - > w ;
if ( winWidth < 0 )
winWidth = - winWidth ;
top = i - > busadr + i - > x * i - > bpp + i - > y * i - > bpl ;
if ( top & 3 ) {
ztv - > vidXshift = ( top & 3 ) / i - > bpp ;
winWidth + = ztv - > vidXshift ;
DEBUG ( printk ( KERN_DEBUG " window-x shifted %d pixels left \n " , ztv - > vidXshift ) ) ;
top & = ~ 3 ;
}
/*
* bottom points to next frame but in interleaved mode we want
* to ' mix ' the 2 frames to one capture , so ' bot ' points to one
* ( physical ) line below the top line .
*/
bot = top + i - > bpl ;
zrwrite ( top , ZORAN_VTOP ) ;
zrwrite ( bot , ZORAN_VBOT ) ;
/*
* Make sure the winWidth is DWORD aligned too ,
* thereby automaticly making sure the stride to the
* next line is DWORD aligned too ( as required by spec ) .
*/
if ( ( winWidth * i - > bpp ) & 3 ) {
DEBUG ( printk ( KERN_DEBUG " window-width enlarged by %d pixels \n " , ( winWidth * i - > bpp ) & 3 ) ) ;
winWidth + = ( winWidth * i - > bpp ) & 3 ;
}
/* determine the DispMode and stride */
if ( i - > h > = 0 & & i - > h < = maxHeight ) {
/* single frame grab suffices for this height. */
vfec | = ZORAN_VFEC_DISPMOD ;
ztv - > vidInterlace = 0 ;
stride = i - > bpl - ( winWidth * i - > bpp ) ;
winHeight = i - > h ;
}
else {
/* interleaving needed for this height */
ztv - > vidInterlace = 1 ;
stride = i - > bpl * 2 - ( winWidth * i - > bpp ) ;
winHeight = i - > h / 2 ;
}
if ( winHeight < 0 ) /* can happen for VBI! */
winHeight = - winHeight ;
/* safety net, sometimes bpl is too short??? */
if ( stride < 0 ) {
DEBUG ( printk ( CARD_DEBUG " WARNING stride = %d \n " , CARD , stride ) ) ;
stride = 0 ;
}
zraor ( ( winHeight < < 12 ) | ( winWidth < < 0 ) , ~ ( ZORAN_VDC_VIDWINHT | ZORAN_VDC_VIDWINWID ) , ZORAN_VDC ) ;
zraor ( stride < < 16 , ~ ZORAN_VSTR_DISPSTRIDE , ZORAN_VSTR ) ;
/* remember vidWidth, vidHeight for overlay calculations */
ztv - > vidWidth = winWidth ;
ztv - > vidHeight = winHeight ;
DEBUG ( printk ( KERN_DEBUG " top=%08lx, bottom=%08lx \n " , top , bot ) ) ;
DEBUG ( printk ( KERN_DEBUG " winWidth=%d, winHeight=%d \n " , winWidth , winHeight ) ) ;
DEBUG ( printk ( KERN_DEBUG " maxWidth=%d, maxHeight=%d \n " , maxWidth , maxHeight ) ) ;
DEBUG ( printk ( KERN_DEBUG " stride=%d \n " , stride ) ) ;
/*
* determine horizontal scales and crops
*/
if ( i - > w < 0 ) {
int Hstart = 1 ;
int Hend = Hstart + winWidth ;
DEBUG ( printk ( KERN_DEBUG " Y: scale=0, start=%d, end=%d \n " , Hstart , Hend ) ) ;
zraor ( ( Hstart < < 10 ) | ( Hend < < 0 ) , ~ ( ZORAN_VFEH_HSTART | ZORAN_VFEH_HEND ) , ZORAN_VFEH ) ;
}
else {
int Wa = maxWidth ;
int X = ( winWidth * 64 + Wa - 1 ) / Wa ;
int We = winWidth * 64 / X ;
int HorDcm = 64 - X ;
int hcrop1 = 2 * ( Wa - We ) / 4 ;
/*
2006-03-25 20:19:53 +08:00
* BUGFIX : Juha Nurmela < junki @ qn - lpr2 - 165. quicknet . inet . fi >
2005-04-17 06:20:36 +08:00
* found the solution to the color phase shift .
* See ChangeLog for the full explanation )
*/
int Hstart = ( maxXOffset + hcrop1 ) | 1 ;
int Hend = Hstart + We - 1 ;
DEBUG ( printk ( KERN_DEBUG " X: scale=%d, start=%d, end=%d \n " , HorDcm , Hstart , Hend ) ) ;
zraor ( ( Hstart < < 10 ) | ( Hend < < 0 ) , ~ ( ZORAN_VFEH_HSTART | ZORAN_VFEH_HEND ) , ZORAN_VFEH ) ;
vfec | = HorDcm < < 14 ;
if ( HorDcm < 16 )
vfec | = ZORAN_VFEC_HFILTER_1 ; /* no filter */
else if ( HorDcm < 32 )
vfec | = ZORAN_VFEC_HFILTER_3 ; /* 3 tap filter */
else if ( HorDcm < 48 )
vfec | = ZORAN_VFEC_HFILTER_4 ; /* 4 tap filter */
else vfec | = ZORAN_VFEC_HFILTER_5 ; /* 5 tap filter */
}
/*
* Determine vertical scales and crops
*
* when height is negative , we want to read starting at line 0
* One day someone might need access to these lines . . .
*/
if ( i - > h < 0 ) {
int Vstart = 0 ;
int Vend = Vstart + winHeight ;
DEBUG ( printk ( KERN_DEBUG " Y: scale=0, start=%d, end=%d \n " , Vstart , Vend ) ) ;
zraor ( ( Vstart < < 10 ) | ( Vend < < 0 ) , ~ ( ZORAN_VFEV_VSTART | ZORAN_VFEV_VEND ) , ZORAN_VFEV ) ;
}
else {
int Ha = maxHeight ;
int Y = ( winHeight * 64 + Ha - 1 ) / Ha ;
int He = winHeight * 64 / Y ;
int VerDcm = 64 - Y ;
int vcrop1 = 2 * ( Ha - He ) / 4 ;
int Vstart = maxYOffset + vcrop1 ;
int Vend = Vstart + He - 1 ;
DEBUG ( printk ( KERN_DEBUG " Y: scale=%d, start=%d, end=%d \n " , VerDcm , Vstart , Vend ) ) ;
zraor ( ( Vstart < < 10 ) | ( Vend < < 0 ) , ~ ( ZORAN_VFEV_VSTART | ZORAN_VFEV_VEND ) , ZORAN_VFEV ) ;
vfec | = VerDcm < < 8 ;
}
DEBUG ( printk ( KERN_DEBUG " F: format=%d(=%s) \n " , i - > format , palette2fmt [ i - > format ] . name ) ) ;
/* setup the requested format */
zrwrite ( vfec , ZORAN_VFEC ) ;
}
static
void zoran_common_open ( struct zoran * ztv , int flags )
{
UNUSED ( flags ) ;
/* already opened? */
if ( ztv - > users + + ! = 0 )
return ;
/* unmute audio */
/* /what/ audio? */
ztv - > state = 0 ;
/* setup the encoder to the initial values */
ztv - > picture . colour = 254 < < 7 ;
ztv - > picture . brightness = 128 < < 8 ;
ztv - > picture . hue = 128 < < 8 ;
ztv - > picture . contrast = 216 < < 7 ;
i2c_control_device ( & ztv - > i2c , I2C_DRIVERID_VIDEODECODER , DECODER_SET_PICTURE , & ztv - > picture ) ;
/* default to the composite input since my camera is there */
zoran_muxsel ( ztv , 0 , VIDEO_MODE_PAL ) ;
}
static
void zoran_common_close ( struct zoran * ztv )
{
if ( - - ztv - > users ! = 0 )
return ;
/* mute audio */
/* /what/ audio? */
/* stop the chip */
zoran_cap ( ztv , 0 ) ;
}
/*
* Open a zoran card . Right now the flags are just a hack
*/
static int zoran_open ( struct video_device * dev , int flags )
{
struct zoran * ztv = ( struct zoran * ) dev ;
struct vidinfo * item ;
char * pos ;
DEBUG ( printk ( CARD_DEBUG " open(dev,%d) \n " , CARD , flags ) ) ;
/*********************************************
* We really should be doing lazy allocing . . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* allocate a frame buffer */
if ( ! ztv - > fbuffer )
ztv - > fbuffer = bmalloc ( ZORAN_MAX_FBUFSIZE ) ;
if ( ! ztv - > fbuffer ) {
/* could not get a buffer, bail out */
return - ENOBUFS ;
}
/* at this time we _always_ have a framebuffer */
memset ( ztv - > fbuffer , 0 , ZORAN_MAX_FBUFSIZE ) ;
if ( ! ztv - > overinfo . overlay )
ztv - > overinfo . overlay = kmalloc ( 1024 * 1024 / 8 , GFP_KERNEL ) ;
if ( ! ztv - > overinfo . overlay ) {
/* could not get an overlay buffer, bail out */
bfree ( ztv - > fbuffer , ZORAN_MAX_FBUFSIZE ) ;
return - ENOBUFS ;
}
/* at this time we _always_ have a overlay */
/* clear buffer status, and give them a DMAable address */
pos = ztv - > fbuffer ;
for ( item = ztv - > grabinfo ; item ! = ztv - > grabinfo + ZORAN_MAX_FBUFFERS ; item + + )
{
item - > status = FBUFFER_FREE ;
item - > memadr = pos ;
item - > busadr = virt_to_bus ( pos ) ;
pos + = ZORAN_MAX_FBUFFER ;
}
/* do the common part of all open's */
zoran_common_open ( ztv , flags ) ;
return 0 ;
}
static
void zoran_close ( struct video_device * dev )
{
struct zoran * ztv = ( struct zoran * ) dev ;
DEBUG ( printk ( CARD_DEBUG " close(dev) \n " , CARD ) ) ;
/* driver specific closure */
clear_bit ( STATE_OVERLAY , & ztv - > state ) ;
zoran_common_close ( ztv ) ;
2006-03-25 20:19:53 +08:00
/*
* This is sucky but right now I can ' t find a good way to
* be sure its safe to free the buffer . We wait 5 - 6 fields
* which is more than sufficient to be sure .
*/
msleep ( 100 ) ; /* Wait 1/10th of a second */
2005-04-17 06:20:36 +08:00
/* free the allocated framebuffer */
2005-09-10 15:26:54 +08:00
bfree ( ztv - > fbuffer , ZORAN_MAX_FBUFSIZE ) ;
2005-04-17 06:20:36 +08:00
ztv - > fbuffer = 0 ;
2005-09-10 15:26:54 +08:00
kfree ( ztv - > overinfo . overlay ) ;
2005-04-17 06:20:36 +08:00
ztv - > overinfo . overlay = 0 ;
}
/*
* This read function could be used reentrant in a SMP situation .
*
* This is made possible by the spinlock which is kept till we
* found and marked a buffer for our own use . The lock must
* be released as soon as possible to prevent lock contention .
*/
static
long zoran_read ( struct video_device * dev , char * buf , unsigned long count , int nonblock )
{
struct zoran * ztv = ( struct zoran * ) dev ;
unsigned long max ;
struct vidinfo * unused = 0 ;
struct vidinfo * done = 0 ;
DEBUG ( printk ( CARD_DEBUG " zoran_read(%p,%ld,%d) \n " , CARD , buf , count , nonblock ) ) ;
/* find ourself a free or completed buffer */
for ( ; ; ) {
struct vidinfo * item ;
write_lock_irq ( & ztv - > lock ) ;
for ( item = ztv - > grabinfo ; item ! = ztv - > grabinfo + ZORAN_MAX_FBUFFERS ; item + + )
{
if ( ! unused & & item - > status = = FBUFFER_FREE )
unused = item ;
if ( ! done & & item - > status = = FBUFFER_DONE )
done = item ;
}
if ( done | | unused )
break ;
/* no more free buffers, wait for them. */
write_unlock_irq ( & ztv - > lock ) ;
if ( nonblock )
return - EWOULDBLOCK ;
interruptible_sleep_on ( & ztv - > grabq ) ;
if ( signal_pending ( current ) )
return - EINTR ;
}
/* Do we have 'ready' data? */
if ( ! done ) {
/* no? than this will take a while... */
if ( nonblock ) {
write_unlock_irq ( & ztv - > lock ) ;
return - EWOULDBLOCK ;
}
/* mark the unused buffer as wanted */
unused - > status = FBUFFER_BUSY ;
unused - > w = 320 ;
unused - > h = 240 ;
unused - > format = VIDEO_PALETTE_RGB24 ;
unused - > bpp = palette2fmt [ unused - > format ] . bpp ;
unused - > bpl = unused - > w * unused - > bpp ;
unused - > next = 0 ;
{ /* add to tail of queue */
struct vidinfo * oldframe = ztv - > workqueue ;
if ( ! oldframe ) ztv - > workqueue = unused ;
else {
while ( oldframe - > next ) oldframe = oldframe - > next ;
oldframe - > next = unused ;
}
}
write_unlock_irq ( & ztv - > lock ) ;
/* tell the state machine we want it filled /NOW/ */
zoran_cap ( ztv , 1 ) ;
/* wait till this buffer gets grabbed */
wait_event_interruptible ( ztv - > grabq ,
( unused - > status ! = FBUFFER_BUSY ) ) ;
/* see if a signal did it */
if ( signal_pending ( current ) )
return - EINTR ;
done = unused ;
}
else
write_unlock_irq ( & ztv - > lock ) ;
/* Yes! we got data! */
max = done - > bpl * done - > h ;
if ( count > max )
count = max ;
if ( copy_to_user ( ( void * ) buf , done - > memadr , count ) )
count = - EFAULT ;
/* keep the engine running */
done - > status = FBUFFER_FREE ;
// zoran_cap(ztv,1);
/* tell listeners this buffer became free */
wake_up_interruptible ( & ztv - > grabq ) ;
/* goodbye */
DEBUG ( printk ( CARD_DEBUG " zoran_read() returns %lu \n " , CARD , count ) ) ;
return count ;
}
static
long zoran_write ( struct video_device * dev , const char * buf , unsigned long count , int nonblock )
{
struct zoran * ztv = ( struct zoran * ) dev ;
UNUSED ( ztv ) ; UNUSED ( dev ) ; UNUSED ( buf ) ; UNUSED ( count ) ; UNUSED ( nonblock ) ;
DEBUG ( printk ( CARD_DEBUG " zoran_write \n " , CARD ) ) ;
return - EINVAL ;
}
static
unsigned int zoran_poll ( struct video_device * dev , struct file * file , poll_table * wait )
{
struct zoran * ztv = ( struct zoran * ) dev ;
struct vidinfo * item ;
unsigned int mask = 0 ;
poll_wait ( file , & ztv - > grabq , wait ) ;
for ( item = ztv - > grabinfo ; item ! = ztv - > grabinfo + ZORAN_MAX_FBUFFERS ; item + + )
if ( item - > status = = FBUFFER_DONE )
{
mask | = ( POLLIN | POLLRDNORM ) ;
break ;
}
DEBUG ( printk ( CARD_DEBUG " zoran_poll()=%x \n " , CARD , mask ) ) ;
return mask ;
}
/* append a new clipregion to the vector of video_clips */
static
void new_clip ( struct video_window * vw , struct video_clip * vcp , int x , int y , int w , int h )
{
vcp [ vw - > clipcount ] . x = x ;
vcp [ vw - > clipcount ] . y = y ;
vcp [ vw - > clipcount ] . width = w ;
vcp [ vw - > clipcount ] . height = h ;
vw - > clipcount + + ;
}
static
int zoran_ioctl ( struct video_device * dev , unsigned int cmd , void * arg )
{
struct zoran * ztv = ( struct zoran * ) dev ;
switch ( cmd ) {
case VIDIOCGCAP :
{
struct video_capability c ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGCAP \n " , CARD ) ) ;
strcpy ( c . name , ztv - > video_dev . name ) ;
c . type = VID_TYPE_CAPTURE |
VID_TYPE_OVERLAY |
VID_TYPE_CLIPPING |
VID_TYPE_FRAMERAM |
VID_TYPE_SCALES ;
if ( ztv - > have_tuner )
c . type | = VID_TYPE_TUNER ;
if ( ztv - > have_decoder ) {
c . channels = ztv - > card - > video_inputs ;
c . audios = ztv - > card - > audio_inputs ;
} else
/* no decoder -> no channels */
c . channels = c . audios = 0 ;
c . maxwidth = 768 ;
c . maxheight = 576 ;
c . minwidth = 32 ;
c . minheight = 32 ;
if ( copy_to_user ( arg , & c , sizeof ( c ) ) )
return - EFAULT ;
break ;
}
case VIDIOCGCHAN :
{
struct video_channel v ;
int mux ;
if ( copy_from_user ( & v , arg , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGCHAN(%d) \n " , CARD , v . channel ) ) ;
v . flags = VIDEO_VC_AUDIO
# ifdef VIDEO_VC_NORM
| VIDEO_VC_NORM
# endif
;
v . tuners = 0 ;
v . type = VIDEO_TYPE_CAMERA ;
# ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API
v . norm = VIDEO_MODE_PAL |
VIDEO_MODE_NTSC |
VIDEO_MODE_SECAM ;
# else
v . norm = VIDEO_MODE_PAL ;
# endif
/* too many inputs? no decoder -> no channels */
if ( ! ztv - > have_decoder | | v . channel < 0 | | v . channel > = ztv - > card - > video_inputs )
return - EINVAL ;
/* now determine the name of the channel */
mux = ztv - > card - > video_mux [ v . channel ] ;
if ( mux & IS_TUNER ) {
/* lets assume only one tuner, yes? */
strcpy ( v . name , " Television " ) ;
v . type = VIDEO_TYPE_TV ;
if ( ztv - > have_tuner ) {
v . flags | = VIDEO_VC_TUNER ;
v . tuners = 1 ;
}
}
else if ( mux & IS_SVHS )
sprintf ( v . name , " S-Video-%d " , v . channel ) ;
else
sprintf ( v . name , " CVBS-%d " , v . channel ) ;
if ( copy_to_user ( arg , & v , sizeof ( v ) ) )
return - EFAULT ;
break ;
}
case VIDIOCSCHAN :
{ /* set video channel */
struct video_channel v ;
if ( copy_from_user ( & v , arg , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSCHAN(%d,%d) \n " , CARD , v . channel , v . norm ) ) ;
/* too many inputs? no decoder -> no channels */
if ( ! ztv - > have_decoder | | v . channel > = ztv - > card - > video_inputs | | v . channel < 0 )
return - EINVAL ;
if ( v . norm ! = VIDEO_MODE_PAL & &
v . norm ! = VIDEO_MODE_NTSC & &
v . norm ! = VIDEO_MODE_SECAM & &
v . norm ! = VIDEO_MODE_AUTO )
return - EOPNOTSUPP ;
/* make it happen, nr1! */
return zoran_muxsel ( ztv , v . channel , v . norm ) ;
}
case VIDIOCGTUNER :
{
struct video_tuner v ;
if ( copy_from_user ( & v , arg , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGTUNER(%d) \n " , CARD , v . tuner ) ) ;
/* Only no or one tuner for now */
if ( ! ztv - > have_tuner | | v . tuner )
return - EINVAL ;
strcpy ( v . name , " Television " ) ;
v . rangelow = 0 ;
v . rangehigh = ~ 0 ;
v . flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC | VIDEO_TUNER_SECAM ;
v . mode = ztv - > norm ;
v . signal = 0xFFFF ; /* unknown */
if ( copy_to_user ( arg , & v , sizeof ( v ) ) )
return - EFAULT ;
break ;
}
case VIDIOCSTUNER :
{
struct video_tuner v ;
if ( copy_from_user ( & v , arg , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSTUNER(%d,%d) \n " , CARD , v . tuner , v . mode ) ) ;
/* Only no or one tuner for now */
if ( ! ztv - > have_tuner | | v . tuner )
return - EINVAL ;
/* and it only has certain valid modes */
if ( v . mode ! = VIDEO_MODE_PAL & &
v . mode ! = VIDEO_MODE_NTSC & &
v . mode ! = VIDEO_MODE_SECAM )
return - EOPNOTSUPP ;
/* engage! */
return zoran_muxsel ( ztv , v . tuner , v . mode ) ;
}
case VIDIOCGPICT :
{
struct video_picture p = ztv - > picture ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGPICT \n " , CARD ) ) ;
p . depth = ztv - > depth ;
switch ( p . depth ) {
case 8 : p . palette = VIDEO_PALETTE_YUV422 ;
break ;
case 15 : p . palette = VIDEO_PALETTE_RGB555 ;
break ;
case 16 : p . palette = VIDEO_PALETTE_RGB565 ;
break ;
case 24 : p . palette = VIDEO_PALETTE_RGB24 ;
break ;
case 32 : p . palette = VIDEO_PALETTE_RGB32 ;
break ;
}
if ( copy_to_user ( arg , & p , sizeof ( p ) ) )
return - EFAULT ;
break ;
}
case VIDIOCSPICT :
{
struct video_picture p ;
if ( copy_from_user ( & p , arg , sizeof ( p ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d) \n " , CARD , p . brightness , p . hue , p . colour , p . contrast , p . whiteness , p . depth , p . palette ) ) ;
/* depth must match with framebuffer */
if ( p . depth ! = ztv - > depth )
return - EINVAL ;
/* check if palette matches this bpp */
if ( p . palette > NRPALETTES | |
palette2fmt [ p . palette ] . bpp ! = ztv - > overinfo . bpp )
return - EINVAL ;
write_lock_irq ( & ztv - > lock ) ;
ztv - > overinfo . format = p . palette ;
ztv - > picture = p ;
write_unlock_irq ( & ztv - > lock ) ;
/* tell the decoder */
i2c_control_device ( & ztv - > i2c , I2C_DRIVERID_VIDEODECODER , DECODER_SET_PICTURE , & p ) ;
break ;
}
case VIDIOCGWIN :
{
struct video_window vw ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGWIN \n " , CARD ) ) ;
read_lock ( & ztv - > lock ) ;
vw . x = ztv - > overinfo . x ;
vw . y = ztv - > overinfo . y ;
vw . width = ztv - > overinfo . w ;
vw . height = ztv - > overinfo . h ;
vw . chromakey = 0 ;
vw . flags = 0 ;
if ( ztv - > vidInterlace )
vw . flags | = VIDEO_WINDOW_INTERLACE ;
read_unlock ( & ztv - > lock ) ;
if ( copy_to_user ( arg , & vw , sizeof ( vw ) ) )
return - EFAULT ;
break ;
}
case VIDIOCSWIN :
{
struct video_window vw ;
struct video_clip * vcp ;
int on ;
if ( copy_from_user ( & vw , arg , sizeof ( vw ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSWIN(%d,%d,%d,%d,%x,%d) \n " , CARD , vw . x , vw . y , vw . width , vw . height , vw . flags , vw . clipcount ) ) ;
if ( vw . flags )
return - EINVAL ;
if ( vw . clipcount < 0 | | vw . clipcount > 256 )
return - EDOM ; /* Too many! */
/*
* Do any clips .
*/
vcp = vmalloc ( sizeof ( struct video_clip ) * ( vw . clipcount + 4 ) ) ;
if ( vcp = = NULL )
return - ENOMEM ;
if ( vw . clipcount & & copy_from_user ( vcp , vw . clips , sizeof ( struct video_clip ) * vw . clipcount ) ) {
vfree ( vcp ) ;
return - EFAULT ;
}
on = ztv - > running ;
if ( on )
zoran_cap ( ztv , 0 ) ;
/*
* strange , it seems xawtv sometimes calls us with 0
* width and / or height . Ignore these values
*/
if ( vw . x = = 0 )
vw . x = ztv - > overinfo . x ;
if ( vw . y = = 0 )
vw . y = ztv - > overinfo . y ;
/* by now we are committed to the new data... */
write_lock_irq ( & ztv - > lock ) ;
ztv - > overinfo . x = vw . x ;
ztv - > overinfo . y = vw . y ;
ztv - > overinfo . w = vw . width ;
ztv - > overinfo . h = vw . height ;
write_unlock_irq ( & ztv - > lock ) ;
/*
* Impose display clips
*/
if ( vw . x + vw . width > ztv - > swidth )
new_clip ( & vw , vcp , ztv - > swidth - vw . x , 0 , vw . width - 1 , vw . height - 1 ) ;
if ( vw . y + vw . height > ztv - > sheight )
new_clip ( & vw , vcp , 0 , ztv - > sheight - vw . y , vw . width - 1 , vw . height - 1 ) ;
/* built the requested clipping zones */
zoran_set_geo ( ztv , & ztv - > overinfo ) ;
zoran_built_overlay ( ztv , vw . clipcount , vcp ) ;
vfree ( vcp ) ;
/* if we were on, restart the video engine */
if ( on )
zoran_cap ( ztv , 1 ) ;
break ;
}
case VIDIOCCAPTURE :
{
int v ;
if ( get_user ( v , ( int * ) arg ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCCAPTURE(%d) \n " , CARD , v ) ) ;
if ( v = = 0 ) {
clear_bit ( STATE_OVERLAY , & ztv - > state ) ;
zoran_cap ( ztv , 1 ) ;
}
else {
/* is VIDIOCSFBUF, VIDIOCSWIN done? */
if ( ztv - > overinfo . busadr = = 0 | | ztv - > overinfo . w = = 0 | | ztv - > overinfo . h = = 0 )
return - EINVAL ;
set_bit ( STATE_OVERLAY , & ztv - > state ) ;
zoran_cap ( ztv , 1 ) ;
}
break ;
}
case VIDIOCGFBUF :
{
struct video_buffer v ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGFBUF \n " , CARD ) ) ;
read_lock ( & ztv - > lock ) ;
v . base = ( void * ) ztv - > overinfo . busadr ;
v . height = ztv - > sheight ;
v . width = ztv - > swidth ;
v . depth = ztv - > depth ;
v . bytesperline = ztv - > overinfo . bpl ;
read_unlock ( & ztv - > lock ) ;
if ( copy_to_user ( arg , & v , sizeof ( v ) ) )
return - EFAULT ;
break ;
}
case VIDIOCSFBUF :
{
struct video_buffer v ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( copy_from_user ( & v , arg , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSFBUF(%p,%d,%d,%d,%d) \n " , CARD , v . base , v . width , v . height , v . depth , v . bytesperline ) ) ;
if ( v . depth ! = 15 & & v . depth ! = 16 & & v . depth ! = 24 & & v . depth ! = 32 )
return - EINVAL ;
if ( v . bytesperline < 1 )
return - EINVAL ;
if ( ztv - > running )
return - EBUSY ;
write_lock_irq ( & ztv - > lock ) ;
ztv - > overinfo . busadr = ( ulong ) v . base ;
ztv - > sheight = v . height ;
ztv - > swidth = v . width ;
ztv - > depth = v . depth ; /* bits per pixel */
ztv - > overinfo . bpp = ( ( v . depth + 1 ) & 0x38 ) / 8 ; /* bytes per pixel */
ztv - > overinfo . bpl = v . bytesperline ; /* bytes per line */
write_unlock_irq ( & ztv - > lock ) ;
break ;
}
case VIDIOCKEY :
{
/* Will be handled higher up .. */
break ;
}
case VIDIOCSYNC :
{
int i ;
if ( get_user ( i , ( int * ) arg ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDEOCSYNC(%d) \n " , CARD , i ) ) ;
if ( i < 0 | | i > ZORAN_MAX_FBUFFERS )
return - EINVAL ;
switch ( ztv - > grabinfo [ i ] . status ) {
case FBUFFER_FREE :
return - EINVAL ;
case FBUFFER_BUSY :
/* wait till this buffer gets grabbed */
wait_event_interruptible ( ztv - > grabq ,
( ztv - > grabinfo [ i ] . status ! = FBUFFER_BUSY ) ) ;
/* see if a signal did it */
if ( signal_pending ( current ) )
return - EINTR ;
/* don't fall through; a DONE buffer is not UNUSED */
break ;
case FBUFFER_DONE :
ztv - > grabinfo [ i ] . status = FBUFFER_FREE ;
/* tell ppl we have a spare buffer */
wake_up_interruptible ( & ztv - > grabq ) ;
break ;
}
DEBUG ( printk ( CARD_DEBUG " VIDEOCSYNC(%d) returns \n " , CARD , i ) ) ;
break ;
}
case VIDIOCMCAPTURE :
{
struct video_mmap vm ;
struct vidinfo * frame ;
if ( copy_from_user ( & vm , arg , sizeof ( vm ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCMCAPTURE(%d,(%d,%d),%d) \n " , CARD , vm . frame , vm . width , vm . height , vm . format ) ) ;
if ( vm . frame < 0 | | vm . frame > ZORAN_MAX_FBUFFERS | |
vm . width < 32 | | vm . width > 768 | |
vm . height < 32 | | vm . height > 576 | |
vm . format > NRPALETTES | |
palette2fmt [ vm . format ] . mode = = 0 )
return - EINVAL ;
/* we are allowed to take over UNUSED and DONE buffers */
frame = & ztv - > grabinfo [ vm . frame ] ;
if ( frame - > status = = FBUFFER_BUSY )
return - EBUSY ;
/* setup the other parameters if they are given */
write_lock_irq ( & ztv - > lock ) ;
frame - > w = vm . width ;
frame - > h = vm . height ;
frame - > format = vm . format ;
frame - > bpp = palette2fmt [ frame - > format ] . bpp ;
frame - > bpl = frame - > w * frame - > bpp ;
frame - > status = FBUFFER_BUSY ;
frame - > next = 0 ;
{ /* add to tail of queue */
struct vidinfo * oldframe = ztv - > workqueue ;
if ( ! oldframe ) ztv - > workqueue = frame ;
else {
while ( oldframe - > next ) oldframe = oldframe - > next ;
oldframe - > next = frame ;
}
}
write_unlock_irq ( & ztv - > lock ) ;
zoran_cap ( ztv , 1 ) ;
break ;
}
case VIDIOCGMBUF :
{
struct video_mbuf mb ;
int i ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGMBUF \n " , CARD ) ) ;
mb . size = ZORAN_MAX_FBUFSIZE ;
mb . frames = ZORAN_MAX_FBUFFERS ;
for ( i = 0 ; i < ZORAN_MAX_FBUFFERS ; i + + )
mb . offsets [ i ] = i * ZORAN_MAX_FBUFFER ;
if ( copy_to_user ( arg , & mb , sizeof ( mb ) ) )
return - EFAULT ;
break ;
}
case VIDIOCGUNIT :
{
struct video_unit vu ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGUNIT \n " , CARD ) ) ;
vu . video = ztv - > video_dev . minor ;
vu . vbi = ztv - > vbi_dev . minor ;
vu . radio = VIDEO_NO_UNIT ;
vu . audio = VIDEO_NO_UNIT ;
vu . teletext = VIDEO_NO_UNIT ;
if ( copy_to_user ( arg , & vu , sizeof ( vu ) ) )
return - EFAULT ;
break ;
}
case VIDIOCGFREQ :
{
unsigned long v = ztv - > tuner_freq ;
if ( copy_to_user ( arg , & v , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGFREQ \n " , CARD ) ) ;
break ;
}
case VIDIOCSFREQ :
{
unsigned long v ;
if ( copy_from_user ( & v , arg , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSFREQ \n " , CARD ) ) ;
if ( ztv - > have_tuner ) {
int fixme = v ;
if ( i2c_control_device ( & ( ztv - > i2c ) , I2C_DRIVERID_TUNER , TUNER_SET_TVFREQ , & fixme ) < 0 )
return - EAGAIN ;
}
ztv - > tuner_freq = v ;
break ;
}
/* Why isn't this in the API?
* And why doesn ' t it take a buffer number ?
2006-03-25 20:19:53 +08:00
case BTTV_FIELDNR :
2005-04-17 06:20:36 +08:00
{
unsigned long v = ztv - > lastfieldnr ;
if ( copy_to_user ( arg , & v , sizeof ( v ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " BTTV_FIELDNR \n " , CARD ) ) ;
break ;
}
*/
default :
return - ENOIOCTLCMD ;
}
return 0 ;
}
static
int zoran_mmap ( struct vm_area_struct * vma , struct video_device * dev , const char * adr , unsigned long size )
{
struct zoran * ztv = ( struct zoran * ) dev ;
unsigned long start = ( unsigned long ) adr ;
unsigned long pos ;
DEBUG ( printk ( CARD_DEBUG " zoran_mmap(0x%p,%ld) \n " , CARD , adr , size ) ) ;
/* sanity checks */
if ( size > ZORAN_MAX_FBUFSIZE | | ! ztv - > fbuffer )
return - EINVAL ;
/* start mapping the whole shabang to user memory */
pos = ( unsigned long ) ztv - > fbuffer ;
while ( size > 0 ) {
unsigned long pfn = virt_to_phys ( ( void * ) pos ) > > PAGE_SHIFT ;
if ( remap_pfn_range ( vma , start , pfn , PAGE_SIZE , PAGE_SHARED ) )
return - EAGAIN ;
start + = PAGE_SIZE ;
pos + = PAGE_SIZE ;
size - = PAGE_SIZE ;
}
return 0 ;
}
static struct video_device zr36120_template =
{
. owner = THIS_MODULE ,
. name = " UNSET " ,
. type = VID_TYPE_TUNER | VID_TYPE_CAPTURE | VID_TYPE_OVERLAY ,
. hardware = VID_HARDWARE_ZR36120 ,
. open = zoran_open ,
. close = zoran_close ,
. read = zoran_read ,
. write = zoran_write ,
. poll = zoran_poll ,
. ioctl = zoran_ioctl ,
2006-01-10 01:24:57 +08:00
. compat_ioctl = v4l_compat_ioctl32 ,
2005-04-17 06:20:36 +08:00
. mmap = zoran_mmap ,
. minor = - 1 ,
} ;
static
int vbi_open ( struct video_device * dev , int flags )
{
struct zoran * ztv = dev - > priv ;
struct vidinfo * item ;
DEBUG ( printk ( CARD_DEBUG " vbi_open(dev,%d) \n " , CARD , flags ) ) ;
/*
* During VBI device open , we continiously grab VBI - like
* data in the vbi buffer when we have nothing to do .
* Only when there is an explicit request for VBI data
* ( read call ) we / force / a read .
*/
/* allocate buffers */
for ( item = ztv - > readinfo ; item ! = ztv - > readinfo + ZORAN_VBI_BUFFERS ; item + + )
{
item - > status = FBUFFER_FREE ;
/* alloc */
if ( ! item - > memadr ) {
item - > memadr = bmalloc ( ZORAN_VBI_BUFSIZE ) ;
if ( ! item - > memadr ) {
/* could not get a buffer, bail out */
while ( item ! = ztv - > readinfo ) {
item - - ;
bfree ( item - > memadr , ZORAN_VBI_BUFSIZE ) ;
item - > memadr = 0 ;
item - > busadr = 0 ;
}
return - ENOBUFS ;
}
}
/* determine the DMAable address */
item - > busadr = virt_to_bus ( item - > memadr ) ;
}
/* do the common part of all open's */
zoran_common_open ( ztv , flags ) ;
set_bit ( STATE_VBI , & ztv - > state ) ;
/* start read-ahead */
zoran_cap ( ztv , 1 ) ;
return 0 ;
}
static
void vbi_close ( struct video_device * dev )
{
struct zoran * ztv = dev - > priv ;
struct vidinfo * item ;
DEBUG ( printk ( CARD_DEBUG " vbi_close(dev) \n " , CARD ) ) ;
/* driver specific closure */
clear_bit ( STATE_VBI , & ztv - > state ) ;
zoran_common_close ( ztv ) ;
2006-03-25 20:19:53 +08:00
/*
* This is sucky but right now I can ' t find a good way to
* be sure its safe to free the buffer . We wait 5 - 6 fields
* which is more than sufficient to be sure .
*/
msleep ( 100 ) ; /* Wait 1/10th of a second */
2005-04-17 06:20:36 +08:00
for ( item = ztv - > readinfo ; item ! = ztv - > readinfo + ZORAN_VBI_BUFFERS ; item + + )
{
if ( item - > memadr )
bfree ( item - > memadr , ZORAN_VBI_BUFSIZE ) ;
item - > memadr = 0 ;
}
}
/*
* This read function could be used reentrant in a SMP situation .
*
* This is made possible by the spinlock which is kept till we
* found and marked a buffer for our own use . The lock must
* be released as soon as possible to prevent lock contention .
*/
static
long vbi_read ( struct video_device * dev , char * buf , unsigned long count , int nonblock )
{
struct zoran * ztv = dev - > priv ;
unsigned long max ;
struct vidinfo * unused = 0 ;
struct vidinfo * done = 0 ;
DEBUG ( printk ( CARD_DEBUG " vbi_read(0x%p,%ld,%d) \n " , CARD , buf , count , nonblock ) ) ;
/* find ourself a free or completed buffer */
for ( ; ; ) {
struct vidinfo * item ;
write_lock_irq ( & ztv - > lock ) ;
for ( item = ztv - > readinfo ; item ! = ztv - > readinfo + ZORAN_VBI_BUFFERS ; item + + ) {
if ( ! unused & & item - > status = = FBUFFER_FREE )
unused = item ;
if ( ! done & & item - > status = = FBUFFER_DONE )
done = item ;
}
if ( done | | unused )
break ;
/* no more free buffers, wait for them. */
write_unlock_irq ( & ztv - > lock ) ;
if ( nonblock )
return - EWOULDBLOCK ;
interruptible_sleep_on ( & ztv - > vbiq ) ;
if ( signal_pending ( current ) )
return - EINTR ;
}
/* Do we have 'ready' data? */
if ( ! done ) {
/* no? than this will take a while... */
if ( nonblock ) {
write_unlock_irq ( & ztv - > lock ) ;
return - EWOULDBLOCK ;
}
2006-03-25 20:19:53 +08:00
2005-04-17 06:20:36 +08:00
/* mark the unused buffer as wanted */
unused - > status = FBUFFER_BUSY ;
unused - > next = 0 ;
{ /* add to tail of queue */
struct vidinfo * oldframe = ztv - > workqueue ;
if ( ! oldframe ) ztv - > workqueue = unused ;
else {
while ( oldframe - > next ) oldframe = oldframe - > next ;
oldframe - > next = unused ;
}
}
write_unlock_irq ( & ztv - > lock ) ;
/* tell the state machine we want it filled /NOW/ */
zoran_cap ( ztv , 1 ) ;
/* wait till this buffer gets grabbed */
wait_event_interruptible ( ztv - > vbiq ,
( unused - > status ! = FBUFFER_BUSY ) ) ;
/* see if a signal did it */
if ( signal_pending ( current ) )
return - EINTR ;
done = unused ;
}
else
write_unlock_irq ( & ztv - > lock ) ;
/* Yes! we got data! */
max = done - > bpl * - done - > h ;
if ( count > max )
count = max ;
/* check if the user gave us enough room to write the data */
if ( ! access_ok ( VERIFY_WRITE , buf , count ) ) {
count = - EFAULT ;
goto out ;
}
/*
* Now transform / strip the data from YUV to Y - only
* NB . Assume the Y is in the LSB of the YUV data .
*/
{
unsigned char * optr = buf ;
unsigned char * eptr = buf + count ;
/* are we beeing accessed from an old driver? */
if ( count = = 2 * 19 * 2048 ) {
/*
* Extreme HACK , old VBI programs expect 2048 points
2006-03-25 20:19:53 +08:00
* of data , and we only got 864 orso . Double each
2005-04-17 06:20:36 +08:00
* datapoint and clear the rest of the line .
* This way we have appear to have a
* sample_frequency of 29.5 Mc .
*/
int x , y ;
unsigned char * iptr = done - > memadr + 1 ;
for ( y = done - > h ; optr < eptr & & y < 0 ; y + + )
{
/* copy to doubled data to userland */
for ( x = 0 ; optr + 1 < eptr & & x < - done - > w ; x + + )
{
unsigned char a = iptr [ x * 2 ] ;
__put_user ( a , optr + + ) ;
__put_user ( a , optr + + ) ;
}
/* and clear the rest of the line */
for ( x * = 2 ; optr < eptr & & x < done - > bpl ; x + + )
__put_user ( 0 , optr + + ) ;
/* next line */
iptr + = done - > bpl ;
}
}
else {
/*
* Other ( probably newer ) programs asked
* us what geometry we are using , and are
* reading the correct size .
*/
int x , y ;
unsigned char * iptr = done - > memadr + 1 ;
for ( y = done - > h ; optr < eptr & & y < 0 ; y + + )
{
/* copy to doubled data to userland */
for ( x = 0 ; optr < eptr & & x < - done - > w ; x + + )
__put_user ( iptr [ x * 2 ] , optr + + ) ;
/* and clear the rest of the line */
for ( ; optr < eptr & & x < done - > bpl ; x + + )
__put_user ( 0 , optr + + ) ;
/* next line */
iptr + = done - > bpl ;
}
}
/* API compliance:
* place the framenumber ( half fieldnr ) in the last long
*/
__put_user ( done - > fieldnr / 2 , ( ( ulong * ) eptr ) [ - 1 ] ) ;
}
/* keep the engine running */
done - > status = FBUFFER_FREE ;
zoran_cap ( ztv , 1 ) ;
/* tell listeners this buffer just became free */
wake_up_interruptible ( & ztv - > vbiq ) ;
/* goodbye */
out :
DEBUG ( printk ( CARD_DEBUG " vbi_read() returns %lu \n " , CARD , count ) ) ;
return count ;
}
static
unsigned int vbi_poll ( struct video_device * dev , struct file * file , poll_table * wait )
{
struct zoran * ztv = dev - > priv ;
struct vidinfo * item ;
unsigned int mask = 0 ;
poll_wait ( file , & ztv - > vbiq , wait ) ;
for ( item = ztv - > readinfo ; item ! = ztv - > readinfo + ZORAN_VBI_BUFFERS ; item + + )
if ( item - > status = = FBUFFER_DONE )
{
mask | = ( POLLIN | POLLRDNORM ) ;
break ;
}
DEBUG ( printk ( CARD_DEBUG " vbi_poll()=%x \n " , CARD , mask ) ) ;
return mask ;
}
static
int vbi_ioctl ( struct video_device * dev , unsigned int cmd , void * arg )
{
struct zoran * ztv = dev - > priv ;
switch ( cmd ) {
case VIDIOCGVBIFMT :
{
struct vbi_format f ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCGVBIINFO \n " , CARD ) ) ;
f . sampling_rate = 14750000UL ;
f . samples_per_line = - ztv - > readinfo [ 0 ] . w ;
f . sample_format = VIDEO_PALETTE_RAW ;
f . start [ 0 ] = f . start [ 1 ] = ztv - > readinfo [ 0 ] . y ;
f . start [ 1 ] + = 312 ;
f . count [ 0 ] = f . count [ 1 ] = - ztv - > readinfo [ 0 ] . h ;
f . flags = VBI_INTERLACED ;
if ( copy_to_user ( arg , & f , sizeof ( f ) ) )
return - EFAULT ;
break ;
}
case VIDIOCSVBIFMT :
{
struct vbi_format f ;
int i ;
if ( copy_from_user ( & f , arg , sizeof ( f ) ) )
return - EFAULT ;
DEBUG ( printk ( CARD_DEBUG " VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x) \n " , CARD , f . sampling_rate , f . samples_per_line , f . sample_format , f . start [ 0 ] , f . start [ 1 ] , f . count [ 0 ] , f . count [ 1 ] , f . flags ) ) ;
/* lots of parameters are fixed... (PAL) */
if ( f . sampling_rate ! = 14750000UL | |
f . samples_per_line > 864 | |
f . sample_format ! = VIDEO_PALETTE_RAW | |
f . start [ 0 ] < 0 | |
f . start [ 0 ] ! = f . start [ 1 ] - 312 | |
f . count [ 0 ] ! = f . count [ 1 ] | |
f . start [ 0 ] + f . count [ 0 ] > = 288 | |
f . flags ! = VBI_INTERLACED )
return - EINVAL ;
write_lock_irq ( & ztv - > lock ) ;
ztv - > readinfo [ 0 ] . y = f . start [ 0 ] ;
ztv - > readinfo [ 0 ] . w = - f . samples_per_line ;
ztv - > readinfo [ 0 ] . h = - f . count [ 0 ] ;
ztv - > readinfo [ 0 ] . bpl = f . samples_per_line * ztv - > readinfo [ 0 ] . bpp ;
for ( i = 1 ; i < ZORAN_VBI_BUFFERS ; i + + )
ztv - > readinfo [ i ] = ztv - > readinfo [ i ] ;
write_unlock_irq ( & ztv - > lock ) ;
break ;
}
default :
return - ENOIOCTLCMD ;
}
return 0 ;
}
static struct video_device vbi_template =
{
. owner = THIS_MODULE ,
. name = " UNSET " ,
. type = VID_TYPE_CAPTURE | VID_TYPE_TELETEXT ,
. hardware = VID_HARDWARE_ZR36120 ,
. open = vbi_open ,
. close = vbi_close ,
. read = vbi_read ,
. write = zoran_write ,
. poll = vbi_poll ,
. ioctl = vbi_ioctl ,
. minor = - 1 ,
} ;
/*
* Scan for a Zoran chip , request the irq and map the io memory
*/
static
int __init find_zoran ( void )
{
int result ;
struct zoran * ztv ;
struct pci_dev * dev = NULL ;
unsigned char revision ;
int zoran_num = 0 ;
while ( ( dev = pci_find_device ( PCI_VENDOR_ID_ZORAN , PCI_DEVICE_ID_ZORAN_36120 , dev ) ) )
{
/* Ok, a ZR36120/ZR36125 found! */
ztv = & zorans [ zoran_num ] ;
ztv - > dev = dev ;
if ( pci_enable_device ( dev ) )
return - EIO ;
pci_read_config_byte ( dev , PCI_CLASS_REVISION , & revision ) ;
printk ( KERN_INFO " zoran: Zoran %x (rev %d) " ,
dev - > device , revision ) ;
printk ( " bus: %d, devfn: %d, irq: %d, " ,
dev - > bus - > number , dev - > devfn , dev - > irq ) ;
printk ( " memory: 0x%08lx. \n " , ztv - > zoran_adr ) ;
ztv - > zoran_mem = ioremap ( ztv - > zoran_adr , 0x1000 ) ;
DEBUG ( printk ( KERN_DEBUG " zoran: mapped-memory at 0x%p \n " , ztv - > zoran_mem ) ) ;
result = request_irq ( dev - > irq , zoran_irq ,
2006-07-02 10:29:37 +08:00
IRQF_SHARED | IRQF_DISABLED , " zoran " , ztv ) ;
2005-04-17 06:20:36 +08:00
if ( result = = - EINVAL )
{
iounmap ( ztv - > zoran_mem ) ;
printk ( KERN_ERR " zoran: Bad irq number or handler \n " ) ;
return - EINVAL ;
}
if ( result = = - EBUSY )
printk ( KERN_ERR " zoran: IRQ %d busy, change your PnP config in BIOS \n " , dev - > irq ) ;
if ( result < 0 ) {
iounmap ( ztv - > zoran_mem ) ;
return result ;
}
/* Enable bus-mastering */
pci_set_master ( dev ) ;
zoran_num + + ;
}
if ( zoran_num )
printk ( KERN_INFO " zoran: %d Zoran card(s) found. \n " , zoran_num ) ;
return zoran_num ;
}
static
int __init init_zoran ( int card )
{
struct zoran * ztv = & zorans [ card ] ;
int i ;
/* if the given cardtype valid? */
if ( cardtype [ card ] > = NRTVCARDS ) {
printk ( KERN_INFO " invalid cardtype(%d) detected \n " , cardtype [ card ] ) ;
return - 1 ;
}
/* reset the zoran */
zrand ( ~ ZORAN_PCI_SOFTRESET , ZORAN_PCI ) ;
udelay ( 10 ) ;
zror ( ZORAN_PCI_SOFTRESET , ZORAN_PCI ) ;
udelay ( 10 ) ;
/* zoran chip specific details */
ztv - > card = tvcards + cardtype [ card ] ; /* point to the selected card */
ztv - > norm = 0 ; /* PAL */
ztv - > tuner_freq = 0 ;
/* videocard details */
ztv - > swidth = 800 ;
ztv - > sheight = 600 ;
ztv - > depth = 16 ;
/* State details */
ztv - > fbuffer = 0 ;
ztv - > overinfo . kindof = FBUFFER_OVERLAY ;
ztv - > overinfo . status = FBUFFER_FREE ;
ztv - > overinfo . x = 0 ;
ztv - > overinfo . y = 0 ;
ztv - > overinfo . w = 768 ; /* 640 */
ztv - > overinfo . h = 576 ; /* 480 */
ztv - > overinfo . format = VIDEO_PALETTE_RGB565 ;
ztv - > overinfo . bpp = palette2fmt [ ztv - > overinfo . format ] . bpp ;
ztv - > overinfo . bpl = ztv - > overinfo . bpp * ztv - > swidth ;
ztv - > overinfo . busadr = 0 ;
ztv - > overinfo . memadr = 0 ;
ztv - > overinfo . overlay = 0 ;
for ( i = 0 ; i < ZORAN_MAX_FBUFFERS ; i + + ) {
ztv - > grabinfo [ i ] = ztv - > overinfo ;
ztv - > grabinfo [ i ] . kindof = FBUFFER_GRAB ;
}
init_waitqueue_head ( & ztv - > grabq ) ;
/* VBI details */
ztv - > readinfo [ 0 ] = ztv - > overinfo ;
ztv - > readinfo [ 0 ] . kindof = FBUFFER_VBI ;
ztv - > readinfo [ 0 ] . w = - 864 ;
ztv - > readinfo [ 0 ] . h = - 38 ;
ztv - > readinfo [ 0 ] . format = VIDEO_PALETTE_YUV422 ;
ztv - > readinfo [ 0 ] . bpp = palette2fmt [ ztv - > readinfo [ 0 ] . format ] . bpp ;
ztv - > readinfo [ 0 ] . bpl = 1024 * ztv - > readinfo [ 0 ] . bpp ;
for ( i = 1 ; i < ZORAN_VBI_BUFFERS ; i + + )
ztv - > readinfo [ i ] = ztv - > readinfo [ 0 ] ;
init_waitqueue_head ( & ztv - > vbiq ) ;
/* maintenance data */
ztv - > have_decoder = 0 ;
ztv - > have_tuner = 0 ;
ztv - > tuner_type = 0 ;
ztv - > running = 0 ;
ztv - > users = 0 ;
rwlock_init ( & ztv - > lock ) ;
ztv - > workqueue = 0 ;
ztv - > fieldnr = 0 ;
ztv - > lastfieldnr = 0 ;
if ( triton1 )
zrand ( ~ ZORAN_VDC_TRICOM , ZORAN_VDC ) ;
/* external FL determines TOP frame */
2006-03-25 20:19:53 +08:00
zror ( ZORAN_VFEC_EXTFL , ZORAN_VFEC ) ;
2005-04-17 06:20:36 +08:00
/* set HSpol */
if ( ztv - > card - > hsync_pos )
zrwrite ( ZORAN_VFEH_HSPOL , ZORAN_VFEH ) ;
/* set VSpol */
if ( ztv - > card - > vsync_pos )
zrwrite ( ZORAN_VFEV_VSPOL , ZORAN_VFEV ) ;
/* Set the proper General Purpuse register bits */
/* implicit: no softreset, 0 waitstates */
zrwrite ( ZORAN_PCI_SOFTRESET | ( ztv - > card - > gpdir < < 0 ) , ZORAN_PCI ) ;
/* implicit: 3 duration and recovery PCI clocks on guest 0-3 */
zrwrite ( ztv - > card - > gpval < < 24 , ZORAN_GUEST ) ;
/* clear interrupt status */
zrwrite ( ~ 0 , ZORAN_ISR ) ;
/*
* i2c template
*/
ztv - > i2c = zoran_i2c_bus_template ;
sprintf ( ztv - > i2c . name , " zoran-%d " , card ) ;
ztv - > i2c . data = ztv ;
/*
* Now add the template and register the device unit
*/
ztv - > video_dev = zr36120_template ;
strcpy ( ztv - > video_dev . name , ztv - > i2c . name ) ;
ztv - > video_dev . priv = ztv ;
if ( video_register_device ( & ztv - > video_dev , VFL_TYPE_GRABBER , video_nr ) < 0 )
return - 1 ;
ztv - > vbi_dev = vbi_template ;
strcpy ( ztv - > vbi_dev . name , ztv - > i2c . name ) ;
ztv - > vbi_dev . priv = ztv ;
if ( video_register_device ( & ztv - > vbi_dev , VFL_TYPE_VBI , vbi_nr ) < 0 ) {
video_unregister_device ( & ztv - > video_dev ) ;
return - 1 ;
}
i2c_register_bus ( & ztv - > i2c ) ;
/* set interrupt mask - the PIN enable will be set later */
zrwrite ( ZORAN_ICR_GIRQ0 | ZORAN_ICR_GIRQ1 | ZORAN_ICR_CODE , ZORAN_ICR ) ;
printk ( KERN_INFO " %s: installed %s \n " , ztv - > i2c . name , ztv - > card - > name ) ;
return 0 ;
}
static
void release_zoran ( int max )
{
struct zoran * ztv ;
int i ;
2006-03-25 20:19:53 +08:00
for ( i = 0 ; i < max ; i + + )
2005-04-17 06:20:36 +08:00
{
ztv = & zorans [ i ] ;
/* turn off all capturing, DMA and IRQs */
/* reset the zoran */
zrand ( ~ ZORAN_PCI_SOFTRESET , ZORAN_PCI ) ;
udelay ( 10 ) ;
zror ( ZORAN_PCI_SOFTRESET , ZORAN_PCI ) ;
udelay ( 10 ) ;
/* first disable interrupts before unmapping the memory! */
zrwrite ( 0 , ZORAN_ICR ) ;
zrwrite ( 0xffffffffUL , ZORAN_ISR ) ;
/* free it */
free_irq ( ztv - > dev - > irq , ztv ) ;
2006-03-25 20:19:53 +08:00
2005-04-17 06:20:36 +08:00
/* unregister i2c_bus */
i2c_unregister_bus ( ( & ztv - > i2c ) ) ;
/* unmap and free memory */
if ( ztv - > zoran_mem )
iounmap ( ztv - > zoran_mem ) ;
video_unregister_device ( & ztv - > video_dev ) ;
video_unregister_device ( & ztv - > vbi_dev ) ;
}
}
void __exit zr36120_exit ( void )
{
release_zoran ( zoran_cards ) ;
}
int __init zr36120_init ( void )
{
int card ;
2006-03-25 20:19:53 +08:00
2005-04-17 06:20:36 +08:00
handle_chipset ( ) ;
zoran_cards = find_zoran ( ) ;
if ( zoran_cards < 0 )
/* no cards found, no need for a driver */
return - EIO ;
/* initialize Zorans */
for ( card = 0 ; card < zoran_cards ; card + + ) {
if ( init_zoran ( card ) < 0 ) {
/* only release the zorans we have registered */
release_zoran ( card ) ;
return - EIO ;
2006-03-25 20:19:53 +08:00
}
2005-04-17 06:20:36 +08:00
}
return 0 ;
}
module_init ( zr36120_init ) ;
module_exit ( zr36120_exit ) ;