diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-06-11 22:31:36 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-06-11 22:31:36 -0300 |
commit | 596e34f736e4d6b93889149cfdd56d3dff96ba51 (patch) | |
tree | af9f600d599de7ef0e4673254faf974baee13c66 | |
parent | 77c159f6b446fdfacf6a8fc3dde6b2626e122cbd (diff) | |
parent | 3a43601e74870844d9420353be082c2a5a1fc56e (diff) | |
download | mediapointer-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.c | 6 | ||||
-rw-r--r-- | linux/drivers/media/video/pvrusb2/Kconfig | 2 | ||||
-rw-r--r-- | linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 71 |
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); |