📄 tda9887.c
字号:
buf[2] |= adjust; return 0;}static int tda9887_set_config(struct tda9887 *t, char *buf){ if (t->config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; if (t->config & TDA9887_PORT1_INACTIVE) buf[1] |= cOutputPort1Inactive; if (t->config & TDA9887_PORT2_ACTIVE) buf[1] &= ~cOutputPort2Inactive; if (t->config & TDA9887_PORT2_INACTIVE) buf[1] |= cOutputPort2Inactive; if (t->config & TDA9887_QSS) buf[1] |= cQSS; if (t->config & TDA9887_INTERCARRIER) buf[1] &= ~cQSS; if (t->config & TDA9887_AUTOMUTE) buf[1] |= cAutoMuteFmActive; if (t->config & TDA9887_DEEMPHASIS_MASK) { buf[2] &= ~0x60; switch (t->config & TDA9887_DEEMPHASIS_MASK) { case TDA9887_DEEMPHASIS_NONE: buf[2] |= cDeemphasisOFF; break; case TDA9887_DEEMPHASIS_50: buf[2] |= cDeemphasisON | cDeemphasis50; break; case TDA9887_DEEMPHASIS_75: buf[2] |= cDeemphasisON | cDeemphasis75; break; } } if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; return 0;}/* ---------------------------------------------------------------------- */static int tda9887_set_pinnacle(struct tda9887 *t, char *buf){ unsigned int bCarrierMode = UNSET; if (t->std & V4L2_STD_625_50) { if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) { bCarrierMode = cIntercarrier; } else { bCarrierMode = cQSS; } } if (t->std & V4L2_STD_525_60) { if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) { bCarrierMode = cIntercarrier; } else { bCarrierMode = cQSS; } } if (bCarrierMode != UNSET) { buf[1] &= ~0x04; buf[1] |= bCarrierMode; } return 0;}/* ---------------------------------------------------------------------- */static char pal[] = "-";module_param_string(pal, pal, sizeof(pal), 0644);static char secam[] = "-";module_param_string(secam, secam, sizeof(secam), 0644);static int tda9887_fixup_std(struct tda9887 *t){ /* get more precise norm info from insmod option */ if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { case 'b': case 'B': case 'g': case 'G': tda9887_dbg("insmod fixup: PAL => PAL-BG\n"); t->std = V4L2_STD_PAL_BG; break; case 'i': case 'I': tda9887_dbg("insmod fixup: PAL => PAL-I\n"); t->std = V4L2_STD_PAL_I; break; case 'd': case 'D': case 'k': case 'K': tda9887_dbg("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; case '-': /* default parameter, do nothing */ break; default: tda9887_info("pal= argument not recognised\n"); break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { case 'd': case 'D': case 'k': case 'K': tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n"); t->std = V4L2_STD_SECAM_DK; break; case 'l': case 'L': tda9887_dbg("insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; break; case '-': /* default parameter, do nothing */ break; default: tda9887_info("secam= argument not recognised\n"); break; } } return 0;}static int tda9887_status(struct tda9887 *t){ unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); if (1 != (rc = i2c_master_recv(&t->client,buf,1))) tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); dump_read_message(t, buf); return 0;}static int tda9887_configure(struct tda9887 *t){ int rc; memset(t->data,0,sizeof(t->data)); tda9887_set_tvnorm(t,t->data); t->data[1] |= cOutputPort1Inactive; t->data[1] |= cOutputPort2Inactive; if (UNSET != t->pinnacle_id) { tda9887_set_pinnacle(t,t->data); } tda9887_set_config(t,t->data); tda9887_set_insmod(t,t->data); if (t->mode == T_STANDBY) { t->data[1] |= cForcedMuteAudioON; } tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1],t->data[2],t->data[3]); if (debug > 1) dump_write_message(t, t->data); if (4 != (rc = i2c_master_send(&t->client,t->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (debug > 2) { msleep_interruptible(1000); tda9887_status(t); } return 0;}/* ---------------------------------------------------------------------- */static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind){ struct tda9887 *t; client_template.adapter = adap; client_template.addr = addr; if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL))) return -ENOMEM; memset(t,0,sizeof(*t)); t->client = client_template; t->std = 0; t->pinnacle_id = UNSET; t->radio_mode = V4L2_TUNER_MODE_STEREO; tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name); i2c_set_clientdata(&t->client, t); i2c_attach_client(&t->client); return 0;}static int tda9887_probe(struct i2c_adapter *adap){#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9887_attach);#else switch (adap->id) { case I2C_HW_B_BT848: case I2C_HW_B_RIVA: case I2C_HW_SAA7134: return i2c_probe(adap, &addr_data, tda9887_attach); break; }#endif return 0;}static int tda9887_detach(struct i2c_client *client){ struct tda9887 *t = i2c_get_clientdata(client); i2c_detach_client(client); kfree(t); return 0;}#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ tda9887_info("switching to v4l2\n"); \ t->using_v4l2 = 1;#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \ tda9887_info("ignore v4l1 call\n"); \ return 0; }static inttda9887_command(struct i2c_client *client, unsigned int cmd, void *arg){ struct tda9887 *t = i2c_get_clientdata(client); switch (cmd) { /* --- configuration --- */ case AUDC_SET_RADIO: { t->mode = T_RADIO; tda9887_configure(t); break; } case TUNER_SET_STANDBY: { t->mode = T_STANDBY; tda9887_configure(t); break; } case AUDC_CONFIG_PINNACLE: { int *i = arg; t->pinnacle_id = *i; tda9887_configure(t); break; } case TDA9887_SET_CONFIG: { int *i = arg; t->config = *i; tda9887_configure(t); break; } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ case VIDIOCSCHAN: { static const v4l2_std_id map[] = { [ VIDEO_MODE_PAL ] = V4L2_STD_PAL, [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, [ 4 /* bttv */ ] = V4L2_STD_PAL_M, [ 5 /* bttv */ ] = V4L2_STD_PAL_N, [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, }; struct video_channel *vc = arg; CHECK_V4L2; t->mode = T_ANALOG_TV; if (vc->norm < ARRAY_SIZE(map)) t->std = map[vc->norm]; tda9887_fixup_std(t); tda9887_configure(t); break; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; SWITCH_V4L2; t->mode = T_ANALOG_TV; t->std = *id; tda9887_fixup_std(t); tda9887_configure(t); break; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *f = arg; SWITCH_V4L2; if (V4L2_TUNER_ANALOG_TV == f->type) { if (t->mode == T_ANALOG_TV) return 0; t->mode = T_ANALOG_TV; } if (V4L2_TUNER_RADIO == f->type) { if (t->mode == T_RADIO) return 0; t->mode = T_RADIO; } tda9887_configure(t); break; } case VIDIOC_G_TUNER: { static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, 187500, 162500, 137500, 112500, 97500 , 62500, 37500 , 12500 }; struct v4l2_tuner* tuner = arg; if (t->mode == T_RADIO) { __u8 reg = 0; tuner->afc=0; if (1 == i2c_master_recv(&t->client,®,1)) tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; } break; } case VIDIOC_S_TUNER: { struct v4l2_tuner* tuner = arg; if (t->mode == T_RADIO) { t->radio_mode = tuner->audmode; tda9887_configure (t); } break; } case VIDIOC_LOG_STATUS: { tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]); break; } default: /* nothing */ break; } return 0;}static int tda9887_suspend(struct device * dev, pm_message_t state){ struct i2c_client *c = container_of(dev, struct i2c_client, dev); struct tda9887 *t = i2c_get_clientdata(c); tda9887_dbg("suspend\n"); return 0;}static int tda9887_resume(struct device * dev){ struct i2c_client *c = container_of(dev, struct i2c_client, dev); struct tda9887 *t = i2c_get_clientdata(c); tda9887_dbg("resume\n"); tda9887_configure(t); return 0;}/* ----------------------------------------------------------------------- */static struct i2c_driver driver = { .owner = THIS_MODULE, .name = "i2c tda9887 driver", .id = -1, /* FIXME */ .flags = I2C_DF_NOTIFY, .attach_adapter = tda9887_probe, .detach_client = tda9887_detach, .command = tda9887_command, .driver = { .suspend = tda9887_suspend, .resume = tda9887_resume, },};static struct i2c_client client_template ={ .name = "tda9887", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver,};static int __init tda9887_init_module(void){ return i2c_add_driver(&driver);}static void __exit tda9887_cleanup_module(void){ i2c_del_driver(&driver);}module_init(tda9887_init_module);module_exit(tda9887_cleanup_module);/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -