diff options
Diffstat (limited to 'drivers/media/video/cx23885')
-rw-r--r-- | drivers/media/video/cx23885/cx23885-417.c | 141 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-cards.c | 79 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-core.c | 24 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-dvb.c | 113 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-i2c.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-video.c | 176 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885.h | 14 |
7 files changed, 403 insertions, 146 deletions
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 67c4a59..f5c79e5 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -900,6 +900,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) int i, retval = 0; u32 value = 0; u32 gpio_output = 0; + u32 gpio_value; u32 checksum = 0; u32 *dataptr; @@ -907,7 +908,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) /* Save GPIO settings before reset of APU */ retval |= mc417_memory_read(dev, 0x9020, &gpio_output); - retval |= mc417_memory_read(dev, 0x900C, &value); + retval |= mc417_memory_read(dev, 0x900C, &gpio_value); retval = mc417_register_write(dev, IVTV_REG_VPU, 0xFFFFFFED); @@ -991,11 +992,18 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) /* F/W power up disturbs the GPIOs, restore state */ retval |= mc417_register_write(dev, 0x9020, gpio_output); - retval |= mc417_register_write(dev, 0x900C, value); + retval |= mc417_register_write(dev, 0x900C, gpio_value); retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); + /* Hardcoded GPIO's here */ + retval |= mc417_register_write(dev, 0x9020, 0x4000); + retval |= mc417_register_write(dev, 0x900C, 0x4000); + + mc417_register_read(dev, 0x9020, &gpio_output); + mc417_register_read(dev, 0x900C, &gpio_value); + if (retval < 0) printk(KERN_ERR "%s: Error with mc417_register_write\n", __func__); @@ -1015,6 +1023,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); + /* Dynamically change the height based on video standard */ + if (dev->encodernorm.id & V4L2_STD_525_60) + dev->ts1.height = 480; + else + dev->ts1.height = 576; + /* assign frame size */ cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->ts1.height, dev->ts1.width); @@ -1030,7 +1044,7 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); } -static int cx23885_initialize_codec(struct cx23885_dev *dev) +static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) { int version; int retval; @@ -1112,9 +1126,11 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev) mc417_memory_write(dev, 2120, 0x00000080); /* start capturing to the host interface */ - cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); - msleep(10); + if (startencoder) { + cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, + CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); + msleep(10); + } return 0; } @@ -1196,6 +1212,16 @@ static int cx23885_querymenu(struct cx23885_dev *dev, cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + call_all(dev, core, g_std, id); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_fh *fh = file->private_data; @@ -1208,55 +1234,31 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; dev->encodernorm = cx23885_tvnorms[i]; + + /* Have the drier core notify the subdevices */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, *id); + mutex_unlock(&dev->lock); + return 0; } static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) + struct v4l2_input *i) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_input *input; - int n; - - if (i->index >= 4) - return -EINVAL; - - input = &cx23885_boards[dev->board].input[i->index]; - - if (input->type == 0) - return -EINVAL; - - /* FIXME - * strcpy(i->name, input->name); */ - strcpy(i->name, "unset"); - - if (input->type == CX23885_VMUX_TELEVISION || - input->type == CX23885_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) - i->std |= cx23885_tvnorms[n].id; - return 0; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + return cx23885_enum_input(dev, i); } static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - *i = dev->input; - return 0; + return cx23885_get_input(file, priv, i); } static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - if (i >= 4) - return -EINVAL; - - return 0; + return cx23885_set_input(file, priv, i); } static int vidioc_g_tuner(struct file *file, void *priv, @@ -1309,43 +1311,25 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", - dev->tuner_type); - dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", - f->tuner, f->type); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - dev->freq = f->frequency; - - call_all(dev, tuner, s_frequency, f); + return cx23885_set_frequency(file, priv, f); +} - cx23885_initialize_codec(dev); +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - return 0; + return cx23885_get_control(dev, ctl); } static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) + struct v4l2_control *ctl) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - /* Update the A/V core */ - call_all(dev, core, s_ctrl, ctl); - return 0; + return cx23885_set_control(dev, ctl); } static int vidioc_querycap(struct file *file, void *priv, @@ -1636,7 +1620,7 @@ static ssize_t mpeg_read(struct file *file, char __user *data, /* Start mpeg encoder on first read. */ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev) < 0) + if (cx23885_initialize_codec(dev, 1) < 0) return -EINVAL; } } @@ -1677,6 +1661,8 @@ static struct v4l2_file_operations mpeg_fops = { }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { + .vidioc_querystd = vidioc_g_std, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1686,6 +1672,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1746,8 +1733,8 @@ static struct video_device *cx23885_video_dev_alloc( if (NULL == vfd) return NULL; *vfd = *template; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, cx23885_boards[tsport->dev->board].name); + snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", + cx23885_boards[tsport->dev->board].name, type); vfd->parent = &pci->dev; vfd->release = video_device_release; return vfd; @@ -1791,5 +1778,11 @@ int cx23885_417_register(struct cx23885_dev *dev) printk(KERN_INFO "%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->v4l_device)); + /* ST: Configure the encoder paramaters, but don't begin + * encoding, this resolves an issue where the first time the + * encoder is started video can be choppy. + */ + cx23885_initialize_codec(dev, 0); + return 0; } diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index c3cf089..19b5499 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -213,8 +213,8 @@ struct cx23885_board cx23885_boards[] = { .portc = CX23885_MPEG_DVB, .tuner_type = TUNER_XC4000, .tuner_addr = 0x61, - .radio_type = TUNER_XC4000, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = {{ .type = CX23885_VMUX_TELEVISION, .vmux = CX25840_VIN2_CH1 | @@ -335,8 +335,33 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1850] = { .name = "Hauppauge WinTV-HVR1850", + .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_ENCODER, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1 | + CX25840_DIF_ON, + .amux = CX25840_AUDIO8, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, }, [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { .name = "Compro VideoMate E800", @@ -438,6 +463,41 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0, } }, }, + [CX23885_BOARD_MYGICA_X8507] = { + .name = "Mygica X8507", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_bus = 1, + .porta = CX23885_ANALOG_VIDEO, + .input = { + { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE2, + .amux = CX25840_AUDIO8, + }, + { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE8, + }, + { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, + { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_COMPONENT_ON | + CX25840_VIN1_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN7_CH3, + }, + }, + }, + [CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = { + .name = "TerraTec Cinergy T PCIe Dual", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + } }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -637,6 +697,14 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x1b55, .subdevice = 0xe2e4, .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8502, + .card = CX23885_BOARD_MYGICA_X8507, + }, { + .subvendor = 0x153b, + .subdevice = 0x117e, + .card = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1068,6 +1136,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_MYGICA_X8506: case CX23885_BOARD_MAGICPRO_PROHDTVE2: + case CX23885_BOARD_MYGICA_X8507: /* GPIO-0 (0)Analog / (1)Digital TV */ /* GPIO-1 reset XC5000 */ /* GPIO-2 reset LGS8GL5 / LGS8G75 */ @@ -1367,6 +1436,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* Defaults for VID B - Analog encoder */ /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ @@ -1377,6 +1447,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* APB_TSVALERR_POL (active low)*/ ts1->vld_misc_val = 0x2000; ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); + cx_write(0x130184, 0xc); /* Defaults for VID C */ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ @@ -1396,6 +1467,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -1431,7 +1503,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: - case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: @@ -1468,6 +1539,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_MPX885: + case CX23885_BOARD_MYGICA_X8507: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 40e68b2..6ad2270 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -206,12 +206,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA1_CNT2, }, [SRAM_CH02] = { - .name = "ch2", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "VID A (VBI)", + .cmds_start = 0x10050, + .ctrl_start = 0x105F0, + .cdt = 0x10810, + .fifo_start = 0x3000, + .fifo_size = 0x1000, .ptr1_reg = DMA2_PTR1, .ptr2_reg = DMA2_PTR2, .cnt1_reg = DMA2_CNT1, @@ -266,12 +266,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA5_CNT2, }, [SRAM_CH07] = { - .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TV Audio", + .cmds_start = 0x10190, + .ctrl_start = 0x106B0, + .cdt = 0x10930, + .fifo_start = 0x7000, + .fifo_size = 0x1000, .ptr1_reg = DMA6_PTR1, .ptr2_reg = DMA6_PTR2, .cnt1_reg = DMA6_CNT1, diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index bcb45be..6835eb1 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -61,6 +61,8 @@ #include "cx23885-f300.h" #include "altera-ci.h" #include "stv0367.h" +#include "drxk.h" +#include "mt2063.h" static unsigned int debug; @@ -111,6 +113,8 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer *)vb); } +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe); + static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) { struct videobuf_dvb_frontends *f; @@ -125,6 +129,12 @@ static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); + + /* + * FIXME: Improve this path to avoid calling the + * cx23885_dvb_set_frontend() every time it passes here. + */ + cx23885_dvb_set_frontend(fe->dvb.frontend); } static struct videobuf_queue_ops dvb_qops = { @@ -479,15 +489,15 @@ static struct xc5000_config mygica_x8506_xc5000_config = { .if_khz = 5380, }; -static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1275: - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: cx23885_gpio_clear(dev, GPIO_5); break; @@ -507,31 +517,6 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, return 0; } -static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, - unsigned int cmd, void *parg, - unsigned int stage) -{ - int err = 0; - - switch (stage) { - case DVB_FE_IOCTL_PRE: - - switch (cmd) { - case FE_SET_FRONTEND: - err = cx23885_dvb_set_frontend(fe, - (struct dvb_frontend_parameters *) parg); - break; - } - break; - - case DVB_FE_IOCTL_POST: - /* no post-ioctl handling required */ - break; - } - return err; -}; - - static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { .prod = LGS8GXX_PROD_LGS8G75, .demod_address = 0x19, @@ -617,6 +602,24 @@ static struct xc5000_config netup_xc5000_config[] = { }, }; +static struct drxk_config terratec_drxk_config[] = { + { + .adr = 0x29, + .no_i2c_bridge = 1, + }, { + .adr = 0x2a, + .no_i2c_bridge = 1, + }, +}; + +static struct mt2063_config terratec_mt2063_config[] = { + { + .tuner_address = 0x60, + }, { + .tuner_address = 0x67, + }, +}; + int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -940,6 +943,11 @@ static int dvb_register(struct cx23885_tsport *port) fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->i2c_bus[1].i2c_adap, &cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc4000 attach failed\n", + dev->name); + goto frontend_detach; + } } break; case CX23885_BOARD_TBS_6920: @@ -1043,6 +1051,20 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_HVR1850: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[0].i2c_adap, + &hauppauge_tda18271_config); + + tda18271_attach(&dev->ts1.analog_fe, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + + break; case CX23885_BOARD_HAUPPAUGE_HVR1290: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(s5h1411_attach, @@ -1118,6 +1140,39 @@ static int dvb_register(struct cx23885_tsport *port) goto frontend_detach; } break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + + switch (port->nr) { + /* port b */ + case 1: + fe0->dvb.frontend = dvb_attach(drxk_attach, + &terratec_drxk_config[0], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(mt2063_attach, + fe0->dvb.frontend, + &terratec_mt2063_config[0], + &i2c_bus2->i2c_adap)) + goto frontend_detach; + } + break; + /* port c */ + case 2: + fe0->dvb.frontend = dvb_attach(drxk_attach, + &terratec_drxk_config[1], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(mt2063_attach, + fe0->dvb.frontend, + &terratec_mt2063_config[1], + &i2c_bus2->i2c_adap)) + goto frontend_detach; + } + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -1151,7 +1206,7 @@ static int dvb_register(struct cx23885_tsport *port) /* register everything */ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, mfe_shared, - cx23885_dvb_fe_ioctl_override); + NULL); if (ret) goto frontend_detach; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 0ff7a9e..be1e21d 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -309,7 +309,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx23885_i2c_register(struct cx23885_i2c *bus) { struct cx23885_dev *dev = bus->dev; diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index e730b92..c654bdc 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -253,9 +253,9 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, + .maximum = 65535, + .step = 65535 / 100, + .default_value = 65535, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = PATH1_VOL_CTL, @@ -316,7 +316,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, __func__, bc); } -static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) { dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, @@ -344,8 +344,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, cx23885_boards[dev->board].name); + snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", + cx23885_boards[dev->board].name, type); video_set_drvdata(vfd, dev); return vfd; } @@ -492,7 +492,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) dev->input = input; if (dev->board == CX23885_BOARD_MYGICA_X8506 || - dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { + dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 || + dev->board == CX23885_BOARD_MYGICA_X8507) { /* Select Analog TV */ if (INPUT(input)->type == CX23885_VMUX_TELEVISION) cx23885_gpio_clear(dev, GPIO_0); @@ -503,7 +504,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) INPUT(input)->vmux, 0, 0); if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || - (dev->board == CX23885_BOARD_MPX885)) { + (dev->board == CX23885_BOARD_MPX885) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); @@ -649,6 +651,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, int rc, init_buffer = 0; u32 line0_offset, line1_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + int field_tff; BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || @@ -690,15 +693,25 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) { + if (dev->tvnorm & V4L2_STD_NTSC) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; + + if (field_tff) { /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating NTSC risc\n", + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); line0_offset = buf->bpl; line1_offset = 0; } else { /* All other formats are top field first */ - dprintk(1, "%s() Creating PAL/SECAM risc\n", + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); line0_offset = 0; line1_offset = buf->bpl; @@ -981,6 +994,8 @@ static int video_release(struct file *file) } videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&fh->vbiq); + file->private_data = NULL; kfree(fh); @@ -1002,7 +1017,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -static int cx23885_get_control(struct cx23885_dev *dev, +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); @@ -1010,7 +1025,7 @@ static int cx23885_get_control(struct cx23885_dev *dev, return 0; } -static int cx23885_set_control(struct cx23885_dev *dev, +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); @@ -1229,6 +1244,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + + call_all(dev, core, g_std, id); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1241,7 +1266,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) return 0; } -static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) { static const char *iname[] = { [CX23885_VMUX_COMPOSITE1] = "Composite1", @@ -1278,6 +1303,15 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) if (INPUT(n)->type != CX23885_VMUX_TELEVISION) i->audioset = 0x3; + if (dev->input == n) { + /* enum'd input matches our configured input. + * Ask the video decoder to process the call + * and give it an oppertunity to update the + * status field. + */ + call_all(dev, video, g_input_status, &i->status); + } + return 0; } @@ -1289,7 +1323,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return cx23885_enum_input(dev, i); } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +int cx23885_get_input(struct file *file, void *priv, unsigned int *i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1298,7 +1332,12 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + return cx23885_get_input(file, priv, i); +} + +int cx23885_set_input(struct file *file, void *priv, unsigned int i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1322,6 +1361,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return cx23885_set_input(file, priv, i); +} + static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_fh *fh = priv; @@ -1329,11 +1373,11 @@ static int vidioc_log_status(struct file *file, void *priv) printk(KERN_INFO "%s/0: ============ START LOG STATUS ============\n", - dev->name); + dev->name); call_all(dev, core, log_status); printk(KERN_INFO "%s/0: ============= END LOG STATUS =============\n", - dev->name); + dev->name); return 0; } @@ -1471,6 +1515,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) { + struct v4l2_control ctrl; + if (unlikely(UNSET == dev->tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) @@ -1479,29 +1525,103 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) mutex_lock(&dev->lock); dev->freq = f->frequency; + /* I need to mute audio here */ + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + cx23885_set_control(dev, &ctrl); + call_all(dev, tuner, s_frequency, f); /* When changing channels it is required to reset TVAUDIO */ - msleep(10); + msleep(100); + + /* I need to unmute audio here */ + ctrl.value = 0; + cx23885_set_control(dev, &ctrl); mutex_unlock(&dev->lock); return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) +static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, + struct v4l2_frequency *f) +{ + struct v4l2_control ctrl; + struct videobuf_dvb_frontend *vfe; + struct dvb_frontend *fe; + + struct analog_parameters params = { + .mode = V4L2_TUNER_ANALOG_TV, + .audmode = V4L2_TUNER_MODE_STEREO, + .std = dev->tvnorm, + .frequency = f->frequency + }; + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + /* I need to mute audio here */ + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + cx23885_set_control(dev, &ctrl); + + /* If HVR1850 */ + dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, + params.frequency, f->tuner, params.std); + + vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + if (!vfe) { + mutex_unlock(&dev->lock); + return -EINVAL; + } + + fe = vfe->dvb.frontend; + + if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) + fe = &dev->ts1.analog_fe; + + if (fe && fe->ops.tuner_ops.set_analog_params) { + call_all(dev, core, s_std, dev->tvnorm); + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + } + else + printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(100); + + /* I need to unmute audio here */ + ctrl.value = 0; + cx23885_set_control(dev, &ctrl); + + mutex_unlock(&dev->lock); + + return 0; +} + +int cx23885_set_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; + int ret; - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1850: + ret = cx23885_set_freq_via_ops(dev, f); + break; + default: + ret = cx23885_set_freq(dev, f); + } - return - cx23885_set_freq(dev, f); + return ret; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + return cx23885_set_frequency(file, priv, f); } /* ----------------------------------------------------------- */ @@ -1613,6 +1733,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, + .vidioc_querystd = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b49036f..f020f05 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -87,6 +87,8 @@ #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 #define CX23885_BOARD_MPX885 32 +#define CX23885_BOARD_MYGICA_X8507 33 +#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -226,6 +228,8 @@ struct cx23885_board { u32 clk_freq; struct cx23885_input input[MAX_CX23885_INPUT]; int ci_type; /* for NetUP */ + /* Force bottom field first during DMA (888 workaround) */ + u32 force_bff; }; struct cx23885_subid { @@ -310,6 +314,9 @@ struct cx23885_tsport { u32 num_frontends; void (*gate_ctrl)(struct cx23885_tsport *port, int open); void *port_priv; + + /* Workaround for a temp dvb_frontend that the tuner can attached to */ + struct dvb_frontend analog_fe; }; struct cx23885_kernel_ir { @@ -574,6 +581,13 @@ extern void cx23885_video_unregister(struct cx23885_dev *dev); extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); extern void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count); +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); +int cx23885_set_input(struct file *file, void *priv, unsigned int i); +int cx23885_get_input(struct file *file, void *priv, unsigned int *i); +int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f); +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); /* ----------------------------------------------------------- */ /* cx23885-vbi.c */ |