xref: /linux/drivers/media/usb/cx231xx/cx231xx-417.c (revision 3f926e326d3c02b73898b7692f2b2306c521e2d3)
10c0d06caSMauro Carvalho Chehab /*
20c0d06caSMauro Carvalho Chehab  *
30c0d06caSMauro Carvalho Chehab  *  Support for a cx23417 mpeg encoder via cx231xx host port.
40c0d06caSMauro Carvalho Chehab  *
50c0d06caSMauro Carvalho Chehab  *    (c) 2004 Jelle Foks <jelle@foks.us>
60c0d06caSMauro Carvalho Chehab  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
70c0d06caSMauro Carvalho Chehab  *    (c) 2008 Steven Toth <stoth@linuxtv.org>
80c0d06caSMauro Carvalho Chehab  *      - CX23885/7/8 support
90c0d06caSMauro Carvalho Chehab  *
100c0d06caSMauro Carvalho Chehab  *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
110c0d06caSMauro Carvalho Chehab  *
120c0d06caSMauro Carvalho Chehab  *  This program is free software; you can redistribute it and/or modify
130c0d06caSMauro Carvalho Chehab  *  it under the terms of the GNU General Public License as published by
140c0d06caSMauro Carvalho Chehab  *  the Free Software Foundation; either version 2 of the License, or
150c0d06caSMauro Carvalho Chehab  *  (at your option) any later version.
160c0d06caSMauro Carvalho Chehab  *
170c0d06caSMauro Carvalho Chehab  *  This program is distributed in the hope that it will be useful,
180c0d06caSMauro Carvalho Chehab  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
190c0d06caSMauro Carvalho Chehab  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
200c0d06caSMauro Carvalho Chehab  *  GNU General Public License for more details.
210c0d06caSMauro Carvalho Chehab  *
220c0d06caSMauro Carvalho Chehab  *  You should have received a copy of the GNU General Public License
230c0d06caSMauro Carvalho Chehab  *  along with this program; if not, write to the Free Software
240c0d06caSMauro Carvalho Chehab  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
250c0d06caSMauro Carvalho Chehab  */
260c0d06caSMauro Carvalho Chehab 
270c0d06caSMauro Carvalho Chehab #include <linux/module.h>
280c0d06caSMauro Carvalho Chehab #include <linux/moduleparam.h>
290c0d06caSMauro Carvalho Chehab #include <linux/init.h>
300c0d06caSMauro Carvalho Chehab #include <linux/fs.h>
310c0d06caSMauro Carvalho Chehab #include <linux/delay.h>
320c0d06caSMauro Carvalho Chehab #include <linux/device.h>
330c0d06caSMauro Carvalho Chehab #include <linux/firmware.h>
340c0d06caSMauro Carvalho Chehab #include <linux/vmalloc.h>
350c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
360c0d06caSMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
370c0d06caSMauro Carvalho Chehab #include <media/cx2341x.h>
380c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
390c0d06caSMauro Carvalho Chehab 
400c0d06caSMauro Carvalho Chehab #include "cx231xx.h"
410c0d06caSMauro Carvalho Chehab /*#include "cx23885-ioctl.h"*/
420c0d06caSMauro Carvalho Chehab 
430c0d06caSMauro Carvalho Chehab #define CX231xx_FIRM_IMAGE_SIZE 376836
440c0d06caSMauro Carvalho Chehab #define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
450c0d06caSMauro Carvalho Chehab 
460c0d06caSMauro Carvalho Chehab /* for polaris ITVC */
470c0d06caSMauro Carvalho Chehab #define ITVC_WRITE_DIR          0x03FDFC00
480c0d06caSMauro Carvalho Chehab #define ITVC_READ_DIR            0x0001FC00
490c0d06caSMauro Carvalho Chehab 
500c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_DATA_BYTE0          0x00
510c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_DATA_BYTE1          0x08
520c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_DATA_BYTE2          0x10
530c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_DATA_BYTE3          0x18
540c0d06caSMauro Carvalho Chehab 
550c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_ADDRESS_BYTE2       0x20
560c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_ADDRESS_BYTE1       0x28
570c0d06caSMauro Carvalho Chehab #define  MCI_MEMORY_ADDRESS_BYTE0       0x30
580c0d06caSMauro Carvalho Chehab 
590c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_DATA_BYTE0        0x40
600c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_DATA_BYTE1        0x48
610c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_DATA_BYTE2        0x50
620c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_DATA_BYTE3        0x58
630c0d06caSMauro Carvalho Chehab 
640c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_ADDRESS_BYTE0     0x60
650c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_ADDRESS_BYTE1     0x68
660c0d06caSMauro Carvalho Chehab 
670c0d06caSMauro Carvalho Chehab #define  MCI_REGISTER_MODE              0x70
680c0d06caSMauro Carvalho Chehab 
690c0d06caSMauro Carvalho Chehab /* Read and write modes for polaris ITVC */
700c0d06caSMauro Carvalho Chehab #define  MCI_MODE_REGISTER_READ         0x000
710c0d06caSMauro Carvalho Chehab #define  MCI_MODE_REGISTER_WRITE        0x100
720c0d06caSMauro Carvalho Chehab #define  MCI_MODE_MEMORY_READ           0x000
730c0d06caSMauro Carvalho Chehab #define  MCI_MODE_MEMORY_WRITE          0x4000
740c0d06caSMauro Carvalho Chehab 
750c0d06caSMauro Carvalho Chehab static unsigned int mpegbufs = 8;
760c0d06caSMauro Carvalho Chehab module_param(mpegbufs, int, 0644);
770c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
780c0d06caSMauro Carvalho Chehab static unsigned int mpeglines = 128;
790c0d06caSMauro Carvalho Chehab module_param(mpeglines, int, 0644);
800c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
810c0d06caSMauro Carvalho Chehab static unsigned int mpeglinesize = 512;
820c0d06caSMauro Carvalho Chehab module_param(mpeglinesize, int, 0644);
830c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(mpeglinesize,
840c0d06caSMauro Carvalho Chehab 	"number of bytes in each line of an MPEG buffer, range 512-1024");
850c0d06caSMauro Carvalho Chehab 
860c0d06caSMauro Carvalho Chehab static unsigned int v4l_debug = 1;
870c0d06caSMauro Carvalho Chehab module_param(v4l_debug, int, 0644);
880c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
890c0d06caSMauro Carvalho Chehab struct cx231xx_dmaqueue *dma_qq;
900c0d06caSMauro Carvalho Chehab #define dprintk(level, fmt, arg...)\
910c0d06caSMauro Carvalho Chehab 	do { if (v4l_debug >= level) \
920c0d06caSMauro Carvalho Chehab 		printk(KERN_INFO "%s: " fmt, \
930c0d06caSMauro Carvalho Chehab 		(dev) ? dev->name : "cx231xx[?]", ## arg); \
940c0d06caSMauro Carvalho Chehab 	} while (0)
950c0d06caSMauro Carvalho Chehab 
960c0d06caSMauro Carvalho Chehab static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
970c0d06caSMauro Carvalho Chehab 	{
980c0d06caSMauro Carvalho Chehab 		.name      = "NTSC-M",
990c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_NTSC_M,
1000c0d06caSMauro Carvalho Chehab 	}, {
1010c0d06caSMauro Carvalho Chehab 		.name      = "NTSC-JP",
1020c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_NTSC_M_JP,
1030c0d06caSMauro Carvalho Chehab 	}, {
1040c0d06caSMauro Carvalho Chehab 		.name      = "PAL-BG",
1050c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_BG,
1060c0d06caSMauro Carvalho Chehab 	}, {
1070c0d06caSMauro Carvalho Chehab 		.name      = "PAL-DK",
1080c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_DK,
1090c0d06caSMauro Carvalho Chehab 	}, {
1100c0d06caSMauro Carvalho Chehab 		.name      = "PAL-I",
1110c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_I,
1120c0d06caSMauro Carvalho Chehab 	}, {
1130c0d06caSMauro Carvalho Chehab 		.name      = "PAL-M",
1140c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_M,
1150c0d06caSMauro Carvalho Chehab 	}, {
1160c0d06caSMauro Carvalho Chehab 		.name      = "PAL-N",
1170c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_N,
1180c0d06caSMauro Carvalho Chehab 	}, {
1190c0d06caSMauro Carvalho Chehab 		.name      = "PAL-Nc",
1200c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_Nc,
1210c0d06caSMauro Carvalho Chehab 	}, {
1220c0d06caSMauro Carvalho Chehab 		.name      = "PAL-60",
1230c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_PAL_60,
1240c0d06caSMauro Carvalho Chehab 	}, {
1250c0d06caSMauro Carvalho Chehab 		.name      = "SECAM-L",
1260c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_SECAM_L,
1270c0d06caSMauro Carvalho Chehab 	}, {
1280c0d06caSMauro Carvalho Chehab 		.name      = "SECAM-DK",
1290c0d06caSMauro Carvalho Chehab 		.id        = V4L2_STD_SECAM_DK,
1300c0d06caSMauro Carvalho Chehab 	}
1310c0d06caSMauro Carvalho Chehab };
1320c0d06caSMauro Carvalho Chehab 
1330c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
1340c0d06caSMauro Carvalho Chehab enum cx231xx_capture_type {
1350c0d06caSMauro Carvalho Chehab 	CX231xx_MPEG_CAPTURE,
1360c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_CAPTURE,
1370c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_PASSTHRU_CAPTURE
1380c0d06caSMauro Carvalho Chehab };
1390c0d06caSMauro Carvalho Chehab enum cx231xx_capture_bits {
1400c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_BITS_NONE             = 0x00,
1410c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_BITS_YUV_CAPTURE      = 0x01,
1420c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_BITS_PCM_CAPTURE      = 0x02,
1430c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_BITS_VBI_CAPTURE      = 0x04,
1440c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
1450c0d06caSMauro Carvalho Chehab 	CX231xx_RAW_BITS_TO_HOST_CAPTURE  = 0x10
1460c0d06caSMauro Carvalho Chehab };
1470c0d06caSMauro Carvalho Chehab enum cx231xx_capture_end {
1480c0d06caSMauro Carvalho Chehab 	CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
1490c0d06caSMauro Carvalho Chehab 	CX231xx_END_NOW, /* stop immediately, no irq */
1500c0d06caSMauro Carvalho Chehab };
1510c0d06caSMauro Carvalho Chehab enum cx231xx_framerate {
1520c0d06caSMauro Carvalho Chehab 	CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
1530c0d06caSMauro Carvalho Chehab 	CX231xx_FRAMERATE_PAL_25   /* PAL: 25fps */
1540c0d06caSMauro Carvalho Chehab };
1550c0d06caSMauro Carvalho Chehab enum cx231xx_stream_port {
1560c0d06caSMauro Carvalho Chehab 	CX231xx_OUTPUT_PORT_MEMORY,
1570c0d06caSMauro Carvalho Chehab 	CX231xx_OUTPUT_PORT_STREAMING,
1580c0d06caSMauro Carvalho Chehab 	CX231xx_OUTPUT_PORT_SERIAL
1590c0d06caSMauro Carvalho Chehab };
1600c0d06caSMauro Carvalho Chehab enum cx231xx_data_xfer_status {
1610c0d06caSMauro Carvalho Chehab 	CX231xx_MORE_BUFFERS_FOLLOW,
1620c0d06caSMauro Carvalho Chehab 	CX231xx_LAST_BUFFER,
1630c0d06caSMauro Carvalho Chehab };
1640c0d06caSMauro Carvalho Chehab enum cx231xx_picture_mask {
1650c0d06caSMauro Carvalho Chehab 	CX231xx_PICTURE_MASK_NONE,
1660c0d06caSMauro Carvalho Chehab 	CX231xx_PICTURE_MASK_I_FRAMES,
1670c0d06caSMauro Carvalho Chehab 	CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
1680c0d06caSMauro Carvalho Chehab 	CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
1690c0d06caSMauro Carvalho Chehab };
1700c0d06caSMauro Carvalho Chehab enum cx231xx_vbi_mode_bits {
1710c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_SLICED,
1720c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_RAW,
1730c0d06caSMauro Carvalho Chehab };
1740c0d06caSMauro Carvalho Chehab enum cx231xx_vbi_insertion_bits {
1750c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
1760c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
1770c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
1780c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
1790c0d06caSMauro Carvalho Chehab 	CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
1800c0d06caSMauro Carvalho Chehab };
1810c0d06caSMauro Carvalho Chehab enum cx231xx_dma_unit {
1820c0d06caSMauro Carvalho Chehab 	CX231xx_DMA_BYTES,
1830c0d06caSMauro Carvalho Chehab 	CX231xx_DMA_FRAMES,
1840c0d06caSMauro Carvalho Chehab };
1850c0d06caSMauro Carvalho Chehab enum cx231xx_dma_transfer_status_bits {
1860c0d06caSMauro Carvalho Chehab 	CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
1870c0d06caSMauro Carvalho Chehab 	CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
1880c0d06caSMauro Carvalho Chehab 	CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
1890c0d06caSMauro Carvalho Chehab };
1900c0d06caSMauro Carvalho Chehab enum cx231xx_pause {
1910c0d06caSMauro Carvalho Chehab 	CX231xx_PAUSE_ENCODING,
1920c0d06caSMauro Carvalho Chehab 	CX231xx_RESUME_ENCODING,
1930c0d06caSMauro Carvalho Chehab };
1940c0d06caSMauro Carvalho Chehab enum cx231xx_copyright {
1950c0d06caSMauro Carvalho Chehab 	CX231xx_COPYRIGHT_OFF,
1960c0d06caSMauro Carvalho Chehab 	CX231xx_COPYRIGHT_ON,
1970c0d06caSMauro Carvalho Chehab };
1980c0d06caSMauro Carvalho Chehab enum cx231xx_notification_type {
1990c0d06caSMauro Carvalho Chehab 	CX231xx_NOTIFICATION_REFRESH,
2000c0d06caSMauro Carvalho Chehab };
2010c0d06caSMauro Carvalho Chehab enum cx231xx_notification_status {
2020c0d06caSMauro Carvalho Chehab 	CX231xx_NOTIFICATION_OFF,
2030c0d06caSMauro Carvalho Chehab 	CX231xx_NOTIFICATION_ON,
2040c0d06caSMauro Carvalho Chehab };
2050c0d06caSMauro Carvalho Chehab enum cx231xx_notification_mailbox {
2060c0d06caSMauro Carvalho Chehab 	CX231xx_NOTIFICATION_NO_MAILBOX = -1,
2070c0d06caSMauro Carvalho Chehab };
2080c0d06caSMauro Carvalho Chehab enum cx231xx_field1_lines {
2090c0d06caSMauro Carvalho Chehab 	CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
2100c0d06caSMauro Carvalho Chehab 	CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
2110c0d06caSMauro Carvalho Chehab 	CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
2120c0d06caSMauro Carvalho Chehab };
2130c0d06caSMauro Carvalho Chehab enum cx231xx_field2_lines {
2140c0d06caSMauro Carvalho Chehab 	CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
2150c0d06caSMauro Carvalho Chehab 	CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
2160c0d06caSMauro Carvalho Chehab 	CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
2170c0d06caSMauro Carvalho Chehab };
2180c0d06caSMauro Carvalho Chehab enum cx231xx_custom_data_type {
2190c0d06caSMauro Carvalho Chehab 	CX231xx_CUSTOM_EXTENSION_USR_DATA,
2200c0d06caSMauro Carvalho Chehab 	CX231xx_CUSTOM_PRIVATE_PACKET,
2210c0d06caSMauro Carvalho Chehab };
2220c0d06caSMauro Carvalho Chehab enum cx231xx_mute {
2230c0d06caSMauro Carvalho Chehab 	CX231xx_UNMUTE,
2240c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE,
2250c0d06caSMauro Carvalho Chehab };
2260c0d06caSMauro Carvalho Chehab enum cx231xx_mute_video_mask {
2270c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
2280c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
2290c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
2300c0d06caSMauro Carvalho Chehab };
2310c0d06caSMauro Carvalho Chehab enum cx231xx_mute_video_shift {
2320c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE_VIDEO_V_SHIFT = 8,
2330c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE_VIDEO_U_SHIFT = 16,
2340c0d06caSMauro Carvalho Chehab 	CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
2350c0d06caSMauro Carvalho Chehab };
2360c0d06caSMauro Carvalho Chehab 
2370c0d06caSMauro Carvalho Chehab /* defines below are from ivtv-driver.h */
2380c0d06caSMauro Carvalho Chehab #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
2390c0d06caSMauro Carvalho Chehab 
2400c0d06caSMauro Carvalho Chehab /* Firmware API commands */
2410c0d06caSMauro Carvalho Chehab #define IVTV_API_STD_TIMEOUT 500
2420c0d06caSMauro Carvalho Chehab 
2430c0d06caSMauro Carvalho Chehab /* Registers */
2440c0d06caSMauro Carvalho Chehab /* IVTV_REG_OFFSET */
2450c0d06caSMauro Carvalho Chehab #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
2460c0d06caSMauro Carvalho Chehab #define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
2470c0d06caSMauro Carvalho Chehab #define IVTV_REG_SPU (0x9050)
2480c0d06caSMauro Carvalho Chehab #define IVTV_REG_HW_BLOCKS (0x9054)
2490c0d06caSMauro Carvalho Chehab #define IVTV_REG_VPU (0x9058)
2500c0d06caSMauro Carvalho Chehab #define IVTV_REG_APU (0xA064)
2510c0d06caSMauro Carvalho Chehab 
2520c0d06caSMauro Carvalho Chehab /*
2530c0d06caSMauro Carvalho Chehab  * Bit definitions for MC417_RWD and MC417_OEN registers
2540c0d06caSMauro Carvalho Chehab  *
2550c0d06caSMauro Carvalho Chehab  * bits 31-16
2560c0d06caSMauro Carvalho Chehab  *+-----------+
2570c0d06caSMauro Carvalho Chehab  *| Reserved  |
2580c0d06caSMauro Carvalho Chehab  *|+-----------+
2590c0d06caSMauro Carvalho Chehab  *|  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
2600c0d06caSMauro Carvalho Chehab  *|+-------+-------+-------+-------+-------+-------+-------+-------+
2610c0d06caSMauro Carvalho Chehab  *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
2620c0d06caSMauro Carvalho Chehab  *|+-------+-------+-------+-------+-------+-------+-------+-------+
2630c0d06caSMauro Carvalho Chehab  *| bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
2640c0d06caSMauro Carvalho Chehab  *|+-------+-------+-------+-------+-------+-------+-------+-------+
2650c0d06caSMauro Carvalho Chehab  *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
2660c0d06caSMauro Carvalho Chehab  *|+-------+-------+-------+-------+-------+-------+-------+-------+
2670c0d06caSMauro Carvalho Chehab  */
2680c0d06caSMauro Carvalho Chehab #define MC417_MIWR	0x8000
2690c0d06caSMauro Carvalho Chehab #define MC417_MIRD	0x4000
2700c0d06caSMauro Carvalho Chehab #define MC417_MICS	0x2000
2710c0d06caSMauro Carvalho Chehab #define MC417_MIRDY	0x1000
2720c0d06caSMauro Carvalho Chehab #define MC417_MIADDR	0x0F00
2730c0d06caSMauro Carvalho Chehab #define MC417_MIDATA	0x00FF
2740c0d06caSMauro Carvalho Chehab 
2750c0d06caSMauro Carvalho Chehab 
2760c0d06caSMauro Carvalho Chehab /* Bit definitions for MC417_CTL register ****
2770c0d06caSMauro Carvalho Chehab  *bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
2780c0d06caSMauro Carvalho Chehab  *+--------+-------------+--------+--------------+------------+
2790c0d06caSMauro Carvalho Chehab  *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
2800c0d06caSMauro Carvalho Chehab  *+--------+-------------+--------+--------------+------------+
2810c0d06caSMauro Carvalho Chehab  */
2820c0d06caSMauro Carvalho Chehab #define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
2830c0d06caSMauro Carvalho Chehab #define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
2840c0d06caSMauro Carvalho Chehab #define MC417_UART_GPIO_EN	0x00000001
2850c0d06caSMauro Carvalho Chehab 
2860c0d06caSMauro Carvalho Chehab /* Values for speed control */
2870c0d06caSMauro Carvalho Chehab #define MC417_SPD_CTL_SLOW	0x1
2880c0d06caSMauro Carvalho Chehab #define MC417_SPD_CTL_MEDIUM	0x0
2890c0d06caSMauro Carvalho Chehab #define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
2900c0d06caSMauro Carvalho Chehab 
2910c0d06caSMauro Carvalho Chehab /* Values for GPIO select */
2920c0d06caSMauro Carvalho Chehab #define MC417_GPIO_SEL_GPIO3	0x3
2930c0d06caSMauro Carvalho Chehab #define MC417_GPIO_SEL_GPIO2	0x2
2940c0d06caSMauro Carvalho Chehab #define MC417_GPIO_SEL_GPIO1	0x1
2950c0d06caSMauro Carvalho Chehab #define MC417_GPIO_SEL_GPIO0	0x0
2960c0d06caSMauro Carvalho Chehab 
2970c0d06caSMauro Carvalho Chehab 
2980c0d06caSMauro Carvalho Chehab #define CX23417_GPIO_MASK 0xFC0003FF
2990c0d06caSMauro Carvalho Chehab static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
3000c0d06caSMauro Carvalho Chehab {
3010c0d06caSMauro Carvalho Chehab 	int status = 0;
3020c0d06caSMauro Carvalho Chehab 	u32 _gpio_direction = 0;
3030c0d06caSMauro Carvalho Chehab 
3040c0d06caSMauro Carvalho Chehab 	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
3050c0d06caSMauro Carvalho Chehab 	_gpio_direction = _gpio_direction|gpio_direction;
3060c0d06caSMauro Carvalho Chehab 	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
3070c0d06caSMauro Carvalho Chehab 			 (u8 *)&value, 4, 0, 0);
3080c0d06caSMauro Carvalho Chehab 	return status;
3090c0d06caSMauro Carvalho Chehab }
3100c0d06caSMauro Carvalho Chehab static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
3110c0d06caSMauro Carvalho Chehab {
3120c0d06caSMauro Carvalho Chehab 	int status = 0;
3130c0d06caSMauro Carvalho Chehab 	u32 _gpio_direction = 0;
3140c0d06caSMauro Carvalho Chehab 
3150c0d06caSMauro Carvalho Chehab 	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
3160c0d06caSMauro Carvalho Chehab 	_gpio_direction = _gpio_direction|gpio_direction;
3170c0d06caSMauro Carvalho Chehab 
3180c0d06caSMauro Carvalho Chehab 	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
3190c0d06caSMauro Carvalho Chehab 		 (u8 *)pValue, 4, 0, 1);
3200c0d06caSMauro Carvalho Chehab 	return status;
3210c0d06caSMauro Carvalho Chehab }
3220c0d06caSMauro Carvalho Chehab 
3230c0d06caSMauro Carvalho Chehab static int waitForMciComplete(struct cx231xx *dev)
3240c0d06caSMauro Carvalho Chehab {
3250c0d06caSMauro Carvalho Chehab 	u32 gpio;
3260c0d06caSMauro Carvalho Chehab 	u32 gpio_driection = 0;
3270c0d06caSMauro Carvalho Chehab 	u8 count = 0;
3280c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, gpio_driection, &gpio);
3290c0d06caSMauro Carvalho Chehab 
3300c0d06caSMauro Carvalho Chehab 	while (!(gpio&0x020000)) {
3310c0d06caSMauro Carvalho Chehab 		msleep(10);
3320c0d06caSMauro Carvalho Chehab 
3330c0d06caSMauro Carvalho Chehab 		getITVCReg(dev, gpio_driection, &gpio);
3340c0d06caSMauro Carvalho Chehab 
3350c0d06caSMauro Carvalho Chehab 		if (count++ > 100) {
3360c0d06caSMauro Carvalho Chehab 			dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
3370c0d06caSMauro Carvalho Chehab 			return -1;
3380c0d06caSMauro Carvalho Chehab 		}
3390c0d06caSMauro Carvalho Chehab 	}
3400c0d06caSMauro Carvalho Chehab 	return 0;
3410c0d06caSMauro Carvalho Chehab }
3420c0d06caSMauro Carvalho Chehab 
3430c0d06caSMauro Carvalho Chehab static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
3440c0d06caSMauro Carvalho Chehab {
3450c0d06caSMauro Carvalho Chehab 	u32 temp;
3460c0d06caSMauro Carvalho Chehab 	int status = 0;
3470c0d06caSMauro Carvalho Chehab 
3480c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
3490c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3500c0d06caSMauro Carvalho Chehab 	status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
3510c0d06caSMauro Carvalho Chehab 	if (status < 0)
3520c0d06caSMauro Carvalho Chehab 		return status;
3530c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3540c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3550c0d06caSMauro Carvalho Chehab 
3560c0d06caSMauro Carvalho Chehab 	/*write data byte 1;*/
3570c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
3580c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3590c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3600c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3610c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3620c0d06caSMauro Carvalho Chehab 
3630c0d06caSMauro Carvalho Chehab 	/*write data byte 2;*/
3640c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
3650c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3660c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3670c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3680c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3690c0d06caSMauro Carvalho Chehab 
3700c0d06caSMauro Carvalho Chehab 	/*write data byte 3;*/
3710c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
3720c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3730c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3740c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3750c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3760c0d06caSMauro Carvalho Chehab 
3770c0d06caSMauro Carvalho Chehab 	/*write address byte 0;*/
3780c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
3790c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3800c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3810c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3820c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3830c0d06caSMauro Carvalho Chehab 
3840c0d06caSMauro Carvalho Chehab 	/*write address byte 1;*/
3850c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
3860c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3870c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3880c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3890c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3900c0d06caSMauro Carvalho Chehab 
3910c0d06caSMauro Carvalho Chehab 	/*Write that the mode is write.*/
3920c0d06caSMauro Carvalho Chehab 	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
3930c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
3940c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3950c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
3960c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
3970c0d06caSMauro Carvalho Chehab 
3980c0d06caSMauro Carvalho Chehab 	return waitForMciComplete(dev);
3990c0d06caSMauro Carvalho Chehab }
4000c0d06caSMauro Carvalho Chehab 
4010c0d06caSMauro Carvalho Chehab static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
4020c0d06caSMauro Carvalho Chehab {
4030c0d06caSMauro Carvalho Chehab 	/*write address byte 0;*/
4040c0d06caSMauro Carvalho Chehab 	u32 temp;
4050c0d06caSMauro Carvalho Chehab 	u32 return_value = 0;
4060c0d06caSMauro Carvalho Chehab 	int ret = 0;
4070c0d06caSMauro Carvalho Chehab 
4080c0d06caSMauro Carvalho Chehab 	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
4090c0d06caSMauro Carvalho Chehab 	temp = temp << 10;
4100c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4110c0d06caSMauro Carvalho Chehab 	temp = temp | ((0x05) << 10);
4120c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4130c0d06caSMauro Carvalho Chehab 
4140c0d06caSMauro Carvalho Chehab 	/*write address byte 1;*/
4150c0d06caSMauro Carvalho Chehab 	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
4160c0d06caSMauro Carvalho Chehab 	temp = temp << 10;
4170c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4180c0d06caSMauro Carvalho Chehab 	temp = temp | ((0x05) << 10);
4190c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4200c0d06caSMauro Carvalho Chehab 
4210c0d06caSMauro Carvalho Chehab 	/*write that the mode is read;*/
4220c0d06caSMauro Carvalho Chehab 	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
4230c0d06caSMauro Carvalho Chehab 	temp = temp << 10;
4240c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4250c0d06caSMauro Carvalho Chehab 	temp = temp | ((0x05) << 10);
4260c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4270c0d06caSMauro Carvalho Chehab 
4280c0d06caSMauro Carvalho Chehab 	/*wait for the MIRDY line to be asserted ,
4290c0d06caSMauro Carvalho Chehab 	signalling that the read is done;*/
4300c0d06caSMauro Carvalho Chehab 	ret = waitForMciComplete(dev);
4310c0d06caSMauro Carvalho Chehab 
4320c0d06caSMauro Carvalho Chehab 	/*switch the DATA- GPIO to input mode;*/
4330c0d06caSMauro Carvalho Chehab 
4340c0d06caSMauro Carvalho Chehab 	/*Read data byte 0;*/
4350c0d06caSMauro Carvalho Chehab 	temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
4360c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4370c0d06caSMauro Carvalho Chehab 	temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
4380c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4390c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
4400c0d06caSMauro Carvalho Chehab 	return_value |= ((temp & 0x03FC0000) >> 18);
4410c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
4420c0d06caSMauro Carvalho Chehab 
4430c0d06caSMauro Carvalho Chehab 	/* Read data byte 1;*/
4440c0d06caSMauro Carvalho Chehab 	temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
4450c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4460c0d06caSMauro Carvalho Chehab 	temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
4470c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4480c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
4490c0d06caSMauro Carvalho Chehab 
4500c0d06caSMauro Carvalho Chehab 	return_value |= ((temp & 0x03FC0000) >> 10);
4510c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
4520c0d06caSMauro Carvalho Chehab 
4530c0d06caSMauro Carvalho Chehab 	/*Read data byte 2;*/
4540c0d06caSMauro Carvalho Chehab 	temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
4550c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4560c0d06caSMauro Carvalho Chehab 	temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
4570c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4580c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
4590c0d06caSMauro Carvalho Chehab 	return_value |= ((temp & 0x03FC0000) >> 2);
4600c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
4610c0d06caSMauro Carvalho Chehab 
4620c0d06caSMauro Carvalho Chehab 	/*Read data byte 3;*/
4630c0d06caSMauro Carvalho Chehab 	temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
4640c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4650c0d06caSMauro Carvalho Chehab 	temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
4660c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
4670c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
4680c0d06caSMauro Carvalho Chehab 	return_value |= ((temp & 0x03FC0000) << 6);
4690c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
4700c0d06caSMauro Carvalho Chehab 
4710c0d06caSMauro Carvalho Chehab 	*value  = return_value;
4720c0d06caSMauro Carvalho Chehab 
4730c0d06caSMauro Carvalho Chehab 
4740c0d06caSMauro Carvalho Chehab 	return ret;
4750c0d06caSMauro Carvalho Chehab }
4760c0d06caSMauro Carvalho Chehab 
4770c0d06caSMauro Carvalho Chehab static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
4780c0d06caSMauro Carvalho Chehab {
4790c0d06caSMauro Carvalho Chehab 	/*write data byte 0;*/
4800c0d06caSMauro Carvalho Chehab 
4810c0d06caSMauro Carvalho Chehab 	u32 temp;
4820c0d06caSMauro Carvalho Chehab 	int ret = 0;
4830c0d06caSMauro Carvalho Chehab 
4840c0d06caSMauro Carvalho Chehab 	temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
4850c0d06caSMauro Carvalho Chehab 	temp = temp << 10;
4860c0d06caSMauro Carvalho Chehab 	ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
4870c0d06caSMauro Carvalho Chehab 	if (ret < 0)
4880c0d06caSMauro Carvalho Chehab 		return ret;
4890c0d06caSMauro Carvalho Chehab 	temp = temp | ((0x05) << 10);
4900c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4910c0d06caSMauro Carvalho Chehab 
4920c0d06caSMauro Carvalho Chehab 	/*write data byte 1;*/
4930c0d06caSMauro Carvalho Chehab 	temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
4940c0d06caSMauro Carvalho Chehab 	temp = temp << 10;
4950c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4960c0d06caSMauro Carvalho Chehab 	temp = temp | ((0x05) << 10);
4970c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
4980c0d06caSMauro Carvalho Chehab 
4990c0d06caSMauro Carvalho Chehab 	/*write data byte 2;*/
5000c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
5010c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5020c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5030c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5040c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5050c0d06caSMauro Carvalho Chehab 
5060c0d06caSMauro Carvalho Chehab 	/*write data byte 3;*/
5070c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
5080c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5090c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5100c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5110c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5120c0d06caSMauro Carvalho Chehab 
5130c0d06caSMauro Carvalho Chehab 	/* write address byte 2;*/
5140c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
5150c0d06caSMauro Carvalho Chehab 		((address & 0x003F0000)>>8);
5160c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5170c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5180c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5190c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5200c0d06caSMauro Carvalho Chehab 
5210c0d06caSMauro Carvalho Chehab 	/* write address byte 1;*/
5220c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
5230c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5240c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5250c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5260c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5270c0d06caSMauro Carvalho Chehab 
5280c0d06caSMauro Carvalho Chehab 	/* write address byte 0;*/
5290c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
5300c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5310c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5320c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5330c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5340c0d06caSMauro Carvalho Chehab 
5350c0d06caSMauro Carvalho Chehab 	/*wait for MIRDY line;*/
5360c0d06caSMauro Carvalho Chehab 	waitForMciComplete(dev);
5370c0d06caSMauro Carvalho Chehab 
5380c0d06caSMauro Carvalho Chehab 	return 0;
5390c0d06caSMauro Carvalho Chehab }
5400c0d06caSMauro Carvalho Chehab 
5410c0d06caSMauro Carvalho Chehab static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
5420c0d06caSMauro Carvalho Chehab {
5430c0d06caSMauro Carvalho Chehab 	u32 temp = 0;
5440c0d06caSMauro Carvalho Chehab 	u32 return_value = 0;
5450c0d06caSMauro Carvalho Chehab 	int ret = 0;
5460c0d06caSMauro Carvalho Chehab 
5470c0d06caSMauro Carvalho Chehab 	/*write address byte 2;*/
5480c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
5490c0d06caSMauro Carvalho Chehab 		((address & 0x003F0000)>>8);
5500c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5510c0d06caSMauro Carvalho Chehab 	ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
5520c0d06caSMauro Carvalho Chehab 	if (ret < 0)
5530c0d06caSMauro Carvalho Chehab 		return ret;
5540c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5550c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5560c0d06caSMauro Carvalho Chehab 
5570c0d06caSMauro Carvalho Chehab 	/*write address byte 1*/
5580c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
5590c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5600c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5610c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5620c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5630c0d06caSMauro Carvalho Chehab 
5640c0d06caSMauro Carvalho Chehab 	/*write address byte 0*/
5650c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
5660c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
5670c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5680c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
5690c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_WRITE_DIR, temp);
5700c0d06caSMauro Carvalho Chehab 
5710c0d06caSMauro Carvalho Chehab 	/*Wait for MIRDY line*/
5720c0d06caSMauro Carvalho Chehab 	ret = waitForMciComplete(dev);
5730c0d06caSMauro Carvalho Chehab 
5740c0d06caSMauro Carvalho Chehab 
5750c0d06caSMauro Carvalho Chehab 	/*Read data byte 3;*/
5760c0d06caSMauro Carvalho Chehab 	temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
5770c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
5780c0d06caSMauro Carvalho Chehab 	temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
5790c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
5800c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
5810c0d06caSMauro Carvalho Chehab 	return_value |= ((temp&0x03FC0000)<<6);
5820c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
5830c0d06caSMauro Carvalho Chehab 
5840c0d06caSMauro Carvalho Chehab 	/*Read data byte 2;*/
5850c0d06caSMauro Carvalho Chehab 	temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
5860c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
5870c0d06caSMauro Carvalho Chehab 	temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
5880c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
5890c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
5900c0d06caSMauro Carvalho Chehab 	return_value |= ((temp&0x03FC0000)>>2);
5910c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
5920c0d06caSMauro Carvalho Chehab 
5930c0d06caSMauro Carvalho Chehab 	/* Read data byte 1;*/
5940c0d06caSMauro Carvalho Chehab 	temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
5950c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
5960c0d06caSMauro Carvalho Chehab 	temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
5970c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
5980c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
5990c0d06caSMauro Carvalho Chehab 	return_value |= ((temp&0x03FC0000)>>10);
6000c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
6010c0d06caSMauro Carvalho Chehab 
6020c0d06caSMauro Carvalho Chehab 	/*Read data byte 0;*/
6030c0d06caSMauro Carvalho Chehab 	temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
6040c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
6050c0d06caSMauro Carvalho Chehab 	temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
6060c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, temp);
6070c0d06caSMauro Carvalho Chehab 	getITVCReg(dev, ITVC_READ_DIR, &temp);
6080c0d06caSMauro Carvalho Chehab 	return_value |= ((temp&0x03FC0000)>>18);
6090c0d06caSMauro Carvalho Chehab 	setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
6100c0d06caSMauro Carvalho Chehab 
6110c0d06caSMauro Carvalho Chehab 	*value  = return_value;
6120c0d06caSMauro Carvalho Chehab 	return ret;
6130c0d06caSMauro Carvalho Chehab }
6140c0d06caSMauro Carvalho Chehab 
6150c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
6160c0d06caSMauro Carvalho Chehab 
6170c0d06caSMauro Carvalho Chehab /* MPEG encoder API */
6180c0d06caSMauro Carvalho Chehab static char *cmd_to_str(int cmd)
6190c0d06caSMauro Carvalho Chehab {
6200c0d06caSMauro Carvalho Chehab 	switch (cmd) {
6210c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_PING_FW:
6220c0d06caSMauro Carvalho Chehab 		return  "PING_FW";
6230c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_START_CAPTURE:
6240c0d06caSMauro Carvalho Chehab 		return  "START_CAPTURE";
6250c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_STOP_CAPTURE:
6260c0d06caSMauro Carvalho Chehab 		return  "STOP_CAPTURE";
6270c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_AUDIO_ID:
6280c0d06caSMauro Carvalho Chehab 		return  "SET_AUDIO_ID";
6290c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_VIDEO_ID:
6300c0d06caSMauro Carvalho Chehab 		return  "SET_VIDEO_ID";
6310c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_PCR_ID:
6320c0d06caSMauro Carvalho Chehab 		return  "SET_PCR_PID";
6330c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_FRAME_RATE:
6340c0d06caSMauro Carvalho Chehab 		return  "SET_FRAME_RATE";
6350c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_FRAME_SIZE:
6360c0d06caSMauro Carvalho Chehab 		return  "SET_FRAME_SIZE";
6370c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_BIT_RATE:
6380c0d06caSMauro Carvalho Chehab 		return  "SET_BIT_RATE";
6390c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_GOP_PROPERTIES:
6400c0d06caSMauro Carvalho Chehab 		return  "SET_GOP_PROPERTIES";
6410c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_ASPECT_RATIO:
6420c0d06caSMauro Carvalho Chehab 		return  "SET_ASPECT_RATIO";
6430c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_DNR_FILTER_MODE:
6440c0d06caSMauro Carvalho Chehab 		return  "SET_DNR_FILTER_PROPS";
6450c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
6460c0d06caSMauro Carvalho Chehab 		return  "SET_DNR_FILTER_PROPS";
6470c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_CORING_LEVELS:
6480c0d06caSMauro Carvalho Chehab 		return  "SET_CORING_LEVELS";
6490c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
6500c0d06caSMauro Carvalho Chehab 		return  "SET_SPATIAL_FILTER_TYPE";
6510c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_VBI_LINE:
6520c0d06caSMauro Carvalho Chehab 		return  "SET_VBI_LINE";
6530c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_STREAM_TYPE:
6540c0d06caSMauro Carvalho Chehab 		return  "SET_STREAM_TYPE";
6550c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_OUTPUT_PORT:
6560c0d06caSMauro Carvalho Chehab 		return  "SET_OUTPUT_PORT";
6570c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
6580c0d06caSMauro Carvalho Chehab 		return  "SET_AUDIO_PROPERTIES";
6590c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_HALT_FW:
6600c0d06caSMauro Carvalho Chehab 		return  "HALT_FW";
6610c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_GET_VERSION:
6620c0d06caSMauro Carvalho Chehab 		return  "GET_VERSION";
6630c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_GOP_CLOSURE:
6640c0d06caSMauro Carvalho Chehab 		return  "SET_GOP_CLOSURE";
6650c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_GET_SEQ_END:
6660c0d06caSMauro Carvalho Chehab 		return  "GET_SEQ_END";
6670c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_PGM_INDEX_INFO:
6680c0d06caSMauro Carvalho Chehab 		return  "SET_PGM_INDEX_INFO";
6690c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_VBI_CONFIG:
6700c0d06caSMauro Carvalho Chehab 		return  "SET_VBI_CONFIG";
6710c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
6720c0d06caSMauro Carvalho Chehab 		return  "SET_DMA_BLOCK_SIZE";
6730c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
6740c0d06caSMauro Carvalho Chehab 		return  "GET_PREV_DMA_INFO_MB_10";
6750c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
6760c0d06caSMauro Carvalho Chehab 		return  "GET_PREV_DMA_INFO_MB_9";
6770c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SCHED_DMA_TO_HOST:
6780c0d06caSMauro Carvalho Chehab 		return  "SCHED_DMA_TO_HOST";
6790c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_INITIALIZE_INPUT:
6800c0d06caSMauro Carvalho Chehab 		return  "INITIALIZE_INPUT";
6810c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_FRAME_DROP_RATE:
6820c0d06caSMauro Carvalho Chehab 		return  "SET_FRAME_DROP_RATE";
6830c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_PAUSE_ENCODER:
6840c0d06caSMauro Carvalho Chehab 		return  "PAUSE_ENCODER";
6850c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_REFRESH_INPUT:
6860c0d06caSMauro Carvalho Chehab 		return  "REFRESH_INPUT";
6870c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_COPYRIGHT:
6880c0d06caSMauro Carvalho Chehab 		return  "SET_COPYRIGHT";
6890c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
6900c0d06caSMauro Carvalho Chehab 		return  "SET_EVENT_NOTIFICATION";
6910c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
6920c0d06caSMauro Carvalho Chehab 		return  "SET_NUM_VSYNC_LINES";
6930c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_SET_PLACEHOLDER:
6940c0d06caSMauro Carvalho Chehab 		return  "SET_PLACEHOLDER";
6950c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_MUTE_VIDEO:
6960c0d06caSMauro Carvalho Chehab 		return  "MUTE_VIDEO";
6970c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_MUTE_AUDIO:
6980c0d06caSMauro Carvalho Chehab 		return  "MUTE_AUDIO";
6990c0d06caSMauro Carvalho Chehab 	case CX2341X_ENC_MISC:
7000c0d06caSMauro Carvalho Chehab 		return  "MISC";
7010c0d06caSMauro Carvalho Chehab 	default:
7020c0d06caSMauro Carvalho Chehab 		return "UNKNOWN";
7030c0d06caSMauro Carvalho Chehab 	}
7040c0d06caSMauro Carvalho Chehab }
7050c0d06caSMauro Carvalho Chehab 
7060c0d06caSMauro Carvalho Chehab static int cx231xx_mbox_func(void *priv,
7070c0d06caSMauro Carvalho Chehab 			     u32 command,
7080c0d06caSMauro Carvalho Chehab 			     int in,
7090c0d06caSMauro Carvalho Chehab 			     int out,
7100c0d06caSMauro Carvalho Chehab 			     u32 data[CX2341X_MBOX_MAX_DATA])
7110c0d06caSMauro Carvalho Chehab {
7120c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = priv;
7130c0d06caSMauro Carvalho Chehab 	unsigned long timeout;
7140c0d06caSMauro Carvalho Chehab 	u32 value, flag, retval = 0;
7150c0d06caSMauro Carvalho Chehab 	int i;
7160c0d06caSMauro Carvalho Chehab 
7170c0d06caSMauro Carvalho Chehab 	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
7180c0d06caSMauro Carvalho Chehab 		cmd_to_str(command));
7190c0d06caSMauro Carvalho Chehab 
7200c0d06caSMauro Carvalho Chehab 	/* this may not be 100% safe if we can't read any memory location
7210c0d06caSMauro Carvalho Chehab 	   without side effects */
7220c0d06caSMauro Carvalho Chehab 	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
7230c0d06caSMauro Carvalho Chehab 	if (value != 0x12345678) {
7240c0d06caSMauro Carvalho Chehab 		dprintk(3,
7250c0d06caSMauro Carvalho Chehab 			"Firmware and/or mailbox pointer not initialized "
7260c0d06caSMauro Carvalho Chehab 			"or corrupted, signature = 0x%x, cmd = %s\n", value,
7270c0d06caSMauro Carvalho Chehab 			cmd_to_str(command));
7280c0d06caSMauro Carvalho Chehab 		return -1;
7290c0d06caSMauro Carvalho Chehab 	}
7300c0d06caSMauro Carvalho Chehab 
7310c0d06caSMauro Carvalho Chehab 	/* This read looks at 32 bits, but flag is only 8 bits.
7320c0d06caSMauro Carvalho Chehab 	 * Seems we also bail if CMD or TIMEOUT bytes are set???
7330c0d06caSMauro Carvalho Chehab 	 */
7340c0d06caSMauro Carvalho Chehab 	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
7350c0d06caSMauro Carvalho Chehab 	if (flag) {
7360c0d06caSMauro Carvalho Chehab 		dprintk(3, "ERROR: Mailbox appears to be in use "
7370c0d06caSMauro Carvalho Chehab 			"(%x), cmd = %s\n", flag, cmd_to_str(command));
7380c0d06caSMauro Carvalho Chehab 		return -1;
7390c0d06caSMauro Carvalho Chehab 	}
7400c0d06caSMauro Carvalho Chehab 
7410c0d06caSMauro Carvalho Chehab 	flag |= 1; /* tell 'em we're working on it */
7420c0d06caSMauro Carvalho Chehab 	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
7430c0d06caSMauro Carvalho Chehab 
7440c0d06caSMauro Carvalho Chehab 	/* write command + args + fill remaining with zeros */
7450c0d06caSMauro Carvalho Chehab 	/* command code */
7460c0d06caSMauro Carvalho Chehab 	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
7470c0d06caSMauro Carvalho Chehab 	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
7480c0d06caSMauro Carvalho Chehab 		IVTV_API_STD_TIMEOUT); /* timeout */
7490c0d06caSMauro Carvalho Chehab 	for (i = 0; i < in; i++) {
7500c0d06caSMauro Carvalho Chehab 		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
7510c0d06caSMauro Carvalho Chehab 		dprintk(3, "API Input %d = %d\n", i, data[i]);
7520c0d06caSMauro Carvalho Chehab 	}
7530c0d06caSMauro Carvalho Chehab 	for (; i < CX2341X_MBOX_MAX_DATA; i++)
7540c0d06caSMauro Carvalho Chehab 		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
7550c0d06caSMauro Carvalho Chehab 
7560c0d06caSMauro Carvalho Chehab 	flag |= 3; /* tell 'em we're done writing */
7570c0d06caSMauro Carvalho Chehab 	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
7580c0d06caSMauro Carvalho Chehab 
7590c0d06caSMauro Carvalho Chehab 	/* wait for firmware to handle the API command */
7600c0d06caSMauro Carvalho Chehab 	timeout = jiffies + msecs_to_jiffies(10);
7610c0d06caSMauro Carvalho Chehab 	for (;;) {
7620c0d06caSMauro Carvalho Chehab 		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
7630c0d06caSMauro Carvalho Chehab 		if (0 != (flag & 4))
7640c0d06caSMauro Carvalho Chehab 			break;
7650c0d06caSMauro Carvalho Chehab 		if (time_after(jiffies, timeout)) {
7660c0d06caSMauro Carvalho Chehab 			dprintk(3, "ERROR: API Mailbox timeout\n");
7670c0d06caSMauro Carvalho Chehab 			return -1;
7680c0d06caSMauro Carvalho Chehab 		}
7690c0d06caSMauro Carvalho Chehab 		udelay(10);
7700c0d06caSMauro Carvalho Chehab 	}
7710c0d06caSMauro Carvalho Chehab 
7720c0d06caSMauro Carvalho Chehab 	/* read output values */
7730c0d06caSMauro Carvalho Chehab 	for (i = 0; i < out; i++) {
7740c0d06caSMauro Carvalho Chehab 		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
7750c0d06caSMauro Carvalho Chehab 		dprintk(3, "API Output %d = %d\n", i, data[i]);
7760c0d06caSMauro Carvalho Chehab 	}
7770c0d06caSMauro Carvalho Chehab 
7780c0d06caSMauro Carvalho Chehab 	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
7790c0d06caSMauro Carvalho Chehab 	dprintk(3, "API result = %d\n", retval);
7800c0d06caSMauro Carvalho Chehab 
7810c0d06caSMauro Carvalho Chehab 	flag = 0;
7820c0d06caSMauro Carvalho Chehab 	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
7830c0d06caSMauro Carvalho Chehab 
7840c0d06caSMauro Carvalho Chehab 	return retval;
7850c0d06caSMauro Carvalho Chehab }
7860c0d06caSMauro Carvalho Chehab 
7870c0d06caSMauro Carvalho Chehab /* We don't need to call the API often, so using just one
7880c0d06caSMauro Carvalho Chehab  * mailbox will probably suffice
7890c0d06caSMauro Carvalho Chehab  */
7900c0d06caSMauro Carvalho Chehab static int cx231xx_api_cmd(struct cx231xx *dev,
7910c0d06caSMauro Carvalho Chehab 			   u32 command,
7920c0d06caSMauro Carvalho Chehab 			   u32 inputcnt,
7930c0d06caSMauro Carvalho Chehab 			   u32 outputcnt,
7940c0d06caSMauro Carvalho Chehab 			   ...)
7950c0d06caSMauro Carvalho Chehab {
7960c0d06caSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
7970c0d06caSMauro Carvalho Chehab 	va_list vargs;
7980c0d06caSMauro Carvalho Chehab 	int i, err;
7990c0d06caSMauro Carvalho Chehab 
8000c0d06caSMauro Carvalho Chehab 	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
8010c0d06caSMauro Carvalho Chehab 
8020c0d06caSMauro Carvalho Chehab 	va_start(vargs, outputcnt);
8030c0d06caSMauro Carvalho Chehab 	for (i = 0; i < inputcnt; i++)
8040c0d06caSMauro Carvalho Chehab 		data[i] = va_arg(vargs, int);
8050c0d06caSMauro Carvalho Chehab 
8060c0d06caSMauro Carvalho Chehab 	err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
8070c0d06caSMauro Carvalho Chehab 	for (i = 0; i < outputcnt; i++) {
8080c0d06caSMauro Carvalho Chehab 		int *vptr = va_arg(vargs, int *);
8090c0d06caSMauro Carvalho Chehab 		*vptr = data[i];
8100c0d06caSMauro Carvalho Chehab 	}
8110c0d06caSMauro Carvalho Chehab 	va_end(vargs);
8120c0d06caSMauro Carvalho Chehab 
8130c0d06caSMauro Carvalho Chehab 	return err;
8140c0d06caSMauro Carvalho Chehab }
8150c0d06caSMauro Carvalho Chehab 
8160c0d06caSMauro Carvalho Chehab static int cx231xx_find_mailbox(struct cx231xx *dev)
8170c0d06caSMauro Carvalho Chehab {
8180c0d06caSMauro Carvalho Chehab 	u32 signature[4] = {
8190c0d06caSMauro Carvalho Chehab 		0x12345678, 0x34567812, 0x56781234, 0x78123456
8200c0d06caSMauro Carvalho Chehab 	};
8210c0d06caSMauro Carvalho Chehab 	int signaturecnt = 0;
8220c0d06caSMauro Carvalho Chehab 	u32 value;
8230c0d06caSMauro Carvalho Chehab 	int i;
8240c0d06caSMauro Carvalho Chehab 	int ret = 0;
8250c0d06caSMauro Carvalho Chehab 
8260c0d06caSMauro Carvalho Chehab 	dprintk(2, "%s()\n", __func__);
8270c0d06caSMauro Carvalho Chehab 
8280c0d06caSMauro Carvalho Chehab 	for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
8290c0d06caSMauro Carvalho Chehab 		ret = mc417_memory_read(dev, i, &value);
8300c0d06caSMauro Carvalho Chehab 		if (ret < 0)
8310c0d06caSMauro Carvalho Chehab 			return ret;
8320c0d06caSMauro Carvalho Chehab 		if (value == signature[signaturecnt])
8330c0d06caSMauro Carvalho Chehab 			signaturecnt++;
8340c0d06caSMauro Carvalho Chehab 		else
8350c0d06caSMauro Carvalho Chehab 			signaturecnt = 0;
8360c0d06caSMauro Carvalho Chehab 		if (4 == signaturecnt) {
8370c0d06caSMauro Carvalho Chehab 			dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
8380c0d06caSMauro Carvalho Chehab 			return i+1;
8390c0d06caSMauro Carvalho Chehab 		}
8400c0d06caSMauro Carvalho Chehab 	}
8410c0d06caSMauro Carvalho Chehab 	dprintk(3, "Mailbox signature values not found!\n");
8420c0d06caSMauro Carvalho Chehab 	return -1;
8430c0d06caSMauro Carvalho Chehab }
8440c0d06caSMauro Carvalho Chehab 
8450c0d06caSMauro Carvalho Chehab static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
8460c0d06caSMauro Carvalho Chehab 		u32 *p_fw_image)
8470c0d06caSMauro Carvalho Chehab {
8480c0d06caSMauro Carvalho Chehab 
8490c0d06caSMauro Carvalho Chehab 	u32 temp = 0;
8500c0d06caSMauro Carvalho Chehab 	int i = 0;
8510c0d06caSMauro Carvalho Chehab 
8520c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
8530c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
8540c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8550c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8560c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
8570c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8580c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8590c0d06caSMauro Carvalho Chehab 
8600c0d06caSMauro Carvalho Chehab 	/*write data byte 1;*/
8610c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
8620c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
8630c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8640c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8650c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
8660c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8670c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8680c0d06caSMauro Carvalho Chehab 
8690c0d06caSMauro Carvalho Chehab 	/*write data byte 2;*/
8700c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
8710c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
8720c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8730c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8740c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
8750c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8760c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8770c0d06caSMauro Carvalho Chehab 
8780c0d06caSMauro Carvalho Chehab 	/*write data byte 3;*/
8790c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
8800c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
8810c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8820c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8830c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
8840c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8850c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8860c0d06caSMauro Carvalho Chehab 
8870c0d06caSMauro Carvalho Chehab 	/* write address byte 2;*/
8880c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
8890c0d06caSMauro Carvalho Chehab 		((address & 0x003F0000)>>8);
8900c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
8910c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8920c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8930c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
8940c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
8950c0d06caSMauro Carvalho Chehab 	p_fw_image++;
8960c0d06caSMauro Carvalho Chehab 
8970c0d06caSMauro Carvalho Chehab 	/* write address byte 1;*/
8980c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
8990c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
9000c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
9010c0d06caSMauro Carvalho Chehab 	p_fw_image++;
9020c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
9030c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
9040c0d06caSMauro Carvalho Chehab 	p_fw_image++;
9050c0d06caSMauro Carvalho Chehab 
9060c0d06caSMauro Carvalho Chehab 	/* write address byte 0;*/
9070c0d06caSMauro Carvalho Chehab 	temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
9080c0d06caSMauro Carvalho Chehab 	temp = temp<<10;
9090c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
9100c0d06caSMauro Carvalho Chehab 	p_fw_image++;
9110c0d06caSMauro Carvalho Chehab 	temp = temp|((0x05)<<10);
9120c0d06caSMauro Carvalho Chehab 	*p_fw_image = temp;
9130c0d06caSMauro Carvalho Chehab 	p_fw_image++;
9140c0d06caSMauro Carvalho Chehab 
9150c0d06caSMauro Carvalho Chehab 	for (i = 0; i < 6; i++) {
9160c0d06caSMauro Carvalho Chehab 		*p_fw_image = 0xFFFFFFFF;
9170c0d06caSMauro Carvalho Chehab 		p_fw_image++;
9180c0d06caSMauro Carvalho Chehab 	}
9190c0d06caSMauro Carvalho Chehab }
9200c0d06caSMauro Carvalho Chehab 
9210c0d06caSMauro Carvalho Chehab 
9220c0d06caSMauro Carvalho Chehab static int cx231xx_load_firmware(struct cx231xx *dev)
9230c0d06caSMauro Carvalho Chehab {
9240c0d06caSMauro Carvalho Chehab 	static const unsigned char magic[8] = {
9250c0d06caSMauro Carvalho Chehab 		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
9260c0d06caSMauro Carvalho Chehab 	};
9270c0d06caSMauro Carvalho Chehab 	const struct firmware *firmware;
9280c0d06caSMauro Carvalho Chehab 	int i, retval = 0;
9290c0d06caSMauro Carvalho Chehab 	u32 value = 0;
9300c0d06caSMauro Carvalho Chehab 	u32 gpio_output = 0;
9310c0d06caSMauro Carvalho Chehab 	/*u32 checksum = 0;*/
9320c0d06caSMauro Carvalho Chehab 	/*u32 *dataptr;*/
9330c0d06caSMauro Carvalho Chehab 	u32 transfer_size = 0;
9340c0d06caSMauro Carvalho Chehab 	u32 fw_data = 0;
9350c0d06caSMauro Carvalho Chehab 	u32 address = 0;
9360c0d06caSMauro Carvalho Chehab 	/*u32 current_fw[800];*/
9370c0d06caSMauro Carvalho Chehab 	u32 *p_current_fw, *p_fw;
9380c0d06caSMauro Carvalho Chehab 	u32 *p_fw_data;
9390c0d06caSMauro Carvalho Chehab 	int frame = 0;
9400c0d06caSMauro Carvalho Chehab 	u16 _buffer_size = 4096;
9410c0d06caSMauro Carvalho Chehab 	u8 *p_buffer;
9420c0d06caSMauro Carvalho Chehab 
9430c0d06caSMauro Carvalho Chehab 	p_current_fw = vmalloc(1884180 * 4);
9440c0d06caSMauro Carvalho Chehab 	p_fw = p_current_fw;
9450c0d06caSMauro Carvalho Chehab 	if (p_current_fw == NULL) {
9460c0d06caSMauro Carvalho Chehab 		dprintk(2, "FAIL!!!\n");
9470c0d06caSMauro Carvalho Chehab 		return -1;
9480c0d06caSMauro Carvalho Chehab 	}
9490c0d06caSMauro Carvalho Chehab 
9500c0d06caSMauro Carvalho Chehab 	p_buffer = vmalloc(4096);
9510c0d06caSMauro Carvalho Chehab 	if (p_buffer == NULL) {
9520c0d06caSMauro Carvalho Chehab 		dprintk(2, "FAIL!!!\n");
9530c0d06caSMauro Carvalho Chehab 		return -1;
9540c0d06caSMauro Carvalho Chehab 	}
9550c0d06caSMauro Carvalho Chehab 
9560c0d06caSMauro Carvalho Chehab 	dprintk(2, "%s()\n", __func__);
9570c0d06caSMauro Carvalho Chehab 
9580c0d06caSMauro Carvalho Chehab 	/* Save GPIO settings before reset of APU */
9590c0d06caSMauro Carvalho Chehab 	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
9600c0d06caSMauro Carvalho Chehab 	retval |= mc417_memory_read(dev, 0x900C, &value);
9610c0d06caSMauro Carvalho Chehab 
9620c0d06caSMauro Carvalho Chehab 	retval  = mc417_register_write(dev,
9630c0d06caSMauro Carvalho Chehab 		IVTV_REG_VPU, 0xFFFFFFED);
9640c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev,
9650c0d06caSMauro Carvalho Chehab 		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
9660c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev,
9670c0d06caSMauro Carvalho Chehab 		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
9680c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev,
9690c0d06caSMauro Carvalho Chehab 		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
9700c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev,
9710c0d06caSMauro Carvalho Chehab 		IVTV_REG_APU, 0);
9720c0d06caSMauro Carvalho Chehab 
9730c0d06caSMauro Carvalho Chehab 	if (retval != 0) {
9740c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "%s: Error with mc417_register_write\n",
9750c0d06caSMauro Carvalho Chehab 			__func__);
9760c0d06caSMauro Carvalho Chehab 		return -1;
9770c0d06caSMauro Carvalho Chehab 	}
9780c0d06caSMauro Carvalho Chehab 
9790c0d06caSMauro Carvalho Chehab 	retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
9800c0d06caSMauro Carvalho Chehab 				  &dev->udev->dev);
9810c0d06caSMauro Carvalho Chehab 
9820c0d06caSMauro Carvalho Chehab 	if (retval != 0) {
9830c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR
9840c0d06caSMauro Carvalho Chehab 			"ERROR: Hotplug firmware request failed (%s).\n",
9850c0d06caSMauro Carvalho Chehab 			CX231xx_FIRM_IMAGE_NAME);
9860c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "Please fix your hotplug setup, the board will "
9870c0d06caSMauro Carvalho Chehab 			"not work without firmware loaded!\n");
9880c0d06caSMauro Carvalho Chehab 		return -1;
9890c0d06caSMauro Carvalho Chehab 	}
9900c0d06caSMauro Carvalho Chehab 
9910c0d06caSMauro Carvalho Chehab 	if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
9920c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "ERROR: Firmware size mismatch "
9930c0d06caSMauro Carvalho Chehab 			"(have %zd, expected %d)\n",
9940c0d06caSMauro Carvalho Chehab 			firmware->size, CX231xx_FIRM_IMAGE_SIZE);
9950c0d06caSMauro Carvalho Chehab 		release_firmware(firmware);
9960c0d06caSMauro Carvalho Chehab 		return -1;
9970c0d06caSMauro Carvalho Chehab 	}
9980c0d06caSMauro Carvalho Chehab 
9990c0d06caSMauro Carvalho Chehab 	if (0 != memcmp(firmware->data, magic, 8)) {
10000c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR
10010c0d06caSMauro Carvalho Chehab 			"ERROR: Firmware magic mismatch, wrong file?\n");
10020c0d06caSMauro Carvalho Chehab 		release_firmware(firmware);
10030c0d06caSMauro Carvalho Chehab 		return -1;
10040c0d06caSMauro Carvalho Chehab 	}
10050c0d06caSMauro Carvalho Chehab 
10060c0d06caSMauro Carvalho Chehab 	initGPIO(dev);
10070c0d06caSMauro Carvalho Chehab 
10080c0d06caSMauro Carvalho Chehab 	/* transfer to the chip */
10090c0d06caSMauro Carvalho Chehab 	dprintk(2, "Loading firmware to GPIO...\n");
10100c0d06caSMauro Carvalho Chehab 	p_fw_data = (u32 *)firmware->data;
10110c0d06caSMauro Carvalho Chehab 	dprintk(2, "firmware->size=%zd\n", firmware->size);
10120c0d06caSMauro Carvalho Chehab 	for (transfer_size = 0; transfer_size < firmware->size;
10130c0d06caSMauro Carvalho Chehab 		 transfer_size += 4) {
10140c0d06caSMauro Carvalho Chehab 		fw_data = *p_fw_data;
10150c0d06caSMauro Carvalho Chehab 
10160c0d06caSMauro Carvalho Chehab 		 mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
10170c0d06caSMauro Carvalho Chehab 		address = address + 1;
10180c0d06caSMauro Carvalho Chehab 		p_current_fw += 20;
10190c0d06caSMauro Carvalho Chehab 		p_fw_data += 1;
10200c0d06caSMauro Carvalho Chehab 	}
10210c0d06caSMauro Carvalho Chehab 
10220c0d06caSMauro Carvalho Chehab 	/*download the firmware by ep5-out*/
10230c0d06caSMauro Carvalho Chehab 
10240c0d06caSMauro Carvalho Chehab 	for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
10250c0d06caSMauro Carvalho Chehab 	     frame++) {
10260c0d06caSMauro Carvalho Chehab 		for (i = 0; i < _buffer_size; i++) {
10270c0d06caSMauro Carvalho Chehab 			*(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
10280c0d06caSMauro Carvalho Chehab 			i++;
10290c0d06caSMauro Carvalho Chehab 			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
10300c0d06caSMauro Carvalho Chehab 			i++;
10310c0d06caSMauro Carvalho Chehab 			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
10320c0d06caSMauro Carvalho Chehab 			i++;
10330c0d06caSMauro Carvalho Chehab 			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
10340c0d06caSMauro Carvalho Chehab 		}
10350c0d06caSMauro Carvalho Chehab 		cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
10360c0d06caSMauro Carvalho Chehab 	}
10370c0d06caSMauro Carvalho Chehab 
10380c0d06caSMauro Carvalho Chehab 	p_current_fw = p_fw;
10390c0d06caSMauro Carvalho Chehab 	vfree(p_current_fw);
10400c0d06caSMauro Carvalho Chehab 	p_current_fw = NULL;
10410c0d06caSMauro Carvalho Chehab 	uninitGPIO(dev);
10420c0d06caSMauro Carvalho Chehab 	release_firmware(firmware);
10430c0d06caSMauro Carvalho Chehab 	dprintk(1, "Firmware upload successful.\n");
10440c0d06caSMauro Carvalho Chehab 
10450c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
10460c0d06caSMauro Carvalho Chehab 		IVTV_CMD_HW_BLOCKS_RST);
10470c0d06caSMauro Carvalho Chehab 	if (retval < 0) {
10480c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "%s: Error with mc417_register_write\n",
10490c0d06caSMauro Carvalho Chehab 			__func__);
10500c0d06caSMauro Carvalho Chehab 		return retval;
10510c0d06caSMauro Carvalho Chehab 	}
10520c0d06caSMauro Carvalho Chehab 	/* F/W power up disturbs the GPIOs, restore state */
10530c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev, 0x9020, gpio_output);
10540c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev, 0x900C, value);
10550c0d06caSMauro Carvalho Chehab 
10560c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
10570c0d06caSMauro Carvalho Chehab 	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
10580c0d06caSMauro Carvalho Chehab 
10590c0d06caSMauro Carvalho Chehab 	if (retval < 0) {
10600c0d06caSMauro Carvalho Chehab 		printk(KERN_ERR "%s: Error with mc417_register_write\n",
10610c0d06caSMauro Carvalho Chehab 			__func__);
10620c0d06caSMauro Carvalho Chehab 		return retval;
10630c0d06caSMauro Carvalho Chehab 	}
10640c0d06caSMauro Carvalho Chehab 	return 0;
10650c0d06caSMauro Carvalho Chehab }
10660c0d06caSMauro Carvalho Chehab 
10670c0d06caSMauro Carvalho Chehab static void cx231xx_417_check_encoder(struct cx231xx *dev)
10680c0d06caSMauro Carvalho Chehab {
10690c0d06caSMauro Carvalho Chehab 	u32 status, seq;
10700c0d06caSMauro Carvalho Chehab 
10710c0d06caSMauro Carvalho Chehab 	status = 0;
10720c0d06caSMauro Carvalho Chehab 	seq = 0;
10730c0d06caSMauro Carvalho Chehab 	cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
10740c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
10750c0d06caSMauro Carvalho Chehab }
10760c0d06caSMauro Carvalho Chehab 
10770c0d06caSMauro Carvalho Chehab static void cx231xx_codec_settings(struct cx231xx *dev)
10780c0d06caSMauro Carvalho Chehab {
10790c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
10800c0d06caSMauro Carvalho Chehab 
10810c0d06caSMauro Carvalho Chehab 	/* assign frame size */
10820c0d06caSMauro Carvalho Chehab 	cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
10830c0d06caSMauro Carvalho Chehab 				dev->ts1.height, dev->ts1.width);
10840c0d06caSMauro Carvalho Chehab 
10850c0d06caSMauro Carvalho Chehab 	dev->mpeg_params.width = dev->ts1.width;
10860c0d06caSMauro Carvalho Chehab 	dev->mpeg_params.height = dev->ts1.height;
10870c0d06caSMauro Carvalho Chehab 
10880c0d06caSMauro Carvalho Chehab 	cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
10890c0d06caSMauro Carvalho Chehab 
10900c0d06caSMauro Carvalho Chehab 	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
10910c0d06caSMauro Carvalho Chehab 	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
10920c0d06caSMauro Carvalho Chehab }
10930c0d06caSMauro Carvalho Chehab 
10940c0d06caSMauro Carvalho Chehab static int cx231xx_initialize_codec(struct cx231xx *dev)
10950c0d06caSMauro Carvalho Chehab {
10960c0d06caSMauro Carvalho Chehab 	int version;
10970c0d06caSMauro Carvalho Chehab 	int retval;
10980c0d06caSMauro Carvalho Chehab 	u32 i;
10990c0d06caSMauro Carvalho Chehab 	u32 val = 0;
11000c0d06caSMauro Carvalho Chehab 
11010c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
11020c0d06caSMauro Carvalho Chehab 	cx231xx_disable656(dev);
11030c0d06caSMauro Carvalho Chehab 	retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
11040c0d06caSMauro Carvalho Chehab 	if (retval < 0) {
11050c0d06caSMauro Carvalho Chehab 		dprintk(2, "%s() PING OK\n", __func__);
11060c0d06caSMauro Carvalho Chehab 		retval = cx231xx_load_firmware(dev);
11070c0d06caSMauro Carvalho Chehab 		if (retval < 0) {
11080c0d06caSMauro Carvalho Chehab 			printk(KERN_ERR "%s() f/w load failed\n", __func__);
11090c0d06caSMauro Carvalho Chehab 			return retval;
11100c0d06caSMauro Carvalho Chehab 		}
11110c0d06caSMauro Carvalho Chehab 		retval = cx231xx_find_mailbox(dev);
11120c0d06caSMauro Carvalho Chehab 		if (retval < 0) {
11130c0d06caSMauro Carvalho Chehab 			printk(KERN_ERR "%s() mailbox < 0, error\n",
11140c0d06caSMauro Carvalho Chehab 				__func__);
11150c0d06caSMauro Carvalho Chehab 			return -1;
11160c0d06caSMauro Carvalho Chehab 		}
11170c0d06caSMauro Carvalho Chehab 		dev->cx23417_mailbox = retval;
11180c0d06caSMauro Carvalho Chehab 		retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
11190c0d06caSMauro Carvalho Chehab 		if (retval < 0) {
11200c0d06caSMauro Carvalho Chehab 			printk(KERN_ERR
11210c0d06caSMauro Carvalho Chehab 				"ERROR: cx23417 firmware ping failed!\n");
11220c0d06caSMauro Carvalho Chehab 			return -1;
11230c0d06caSMauro Carvalho Chehab 		}
11240c0d06caSMauro Carvalho Chehab 		retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
11250c0d06caSMauro Carvalho Chehab 			&version);
11260c0d06caSMauro Carvalho Chehab 		if (retval < 0) {
11270c0d06caSMauro Carvalho Chehab 			printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
11280c0d06caSMauro Carvalho Chehab 				"version failed!\n");
11290c0d06caSMauro Carvalho Chehab 			return -1;
11300c0d06caSMauro Carvalho Chehab 		}
11310c0d06caSMauro Carvalho Chehab 		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
11320c0d06caSMauro Carvalho Chehab 		msleep(200);
11330c0d06caSMauro Carvalho Chehab 	}
11340c0d06caSMauro Carvalho Chehab 
11350c0d06caSMauro Carvalho Chehab 	for (i = 0; i < 1; i++) {
11360c0d06caSMauro Carvalho Chehab 		retval = mc417_register_read(dev, 0x20f8, &val);
11370c0d06caSMauro Carvalho Chehab 		dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
11380c0d06caSMauro Carvalho Chehab 				 val);
11390c0d06caSMauro Carvalho Chehab 		if (retval < 0)
11400c0d06caSMauro Carvalho Chehab 			return retval;
11410c0d06caSMauro Carvalho Chehab 	}
11420c0d06caSMauro Carvalho Chehab 
11430c0d06caSMauro Carvalho Chehab 	cx231xx_enable656(dev);
11440c0d06caSMauro Carvalho Chehab 			/* stop mpeg capture */
11450c0d06caSMauro Carvalho Chehab 			cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE,
11460c0d06caSMauro Carvalho Chehab 				 3, 0, 1, 3, 4);
11470c0d06caSMauro Carvalho Chehab 
11480c0d06caSMauro Carvalho Chehab 	cx231xx_codec_settings(dev);
11490c0d06caSMauro Carvalho Chehab 	msleep(60);
11500c0d06caSMauro Carvalho Chehab 
11510c0d06caSMauro Carvalho Chehab /*	cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
11520c0d06caSMauro Carvalho Chehab 		CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
11530c0d06caSMauro Carvalho Chehab 	cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
11540c0d06caSMauro Carvalho Chehab 		CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11550c0d06caSMauro Carvalho Chehab 		0, 0);
11560c0d06caSMauro Carvalho Chehab */
11570c0d06caSMauro Carvalho Chehab 
11580c0d06caSMauro Carvalho Chehab #if 0
11590c0d06caSMauro Carvalho Chehab 	/* TODO */
11600c0d06caSMauro Carvalho Chehab 	u32 data[7];
11610c0d06caSMauro Carvalho Chehab 
11620c0d06caSMauro Carvalho Chehab 	/* Setup to capture VBI */
11630c0d06caSMauro Carvalho Chehab 	data[0] = 0x0001BD00;
11640c0d06caSMauro Carvalho Chehab 	data[1] = 1;          /* frames per interrupt */
11650c0d06caSMauro Carvalho Chehab 	data[2] = 4;          /* total bufs */
11660c0d06caSMauro Carvalho Chehab 	data[3] = 0x91559155; /* start codes */
11670c0d06caSMauro Carvalho Chehab 	data[4] = 0x206080C0; /* stop codes */
11680c0d06caSMauro Carvalho Chehab 	data[5] = 6;          /* lines */
11690c0d06caSMauro Carvalho Chehab 	data[6] = 64;         /* BPL */
11700c0d06caSMauro Carvalho Chehab 
11710c0d06caSMauro Carvalho Chehab 	cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
11720c0d06caSMauro Carvalho Chehab 		data[2], data[3], data[4], data[5], data[6]);
11730c0d06caSMauro Carvalho Chehab 
11740c0d06caSMauro Carvalho Chehab 	for (i = 2; i <= 24; i++) {
11750c0d06caSMauro Carvalho Chehab 		int valid;
11760c0d06caSMauro Carvalho Chehab 
11770c0d06caSMauro Carvalho Chehab 		valid = ((i >= 19) && (i <= 21));
11780c0d06caSMauro Carvalho Chehab 		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
11790c0d06caSMauro Carvalho Chehab 				valid, 0 , 0, 0);
11800c0d06caSMauro Carvalho Chehab 		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
11810c0d06caSMauro Carvalho Chehab 				i | 0x80000000, valid, 0, 0, 0);
11820c0d06caSMauro Carvalho Chehab 	}
11830c0d06caSMauro Carvalho Chehab #endif
11840c0d06caSMauro Carvalho Chehab /*	cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
11850c0d06caSMauro Carvalho Chehab 	msleep(60);
11860c0d06caSMauro Carvalho Chehab */
11870c0d06caSMauro Carvalho Chehab 	/* initialize the video input */
11880c0d06caSMauro Carvalho Chehab 	retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
11890c0d06caSMauro Carvalho Chehab 	if (retval < 0)
11900c0d06caSMauro Carvalho Chehab 		return retval;
11910c0d06caSMauro Carvalho Chehab 	msleep(60);
11920c0d06caSMauro Carvalho Chehab 
11930c0d06caSMauro Carvalho Chehab 	/* Enable VIP style pixel invalidation so we work with scaled mode */
11940c0d06caSMauro Carvalho Chehab 	mc417_memory_write(dev, 2120, 0x00000080);
11950c0d06caSMauro Carvalho Chehab 
11960c0d06caSMauro Carvalho Chehab 	/* start capturing to the host interface */
11970c0d06caSMauro Carvalho Chehab 	retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
11980c0d06caSMauro Carvalho Chehab 		CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
11990c0d06caSMauro Carvalho Chehab 	if (retval < 0)
12000c0d06caSMauro Carvalho Chehab 		return retval;
12010c0d06caSMauro Carvalho Chehab 	msleep(10);
12020c0d06caSMauro Carvalho Chehab 
12030c0d06caSMauro Carvalho Chehab 	for (i = 0; i < 1; i++) {
12040c0d06caSMauro Carvalho Chehab 		mc417_register_read(dev, 0x20f8, &val);
12050c0d06caSMauro Carvalho Chehab 	dprintk(3, "***VIM Capture Lines =%d ***\n", val);
12060c0d06caSMauro Carvalho Chehab 	}
12070c0d06caSMauro Carvalho Chehab 
12080c0d06caSMauro Carvalho Chehab 	return 0;
12090c0d06caSMauro Carvalho Chehab }
12100c0d06caSMauro Carvalho Chehab 
12110c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
12120c0d06caSMauro Carvalho Chehab 
12130c0d06caSMauro Carvalho Chehab static int bb_buf_setup(struct videobuf_queue *q,
12140c0d06caSMauro Carvalho Chehab 	unsigned int *count, unsigned int *size)
12150c0d06caSMauro Carvalho Chehab {
12160c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = q->priv_data;
12170c0d06caSMauro Carvalho Chehab 
12180c0d06caSMauro Carvalho Chehab 	fh->dev->ts1.ts_packet_size  = mpeglinesize;
12190c0d06caSMauro Carvalho Chehab 	fh->dev->ts1.ts_packet_count = mpeglines;
12200c0d06caSMauro Carvalho Chehab 
12210c0d06caSMauro Carvalho Chehab 	*size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
12220c0d06caSMauro Carvalho Chehab 	*count = mpegbufs;
12230c0d06caSMauro Carvalho Chehab 
12240c0d06caSMauro Carvalho Chehab 	return 0;
12250c0d06caSMauro Carvalho Chehab }
12260c0d06caSMauro Carvalho Chehab static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
12270c0d06caSMauro Carvalho Chehab {
12280c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = vq->priv_data;
12290c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
12300c0d06caSMauro Carvalho Chehab 	unsigned long flags = 0;
12310c0d06caSMauro Carvalho Chehab 
12320c0d06caSMauro Carvalho Chehab 	if (in_interrupt())
12330c0d06caSMauro Carvalho Chehab 		BUG();
12340c0d06caSMauro Carvalho Chehab 
12350c0d06caSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->video_mode.slock, flags);
12360c0d06caSMauro Carvalho Chehab 	if (dev->USE_ISO) {
12370c0d06caSMauro Carvalho Chehab 		if (dev->video_mode.isoc_ctl.buf == buf)
12380c0d06caSMauro Carvalho Chehab 			dev->video_mode.isoc_ctl.buf = NULL;
12390c0d06caSMauro Carvalho Chehab 	} else {
12400c0d06caSMauro Carvalho Chehab 		if (dev->video_mode.bulk_ctl.buf == buf)
12410c0d06caSMauro Carvalho Chehab 			dev->video_mode.bulk_ctl.buf = NULL;
12420c0d06caSMauro Carvalho Chehab 	}
12430c0d06caSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
12440c0d06caSMauro Carvalho Chehab 	videobuf_waiton(vq, &buf->vb, 0, 0);
12450c0d06caSMauro Carvalho Chehab 	videobuf_vmalloc_free(&buf->vb);
12460c0d06caSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
12470c0d06caSMauro Carvalho Chehab }
12480c0d06caSMauro Carvalho Chehab 
12490c0d06caSMauro Carvalho Chehab static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
12500c0d06caSMauro Carvalho Chehab 		struct cx231xx_dmaqueue *dma_q)
12510c0d06caSMauro Carvalho Chehab {
12520c0d06caSMauro Carvalho Chehab 		void *vbuf;
12530c0d06caSMauro Carvalho Chehab 		struct cx231xx_buffer *buf;
12540c0d06caSMauro Carvalho Chehab 		u32 tail_data = 0;
12550c0d06caSMauro Carvalho Chehab 		char *p_data;
12560c0d06caSMauro Carvalho Chehab 
12570c0d06caSMauro Carvalho Chehab 		if (dma_q->mpeg_buffer_done == 0) {
12580c0d06caSMauro Carvalho Chehab 			if (list_empty(&dma_q->active))
12590c0d06caSMauro Carvalho Chehab 				return;
12600c0d06caSMauro Carvalho Chehab 
12610c0d06caSMauro Carvalho Chehab 			buf = list_entry(dma_q->active.next,
12620c0d06caSMauro Carvalho Chehab 					struct cx231xx_buffer, vb.queue);
12630c0d06caSMauro Carvalho Chehab 			dev->video_mode.isoc_ctl.buf = buf;
12640c0d06caSMauro Carvalho Chehab 			dma_q->mpeg_buffer_done = 1;
12650c0d06caSMauro Carvalho Chehab 		}
12660c0d06caSMauro Carvalho Chehab 		/* Fill buffer */
12670c0d06caSMauro Carvalho Chehab 		buf = dev->video_mode.isoc_ctl.buf;
12680c0d06caSMauro Carvalho Chehab 		vbuf = videobuf_to_vmalloc(&buf->vb);
12690c0d06caSMauro Carvalho Chehab 
12700c0d06caSMauro Carvalho Chehab 		if ((dma_q->mpeg_buffer_completed+len) <
12710c0d06caSMauro Carvalho Chehab 		   mpeglines*mpeglinesize) {
12720c0d06caSMauro Carvalho Chehab 			if (dma_q->add_ps_package_head ==
12730c0d06caSMauro Carvalho Chehab 			   CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
12740c0d06caSMauro Carvalho Chehab 				memcpy(vbuf+dma_q->mpeg_buffer_completed,
12750c0d06caSMauro Carvalho Chehab 				       dma_q->ps_head, 3);
12760c0d06caSMauro Carvalho Chehab 				dma_q->mpeg_buffer_completed =
12770c0d06caSMauro Carvalho Chehab 				  dma_q->mpeg_buffer_completed + 3;
12780c0d06caSMauro Carvalho Chehab 				dma_q->add_ps_package_head =
12790c0d06caSMauro Carvalho Chehab 				  CX231XX_NONEED_PS_PACKAGE_HEAD;
12800c0d06caSMauro Carvalho Chehab 			}
12810c0d06caSMauro Carvalho Chehab 			memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
12820c0d06caSMauro Carvalho Chehab 			dma_q->mpeg_buffer_completed =
12830c0d06caSMauro Carvalho Chehab 			  dma_q->mpeg_buffer_completed + len;
12840c0d06caSMauro Carvalho Chehab 		} else {
12850c0d06caSMauro Carvalho Chehab 			dma_q->mpeg_buffer_done = 0;
12860c0d06caSMauro Carvalho Chehab 
12870c0d06caSMauro Carvalho Chehab 			tail_data =
12880c0d06caSMauro Carvalho Chehab 			  mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
12890c0d06caSMauro Carvalho Chehab 			memcpy(vbuf+dma_q->mpeg_buffer_completed,
12900c0d06caSMauro Carvalho Chehab 			       data, tail_data);
12910c0d06caSMauro Carvalho Chehab 
12920c0d06caSMauro Carvalho Chehab 			buf->vb.state = VIDEOBUF_DONE;
12930c0d06caSMauro Carvalho Chehab 			buf->vb.field_count++;
12948e6057b5SSakari Ailus 			v4l2_get_timestamp(&buf->vb.ts);
12950c0d06caSMauro Carvalho Chehab 			list_del(&buf->vb.queue);
12960c0d06caSMauro Carvalho Chehab 			wake_up(&buf->vb.done);
12970c0d06caSMauro Carvalho Chehab 			dma_q->mpeg_buffer_completed = 0;
12980c0d06caSMauro Carvalho Chehab 
12990c0d06caSMauro Carvalho Chehab 			if (len - tail_data > 0) {
13000c0d06caSMauro Carvalho Chehab 				p_data = data + tail_data;
13010c0d06caSMauro Carvalho Chehab 				dma_q->left_data_count = len - tail_data;
13020c0d06caSMauro Carvalho Chehab 				memcpy(dma_q->p_left_data,
13030c0d06caSMauro Carvalho Chehab 				       p_data, len - tail_data);
13040c0d06caSMauro Carvalho Chehab 			}
13050c0d06caSMauro Carvalho Chehab 
13060c0d06caSMauro Carvalho Chehab 		}
13070c0d06caSMauro Carvalho Chehab 
13080c0d06caSMauro Carvalho Chehab 	    return;
13090c0d06caSMauro Carvalho Chehab }
13100c0d06caSMauro Carvalho Chehab 
13110c0d06caSMauro Carvalho Chehab static void buffer_filled(char *data, int len, struct urb *urb,
13120c0d06caSMauro Carvalho Chehab 		struct cx231xx_dmaqueue *dma_q)
13130c0d06caSMauro Carvalho Chehab {
13140c0d06caSMauro Carvalho Chehab 		void *vbuf;
13150c0d06caSMauro Carvalho Chehab 		struct cx231xx_buffer *buf;
13160c0d06caSMauro Carvalho Chehab 
13170c0d06caSMauro Carvalho Chehab 		if (list_empty(&dma_q->active))
13180c0d06caSMauro Carvalho Chehab 			return;
13190c0d06caSMauro Carvalho Chehab 
13200c0d06caSMauro Carvalho Chehab 
13210c0d06caSMauro Carvalho Chehab 		buf = list_entry(dma_q->active.next,
13220c0d06caSMauro Carvalho Chehab 				 struct cx231xx_buffer, vb.queue);
13230c0d06caSMauro Carvalho Chehab 
13240c0d06caSMauro Carvalho Chehab 
13250c0d06caSMauro Carvalho Chehab 		/* Fill buffer */
13260c0d06caSMauro Carvalho Chehab 		vbuf = videobuf_to_vmalloc(&buf->vb);
13270c0d06caSMauro Carvalho Chehab 		memcpy(vbuf, data, len);
13280c0d06caSMauro Carvalho Chehab 		buf->vb.state = VIDEOBUF_DONE;
13290c0d06caSMauro Carvalho Chehab 		buf->vb.field_count++;
13308e6057b5SSakari Ailus 		v4l2_get_timestamp(&buf->vb.ts);
13310c0d06caSMauro Carvalho Chehab 		list_del(&buf->vb.queue);
13320c0d06caSMauro Carvalho Chehab 		wake_up(&buf->vb.done);
13330c0d06caSMauro Carvalho Chehab 
13340c0d06caSMauro Carvalho Chehab 	    return;
13350c0d06caSMauro Carvalho Chehab }
13360c0d06caSMauro Carvalho Chehab static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
13370c0d06caSMauro Carvalho Chehab {
13380c0d06caSMauro Carvalho Chehab 	struct cx231xx_dmaqueue *dma_q = urb->context;
13390c0d06caSMauro Carvalho Chehab 	unsigned char *p_buffer;
13400c0d06caSMauro Carvalho Chehab 	u32 buffer_size = 0;
13410c0d06caSMauro Carvalho Chehab 	u32 i = 0;
13420c0d06caSMauro Carvalho Chehab 
13430c0d06caSMauro Carvalho Chehab 	for (i = 0; i < urb->number_of_packets; i++) {
13440c0d06caSMauro Carvalho Chehab 		if (dma_q->left_data_count > 0) {
13450c0d06caSMauro Carvalho Chehab 			buffer_copy(dev, dma_q->p_left_data,
13460c0d06caSMauro Carvalho Chehab 				    dma_q->left_data_count, urb, dma_q);
13470c0d06caSMauro Carvalho Chehab 			dma_q->mpeg_buffer_completed = dma_q->left_data_count;
13480c0d06caSMauro Carvalho Chehab 			dma_q->left_data_count = 0;
13490c0d06caSMauro Carvalho Chehab 		}
13500c0d06caSMauro Carvalho Chehab 
13510c0d06caSMauro Carvalho Chehab 		p_buffer = urb->transfer_buffer +
13520c0d06caSMauro Carvalho Chehab 				urb->iso_frame_desc[i].offset;
13530c0d06caSMauro Carvalho Chehab 		buffer_size = urb->iso_frame_desc[i].actual_length;
13540c0d06caSMauro Carvalho Chehab 
13550c0d06caSMauro Carvalho Chehab 		if (buffer_size > 0)
13560c0d06caSMauro Carvalho Chehab 			buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
13570c0d06caSMauro Carvalho Chehab 	}
13580c0d06caSMauro Carvalho Chehab 
13590c0d06caSMauro Carvalho Chehab 	return 0;
13600c0d06caSMauro Carvalho Chehab }
13610c0d06caSMauro Carvalho Chehab static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
13620c0d06caSMauro Carvalho Chehab {
13630c0d06caSMauro Carvalho Chehab 
13640c0d06caSMauro Carvalho Chehab 	/*char *outp;*/
13650c0d06caSMauro Carvalho Chehab 	/*struct cx231xx_buffer *buf;*/
13660c0d06caSMauro Carvalho Chehab 	struct cx231xx_dmaqueue *dma_q = urb->context;
13670c0d06caSMauro Carvalho Chehab 	unsigned char *p_buffer, *buffer;
13680c0d06caSMauro Carvalho Chehab 	u32 buffer_size = 0;
13690c0d06caSMauro Carvalho Chehab 
13700c0d06caSMauro Carvalho Chehab 	p_buffer = urb->transfer_buffer;
13710c0d06caSMauro Carvalho Chehab 	buffer_size = urb->actual_length;
13720c0d06caSMauro Carvalho Chehab 
13730c0d06caSMauro Carvalho Chehab 	buffer = kmalloc(buffer_size, GFP_ATOMIC);
13740c0d06caSMauro Carvalho Chehab 
13750c0d06caSMauro Carvalho Chehab 	memcpy(buffer, dma_q->ps_head, 3);
13760c0d06caSMauro Carvalho Chehab 	memcpy(buffer+3, p_buffer, buffer_size-3);
13770c0d06caSMauro Carvalho Chehab 	memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
13780c0d06caSMauro Carvalho Chehab 
13790c0d06caSMauro Carvalho Chehab 	p_buffer = buffer;
13800c0d06caSMauro Carvalho Chehab 	buffer_filled(p_buffer, buffer_size, urb, dma_q);
13810c0d06caSMauro Carvalho Chehab 
13820c0d06caSMauro Carvalho Chehab 	kfree(buffer);
13830c0d06caSMauro Carvalho Chehab 	return 0;
13840c0d06caSMauro Carvalho Chehab }
13850c0d06caSMauro Carvalho Chehab 
13860c0d06caSMauro Carvalho Chehab static int bb_buf_prepare(struct videobuf_queue *q,
13870c0d06caSMauro Carvalho Chehab 	struct videobuf_buffer *vb, enum v4l2_field field)
13880c0d06caSMauro Carvalho Chehab {
13890c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = q->priv_data;
13900c0d06caSMauro Carvalho Chehab 	struct cx231xx_buffer *buf =
13910c0d06caSMauro Carvalho Chehab 	    container_of(vb, struct cx231xx_buffer, vb);
13920c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
13930c0d06caSMauro Carvalho Chehab 	int rc = 0, urb_init = 0;
13940c0d06caSMauro Carvalho Chehab 	int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
13950c0d06caSMauro Carvalho Chehab 
13960c0d06caSMauro Carvalho Chehab 	dma_qq = &dev->video_mode.vidq;
13970c0d06caSMauro Carvalho Chehab 
13980c0d06caSMauro Carvalho Chehab 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
13990c0d06caSMauro Carvalho Chehab 		return -EINVAL;
14000c0d06caSMauro Carvalho Chehab 	buf->vb.width = fh->dev->ts1.ts_packet_size;
14010c0d06caSMauro Carvalho Chehab 	buf->vb.height = fh->dev->ts1.ts_packet_count;
14020c0d06caSMauro Carvalho Chehab 	buf->vb.size = size;
14030c0d06caSMauro Carvalho Chehab 	buf->vb.field = field;
14040c0d06caSMauro Carvalho Chehab 
14050c0d06caSMauro Carvalho Chehab 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
14060c0d06caSMauro Carvalho Chehab 		rc = videobuf_iolock(q, &buf->vb, NULL);
14070c0d06caSMauro Carvalho Chehab 		if (rc < 0)
14080c0d06caSMauro Carvalho Chehab 			goto fail;
14090c0d06caSMauro Carvalho Chehab 	}
14100c0d06caSMauro Carvalho Chehab 
14110c0d06caSMauro Carvalho Chehab 	if (dev->USE_ISO) {
14120c0d06caSMauro Carvalho Chehab 		if (!dev->video_mode.isoc_ctl.num_bufs)
14130c0d06caSMauro Carvalho Chehab 			urb_init = 1;
14140c0d06caSMauro Carvalho Chehab 	} else {
14150c0d06caSMauro Carvalho Chehab 		if (!dev->video_mode.bulk_ctl.num_bufs)
14160c0d06caSMauro Carvalho Chehab 			urb_init = 1;
14170c0d06caSMauro Carvalho Chehab 	}
14180c0d06caSMauro Carvalho Chehab 	/*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
14190c0d06caSMauro Carvalho Chehab 		urb_init, dev->video_mode.max_pkt_size);*/
14200c0d06caSMauro Carvalho Chehab 	dev->mode_tv = 1;
14210c0d06caSMauro Carvalho Chehab 
14220c0d06caSMauro Carvalho Chehab 	if (urb_init) {
14230c0d06caSMauro Carvalho Chehab 		rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
14240c0d06caSMauro Carvalho Chehab 		rc = cx231xx_unmute_audio(dev);
14250c0d06caSMauro Carvalho Chehab 		if (dev->USE_ISO) {
14260c0d06caSMauro Carvalho Chehab 			cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
14270c0d06caSMauro Carvalho Chehab 			rc = cx231xx_init_isoc(dev, mpeglines,
14280c0d06caSMauro Carvalho Chehab 				       mpegbufs,
14290c0d06caSMauro Carvalho Chehab 				       dev->ts1_mode.max_pkt_size,
14300c0d06caSMauro Carvalho Chehab 				       cx231xx_isoc_copy);
14310c0d06caSMauro Carvalho Chehab 		} else {
14320c0d06caSMauro Carvalho Chehab 			cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
14330c0d06caSMauro Carvalho Chehab 			rc = cx231xx_init_bulk(dev, mpeglines,
14340c0d06caSMauro Carvalho Chehab 				       mpegbufs,
14350c0d06caSMauro Carvalho Chehab 				       dev->ts1_mode.max_pkt_size,
14360c0d06caSMauro Carvalho Chehab 				       cx231xx_bulk_copy);
14370c0d06caSMauro Carvalho Chehab 		}
14380c0d06caSMauro Carvalho Chehab 		if (rc < 0)
14390c0d06caSMauro Carvalho Chehab 			goto fail;
14400c0d06caSMauro Carvalho Chehab 	}
14410c0d06caSMauro Carvalho Chehab 
14420c0d06caSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_PREPARED;
14430c0d06caSMauro Carvalho Chehab 	return 0;
14440c0d06caSMauro Carvalho Chehab 
14450c0d06caSMauro Carvalho Chehab fail:
14460c0d06caSMauro Carvalho Chehab 	free_buffer(q, buf);
14470c0d06caSMauro Carvalho Chehab 	return rc;
14480c0d06caSMauro Carvalho Chehab }
14490c0d06caSMauro Carvalho Chehab 
14500c0d06caSMauro Carvalho Chehab static void bb_buf_queue(struct videobuf_queue *q,
14510c0d06caSMauro Carvalho Chehab 	struct videobuf_buffer *vb)
14520c0d06caSMauro Carvalho Chehab {
14530c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = q->priv_data;
14540c0d06caSMauro Carvalho Chehab 
14550c0d06caSMauro Carvalho Chehab 	struct cx231xx_buffer *buf =
14560c0d06caSMauro Carvalho Chehab 	    container_of(vb, struct cx231xx_buffer, vb);
14570c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
14580c0d06caSMauro Carvalho Chehab 	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
14590c0d06caSMauro Carvalho Chehab 
14600c0d06caSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_QUEUED;
14610c0d06caSMauro Carvalho Chehab 	list_add_tail(&buf->vb.queue, &vidq->active);
14620c0d06caSMauro Carvalho Chehab 
14630c0d06caSMauro Carvalho Chehab }
14640c0d06caSMauro Carvalho Chehab 
14650c0d06caSMauro Carvalho Chehab static void bb_buf_release(struct videobuf_queue *q,
14660c0d06caSMauro Carvalho Chehab 	struct videobuf_buffer *vb)
14670c0d06caSMauro Carvalho Chehab {
14680c0d06caSMauro Carvalho Chehab 	struct cx231xx_buffer *buf =
14690c0d06caSMauro Carvalho Chehab 	    container_of(vb, struct cx231xx_buffer, vb);
14700c0d06caSMauro Carvalho Chehab 	/*struct cx231xx_fh *fh = q->priv_data;*/
14710c0d06caSMauro Carvalho Chehab 	/*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/
14720c0d06caSMauro Carvalho Chehab 
14730c0d06caSMauro Carvalho Chehab 	free_buffer(q, buf);
14740c0d06caSMauro Carvalho Chehab }
14750c0d06caSMauro Carvalho Chehab 
14760c0d06caSMauro Carvalho Chehab static struct videobuf_queue_ops cx231xx_qops = {
14770c0d06caSMauro Carvalho Chehab 	.buf_setup    = bb_buf_setup,
14780c0d06caSMauro Carvalho Chehab 	.buf_prepare  = bb_buf_prepare,
14790c0d06caSMauro Carvalho Chehab 	.buf_queue    = bb_buf_queue,
14800c0d06caSMauro Carvalho Chehab 	.buf_release  = bb_buf_release,
14810c0d06caSMauro Carvalho Chehab };
14820c0d06caSMauro Carvalho Chehab 
14830c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
14840c0d06caSMauro Carvalho Chehab 
14850c0d06caSMauro Carvalho Chehab static const u32 *ctrl_classes[] = {
14860c0d06caSMauro Carvalho Chehab 	cx2341x_mpeg_ctrls,
14870c0d06caSMauro Carvalho Chehab 	NULL
14880c0d06caSMauro Carvalho Chehab };
14890c0d06caSMauro Carvalho Chehab 
14900c0d06caSMauro Carvalho Chehab static int cx231xx_queryctrl(struct cx231xx *dev,
14910c0d06caSMauro Carvalho Chehab 	struct v4l2_queryctrl *qctrl)
14920c0d06caSMauro Carvalho Chehab {
14930c0d06caSMauro Carvalho Chehab 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
14940c0d06caSMauro Carvalho Chehab 	if (qctrl->id == 0)
14950c0d06caSMauro Carvalho Chehab 		return -EINVAL;
14960c0d06caSMauro Carvalho Chehab 
14970c0d06caSMauro Carvalho Chehab 	/* MPEG V4L2 controls */
14980c0d06caSMauro Carvalho Chehab 	if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
14990c0d06caSMauro Carvalho Chehab 		qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
15000c0d06caSMauro Carvalho Chehab 
15010c0d06caSMauro Carvalho Chehab 	return 0;
15020c0d06caSMauro Carvalho Chehab }
15030c0d06caSMauro Carvalho Chehab 
15040c0d06caSMauro Carvalho Chehab static int cx231xx_querymenu(struct cx231xx *dev,
15050c0d06caSMauro Carvalho Chehab 	struct v4l2_querymenu *qmenu)
15060c0d06caSMauro Carvalho Chehab {
15070c0d06caSMauro Carvalho Chehab 	struct v4l2_queryctrl qctrl;
15080c0d06caSMauro Carvalho Chehab 
15090c0d06caSMauro Carvalho Chehab 	qctrl.id = qmenu->id;
15100c0d06caSMauro Carvalho Chehab 	cx231xx_queryctrl(dev, &qctrl);
15110c0d06caSMauro Carvalho Chehab 	return v4l2_ctrl_query_menu(qmenu, &qctrl,
15120c0d06caSMauro Carvalho Chehab 		cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
15130c0d06caSMauro Carvalho Chehab }
15140c0d06caSMauro Carvalho Chehab 
15150c0d06caSMauro Carvalho Chehab static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
15160c0d06caSMauro Carvalho Chehab {
15170c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
15180c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
15190c0d06caSMauro Carvalho Chehab 
15200c0d06caSMauro Carvalho Chehab 	*norm = dev->encodernorm.id;
15210c0d06caSMauro Carvalho Chehab 	return 0;
15220c0d06caSMauro Carvalho Chehab }
15230c0d06caSMauro Carvalho Chehab static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
15240c0d06caSMauro Carvalho Chehab {
15250c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
15260c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
15270c0d06caSMauro Carvalho Chehab 	unsigned int i;
15280c0d06caSMauro Carvalho Chehab 
15290c0d06caSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
15300c0d06caSMauro Carvalho Chehab 		if (*id & cx231xx_tvnorms[i].id)
15310c0d06caSMauro Carvalho Chehab 			break;
15320c0d06caSMauro Carvalho Chehab 	if (i == ARRAY_SIZE(cx231xx_tvnorms))
15330c0d06caSMauro Carvalho Chehab 		return -EINVAL;
15340c0d06caSMauro Carvalho Chehab 	dev->encodernorm = cx231xx_tvnorms[i];
15350c0d06caSMauro Carvalho Chehab 
15360c0d06caSMauro Carvalho Chehab 	if (dev->encodernorm.id & 0xb000) {
15370c0d06caSMauro Carvalho Chehab 		dprintk(3, "encodernorm set to NTSC\n");
15380c0d06caSMauro Carvalho Chehab 		dev->norm = V4L2_STD_NTSC;
15390c0d06caSMauro Carvalho Chehab 		dev->ts1.height = 480;
15400c0d06caSMauro Carvalho Chehab 		dev->mpeg_params.is_50hz = 0;
15410c0d06caSMauro Carvalho Chehab 	} else {
15420c0d06caSMauro Carvalho Chehab 		dprintk(3, "encodernorm set to PAL\n");
15430c0d06caSMauro Carvalho Chehab 		dev->norm = V4L2_STD_PAL_B;
15440c0d06caSMauro Carvalho Chehab 		dev->ts1.height = 576;
15450c0d06caSMauro Carvalho Chehab 		dev->mpeg_params.is_50hz = 1;
15460c0d06caSMauro Carvalho Chehab 	}
15470c0d06caSMauro Carvalho Chehab 	call_all(dev, core, s_std, dev->norm);
15480c0d06caSMauro Carvalho Chehab 	/* do mode control overrides */
15490c0d06caSMauro Carvalho Chehab 	cx231xx_do_mode_ctrl_overrides(dev);
15500c0d06caSMauro Carvalho Chehab 
15510c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
15520c0d06caSMauro Carvalho Chehab 	return 0;
15530c0d06caSMauro Carvalho Chehab }
15540c0d06caSMauro Carvalho Chehab static const char *iname[] = {
15550c0d06caSMauro Carvalho Chehab 	[CX231XX_VMUX_COMPOSITE1] = "Composite1",
15560c0d06caSMauro Carvalho Chehab 	[CX231XX_VMUX_SVIDEO]     = "S-Video",
15570c0d06caSMauro Carvalho Chehab 	[CX231XX_VMUX_TELEVISION] = "Television",
15580c0d06caSMauro Carvalho Chehab 	[CX231XX_VMUX_CABLE]      = "Cable TV",
15590c0d06caSMauro Carvalho Chehab 	[CX231XX_VMUX_DVB]        = "DVB",
15600c0d06caSMauro Carvalho Chehab 	[CX231XX_VMUX_DEBUG]      = "for debug only",
15610c0d06caSMauro Carvalho Chehab };
15620c0d06caSMauro Carvalho Chehab static int vidioc_enum_input(struct file *file, void *priv,
15630c0d06caSMauro Carvalho Chehab 				struct v4l2_input *i)
15640c0d06caSMauro Carvalho Chehab {
15650c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
15660c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
15670c0d06caSMauro Carvalho Chehab 	struct cx231xx_input *input;
15680c0d06caSMauro Carvalho Chehab 	int n;
15690c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
15700c0d06caSMauro Carvalho Chehab 
15710c0d06caSMauro Carvalho Chehab 	if (i->index >= 4)
15720c0d06caSMauro Carvalho Chehab 		return -EINVAL;
15730c0d06caSMauro Carvalho Chehab 
15740c0d06caSMauro Carvalho Chehab 
15750c0d06caSMauro Carvalho Chehab 	input = &cx231xx_boards[dev->model].input[i->index];
15760c0d06caSMauro Carvalho Chehab 
15770c0d06caSMauro Carvalho Chehab 	if (input->type == 0)
15780c0d06caSMauro Carvalho Chehab 		return -EINVAL;
15790c0d06caSMauro Carvalho Chehab 
15800c0d06caSMauro Carvalho Chehab 	/* FIXME
15810c0d06caSMauro Carvalho Chehab 	 * strcpy(i->name, input->name); */
15820c0d06caSMauro Carvalho Chehab 
15830c0d06caSMauro Carvalho Chehab 	n = i->index;
15840c0d06caSMauro Carvalho Chehab 	strcpy(i->name, iname[INPUT(n)->type]);
15850c0d06caSMauro Carvalho Chehab 
15860c0d06caSMauro Carvalho Chehab 	if (input->type == CX231XX_VMUX_TELEVISION ||
15870c0d06caSMauro Carvalho Chehab 	    input->type == CX231XX_VMUX_CABLE)
15880c0d06caSMauro Carvalho Chehab 		i->type = V4L2_INPUT_TYPE_TUNER;
15890c0d06caSMauro Carvalho Chehab 	else
15900c0d06caSMauro Carvalho Chehab 		i->type  = V4L2_INPUT_TYPE_CAMERA;
15910c0d06caSMauro Carvalho Chehab 
15920c0d06caSMauro Carvalho Chehab 
15930c0d06caSMauro Carvalho Chehab 	return 0;
15940c0d06caSMauro Carvalho Chehab }
15950c0d06caSMauro Carvalho Chehab 
15960c0d06caSMauro Carvalho Chehab static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
15970c0d06caSMauro Carvalho Chehab {
15980c0d06caSMauro Carvalho Chehab 	*i = 0;
15990c0d06caSMauro Carvalho Chehab 	return  0;
16000c0d06caSMauro Carvalho Chehab }
16010c0d06caSMauro Carvalho Chehab 
16020c0d06caSMauro Carvalho Chehab static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
16030c0d06caSMauro Carvalho Chehab {
16040c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
16050c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
16060c0d06caSMauro Carvalho Chehab 
16070c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_s_input() i=%d\n", i);
16080c0d06caSMauro Carvalho Chehab 
16090c0d06caSMauro Carvalho Chehab 	video_mux(dev, i);
16100c0d06caSMauro Carvalho Chehab 
16110c0d06caSMauro Carvalho Chehab 	if (i >= 4)
16120c0d06caSMauro Carvalho Chehab 		return -EINVAL;
16130c0d06caSMauro Carvalho Chehab 	dev->input = i;
16140c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_s_input()\n");
16150c0d06caSMauro Carvalho Chehab 	return 0;
16160c0d06caSMauro Carvalho Chehab }
16170c0d06caSMauro Carvalho Chehab 
16180c0d06caSMauro Carvalho Chehab static int vidioc_s_ctrl(struct file *file, void *priv,
16190c0d06caSMauro Carvalho Chehab 				struct v4l2_control *ctl)
16200c0d06caSMauro Carvalho Chehab {
16210c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
16220c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
16230c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_s_ctrl()\n");
16240c0d06caSMauro Carvalho Chehab 	/* Update the A/V core */
16250c0d06caSMauro Carvalho Chehab 	call_all(dev, core, s_ctrl, ctl);
16260c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_s_ctrl()\n");
16270c0d06caSMauro Carvalho Chehab 	return 0;
16280c0d06caSMauro Carvalho Chehab }
16290c0d06caSMauro Carvalho Chehab static struct v4l2_capability pvr_capability = {
16300c0d06caSMauro Carvalho Chehab 	.driver         = "cx231xx",
16310c0d06caSMauro Carvalho Chehab 	.card           = "VideoGrabber",
16320c0d06caSMauro Carvalho Chehab 	.bus_info       = "usb",
16330c0d06caSMauro Carvalho Chehab 	.version        = 1,
16340c0d06caSMauro Carvalho Chehab 	.capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
16350c0d06caSMauro Carvalho Chehab 			   V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
16360c0d06caSMauro Carvalho Chehab 			 V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
16370c0d06caSMauro Carvalho Chehab };
16380c0d06caSMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void  *priv,
16390c0d06caSMauro Carvalho Chehab 				struct v4l2_capability *cap)
16400c0d06caSMauro Carvalho Chehab {
16410c0d06caSMauro Carvalho Chehab 
16420c0d06caSMauro Carvalho Chehab 
16430c0d06caSMauro Carvalho Chehab 
16440c0d06caSMauro Carvalho Chehab 		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
16450c0d06caSMauro Carvalho Chehab 	return 0;
16460c0d06caSMauro Carvalho Chehab }
16470c0d06caSMauro Carvalho Chehab 
16480c0d06caSMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
16490c0d06caSMauro Carvalho Chehab 					struct v4l2_fmtdesc *f)
16500c0d06caSMauro Carvalho Chehab {
16510c0d06caSMauro Carvalho Chehab 
16520c0d06caSMauro Carvalho Chehab 	if (f->index != 0)
16530c0d06caSMauro Carvalho Chehab 		return -EINVAL;
16540c0d06caSMauro Carvalho Chehab 
16550c0d06caSMauro Carvalho Chehab 	strlcpy(f->description, "MPEG", sizeof(f->description));
16560c0d06caSMauro Carvalho Chehab 	f->pixelformat = V4L2_PIX_FMT_MPEG;
16570c0d06caSMauro Carvalho Chehab 
16580c0d06caSMauro Carvalho Chehab 	return 0;
16590c0d06caSMauro Carvalho Chehab }
16600c0d06caSMauro Carvalho Chehab 
16610c0d06caSMauro Carvalho Chehab static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
16620c0d06caSMauro Carvalho Chehab 				struct v4l2_format *f)
16630c0d06caSMauro Carvalho Chehab {
16640c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
16650c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
16660c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
16670c0d06caSMauro Carvalho Chehab 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
16680c0d06caSMauro Carvalho Chehab 	f->fmt.pix.bytesperline = 0;
16690c0d06caSMauro Carvalho Chehab 	f->fmt.pix.sizeimage    =
16700c0d06caSMauro Carvalho Chehab 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
16710c0d06caSMauro Carvalho Chehab 	f->fmt.pix.colorspace   = 0;
16720c0d06caSMauro Carvalho Chehab 	f->fmt.pix.width        = dev->ts1.width;
16730c0d06caSMauro Carvalho Chehab 	f->fmt.pix.height       = dev->ts1.height;
16740c0d06caSMauro Carvalho Chehab 	f->fmt.pix.field        = fh->vidq.field;
16750c0d06caSMauro Carvalho Chehab 	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
16760c0d06caSMauro Carvalho Chehab 		dev->ts1.width, dev->ts1.height, fh->vidq.field);
16770c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
16780c0d06caSMauro Carvalho Chehab 	return 0;
16790c0d06caSMauro Carvalho Chehab }
16800c0d06caSMauro Carvalho Chehab 
16810c0d06caSMauro Carvalho Chehab static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
16820c0d06caSMauro Carvalho Chehab 				struct v4l2_format *f)
16830c0d06caSMauro Carvalho Chehab {
16840c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
16850c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
16860c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
16870c0d06caSMauro Carvalho Chehab 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
16880c0d06caSMauro Carvalho Chehab 	f->fmt.pix.bytesperline = 0;
16890c0d06caSMauro Carvalho Chehab 	f->fmt.pix.sizeimage    =
16900c0d06caSMauro Carvalho Chehab 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
16910c0d06caSMauro Carvalho Chehab 	f->fmt.pix.colorspace   = 0;
16920c0d06caSMauro Carvalho Chehab 	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
16930c0d06caSMauro Carvalho Chehab 		dev->ts1.width, dev->ts1.height, fh->vidq.field);
16940c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
16950c0d06caSMauro Carvalho Chehab 	return 0;
16960c0d06caSMauro Carvalho Chehab }
16970c0d06caSMauro Carvalho Chehab 
16980c0d06caSMauro Carvalho Chehab static int vidioc_reqbufs(struct file *file, void *priv,
16990c0d06caSMauro Carvalho Chehab 				struct v4l2_requestbuffers *p)
17000c0d06caSMauro Carvalho Chehab {
17010c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
17020c0d06caSMauro Carvalho Chehab 
17030c0d06caSMauro Carvalho Chehab 	return videobuf_reqbufs(&fh->vidq, p);
17040c0d06caSMauro Carvalho Chehab }
17050c0d06caSMauro Carvalho Chehab 
17060c0d06caSMauro Carvalho Chehab static int vidioc_querybuf(struct file *file, void *priv,
17070c0d06caSMauro Carvalho Chehab 				struct v4l2_buffer *p)
17080c0d06caSMauro Carvalho Chehab {
17090c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
17100c0d06caSMauro Carvalho Chehab 
17110c0d06caSMauro Carvalho Chehab 	return videobuf_querybuf(&fh->vidq, p);
17120c0d06caSMauro Carvalho Chehab }
17130c0d06caSMauro Carvalho Chehab 
17140c0d06caSMauro Carvalho Chehab static int vidioc_qbuf(struct file *file, void *priv,
17150c0d06caSMauro Carvalho Chehab 				struct v4l2_buffer *p)
17160c0d06caSMauro Carvalho Chehab {
17170c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
17180c0d06caSMauro Carvalho Chehab 
17190c0d06caSMauro Carvalho Chehab 	return videobuf_qbuf(&fh->vidq, p);
17200c0d06caSMauro Carvalho Chehab }
17210c0d06caSMauro Carvalho Chehab 
17220c0d06caSMauro Carvalho Chehab static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
17230c0d06caSMauro Carvalho Chehab {
17240c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
17250c0d06caSMauro Carvalho Chehab 
17260c0d06caSMauro Carvalho Chehab 	return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK);
17270c0d06caSMauro Carvalho Chehab }
17280c0d06caSMauro Carvalho Chehab 
17290c0d06caSMauro Carvalho Chehab 
17300c0d06caSMauro Carvalho Chehab static int vidioc_streamon(struct file *file, void *priv,
17310c0d06caSMauro Carvalho Chehab 				enum v4l2_buf_type i)
17320c0d06caSMauro Carvalho Chehab {
17330c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
17340c0d06caSMauro Carvalho Chehab 
17350c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
17360c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_streamon()\n");
17370c0d06caSMauro Carvalho Chehab 		cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
17380c0d06caSMauro Carvalho Chehab 		cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
17390c0d06caSMauro Carvalho Chehab 		if (dev->USE_ISO)
17400c0d06caSMauro Carvalho Chehab 			cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
17410c0d06caSMauro Carvalho Chehab 				       CX231XX_NUM_BUFS,
17420c0d06caSMauro Carvalho Chehab 				       dev->video_mode.max_pkt_size,
17430c0d06caSMauro Carvalho Chehab 				       cx231xx_isoc_copy);
17440c0d06caSMauro Carvalho Chehab 		else {
17450c0d06caSMauro Carvalho Chehab 			cx231xx_init_bulk(dev, 320,
17460c0d06caSMauro Carvalho Chehab 				       5,
17470c0d06caSMauro Carvalho Chehab 				       dev->ts1_mode.max_pkt_size,
17480c0d06caSMauro Carvalho Chehab 				       cx231xx_bulk_copy);
17490c0d06caSMauro Carvalho Chehab 		}
17500c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_streamon()\n");
17510c0d06caSMauro Carvalho Chehab 	return videobuf_streamon(&fh->vidq);
17520c0d06caSMauro Carvalho Chehab }
17530c0d06caSMauro Carvalho Chehab 
17540c0d06caSMauro Carvalho Chehab static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
17550c0d06caSMauro Carvalho Chehab {
17560c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
17570c0d06caSMauro Carvalho Chehab 
17580c0d06caSMauro Carvalho Chehab 	return videobuf_streamoff(&fh->vidq);
17590c0d06caSMauro Carvalho Chehab }
17600c0d06caSMauro Carvalho Chehab 
17610c0d06caSMauro Carvalho Chehab static int vidioc_g_ext_ctrls(struct file *file, void *priv,
17620c0d06caSMauro Carvalho Chehab 				struct v4l2_ext_controls *f)
17630c0d06caSMauro Carvalho Chehab {
17640c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
17650c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
17660c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_g_ext_ctrls()\n");
17670c0d06caSMauro Carvalho Chehab 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
17680c0d06caSMauro Carvalho Chehab 		return -EINVAL;
17690c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_g_ext_ctrls()\n");
17700c0d06caSMauro Carvalho Chehab 	return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
17710c0d06caSMauro Carvalho Chehab }
17720c0d06caSMauro Carvalho Chehab 
17730c0d06caSMauro Carvalho Chehab static int vidioc_s_ext_ctrls(struct file *file, void *priv,
17740c0d06caSMauro Carvalho Chehab 				struct v4l2_ext_controls *f)
17750c0d06caSMauro Carvalho Chehab {
17760c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
17770c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
17780c0d06caSMauro Carvalho Chehab 	struct cx2341x_mpeg_params p;
17790c0d06caSMauro Carvalho Chehab 	int err;
17800c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_s_ext_ctrls()\n");
17810c0d06caSMauro Carvalho Chehab 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
17820c0d06caSMauro Carvalho Chehab 		return -EINVAL;
17830c0d06caSMauro Carvalho Chehab 
17840c0d06caSMauro Carvalho Chehab 	p = dev->mpeg_params;
17850c0d06caSMauro Carvalho Chehab 	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
17860c0d06caSMauro Carvalho Chehab 	if (err == 0) {
17870c0d06caSMauro Carvalho Chehab 		err = cx2341x_update(dev, cx231xx_mbox_func,
17880c0d06caSMauro Carvalho Chehab 			&dev->mpeg_params, &p);
17890c0d06caSMauro Carvalho Chehab 		dev->mpeg_params = p;
17900c0d06caSMauro Carvalho Chehab 	}
17910c0d06caSMauro Carvalho Chehab 
17920c0d06caSMauro Carvalho Chehab 	return err;
17930c0d06caSMauro Carvalho Chehab 
17940c0d06caSMauro Carvalho Chehab 
17950c0d06caSMauro Carvalho Chehab return 0;
17960c0d06caSMauro Carvalho Chehab }
17970c0d06caSMauro Carvalho Chehab 
17980c0d06caSMauro Carvalho Chehab static int vidioc_try_ext_ctrls(struct file *file, void *priv,
17990c0d06caSMauro Carvalho Chehab 				struct v4l2_ext_controls *f)
18000c0d06caSMauro Carvalho Chehab {
18010c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
18020c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
18030c0d06caSMauro Carvalho Chehab 	struct cx2341x_mpeg_params p;
18040c0d06caSMauro Carvalho Chehab 	int err;
18050c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_try_ext_ctrls()\n");
18060c0d06caSMauro Carvalho Chehab 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
18070c0d06caSMauro Carvalho Chehab 		return -EINVAL;
18080c0d06caSMauro Carvalho Chehab 
18090c0d06caSMauro Carvalho Chehab 	p = dev->mpeg_params;
18100c0d06caSMauro Carvalho Chehab 	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
18110c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
18120c0d06caSMauro Carvalho Chehab 	return err;
18130c0d06caSMauro Carvalho Chehab }
18140c0d06caSMauro Carvalho Chehab 
18150c0d06caSMauro Carvalho Chehab static int vidioc_log_status(struct file *file, void *priv)
18160c0d06caSMauro Carvalho Chehab {
18170c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
18180c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
18190c0d06caSMauro Carvalho Chehab 	char name[32 + 2];
18200c0d06caSMauro Carvalho Chehab 
18210c0d06caSMauro Carvalho Chehab 	snprintf(name, sizeof(name), "%s/2", dev->name);
18220c0d06caSMauro Carvalho Chehab 	dprintk(3,
18230c0d06caSMauro Carvalho Chehab 		"%s/2: ============  START LOG STATUS  ============\n",
18240c0d06caSMauro Carvalho Chehab 	       dev->name);
18250c0d06caSMauro Carvalho Chehab 	call_all(dev, core, log_status);
18260c0d06caSMauro Carvalho Chehab 	cx2341x_log_status(&dev->mpeg_params, name);
18270c0d06caSMauro Carvalho Chehab 	dprintk(3,
18280c0d06caSMauro Carvalho Chehab 		"%s/2: =============  END LOG STATUS  =============\n",
18290c0d06caSMauro Carvalho Chehab 	       dev->name);
18300c0d06caSMauro Carvalho Chehab 	return 0;
18310c0d06caSMauro Carvalho Chehab }
18320c0d06caSMauro Carvalho Chehab 
18330c0d06caSMauro Carvalho Chehab static int vidioc_querymenu(struct file *file, void *priv,
18340c0d06caSMauro Carvalho Chehab 				struct v4l2_querymenu *a)
18350c0d06caSMauro Carvalho Chehab {
18360c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
18370c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
18380c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_querymenu()\n");
18390c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_querymenu()\n");
18400c0d06caSMauro Carvalho Chehab 	return cx231xx_querymenu(dev, a);
18410c0d06caSMauro Carvalho Chehab }
18420c0d06caSMauro Carvalho Chehab 
18430c0d06caSMauro Carvalho Chehab static int vidioc_queryctrl(struct file *file, void *priv,
18440c0d06caSMauro Carvalho Chehab 				struct v4l2_queryctrl *c)
18450c0d06caSMauro Carvalho Chehab {
18460c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = priv;
18470c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
18480c0d06caSMauro Carvalho Chehab 	dprintk(3, "enter vidioc_queryctrl()\n");
18490c0d06caSMauro Carvalho Chehab 	dprintk(3, "exit vidioc_queryctrl()\n");
18500c0d06caSMauro Carvalho Chehab 	return cx231xx_queryctrl(dev, c);
18510c0d06caSMauro Carvalho Chehab }
18520c0d06caSMauro Carvalho Chehab 
18530c0d06caSMauro Carvalho Chehab static int mpeg_open(struct file *file)
18540c0d06caSMauro Carvalho Chehab {
18550c0d06caSMauro Carvalho Chehab 	int minor = video_devdata(file)->minor;
18560c0d06caSMauro Carvalho Chehab 	struct cx231xx *h, *dev = NULL;
18570c0d06caSMauro Carvalho Chehab 	/*struct list_head *list;*/
18580c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh;
18590c0d06caSMauro Carvalho Chehab 	/*u32 value = 0;*/
18600c0d06caSMauro Carvalho Chehab 
18610c0d06caSMauro Carvalho Chehab 	dprintk(2, "%s()\n", __func__);
18620c0d06caSMauro Carvalho Chehab 
18630c0d06caSMauro Carvalho Chehab 	list_for_each_entry(h, &cx231xx_devlist, devlist) {
18640c0d06caSMauro Carvalho Chehab 		if (h->v4l_device->minor == minor)
18650c0d06caSMauro Carvalho Chehab 			dev = h;
18660c0d06caSMauro Carvalho Chehab 	}
18670c0d06caSMauro Carvalho Chehab 
18680c0d06caSMauro Carvalho Chehab 	if (dev == NULL)
18690c0d06caSMauro Carvalho Chehab 		return -ENODEV;
18700c0d06caSMauro Carvalho Chehab 
18711265f080SHans Verkuil 	if (mutex_lock_interruptible(&dev->lock))
18721265f080SHans Verkuil 		return -ERESTARTSYS;
18730c0d06caSMauro Carvalho Chehab 
18740c0d06caSMauro Carvalho Chehab 	/* allocate + initialize per filehandle data */
18750c0d06caSMauro Carvalho Chehab 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
18760c0d06caSMauro Carvalho Chehab 	if (NULL == fh) {
18770c0d06caSMauro Carvalho Chehab 		mutex_unlock(&dev->lock);
18780c0d06caSMauro Carvalho Chehab 		return -ENOMEM;
18790c0d06caSMauro Carvalho Chehab 	}
18800c0d06caSMauro Carvalho Chehab 
18810c0d06caSMauro Carvalho Chehab 	file->private_data = fh;
18820c0d06caSMauro Carvalho Chehab 	fh->dev      = dev;
18830c0d06caSMauro Carvalho Chehab 
18840c0d06caSMauro Carvalho Chehab 
18850c0d06caSMauro Carvalho Chehab 	videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
18860c0d06caSMauro Carvalho Chehab 			    NULL, &dev->video_mode.slock,
18870c0d06caSMauro Carvalho Chehab 			    V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
18881265f080SHans Verkuil 			    sizeof(struct cx231xx_buffer), fh, &dev->lock);
18890c0d06caSMauro Carvalho Chehab /*
18900c0d06caSMauro Carvalho Chehab 	videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
18910c0d06caSMauro Carvalho Chehab 			    &dev->udev->dev, &dev->ts1.slock,
18920c0d06caSMauro Carvalho Chehab 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
18930c0d06caSMauro Carvalho Chehab 			    V4L2_FIELD_INTERLACED,
18940c0d06caSMauro Carvalho Chehab 			    sizeof(struct cx231xx_buffer),
18951265f080SHans Verkuil 			    fh, &dev->lock);
18960c0d06caSMauro Carvalho Chehab */
18970c0d06caSMauro Carvalho Chehab 
18980c0d06caSMauro Carvalho Chehab 
18990c0d06caSMauro Carvalho Chehab 	cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
19000c0d06caSMauro Carvalho Chehab 	cx231xx_set_gpio_value(dev, 2, 0);
19010c0d06caSMauro Carvalho Chehab 
19020c0d06caSMauro Carvalho Chehab 	cx231xx_initialize_codec(dev);
19030c0d06caSMauro Carvalho Chehab 
19040c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
19050c0d06caSMauro Carvalho Chehab 	cx231xx_start_TS1(dev);
19060c0d06caSMauro Carvalho Chehab 
19070c0d06caSMauro Carvalho Chehab 	return 0;
19080c0d06caSMauro Carvalho Chehab }
19090c0d06caSMauro Carvalho Chehab 
19100c0d06caSMauro Carvalho Chehab static int mpeg_release(struct file *file)
19110c0d06caSMauro Carvalho Chehab {
19120c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh  *fh  = file->private_data;
19130c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
19140c0d06caSMauro Carvalho Chehab 
19150c0d06caSMauro Carvalho Chehab 	dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
19160c0d06caSMauro Carvalho Chehab 
19170c0d06caSMauro Carvalho Chehab 	if (!dev) {
19180c0d06caSMauro Carvalho Chehab 		dprintk(3, "abort!!!\n");
19190c0d06caSMauro Carvalho Chehab 		return 0;
19200c0d06caSMauro Carvalho Chehab 	}
19210c0d06caSMauro Carvalho Chehab 
19220c0d06caSMauro Carvalho Chehab 	mutex_lock(&dev->lock);
19230c0d06caSMauro Carvalho Chehab 
19240c0d06caSMauro Carvalho Chehab 	cx231xx_stop_TS1(dev);
19250c0d06caSMauro Carvalho Chehab 
19260c0d06caSMauro Carvalho Chehab 		/* do this before setting alternate! */
19270c0d06caSMauro Carvalho Chehab 		if (dev->USE_ISO)
19280c0d06caSMauro Carvalho Chehab 			cx231xx_uninit_isoc(dev);
19290c0d06caSMauro Carvalho Chehab 		else
19300c0d06caSMauro Carvalho Chehab 			cx231xx_uninit_bulk(dev);
19310c0d06caSMauro Carvalho Chehab 		cx231xx_set_mode(dev, CX231XX_SUSPEND);
19320c0d06caSMauro Carvalho Chehab 
19330c0d06caSMauro Carvalho Chehab 		cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
19340c0d06caSMauro Carvalho Chehab 				CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
19350c0d06caSMauro Carvalho Chehab 				CX231xx_RAW_BITS_NONE);
19360c0d06caSMauro Carvalho Chehab 
19370c0d06caSMauro Carvalho Chehab 	/* FIXME: Review this crap */
19380c0d06caSMauro Carvalho Chehab 	/* Shut device down on last close */
19390c0d06caSMauro Carvalho Chehab 	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
19400c0d06caSMauro Carvalho Chehab 		if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
19410c0d06caSMauro Carvalho Chehab 			/* stop mpeg capture */
19420c0d06caSMauro Carvalho Chehab 
19430c0d06caSMauro Carvalho Chehab 			msleep(500);
19440c0d06caSMauro Carvalho Chehab 			cx231xx_417_check_encoder(dev);
19450c0d06caSMauro Carvalho Chehab 
19460c0d06caSMauro Carvalho Chehab 		}
19470c0d06caSMauro Carvalho Chehab 	}
19480c0d06caSMauro Carvalho Chehab 
19490c0d06caSMauro Carvalho Chehab 	if (fh->vidq.streaming)
19500c0d06caSMauro Carvalho Chehab 		videobuf_streamoff(&fh->vidq);
19510c0d06caSMauro Carvalho Chehab 	if (fh->vidq.reading)
19520c0d06caSMauro Carvalho Chehab 		videobuf_read_stop(&fh->vidq);
19530c0d06caSMauro Carvalho Chehab 
19540c0d06caSMauro Carvalho Chehab 	videobuf_mmap_free(&fh->vidq);
19550c0d06caSMauro Carvalho Chehab 	file->private_data = NULL;
19560c0d06caSMauro Carvalho Chehab 	kfree(fh);
19570c0d06caSMauro Carvalho Chehab 	mutex_unlock(&dev->lock);
19580c0d06caSMauro Carvalho Chehab 	return 0;
19590c0d06caSMauro Carvalho Chehab }
19600c0d06caSMauro Carvalho Chehab 
19610c0d06caSMauro Carvalho Chehab static ssize_t mpeg_read(struct file *file, char __user *data,
19620c0d06caSMauro Carvalho Chehab 	size_t count, loff_t *ppos)
19630c0d06caSMauro Carvalho Chehab {
19640c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = file->private_data;
19650c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
19660c0d06caSMauro Carvalho Chehab 
19670c0d06caSMauro Carvalho Chehab 
19680c0d06caSMauro Carvalho Chehab 	/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
19690c0d06caSMauro Carvalho Chehab 	/* Start mpeg encoder on first read. */
19700c0d06caSMauro Carvalho Chehab 	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
19710c0d06caSMauro Carvalho Chehab 		if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
19720c0d06caSMauro Carvalho Chehab 			if (cx231xx_initialize_codec(dev) < 0)
19730c0d06caSMauro Carvalho Chehab 				return -EINVAL;
19740c0d06caSMauro Carvalho Chehab 		}
19750c0d06caSMauro Carvalho Chehab 	}
19760c0d06caSMauro Carvalho Chehab 
19770c0d06caSMauro Carvalho Chehab 	return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
19780c0d06caSMauro Carvalho Chehab 				    file->f_flags & O_NONBLOCK);
19790c0d06caSMauro Carvalho Chehab }
19800c0d06caSMauro Carvalho Chehab 
19810c0d06caSMauro Carvalho Chehab static unsigned int mpeg_poll(struct file *file,
19820c0d06caSMauro Carvalho Chehab 	struct poll_table_struct *wait)
19830c0d06caSMauro Carvalho Chehab {
19840c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = file->private_data;
19850c0d06caSMauro Carvalho Chehab 	/*struct cx231xx *dev = fh->dev;*/
19860c0d06caSMauro Carvalho Chehab 
19870c0d06caSMauro Carvalho Chehab 	/*dprintk(2, "%s\n", __func__);*/
19880c0d06caSMauro Carvalho Chehab 
19890c0d06caSMauro Carvalho Chehab 	return videobuf_poll_stream(file, &fh->vidq, wait);
19900c0d06caSMauro Carvalho Chehab }
19910c0d06caSMauro Carvalho Chehab 
19920c0d06caSMauro Carvalho Chehab static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
19930c0d06caSMauro Carvalho Chehab {
19940c0d06caSMauro Carvalho Chehab 	struct cx231xx_fh *fh = file->private_data;
19950c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev = fh->dev;
19960c0d06caSMauro Carvalho Chehab 
19970c0d06caSMauro Carvalho Chehab 	dprintk(2, "%s()\n", __func__);
19980c0d06caSMauro Carvalho Chehab 
19990c0d06caSMauro Carvalho Chehab 	return videobuf_mmap_mapper(&fh->vidq, vma);
20000c0d06caSMauro Carvalho Chehab }
20010c0d06caSMauro Carvalho Chehab 
20020c0d06caSMauro Carvalho Chehab static struct v4l2_file_operations mpeg_fops = {
20030c0d06caSMauro Carvalho Chehab 	.owner	       = THIS_MODULE,
20040c0d06caSMauro Carvalho Chehab 	.open	       = mpeg_open,
20050c0d06caSMauro Carvalho Chehab 	.release       = mpeg_release,
20060c0d06caSMauro Carvalho Chehab 	.read	       = mpeg_read,
20070c0d06caSMauro Carvalho Chehab 	.poll          = mpeg_poll,
20080c0d06caSMauro Carvalho Chehab 	.mmap	       = mpeg_mmap,
20091265f080SHans Verkuil 	.unlocked_ioctl = video_ioctl2,
20100c0d06caSMauro Carvalho Chehab };
20110c0d06caSMauro Carvalho Chehab 
20120c0d06caSMauro Carvalho Chehab static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
20130c0d06caSMauro Carvalho Chehab 	.vidioc_s_std		 = vidioc_s_std,
20140c0d06caSMauro Carvalho Chehab 	.vidioc_g_std		 = vidioc_g_std,
20150c0d06caSMauro Carvalho Chehab 	.vidioc_enum_input	 = vidioc_enum_input,
20160c0d06caSMauro Carvalho Chehab 	.vidioc_g_input		 = vidioc_g_input,
20170c0d06caSMauro Carvalho Chehab 	.vidioc_s_input		 = vidioc_s_input,
20180c0d06caSMauro Carvalho Chehab 	.vidioc_s_ctrl		 = vidioc_s_ctrl,
20190c0d06caSMauro Carvalho Chehab 	.vidioc_querycap	 = vidioc_querycap,
20200c0d06caSMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
20210c0d06caSMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
20220c0d06caSMauro Carvalho Chehab 	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
2023*3f926e32SHans Verkuil 	.vidioc_s_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
20240c0d06caSMauro Carvalho Chehab 	.vidioc_reqbufs		 = vidioc_reqbufs,
20250c0d06caSMauro Carvalho Chehab 	.vidioc_querybuf	 = vidioc_querybuf,
20260c0d06caSMauro Carvalho Chehab 	.vidioc_qbuf		 = vidioc_qbuf,
20270c0d06caSMauro Carvalho Chehab 	.vidioc_dqbuf		 = vidioc_dqbuf,
20280c0d06caSMauro Carvalho Chehab 	.vidioc_streamon	 = vidioc_streamon,
20290c0d06caSMauro Carvalho Chehab 	.vidioc_streamoff	 = vidioc_streamoff,
20300c0d06caSMauro Carvalho Chehab 	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
20310c0d06caSMauro Carvalho Chehab 	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
20320c0d06caSMauro Carvalho Chehab 	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
20330c0d06caSMauro Carvalho Chehab 	.vidioc_log_status	 = vidioc_log_status,
20340c0d06caSMauro Carvalho Chehab 	.vidioc_querymenu	 = vidioc_querymenu,
20350c0d06caSMauro Carvalho Chehab 	.vidioc_queryctrl	 = vidioc_queryctrl,
20360c0d06caSMauro Carvalho Chehab /*	.vidioc_g_chip_ident	 = cx231xx_g_chip_ident,*/
20370c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
20380c0d06caSMauro Carvalho Chehab /*	.vidioc_g_register	 = cx231xx_g_register,*/
20390c0d06caSMauro Carvalho Chehab /*	.vidioc_s_register	 = cx231xx_s_register,*/
20400c0d06caSMauro Carvalho Chehab #endif
20410c0d06caSMauro Carvalho Chehab };
20420c0d06caSMauro Carvalho Chehab 
20430c0d06caSMauro Carvalho Chehab static struct video_device cx231xx_mpeg_template = {
20440c0d06caSMauro Carvalho Chehab 	.name          = "cx231xx",
20450c0d06caSMauro Carvalho Chehab 	.fops          = &mpeg_fops,
20460c0d06caSMauro Carvalho Chehab 	.ioctl_ops     = &mpeg_ioctl_ops,
20470c0d06caSMauro Carvalho Chehab 	.minor         = -1,
20480c0d06caSMauro Carvalho Chehab 	.tvnorms       = CX231xx_NORMS,
20490c0d06caSMauro Carvalho Chehab };
20500c0d06caSMauro Carvalho Chehab 
20510c0d06caSMauro Carvalho Chehab void cx231xx_417_unregister(struct cx231xx *dev)
20520c0d06caSMauro Carvalho Chehab {
20530c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
20540c0d06caSMauro Carvalho Chehab 	dprintk(3, "%s()\n", __func__);
20550c0d06caSMauro Carvalho Chehab 
20560c0d06caSMauro Carvalho Chehab 	if (dev->v4l_device) {
20570c0d06caSMauro Carvalho Chehab 		if (-1 != dev->v4l_device->minor)
20580c0d06caSMauro Carvalho Chehab 			video_unregister_device(dev->v4l_device);
20590c0d06caSMauro Carvalho Chehab 		else
20600c0d06caSMauro Carvalho Chehab 			video_device_release(dev->v4l_device);
20610c0d06caSMauro Carvalho Chehab 		dev->v4l_device = NULL;
20620c0d06caSMauro Carvalho Chehab 	}
20630c0d06caSMauro Carvalho Chehab }
20640c0d06caSMauro Carvalho Chehab 
20650c0d06caSMauro Carvalho Chehab static struct video_device *cx231xx_video_dev_alloc(
20660c0d06caSMauro Carvalho Chehab 	struct cx231xx *dev,
20670c0d06caSMauro Carvalho Chehab 	struct usb_device *usbdev,
20680c0d06caSMauro Carvalho Chehab 	struct video_device *template,
20690c0d06caSMauro Carvalho Chehab 	char *type)
20700c0d06caSMauro Carvalho Chehab {
20710c0d06caSMauro Carvalho Chehab 	struct video_device *vfd;
20720c0d06caSMauro Carvalho Chehab 
20730c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
20740c0d06caSMauro Carvalho Chehab 	vfd = video_device_alloc();
20750c0d06caSMauro Carvalho Chehab 	if (NULL == vfd)
20760c0d06caSMauro Carvalho Chehab 		return NULL;
20770c0d06caSMauro Carvalho Chehab 	*vfd = *template;
20780c0d06caSMauro Carvalho Chehab 	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
20790c0d06caSMauro Carvalho Chehab 		type, cx231xx_boards[dev->model].name);
20800c0d06caSMauro Carvalho Chehab 
20810c0d06caSMauro Carvalho Chehab 	vfd->v4l2_dev = &dev->v4l2_dev;
20821265f080SHans Verkuil 	vfd->lock = &dev->lock;
20830c0d06caSMauro Carvalho Chehab 	vfd->release = video_device_release;
20840c0d06caSMauro Carvalho Chehab 
20850c0d06caSMauro Carvalho Chehab 	return vfd;
20860c0d06caSMauro Carvalho Chehab 
20870c0d06caSMauro Carvalho Chehab }
20880c0d06caSMauro Carvalho Chehab 
20890c0d06caSMauro Carvalho Chehab int cx231xx_417_register(struct cx231xx *dev)
20900c0d06caSMauro Carvalho Chehab {
20910c0d06caSMauro Carvalho Chehab 	/* FIXME: Port1 hardcoded here */
20920c0d06caSMauro Carvalho Chehab 	int err = -ENODEV;
20930c0d06caSMauro Carvalho Chehab 	struct cx231xx_tsport *tsport = &dev->ts1;
20940c0d06caSMauro Carvalho Chehab 
20950c0d06caSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
20960c0d06caSMauro Carvalho Chehab 
20970c0d06caSMauro Carvalho Chehab 	/* Set default TV standard */
20980c0d06caSMauro Carvalho Chehab 	dev->encodernorm = cx231xx_tvnorms[0];
20990c0d06caSMauro Carvalho Chehab 
21000c0d06caSMauro Carvalho Chehab 	if (dev->encodernorm.id & V4L2_STD_525_60)
21010c0d06caSMauro Carvalho Chehab 		tsport->height = 480;
21020c0d06caSMauro Carvalho Chehab 	else
21030c0d06caSMauro Carvalho Chehab 		tsport->height = 576;
21040c0d06caSMauro Carvalho Chehab 
21050c0d06caSMauro Carvalho Chehab 	tsport->width = 720;
21060c0d06caSMauro Carvalho Chehab 	cx2341x_fill_defaults(&dev->mpeg_params);
21070c0d06caSMauro Carvalho Chehab 	dev->norm = V4L2_STD_NTSC;
21080c0d06caSMauro Carvalho Chehab 
21090c0d06caSMauro Carvalho Chehab 	dev->mpeg_params.port = CX2341X_PORT_SERIAL;
21100c0d06caSMauro Carvalho Chehab 
21110c0d06caSMauro Carvalho Chehab 	/* Allocate and initialize V4L video device */
21120c0d06caSMauro Carvalho Chehab 	dev->v4l_device = cx231xx_video_dev_alloc(dev,
21130c0d06caSMauro Carvalho Chehab 		dev->udev, &cx231xx_mpeg_template, "mpeg");
21140c0d06caSMauro Carvalho Chehab 	err = video_register_device(dev->v4l_device,
21150c0d06caSMauro Carvalho Chehab 		VFL_TYPE_GRABBER, -1);
21160c0d06caSMauro Carvalho Chehab 	if (err < 0) {
21170c0d06caSMauro Carvalho Chehab 		dprintk(3, "%s: can't register mpeg device\n", dev->name);
21180c0d06caSMauro Carvalho Chehab 		return err;
21190c0d06caSMauro Carvalho Chehab 	}
21200c0d06caSMauro Carvalho Chehab 
21210c0d06caSMauro Carvalho Chehab 	dprintk(3, "%s: registered device video%d [mpeg]\n",
21220c0d06caSMauro Carvalho Chehab 	       dev->name, dev->v4l_device->num);
21230c0d06caSMauro Carvalho Chehab 
21240c0d06caSMauro Carvalho Chehab 	return 0;
21250c0d06caSMauro Carvalho Chehab }
21260c0d06caSMauro Carvalho Chehab 
21270c0d06caSMauro Carvalho Chehab MODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME);
2128