📄 cx25840-core.c
字号:
cx25840_err("%dx%d is not a valid size!\n", pix->width, pix->height); return -ERANGE; } HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); VSC &= 0x1fff; if (pix->width >= 385) filter = 0; else if (pix->width > 192) filter = 1; else if (pix->width > 96) filter = 2; else filter = 3; cx25840_dbg("decoder set size %dx%d -> scale %ux%u\n", pix->width, pix->height, HSC, VSC); /* HSCALE=HSC */ cx25840_write(client, 0x418, HSC & 0xff); cx25840_write(client, 0x419, (HSC >> 8) & 0xff); cx25840_write(client, 0x41a, HSC >> 16); /* VSCALE=VSC */ cx25840_write(client, 0x41c, VSC & 0xff); cx25840_write(client, 0x41d, VSC >> 8); /* VS_INTRLACE=1 VFILT=filter */ cx25840_write(client, 0x41e, 0x8 | filter); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: return cx25840_vbi(client, VIDIOC_S_FMT, fmt); case V4L2_BUF_TYPE_VBI_CAPTURE: return cx25840_vbi(client, VIDIOC_S_FMT, fmt); default: return -EINVAL; } return 0;}/* ----------------------------------------------------------------------- */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; int result = 0; switch (cmd) { case 0: break;#ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the * cx25840 registers for testing */ case VIDIOC_INT_G_REGISTER: { struct v4l2_register *reg = arg; if (reg->i2c_id != I2C_DRIVERID_CX25840) return -EINVAL; reg->val = cx25840_read(client, reg->reg & 0x0fff); break; } case VIDIOC_INT_S_REGISTER: { struct v4l2_register *reg = arg; if (reg->i2c_id != I2C_DRIVERID_CX25840) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; 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: case AUDC_SET_INPUT: result = cx25840_audio(client, cmd, arg); break; case VIDIOC_STREAMON: cx25840_dbg("enable output\n"); cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); break; case VIDIOC_STREAMOFF: cx25840_dbg("disable output\n"); cx25840_write(client, 0x115, 0x00); cx25840_write(client, 0x116, 0x00); break; case VIDIOC_LOG_STATUS: log_status(client); break; case VIDIOC_G_CTRL: result = get_v4lctrl(client, (struct v4l2_control *)arg); break; case VIDIOC_S_CTRL: result = set_v4lctrl(client, (struct v4l2_control *)arg); break; case VIDIOC_G_STD: *(v4l2_std_id *)arg = cx25840_get_v4lstd(client); break; case VIDIOC_S_STD: result = set_v4lstd(client, *(v4l2_std_id *)arg); break; case VIDIOC_G_INPUT: *(int *)arg = state->input; break; case VIDIOC_S_INPUT: result = set_input(client, *(int *)arg); break; case VIDIOC_S_FREQUENCY: input_change(client); break; case VIDIOC_G_TUNER: { u8 mode = cx25840_read(client, 0x804); u8 pref = cx25840_read(client, 0x809) & 0xf; u8 vpres = cx25840_read(client, 0x80a) & 0x10; int val = 0; vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; vt->signal = vpres ? 0xffff : 0x0; /* 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; switch (pref) { case 0: vt->audmode = V4L2_TUNER_MODE_MONO; break; case 1: case 2: vt->audmode = V4L2_TUNER_MODE_LANG2; break; case 4: default: vt->audmode = V4L2_TUNER_MODE_STEREO; } break; } case VIDIOC_S_TUNER: switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: /* Force PREF_MODE to MONO */ cx25840_and_or(client, 0x809, ~0xf, 0x00); break; case V4L2_TUNER_MODE_STEREO: /* Force PREF_MODE to STEREO */ cx25840_and_or(client, 0x809, ~0xf, 0x04); break; case V4L2_TUNER_MODE_LANG2: /* Force PREF_MODE to LANG2 */ cx25840_and_or(client, 0x809, ~0xf, 0x01); break; } break; case VIDIOC_G_FMT: result = get_v4lfmt(client, (struct v4l2_format *)arg); break; case VIDIOC_S_FMT: result = set_v4lfmt(client, (struct v4l2_format *)arg); break; 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: cx25840_err("invalid ioctl %x\n", cmd); return -EINVAL; } return result;}/* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver_cx25840;static int cx25840_detect_client(struct i2c_adapter *adapter, int address, 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 (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return 0; client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (client == 0) return -ENOMEM; memset(client, 0, sizeof(struct i2c_client)); client->addr = address; client->adapter = adapter; client->driver = &i2c_driver_cx25840; client->flags = I2C_CLIENT_ALLOW_USE; snprintf(client->name, sizeof(client->name) - 1, "cx25840"); cx25840_dbg("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) { cx25840_dbg("cx25840 not found\n"); kfree(client); return 0; } cx25840_info("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->input = CX25840_TUNER; state->audclk_freq = V4L2_AUDCLK_48_KHZ; state->audio_input = AUDIO_TUNER; state->cardtype = CARDTYPE_PVR150; cx25840_initialize(client, 1); i2c_attach_client(client); 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); return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver i2c_driver_cx25840 = { .name = "cx25840", .id = I2C_DRIVERID_CX25840, .flags = I2C_DF_NOTIFY, .attach_adapter = cx25840_attach_adapter, .detach_client = cx25840_detach_client, .command = cx25840_command, .owner = THIS_MODULE,};static 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); char *p; cx25840_info("Video signal: %spresent\n", (microctrl_vidfmt & 0x10) ? "" : "not "); cx25840_info("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"; } cx25840_info("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"; } cx25840_info("Detected audio standard: %s\n", p); cx25840_info("Audio muted: %s\n", (mute_ctl & 0x2) ? "yes" : "no"); cx25840_info("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"; } cx25840_info("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"; } cx25840_info("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"; } cx25840_info("Configured audio system: %s\n", p); } cx25840_info("Specified standard: %s\n", vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); switch (state->input) { case CX25840_COMPOSITE0: p = "Composite 0"; break; case CX25840_COMPOSITE1: p = "Composite 1"; break; case CX25840_SVIDEO0: p = "S-Video 0"; break; case CX25840_SVIDEO1: p = "S-Video 1"; break; case CX25840_TUNER: p = "Tuner"; break; } cx25840_info("Specified input: %s\n", p); cx25840_info("Specified audio input: %s\n", state->audio_input == 0 ? "Tuner" : "External"); switch (state->audclk_freq) { case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break; case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break; case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break; default: p = "undefined"; } cx25840_info("Specified audioclock freq: %s\n", p); 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"; } cx25840_info("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"; } cx25840_info("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"; } cx25840_info("Selected 45 MHz format: %s\n", p); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -