summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/msp3400-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/msp3400-driver.c')
-rw-r--r--linux/drivers/media/video/msp3400-driver.c348
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(&current->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(&current->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;
}