📄 cx25840-core.c
字号:
case 0x14: p = "tri with SAP"; break; case 0xfe: p = "forced mode"; break; default: p = "not defined"; } v4l_info(client, "Detected audio mode: %s\n", p); switch (mod_det_stat1) { case 0x00: p = "not defined"; break; case 0x01: p = "EIAJ"; break; case 0x02: p = "A2-M"; break; case 0x03: p = "A2-BG"; break; case 0x04: p = "A2-DK1"; break; case 0x05: p = "A2-DK2"; break; case 0x06: p = "A2-DK3"; break; case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; case 0x08: p = "AM-L"; break; case 0x09: p = "NICAM-BG"; break; case 0x0a: p = "NICAM-DK"; break; case 0x0b: p = "NICAM-I"; break; case 0x0c: p = "NICAM-L"; break; case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; case 0x0e: p = "IF FM Radio"; break; case 0x0f: p = "BTSC"; break; case 0x10: p = "high-deviation FM"; break; case 0x11: p = "very high-deviation FM"; break; case 0xfd: p = "unknown audio standard"; break; case 0xfe: p = "forced audio standard"; break; case 0xff: p = "no detected audio standard"; break; default: p = "not defined"; } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio muted: %s\n", (state->unmute_volume >= 0) ? "yes" : "no"); v4l_info(client, "Audio microcontroller: %s\n", (download_ctl & 0x10) ? ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { case 0x00: p = "undefined"; break; case 0x01: p = "BTSC"; break; case 0x02: p = "EIAJ"; break; case 0x03: p = "A2-M"; break; case 0x04: p = "A2-BG"; break; case 0x05: p = "A2-DK1"; break; case 0x06: p = "A2-DK2"; break; case 0x07: p = "A2-DK3"; break; case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; case 0x09: p = "AM-L"; break; case 0x0a: p = "NICAM-BG"; break; case 0x0b: p = "NICAM-DK"; break; case 0x0c: p = "NICAM-I"; break; case 0x0d: p = "NICAM-L"; break; case 0x0e: p = "FM radio"; break; case 0x0f: p = "automatic detection"; break; default: p = "undefined"; } v4l_info(client, "Configured audio standard: %s\n", p); if ((audio_config >> 4) < 0xF) { switch (audio_config & 0xF) { case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; case 0x01: p = "MONO2 (LANGUAGE B)"; break; case 0x02: p = "MONO3 (STEREO forced MONO)"; break; case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; case 0x04: p = "STEREO"; break; case 0x05: p = "DUAL1 (AB)"; break; case 0x06: p = "DUAL2 (AC) (FM)"; break; case 0x07: p = "DUAL3 (BC) (FM)"; break; case 0x08: p = "DUAL4 (AC) (AM)"; break; case 0x09: p = "DUAL5 (BC) (AM)"; break; case 0x0a: p = "SAP"; break; default: p = "undefined"; } v4l_info(client, "Configured audio mode: %s\n", p); } else { switch (audio_config & 0xF) { case 0x00: p = "BG"; break; case 0x01: p = "DK1"; break; case 0x02: p = "DK2"; break; case 0x03: p = "DK3"; break; case 0x04: p = "I"; break; case 0x05: p = "L"; break; case 0x06: p = "BTSC"; break; case 0x07: p = "EIAJ"; break; case 0x08: p = "A2-M"; break; case 0x09: p = "FM Radio"; break; case 0x0f: p = "automatic standard and mode detection"; break; default: p = "undefined"; } v4l_info(client, "Configured audio system: %s\n", p); } if (aud_input) { v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); } else { v4l_info(client, "Specified audio input: External\n"); } switch (pref_mode & 0xf) { case 0: p = "mono/language A"; break; case 1: p = "language B"; break; case 2: p = "language C"; break; case 3: p = "analog fallback"; break; case 4: p = "stereo"; break; case 5: p = "language AC"; break; case 6: p = "language BC"; break; case 7: p = "language AB"; break; default: p = "undefined"; } v4l_info(client, "Preferred audio mode: %s\n", p); if ((audio_config & 0xf) == 0xf) { switch ((afc0 >> 3) & 0x3) { case 0: p = "system DK"; break; case 1: p = "system L"; break; case 2: p = "autodetect"; break; default: p = "undefined"; } v4l_info(client, "Selected 65 MHz format: %s\n", p); switch (afc0 & 0x7) { case 0: p = "chroma"; break; case 1: p = "BTSC"; break; case 2: p = "EIAJ"; break; case 3: p = "A2-M"; break; case 4: p = "autodetect"; break; default: p = "undefined"; } v4l_info(client, "Selected 45 MHz format: %s\n", p); }}/* ----------------------------------------------------------------------- */static int cx25840_command(struct i2c_client *client, unsigned int cmd, void *arg){ struct cx25840_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; struct v4l2_routing *route = arg; /* ignore these commands */ switch (cmd) { case TUNER_SET_TYPE_ADDR: return 0; } if (!state->is_initialized) { v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd); /* initialize on first use */ state->is_initialized = 1; if (state->is_cx25836) cx25836_initialize(client); else if (state->is_cx23885) cx23885_initialize(client); else cx25840_initialize(client); } switch (cmd) {#ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the * cx25840 registers for testing */ case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = cx25840_read(client, reg->reg & 0x0fff); else cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); break; }#endif case VIDIOC_INT_DECODE_VBI_LINE: return cx25840_vbi(client, cmd, arg); case VIDIOC_INT_AUDIO_CLOCK_FREQ: return cx25840_audio(client, cmd, arg); case VIDIOC_STREAMON: v4l_dbg(1, cx25840_debug, client, "enable output\n"); if (state->is_cx23885) { u8 v = (cx25840_read(client, 0x421) | 0x0b); cx25840_write(client, 0x421, v); } else { cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c); cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07); } break; case VIDIOC_STREAMOFF: v4l_dbg(1, cx25840_debug, client, "disable output\n"); if (state->is_cx23885) { u8 v = cx25840_read(client, 0x421) & ~(0x0b); cx25840_write(client, 0x421, v); } else { cx25840_write(client, 0x115, 0x00); cx25840_write(client, 0x116, 0x00); } break; case VIDIOC_LOG_STATUS: log_video_status(client); if (!state->is_cx25836) log_audio_status(client); break; case VIDIOC_G_CTRL: return get_v4lctrl(client, (struct v4l2_control *)arg); case VIDIOC_S_CTRL: return set_v4lctrl(client, (struct v4l2_control *)arg); case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; switch (qc->id) { case V4L2_CID_BRIGHTNESS: case V4L2_CID_CONTRAST: case V4L2_CID_SATURATION: case V4L2_CID_HUE: return v4l2_ctrl_query_fill_std(qc); default: break; } if (state->is_cx25836) return -EINVAL; switch (qc->id) { case V4L2_CID_AUDIO_VOLUME: return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, state->default_volume); case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: return v4l2_ctrl_query_fill_std(qc); default: return -EINVAL; } return -EINVAL; } case VIDIOC_G_STD: *(v4l2_std_id *)arg = state->std; break; case VIDIOC_S_STD: if (state->radio == 0 && state->std == *(v4l2_std_id *)arg) return 0; state->radio = 0; state->std = *(v4l2_std_id *)arg; return set_v4lstd(client); case AUDC_SET_RADIO: state->radio = 1; break; case VIDIOC_INT_G_VIDEO_ROUTING: route->input = state->vid_input; route->output = 0; break; case VIDIOC_INT_S_VIDEO_ROUTING: return set_input(client, route->input, state->aud_input); case VIDIOC_INT_G_AUDIO_ROUTING: if (state->is_cx25836) return -EINVAL; route->input = state->aud_input; route->output = 0; break; case VIDIOC_INT_S_AUDIO_ROUTING: if (state->is_cx25836) return -EINVAL; return set_input(client, state->vid_input, route->input); case VIDIOC_S_FREQUENCY: if (!state->is_cx25836) { input_change(client); } break; case VIDIOC_G_TUNER: { u8 vpres = cx25840_read(client, 0x40e) & 0x20; u8 mode; int val = 0; if (state->radio) break; vt->signal = vpres ? 0xffff : 0x0; if (state->is_cx25836) break; vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; mode = cx25840_read(client, 0x804); /* get rxsubchans and audmode */ if ((mode & 0xf) == 1) val |= V4L2_TUNER_SUB_STEREO; else val |= V4L2_TUNER_SUB_MONO; if (mode == 2 || mode == 4) val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; if (mode & 0x10) val |= V4L2_TUNER_SUB_SAP; vt->rxsubchans = val; vt->audmode = state->audmode; break; } case VIDIOC_S_TUNER: if (state->radio || state->is_cx25836) break; switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: /* mono -> mono stereo -> mono bilingual -> lang1 */ cx25840_and_or(client, 0x809, ~0xf, 0x00); break; case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1: /* mono -> mono stereo -> stereo bilingual -> lang1 */ cx25840_and_or(client, 0x809, ~0xf, 0x04); break; case V4L2_TUNER_MODE_LANG1_LANG2: /* mono -> mono stereo -> stereo bilingual -> lang1/lang2 */ cx25840_and_or(client, 0x809, ~0xf, 0x07); break; case V4L2_TUNER_MODE_LANG2: /* mono -> mono stereo -> stereo bilingual -> lang2 */ cx25840_and_or(client, 0x809, ~0xf, 0x01); break; default: return -EINVAL; } state->audmode = vt->audmode; break; case VIDIOC_G_FMT: return get_v4lfmt(client, (struct v4l2_format *)arg); case VIDIOC_S_FMT: return set_v4lfmt(client, (struct v4l2_format *)arg); case VIDIOC_INT_RESET: if (state->is_cx25836) cx25836_initialize(client); else if (state->is_cx23885) cx23885_initialize(client); else cx25840_initialize(client); break; case VIDIOC_G_CHIP_IDENT: return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev); default: return -EINVAL; } return 0;}/* ----------------------------------------------------------------------- */static int cx25840_probe(struct i2c_client *client, const struct i2c_device_id *did){ struct cx25840_state *state; u32 id; u16 device_id; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); /* The high byte of the device ID should be * 0x83 for the cx2583x and 0x84 for the cx2584x */ if ((device_id & 0xff00) == 0x8300) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); } else if (device_id == 0x0000) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; } else if (device_id == 0x1313) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); return -ENODEV; } state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); if (state == NULL) { return -ENOMEM; } /* Note: revision '(device_id & 0x0f) == 2' was never built. The marking skips from 0x1 == 22 to 0x3 == 23. */ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), client->addr << 1, client->adapter->name); i2c_set_clientdata(client, state); state->c = client; state->is_cx25836 = ((device_id & 0xff00) == 0x8300); state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; state->unmute_volume = -1; state->default_volume = 228 - cx25840_read(client, 0x8d4); state->default_volume = ((state->default_volume / 2) + 23) << 9; state->vbi_line_offset = 8; state->id = id; state->rev = device_id; if (state->is_cx23885) { /* Drive GPIO2 direction and values */ cx25840_write(client, 0x160, 0x1d); cx25840_write(client, 0x164, 0x00); } return 0;}static int cx25840_remove(struct i2c_client *client){ kfree(i2c_get_clientdata(client)); return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)static const struct i2c_device_id cx25840_id[] = { { "cx25840", 0 }, { }};MODULE_DEVICE_TABLE(i2c, cx25840_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "cx25840", .driverid = I2C_DRIVERID_CX25840, .command = cx25840_command, .probe = cx25840_probe, .remove = cx25840_remove,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) .id_table = cx25840_id,#endif};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -