summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2006-06-11 22:31:36 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-06-11 22:31:36 -0300
commit596e34f736e4d6b93889149cfdd56d3dff96ba51 (patch)
treeaf9f600d599de7ef0e4673254faf974baee13c66
parent77c159f6b446fdfacf6a8fc3dde6b2626e122cbd (diff)
parent3a43601e74870844d9420353be082c2a5a1fc56e (diff)
downloadmediapointer-dvb-s2-596e34f736e4d6b93889149cfdd56d3dff96ba51.tar.gz
mediapointer-dvb-s2-596e34f736e4d6b93889149cfdd56d3dff96ba51.tar.bz2
merge: http://linuxtv.org/hg/~mkrufky/bluebird
From: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--linux/drivers/media/dvb/cinergyT2/cinergyT2.c6
-rw-r--r--linux/drivers/media/video/pvrusb2/Kconfig2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c71
3 files changed, 69 insertions, 10 deletions
diff --git a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c
index 8dbba1ca7..0fb56a66a 100644
--- a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -561,15 +561,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
+ unsigned int mask = 0;
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
+ if (cinergyt2->pending_fe_events != 0)
+ mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
mutex_unlock(&cinergyt2->sem);
- return (POLLIN | POLLRDNORM | POLLPRI);
+ return mask;
}
diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig
index 207efa6c0..4a7f88484 100644
--- a/linux/drivers/media/video/pvrusb2/Kconfig
+++ b/linux/drivers/media/video/pvrusb2/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_PVRUSB2
tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_V4L1 && USB && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && USB && I2C && EXPERIMENTAL
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index f4284f927..78cdd01c8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -22,8 +22,6 @@
#include "compat.h"
#include <linux/kernel.h>
-#include <linux/videodev.h>
-
#include "pvrusb2-context.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2.h"
@@ -37,10 +35,21 @@ struct pvr2_v4l2_dev;
struct pvr2_v4l2_fh;
struct pvr2_v4l2;
+/* V4L no longer provide the ability to set / get a private context pointer
+ (i.e. video_get_drvdata / video_set_drvdata), which means we have to
+ concoct our own context locating mechanism. Supposedly this is intended
+ to simplify driver implementation. It's not clear to me how that can
+ possibly be true. Our solution here is to maintain a lookup table of
+ our context instances, indexed by the minor device number of the V4L
+ device. See pvr2_v4l2_open() for some implications of this approach. */
+static struct pvr2_v4l2_dev *devices[256];
+static DEFINE_MUTEX(device_lock);
+
struct pvr2_v4l2_dev {
struct pvr2_v4l2 *v4lp;
struct video_device *vdev;
struct pvr2_context_stream *stream;
+ int ctxt_idx;
enum pvr2_config config;
};
@@ -641,6 +650,12 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
pvr2_trace(PVR2_TRACE_INIT,
"unregistering device video%d [%s]",
dip->vdev->minor,pvr2_config_get_name(dip->config));
+ if (dip->ctxt_idx >= 0) {
+ mutex_lock(&device_lock);
+ devices[dip->ctxt_idx] = NULL;
+ dip->ctxt_idx = -1;
+ mutex_unlock(&device_lock);
+ }
video_unregister_device(dip->vdev);
}
@@ -727,12 +742,43 @@ int pvr2_v4l2_release(struct inode *inode, struct file *file)
int pvr2_v4l2_open(struct inode *inode, struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct pvr2_v4l2_dev *dip =
- (struct pvr2_v4l2_dev *)video_get_drvdata(vdev);
+ struct pvr2_v4l2_dev *dip = 0; /* Our own context pointer */
struct pvr2_v4l2_fh *fhp;
- struct pvr2_v4l2 *vp = dip->v4lp;
- struct pvr2_hdw *hdw = vp->channel.hdw;
+ struct pvr2_v4l2 *vp;
+ struct pvr2_hdw *hdw;
+
+ mutex_lock(&device_lock);
+ /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
+ atomic read of the device mapping array here, we still need the
+ mutex. The problem is that there is a tiny race possible when
+ we register the device. We can't update the device mapping
+ array until after the device has been registered, owing to the
+ fact that we can't know the minor device number until after the
+ registration succeeds. And if another thread tries to open the
+ device in the window of time after registration but before the
+ map is updated, then it will get back an erroneous null pointer
+ and the open will result in a spurious failure. The only way to
+ prevent that is to (a) be inside the mutex here before we access
+ the array, and (b) cover the entire registration process later
+ on with this same mutex. Thus if we get inside the mutex here,
+ then we can be assured that the registration process actually
+ completed correctly. This is an unhappy complication from the
+ use of global data in a driver that lives in a preemptible
+ environment. It sure would be nice if the video device itself
+ had a means for storing and retrieving a local context pointer.
+ Oh wait. It did. But now it's gone. Silly me. */
+ {
+ unsigned int midx = iminor(file->f_dentry->d_inode);
+ if (midx < sizeof(devices)/sizeof(devices[0])) {
+ dip = devices[midx];
+ }
+ }
+ mutex_unlock(&device_lock);
+
+ if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
+
+ vp = dip->v4lp;
+ hdw = vp->channel.hdw;
pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
@@ -980,7 +1026,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
dip->vdev->dev = &usbdev->dev;
#endif
dip->vdev->release = video_device_release;
- video_set_drvdata(dip->vdev,dip);
+ mutex_lock(&device_lock);
mindevnum = -1;
unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
@@ -995,6 +1041,14 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
"registered device video%d [%s]",
dip->vdev->minor,pvr2_config_get_name(dip->config));
}
+
+ if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
+ (devices[dip->vdev->minor] == NULL)) {
+ dip->ctxt_idx = dip->vdev->minor;
+ devices[dip->ctxt_idx] = dip;
+ }
+ mutex_unlock(&device_lock);
+
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
dip->vdev->minor);
}
@@ -1007,6 +1061,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
vp = kmalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
memset(vp,0,sizeof(*vp));
+ vp->video_dev.ctxt_idx = -1;
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);