📄 av7110_v4l.c
字号:
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume return 0; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; DEB_EE(("VIDIOC_ENUMINPUT: %d\n", i->index)); if (av7110->has_analog_tuner ) { if (i->index < 0 || i->index >= 2) return -EINVAL; } else { if (i->index != 0) return -EINVAL; } memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); return 0; } case VIDIOC_G_INPUT: { int *input = (int *)arg; *input = av7110->current_input; DEB_EE(("VIDIOC_G_INPUT: %d\n", *input)); return 0; } case VIDIOC_S_INPUT: { int input = *(int *)arg; DEB_EE(("VIDIOC_S_INPUT: %d\n", input)); if (!av7110->has_analog_tuner ) return 0; if (input < 0 || input >= 2) return -EINVAL; /* FIXME: switch inputs here */ av7110->current_input = input; return av7110_dvb_c_switch(fh); } case VIDIOC_G_AUDIO: { struct v4l2_audio *a = arg; DEB_EE(("VIDIOC_G_AUDIO: %d\n", a->index)); if (a->index != 0) return -EINVAL; memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); break; } case VIDIOC_S_AUDIO: { struct v4l2_audio *a = arg; DEB_EE(("VIDIOC_S_AUDIO: %d\n", a->index)); break; } default: printk("no such ioctl\n"); return -ENOIOCTLCMD; } return 0;}/**************************************************************************** * INITIALIZATION ****************************************************************************/struct saa7146_extension_ioctls ioctls[] = { { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, { 0, 0 }};static u8 saa7113_init_regs[] = { 0x02, 0xd0, 0x03, 0x23, 0x04, 0x00, 0x05, 0x00, 0x06, 0xe9, 0x07, 0x0d, 0x08, 0x98, 0x09, 0x02, 0x0a, 0x80, 0x0b, 0x40, 0x0c, 0x40, 0x0d, 0x00, 0x0e, 0x01, 0x0f, 0x7c, 0x10, 0x48, 0x11, 0x0c, 0x12, 0x8b, 0x13, 0x1a, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x41, 0x77, 0x42, 0x77, 0x43, 0x77, 0x44, 0x77, 0x45, 0x77, 0x46, 0x77, 0x47, 0x77, 0x48, 0x77, 0x49, 0x77, 0x4a, 0x77, 0x4b, 0x77, 0x4c, 0x77, 0x4d, 0x77, 0x4e, 0x77, 0x4f, 0x77, 0x50, 0x77, 0x51, 0x77, 0x52, 0x77, 0x53, 0x77, 0x54, 0x77, 0x55, 0x77, 0x56, 0x77, 0x57, 0xff, 0xff};static struct saa7146_ext_vv av7110_vv_data_st;static struct saa7146_ext_vv av7110_vv_data_c;int av7110_init_analog_module(struct av7110 *av7110){ u16 version1, version2; if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1 || i2c_writereg(av7110, 0x80, 0x0, 0) != 1) return -ENODEV; printk("av7110(%d): DVB-C analog module detected, initializing MSP3400\n", av7110->dvb_adapter->num); av7110->adac_type = DVB_ADAC_MSP; dvb_delay(100); // the probing above resets the msp... msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); printk("av7110(%d): MSP3400 version 0x%04x 0x%04x\n", av7110->dvb_adapter->num, version1, version2); msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { INFO(("saa7113 not accessible.\n")); } else { u8 *i = saa7113_init_regs; av7110->has_analog_tuner = 1; /* init the saa7113 */ while (*i != 0xff) { if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { printk("av7110(%d): saa7113 initialization failed", av7110->dvb_adapter->num); break; } i += 2; } /* setup msp for analog sound: B/G Dual-FM */ msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2 msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2 } memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); /* set dd1 stream a & b */ saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); saa7146_write(av7110->dev, DD1_INIT, 0x03000700); saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); return 0;}int av7110_init_v4l(struct av7110 *av7110){ struct saa7146_dev* dev = av7110->dev; int ret; /* special case DVB-C: these cards have an analog tuner plus need some special handling, so we have separate saa7146_ext_vv data for these... */ if (av7110->has_analog_tuner) ret = saa7146_vv_init(dev, &av7110_vv_data_c); else ret = saa7146_vv_init(dev, &av7110_vv_data_st); if (ret) { ERR(("cannot init capture device. skipping.\n")); return -ENODEV; } if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { ERR(("cannot register capture device. skipping.\n")); saa7146_vv_release(dev); return -ENODEV; } if (av7110->has_analog_tuner) { if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) { ERR(("cannot register vbi v4l2 device. skipping.\n")); } else /* we use this to remember that this dvb-c card can do vbi */ av7110->has_analog_tuner = 2; } return 0;}int av7110_exit_v4l(struct av7110 *av7110){ saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); if (2 == av7110->has_analog_tuner) saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); return 0;}/* FIXME: these values are experimental values that look better than the values from the latest "official" driver -- at least for me... (MiHu) */static struct saa7146_standard standard[] = { { .name = "PAL", .id = V4L2_STD_PAL_BG, .v_offset = 0x15, .v_field = 288, .v_calc = 576, .h_offset = 0x48, .h_pixels = 708, .h_calc = 708, .v_max_out = 576, .h_max_out = 768, }, { .name = "NTSC", .id = V4L2_STD_NTSC, .v_offset = 0x10, .v_field = 244, .v_calc = 480, .h_offset = 0x40, .h_pixels = 708, .h_calc = 708, .v_max_out = 480, .h_max_out = 640, }};static struct saa7146_standard analog_standard[] = { { .name = "PAL", .id = V4L2_STD_PAL_BG, .v_offset = 0x1b, .v_field = 288, .v_calc = 576, .h_offset = 0x08, .h_pixels = 708, .h_calc = 708, .v_max_out = 576, .h_max_out = 768, }, { .name = "NTSC", .id = V4L2_STD_NTSC, .v_offset = 0x10, .v_field = 244, .v_calc = 480, .h_offset = 0x40, .h_pixels = 708, .h_calc = 708, .v_max_out = 480, .h_max_out = 640, }};static struct saa7146_standard dvb_standard[] = { { .name = "PAL", .id = V4L2_STD_PAL_BG, .v_offset = 0x14, .v_field = 288, .v_calc = 576, .h_offset = 0x48, .h_pixels = 708, .h_calc = 708, .v_max_out = 576, .h_max_out = 768, }, { .name = "NTSC", .id = V4L2_STD_NTSC, .v_offset = 0x10, .v_field = 244, .v_calc = 480, .h_offset = 0x40, .h_pixels = 708, .h_calc = 708, .v_max_out = 480, .h_max_out = 640, }};static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std){ struct av7110 *av7110 = (struct av7110*) dev->ext_priv; if (std->id == V4L2_STD_PAL) { av7110->vidmode = VIDEO_MODE_PAL; av7110_set_vidmode(av7110, av7110->vidmode); } else if (std->id == V4L2_STD_NTSC) { av7110->vidmode = VIDEO_MODE_NTSC; av7110_set_vidmode(av7110, av7110->vidmode); } else return -1; return 0;}static struct saa7146_ext_vv av7110_vv_data_st = { .inputs = 1, .audios = 1, .capabilities = 0, .flags = 0, .stds = &standard[0], .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), .std_callback = &std_callback, .ioctls = &ioctls[0], .ioctl = av7110_ioctl,};static struct saa7146_ext_vv av7110_vv_data_c = { .inputs = 1, .audios = 1, .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, .flags = SAA7146_USE_PORT_B_FOR_VBI, .stds = &standard[0], .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), .std_callback = &std_callback, .ioctls = &ioctls[0], .ioctl = av7110_ioctl,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -