diff options
Diffstat (limited to 'drivers/char/msp3400.c')
-rw-r--r-- | drivers/char/msp3400.c | 414 |
1 files changed, 279 insertions, 135 deletions
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 651d5b733..abf08764d 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -1,21 +1,21 @@ /* * programming the msp34* sound processor family * - * (c) 1997,1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * (c) 1997,1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * * what works and what doesn't: * - * AM mono + * AM-Mono * probably doesn't (untested) * - * FM-mono - * should work. FM stereo modes are backward-compatible to mono. - * Therefore FM mono should always be available. + * FM-Mono + * should work. The stereo modes are backward compatible to FM-mono, + * therefore FM-Mono should be allways available. * - * FM stereo (B/G, used in Germany) + * FM-Stereo (B/G, used in germany) * should work, with autodetect * - * FM stereo (satellite) + * FM-Stereo (satellite) * should work, no autodetect (i.e. default is mono, but you can * switch to stereo -- untested) * @@ -27,9 +27,14 @@ * TODO: * - better SAT support * + * + * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) + * using soundcore instead of OSS + * */ #include <linux/module.h> +#include <linux/version.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> @@ -37,6 +42,10 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/malloc.h> +#ifdef __SMP__ +#include <asm/pgtable.h> +#include <linux/smp_lock.h> +#endif /* kernel_thread */ #define __KERNEL_SYSCALLS__ @@ -67,14 +76,14 @@ struct msp3400c { int mode; int norm; int stereo; + int main, second; /* sound carrier */ - int mixer; - int left, right; /* volume */ + int left, right; /* volume */ int bass, treble; /* thread */ struct task_struct *thread; - struct semaphore *wait; + struct wait_queue *wq; struct semaphore *notify; int active,restart,rmmod; @@ -88,7 +97,22 @@ struct msp3400c { #define dprintk if (debug) printk +#if LINUX_VERSION_CODE < 0x020100 +/* 2.0.x */ +#define signal_pending(current) (current->signal & ~current->blocked) +#define sigfillset(set) +#define mdelay(x) udelay(1000*x) +#else MODULE_PARM(debug,"i"); +#endif + +#if LINUX_VERSION_CODE < 0x02017f +void schedule_timeout(int j) +{ + current->timeout = jiffies + j; + schedule(); +} +#endif /* ---------------------------------------------------------------------- */ @@ -211,9 +235,9 @@ static struct MSP_INIT_DATA_DEM { /* FM Radio */ { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, MSP_CARRIER(10.7), MSP_CARRIER(10.7), - 0x00d0, 0x0480, 0x0020, 0x3002 }, + 0x00d0, 0x0480, 0x0020, 0x3000 }, - /* Terrestial FM-mono */ + /* Terrestial FM-mono + FM-stereo */ { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000}, @@ -230,7 +254,7 @@ static struct MSP_INIT_DATA_DEM { /* NICAM I */ { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), + MSP_CARRIER(6.0), MSP_CARRIER(6.0), 0x00d0, 0x0040, 0x0120, 0x3000}, }; @@ -244,7 +268,7 @@ static struct CARRIER_DETECT carrier_detect_main[] = { { MSP_CARRIER(4.5), "4.5 NTSC" }, { MSP_CARRIER(5.5), "5.5 PAL B/G" }, { MSP_CARRIER(6.0), "6.0 PAL I" }, - { MSP_CARRIER(6.5), "6.5 PAL SAT / SECAM" } + { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } }; static struct CARRIER_DETECT carrier_detect_55[] = { @@ -255,6 +279,9 @@ static struct CARRIER_DETECT carrier_detect_55[] = { static struct CARRIER_DETECT carrier_detect_65[] = { /* PAL SAT / SECAM */ + { MSP_CARRIER(5.85), "5.85 PAL D/K NICAM" }, + { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, + { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, @@ -270,6 +297,7 @@ static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2) msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); + msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ } static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right) @@ -329,12 +357,14 @@ static void msp3400c_setmode(struct msp3400c *msp, int type) msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, msp_init_data[type].fir2[i]); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ msp_init_data[type].mode_reg); msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1, msp_init_data[type].cdo2); + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, msp_init_data[type].dfp_src); msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, @@ -357,9 +387,9 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) /* switch demodulator */ switch (msp->mode) { case MSP_MODE_FM_TERRA: - dprintk("msp3400: B/G setstereo: %d\n",mode); + dprintk("msp3400: FM setstereo: %d\n",mode); msp->stereo = mode; - msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5)); + msp3400c_setcarrier(msp->bus,msp->second,msp->main); switch (mode) { case VIDEO_SOUND_STEREO: msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001); @@ -372,7 +402,7 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) } break; case MSP_MODE_FM_SAT: - dprintk("msp3400: sat setstereo: %d\n",mode); + dprintk("msp3400: SAT setstereo: %d\n",mode); msp->stereo = mode; switch (mode) { case VIDEO_SOUND_MONO: @@ -390,9 +420,10 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) } break; case MSP_MODE_FM_NICAM1: - dprintk("msp3400: NICAM1 setstereo: %d\n",mode); + case MSP_MODE_FM_NICAM2: + dprintk("msp3400: NICAM setstereo: %d\n",mode); msp->stereo = mode; - msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5)); + msp3400c_setcarrier(msp->bus,msp->second,msp->main); nicam=0x0100; break; default: @@ -406,7 +437,9 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0020|nicam); msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0020|nicam); msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0020|nicam); +#if 0 msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005,0x4000); +#endif break; case VIDEO_SOUND_MONO: case VIDEO_SOUND_LANG1: @@ -422,6 +455,27 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) } } +static void +msp3400c_print_mode(struct msp3400c *msp) +{ + if (msp->main == msp->second) { + printk("msp3400: mono sound carrier: %d.%03d MHz\n", + msp->main/910000,(msp->main/910)%1000); + } else { + printk("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("msp3400: NICAM carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + if (msp->mode == MSP_MODE_FM_TERRA && + msp->main != msp->second) { + printk("msp3400: FM-stereo carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + } +} + /* ----------------------------------------------------------------------- */ struct REGISTER_DUMP { @@ -446,21 +500,21 @@ static void msp3400c_stereo_wake(unsigned long data) { struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */ - if (!msp->active) - up(msp->wait); + wake_up_interruptible(&msp->wq); } static int msp3400c_thread(void *data) { - unsigned long flags; struct msp3400c *msp = data; - struct semaphore sem = MUTEX_LOCKED; struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; int newstereo; + LOCK_FLAGS; - /* lock_kernel(); */ +#ifdef __SMP__ + lock_kernel(); +#endif exit_mm(current); current->session = 1; @@ -469,10 +523,12 @@ static int msp3400c_thread(void *data) current->fs->umask = 0; strcpy(current->comm,"msp3400"); - msp->wait = &sem; + msp->wq = NULL; msp->thread = current; - /* unlock_kernel(); */ +#ifdef __SMP__ + unlock_kernel(); +#endif dprintk("msp3400: thread: start\n"); if(msp->notify != NULL) @@ -481,9 +537,11 @@ static int msp3400c_thread(void *data) for (;;) { if (msp->rmmod) goto done; - dprintk("msp3400: thread: sleep\n"); - down_interruptible(&sem); - dprintk("msp3400: thread: wakeup\n"); + 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; @@ -510,6 +568,7 @@ static int msp3400c_thread(void *data) } break; case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23); switch ((val & 0x1e) >> 1) { case 0: @@ -553,7 +612,7 @@ static int msp3400c_thread(void *data) msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); UNLOCK_I2C_BUS(msp->bus); - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/25); if (signal_pending(current)) goto done; @@ -587,7 +646,7 @@ static int msp3400c_thread(void *data) msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); UNLOCK_I2C_BUS(msp->bus); - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/25); if (signal_pending(current)) goto done; @@ -603,34 +662,56 @@ static int msp3400c_thread(void *data) dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); } - /* program the msp3400 according to the results */ + /* programm the msp3400 according to the results */ + msp->main = carrier_detect_main[max1].cdo; switch (max1) { - case 0: /* 4.5 */ case 1: /* 5.5 */ - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo, - carrier_detect_main[max1].cdo); if (max2 == 0) { /* B/G FM-stereo */ + msp->second = carrier_detect_55[max2].cdo; + msp3400c_setmode(msp, MSP_MODE_FM_TERRA); msp3400c_setstereo(msp, VIDEO_SOUND_MONO); msp->watch_stereo = 1; - } - if (max2 == 1 && msp->nicam) { + } else if (max2 == 1 && msp->nicam) { /* B/G NICAM */ + msp->second = carrier_detect_55[max2].cdo; msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); - /* msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); */ - msp3400c_setcarrier(msp->bus, MSP_CARRIER(5.85), - MSP_CARRIER(5.5)); + msp3400c_setcarrier(msp->bus, msp->second, msp->main); msp->watch_stereo = 1; + } else { + goto no_second; } break; case 2: /* 6.0 */ + /* PAL I NICAM */ + msp->second = MSP_CARRIER(6.552); + msp3400c_setmode(msp, MSP_MODE_FM_NICAM2); + msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp->watch_stereo = 1; + break; case 3: /* 6.5 */ + if (max2 == 1 || max2 == 2) { + /* D/K FM-stereo */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + } else if (max2 == 0 && msp->nicam) { + /* D/K NICAM */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 0: /* 4.5 */ default: + no_second: + msp->second = carrier_detect_main[max1].cdo; msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo, - carrier_detect_main[max1].cdo); - msp3400c_setstereo(msp, VIDEO_SOUND_STEREO); + msp3400c_setcarrier(msp->bus, msp->second, msp->main); break; } @@ -640,15 +721,18 @@ static int msp3400c_thread(void *data) if (msp->watch_stereo) { del_timer(&msp->wake_stereo); - msp->wake_stereo.expires = jiffies + HZ; + msp->wake_stereo.expires = jiffies + 2*HZ; add_timer(&msp->wake_stereo); } + + if (debug) + msp3400c_print_mode(msp); + msp->active = 0; } done: dprintk("msp3400: thread: exit\n"); - msp->wait = NULL; msp->active = 0; msp->thread = NULL; @@ -690,6 +774,7 @@ static int msp3410d_thread(void *data) goto done; dprintk("msp3410: thread: sleep\n"); down_interruptible(&sem); + sem.owner = 0; dprintk("msp3410: thread: wakeup\n"); if (msp->rmmod) goto done; @@ -713,7 +798,8 @@ static int msp3410d_thread(void *data) /* wait 1 sec */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ); + current->timeout = jiffies + HZ; + schedule(); if (signal_pending(current)) goto done; if (msp->restart) { @@ -752,9 +838,14 @@ done: #ifdef REGISTER_MIXER +#include <linux/sound.h> #include <linux/soundcard.h> -#include <../drivers/sound/sound_config.h> -#include <../drivers/sound/dev_table.h> +#include <asm/uaccess.h> + +static struct msp3400c *mspmix = NULL; /* ugly hack, should do something more sensible */ +static int mixer_num; +static int mixer_modcnt = 0; +static struct semaphore mixer_sem = MUTEX; static int mix_to_v4l(int i) { @@ -787,16 +878,42 @@ static int v4l_to_mix2(int l, int r) return (r << 8) | l; } -static int msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +static int +msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct msp3400c *msp = mixer_devs[dev]->devc; - unsigned long flags; int ret,val = 0; + LOCK_FLAGS; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "MSP3400", sizeof(info.id)); + strncpy(info.name, "MSP 3400", sizeof(info.name)); + info.modify_counter = mixer_modcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "MSP3400", sizeof(info.id)); + strncpy(info.name, "MSP 3400", sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); if (_SIOC_DIR(cmd) & _SIOC_WRITE) if (get_user(val, (int *)arg)) return -EFAULT; + down(&mixer_sem); + if (!mspmix) { + up(&mixer_sem); + return -ENODEV; + } + switch (cmd) { case MIXER_READ(SOUND_MIXER_RECMASK): case MIXER_READ(SOUND_MIXER_CAPS): @@ -813,91 +930,97 @@ static int msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) break; case MIXER_WRITE(SOUND_MIXER_VOLUME): - msp->left = mix_to_v4l(val); - msp->right = mix_to_v4l(val >> 8); - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus,msp->left,msp->right); - UNLOCK_I2C_BUS(msp->bus); + mspmix->left = mix_to_v4l(val); + mspmix->right = mix_to_v4l(val >> 8); + LOCK_I2C_BUS(mspmix->bus); + msp3400c_setvolume(mspmix->bus,mspmix->left,mspmix->right); + UNLOCK_I2C_BUS(mspmix->bus); + mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_VOLUME): - ret = v4l_to_mix2(msp->left, msp->right); + ret = v4l_to_mix2(mspmix->left, mspmix->right); break; case MIXER_WRITE(SOUND_MIXER_BASS): - msp->bass = mix_to_v4l(val); - LOCK_I2C_BUS(msp->bus); - msp3400c_setbass(msp->bus,msp->bass); - UNLOCK_I2C_BUS(msp->bus); + mspmix->bass = mix_to_v4l(val); + LOCK_I2C_BUS(mspmix->bus); + msp3400c_setbass(mspmix->bus,mspmix->bass); + UNLOCK_I2C_BUS(mspmix->bus); + mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_BASS): - ret = v4l_to_mix(msp->bass); + ret = v4l_to_mix(mspmix->bass); break; case MIXER_WRITE(SOUND_MIXER_TREBLE): - msp->treble = mix_to_v4l(val); - LOCK_I2C_BUS(msp->bus); - msp3400c_settreble(msp->bus,msp->treble); - UNLOCK_I2C_BUS(msp->bus); + mspmix->treble = mix_to_v4l(val); + LOCK_I2C_BUS(mspmix->bus); + msp3400c_settreble(mspmix->bus,mspmix->treble); + UNLOCK_I2C_BUS(mspmix->bus); + mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_TREBLE): - ret = v4l_to_mix(msp->treble); + ret = v4l_to_mix(mspmix->treble); break; default: + up(&mixer_sem); return -EINVAL; } + up(&mixer_sem); if (put_user(ret, (int *)arg)) return -EFAULT; return 0; } -struct mixer_operations msp3400c_mixer = { - "video4linux", - "TV card sound (msp3400)", - msp3400c_mixer_ioctl -}; - -static int msp3400c_mixer_init(struct msp3400c *msp) +static int +msp3400c_mixer_open(struct inode *inode, struct file *file) { - int m; - - msp->mixer = m = sound_alloc_mixerdev(); - if (m == -1) - return -1; - - mixer_devs[m] = (struct mixer_operations *) - kmalloc(sizeof(struct mixer_operations), GFP_KERNEL); - if (mixer_devs[m] == NULL) { - printk(KERN_ERR "msp3400c: can't allocate memory\n"); - sound_unload_mixerdev(m); - return -1; - } - memcpy(mixer_devs[m],&msp3400c_mixer,sizeof(struct mixer_operations)); - mixer_devs[m]->devc = msp; - return 0; + MOD_INC_USE_COUNT; + return 0; } -static int msp3400c_mixer_close(struct msp3400c *msp) +static int +msp3400c_mixer_release(struct inode *inode, struct file *file) { - int m = msp->mixer; + MOD_DEC_USE_COUNT; + return 0; +} - if (m != -1 ) { - sound_unload_mixerdev(m); - kfree(mixer_devs[m]); - } - return 0; +static loff_t +msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; } +static /*const*/ struct file_operations msp3400c_mixer_fops = { + &msp3400c_mixer_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &msp3400c_mixer_ioctl, + NULL, /* mmap */ + &msp3400c_mixer_open, + NULL, + &msp3400c_mixer_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + #endif /* ----------------------------------------------------------------------- */ static int msp3400c_attach(struct i2c_device *device) { - unsigned long flags; struct semaphore sem = MUTEX_LOCKED; struct msp3400c *msp; int rev1,rev2; + LOCK_FLAGS; device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL); if (NULL == msp) @@ -913,17 +1036,24 @@ static int msp3400c_attach(struct i2c_device *device) if (-1 == msp3400c_reset(msp->bus)) { UNLOCK_I2C_BUS(msp->bus); kfree(msp); - return -EIO; + dprintk("msp3400: no chip found\n"); + return -1; } + rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e); + rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f); + if (0 == rev1 && 0 == rev2) { + UNLOCK_I2C_BUS(msp->bus); + kfree(msp); + printk("msp3400: error while reading chip version\n"); + return -1; + } + msp3400c_setmode(msp, MSP_MODE_FM_TERRA); msp3400c_setvolume(msp->bus, msp->left, msp->right); msp3400c_setbass(msp->bus, msp->bass); msp3400c_settreble(msp->bus, msp->treble); - rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e); - rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f); - #if 0 /* this will turn on a 1kHz beep - might be useful for debugging... */ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040); @@ -932,7 +1062,7 @@ static int msp3400c_attach(struct i2c_device *device) sprintf(device->name,"MSP34%02d%c-%c%d", (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); - msp->nicam = (((rev2>>8)&0xff) == 10) ? 1 : 0; + msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; /* timer for stereo checking */ msp->wake_stereo.function = msp3400c_stereo_wake; @@ -940,19 +1070,20 @@ static int msp3400c_attach(struct i2c_device *device) /* startup control thread */ MOD_INC_USE_COUNT; + msp->wq = NULL; msp->notify = &sem; kernel_thread(msp3400c_thread, (void *)msp, 0); down(&sem); msp->notify = NULL; - if (!msp->active) - up(msp->wait); + wake_up_interruptible(&msp->wq); printk(KERN_INFO "msp3400: init: chip=%s",device->name); if (msp->nicam) printk(", has NICAM support"); #ifdef REGISTER_MIXER - if (0 == msp3400c_mixer_init(msp)) - printk(", registered as sound mixer"); + down(&mixer_sem); + mspmix = msp; + up(&mixer_sem); #endif printk("\n"); return 0; @@ -960,12 +1091,14 @@ static int msp3400c_attach(struct i2c_device *device) static int msp3400c_detach(struct i2c_device *device) { - unsigned long flags; struct semaphore sem = MUTEX_LOCKED; struct msp3400c *msp = (struct msp3400c*)device->data; + LOCK_FLAGS; #ifdef REGISTER_MIXER - msp3400c_mixer_close(msp); + down(&mixer_sem); + mspmix = NULL; + up(&mixer_sem); #endif /* shutdown control thread */ @@ -974,8 +1107,7 @@ static int msp3400c_detach(struct i2c_device *device) { msp->notify = &sem; msp->rmmod = 1; - if (!msp->active) - up(msp->wait); + wake_up_interruptible(&msp->wq); down(&sem); msp->notify = NULL; } @@ -992,9 +1124,10 @@ static int msp3400c_detach(struct i2c_device *device) static int msp3400c_command(struct i2c_device *device, unsigned int cmd, void *arg) { - unsigned long flags; struct msp3400c *msp = (struct msp3400c*)device->data; int *iarg = (int*)arg; + __u16 *sarg = arg; + LOCK_FLAGS; switch (cmd) { case MSP_SET_RADIO: @@ -1004,74 +1137,79 @@ static int msp3400c_command(struct i2c_device *device, LOCK_I2C_BUS(msp->bus); msp3400c_setmode(msp,MSP_MODE_FM_RADIO); msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); + msp3400c_setvolume(msp->bus,msp->left, msp->right); UNLOCK_I2C_BUS(msp->bus); break; case MSP_SET_TVNORM: msp->norm = *iarg; break; + case MSP_SWITCH_MUTE: + /* channels switching step one -- mute */ + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + LOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(msp->bus,0,0); + UNLOCK_I2C_BUS(msp->bus); + break; case MSP_NEWCHANNEL: + /* channels switching step two -- trigger sound carrier scan */ msp->watch_stereo=0; del_timer(&msp->wake_stereo); - if (!msp->active) - up(msp->wait); - else + if (msp->active) msp->restart = 1; + wake_up_interruptible(&msp->wq); break; case MSP_GET_VOLUME: - *iarg = (msp->left > msp->right) ? msp->left : msp->right; + *sarg = (msp->left > msp->right) ? msp->left : msp->right; break; case MSP_SET_VOLUME: - msp->left = msp->right = *iarg; + msp->left = msp->right = *sarg; LOCK_I2C_BUS(msp->bus); msp3400c_setvolume(msp->bus,msp->left, msp->right); UNLOCK_I2C_BUS(msp->bus); break; case MSP_GET_BASS: - *iarg = msp->bass; + *sarg = msp->bass; break; case MSP_SET_BASS: - msp->bass = *iarg; + msp->bass = *sarg; LOCK_I2C_BUS(msp->bus); msp3400c_setbass(msp->bus,msp->bass); UNLOCK_I2C_BUS(msp->bus); break; case MSP_GET_TREBLE: - *iarg = msp->treble; + *sarg = msp->treble; break; case MSP_SET_TREBLE: - msp->treble = *iarg; + msp->treble = *sarg; LOCK_I2C_BUS(msp->bus); msp3400c_settreble(msp->bus,msp->treble); UNLOCK_I2C_BUS(msp->bus); break; case MSP_GET_STEREO: - *iarg = msp->stereo; + *sarg = msp->stereo; break; case MSP_SET_STEREO: - if (*iarg) { + if (*sarg) { msp->watch_stereo=0; del_timer(&msp->wake_stereo); LOCK_I2C_BUS(msp->bus); - msp3400c_setstereo(msp,*iarg); + msp3400c_setstereo(msp,*sarg); UNLOCK_I2C_BUS(msp->bus); } break; case MSP_GET_DC: LOCK_I2C_BUS(msp->bus); - *iarg = (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) + - (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c); + *sarg = ((int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) + + (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c)); UNLOCK_I2C_BUS(msp->bus); break; - - case MSP_GET_UNIT: - *iarg = msp->mixer; - break; - + default: return -EINVAL; } @@ -1090,8 +1228,6 @@ struct i2c_driver i2c_driver_msp = { msp3400c_command }; -EXPORT_NO_SYMBOLS; - #ifdef MODULE int init_module(void) #else @@ -1099,6 +1235,10 @@ int init_module(void) #endif { i2c_register_driver(&i2c_driver_msp); +#ifdef REGISTER_MIXER + if ((mixer_num = register_sound_mixer(&msp3400c_mixer_fops, -1)) < 0) + printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); +#endif return 0; } @@ -1106,6 +1246,10 @@ int init_module(void) void cleanup_module(void) { i2c_unregister_driver(&i2c_driver_msp); +#ifdef REGISTER_MIXER + if (mixer_num >= 0) + unregister_sound_mixer(mixer_num); +#endif } #endif |