diff options
Diffstat (limited to 'linux/drivers/media/video/msp3400-driver.c')
-rw-r--r-- | linux/drivers/media/video/msp3400-driver.c | 348 |
1 files changed, 120 insertions, 228 deletions
diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index c0f090a91..61b6fdcae 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -47,17 +47,12 @@ #include <linux/videodev.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/kthread.h> #include <asm/semaphore.h> #include <asm/pgtable.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#include "audiochip.h" -#include "i2c-compat.h" -#include "id.h" -#else #include <media/audiochip.h> #include <media/id.h> -#endif #include "msp3400.h" #include "compat.h" @@ -99,16 +94,10 @@ struct msp3400c { int bass, treble; /* thread */ - pid_t tpid; - struct completion texit; + struct task_struct *kthread; wait_queue_head_t wq; - - int active:1; int restart:1; - int rmmod:1; - - int watch_stereo; - struct timer_list wake_stereo; + int watch_stereo:1; }; #define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00) @@ -159,10 +148,6 @@ I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ /* functions for talking to the MSP3400C Sound processor */ -#ifndef I2C_M_IGNORE_NAK -# define I2C_M_IGNORE_NAK 0x1000 -#endif - static int msp3400c_reset(struct i2c_client *client) { /* reset and read revision code */ @@ -753,22 +738,22 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) DECLARE_WAITQUEUE(wait, current); add_wait_queue(&msp->wq, &wait); - if (!msp->rmmod) { + if (!kthread_should_stop()) { if (timeout < 0) { set_current_state(TASK_INTERRUPTIBLE); schedule(); - } else + } else { +#if 0 + /* hmm, that one doesn't return after waking up msp->wq */ msleep_interruptible(timeout); +#else + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(timeout)); +#endif + } } remove_wait_queue(&msp->wq, &wait); - return msp->rmmod || signal_pending(current); -} - -static void msp3400c_stereo_wake(unsigned long data) -{ - struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */ - - wake_up_interruptible(&msp->wq); + return msp->restart; } /* stereo/multilang monitoring */ @@ -780,49 +765,27 @@ static void watch_stereo(struct i2c_client *client) msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans)); 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; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) - lock_kernel(); - daemonize(); - sigfillset(¤t->blocked); - strcpy(current->comm,"msp3400"); - unlock_kernel(); -#else - daemonize("msp3400"); - allow_signal(SIGTERM); -#endif - printk("msp3400: daemon started\n"); - + printk("msp3400: kthread started\n"); for (;;) { d2printk("msp3400: thread: sleep\n"); - if (msp34xx_sleep(msp,-1)) - goto done; - + msp34xx_sleep(msp,-1); d2printk("msp3400: thread: wakeup\n"); - msp->active = 1; - if (msp->watch_stereo) { - watch_stereo(client); - msp->active = 0; - continue; - } - - /* some time for the tuner to sync */ - if (msp34xx_sleep(msp,200)) - goto done; - restart: + dprintk("msp3410: thread: restart scan\n"); + msp->restart = 0; + if (kthread_should_stop()) + break; + if (VIDEO_MODE_RADIO == msp->norm || MSP_MODE_EXTERN == msp->mode) { /* no carrier scan, just unmute */ @@ -831,14 +794,18 @@ static int msp3400c_thread(void *data) msp->volume, msp->balance); continue; } - msp->restart = 0; + + /* mute */ msp3400c_setvolume(client, msp->muted, 0, 0); msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; - del_timer(&msp->wake_stereo); msp->watch_stereo = 0; + /* some time for the tuner to sync */ + if (msp34xx_sleep(msp,200)) + goto restart; + /* carrier detect pass #1 -- main carrier */ cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); @@ -851,12 +818,8 @@ static int msp3400c_thread(void *data) for (this = 0; this < count; this++) { msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - if (msp34xx_sleep(msp,100)) - goto done; - if (msp->restart) - msp->restart = 0; - + goto restart; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); if (val > 32767) val -= 65536; @@ -888,12 +851,8 @@ static int msp3400c_thread(void *data) } for (this = 0; this < count; this++) { msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - if (msp34xx_sleep(msp,100)) - goto done; - if (msp->restart) goto restart; - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); if (val > 32767) val -= 65536; @@ -974,23 +933,21 @@ static int msp3400c_thread(void *data) break; } - /* unmute + restore dfp registers */ + /* unmute */ msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance); - - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+5*HZ); - if (debug) msp3400c_print_mode(msp); - - msp->active = 0; - } -done: - msp->active = 0; + /* monitor tv audio mode */ + while (msp->watch_stereo) { + if (msp34xx_sleep(msp,5000)) + goto restart; + watch_stereo(client); + } + } dprintk(KERN_DEBUG "msp3400: thread: exit\n"); - complete_and_exit(&msp->texit, 0); + return 0; } /* ----------------------------------------------------------------------- */ @@ -1073,37 +1030,18 @@ static int msp3410d_thread(void *data) struct msp3400c *msp = i2c_get_clientdata(client); int mode,val,i,std; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) - lock_kernel(); - daemonize(); - sigfillset(¤t->blocked); - strcpy(current->comm,"msp3410 [auto]"); - unlock_kernel(); -#else - daemonize("msp3410 [auto]"); - allow_signal(SIGTERM); -#endif printk("msp3410: daemon started\n"); - for (;;) { d2printk(KERN_DEBUG "msp3410: thread: sleep\n"); - if (msp34xx_sleep(msp,-1)) - goto done; - + msp34xx_sleep(msp,-1); d2printk(KERN_DEBUG "msp3410: thread: wakeup\n"); - msp->active = 1; - - if (msp->watch_stereo) { - watch_stereo(client); - msp->active = 0; - continue; - } - - /* some time for the tuner to sync */ - if (msp34xx_sleep(msp,200)) - goto done; restart: + dprintk("msp3410: thread: restart scan\n"); + msp->restart = 0; + if (kthread_should_stop()) + break; + if (msp->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n"); @@ -1111,18 +1049,20 @@ static int msp3410d_thread(void *data) msp->volume, msp->balance); continue; } - msp->restart = 0; - del_timer(&msp->wake_stereo); - msp->watch_stereo = 0; /* put into sane state (and mute) */ msp3400c_reset(client); + /* some time for the tuner to sync */ + if (msp34xx_sleep(msp,200)) + goto restart; + /* start autodetect */ mode = msp34xx_modus(msp->norm); std = msp34xx_standard(msp->norm); msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); + msp->watch_stereo = 0; if (debug) printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n", @@ -1135,8 +1075,6 @@ static int msp3410d_thread(void *data) /* triggered autodetect */ for (;;) { if (msp34xx_sleep(msp,100)) - goto done; - if (msp->restart) goto restart; /* check results */ @@ -1241,16 +1179,14 @@ static int msp3410d_thread(void *data) msp->volume, msp->balance); msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb); - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+HZ); - - msp->active = 0; + /* monitor tv audio mode */ + while (msp->watch_stereo) { + if (msp34xx_sleep(msp,5000)) + goto restart; + watch_stereo(client); + } } - -done: - msp->active = 0; dprintk(KERN_DEBUG "msp3410: thread: exit\n"); - complete_and_exit(&msp->texit, 0); return 0; } @@ -1265,12 +1201,10 @@ static void msp34xxg_set_source(struct i2c_client *client, int source); /* (re-)initialize the msp34xxg, according to the current norm in msp->norm * return 0 if it worked, -1 if it failed */ -static int msp34xxg_reset(struct i2c_client *client) +static int msp34xxg_init(struct i2c_client *client) { struct msp3400c *msp = i2c_get_clientdata(client); - int i; int modus; - int std; if (msp3400c_reset(client)) return -1; @@ -1306,55 +1240,76 @@ static int msp34xxg_reset(struct i2c_client *client) 0x5a00 /* default: 9db gain (as recommended) */)) return -1; - std = standard; if (msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, /* STANDARD SELECT */ - std /* default: 0x01 for automatic standard select*/)) + standard /* default: 0x01 for automatic standard select*/)) return -1; + return 0; +} + +static int msp34xxg_thread(void *data) +{ + struct i2c_client *client = data; + struct msp3400c *msp = i2c_get_clientdata(client); + int val, std, i; + + printk("msp34xxg: daemon started\n"); + for (;;) { + d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n"); + msp34xx_sleep(msp,-1); + d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n"); + restart: + dprintk("msp34xxg: thread: restart scan\n"); + msp->restart = 0; + if (kthread_should_stop()) + break; - if (std == 0x01) { - dprintk("msp34xxg: triggered autodetect, waiting for result\n"); + /* setup the chip*/ + msp34xxg_init(client); + std = standard; + if (std != 0x01) + goto unmute; - /* triggered autodetect */ + /* watch autodetect */ + dprintk("msp34xxg: triggered autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { - int val; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - if (signal_pending(current)) - return -1; /* failed */ + if (msp34xx_sleep(msp,100)) + goto restart; /* check results */ val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); if (val < 0x07ff) { - std=val; + std = val; break; } dprintk("msp34xxg: detection still in progress\n"); } - if (i == 10) { + if (0x01 == std) { dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n"); - return -1; + continue; } - } - dprintk("msp34xxg: current mode: %s (0x%04x)\n", - msp34xx_standard_mode_name(std), std); - - /* unmute: dispatch sound to scart output, set scart volume */ - dprintk("msp34xxg: unmute\n"); - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance); - - /* restore ACB */ - if (msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x13, /* ACB */ - msp->acb)) - return -1; + unmute: + dprintk("msp34xxg: current mode: %s (0x%04x)\n", + msp34xx_standard_mode_name(std), std); + /* unmute: dispatch sound to scart output, set scart volume */ + dprintk("msp34xxg: unmute\n"); + + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance); + + /* restore ACB */ + if (msp3400c_write(client, + I2C_MSP3400C_DFP, + 0x13, /* ACB */ + msp->acb)) + return -1; + } + dprintk(KERN_DEBUG "msp34xxg: thread: exit\n"); return 0; } @@ -1457,21 +1412,14 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) /* ----------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int msp_attach(struct i2c_adapter *adap, int addr, int kind); -#else -static int msp_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind); -#endif static int msp_detach(struct i2c_client *client); static int msp_probe(struct i2c_adapter *adap); static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); static struct i2c_driver driver = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) .owner = THIS_MODULE, -#endif - .name = "i2c msp3400 driver", + .name = "i2c msp3400 driver", .id = I2C_DRIVERID_MSP3400, .flags = I2C_DF_NOTIFY, .attach_adapter = msp_probe, @@ -1486,12 +1434,7 @@ static struct i2c_client client_template = .driver = &driver, }; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int msp_attach(struct i2c_adapter *adap, int addr, int kind) -#else -static int msp_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -#endif { struct msp3400c *msp; struct i2c_client *c; @@ -1561,11 +1504,6 @@ static int msp_attach(struct i2c_adapter *adap, int addr, msp->opmode = OPMODE_MANUAL; } - /* timer for stereo checking */ - init_timer(&msp->wake_stereo); - msp->wake_stereo.function = msp3400c_stereo_wake; - msp->wake_stereo.data = (unsigned long)msp; - /* hello world :-) */ printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c)); if (HAVE_NICAM(msp)) @@ -1589,26 +1527,20 @@ static int msp_attach(struct i2c_adapter *adap, int addr, break; case OPMODE_SIMPLER: printk(" mode=simpler"); - msp34xxg_reset(c); + thread_func = msp34xxg_thread; break; } printk("\n"); /* startup control thread if needed */ if (thread_func) { - init_completion(&msp->texit); - msp->tpid = kernel_thread(thread_func, (void *)c, 0); - if (msp->tpid < 0) + msp->kthread = kthread_run(thread_func, c, "msp34xx"); + if (NULL == msp->kthread) printk(KERN_WARNING "msp34xx: kernel_thread() failed\n"); wake_up_interruptible(&msp->wq); - } else { - msp->tpid = -1; } /* done */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - MOD_INC_USE_COUNT; -#endif i2c_attach_client(c); return 0; } @@ -1618,37 +1550,22 @@ static int msp_detach(struct i2c_client *client) struct msp3400c *msp = i2c_get_clientdata(client); /* shutdown control thread */ - del_timer_sync(&msp->wake_stereo); - if (msp->tpid >= 0) { - msp->rmmod = 1; - wake_up_interruptible(&msp->wq); - wait_for_completion(&msp->texit); + if (msp->kthread >= 0) { + msp->restart = 1; + kthread_stop(msp->kthread); } msp3400c_reset(client); i2c_detach_client(client); kfree(msp); kfree(client); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - MOD_DEC_USE_COUNT; -#endif return 0; } static int msp_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, msp_attach); -#else - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3: - case I2C_ALGO_BIT | I2C_HW_B_BT848: - //case I2C_ALGO_SAA7134: - return i2c_probe(adap, &addr_data, msp_attach); - break; - } -#endif return 0; } @@ -1656,13 +1573,11 @@ static void msp_wake_thread(struct i2c_client *client) { struct msp3400c *msp = i2c_get_clientdata(client); - if (-1 == msp->tpid) + if (NULL == msp->kthread) return; msp3400c_setvolume(client,msp->muted,0,0); - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - if (msp->active) - msp->restart = 1; + msp->watch_stereo = 0; + msp->restart = 1; wake_up_interruptible(&msp->wq); } @@ -1694,21 +1609,6 @@ static int mode_v4l1_to_v4l2(int mode) return V4L2_TUNER_MODE_MONO; } -static void msp_any_rescan(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - switch (msp->opmode) { - case OPMODE_MANUAL: - case OPMODE_SIMPLE: - msp_wake_thread(client); - break; - case OPMODE_SIMPLER: - msp34xxg_reset(client); - break; - } -} - static void msp_any_detect_stereo(struct i2c_client *client) { struct msp3400c *msp = i2c_get_clientdata(client); @@ -1731,8 +1631,7 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode) switch (msp->opmode) { case OPMODE_MANUAL: case OPMODE_SIMPLE: - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); + msp->watch_stereo = 0; msp3400c_set_audmode(client, audmode); break; case OPMODE_SIMPLER: @@ -1772,7 +1671,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; case AUDIO_TUNER: msp->mode = -1; - msp_wake_thread(client); break; default: if (*sarg & AUDIO_MUTE) @@ -1787,8 +1685,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (msp->opmode != OPMODE_SIMPLER) msp3400c_set_audmode(client, msp->audmode); } - if (msp->active) - msp->restart = 1; + msp_wake_thread(client); break; case AUDC_SET_RADIO: @@ -1796,7 +1693,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp->norm = VIDEO_MODE_RADIO; dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n"); msp->watch_stereo = 0; - del_timer(&msp->wake_stereo); switch (msp->opmode) { case OPMODE_MANUAL: /* set msp3400 to FM radio mode */ @@ -1807,12 +1703,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp->volume, msp->balance); break; case OPMODE_SIMPLE: + case OPMODE_SIMPLER: /* the thread will do for us */ msp_wake_thread(client); break; - case OPMODE_SIMPLER: - msp34xxg_reset(client); - break; } break; @@ -1866,7 +1760,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm); msp->norm = vc->norm; - msp_any_rescan(client); + msp_wake_thread(client); break; } @@ -1875,7 +1769,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { /* new channel -- kick audio carrier scan */ dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n"); - msp_any_rescan(client); + msp_wake_thread(client); break; } @@ -1897,10 +1791,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; /* only set audmode */ - if (vt->audmode != -1 && - vt->audmode != 0) { + if (vt->audmode != -1 && vt->audmode != 0) msp_any_set_audmode(client, vt->audmode); - } break; } |