📄 msp3400.c
字号:
}
static void msp3400c_settreble(struct i2c_client *client, int treble)
{
int val = ((treble-32768) * 0x60 / 65535) << 8;
dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
}
static void msp3400c_setmode(struct i2c_client *client, int type)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int i;
dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
msp->mode = type;
msp->stereo = VIDEO_SOUND_MONO;
msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */
msp_init_data[type].ad_cv);
for (i = 5; i >= 0; i--) /* fir 1 */
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001,
msp_init_data[type].fir1[i]);
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040);
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000);
for (i = 5; i >= 0; i--)
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005,
msp_init_data[type].fir2[i]);
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */
msp_init_data[type].mode_reg);
msp3400c_setcarrier(client, msp_init_data[type].cdo1,
msp_init_data[type].cdo2);
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
if (dolby) {
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
0x0520); /* I2S1 */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
0x0620); /* I2S2 */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
msp_init_data[type].dfp_src);
} else {
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
msp_init_data[type].dfp_src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
msp_init_data[type].dfp_src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
msp_init_data[type].dfp_src);
}
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,
msp_init_data[type].dfp_src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e,
msp_init_data[type].dfp_matrix);
if (HAVE_NICAM(msp)) {
/* nicam prescale */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
}
}
/* turn on/off nicam + stereo */
static void msp3400c_setstereo(struct i2c_client *client, int mode)
{
static char *strmode[16] = {
#if __GNUC__ >= 3
[ 0 ... 15 ] = "invalid",
#endif
[ VIDEO_SOUND_MONO ] = "mono",
[ VIDEO_SOUND_STEREO ] = "stereo",
[ VIDEO_SOUND_LANG1 ] = "lang1",
[ VIDEO_SOUND_LANG2 ] = "lang2",
};
struct msp3400c *msp = i2c_get_clientdata(client);
int nicam=0; /* channel source: FM/AM or nicam */
int src=0;
/* switch demodulator */
switch (msp->mode) {
case MSP_MODE_FM_TERRA:
dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",strmode[mode]);
msp3400c_setcarrier(client,msp->second,msp->main);
switch (mode) {
case VIDEO_SOUND_STEREO:
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
break;
case VIDEO_SOUND_MONO:
case VIDEO_SOUND_LANG1:
case VIDEO_SOUND_LANG2:
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000);
break;
}
break;
case MSP_MODE_FM_SAT:
dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",strmode[mode]);
switch (mode) {
case VIDEO_SOUND_MONO:
msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
break;
case VIDEO_SOUND_STEREO:
msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
break;
case VIDEO_SOUND_LANG1:
msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
break;
case VIDEO_SOUND_LANG2:
msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
break;
}
break;
case MSP_MODE_FM_NICAM1:
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",strmode[mode]);
msp3400c_setcarrier(client,msp->second,msp->main);
if (msp->nicam_on)
nicam=0x0100;
break;
case MSP_MODE_BTSC:
dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",strmode[mode]);
nicam=0x0300;
break;
case MSP_MODE_EXTERN:
dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",strmode[mode]);
nicam = 0x0200;
break;
case MSP_MODE_FM_RADIO:
dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",strmode[mode]);
break;
default:
dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
return;
}
/* switch audio */
switch (mode) {
case VIDEO_SOUND_STEREO:
src = 0x0020 | nicam;
#if 0
/* spatial effect */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000);
#endif
break;
case VIDEO_SOUND_MONO:
if (msp->mode == MSP_MODE_AM_NICAM) {
dprintk("msp3400: switching to AM mono\n");
/* AM mono decoding is handled by tuner, not MSP chip */
/* SCART switching control register */
msp3400c_set_scart(client,SCART_MONO,0);
src = 0x0200;
break;
}
case VIDEO_SOUND_LANG1:
src = 0x0000 | nicam;
break;
case VIDEO_SOUND_LANG2:
src = 0x0010 | nicam;
break;
}
dprintk(KERN_DEBUG
"msp3400: setstereo final source/matrix = 0x%x\n", src);
if (dolby) {
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
} else {
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
}
}
static void
msp3400c_print_mode(struct msp3400c *msp)
{
if (msp->main == msp->second) {
printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
msp->main/910000,(msp->main/910)%1000);
} else {
printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
msp->main/910000,(msp->main/910)%1000);
}
if (msp->mode == MSP_MODE_FM_NICAM1 ||
msp->mode == MSP_MODE_FM_NICAM2)
printk(KERN_DEBUG "msp3400: NICAM/FM carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
if (msp->mode == MSP_MODE_AM_NICAM)
printk(KERN_DEBUG "msp3400: NICAM/AM carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
if (msp->mode == MSP_MODE_FM_TERRA &&
msp->main != msp->second) {
printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
}
}
static void
msp3400c_restore_dfp(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int i;
for (i = 0; i < DFP_COUNT; i++) {
if (-1 == msp->dfp_regs[i])
continue;
msp3400c_write(client,I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
}
}
/* ----------------------------------------------------------------------- */
struct REGISTER_DUMP {
int addr;
char *name;
};
struct REGISTER_DUMP d1[] = {
{ 0x007e, "autodetect" },
{ 0x0023, "C_AD_BITS " },
{ 0x0038, "ADD_BITS " },
{ 0x003e, "CIB_BITS " },
{ 0x0057, "ERROR_RATE" },
};
static int
autodetect_stereo(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int val;
int newstereo = msp->stereo;
int newnicam = msp->nicam_on;
int update = 0;
switch (msp->mode) {
case MSP_MODE_FM_TERRA:
val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
if (val > 32767)
val -= 65536;
dprintk(KERN_DEBUG
"msp34xx: stereo detect register: %d\n",val);
if (val > 4096) {
newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO;
} else if (val < -4096) {
newstereo = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
} else {
newstereo = VIDEO_SOUND_MONO;
}
newnicam = 0;
break;
case MSP_MODE_FM_NICAM1:
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
dprintk(KERN_DEBUG
"msp34xx: nicam sync=%d, mode=%d\n",
val & 1, (val & 0x1e) >> 1);
if (val & 1) {
/* nicam synced */
switch ((val & 0x1e) >> 1) {
case 0:
case 8:
newstereo = VIDEO_SOUND_STEREO;
break;
case 1:
case 9:
newstereo = VIDEO_SOUND_MONO
| VIDEO_SOUND_LANG1;
break;
case 2:
case 10:
newstereo = VIDEO_SOUND_MONO
| VIDEO_SOUND_LANG1
| VIDEO_SOUND_LANG2;
break;
default:
newstereo = VIDEO_SOUND_MONO;
break;
}
newnicam=1;
} else {
newnicam = 0;
newstereo = VIDEO_SOUND_MONO;
}
break;
case MSP_MODE_BTSC:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
dprintk(KERN_DEBUG
"msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
val,
(val & 0x0002) ? "no" : "yes",
(val & 0x0004) ? "no" : "yes",
(val & 0x0040) ? "stereo" : "mono",
(val & 0x0080) ? ", nicam 2nd mono" : "",
(val & 0x0100) ? ", bilingual/SAP" : "");
newstereo = VIDEO_SOUND_MONO;
if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO;
if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1;
break;
}
if (newstereo != msp->stereo) {
update = 1;
dprintk(KERN_DEBUG "msp34xx: watch: stereo %d => %d\n",
msp->stereo,newstereo);
msp->stereo = newstereo;
}
if (newnicam != msp->nicam_on) {
update = 1;
dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
msp->nicam_on,newnicam);
msp->nicam_on = newnicam;
}
return update;
}
/*
* A kernel thread for msp3400 control -- we don't want to block the
* in the ioctl while doing the sound carrier & stereo detect
*/
static void msp3400c_stereo_wake(unsigned long data)
{
struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */
wake_up_interruptible(&msp->wq);
}
/* stereo/multilang monitoring */
static void watch_stereo(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
if (autodetect_stereo(client)) {
if (msp->stereo & VIDEO_SOUND_STEREO)
msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
else if (msp->stereo & VIDEO_SOUND_LANG1)
msp3400c_setstereo(client,VIDEO_SOUND_LANG1);
else if (msp->stereo & VIDEO_SOUND_LANG2)
msp3400c_setstereo(client,VIDEO_SOUND_LANG2);
else
msp3400c_setstereo(client,VIDEO_SOUND_MONO);
}
if (once)
msp->watch_stereo = 0;
if (msp->watch_stereo)
mod_timer(&msp->wake_stereo, jiffies+5*HZ);
}
static int msp3400c_thread(void *data)
{
struct i2c_client *client = data;
struct msp3400c *msp = i2c_get_clientdata(client);
struct CARRIER_DETECT *cd;
int count, max1,max2,val1,val2, val,this;
lock_kernel();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
daemonize();
sigfillset(¤t->blocked);
strcpy(current->comm,"msp3400");
#else
daemonize("msp3400");
#endif
msp->thread = current;
unlock_kernel();
printk("msp3400: daemon started\n");
if(msp->notify != NULL)
up(msp->notify);
for (;;) {
if (msp->rmmod)
goto done;
if (debug > 1)
printk("msp3400: thread: sleep\n");
interruptible_sleep_on(&msp->wq);
if (debug > 1)
printk("msp3400: thread: wakeup\n");
if (msp->rmmod || signal_pending(current))
goto done;
msp->active = 1;
if (msp->watch_stereo) {
watch_stereo(client);
msp->active = 0;
continue;
}
/* some time for the tuner to sync */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/5);
if (signal_pending(current))
goto done;
restart:
if (VIDEO_MODE_RADIO == msp->norm ||
MSP_MODE_EXTERN == msp->mode) {
/* no carrier scan, just unmute */
printk("msp3400: thread: no carrier scan\n");
msp3400c_setvolume(client, msp->muted,
msp->left, msp->right);
continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -