📄 cx25840-core.c
字号:
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) 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: cx25840_initialize(client, 0); break; case VIDIOC_INT_G_CHIP_IDENT: *(enum v4l2_chip_ident *)arg = V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf); break; default: return -EINVAL; } return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver_cx25840;static int cx25840_detect_client(struct i2c_adapter *adapter, int address,#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) unsigned short flags,#endif int kind){ struct i2c_client *client; struct cx25840_state *state; u16 device_id; /* Check if the adapter supports the needed features * Not until kernel version 2.6.11 did the bit-algo * correctly report that it would do an I2C-level xfer */#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) if (!adapter->algo->master_xfer)#else if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))#endif return 0; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (client == 0) return -ENOMEM; client->addr = address; client->adapter = adapter; client->driver = &i2c_driver_cx25840;#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) client->flags = I2C_CLIENT_ALLOW_USE;#endif snprintf(client->name, sizeof(client->name) - 1, "cx25840"); v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); /* The high byte of the device ID should be * 0x84 if chip is present */ if ((device_id & 0xff00) != 0x8400) { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); kfree(client); return 0; } v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3, address << 1, adapter->name); state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL); if (state == NULL) { kfree(client); return -ENOMEM; } i2c_set_clientdata(client, state); memset(state, 0, sizeof(struct cx25840_state)); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; cx25840_initialize(client, 1); i2c_attach_client(client);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_INC_USE_COUNT;#endif return 0;}static int cx25840_attach_adapter(struct i2c_adapter *adapter){#ifdef I2C_CLASS_TV_ANALOG if (adapter->class & I2C_CLASS_TV_ANALOG)#else if (adapter->id == I2C_HW_B_BT848)#endif return i2c_probe(adapter, &addr_data, &cx25840_detect_client); return 0;}static int cx25840_detach_client(struct i2c_client *client){ struct cx25840_state *state = i2c_get_clientdata(client); int err; err = i2c_detach_client(client); if (err) { return err; } kfree(state); kfree(client);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_DEC_USE_COUNT;#endif return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver_cx25840 = {#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)) .owner = THIS_MODULE,#endif#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) .name = "cx25840", .flags = I2C_DF_NOTIFY,#else .driver = { .name = "cx25840", },#endif .id = I2C_DRIVERID_CX25840, .attach_adapter = cx25840_attach_adapter, .detach_client = cx25840_detach_client, .command = cx25840_command,};#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)EXPORT_NO_SYMBOLS;#endifstatic int __init m__init(void){ return i2c_add_driver(&i2c_driver_cx25840);}static void __exit m__exit(void){ i2c_del_driver(&i2c_driver_cx25840);}module_init(m__init);module_exit(m__exit);/* ----------------------------------------------------------------------- */static void log_status(struct i2c_client *client){ static const char *const fmt_strs[] = { "0x0", "NTSC-M", "NTSC-J", "NTSC-4.43", "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", "0x9", "0xA", "0xB", "SECAM", "0xD", "0xE", "0xF" }; struct cx25840_state *state = i2c_get_clientdata(client); u8 microctrl_vidfmt = cx25840_read(client, 0x80a); u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; u8 gen_stat1 = cx25840_read(client, 0x40d); u8 download_ctl = cx25840_read(client, 0x803); u8 mod_det_stat0 = cx25840_read(client, 0x804); u8 mod_det_stat1 = cx25840_read(client, 0x805); u8 audio_config = cx25840_read(client, 0x808); u8 pref_mode = cx25840_read(client, 0x809); u8 afc0 = cx25840_read(client, 0x80b); u8 mute_ctl = cx25840_read(client, 0x8d3); int vid_input = state->vid_input; int aud_input = state->aud_input; char *p; v4l_info(client, "Video signal: %spresent\n", (microctrl_vidfmt & 0x10) ? "" : "not "); v4l_info(client, "Detected format: %s\n", fmt_strs[gen_stat1 & 0xf]); switch (mod_det_stat0) { case 0x00: p = "mono"; break; case 0x01: p = "stereo"; break; case 0x02: p = "dual"; break; case 0x04: p = "tri"; break; case 0x10: p = "mono with SAP"; break; case 0x11: p = "stereo with SAP"; break; case 0x12: p = "dual with SAP"; break; 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", (mute_ctl & 0x2) ? "yes" : "no"); v4l_info(client, "Audio microcontroller: %s\n", (download_ctl & 0x10) ? "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); } v4l_info(client, "Specified standard: %s\n", vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); if (vid_input >= CX25840_COMPOSITE1 && vid_input <= CX25840_COMPOSITE8) { v4l_info(client, "Specified video input: Composite %d\n", vid_input - CX25840_COMPOSITE1 + 1); } else { v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); } if (aud_input) { v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); } else { v4l_info(client, "Specified audio input: External\n"); } v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); 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); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -