summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/em28xx/em28xx-video.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/em28xx/em28xx-video.c')
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c275
1 files changed, 115 insertions, 160 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index d3bb65306..c75111219 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -39,7 +39,6 @@
#endif
#include "em28xx.h"
-#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/msp3400.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
@@ -89,10 +88,6 @@ MODULE_PARM_DESC(card,"card type");
MODULE_PARM_DESC(video_nr,"video device numbers");
MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
-static int tuner = -1;
-module_param(tuner, int, 0444);
-MODULE_PARM_DESC(tuner, "tuner type");
-
static unsigned int video_debug = 0;
module_param(video_debug,int,0644);
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
@@ -149,8 +144,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
static struct usb_driver em28xx_usb_driver;
-static DEFINE_MUTEX(em28xx_sysfs_lock);
-static DECLARE_RWSEM(em28xx_disconnect);
/********************* v4l2 interface ******************************************/
@@ -162,7 +155,8 @@ static int em28xx_config(struct em28xx *dev)
{
/* Sets I2C speed to 100 KHz */
- em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+ if (!dev->is_em2800)
+ em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
#if 1
/* enable vbi capturing */
@@ -190,7 +184,6 @@ static int em28xx_config(struct em28xx *dev)
*/
static void em28xx_config_i2c(struct em28xx *dev)
{
- struct v4l2_frequency f;
struct v4l2_routing route;
route.input = INPUT(dev->ctl_input)->vmux;
@@ -198,13 +191,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-
- /* configure tuner */
- f.tuner = 0;
- f.type = V4L2_TUNER_ANALOG_TV;
- f.frequency = 9076; /* FIXME:remove magic number */
- dev->ctl_freq = f.frequency;
- em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
}
/*
@@ -285,22 +271,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
em28xx_videodbg("open minor=%d type=%s users=%d\n",
minor,v4l2_type_names[dev->type],dev->users);
- if (!down_read_trylock(&em28xx_disconnect))
- return -ERESTARTSYS;
+ mutex_lock(&dev->lock);
if (dev->users) {
em28xx_warn("this driver can be opened only once\n");
- up_read(&em28xx_disconnect);
+ mutex_unlock(&dev->lock);
return -EBUSY;
}
- mutex_init(&dev->fileop_lock); /* to 1 == available */
spin_lock_init(&dev->queue_lock);
init_waitqueue_head(&dev->wait_frame);
init_waitqueue_head(&dev->wait_stream);
- mutex_lock(&dev->lock);
-
if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
em28xx_set_alternate(dev);
@@ -338,7 +320,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
err:
mutex_unlock(&dev->lock);
- up_read(&em28xx_disconnect);
return errCode;
}
@@ -349,7 +330,6 @@ err:
*/
static void em28xx_release_resources(struct em28xx *dev)
{
- mutex_lock(&em28xx_sysfs_lock);
/*FIXME: I2C IR should be disconnected */
@@ -361,7 +341,6 @@ static void em28xx_release_resources(struct em28xx *dev)
video_unregister_device(dev->vbi_dev);
em28xx_i2c_unregister(dev);
usb_put_dev(dev->udev);
- mutex_unlock(&em28xx_sysfs_lock);
#if 0 /* Fixme: disallocating these generates kernel hang */
kfree (dev->vdev);
@@ -425,6 +404,8 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
int ret = 0;
struct em28xx *dev = filp->private_data;
+ mutex_lock(&dev->lock);
+
if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
}
@@ -432,47 +413,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
em28xx_videodbg("not supported yet! ...\n");
if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EFAULT;
}
+ mutex_unlock(&dev->lock);
return (1);
}
if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
em28xx_videodbg("not supported yet! ...\n");
if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EFAULT;
}
+ mutex_unlock(&dev->lock);
return (1);
}
- if (mutex_lock_interruptible(&dev->fileop_lock))
- return -ERESTARTSYS;
-
if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("device not present\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -ENODEV;
}
if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg("device misconfigured; close and open it again\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EIO;
}
if (dev->io == IO_MMAP) {
em28xx_videodbg ("IO method is set to mmap; close and open"
" the device again to choose the read method\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EINVAL;
}
if (dev->io == IO_NONE) {
if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
em28xx_errdev("read failed, not enough memory\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -ENOMEM;
}
dev->io = IO_READ;
@@ -481,13 +461,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
}
if (!count) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return 0;
}
if (list_empty(&dev->outqueue)) {
if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EAGAIN;
}
ret = wait_event_interruptible
@@ -495,11 +475,11 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
(!list_empty(&dev->outqueue)) ||
(dev->state & DEV_DISCONNECTED));
if (ret) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return ret;
}
if (dev->state & DEV_DISCONNECTED) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -ENODEV;
}
}
@@ -518,12 +498,12 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
count = f->buf.length;
if (copy_to_user(buf, f->bufmem, count)) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EFAULT;
}
*f_pos += count;
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return count;
}
@@ -537,8 +517,7 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
unsigned int mask = 0;
struct em28xx *dev = filp->private_data;
- if (mutex_lock_interruptible(&dev->fileop_lock))
- return POLLERR;
+ mutex_lock(&dev->lock);
if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("device not present\n");
@@ -563,13 +542,13 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
if (!list_empty(&dev->outqueue))
mask |= POLLIN | POLLRDNORM;
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return mask;
}
}
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return POLLERR;
}
@@ -609,25 +588,24 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
struct em28xx *dev = filp->private_data;
- if (mutex_lock_interruptible(&dev->fileop_lock))
- return -ERESTARTSYS;
+ mutex_lock(&dev->lock);
if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("mmap: device not present\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -ENODEV;
}
if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg ("mmap: Device is misconfigured; close and "
"open it again\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EIO;
}
if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
size != PAGE_ALIGN(dev->frame[0].buf.length)) {
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EINVAL;
}
@@ -637,7 +615,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
}
if (i == dev->num_frames) {
em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EINVAL;
}
@@ -649,7 +627,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
while (size > 0) { /* size is page-aligned */
if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
em28xx_videodbg("mmap: vm_insert_page failed\n");
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return -EAGAIN;
}
start += PAGE_SIZE;
@@ -661,7 +639,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_private_data = &dev->frame[i];
em28xx_vm_open(vma);
- mutex_unlock(&dev->fileop_lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1148,7 +1126,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
}
}
}
+ mutex_lock(&dev->lock);
em28xx_i2c_call_clients(dev,cmd,qc);
+ mutex_unlock(&dev->lock);
if (qc->type)
return 0;
else
@@ -1162,7 +1142,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
if (!dev->has_msp34xx)
retval=em28xx_get_ctrl(dev, ctrl);
if (retval==-EINVAL) {
+ mutex_lock(&dev->lock);
em28xx_i2c_call_clients(dev,cmd,arg);
+ mutex_unlock(&dev->lock);
return 0;
} else return retval;
}
@@ -1170,21 +1152,26 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
{
struct v4l2_control *ctrl = arg;
u8 i;
+ mutex_lock(&dev->lock);
if (!dev->has_msp34xx){
for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
if (ctrl->id == em28xx_qctrl[i].id) {
+ int retval=-EINVAL;
if (ctrl->value <
em28xx_qctrl[i].minimum
|| ctrl->value >
em28xx_qctrl[i].maximum)
return -ERANGE;
- return em28xx_set_ctrl(dev, ctrl);
+ retval = em28xx_set_ctrl(dev, ctrl);
+ mutex_unlock(&dev->lock);
+ return retval;
}
}
}
em28xx_i2c_call_clients(dev,cmd,arg);
+ mutex_unlock(&dev->lock);
return 0;
}
/* --- tuner ioctls ------------------------------------------ */
@@ -1292,12 +1279,16 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
|| dev->io != IO_MMAP)
return -EINVAL;
+ mutex_lock(&dev->lock);
if (dev->stream == STREAM_ON) {
em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
- if ((ret = em28xx_stream_interrupt(dev)))
+ if ((ret = em28xx_stream_interrupt(dev))){
+ mutex_unlock(&dev->lock);
return ret;
+ }
}
em28xx_empty_framequeues(dev);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1366,11 +1357,23 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
return 0;
}
case VIDIOC_G_FMT:
- return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
+ {
+ int retval;
+ mutex_lock(&dev->lock);
+ retval = em28xx_get_fmt(dev, (struct v4l2_format *) arg);
+ mutex_unlock(&dev->lock);
+ return retval;
+ }
case VIDIOC_TRY_FMT:
case VIDIOC_S_FMT:
- return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
+ {
+ int retval;
+ mutex_lock(&dev->lock);
+ retval = em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
+ mutex_unlock(&dev->lock);
+ return retval;
+ }
#if 0
case VIDIOCGMBUF:
@@ -1421,10 +1424,13 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
return -EINVAL;
}
+ mutex_lock(&dev->lock);
if (dev->stream == STREAM_ON) {
em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
- if ((ret = em28xx_stream_interrupt(dev)))
+ if ((ret = em28xx_stream_interrupt(dev))){
+ mutex_unlock(&dev->lock);
return ret;
+ }
}
em28xx_empty_framequeues(dev);
@@ -1439,6 +1445,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
rb->count);
dev->io = rb->count ? IO_MMAP : IO_NONE;
+ mutex_unlock(&dev->lock);
return 0;
}
case VIDIOC_QUERYBUF:
@@ -1540,26 +1547,19 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
int ret = 0;
struct em28xx *dev = filp->private_data;
- if (mutex_lock_interruptible(&dev->fileop_lock))
- return -ERESTARTSYS;
-
if (dev->state & DEV_DISCONNECTED) {
em28xx_errdev("v4l2 ioctl: device not present\n");
- mutex_unlock(&dev->fileop_lock);
return -ENODEV;
}
if (dev->state & DEV_MISCONFIGURED) {
em28xx_errdev
("v4l2 ioctl: device is misconfigured; close and open it again\n");
- mutex_unlock(&dev->fileop_lock);
return -EIO;
}
ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
- mutex_unlock(&dev->fileop_lock);
-
return ret;
}
@@ -1585,7 +1585,7 @@ static const struct file_operations em28xx_v4l_fops = {
* allocates and inits the device structs, registers i2c bus and v4l device
*/
static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
- int minor, int model)
+ int minor)
{
struct em28xx *dev = *devhandle;
int retval = -ENOMEM;
@@ -1593,7 +1593,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
unsigned int maxh, maxw;
dev->udev = udev;
- dev->model = model;
mutex_init(&dev->lock);
init_waitqueue_head(&dev->open);
@@ -1602,43 +1601,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
dev->em28xx_write_regs_req = em28xx_write_regs_req;
dev->em28xx_read_reg_req = em28xx_read_reg_req;
- dev->is_em2800 = em28xx_boards[model].is_em2800;
- dev->has_tuner = em28xx_boards[model].has_tuner;
- dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
- dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
- dev->decoder = em28xx_boards[model].decoder;
-
- if (tuner >= 0)
- dev->tuner_type = tuner;
- else
- dev->tuner_type = em28xx_boards[model].tuner_type;
-
- dev->video_inputs = em28xx_boards[model].vchannels;
-
- for (i = 0; i < TVNORMS; i++)
- if (em28xx_boards[model].norm == tvnorms[i].mode)
- break;
- if (i == TVNORMS)
- i = 0;
-
- dev->tvnorm = &tvnorms[i]; /* set default norm */
-
- em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
-
- maxw = norm_maxw(dev);
- maxh = norm_maxh(dev);
-
- /* set default image size */
- dev->width = maxw;
- dev->height = maxh;
- dev->interlaced = EM28XX_INTERLACED_DEFAULT;
- dev->field_size = dev->width * dev->height;
- dev->frame_size =
- dev->interlaced ? dev->field_size << 1 : dev->field_size;
- dev->bytesperline = dev->width * 2;
- dev->hscale = 0;
- dev->vscale = 0;
- dev->ctl_input = 2;
+ dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
/* setup video picture settings for saa7113h */
memset(&dev->vpic, 0, sizeof(dev->vpic));
@@ -1651,24 +1614,15 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->vpic.palette = VIDEO_PALETTE_YUV422;
em28xx_pre_card_setup(dev);
-#ifdef CONFIG_MODULES
- /* request some modules */
- if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
- request_module("saa7115");
- if (dev->decoder == EM28XX_TVP5150)
- request_module("tvp5150");
- if (dev->has_tuner)
- request_module("tuner");
-#endif
+
errCode = em28xx_config(dev);
if (errCode) {
em28xx_errdev("error configuring device\n");
- em28xx_devused&=~(1<<dev->devno);
+ em28xx_devused &= ~(1<<dev->devno);
kfree(dev);
return -ENOMEM;
}
- mutex_lock(&dev->lock);
/* register i2c bus */
em28xx_i2c_register(dev);
@@ -1678,14 +1632,33 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
/* configure the device */
em28xx_config_i2c(dev);
- mutex_unlock(&dev->lock);
+ for (i = 0; i < TVNORMS; i++)
+ if (em28xx_boards[dev->model].norm == tvnorms[i].mode)
+ break;
+ if (i == TVNORMS)
+ i = 0;
+
+ dev->tvnorm = &tvnorms[i]; /* set default norm */
+
+ em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ /* set default image size */
+ dev->width = maxw;
+ dev->height = maxh;
+ dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+ dev->field_size = dev->width * dev->height;
+ dev->frame_size =
+ dev->interlaced ? dev->field_size << 1 : dev->field_size;
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = 0;
+ dev->vscale = 0;
+ dev->ctl_input = 2;
errCode = em28xx_config(dev);
-#ifdef CONFIG_MODULES
- if (dev->has_msp34xx)
- request_module("msp3400");
-#endif
/* allocate and fill v4l2 device struct */
dev->vdev = video_device_alloc();
if (NULL == dev->vdev) {
@@ -1732,8 +1705,18 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
video_set_drvdata(dev->vbi_dev, dev);
#endif
+
+ if (dev->has_msp34xx) {
+ /* Send a reset to other chips via gpio */
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+ msleep(3);
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+ msleep(3);
+
+ }
+ video_mux(dev, 0);
+
/* register v4l2 device */
- mutex_lock(&dev->lock);
if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]))) {
em28xx_errdev("unable to register video device (error=%i).\n",
@@ -1760,18 +1743,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
printk("registered VBI\n");
}
- if (dev->has_msp34xx) {
- /* Send a reset to other chips via gpio */
- em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
- msleep(3);
- em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
- msleep(3);
-
- }
- video_mux(dev, 0);
-
- mutex_unlock(&dev->lock);
-
em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
@@ -1791,7 +1762,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
struct usb_interface *uif;
struct em28xx *dev = NULL;
int retval = -ENODEV;
- int model,i,nr,ifnum;
+ int i, nr, ifnum;
udev = usb_get_dev(interface_to_usbdev(interface));
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
@@ -1831,8 +1802,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
return -ENODEV;
}
- model=id->driver_info;
-
if (nr >= EM28XX_MAXBOARDS) {
printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
em28xx_devused&=~(1<<nr);
@@ -1848,7 +1817,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
snprintf(dev->name, 29, "em28xx #%d", nr);
- dev->devno=nr;
+ dev->devno = nr;
+ dev->model = id->driver_info;
/* compute alternate max packet sizes */
uif = udev->actconfig->interface[0];
@@ -1875,30 +1845,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
- model=card[nr];
-
- if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
- em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
- "%s: be autodetected. Please pass card=<n> insmod option to\n"
- "%s: workaround that. Redirect complaints to the vendor of\n"
- "%s: the TV card. Generic type will be used."
- "%s: Best regards,\n"
- "%s: -- tux\n",
- dev->name,dev->name,dev->name,dev->name,dev->name);
- em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
- dev->name);
- for (i = 0; i < em28xx_bcount; i++) {
- em28xx_errdev(" card=%d -> %s\n", i,
- em28xx_boards[i].name);
- }
- }
+ dev->model = card[nr];
/* allocate device struct */
- retval = em28xx_init_dev(&dev, udev, nr, model);
+ retval = em28xx_init_dev(&dev, udev, nr);
if (retval)
return retval;
- em28xx_info("Found %s\n", em28xx_boards[model].name);
+ em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
@@ -1912,18 +1866,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
*/
static void em28xx_usb_disconnect(struct usb_interface *interface)
{
- struct em28xx *dev = usb_get_intfdata(interface);
+ struct em28xx *dev;
+
+ dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
if (!dev)
return;
- down_write(&em28xx_disconnect);
+ em28xx_info("disconnecting %s\n", dev->vdev->name);
+ /* wait until all current v4l2 io is finished then deallocate resources */
mutex_lock(&dev->lock);
- em28xx_info("disconnecting %s\n", dev->vdev->name);
-
wake_up_interruptible_all(&dev->open);
if (dev->users) {
@@ -1942,6 +1897,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_release_resources(dev);
}
+
mutex_unlock(&dev->lock);
if (!dev->users) {
@@ -1949,7 +1905,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
kfree(dev);
}
- up_write(&em28xx_disconnect);
}
static struct usb_driver em28xx_usb_driver = {