2008-01-13 23:42:44 -03:00
/*
*
* Support for a cx23417 mpeg encoder via cx23885 host port .
*
* ( c ) 2004 Jelle Foks < jelle @ foks .8 m . com >
* ( c ) 2004 Gerd Knorr < kraxel @ bytesex . org >
2008-09-03 17:12:12 -03:00
* ( c ) 2008 Steven Toth < stoth @ linuxtv . org >
2008-01-13 23:42:44 -03:00
* - CX23885 / 7 / 8 support
*
* Includes parts from the ivtv driver ( http : //ivtv.sourceforge.net/),
*
* 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/moduleparam.h>
# include <linux/init.h>
# include <linux/fs.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/firmware.h>
# include <media/v4l2-common.h>
2008-07-20 08:12:02 -03:00
# include <media/v4l2-ioctl.h>
2008-01-13 23:42:44 -03:00
# include <media/cx2341x.h>
# include "cx23885.h"
# define CX23885_FIRM_IMAGE_SIZE 376836
# define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
static unsigned int mpegbufs = 32 ;
module_param ( mpegbufs , int , 0644 ) ;
MODULE_PARM_DESC ( mpegbufs , " number of mpeg buffers, range 2-32 " ) ;
static unsigned int mpeglines = 32 ;
module_param ( mpeglines , int , 0644 ) ;
MODULE_PARM_DESC ( mpeglines , " number of lines in an MPEG buffer, range 2-32 " ) ;
static unsigned int mpeglinesize = 512 ;
module_param ( mpeglinesize , int , 0644 ) ;
MODULE_PARM_DESC ( mpeglinesize ,
" number of bytes in each line of an MPEG buffer, range 512-1024 " ) ;
static unsigned int v4l_debug ;
module_param ( v4l_debug , int , 0644 ) ;
MODULE_PARM_DESC ( v4l_debug , " enable V4L debug messages " ) ;
# define dprintk(level, fmt, arg...)\
do { if ( v4l_debug > = level ) \
printk ( KERN_DEBUG " %s: " fmt , dev - > name , # # arg ) ; \
} while ( 0 )
static struct cx23885_tvnorm cx23885_tvnorms [ ] = {
{
. name = " NTSC-M " ,
. id = V4L2_STD_NTSC_M ,
} , {
. name = " NTSC-JP " ,
. id = V4L2_STD_NTSC_M_JP ,
} , {
. name = " PAL-BG " ,
. id = V4L2_STD_PAL_BG ,
} , {
. name = " PAL-DK " ,
. id = V4L2_STD_PAL_DK ,
} , {
. name = " PAL-I " ,
. id = V4L2_STD_PAL_I ,
} , {
. name = " PAL-M " ,
. id = V4L2_STD_PAL_M ,
} , {
. name = " PAL-N " ,
. id = V4L2_STD_PAL_N ,
} , {
. name = " PAL-Nc " ,
. id = V4L2_STD_PAL_Nc ,
} , {
. name = " PAL-60 " ,
. id = V4L2_STD_PAL_60 ,
} , {
. name = " SECAM-L " ,
. id = V4L2_STD_SECAM_L ,
} , {
. name = " SECAM-DK " ,
. id = V4L2_STD_SECAM_DK ,
}
} ;
/* ------------------------------------------------------------------ */
enum cx23885_capture_type {
CX23885_MPEG_CAPTURE ,
CX23885_RAW_CAPTURE ,
CX23885_RAW_PASSTHRU_CAPTURE
} ;
enum cx23885_capture_bits {
CX23885_RAW_BITS_NONE = 0x00 ,
CX23885_RAW_BITS_YUV_CAPTURE = 0x01 ,
CX23885_RAW_BITS_PCM_CAPTURE = 0x02 ,
CX23885_RAW_BITS_VBI_CAPTURE = 0x04 ,
CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08 ,
CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10
} ;
enum cx23885_capture_end {
CX23885_END_AT_GOP , /* stop at the end of gop, generate irq */
CX23885_END_NOW , /* stop immediately, no irq */
} ;
enum cx23885_framerate {
CX23885_FRAMERATE_NTSC_30 , /* NTSC: 30fps */
CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */
} ;
enum cx23885_stream_port {
CX23885_OUTPUT_PORT_MEMORY ,
CX23885_OUTPUT_PORT_STREAMING ,
CX23885_OUTPUT_PORT_SERIAL
} ;
enum cx23885_data_xfer_status {
CX23885_MORE_BUFFERS_FOLLOW ,
CX23885_LAST_BUFFER ,
} ;
enum cx23885_picture_mask {
CX23885_PICTURE_MASK_NONE ,
CX23885_PICTURE_MASK_I_FRAMES ,
CX23885_PICTURE_MASK_I_P_FRAMES = 0x3 ,
CX23885_PICTURE_MASK_ALL_FRAMES = 0x7 ,
} ;
enum cx23885_vbi_mode_bits {
CX23885_VBI_BITS_SLICED ,
CX23885_VBI_BITS_RAW ,
} ;
enum cx23885_vbi_insertion_bits {
CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA ,
CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 < < 1 ,
CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 < < 1 ,
CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 < < 1 ,
CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 < < 1 ,
} ;
enum cx23885_dma_unit {
CX23885_DMA_BYTES ,
CX23885_DMA_FRAMES ,
} ;
enum cx23885_dma_transfer_status_bits {
CX23885_DMA_TRANSFER_BITS_DONE = 0x01 ,
CX23885_DMA_TRANSFER_BITS_ERROR = 0x04 ,
CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10 ,
} ;
enum cx23885_pause {
CX23885_PAUSE_ENCODING ,
CX23885_RESUME_ENCODING ,
} ;
enum cx23885_copyright {
CX23885_COPYRIGHT_OFF ,
CX23885_COPYRIGHT_ON ,
} ;
enum cx23885_notification_type {
CX23885_NOTIFICATION_REFRESH ,
} ;
enum cx23885_notification_status {
CX23885_NOTIFICATION_OFF ,
CX23885_NOTIFICATION_ON ,
} ;
enum cx23885_notification_mailbox {
CX23885_NOTIFICATION_NO_MAILBOX = - 1 ,
} ;
enum cx23885_field1_lines {
CX23885_FIELD1_SAA7114 = 0x00EF , /* 239 */
CX23885_FIELD1_SAA7115 = 0x00F0 , /* 240 */
CX23885_FIELD1_MICRONAS = 0x0105 , /* 261 */
} ;
enum cx23885_field2_lines {
CX23885_FIELD2_SAA7114 = 0x00EF , /* 239 */
CX23885_FIELD2_SAA7115 = 0x00F0 , /* 240 */
CX23885_FIELD2_MICRONAS = 0x0106 , /* 262 */
} ;
enum cx23885_custom_data_type {
CX23885_CUSTOM_EXTENSION_USR_DATA ,
CX23885_CUSTOM_PRIVATE_PACKET ,
} ;
enum cx23885_mute {
CX23885_UNMUTE ,
CX23885_MUTE ,
} ;
enum cx23885_mute_video_mask {
CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00 ,
CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000 ,
CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000 ,
} ;
enum cx23885_mute_video_shift {
CX23885_MUTE_VIDEO_V_SHIFT = 8 ,
CX23885_MUTE_VIDEO_U_SHIFT = 16 ,
CX23885_MUTE_VIDEO_Y_SHIFT = 24 ,
} ;
/* defines below are from ivtv-driver.h */
# define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
/* Firmware API commands */
# define IVTV_API_STD_TIMEOUT 500
/* Registers */
/* IVTV_REG_OFFSET */
# define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
# define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
# define IVTV_REG_SPU (0x9050)
# define IVTV_REG_HW_BLOCKS (0x9054)
# define IVTV_REG_VPU (0x9058)
# define IVTV_REG_APU (0xA064)
/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
bits 31 - 16
+ - - - - - - - - - - - +
| Reserved |
+ - - - - - - - - - - - +
bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
+ - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
| MIWR # | MIRD # | MICS # | MIRDY # | MIADDR3 | MIADDR2 | MIADDR1 | MIADDR0 |
+ - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
+ - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
| MIDATA7 | MIDATA6 | MIDATA5 | MIDATA4 | MIDATA3 | MIDATA2 | MIDATA1 | MIDATA0 |
+ - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
* * */
# define MC417_MIWR 0x8000
# define MC417_MIRD 0x4000
# define MC417_MICS 0x2000
# define MC417_MIRDY 0x1000
# define MC417_MIADDR 0x0F00
# define MC417_MIDATA 0x00FF
/* MIADDR* nibble definitions */
# define MCI_MEMORY_DATA_BYTE0 0x000
# define MCI_MEMORY_DATA_BYTE1 0x100
# define MCI_MEMORY_DATA_BYTE2 0x200
# define MCI_MEMORY_DATA_BYTE3 0x300
# define MCI_MEMORY_ADDRESS_BYTE2 0x400
# define MCI_MEMORY_ADDRESS_BYTE1 0x500
# define MCI_MEMORY_ADDRESS_BYTE0 0x600
# define MCI_REGISTER_DATA_BYTE0 0x800
# define MCI_REGISTER_DATA_BYTE1 0x900
# define MCI_REGISTER_DATA_BYTE2 0xA00
# define MCI_REGISTER_DATA_BYTE3 0xB00
# define MCI_REGISTER_ADDRESS_BYTE0 0xC00
# define MCI_REGISTER_ADDRESS_BYTE1 0xD00
# define MCI_REGISTER_MODE 0xE00
/* Read and write modes */
# define MCI_MODE_REGISTER_READ 0
# define MCI_MODE_REGISTER_WRITE 1
# define MCI_MODE_MEMORY_READ 0
# define MCI_MODE_MEMORY_WRITE 0x40
/*** Bit definitions for MC417_CTL register ****
bits 31 - 6 bits 5 - 4 bit 3 bits 2 - 1 Bit 0
+ - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - + - - - - - - - - - - - - - - + - - - - - - - - - - - - +
| Reserved | MC417_SPD_CTL | Reserved | MC417_GPIO_SEL | UART_GPIO_EN |
+ - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - + - - - - - - - - - - - - - - + - - - - - - - - - - - - +
* * */
# define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
# define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
# define MC417_UART_GPIO_EN 0x00000001
/* Values for speed control */
# define MC417_SPD_CTL_SLOW 0x1
# define MC417_SPD_CTL_MEDIUM 0x0
# define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
/* Values for GPIO select */
# define MC417_GPIO_SEL_GPIO3 0x3
# define MC417_GPIO_SEL_GPIO2 0x2
# define MC417_GPIO_SEL_GPIO1 0x1
# define MC417_GPIO_SEL_GPIO0 0x0
void cx23885_mc417_init ( struct cx23885_dev * dev )
{
u32 regval ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
/* Configure MC417_CTL register to defaults. */
regval = MC417_SPD_CTL ( MC417_SPD_CTL_FAST ) |
MC417_GPIO_SEL ( MC417_GPIO_SEL_GPIO3 ) |
MC417_UART_GPIO_EN ;
cx_write ( MC417_CTL , regval ) ;
/* Configure MC417_OEN to defaults. */
regval = MC417_MIRDY ;
cx_write ( MC417_OEN , regval ) ;
/* Configure MC417_RWD to defaults. */
regval = MC417_MIWR | MC417_MIRD | MC417_MICS ;
cx_write ( MC417_RWD , regval ) ;
}
static int mc417_wait_ready ( struct cx23885_dev * dev )
{
u32 mi_ready ;
unsigned long timeout = jiffies + msecs_to_jiffies ( 1 ) ;
for ( ; ; ) {
mi_ready = cx_read ( MC417_RWD ) & MC417_MIRDY ;
if ( mi_ready ! = 0 )
return 0 ;
if ( time_after ( jiffies , timeout ) )
return - 1 ;
udelay ( 1 ) ;
}
}
static int mc417_register_write ( struct cx23885_dev * dev , u16 address , u32 value )
{
u32 regval ;
/* Enable MC417 GPIO outputs except for MC417_MIRDY,
* which is an input .
*/
cx_write ( MC417_OEN , MC417_MIRDY ) ;
/* Write data byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
( value & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
/* Transition CS/WR to effect write transaction across bus. */
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write data byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
( ( value > > 8 ) & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write data byte 2 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
( ( value > > 16 ) & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write data byte 3 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
( ( value > > 24 ) & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
( address & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
( ( address > > 8 ) & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Indicate that this is a write. */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
MCI_MODE_REGISTER_WRITE ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Wait for the trans to complete (MC417_MIRDY asserted). */
return mc417_wait_ready ( dev ) ;
}
static int mc417_register_read ( struct cx23885_dev * dev , u16 address , u32 * value )
{
int retval ;
u32 regval ;
u32 tempval ;
u32 dataval ;
/* Enable MC417 GPIO outputs except for MC417_MIRDY,
* which is an input .
*/
cx_write ( MC417_OEN , MC417_MIRDY ) ;
/* Write address byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
( ( address & 0x00FF ) ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
( ( address > > 8 ) & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Indicate that this is a register read. */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
MCI_MODE_REGISTER_READ ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Wait for the trans to complete (MC417_MIRDY asserted). */
retval = mc417_wait_ready ( dev ) ;
/* switch the DAT0-7 GPIO[10:3] to input mode */
cx_write ( MC417_OEN , MC417_MIRDY | MC417_MIDATA ) ;
/* Read data byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 ;
cx_write ( MC417_RWD , regval ) ;
/* Transition RD to effect read transaction across bus.
* Transtion 0x5000 - > 0x9000 correct ( RD / RDY - > WR / RDY ) ?
* Should it be 0x9000 - > 0xF000 ( also why is RDY being set , its
* input only . . . )
*/
regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 ;
cx_write ( MC417_RWD , regval ) ;
/* Collect byte */
tempval = cx_read ( MC417_RWD ) ;
dataval = tempval & 0x000000FF ;
/* Bring CS and RD high. */
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
/* Read data byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 ;
cx_write ( MC417_RWD , regval ) ;
regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 ;
cx_write ( MC417_RWD , regval ) ;
tempval = cx_read ( MC417_RWD ) ;
dataval | = ( ( tempval & 0x000000FF ) < < 8 ) ;
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
/* Read data byte 2 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 ;
cx_write ( MC417_RWD , regval ) ;
regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 ;
cx_write ( MC417_RWD , regval ) ;
tempval = cx_read ( MC417_RWD ) ;
dataval | = ( ( tempval & 0x000000FF ) < < 16 ) ;
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
/* Read data byte 3 */
regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 ;
cx_write ( MC417_RWD , regval ) ;
regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 ;
cx_write ( MC417_RWD , regval ) ;
tempval = cx_read ( MC417_RWD ) ;
dataval | = ( ( tempval & 0x000000FF ) < < 24 ) ;
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
* value = dataval ;
return retval ;
}
int mc417_memory_write ( struct cx23885_dev * dev , u32 address , u32 value )
{
u32 regval ;
/* Enable MC417 GPIO outputs except for MC417_MIRDY,
* which is an input .
*/
cx_write ( MC417_OEN , MC417_MIRDY ) ;
/* Write data byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
( value & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
/* Transition CS/WR to effect write transaction across bus. */
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write data byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
( ( value > > 8 ) & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write data byte 2 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
( ( value > > 16 ) & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write data byte 3 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
( ( value > > 24 ) & 0x000000FF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 2 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
MCI_MODE_MEMORY_WRITE | ( ( address > > 16 ) & 0x3F ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
( ( address > > 8 ) & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
( address & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Wait for the trans to complete (MC417_MIRDY asserted). */
return mc417_wait_ready ( dev ) ;
}
int mc417_memory_read ( struct cx23885_dev * dev , u32 address , u32 * value )
{
int retval ;
u32 regval ;
u32 tempval ;
u32 dataval ;
/* Enable MC417 GPIO outputs except for MC417_MIRDY,
* which is an input .
*/
cx_write ( MC417_OEN , MC417_MIRDY ) ;
/* Write address byte 2 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
MCI_MODE_MEMORY_READ | ( ( address > > 16 ) & 0x3F ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
( ( address > > 8 ) & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Write address byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
( address & 0xFF ) ;
cx_write ( MC417_RWD , regval ) ;
regval | = MC417_MICS | MC417_MIWR ;
cx_write ( MC417_RWD , regval ) ;
/* Wait for the trans to complete (MC417_MIRDY asserted). */
retval = mc417_wait_ready ( dev ) ;
/* switch the DAT0-7 GPIO[10:3] to input mode */
cx_write ( MC417_OEN , MC417_MIRDY | MC417_MIDATA ) ;
/* Read data byte 3 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 ;
cx_write ( MC417_RWD , regval ) ;
/* Transition RD to effect read transaction across bus. */
regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 ;
cx_write ( MC417_RWD , regval ) ;
/* Collect byte */
tempval = cx_read ( MC417_RWD ) ;
dataval = ( ( tempval & 0x000000FF ) < < 24 ) ;
/* Bring CS and RD high. */
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
/* Read data byte 2 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 ;
cx_write ( MC417_RWD , regval ) ;
regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 ;
cx_write ( MC417_RWD , regval ) ;
tempval = cx_read ( MC417_RWD ) ;
dataval | = ( ( tempval & 0x000000FF ) < < 16 ) ;
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
/* Read data byte 1 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 ;
cx_write ( MC417_RWD , regval ) ;
regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 ;
cx_write ( MC417_RWD , regval ) ;
tempval = cx_read ( MC417_RWD ) ;
dataval | = ( ( tempval & 0x000000FF ) < < 8 ) ;
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
/* Read data byte 0 */
regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 ;
cx_write ( MC417_RWD , regval ) ;
regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 ;
cx_write ( MC417_RWD , regval ) ;
tempval = cx_read ( MC417_RWD ) ;
dataval | = ( tempval & 0x000000FF ) ;
regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY ;
cx_write ( MC417_RWD , regval ) ;
* value = dataval ;
return retval ;
}
/* ------------------------------------------------------------------ */
/* MPEG encoder API */
2008-09-04 03:33:43 -03:00
static char * cmd_to_str ( int cmd )
2008-01-13 23:42:44 -03:00
{
switch ( cmd ) {
case CX2341X_ENC_PING_FW :
return " PING_FW " ;
case CX2341X_ENC_START_CAPTURE :
return " START_CAPTURE " ;
case CX2341X_ENC_STOP_CAPTURE :
return " STOP_CAPTURE " ;
case CX2341X_ENC_SET_AUDIO_ID :
return " SET_AUDIO_ID " ;
case CX2341X_ENC_SET_VIDEO_ID :
return " SET_VIDEO_ID " ;
case CX2341X_ENC_SET_PCR_ID :
return " SET_PCR_PID " ;
case CX2341X_ENC_SET_FRAME_RATE :
return " SET_FRAME_RATE " ;
case CX2341X_ENC_SET_FRAME_SIZE :
return " SET_FRAME_SIZE " ;
case CX2341X_ENC_SET_BIT_RATE :
return " SET_BIT_RATE " ;
case CX2341X_ENC_SET_GOP_PROPERTIES :
return " SET_GOP_PROPERTIES " ;
case CX2341X_ENC_SET_ASPECT_RATIO :
return " SET_ASPECT_RATIO " ;
case CX2341X_ENC_SET_DNR_FILTER_MODE :
return " SET_DNR_FILTER_PROPS " ;
case CX2341X_ENC_SET_DNR_FILTER_PROPS :
return " SET_DNR_FILTER_PROPS " ;
case CX2341X_ENC_SET_CORING_LEVELS :
return " SET_CORING_LEVELS " ;
case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE :
return " SET_SPATIAL_FILTER_TYPE " ;
case CX2341X_ENC_SET_VBI_LINE :
return " SET_VBI_LINE " ;
case CX2341X_ENC_SET_STREAM_TYPE :
return " SET_STREAM_TYPE " ;
case CX2341X_ENC_SET_OUTPUT_PORT :
return " SET_OUTPUT_PORT " ;
case CX2341X_ENC_SET_AUDIO_PROPERTIES :
return " SET_AUDIO_PROPERTIES " ;
case CX2341X_ENC_HALT_FW :
return " HALT_FW " ;
case CX2341X_ENC_GET_VERSION :
return " GET_VERSION " ;
case CX2341X_ENC_SET_GOP_CLOSURE :
return " SET_GOP_CLOSURE " ;
case CX2341X_ENC_GET_SEQ_END :
return " GET_SEQ_END " ;
case CX2341X_ENC_SET_PGM_INDEX_INFO :
return " SET_PGM_INDEX_INFO " ;
case CX2341X_ENC_SET_VBI_CONFIG :
return " SET_VBI_CONFIG " ;
case CX2341X_ENC_SET_DMA_BLOCK_SIZE :
return " SET_DMA_BLOCK_SIZE " ;
case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10 :
return " GET_PREV_DMA_INFO_MB_10 " ;
case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9 :
return " GET_PREV_DMA_INFO_MB_9 " ;
case CX2341X_ENC_SCHED_DMA_TO_HOST :
return " SCHED_DMA_TO_HOST " ;
case CX2341X_ENC_INITIALIZE_INPUT :
return " INITIALIZE_INPUT " ;
case CX2341X_ENC_SET_FRAME_DROP_RATE :
return " SET_FRAME_DROP_RATE " ;
case CX2341X_ENC_PAUSE_ENCODER :
return " PAUSE_ENCODER " ;
case CX2341X_ENC_REFRESH_INPUT :
return " REFRESH_INPUT " ;
case CX2341X_ENC_SET_COPYRIGHT :
return " SET_COPYRIGHT " ;
case CX2341X_ENC_SET_EVENT_NOTIFICATION :
return " SET_EVENT_NOTIFICATION " ;
case CX2341X_ENC_SET_NUM_VSYNC_LINES :
return " SET_NUM_VSYNC_LINES " ;
case CX2341X_ENC_SET_PLACEHOLDER :
return " SET_PLACEHOLDER " ;
case CX2341X_ENC_MUTE_VIDEO :
return " MUTE_VIDEO " ;
case CX2341X_ENC_MUTE_AUDIO :
return " MUTE_AUDIO " ;
case CX2341X_ENC_MISC :
return " MISC " ;
default :
return " UNKNOWN " ;
}
}
static int cx23885_mbox_func ( void * priv ,
u32 command ,
int in ,
int out ,
u32 data [ CX2341X_MBOX_MAX_DATA ] )
{
struct cx23885_dev * dev = priv ;
unsigned long timeout ;
u32 value , flag , retval = 0 ;
int i ;
dprintk ( 3 , " %s: command(0x%X) = %s \n " , __func__ , command ,
cmd_to_str ( command ) ) ;
/* this may not be 100% safe if we can't read any memory location
without side effects */
mc417_memory_read ( dev , dev - > cx23417_mailbox - 4 , & value ) ;
if ( value ! = 0x12345678 ) {
printk ( KERN_ERR
" Firmware and/or mailbox pointer not initialized "
" or corrupted, signature = 0x%x, cmd = %s \n " , value ,
cmd_to_str ( command ) ) ;
return - 1 ;
}
/* This read looks at 32 bits, but flag is only 8 bits.
* Seems we also bail if CMD or TIMEOUT bytes are set ? ? ?
*/
mc417_memory_read ( dev , dev - > cx23417_mailbox , & flag ) ;
if ( flag ) {
printk ( KERN_ERR " ERROR: Mailbox appears to be in use "
" (%x), cmd = %s \n " , flag , cmd_to_str ( command ) ) ;
return - 1 ;
}
flag | = 1 ; /* tell 'em we're working on it */
mc417_memory_write ( dev , dev - > cx23417_mailbox , flag ) ;
/* write command + args + fill remaining with zeros */
/* command code */
mc417_memory_write ( dev , dev - > cx23417_mailbox + 1 , command ) ;
mc417_memory_write ( dev , dev - > cx23417_mailbox + 3 ,
IVTV_API_STD_TIMEOUT ) ; /* timeout */
for ( i = 0 ; i < in ; i + + ) {
mc417_memory_write ( dev , dev - > cx23417_mailbox + 4 + i , data [ i ] ) ;
dprintk ( 3 , " API Input %d = %d \n " , i , data [ i ] ) ;
}
for ( ; i < CX2341X_MBOX_MAX_DATA ; i + + )
mc417_memory_write ( dev , dev - > cx23417_mailbox + 4 + i , 0 ) ;
flag | = 3 ; /* tell 'em we're done writing */
mc417_memory_write ( dev , dev - > cx23417_mailbox , flag ) ;
/* wait for firmware to handle the API command */
timeout = jiffies + msecs_to_jiffies ( 10 ) ;
for ( ; ; ) {
mc417_memory_read ( dev , dev - > cx23417_mailbox , & flag ) ;
if ( 0 ! = ( flag & 4 ) )
break ;
if ( time_after ( jiffies , timeout ) ) {
printk ( KERN_ERR " ERROR: API Mailbox timeout \n " ) ;
return - 1 ;
}
udelay ( 10 ) ;
}
/* read output values */
for ( i = 0 ; i < out ; i + + ) {
mc417_memory_read ( dev , dev - > cx23417_mailbox + 4 + i , data + i ) ;
dprintk ( 3 , " API Output %d = %d \n " , i , data [ i ] ) ;
}
mc417_memory_read ( dev , dev - > cx23417_mailbox + 2 , & retval ) ;
dprintk ( 3 , " API result = %d \n " , retval ) ;
flag = 0 ;
mc417_memory_write ( dev , dev - > cx23417_mailbox , flag ) ;
return retval ;
}
/* We don't need to call the API often, so using just one
* mailbox will probably suffice
*/
static int cx23885_api_cmd ( struct cx23885_dev * dev ,
u32 command ,
u32 inputcnt ,
u32 outputcnt ,
. . . )
{
u32 data [ CX2341X_MBOX_MAX_DATA ] ;
va_list vargs ;
int i , err ;
dprintk ( 3 , " %s() cmds = 0x%08x \n " , __func__ , command ) ;
va_start ( vargs , outputcnt ) ;
for ( i = 0 ; i < inputcnt ; i + + )
data [ i ] = va_arg ( vargs , int ) ;
err = cx23885_mbox_func ( dev , command , inputcnt , outputcnt , data ) ;
for ( i = 0 ; i < outputcnt ; i + + ) {
int * vptr = va_arg ( vargs , int * ) ;
* vptr = data [ i ] ;
}
va_end ( vargs ) ;
return err ;
}
static int cx23885_find_mailbox ( struct cx23885_dev * dev )
{
u32 signature [ 4 ] = {
0x12345678 , 0x34567812 , 0x56781234 , 0x78123456
} ;
int signaturecnt = 0 ;
u32 value ;
int i ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
for ( i = 0 ; i < CX23885_FIRM_IMAGE_SIZE ; i + + ) {
mc417_memory_read ( dev , i , & value ) ;
if ( value = = signature [ signaturecnt ] )
signaturecnt + + ;
else
signaturecnt = 0 ;
if ( 4 = = signaturecnt ) {
dprintk ( 1 , " Mailbox signature found at 0x%x \n " , i + 1 ) ;
return i + 1 ;
}
}
printk ( KERN_ERR " Mailbox signature values not found! \n " ) ;
return - 1 ;
}
static int cx23885_load_firmware ( struct cx23885_dev * dev )
{
static const unsigned char magic [ 8 ] = {
0xa7 , 0x0d , 0x00 , 0x00 , 0x66 , 0xbb , 0x55 , 0xaa
} ;
const struct firmware * firmware ;
int i , retval = 0 ;
u32 value = 0 ;
u32 gpio_output = 0 ;
u32 checksum = 0 ;
u32 * dataptr ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
/* Save GPIO settings before reset of APU */
retval | = mc417_memory_read ( dev , 0x9020 , & gpio_output ) ;
retval | = mc417_memory_read ( dev , 0x900C , & value ) ;
retval = mc417_register_write ( dev ,
IVTV_REG_VPU , 0xFFFFFFED ) ;
retval | = mc417_register_write ( dev ,
IVTV_REG_HW_BLOCKS , IVTV_CMD_HW_BLOCKS_RST ) ;
retval | = mc417_register_write ( dev ,
IVTV_REG_ENC_SDRAM_REFRESH , 0x80000800 ) ;
retval | = mc417_register_write ( dev ,
IVTV_REG_ENC_SDRAM_PRECHARGE , 0x1A ) ;
retval | = mc417_register_write ( dev ,
IVTV_REG_APU , 0 ) ;
if ( retval ! = 0 ) {
printk ( KERN_ERR " %s: Error with mc417_register_write \n " ,
__func__ ) ;
return - 1 ;
}
retval = request_firmware ( & firmware , CX23885_FIRM_IMAGE_NAME ,
& dev - > pci - > dev ) ;
if ( retval ! = 0 ) {
printk ( KERN_ERR
" ERROR: Hotplug firmware request failed (%s). \n " ,
CX2341X_FIRM_ENC_FILENAME ) ;
printk ( KERN_ERR " Please fix your hotplug setup, the board will "
" not work without firmware loaded! \n " ) ;
return - 1 ;
}
if ( firmware - > size ! = CX23885_FIRM_IMAGE_SIZE ) {
printk ( KERN_ERR " ERROR: Firmware size mismatch "
" (have %zd, expected %d) \n " ,
firmware - > size , CX23885_FIRM_IMAGE_SIZE ) ;
release_firmware ( firmware ) ;
return - 1 ;
}
if ( 0 ! = memcmp ( firmware - > data , magic , 8 ) ) {
printk ( KERN_ERR
" ERROR: Firmware magic mismatch, wrong file? \n " ) ;
release_firmware ( firmware ) ;
return - 1 ;
}
/* transfer to the chip */
dprintk ( 2 , " Loading firmware ... \n " ) ;
dataptr = ( u32 * ) firmware - > data ;
for ( i = 0 ; i < ( firmware - > size > > 2 ) ; i + + ) {
value = * dataptr ;
checksum + = ~ value ;
if ( mc417_memory_write ( dev , i , value ) ! = 0 ) {
printk ( KERN_ERR " ERROR: Loading firmware failed! \n " ) ;
release_firmware ( firmware ) ;
return - 1 ;
}
dataptr + + ;
}
/* read back to verify with the checksum */
dprintk ( 1 , " Verifying firmware ... \n " ) ;
for ( i - - ; i > = 0 ; i - - ) {
if ( mc417_memory_read ( dev , i , & value ) ! = 0 ) {
printk ( KERN_ERR " ERROR: Reading firmware failed! \n " ) ;
release_firmware ( firmware ) ;
return - 1 ;
}
checksum - = ~ value ;
}
if ( checksum ) {
printk ( KERN_ERR
" ERROR: Firmware load failed (checksum mismatch). \n " ) ;
release_firmware ( firmware ) ;
return - 1 ;
}
release_firmware ( firmware ) ;
dprintk ( 1 , " Firmware upload successful. \n " ) ;
retval | = mc417_register_write ( dev , IVTV_REG_HW_BLOCKS ,
IVTV_CMD_HW_BLOCKS_RST ) ;
/* Restore GPIO settings, make sure EIO14 is enabled as an output. */
dprintk ( 2 , " %s: GPIO output EIO 0-15 was = 0x%x \n " ,
__func__ , gpio_output ) ;
/* Power-up seems to have GPIOs AFU. This was causing digital side
* to fail at power - up . Seems GPIOs should be set to 0x10ff0411 at
* power - up .
* gpio_output | = ( 1 < < 14 ) ;
*/
/* Note: GPIO14 is specific to the HVR1800 here */
gpio_output = 0x10ff0411 | ( 1 < < 14 ) ;
retval | = mc417_register_write ( dev , 0x9020 , gpio_output | ( 1 < < 14 ) ) ;
dprintk ( 2 , " %s: GPIO output EIO 0-15 now = 0x%x \n " ,
__func__ , gpio_output ) ;
dprintk ( 1 , " %s: GPIO value EIO 0-15 was = 0x%x \n " ,
__func__ , value ) ;
value | = ( 1 < < 14 ) ;
dprintk ( 1 , " %s: GPIO value EIO 0-15 now = 0x%x \n " ,
__func__ , value ) ;
retval | = mc417_register_write ( dev , 0x900C , value ) ;
retval | = mc417_register_read ( dev , IVTV_REG_VPU , & value ) ;
retval | = mc417_register_write ( dev , IVTV_REG_VPU , value & 0xFFFFFFE8 ) ;
if ( retval < 0 )
printk ( KERN_ERR " %s: Error with mc417_register_write \n " ,
__func__ ) ;
return 0 ;
}
void cx23885_417_check_encoder ( struct cx23885_dev * dev )
{
u32 status , seq ;
status = seq = 0 ;
cx23885_api_cmd ( dev , CX2341X_ENC_GET_SEQ_END , 0 , 2 , & status , & seq ) ;
dprintk ( 1 , " %s() status = %d, seq = %d \n " , __func__ , status , seq ) ;
}
static void cx23885_codec_settings ( struct cx23885_dev * dev )
{
dprintk ( 1 , " %s() \n " , __func__ ) ;
/* assign frame size */
cx23885_api_cmd ( dev , CX2341X_ENC_SET_FRAME_SIZE , 2 , 0 ,
dev - > ts1 . height , dev - > ts1 . width ) ;
dev - > mpeg_params . width = dev - > ts1 . width ;
dev - > mpeg_params . height = dev - > ts1 . height ;
dev - > mpeg_params . is_50hz =
( dev - > encodernorm . id & V4L2_STD_625_50 ) ! = 0 ;
cx2341x_update ( dev , cx23885_mbox_func , NULL , & dev - > mpeg_params ) ;
cx23885_api_cmd ( dev , CX2341X_ENC_MISC , 2 , 0 , 3 , 1 ) ;
cx23885_api_cmd ( dev , CX2341X_ENC_MISC , 2 , 0 , 4 , 1 ) ;
}
static int cx23885_initialize_codec ( struct cx23885_dev * dev )
{
int version ;
int retval ;
u32 i , data [ 7 ] ;
dprintk ( 1 , " %s() \n " , __func__ ) ;
retval = cx23885_api_cmd ( dev , CX2341X_ENC_PING_FW , 0 , 0 ) ; /* ping */
if ( retval < 0 ) {
dprintk ( 2 , " %s() PING OK \n " , __func__ ) ;
retval = cx23885_load_firmware ( dev ) ;
if ( retval < 0 ) {
printk ( KERN_ERR " %s() f/w load failed \n " , __func__ ) ;
return retval ;
}
dev - > cx23417_mailbox = cx23885_find_mailbox ( dev ) ;
if ( dev - > cx23417_mailbox < 0 ) {
printk ( KERN_ERR " %s() mailbox < 0, error \n " ,
__func__ ) ;
return - 1 ;
}
retval = cx23885_api_cmd ( dev , CX2341X_ENC_PING_FW , 0 , 0 ) ;
if ( retval < 0 ) {
printk ( KERN_ERR
" ERROR: cx23417 firmware ping failed! \n " ) ;
return - 1 ;
}
retval = cx23885_api_cmd ( dev , CX2341X_ENC_GET_VERSION , 0 , 1 ,
& version ) ;
if ( retval < 0 ) {
printk ( KERN_ERR " ERROR: cx23417 firmware get encoder : "
" version failed! \n " ) ;
return - 1 ;
}
dprintk ( 1 , " cx23417 firmware version is 0x%08x \n " , version ) ;
msleep ( 200 ) ;
}
cx23885_codec_settings ( dev ) ;
msleep ( 60 ) ;
cx23885_api_cmd ( dev , CX2341X_ENC_SET_NUM_VSYNC_LINES , 2 , 0 ,
CX23885_FIELD1_SAA7115 , CX23885_FIELD2_SAA7115 ) ;
cx23885_api_cmd ( dev , CX2341X_ENC_SET_PLACEHOLDER , 12 , 0 ,
CX23885_CUSTOM_EXTENSION_USR_DATA , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 ) ;
/* Setup to capture VBI */
data [ 0 ] = 0x0001BD00 ;
data [ 1 ] = 1 ; /* frames per interrupt */
data [ 2 ] = 4 ; /* total bufs */
data [ 3 ] = 0x91559155 ; /* start codes */
data [ 4 ] = 0x206080C0 ; /* stop codes */
data [ 5 ] = 6 ; /* lines */
data [ 6 ] = 64 ; /* BPL */
cx23885_api_cmd ( dev , CX2341X_ENC_SET_VBI_CONFIG , 7 , 0 , data [ 0 ] , data [ 1 ] ,
data [ 2 ] , data [ 3 ] , data [ 4 ] , data [ 5 ] , data [ 6 ] ) ;
for ( i = 2 ; i < = 24 ; i + + ) {
int valid ;
valid = ( ( i > = 19 ) & & ( i < = 21 ) ) ;
cx23885_api_cmd ( dev , CX2341X_ENC_SET_VBI_LINE , 5 , 0 , i ,
valid , 0 , 0 , 0 ) ;
cx23885_api_cmd ( dev , CX2341X_ENC_SET_VBI_LINE , 5 , 0 ,
i | 0x80000000 , valid , 0 , 0 , 0 ) ;
}
cx23885_api_cmd ( dev , CX2341X_ENC_MUTE_AUDIO , 1 , 0 , CX23885_UNMUTE ) ;
msleep ( 60 ) ;
/* initialize the video input */
cx23885_api_cmd ( dev , CX2341X_ENC_INITIALIZE_INPUT , 0 , 0 ) ;
msleep ( 60 ) ;
/* Enable VIP style pixel invalidation so we work with scaled mode */
mc417_memory_write ( dev , 2120 , 0x00000080 ) ;
/* start capturing to the host interface */
cx23885_api_cmd ( dev , CX2341X_ENC_START_CAPTURE , 2 , 0 ,
CX23885_MPEG_CAPTURE , CX23885_RAW_BITS_NONE ) ;
msleep ( 10 ) ;
return 0 ;
}
/* ------------------------------------------------------------------ */
static int bb_buf_setup ( struct videobuf_queue * q ,
unsigned int * count , unsigned int * size )
{
struct cx23885_fh * fh = q - > priv_data ;
fh - > dev - > ts1 . ts_packet_size = mpeglinesize ;
fh - > dev - > ts1 . ts_packet_count = mpeglines ;
* size = fh - > dev - > ts1 . ts_packet_size * fh - > dev - > ts1 . ts_packet_count ;
* count = mpegbufs ;
return 0 ;
}
static int bb_buf_prepare ( struct videobuf_queue * q ,
struct videobuf_buffer * vb , enum v4l2_field field )
{
struct cx23885_fh * fh = q - > priv_data ;
return cx23885_buf_prepare ( q , & fh - > dev - > ts1 ,
( struct cx23885_buffer * ) vb ,
field ) ;
}
static void bb_buf_queue ( struct videobuf_queue * q ,
struct videobuf_buffer * vb )
{
struct cx23885_fh * fh = q - > priv_data ;
cx23885_buf_queue ( & fh - > dev - > ts1 , ( struct cx23885_buffer * ) vb ) ;
}
static void bb_buf_release ( struct videobuf_queue * q ,
struct videobuf_buffer * vb )
{
cx23885_free_buffer ( q , ( struct cx23885_buffer * ) vb ) ;
}
static struct videobuf_queue_ops cx23885_qops = {
. buf_setup = bb_buf_setup ,
. buf_prepare = bb_buf_prepare ,
. buf_queue = bb_buf_queue ,
. buf_release = bb_buf_release ,
} ;
/* ------------------------------------------------------------------ */
static const u32 * ctrl_classes [ ] = {
cx2341x_mpeg_ctrls ,
NULL
} ;
static int cx23885_queryctrl ( struct cx23885_dev * dev ,
struct v4l2_queryctrl * qctrl )
{
qctrl - > id = v4l2_ctrl_next ( ctrl_classes , qctrl - > id ) ;
if ( qctrl - > id = = 0 )
return - EINVAL ;
/* MPEG V4L2 controls */
if ( cx2341x_ctrl_query ( & dev - > mpeg_params , qctrl ) )
qctrl - > flags | = V4L2_CTRL_FLAG_DISABLED ;
return 0 ;
}
static int cx23885_querymenu ( struct cx23885_dev * dev ,
struct v4l2_querymenu * qmenu )
{
struct v4l2_queryctrl qctrl ;
qctrl . id = qmenu - > id ;
cx23885_queryctrl ( dev , & qctrl ) ;
return v4l2_ctrl_query_menu ( qmenu , & qctrl ,
2008-06-22 12:03:28 -03:00
cx2341x_ctrl_get_menu ( & dev - > mpeg_params , qmenu - > id ) ) ;
2008-01-13 23:42:44 -03:00
}
2008-06-27 04:15:38 -03:00
static int vidioc_s_std ( struct file * file , void * priv , v4l2_std_id * id )
2008-01-13 23:42:44 -03:00
{
2008-06-27 04:15:38 -03:00
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
unsigned int i ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( cx23885_tvnorms ) ; i + + )
if ( * id & cx23885_tvnorms [ i ] . id )
break ;
if ( i = = ARRAY_SIZE ( cx23885_tvnorms ) )
return - EINVAL ;
dev - > encodernorm = cx23885_tvnorms [ i ] ;
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_enum_input ( struct file * file , void * priv ,
struct v4l2_input * i )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
struct cx23885_input * input ;
unsigned int n ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
n = i - > index ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
if ( n > = 4 )
return - EINVAL ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
input = & cx23885_boards [ dev - > board ] . input [ n ] ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
if ( input - > type = = 0 )
return - EINVAL ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
memset ( i , 0 , sizeof ( * i ) ) ;
i - > index = n ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
/* FIXME
* strcpy ( i - > name , input - > name ) ; */
strcpy ( i - > name , " unset " ) ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
if ( input - > type = = CX23885_VMUX_TELEVISION | |
input - > type = = CX23885_VMUX_CABLE )
i - > type = V4L2_INPUT_TYPE_TUNER ;
else
i - > type = V4L2_INPUT_TYPE_CAMERA ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
for ( n = 0 ; n < ARRAY_SIZE ( cx23885_tvnorms ) ; n + + )
i - > std | = cx23885_tvnorms [ n ] . id ;
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_g_input ( struct file * file , void * priv , unsigned int * i )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
* i = dev - > input ;
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_s_input ( struct file * file , void * priv , unsigned int i )
{
if ( i > = 4 )
return - EINVAL ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_g_tuner ( struct file * file , void * priv ,
struct v4l2_tuner * t )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
if ( UNSET = = dev - > tuner_type )
return - EINVAL ;
if ( 0 ! = t - > index )
return - EINVAL ;
memset ( t , 0 , sizeof ( * t ) ) ;
strcpy ( t - > name , " Television " ) ;
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 2 ] , VIDIOC_G_TUNER , t ) ;
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 1 ] , VIDIOC_G_TUNER , t ) ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
dprintk ( 1 , " VIDIOC_G_TUNER: tuner type %d \n " , t - > type ) ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_s_tuner ( struct file * file , void * priv ,
struct v4l2_tuner * t )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
if ( UNSET = = dev - > tuner_type )
return - EINVAL ;
/* Update the A/V core */
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 2 ] , VIDIOC_S_TUNER , t ) ;
return 0 ;
}
static int vidioc_g_frequency ( struct file * file , void * priv ,
struct v4l2_frequency * f )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
memset ( f , 0 , sizeof ( * f ) ) ;
if ( UNSET = = dev - > tuner_type )
return - EINVAL ;
f - > type = V4L2_TUNER_ANALOG_TV ;
f - > frequency = dev - > freq ;
/* Assumption that tuner is always on bus 1 */
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 1 ] , VIDIOC_G_FREQUENCY , f ) ;
return 0 ;
}
static int vidioc_s_frequency ( struct file * file , void * priv ,
struct v4l2_frequency * f )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
cx23885_api_cmd ( fh - > dev , CX2341X_ENC_STOP_CAPTURE , 3 , 0 ,
CX23885_END_NOW , CX23885_MPEG_CAPTURE ,
CX23885_RAW_BITS_NONE ) ;
dprintk ( 1 , " VIDIOC_S_FREQUENCY: dev type %d, f \n " ,
dev - > tuner_type ) ;
dprintk ( 1 , " VIDIOC_S_FREQUENCY: f tuner %d, f type %d \n " ,
f - > tuner , f - > type ) ;
if ( UNSET = = dev - > tuner_type )
return - EINVAL ;
if ( f - > tuner ! = 0 )
return - EINVAL ;
if ( f - > type ! = V4L2_TUNER_ANALOG_TV )
return - EINVAL ;
dev - > freq = f - > frequency ;
/* Assumption that tuner is always on bus 1 */
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 1 ] , VIDIOC_S_FREQUENCY , f ) ;
cx23885_initialize_codec ( dev ) ;
2008-01-13 23:42:44 -03:00
return 0 ;
}
2008-06-27 04:15:38 -03:00
static int vidioc_s_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctl )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
/* Update the A/V core */
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 2 ] , VIDIOC_S_CTRL , ctl ) ;
return 0 ;
}
static int vidioc_querycap ( struct file * file , void * priv ,
struct v4l2_capability * cap )
2008-01-13 23:42:44 -03:00
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
struct cx23885_tsport * tsport = & dev - > ts1 ;
2008-06-27 04:15:38 -03:00
memset ( cap , 0 , sizeof ( * cap ) ) ;
strcpy ( cap - > driver , dev - > name ) ;
strlcpy ( cap - > card , cx23885_boards [ tsport - > dev - > board ] . name ,
sizeof ( cap - > card ) ) ;
sprintf ( cap - > bus_info , " PCI:%s " , pci_name ( dev - > pci ) ) ;
cap - > version = CX23885_VERSION_CODE ;
cap - > capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
0 ;
if ( UNSET ! = dev - > tuner_type )
cap - > capabilities | = V4L2_CAP_TUNER ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_enum_fmt_vid_cap ( struct file * file , void * priv ,
struct v4l2_fmtdesc * f )
{
int index ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
index = f - > index ;
if ( index ! = 0 )
return - EINVAL ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
memset ( f , 0 , sizeof ( * f ) ) ;
f - > index = index ;
strlcpy ( f - > description , " MPEG " , sizeof ( f - > description ) ) ;
f - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
f - > pixelformat = V4L2_PIX_FMT_MPEG ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_g_fmt_vid_cap ( struct file * file , void * priv ,
struct v4l2_format * f )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
memset ( f , 0 , sizeof ( * f ) ) ;
f - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
f - > fmt . pix . pixelformat = V4L2_PIX_FMT_MPEG ;
f - > fmt . pix . bytesperline = 0 ;
f - > fmt . pix . sizeimage =
dev - > ts1 . ts_packet_size * dev - > ts1 . ts_packet_count ;
f - > fmt . pix . colorspace = 0 ;
f - > fmt . pix . width = dev - > ts1 . width ;
f - > fmt . pix . height = dev - > ts1 . height ;
f - > fmt . pix . field = fh - > mpegq . field ;
dprintk ( 1 , " VIDIOC_G_FMT: w: %d, h: %d, f: %d \n " ,
dev - > ts1 . width , dev - > ts1 . height , fh - > mpegq . field ) ;
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_try_fmt_vid_cap ( struct file * file , void * priv ,
struct v4l2_format * f )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
f - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
f - > fmt . pix . pixelformat = V4L2_PIX_FMT_MPEG ;
f - > fmt . pix . bytesperline = 0 ;
f - > fmt . pix . sizeimage =
dev - > ts1 . ts_packet_size * dev - > ts1 . ts_packet_count ;
f - > fmt . pix . sizeimage =
f - > fmt . pix . colorspace = 0 ;
dprintk ( 1 , " VIDIOC_TRY_FMT: w: %d, h: %d, f: %d \n " ,
dev - > ts1 . width , dev - > ts1 . height , fh - > mpegq . field ) ;
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_s_fmt_vid_cap ( struct file * file , void * priv ,
struct v4l2_format * f )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
f - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
f - > fmt . pix . pixelformat = V4L2_PIX_FMT_MPEG ;
f - > fmt . pix . bytesperline = 0 ;
f - > fmt . pix . sizeimage =
dev - > ts1 . ts_packet_size * dev - > ts1 . ts_packet_count ;
f - > fmt . pix . colorspace = 0 ;
dprintk ( 1 , " VIDIOC_S_FMT: w: %d, h: %d, f: %d \n " ,
f - > fmt . pix . width , f - > fmt . pix . height , f - > fmt . pix . field ) ;
return 0 ;
}
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
static int vidioc_reqbufs ( struct file * file , void * priv ,
struct v4l2_requestbuffers * p )
{
struct cx23885_fh * fh = file - > private_data ;
2008-01-13 23:42:44 -03:00
2008-06-27 04:15:38 -03:00
return videobuf_reqbufs ( & fh - > mpegq , p ) ;
}
static int vidioc_querybuf ( struct file * file , void * priv ,
struct v4l2_buffer * p )
{
struct cx23885_fh * fh = file - > private_data ;
return videobuf_querybuf ( & fh - > mpegq , p ) ;
}
static int vidioc_qbuf ( struct file * file , void * priv ,
struct v4l2_buffer * p )
{
struct cx23885_fh * fh = file - > private_data ;
return videobuf_qbuf ( & fh - > mpegq , p ) ;
}
static int vidioc_dqbuf ( struct file * file , void * priv , struct v4l2_buffer * b )
{
struct cx23885_fh * fh = priv ;
return videobuf_dqbuf ( & fh - > mpegq , b , file - > f_flags & O_NONBLOCK ) ;
}
static int vidioc_streamon ( struct file * file , void * priv ,
enum v4l2_buf_type i )
{
struct cx23885_fh * fh = file - > private_data ;
return videobuf_streamon ( & fh - > mpegq ) ;
}
static int vidioc_streamoff ( struct file * file , void * priv , enum v4l2_buf_type i )
{
struct cx23885_fh * fh = file - > private_data ;
return videobuf_streamoff ( & fh - > mpegq ) ;
}
static int vidioc_g_ext_ctrls ( struct file * file , void * priv ,
struct v4l2_ext_controls * f )
{
struct cx23885_fh * fh = priv ;
struct cx23885_dev * dev = fh - > dev ;
if ( f - > ctrl_class ! = V4L2_CTRL_CLASS_MPEG )
return - EINVAL ;
return cx2341x_ext_ctrls ( & dev - > mpeg_params , 0 , f , VIDIOC_G_EXT_CTRLS ) ;
}
static int vidioc_s_ext_ctrls ( struct file * file , void * priv ,
struct v4l2_ext_controls * f )
{
struct cx23885_fh * fh = priv ;
struct cx23885_dev * dev = fh - > dev ;
struct cx2341x_mpeg_params p ;
int err ;
if ( f - > ctrl_class ! = V4L2_CTRL_CLASS_MPEG )
return - EINVAL ;
p = dev - > mpeg_params ;
err = cx2341x_ext_ctrls ( & p , 0 , f , VIDIOC_S_EXT_CTRLS ) ;
if ( err = = 0 ) {
err = cx2341x_update ( dev , cx23885_mbox_func ,
& dev - > mpeg_params , & p ) ;
dev - > mpeg_params = p ;
2008-01-13 23:42:44 -03:00
}
2008-06-27 04:15:38 -03:00
return err ;
}
static int vidioc_try_ext_ctrls ( struct file * file , void * priv ,
struct v4l2_ext_controls * f )
{
struct cx23885_fh * fh = priv ;
struct cx23885_dev * dev = fh - > dev ;
struct cx2341x_mpeg_params p ;
int err ;
if ( f - > ctrl_class ! = V4L2_CTRL_CLASS_MPEG )
return - EINVAL ;
p = dev - > mpeg_params ;
err = cx2341x_ext_ctrls ( & p , 0 , f , VIDIOC_TRY_EXT_CTRLS ) ;
return err ;
}
static int vidioc_log_status ( struct file * file , void * priv )
{
struct cx23885_fh * fh = priv ;
struct cx23885_dev * dev = fh - > dev ;
char name [ 32 + 2 ] ;
snprintf ( name , sizeof ( name ) , " %s/2 " , dev - > name ) ;
printk ( KERN_INFO
" %s/2: ============ START LOG STATUS ============ \n " ,
dev - > name ) ;
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 0 ] , VIDIOC_LOG_STATUS ,
NULL ) ;
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 1 ] , VIDIOC_LOG_STATUS ,
NULL ) ;
cx23885_call_i2c_clients ( & dev - > i2c_bus [ 2 ] , VIDIOC_LOG_STATUS ,
NULL ) ;
cx2341x_log_status ( & dev - > mpeg_params , name ) ;
printk ( KERN_INFO
" %s/2: ============= END LOG STATUS ============= \n " ,
dev - > name ) ;
2008-01-13 23:42:44 -03:00
return 0 ;
}
2008-06-27 04:15:38 -03:00
static int vidioc_querymenu ( struct file * file , void * priv ,
struct v4l2_querymenu * a )
{
struct cx23885_fh * fh = priv ;
struct cx23885_dev * dev = fh - > dev ;
return cx23885_querymenu ( dev , a ) ;
}
static int vidioc_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * c )
2008-01-13 23:42:44 -03:00
{
2008-06-27 04:15:38 -03:00
struct cx23885_fh * fh = priv ;
struct cx23885_dev * dev = fh - > dev ;
return cx23885_queryctrl ( dev , c ) ;
2008-01-13 23:42:44 -03:00
}
static int mpeg_open ( struct inode * inode , struct file * file )
{
int minor = iminor ( inode ) ;
struct cx23885_dev * h , * dev = NULL ;
struct list_head * list ;
struct cx23885_fh * fh ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
2008-07-30 08:43:36 -03:00
lock_kernel ( ) ;
2008-01-13 23:42:44 -03:00
list_for_each ( list , & cx23885_devlist ) {
h = list_entry ( list , struct cx23885_dev , devlist ) ;
if ( h - > v4l_device - > minor = = minor ) {
dev = h ;
break ;
}
}
2008-07-30 08:43:36 -03:00
if ( dev = = NULL ) {
unlock_kernel ( ) ;
2008-01-13 23:42:44 -03:00
return - ENODEV ;
2008-07-30 08:43:36 -03:00
}
2008-01-13 23:42:44 -03:00
/* allocate + initialize per filehandle data */
fh = kzalloc ( sizeof ( * fh ) , GFP_KERNEL ) ;
2008-07-30 08:43:36 -03:00
if ( NULL = = fh ) {
unlock_kernel ( ) ;
2008-01-13 23:42:44 -03:00
return - ENOMEM ;
2008-07-30 08:43:36 -03:00
}
2008-01-13 23:42:44 -03:00
file - > private_data = fh ;
fh - > dev = dev ;
videobuf_queue_sg_init ( & fh - > mpegq , & cx23885_qops ,
& dev - > pci - > dev , & dev - > ts1 . slock ,
V4L2_BUF_TYPE_VIDEO_CAPTURE ,
V4L2_FIELD_INTERLACED ,
sizeof ( struct cx23885_buffer ) ,
fh ) ;
2008-07-30 08:43:36 -03:00
unlock_kernel ( ) ;
2008-01-13 23:42:44 -03:00
return 0 ;
}
static int mpeg_release ( struct inode * inode , struct file * file )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
/* FIXME: Review this crap */
/* Shut device down on last close */
if ( atomic_cmpxchg ( & fh - > v4l_reading , 1 , 0 ) = = 1 ) {
if ( atomic_dec_return ( & dev - > v4l_reader_count ) = = 0 ) {
/* stop mpeg capture */
cx23885_api_cmd ( fh - > dev , CX2341X_ENC_STOP_CAPTURE , 3 , 0 ,
CX23885_END_NOW , CX23885_MPEG_CAPTURE ,
CX23885_RAW_BITS_NONE ) ;
msleep ( 500 ) ;
cx23885_417_check_encoder ( dev ) ;
cx23885_cancel_buffers ( & fh - > dev - > ts1 ) ;
}
}
if ( fh - > mpegq . streaming )
videobuf_streamoff ( & fh - > mpegq ) ;
if ( fh - > mpegq . reading )
videobuf_read_stop ( & fh - > mpegq ) ;
videobuf_mmap_free ( & fh - > mpegq ) ;
file - > private_data = NULL ;
kfree ( fh ) ;
return 0 ;
}
static ssize_t mpeg_read ( struct file * file , char __user * data ,
size_t count , loff_t * ppos )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
/* Start mpeg encoder on first read. */
if ( atomic_cmpxchg ( & fh - > v4l_reading , 0 , 1 ) = = 0 ) {
if ( atomic_inc_return ( & dev - > v4l_reader_count ) = = 1 ) {
if ( cx23885_initialize_codec ( dev ) < 0 )
return - EINVAL ;
}
}
return videobuf_read_stream ( & fh - > mpegq , data , count , ppos , 0 ,
file - > f_flags & O_NONBLOCK ) ;
}
static unsigned int mpeg_poll ( struct file * file ,
struct poll_table_struct * wait )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
dprintk ( 2 , " %s \n " , __func__ ) ;
return videobuf_poll_stream ( file , & fh - > mpegq , wait ) ;
}
static int mpeg_mmap ( struct file * file , struct vm_area_struct * vma )
{
struct cx23885_fh * fh = file - > private_data ;
struct cx23885_dev * dev = fh - > dev ;
dprintk ( 2 , " %s() \n " , __func__ ) ;
return videobuf_mmap_mapper ( & fh - > mpegq , vma ) ;
}
static struct file_operations mpeg_fops = {
. owner = THIS_MODULE ,
. open = mpeg_open ,
. release = mpeg_release ,
. read = mpeg_read ,
. poll = mpeg_poll ,
. mmap = mpeg_mmap ,
2008-06-27 04:15:38 -03:00
. ioctl = video_ioctl2 ,
2008-01-13 23:42:44 -03:00
. llseek = no_llseek ,
} ;
2008-07-21 02:57:38 -03:00
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
2008-06-27 04:15:38 -03:00
. vidioc_s_std = vidioc_s_std ,
. vidioc_enum_input = vidioc_enum_input ,
. vidioc_g_input = vidioc_g_input ,
. vidioc_s_input = vidioc_s_input ,
. vidioc_g_tuner = vidioc_g_tuner ,
. vidioc_s_tuner = vidioc_s_tuner ,
. vidioc_g_frequency = vidioc_g_frequency ,
. vidioc_s_frequency = vidioc_s_frequency ,
. vidioc_s_ctrl = vidioc_s_ctrl ,
. vidioc_querycap = vidioc_querycap ,
. vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap ,
. vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap ,
. vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap ,
. vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap ,
. vidioc_reqbufs = vidioc_reqbufs ,
. vidioc_querybuf = vidioc_querybuf ,
. vidioc_qbuf = vidioc_qbuf ,
. vidioc_dqbuf = vidioc_dqbuf ,
. vidioc_streamon = vidioc_streamon ,
. vidioc_streamoff = vidioc_streamoff ,
. vidioc_g_ext_ctrls = vidioc_g_ext_ctrls ,
. vidioc_s_ext_ctrls = vidioc_s_ext_ctrls ,
. vidioc_try_ext_ctrls = vidioc_try_ext_ctrls ,
. vidioc_log_status = vidioc_log_status ,
. vidioc_querymenu = vidioc_querymenu ,
. vidioc_queryctrl = vidioc_queryctrl ,
2008-01-13 23:42:44 -03:00
} ;
2008-07-21 02:57:38 -03:00
static struct video_device cx23885_mpeg_template = {
. name = " cx23885 " ,
. fops = & mpeg_fops ,
. ioctl_ops = & mpeg_ioctl_ops ,
. minor = - 1 ,
} ;
2008-01-13 23:42:44 -03:00
void cx23885_417_unregister ( struct cx23885_dev * dev )
{
dprintk ( 1 , " %s() \n " , __func__ ) ;
if ( dev - > v4l_device ) {
if ( - 1 ! = dev - > v4l_device - > minor )
video_unregister_device ( dev - > v4l_device ) ;
else
video_device_release ( dev - > v4l_device ) ;
dev - > v4l_device = NULL ;
}
}
static struct video_device * cx23885_video_dev_alloc (
struct cx23885_tsport * tsport ,
struct pci_dev * pci ,
struct video_device * template ,
char * type )
{
struct video_device * vfd ;
struct cx23885_dev * dev = tsport - > dev ;
dprintk ( 1 , " %s() \n " , __func__ ) ;
vfd = video_device_alloc ( ) ;
if ( NULL = = vfd )
return NULL ;
* vfd = * template ;
vfd - > minor = - 1 ;
snprintf ( vfd - > name , sizeof ( vfd - > name ) , " %s %s (%s) " , dev - > name ,
type , cx23885_boards [ tsport - > dev - > board ] . name ) ;
2008-07-20 06:31:39 -03:00
vfd - > parent = & pci - > dev ;
2008-01-13 23:42:44 -03:00
vfd - > release = video_device_release ;
return vfd ;
}
int cx23885_417_register ( struct cx23885_dev * dev )
{
/* FIXME: Port1 hardcoded here */
int err = - ENODEV ;
struct cx23885_tsport * tsport = & dev - > ts1 ;
dprintk ( 1 , " %s() \n " , __func__ ) ;
if ( cx23885_boards [ dev - > board ] . portb ! = CX23885_MPEG_ENCODER )
return err ;
/* Set default TV standard */
dev - > encodernorm = cx23885_tvnorms [ 0 ] ;
if ( dev - > encodernorm . id & V4L2_STD_525_60 )
tsport - > height = 480 ;
else
tsport - > height = 576 ;
tsport - > width = 720 ;
cx2341x_fill_defaults ( & dev - > mpeg_params ) ;
dev - > mpeg_params . port = CX2341X_PORT_SERIAL ;
/* Allocate and initialize V4L video device */
dev - > v4l_device = cx23885_video_dev_alloc ( tsport ,
dev - > pci , & cx23885_mpeg_template , " mpeg " ) ;
err = video_register_device ( dev - > v4l_device ,
VFL_TYPE_GRABBER , - 1 ) ;
if ( err < 0 ) {
printk ( KERN_INFO " %s: can't register mpeg device \n " , dev - > name ) ;
return err ;
}
/* Initialize MC417 registers */
cx23885_mc417_init ( dev ) ;
printk ( KERN_INFO " %s: registered device video%d [mpeg] \n " ,
dev - > name , dev - > v4l_device - > minor & 0x1f ) ;
return 0 ;
}