2008-04-29 03:24:33 +04:00
/*
* cx18 driver initialization and card probing
*
* Derived from ivtv - driver . c
*
* Copyright ( C ) 2007 Hans Verkuil < hverkuil @ xs4all . nl >
2008-09-01 07:40:41 +04:00
* Copyright ( C ) 2008 Andy Walls < awalls @ radix . net >
2008-04-29 03:24:33 +04:00
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA
* 02111 - 1307 USA
*/
# include "cx18-driver.h"
2008-08-30 23:03:44 +04:00
# include "cx18-io.h"
2008-04-29 03:24:33 +04:00
# include "cx18-version.h"
# include "cx18-cards.h"
# include "cx18-i2c.h"
# include "cx18-irq.h"
# include "cx18-gpio.h"
# include "cx18-firmware.h"
# include "cx18-streams.h"
# include "cx18-av-core.h"
# include "cx18-scb.h"
# include "cx18-mailbox.h"
# include "cx18-ioctl.h"
# include "tuner-xc2028.h"
# include <media/tveeprom.h>
/* If you have already X v4l cards, then set this to X. This way
the device numbers stay matched . Example : you have a WinTV card
without radio and a Compro H900 with . Normally this would give a
video1 device together with a radio0 device for the Compro . By
setting this to 1 you ensure that radio0 is now also radio1 . */
int cx18_first_minor ;
/* add your revision and whatnot here */
static struct pci_device_id cx18_pci_tbl [ ] __devinitdata = {
{ PCI_VENDOR_ID_CX , PCI_DEVICE_ID_CX23418 ,
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , cx18_pci_tbl ) ;
2009-02-14 23:08:37 +03:00
static atomic_t cx18_instance = ATOMIC_INIT ( 0 ) ;
2008-04-29 03:24:33 +04:00
/* Parameter declarations */
static int cardtype [ CX18_MAX_CARDS ] ;
static int tuner [ CX18_MAX_CARDS ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
static int radio [ CX18_MAX_CARDS ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
2008-09-04 00:11:54 +04:00
static unsigned cardtype_c = 1 ;
static unsigned tuner_c = 1 ;
static unsigned radio_c = 1 ;
2008-04-29 03:24:33 +04:00
static char pal [ ] = " -- " ;
static char secam [ ] = " -- " ;
static char ntsc [ ] = " - " ;
/* Buffers */
static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS ;
2008-12-08 05:30:17 +03:00
static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS ;
static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS ;
2008-04-29 03:24:33 +04:00
static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS ;
static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS ;
static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS ;
2008-12-08 05:30:17 +03:00
static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE ;
static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE ;
static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE ;
static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE ;
/* VBI bufsize based on standards supported by card tuner for now */
static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE ;
static int enc_ts_bufs = - 1 ;
static int enc_mpg_bufs = - 1 ;
static int enc_idx_bufs = - 1 ;
static int enc_yuv_bufs = - 1 ;
static int enc_vbi_bufs = - 1 ;
static int enc_pcm_bufs = - 1 ;
2008-04-29 03:24:33 +04:00
static int cx18_pci_latency = 1 ;
2008-11-17 05:33:41 +03:00
static int mmio_ndelay ;
static int retry_mmio = 1 ;
2008-04-29 03:24:33 +04:00
int cx18_debug ;
module_param_array ( tuner , int , & tuner_c , 0644 ) ;
module_param_array ( radio , bool , & radio_c , 0644 ) ;
module_param_array ( cardtype , int , & cardtype_c , 0644 ) ;
module_param_string ( pal , pal , sizeof ( pal ) , 0644 ) ;
module_param_string ( secam , secam , sizeof ( secam ) , 0644 ) ;
module_param_string ( ntsc , ntsc , sizeof ( ntsc ) , 0644 ) ;
module_param_named ( debug , cx18_debug , int , 0644 ) ;
2008-11-17 05:33:41 +03:00
module_param ( mmio_ndelay , int , 0644 ) ;
module_param ( retry_mmio , int , 0644 ) ;
2008-04-29 03:24:33 +04:00
module_param ( cx18_pci_latency , int , 0644 ) ;
module_param ( cx18_first_minor , int , 0644 ) ;
module_param ( enc_ts_buffers , int , 0644 ) ;
2008-12-08 05:30:17 +03:00
module_param ( enc_mpg_buffers , int , 0644 ) ;
module_param ( enc_idx_buffers , int , 0644 ) ;
2008-04-29 03:24:33 +04:00
module_param ( enc_yuv_buffers , int , 0644 ) ;
module_param ( enc_vbi_buffers , int , 0644 ) ;
module_param ( enc_pcm_buffers , int , 0644 ) ;
2008-12-08 05:30:17 +03:00
module_param ( enc_ts_bufsize , int , 0644 ) ;
module_param ( enc_mpg_bufsize , int , 0644 ) ;
module_param ( enc_idx_bufsize , int , 0644 ) ;
module_param ( enc_yuv_bufsize , int , 0644 ) ;
/* VBI bufsize based on standards supported by card tuner for now */
module_param ( enc_pcm_bufsize , int , 0644 ) ;
module_param ( enc_ts_bufs , int , 0644 ) ;
module_param ( enc_mpg_bufs , int , 0644 ) ;
module_param ( enc_idx_bufs , int , 0644 ) ;
module_param ( enc_yuv_bufs , int , 0644 ) ;
module_param ( enc_vbi_bufs , int , 0644 ) ;
module_param ( enc_pcm_bufs , int , 0644 ) ;
2008-04-29 03:24:33 +04:00
MODULE_PARM_DESC ( tuner , " Tuner type selection, \n "
" \t \t \t see tuner.h for values " ) ;
MODULE_PARM_DESC ( radio ,
" Enable or disable the radio. Use only if autodetection \n "
" \t \t \t fails. 0 = disable, 1 = enable " ) ;
MODULE_PARM_DESC ( cardtype ,
" Only use this option if your card is not detected properly. \n "
" \t \t Specify card type: \n "
" \t \t \t 1 = Hauppauge HVR 1600 (ESMT memory) \n "
" \t \t \t 2 = Hauppauge HVR 1600 (Samsung memory) \n "
" \t \t \t 3 = Compro VideoMate H900 \n "
" \t \t \t 4 = Yuan MPC718 \n "
2008-06-21 18:06:44 +04:00
" \t \t \t 5 = Conexant Raptor PAL/SECAM \n "
2008-10-05 03:28:40 +04:00
" \t \t \t 6 = Toshiba Qosmio DVB-T/Analog \n "
2009-01-20 00:31:22 +03:00
" \t \t \t 7 = Leadtek WinFast PVR2100/DVR3100 H \n "
2008-04-29 03:24:33 +04:00
" \t \t \t 0 = Autodetect (default) \n "
" \t \t \t -1 = Ignore this card \n \t \t " ) ;
MODULE_PARM_DESC ( pal , " Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60 " ) ;
MODULE_PARM_DESC ( secam , " Set SECAM standard: B, G, H, D, K, L, LC " ) ;
MODULE_PARM_DESC ( ntsc , " Set NTSC standard: M, J, K " ) ;
MODULE_PARM_DESC ( debug ,
" Debug level (bitmask). Default: 0 \n "
" \t \t \t 1/0x0001: warning \n "
" \t \t \t 2/0x0002: info \n "
" \t \t \t 4/0x0004: mailbox \n "
" \t \t \t 8/0x0008: dma \n "
" \t \t \t 16/0x0010: ioctl \n "
" \t \t \t 32/0x0020: file \n "
" \t \t \t 64/0x0040: i2c \n "
" \t \t \t 128/0x0080: irq \n "
" \t \t \t 256/0x0100: high volume \n " ) ;
MODULE_PARM_DESC ( cx18_pci_latency ,
" Change the PCI latency to 64 if lower: 0 = No, 1 = Yes, \n "
" \t \t \t Default: Yes " ) ;
2008-09-29 04:46:02 +04:00
MODULE_PARM_DESC ( retry_mmio ,
2008-11-17 05:33:41 +03:00
" (Deprecated) MMIO writes are now always checked and retried \n "
" \t \t \t Effectively: 1 [Yes] " ) ;
2008-09-01 07:40:41 +04:00
MODULE_PARM_DESC ( mmio_ndelay ,
2008-11-17 05:33:41 +03:00
" (Deprecated) MMIO accesses are now never purposely delayed \n "
" \t \t \t Effectively: 0 ns " ) ;
2008-04-29 03:24:33 +04:00
MODULE_PARM_DESC ( enc_ts_buffers ,
2008-12-08 05:30:17 +03:00
" Encoder TS buffer memory (MB). (enc_ts_bufs can override) \n "
2008-04-29 03:24:33 +04:00
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_TS_BUFFERS ) ) ;
2008-12-08 05:30:17 +03:00
MODULE_PARM_DESC ( enc_ts_bufsize ,
" Size of an encoder TS buffer (kB) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_TS_BUFSIZE ) ) ;
MODULE_PARM_DESC ( enc_ts_bufs ,
" Number of encoder TS buffers \n "
" \t \t \t Default is computed from other enc_ts_* parameters " ) ;
MODULE_PARM_DESC ( enc_mpg_buffers ,
" Encoder MPG buffer memory (MB). (enc_mpg_bufs can override) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_MPG_BUFFERS ) ) ;
MODULE_PARM_DESC ( enc_mpg_bufsize ,
" Size of an encoder MPG buffer (kB) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_MPG_BUFSIZE ) ) ;
MODULE_PARM_DESC ( enc_mpg_bufs ,
" Number of encoder MPG buffers \n "
" \t \t \t Default is computed from other enc_mpg_* parameters " ) ;
MODULE_PARM_DESC ( enc_idx_buffers ,
" Encoder IDX buffer memory (MB). (enc_idx_bufs can override) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_IDX_BUFFERS ) ) ;
MODULE_PARM_DESC ( enc_idx_bufsize ,
" Size of an encoder IDX buffer (kB) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_IDX_BUFSIZE ) ) ;
MODULE_PARM_DESC ( enc_idx_bufs ,
" Number of encoder IDX buffers \n "
" \t \t \t Default is computed from other enc_idx_* parameters " ) ;
2008-04-29 03:24:33 +04:00
MODULE_PARM_DESC ( enc_yuv_buffers ,
2008-12-08 05:30:17 +03:00
" Encoder YUV buffer memory (MB). (enc_yuv_bufs can override) \n "
2008-04-29 03:24:33 +04:00
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_YUV_BUFFERS ) ) ;
2008-12-08 05:30:17 +03:00
MODULE_PARM_DESC ( enc_yuv_bufsize ,
" Size of an encoder YUV buffer (kB) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_YUV_BUFSIZE ) ) ;
MODULE_PARM_DESC ( enc_yuv_bufs ,
" Number of encoder YUV buffers \n "
" \t \t \t Default is computed from other enc_yuv_* parameters " ) ;
2008-04-29 03:24:33 +04:00
MODULE_PARM_DESC ( enc_vbi_buffers ,
2008-12-08 05:30:17 +03:00
" Encoder VBI buffer memory (MB). (enc_vbi_bufs can override) \n "
2008-04-29 03:24:33 +04:00
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_VBI_BUFFERS ) ) ;
2008-12-08 05:30:17 +03:00
MODULE_PARM_DESC ( enc_vbi_bufs ,
" Number of encoder VBI buffers \n "
" \t \t \t Default is computed from enc_vbi_buffers & tuner std " ) ;
2008-04-29 03:24:33 +04:00
MODULE_PARM_DESC ( enc_pcm_buffers ,
2008-12-08 05:30:17 +03:00
" Encoder PCM buffer memory (MB). (enc_pcm_bufs can override) \n "
2008-04-29 03:24:33 +04:00
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_PCM_BUFFERS ) ) ;
2008-12-08 05:30:17 +03:00
MODULE_PARM_DESC ( enc_pcm_bufsize ,
" Size of an encoder PCM buffer (kB) \n "
" \t \t \t Default: " __stringify ( CX18_DEFAULT_ENC_PCM_BUFSIZE ) ) ;
MODULE_PARM_DESC ( enc_pcm_bufs ,
" Number of encoder PCM buffers \n "
" \t \t \t Default is computed from other enc_pcm_* parameters " ) ;
2008-04-29 03:24:33 +04:00
2008-10-04 15:36:54 +04:00
MODULE_PARM_DESC ( cx18_first_minor , " Set kernel number assigned to first card " ) ;
2008-04-29 03:24:33 +04:00
MODULE_AUTHOR ( " Hans Verkuil " ) ;
MODULE_DESCRIPTION ( " CX23418 driver " ) ;
MODULE_SUPPORTED_DEVICE ( " CX23418 MPEG2 encoder " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( CX18_VERSION ) ;
/* Generic utility functions */
int cx18_msleep_timeout ( unsigned int msecs , int intr )
{
2008-11-08 20:19:37 +03:00
long int timeout = msecs_to_jiffies ( msecs ) ;
2008-04-29 03:24:33 +04:00
int sig ;
do {
set_current_state ( intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE ) ;
timeout = schedule_timeout ( timeout ) ;
sig = intr ? signal_pending ( current ) : 0 ;
} while ( ! sig & & timeout ) ;
return sig ;
}
/* Release ioremapped memory */
static void cx18_iounmap ( struct cx18 * cx )
{
if ( cx = = NULL )
return ;
/* Release io memory */
if ( cx - > enc_mem ! = NULL ) {
CX18_DEBUG_INFO ( " releasing enc_mem \n " ) ;
iounmap ( cx - > enc_mem ) ;
cx - > enc_mem = NULL ;
}
}
/* Hauppauge card? get values from tveeprom */
void cx18_read_eeprom ( struct cx18 * cx , struct tveeprom * tv )
{
2009-02-21 05:52:13 +03:00
struct i2c_client c ;
2008-04-29 03:24:33 +04:00
u8 eedata [ 256 ] ;
2009-02-22 04:27:37 +03:00
memset ( & c , 0 , sizeof ( c ) ) ;
2009-02-21 05:52:13 +03:00
strncpy ( c . name , " cx18 tveeprom tmp " , sizeof ( c . name ) ) ;
c . name [ sizeof ( c . name ) - 1 ] = ' \0 ' ;
c . adapter = & cx - > i2c_adap [ 0 ] ;
c . addr = 0xA0 > > 1 ;
tveeprom_read ( & c , eedata , sizeof ( eedata ) ) ;
tveeprom_hauppauge_analog ( & c , tv , eedata ) ;
2008-04-29 03:24:33 +04:00
}
static void cx18_process_eeprom ( struct cx18 * cx )
{
struct tveeprom tv ;
cx18_read_eeprom ( cx , & tv ) ;
/* Many thanks to Steven Toth from Hauppauge for providing the
model numbers */
2008-05-12 21:45:19 +04:00
/* Note: the Samsung memory models cannot be reliably determined
from the model number . Use the cardtype module option if you
have one of these preproduction models . */
2008-04-29 03:24:33 +04:00
switch ( tv . model ) {
2008-05-12 21:45:19 +04:00
case 74000 . . . 74999 :
2008-04-29 03:24:33 +04:00
cx - > card = cx18_get_card ( CX18_CARD_HVR_1600_ESMT ) ;
break ;
case 0 :
CX18_ERR ( " Invalid EEPROM \n " ) ;
return ;
default :
CX18_ERR ( " Unknown model %d, defaulting to HVR-1600 \n " , tv . model ) ;
cx - > card = cx18_get_card ( CX18_CARD_HVR_1600_ESMT ) ;
break ;
}
cx - > v4l2_cap = cx - > card - > v4l2_capabilities ;
cx - > card_name = cx - > card - > name ;
cx - > card_i2c = cx - > card - > i2c ;
CX18_INFO ( " Autodetected %s \n " , cx - > card_name ) ;
if ( tv . tuner_type = = TUNER_ABSENT )
CX18_ERR ( " tveeprom cannot autodetect tuner! " ) ;
if ( cx - > options . tuner = = - 1 )
cx - > options . tuner = tv . tuner_type ;
if ( cx - > options . radio = = - 1 )
cx - > options . radio = ( tv . has_radio ! = 0 ) ;
if ( cx - > std ! = 0 )
/* user specified tuner standard */
return ;
/* autodetect tuner standard */
if ( tv . tuner_formats & V4L2_STD_PAL ) {
CX18_DEBUG_INFO ( " PAL tuner detected \n " ) ;
cx - > std | = V4L2_STD_PAL_BG | V4L2_STD_PAL_H ;
} else if ( tv . tuner_formats & V4L2_STD_NTSC ) {
CX18_DEBUG_INFO ( " NTSC tuner detected \n " ) ;
cx - > std | = V4L2_STD_NTSC_M ;
} else if ( tv . tuner_formats & V4L2_STD_SECAM ) {
CX18_DEBUG_INFO ( " SECAM tuner detected \n " ) ;
cx - > std | = V4L2_STD_SECAM_L ;
} else {
CX18_INFO ( " No tuner detected, default to NTSC-M \n " ) ;
cx - > std | = V4L2_STD_NTSC_M ;
}
}
static v4l2_std_id cx18_parse_std ( struct cx18 * cx )
{
switch ( pal [ 0 ] ) {
case ' 6 ' :
return V4L2_STD_PAL_60 ;
case ' b ' :
case ' B ' :
case ' g ' :
case ' G ' :
return V4L2_STD_PAL_BG ;
case ' h ' :
case ' H ' :
return V4L2_STD_PAL_H ;
case ' n ' :
case ' N ' :
if ( pal [ 1 ] = = ' c ' | | pal [ 1 ] = = ' C ' )
return V4L2_STD_PAL_Nc ;
return V4L2_STD_PAL_N ;
case ' i ' :
case ' I ' :
return V4L2_STD_PAL_I ;
case ' d ' :
case ' D ' :
case ' k ' :
case ' K ' :
return V4L2_STD_PAL_DK ;
case ' M ' :
case ' m ' :
return V4L2_STD_PAL_M ;
case ' - ' :
break ;
default :
CX18_WARN ( " pal= argument not recognised \n " ) ;
return 0 ;
}
switch ( secam [ 0 ] ) {
case ' b ' :
case ' B ' :
case ' g ' :
case ' G ' :
case ' h ' :
case ' H ' :
return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H ;
case ' d ' :
case ' D ' :
case ' k ' :
case ' K ' :
return V4L2_STD_SECAM_DK ;
case ' l ' :
case ' L ' :
if ( secam [ 1 ] = = ' C ' | | secam [ 1 ] = = ' c ' )
return V4L2_STD_SECAM_LC ;
return V4L2_STD_SECAM_L ;
case ' - ' :
break ;
default :
CX18_WARN ( " secam= argument not recognised \n " ) ;
return 0 ;
}
switch ( ntsc [ 0 ] ) {
case ' m ' :
case ' M ' :
return V4L2_STD_NTSC_M ;
case ' j ' :
case ' J ' :
return V4L2_STD_NTSC_M_JP ;
case ' k ' :
case ' K ' :
return V4L2_STD_NTSC_M_KR ;
case ' - ' :
break ;
default :
CX18_WARN ( " ntsc= argument not recognised \n " ) ;
return 0 ;
}
/* no match found */
return 0 ;
}
static void cx18_process_options ( struct cx18 * cx )
{
int i , j ;
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_TS ] = enc_ts_buffers ;
2008-12-08 05:30:17 +03:00
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_MPG ] = enc_mpg_buffers ;
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_IDX ] = enc_idx_buffers ;
2008-04-29 03:24:33 +04:00
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_YUV ] = enc_yuv_buffers ;
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_VBI ] = enc_vbi_buffers ;
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_PCM ] = enc_pcm_buffers ;
2008-12-08 05:30:17 +03:00
cx - > options . megabytes [ CX18_ENC_STREAM_TYPE_RAD ] = 0 ; /* control only */
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_TS ] = enc_ts_bufs ;
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_MPG ] = enc_mpg_bufs ;
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_IDX ] = enc_idx_bufs ;
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_YUV ] = enc_yuv_bufs ;
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_VBI ] = enc_vbi_bufs ;
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_PCM ] = enc_pcm_bufs ;
cx - > stream_buffers [ CX18_ENC_STREAM_TYPE_RAD ] = 0 ; /* control, no data */
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_TS ] = enc_ts_bufsize ;
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_MPG ] = enc_mpg_bufsize ;
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_IDX ] = enc_idx_bufsize ;
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_YUV ] = enc_yuv_bufsize ;
2009-02-07 21:47:28 +03:00
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_VBI ] = vbi_active_samples * 36 ;
2008-12-08 05:30:17 +03:00
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_PCM ] = enc_pcm_bufsize ;
cx - > stream_buf_size [ CX18_ENC_STREAM_TYPE_RAD ] = 0 ; /* control no data */
2009-02-07 21:47:28 +03:00
/* Ensure stream_buffers & stream_buf_size are valid */
2008-12-08 05:30:17 +03:00
for ( i = 0 ; i < CX18_MAX_STREAMS ; i + + ) {
2009-02-07 21:47:28 +03:00
if ( cx - > stream_buffers [ i ] = = 0 | | /* User said 0 buffers */
cx - > options . megabytes [ i ] < = 0 | | /* User said 0 MB total */
cx - > stream_buf_size [ i ] < = 0 ) { /* User said buf size 0 */
2008-12-08 05:30:17 +03:00
cx - > options . megabytes [ i ] = 0 ;
cx - > stream_buffers [ i ] = 0 ;
cx - > stream_buf_size [ i ] = 0 ;
continue ;
}
2009-02-07 21:47:28 +03:00
/*
* VBI is a special case where the stream_buf_size is fixed
* and already in bytes
*/
if ( i = = CX18_ENC_STREAM_TYPE_VBI ) {
if ( cx - > stream_buffers [ i ] < 0 ) {
cx - > stream_buffers [ i ] =
cx - > options . megabytes [ i ] * 1024 * 1024
/ cx - > stream_buf_size [ i ] ;
} else {
/* N.B. This might round down to 0 */
cx - > options . megabytes [ i ] =
cx - > stream_buffers [ i ]
* cx - > stream_buf_size [ i ] / ( 1024 * 1024 ) ;
2008-12-08 05:30:17 +03:00
}
continue ;
}
2009-02-07 21:47:28 +03:00
/* All other streams have stream_buf_size in kB at this point */
2008-12-08 05:30:17 +03:00
if ( cx - > stream_buffers [ i ] < 0 ) {
cx - > stream_buffers [ i ] = cx - > options . megabytes [ i ] * 1024
/ cx - > stream_buf_size [ i ] ;
} else {
/* N.B. This might round down to 0 */
cx - > options . megabytes [ i ] =
cx - > stream_buffers [ i ] * cx - > stream_buf_size [ i ] / 1024 ;
}
cx - > stream_buf_size [ i ] * = 1024 ; /* convert from kB to bytes */
}
2009-02-14 23:08:37 +03:00
cx - > options . cardtype = cardtype [ cx - > instance ] ;
cx - > options . tuner = tuner [ cx - > instance ] ;
cx - > options . radio = radio [ cx - > instance ] ;
2008-04-29 03:24:33 +04:00
cx - > std = cx18_parse_std ( cx ) ;
if ( cx - > options . cardtype = = - 1 ) {
CX18_INFO ( " Ignore card \n " ) ;
return ;
}
cx - > card = cx18_get_card ( cx - > options . cardtype - 1 ) ;
if ( cx - > card )
CX18_INFO ( " User specified %s card \n " , cx - > card - > name ) ;
else if ( cx - > options . cardtype ! = 0 )
CX18_ERR ( " Unknown user specified type, trying to autodetect card \n " ) ;
if ( cx - > card = = NULL ) {
2009-01-11 03:54:39 +03:00
if ( cx - > pci_dev - > subsystem_vendor = = CX18_PCI_ID_HAUPPAUGE ) {
2008-04-29 03:24:33 +04:00
cx - > card = cx18_get_card ( CX18_CARD_HVR_1600_ESMT ) ;
CX18_INFO ( " Autodetected Hauppauge card \n " ) ;
}
}
if ( cx - > card = = NULL ) {
for ( i = 0 ; ( cx - > card = cx18_get_card ( i ) ) ; i + + ) {
if ( cx - > card - > pci_list = = NULL )
continue ;
for ( j = 0 ; cx - > card - > pci_list [ j ] . device ; j + + ) {
2009-01-11 03:54:39 +03:00
if ( cx - > pci_dev - > device ! =
2008-04-29 03:24:33 +04:00
cx - > card - > pci_list [ j ] . device )
continue ;
2009-01-11 03:54:39 +03:00
if ( cx - > pci_dev - > subsystem_vendor ! =
2008-04-29 03:24:33 +04:00
cx - > card - > pci_list [ j ] . subsystem_vendor )
continue ;
2009-01-11 03:54:39 +03:00
if ( cx - > pci_dev - > subsystem_device ! =
2008-04-29 03:24:33 +04:00
cx - > card - > pci_list [ j ] . subsystem_device )
continue ;
CX18_INFO ( " Autodetected %s card \n " , cx - > card - > name ) ;
goto done ;
}
}
}
done :
if ( cx - > card = = NULL ) {
cx - > card = cx18_get_card ( CX18_CARD_HVR_1600_ESMT ) ;
2008-09-05 00:24:51 +04:00
CX18_ERR ( " Unknown card: vendor/device: [%04x:%04x] \n " ,
2009-01-11 03:54:39 +03:00
cx - > pci_dev - > vendor , cx - > pci_dev - > device ) ;
2008-09-05 00:24:51 +04:00
CX18_ERR ( " subsystem vendor/device: [%04x:%04x] \n " ,
2009-01-11 03:54:39 +03:00
cx - > pci_dev - > subsystem_vendor ,
cx - > pci_dev - > subsystem_device ) ;
2008-04-29 03:24:33 +04:00
CX18_ERR ( " Defaulting to %s card \n " , cx - > card - > name ) ;
CX18_ERR ( " Please mail the vendor/device and subsystem vendor/device IDs and what kind of \n " ) ;
CX18_ERR ( " card you have to the ivtv-devel mailinglist (www.ivtvdriver.org) \n " ) ;
CX18_ERR ( " Prefix your subject line with [UNKNOWN CX18 CARD]. \n " ) ;
}
cx - > v4l2_cap = cx - > card - > v4l2_capabilities ;
cx - > card_name = cx - > card - > name ;
cx - > card_i2c = cx - > card - > i2c ;
}
/* Precondition: the cx18 structure has been memset to 0. Only
2009-02-14 23:08:37 +03:00
the dev and instance fields have been filled in .
2008-04-29 03:24:33 +04:00
No assumptions on the card type may be made here ( see cx18_init_struct2
for that ) .
*/
static int __devinit cx18_init_struct1 ( struct cx18 * cx )
{
2008-11-16 07:38:19 +03:00
int i ;
2009-01-11 03:54:39 +03:00
cx - > base_addr = pci_resource_start ( cx - > pci_dev , 0 ) ;
2008-04-29 03:24:33 +04:00
mutex_init ( & cx - > serialize_lock ) ;
2008-07-14 02:05:25 +04:00
mutex_init ( & cx - > gpio_lock ) ;
2008-11-06 07:15:41 +03:00
mutex_init ( & cx - > epu2apu_mb_lock ) ;
mutex_init ( & cx - > epu2cpu_mb_lock ) ;
2008-04-29 03:24:33 +04:00
2009-02-14 23:08:37 +03:00
cx - > work_queue = create_singlethread_workqueue ( cx - > v4l2_dev . name ) ;
2008-11-26 03:43:05 +03:00
if ( cx - > work_queue = = NULL ) {
CX18_ERR ( " Unable to create work hander thread \n " ) ;
return - ENOMEM ;
}
2008-11-16 07:38:19 +03:00
for ( i = 0 ; i < CX18_MAX_EPU_WORK_ORDERS ; i + + ) {
cx - > epu_work_order [ i ] . cx = cx ;
cx - > epu_work_order [ i ] . str = cx - > epu_debug_str ;
INIT_WORK ( & cx - > epu_work_order [ i ] . work , cx18_epu_work_handler ) ;
}
2008-11-05 06:49:14 +03:00
2008-04-29 03:24:33 +04:00
/* start counting open_id at 1 */
cx - > open_id = 1 ;
/* Initial settings */
cx2341x_fill_defaults ( & cx - > params ) ;
cx - > temporal_strength = cx - > params . video_temporal_filter ;
cx - > spatial_strength = cx - > params . video_spatial_filter ;
cx - > filter_mode = cx - > params . video_spatial_filter_mode |
( cx - > params . video_temporal_filter_mode < < 1 ) |
( cx - > params . video_median_filter_type < < 2 ) ;
cx - > params . port = CX2341X_PORT_MEMORY ;
2009-01-31 06:33:02 +03:00
cx - > params . capabilities =
CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3 | CX2341X_CAP_HAS_SLICED_VBI ;
2008-04-29 03:24:33 +04:00
init_waitqueue_head ( & cx - > cap_w ) ;
init_waitqueue_head ( & cx - > mb_apu_waitq ) ;
init_waitqueue_head ( & cx - > mb_cpu_waitq ) ;
init_waitqueue_head ( & cx - > dma_waitq ) ;
/* VBI */
2008-12-12 22:24:04 +03:00
cx - > vbi . in . type = V4L2_BUF_TYPE_VBI_CAPTURE ;
2008-04-29 03:24:33 +04:00
cx - > vbi . sliced_in = & cx - > vbi . in . fmt . sliced ;
2008-12-13 02:00:29 +03:00
2008-04-29 03:24:33 +04:00
return 0 ;
}
/* Second initialization part. Here the card type has been
autodetected . */
static void __devinit cx18_init_struct2 ( struct cx18 * cx )
{
int i ;
for ( i = 0 ; i < CX18_CARD_MAX_VIDEO_INPUTS ; i + + )
if ( cx - > card - > video_inputs [ i ] . video_type = = 0 )
break ;
cx - > nof_inputs = i ;
for ( i = 0 ; i < CX18_CARD_MAX_AUDIO_INPUTS ; i + + )
if ( cx - > card - > audio_inputs [ i ] . audio_type = = 0 )
break ;
cx - > nof_audio_inputs = i ;
/* Find tuner input */
for ( i = 0 ; i < cx - > nof_inputs ; i + + ) {
if ( cx - > card - > video_inputs [ i ] . video_type = =
CX18_CARD_INPUT_VID_TUNER )
break ;
}
if ( i = = cx - > nof_inputs )
i = 0 ;
cx - > active_input = i ;
cx - > audio_input = cx - > card - > video_inputs [ i ] . audio_index ;
}
2009-01-11 03:54:39 +03:00
static int cx18_setup_pci ( struct cx18 * cx , struct pci_dev * pci_dev ,
2008-04-29 03:24:33 +04:00
const struct pci_device_id * pci_id )
{
u16 cmd ;
unsigned char pci_latency ;
CX18_DEBUG_INFO ( " Enabling pci device \n " ) ;
2009-01-11 03:54:39 +03:00
if ( pci_enable_device ( pci_dev ) ) {
2009-02-14 23:08:37 +03:00
CX18_ERR ( " Can't enable device %d! \n " , cx - > instance ) ;
2008-04-29 03:24:33 +04:00
return - EIO ;
}
2009-01-11 03:54:39 +03:00
if ( pci_set_dma_mask ( pci_dev , 0xffffffff ) ) {
2009-02-14 23:08:37 +03:00
CX18_ERR ( " No suitable DMA available, card %d \n " , cx - > instance ) ;
2008-04-29 03:24:33 +04:00
return - EIO ;
}
if ( ! request_mem_region ( cx - > base_addr , CX18_MEM_SIZE , " cx18 encoder " ) ) {
2009-02-14 23:08:37 +03:00
CX18_ERR ( " Cannot request encoder memory region, card %d \n " ,
cx - > instance ) ;
2008-04-29 03:24:33 +04:00
return - EIO ;
}
2008-08-29 23:10:21 +04:00
/* Enable bus mastering and memory mapped IO for the CX23418 */
2009-01-11 03:54:39 +03:00
pci_read_config_word ( pci_dev , PCI_COMMAND , & cmd ) ;
2008-08-29 23:10:21 +04:00
cmd | = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ;
2009-01-11 03:54:39 +03:00
pci_write_config_word ( pci_dev , PCI_COMMAND , cmd ) ;
2008-04-29 03:24:33 +04:00
2009-01-11 03:54:39 +03:00
pci_read_config_byte ( pci_dev , PCI_CLASS_REVISION , & cx - > card_rev ) ;
pci_read_config_byte ( pci_dev , PCI_LATENCY_TIMER , & pci_latency ) ;
2008-04-29 03:24:33 +04:00
if ( pci_latency < 64 & & cx18_pci_latency ) {
CX18_INFO ( " Unreasonably low latency timer, "
" setting to 64 (was %d) \n " , pci_latency ) ;
2009-01-11 03:54:39 +03:00
pci_write_config_byte ( pci_dev , PCI_LATENCY_TIMER , 64 ) ;
pci_read_config_byte ( pci_dev , PCI_LATENCY_TIMER , & pci_latency ) ;
2008-04-29 03:24:33 +04:00
}
CX18_DEBUG_INFO ( " cx%d (rev %d) at %02x:%02x.%x, "
" irq: %d, latency: %d, memory: 0x%lx \n " ,
2009-01-11 03:54:39 +03:00
cx - > pci_dev - > device , cx - > card_rev , pci_dev - > bus - > number ,
PCI_SLOT ( pci_dev - > devfn ) , PCI_FUNC ( pci_dev - > devfn ) ,
cx - > pci_dev - > irq , pci_latency , ( unsigned long ) cx - > base_addr ) ;
2008-04-29 03:24:33 +04:00
return 0 ;
}
2009-02-21 05:52:13 +03:00
static void cx18_init_subdevs ( struct cx18 * cx )
2008-04-29 03:24:33 +04:00
{
u32 hw = cx - > card - > hw_all ;
2009-02-21 05:52:13 +03:00
u32 device ;
2008-04-29 03:24:33 +04:00
int i ;
2009-02-21 05:52:13 +03:00
for ( i = 0 , device = 1 ; i < 32 ; i + + , device < < = 1 ) {
2008-04-29 03:24:33 +04:00
if ( ! ( device & hw ) )
continue ;
2009-02-21 05:52:13 +03:00
switch ( device ) {
case CX18_HW_DVB :
case CX18_HW_TVEEPROM :
/* These subordinate devices do not use probing */
2008-04-29 03:24:33 +04:00
cx - > hw_flags | = device ;
2009-02-21 05:52:13 +03:00
break ;
case CX18_HW_418_AV :
/* The A/V decoder gets probed earlier to set PLLs */
/* Just note that the card uses it (i.e. has analog) */
2008-04-29 03:24:33 +04:00
cx - > hw_flags | = device ;
2009-02-21 05:52:13 +03:00
break ;
2009-02-22 00:42:49 +03:00
case CX18_HW_GPIO_RESET_CTRL :
/*
* The Reset Controller gets probed and added to
* hw_flags earlier for i2c adapter / bus initialization
*/
break ;
case CX18_HW_GPIO_MUX :
if ( cx18_gpio_register ( cx , device ) = = 0 )
cx - > hw_flags | = device ;
break ;
2009-02-21 05:52:13 +03:00
default :
if ( cx18_i2c_register ( cx , i ) = = 0 )
cx - > hw_flags | = device ;
break ;
}
2008-04-29 03:24:33 +04:00
}
2009-02-21 05:52:13 +03:00
if ( cx - > hw_flags & CX18_HW_418_AV )
cx - > sd_av = cx18_find_hw ( cx , CX18_HW_418_AV ) ;
if ( cx - > card - > hw_muxer ! = 0 )
cx - > sd_extmux = cx18_find_hw ( cx , cx - > card - > hw_muxer ) ;
2008-04-29 03:24:33 +04:00
}
2009-01-11 03:54:39 +03:00
static int __devinit cx18_probe ( struct pci_dev * pci_dev ,
2008-04-29 03:24:33 +04:00
const struct pci_device_id * pci_id )
{
int retval = 0 ;
2008-10-18 15:51:28 +04:00
int i ;
2008-04-29 03:24:33 +04:00
u32 devtype ;
struct cx18 * cx ;
2009-02-14 23:08:37 +03:00
/* FIXME - module parameter arrays constrain max instances */
i = atomic_inc_return ( & cx18_instance ) - 1 ;
if ( i > = CX18_MAX_CARDS ) {
printk ( KERN_ERR " cx18: cannot manage card %d, driver has a "
" limit of 0 - %d \n " , i , CX18_MAX_CARDS - 1 ) ;
2008-04-29 03:24:33 +04:00
return - ENOMEM ;
}
cx = kzalloc ( sizeof ( struct cx18 ) , GFP_ATOMIC ) ;
2009-02-14 23:08:37 +03:00
if ( cx = = NULL ) {
printk ( KERN_ERR " cx18: cannot manage card %d, out of memory \n " ,
i ) ;
2008-04-29 03:24:33 +04:00
return - ENOMEM ;
}
2009-01-11 21:08:53 +03:00
cx - > pci_dev = pci_dev ;
2009-02-14 23:08:37 +03:00
cx - > instance = i ;
2009-01-11 21:08:53 +03:00
retval = v4l2_device_register ( & pci_dev - > dev , & cx - > v4l2_dev ) ;
if ( retval ) {
2009-02-14 23:08:37 +03:00
printk ( KERN_ERR " cx18: v4l2_device_register of card %d failed "
" \n " , cx - > instance ) ;
kfree ( cx ) ;
return retval ;
2009-01-11 21:08:53 +03:00
}
2009-02-14 23:08:37 +03:00
snprintf ( cx - > v4l2_dev . name , sizeof ( cx - > v4l2_dev . name ) , " cx18-%d " ,
cx - > instance ) ;
CX18_INFO ( " Initializing card %d \n " , cx - > instance ) ;
2009-01-11 21:08:53 +03:00
2008-04-29 03:24:33 +04:00
cx18_process_options ( cx ) ;
if ( cx - > options . cardtype = = - 1 ) {
retval = - ENODEV ;
2009-02-14 23:08:37 +03:00
goto err ;
2008-04-29 03:24:33 +04:00
}
if ( cx18_init_struct1 ( cx ) ) {
retval = - ENOMEM ;
2009-02-14 23:08:37 +03:00
goto err ;
2008-04-29 03:24:33 +04:00
}
CX18_DEBUG_INFO ( " base addr: 0x%08x \n " , cx - > base_addr ) ;
/* PCI Device Setup */
2009-01-11 03:54:39 +03:00
retval = cx18_setup_pci ( cx , pci_dev , pci_id ) ;
2008-11-26 03:43:05 +03:00
if ( retval ! = 0 )
goto free_workqueue ;
2008-04-29 03:24:33 +04:00
/* map io memory */
CX18_DEBUG_INFO ( " attempting ioremap at 0x%08x len 0x%08x \n " ,
cx - > base_addr + CX18_MEM_OFFSET , CX18_MEM_SIZE ) ;
cx - > enc_mem = ioremap_nocache ( cx - > base_addr + CX18_MEM_OFFSET ,
CX18_MEM_SIZE ) ;
if ( ! cx - > enc_mem ) {
CX18_ERR ( " ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h \n " ) ;
CX18_ERR ( " or disabling CONFIG_HIGHMEM4G into the kernel would help \n " ) ;
retval = - ENOMEM ;
goto free_mem ;
}
cx - > reg_mem = cx - > enc_mem + CX18_REG_OFFSET ;
2008-08-30 23:03:44 +04:00
devtype = cx18_read_reg ( cx , 0xC72028 ) ;
2008-04-29 03:24:33 +04:00
switch ( devtype & 0xff000000 ) {
case 0xff000000 :
CX18_INFO ( " cx23418 revision %08x (A) \n " , devtype ) ;
break ;
case 0x01000000 :
CX18_INFO ( " cx23418 revision %08x (B) \n " , devtype ) ;
break ;
default :
CX18_INFO ( " cx23418 revision %08x (Unknown) \n " , devtype ) ;
break ;
}
cx18_init_power ( cx , 1 ) ;
cx18_init_memory ( cx ) ;
2008-05-21 07:32:01 +04:00
cx - > scb = ( struct cx18_scb __iomem * ) ( cx - > enc_mem + SCB_OFFSET ) ;
2008-04-29 03:24:33 +04:00
cx18_init_scb ( cx ) ;
cx18_gpio_init ( cx ) ;
2009-02-21 05:52:13 +03:00
/* Initialize integrated A/V decoder early to set PLLs, just in case */
retval = cx18_av_probe ( cx ) ;
2009-02-16 08:23:25 +03:00
if ( retval ) {
CX18_ERR ( " Could not register A/V decoder subdevice \n " ) ;
goto free_map ;
}
2009-02-21 05:52:13 +03:00
cx18_call_hw ( cx , CX18_HW_418_AV , core , init , ( u32 ) CX18_AV_INIT_PLLS ) ;
2009-02-16 08:23:25 +03:00
2009-02-22 00:42:49 +03:00
/* Initialize GPIO Reset Controller to do chip resets during i2c init */
if ( cx - > card - > hw_all & CX18_HW_GPIO_RESET_CTRL ) {
if ( cx18_gpio_register ( cx , CX18_HW_GPIO_RESET_CTRL ) ! = 0 )
CX18_WARN ( " Could not register GPIO reset controller "
" subdevice; proceeding anyway. \n " ) ;
else
cx - > hw_flags | = CX18_HW_GPIO_RESET_CTRL ;
}
2008-04-29 03:24:33 +04:00
/* active i2c */
CX18_DEBUG_INFO ( " activating i2c... \n " ) ;
2008-10-18 17:20:25 +04:00
retval = init_cx18_i2c ( cx ) ;
if ( retval ) {
2008-04-29 03:24:33 +04:00
CX18_ERR ( " Could not initialize i2c \n " ) ;
goto free_map ;
}
if ( cx - > card - > hw_all & CX18_HW_TVEEPROM ) {
/* Based on the model number the cardtype may be changed.
The PCI IDs are not always reliable . */
cx18_process_eeprom ( cx ) ;
}
if ( cx - > card - > comment )
CX18_INFO ( " %s " , cx - > card - > comment ) ;
if ( cx - > card - > v4l2_capabilities = = 0 ) {
retval = - ENODEV ;
goto free_i2c ;
}
cx18_init_memory ( cx ) ;
2008-12-15 03:26:25 +03:00
cx18_init_scb ( cx ) ;
2008-04-29 03:24:33 +04:00
/* Register IRQ */
2009-01-11 03:54:39 +03:00
retval = request_irq ( cx - > pci_dev - > irq , cx18_irq_handler ,
2009-02-14 23:08:37 +03:00
IRQF_SHARED | IRQF_DISABLED ,
cx - > v4l2_dev . name , ( void * ) cx ) ;
2008-04-29 03:24:33 +04:00
if ( retval ) {
CX18_ERR ( " Failed to register irq %d \n " , retval ) ;
goto free_i2c ;
}
if ( cx - > std = = 0 )
cx - > std = V4L2_STD_NTSC_M ;
if ( cx - > options . tuner = = - 1 ) {
for ( i = 0 ; i < CX18_CARD_MAX_TUNERS ; i + + ) {
if ( ( cx - > std & cx - > card - > tuners [ i ] . std ) = = 0 )
continue ;
cx - > options . tuner = cx - > card - > tuners [ i ] . tuner ;
break ;
}
}
/* if no tuner was found, then pick the first tuner in the card list */
if ( cx - > options . tuner = = - 1 & & cx - > card - > tuners [ 0 ] . std ) {
cx - > std = cx - > card - > tuners [ 0 ] . std ;
2008-06-28 06:27:25 +04:00
if ( cx - > std & V4L2_STD_PAL )
cx - > std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H ;
else if ( cx - > std & V4L2_STD_NTSC )
cx - > std = V4L2_STD_NTSC_M ;
else if ( cx - > std & V4L2_STD_SECAM )
cx - > std = V4L2_STD_SECAM_L ;
2008-04-29 03:24:33 +04:00
cx - > options . tuner = cx - > card - > tuners [ 0 ] . tuner ;
}
if ( cx - > options . radio = = - 1 )
cx - > options . radio = ( cx - > card - > radio_input . audio_type ! = 0 ) ;
/* The card is now fully identified, continue with card-specific
initialization . */
cx18_init_struct2 ( cx ) ;
2009-02-21 05:52:13 +03:00
cx18_init_subdevs ( cx ) ;
2008-04-29 03:24:33 +04:00
if ( cx - > std & V4L2_STD_525_60 ) {
cx - > is_60hz = 1 ;
cx - > is_out_60hz = 1 ;
} else {
cx - > is_50hz = 1 ;
cx - > is_out_50hz = 1 ;
}
cx - > params . video_gop_size = cx - > is_60hz ? 15 : 12 ;
if ( cx - > options . radio > 0 )
cx - > v4l2_cap | = V4L2_CAP_RADIO ;
if ( cx - > options . tuner > - 1 ) {
struct tuner_setup setup ;
setup . addr = ADDR_UNSET ;
setup . type = cx - > options . tuner ;
setup . mode_mask = T_ANALOG_TV ; /* matches TV tuners */
setup . tuner_callback = ( setup . type = = TUNER_XC2028 ) ?
cx18_reset_tuner_gpio : NULL ;
2009-02-21 05:52:13 +03:00
cx18_call_all ( cx , tuner , s_type_addr , & setup ) ;
2008-04-29 03:24:33 +04:00
if ( setup . type = = TUNER_XC2028 ) {
static struct xc2028_ctrl ctrl = {
. fname = XC2028_DEFAULT_FIRMWARE ,
. max_len = 64 ,
} ;
struct v4l2_priv_tun_config cfg = {
. tuner = cx - > options . tuner ,
. priv = & ctrl ,
} ;
2009-02-21 05:52:13 +03:00
cx18_call_all ( cx , tuner , s_config , & cfg ) ;
2008-04-29 03:24:33 +04:00
}
}
/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
are not . */
cx - > tuner_std = cx - > std ;
2008-05-30 17:51:53 +04:00
retval = cx18_streams_setup ( cx ) ;
if ( retval ) {
CX18_ERR ( " Error %d setting up streams \n " , retval ) ;
goto free_irq ;
}
retval = cx18_streams_register ( cx ) ;
if ( retval ) {
CX18_ERR ( " Error %d registering devices \n " , retval ) ;
goto free_streams ;
}
2008-04-29 03:24:33 +04:00
2009-02-14 23:08:37 +03:00
CX18_INFO ( " Initialized card: %s \n " , cx - > card_name ) ;
2008-04-29 03:24:33 +04:00
return 0 ;
free_streams :
2008-05-01 17:31:12 +04:00
cx18_streams_cleanup ( cx , 1 ) ;
2008-04-29 03:24:33 +04:00
free_irq :
2009-01-11 03:54:39 +03:00
free_irq ( cx - > pci_dev - > irq , ( void * ) cx ) ;
2008-04-29 03:24:33 +04:00
free_i2c :
exit_cx18_i2c ( cx ) ;
free_map :
cx18_iounmap ( cx ) ;
free_mem :
release_mem_region ( cx - > base_addr , CX18_MEM_SIZE ) ;
free_workqueue :
2008-11-26 03:43:05 +03:00
destroy_workqueue ( cx - > work_queue ) ;
2008-04-29 03:24:33 +04:00
err :
if ( retval = = 0 )
retval = - ENODEV ;
CX18_ERR ( " Error %d on initialization \n " , retval ) ;
2009-02-14 23:08:37 +03:00
v4l2_device_unregister ( & cx - > v4l2_dev ) ;
kfree ( cx ) ;
2008-04-29 03:24:33 +04:00
return retval ;
}
int cx18_init_on_first_open ( struct cx18 * cx )
{
int video_input ;
int fw_retry_count = 3 ;
struct v4l2_frequency vf ;
2008-06-21 15:36:31 +04:00
struct cx18_open_id fh ;
fh . cx = cx ;
2008-04-29 03:24:33 +04:00
if ( test_bit ( CX18_F_I_FAILED , & cx - > i_flags ) )
return - ENXIO ;
if ( test_and_set_bit ( CX18_F_I_INITED , & cx - > i_flags ) )
return 0 ;
while ( - - fw_retry_count > 0 ) {
/* load firmware */
if ( cx18_firmware_init ( cx ) = = 0 )
break ;
if ( fw_retry_count > 1 )
CX18_WARN ( " Retry loading firmware \n " ) ;
}
if ( fw_retry_count = = 0 ) {
set_bit ( CX18_F_I_FAILED , & cx - > i_flags ) ;
return - ENXIO ;
}
set_bit ( CX18_F_I_LOADED_FW , & cx - > i_flags ) ;
2009-01-05 03:51:17 +03:00
/*
* Init the firmware twice to work around a silicon bug
* with the digital TS .
*
* The second firmware load requires us to normalize the APU state ,
* or the audio for the first analog capture will be badly incorrect .
*
* I can ' t seem to call APU_RESETAI and have it succeed without the
* APU capturing audio , so we start and stop it here to do the reset
*/
/* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
cx18_vapi ( cx , CX18_APU_START , 2 , CX18_APU_ENCODING_METHOD_MPEG | 0xb9 , 0 ) ;
cx18_vapi ( cx , CX18_APU_RESETAI , 0 ) ;
cx18_vapi ( cx , CX18_APU_STOP , 1 , CX18_APU_ENCODING_METHOD_MPEG ) ;
2008-04-29 03:24:33 +04:00
fw_retry_count = 3 ;
while ( - - fw_retry_count > 0 ) {
/* load firmware */
if ( cx18_firmware_init ( cx ) = = 0 )
break ;
if ( fw_retry_count > 1 )
CX18_WARN ( " Retry loading firmware \n " ) ;
}
if ( fw_retry_count = = 0 ) {
set_bit ( CX18_F_I_FAILED , & cx - > i_flags ) ;
return - ENXIO ;
}
2009-01-31 04:48:40 +03:00
/*
* The second firmware load requires us to normalize the APU state ,
* or the audio for the first analog capture will be badly incorrect .
*
* I can ' t seem to call APU_RESETAI and have it succeed without the
* APU capturing audio , so we start and stop it here to do the reset
*/
/* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
cx18_vapi ( cx , CX18_APU_START , 2 , CX18_APU_ENCODING_METHOD_MPEG | 0xb9 , 0 ) ;
cx18_vapi ( cx , CX18_APU_RESETAI , 0 ) ;
cx18_vapi ( cx , CX18_APU_STOP , 1 , CX18_APU_ENCODING_METHOD_MPEG ) ;
2009-02-16 08:23:25 +03:00
/* Init the A/V decoder, if it hasn't been already */
v4l2_subdev_call ( cx - > sd_av , core , init , ( u32 ) CX18_AV_INIT_NORMAL ) ;
2008-04-29 03:24:33 +04:00
vf . tuner = 0 ;
vf . type = V4L2_TUNER_ANALOG_TV ;
vf . frequency = 6400 ; /* the tuner 'baseline' frequency */
/* Set initial frequency. For PAL/SECAM broadcasts no
' default ' channel exists AFAIK . */
if ( cx - > std = = V4L2_STD_NTSC_M_JP )
vf . frequency = 1460 ; /* ch. 1 91250*16/1000 */
else if ( cx - > std & V4L2_STD_NTSC_M )
vf . frequency = 1076 ; /* ch. 4 67250*16/1000 */
video_input = cx - > active_input ;
cx - > active_input + + ; /* Force update of input */
2008-06-21 15:36:31 +04:00
cx18_s_input ( NULL , & fh , video_input ) ;
2008-04-29 03:24:33 +04:00
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place . */
cx - > std + + ; /* Force full standard initialization */
2008-06-21 15:36:31 +04:00
cx18_s_std ( NULL , & fh , & cx - > tuner_std ) ;
cx18_s_frequency ( NULL , & fh , & vf ) ;
2008-04-29 03:24:33 +04:00
return 0 ;
}
2008-11-16 23:15:01 +03:00
static void cx18_cancel_epu_work_orders ( struct cx18 * cx )
{
int i ;
for ( i = 0 ; i < CX18_MAX_EPU_WORK_ORDERS ; i + + )
cancel_work_sync ( & cx - > epu_work_order [ i ] . work ) ;
}
2008-04-29 03:24:33 +04:00
static void cx18_remove ( struct pci_dev * pci_dev )
{
2009-01-11 21:08:53 +03:00
struct v4l2_device * v4l2_dev = pci_get_drvdata ( pci_dev ) ;
2009-02-14 23:08:37 +03:00
struct cx18 * cx = to_cx18 ( v4l2_dev ) ;
2009-02-22 01:53:54 +03:00
int i ;
2008-04-29 03:24:33 +04:00
2009-02-14 23:08:37 +03:00
CX18_DEBUG_INFO ( " Removing Card \n " ) ;
2008-04-29 03:24:33 +04:00
/* Stop all captures */
CX18_DEBUG_INFO ( " Stopping all streams \n " ) ;
2008-05-25 18:21:27 +04:00
if ( atomic_read ( & cx - > tot_capturing ) > 0 )
2008-04-29 03:24:33 +04:00
cx18_stop_all_captures ( cx ) ;
/* Interrupts */
2008-08-30 23:03:44 +04:00
cx18_sw1_irq_disable ( cx , IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU ) ;
cx18_sw2_irq_disable ( cx , IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK ) ;
2008-04-29 03:24:33 +04:00
cx18_halt_firmware ( cx ) ;
2008-11-16 23:15:01 +03:00
cx18_cancel_epu_work_orders ( cx ) ;
2008-11-05 06:49:14 +03:00
2008-11-26 03:43:05 +03:00
destroy_workqueue ( cx - > work_queue ) ;
2008-05-01 17:31:12 +04:00
cx18_streams_cleanup ( cx , 1 ) ;
2008-04-29 03:24:33 +04:00
exit_cx18_i2c ( cx ) ;
2009-01-11 03:54:39 +03:00
free_irq ( cx - > pci_dev - > irq , ( void * ) cx ) ;
2008-04-29 03:24:33 +04:00
2008-05-12 21:48:26 +04:00
cx18_iounmap ( cx ) ;
2008-04-29 03:24:33 +04:00
release_mem_region ( cx - > base_addr , CX18_MEM_SIZE ) ;
2009-01-11 03:54:39 +03:00
pci_disable_device ( cx - > pci_dev ) ;
2009-02-22 01:53:54 +03:00
if ( cx - > vbi . sliced_mpeg_data [ 0 ] ! = NULL )
for ( i = 0 ; i < CX18_VBI_FRAMES ; i + + )
kfree ( cx - > vbi . sliced_mpeg_data [ i ] ) ;
2008-04-29 03:24:33 +04:00
2009-02-14 23:08:37 +03:00
CX18_INFO ( " Removed %s \n " , cx - > card_name ) ;
2009-01-11 21:08:53 +03:00
2009-02-14 23:08:37 +03:00
v4l2_device_unregister ( v4l2_dev ) ;
kfree ( cx ) ;
2008-04-29 03:24:33 +04:00
}
/* define a pci_driver for card detection */
static struct pci_driver cx18_pci_driver = {
. name = " cx18 " ,
. id_table = cx18_pci_tbl ,
. probe = cx18_probe ,
. remove = cx18_remove ,
} ;
static int module_start ( void )
{
printk ( KERN_INFO " cx18: Start initialization, version %s \n " , CX18_VERSION ) ;
/* Validate parameters */
if ( cx18_first_minor < 0 | | cx18_first_minor > = CX18_MAX_CARDS ) {
2008-10-04 15:36:54 +04:00
printk ( KERN_ERR " cx18: Exiting, cx18_first_minor must be between 0 and %d \n " ,
2008-04-29 03:24:33 +04:00
CX18_MAX_CARDS - 1 ) ;
return - 1 ;
}
if ( cx18_debug < 0 | | cx18_debug > 511 ) {
cx18_debug = 0 ;
printk ( KERN_INFO " cx18: Debug value must be >= 0 and <= 511! \n " ) ;
}
if ( pci_register_driver ( & cx18_pci_driver ) ) {
printk ( KERN_ERR " cx18: Error detecting PCI card \n " ) ;
return - ENODEV ;
}
printk ( KERN_INFO " cx18: End initialization \n " ) ;
return 0 ;
}
static void module_cleanup ( void )
{
pci_unregister_driver ( & cx18_pci_driver ) ;
}
module_init ( module_start ) ;
module_exit ( module_cleanup ) ;