V4L/DVB (13422): gspca - ov534: ov772x changes from Richard Kaswy.
[safe/jmp/linux-2.6] / drivers / media / video / w9968cf.c
index cce23d2..37fcdc4 100644 (file)
@@ -42,6 +42,8 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <linux/page-flags.h>
+#include <linux/videodev.h>
+#include <media/v4l2-ioctl.h>
 
 #include "w9968cf.h"
 #include "w9968cf_decoder.h"
@@ -67,7 +69,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION);
 MODULE_LICENSE(W9968CF_MODULE_LICENSE);
 MODULE_SUPPORTED_DEVICE("Video");
 
-static int ovmod_load = W9968CF_OVMOD_LOAD;
 static unsigned short simcams = W9968CF_SIMCAMS;
 static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
 static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
@@ -110,9 +111,6 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG;
 
 static unsigned int param_nv[24]; /* number of values per parameter */
 
-#ifdef CONFIG_KMOD
-module_param(ovmod_load, bool, 0644);
-#endif
 module_param(simcams, ushort, 0644);
 module_param_array(video_nr, short, &param_nv[0], 0444);
 module_param_array(packet_size, uint, &param_nv[1], 0444);
@@ -143,18 +141,6 @@ module_param(debug, ushort, 0644);
 module_param(specific_debug, bool, 0644);
 #endif
 
-#ifdef CONFIG_KMOD
-MODULE_PARM_DESC(ovmod_load,
-                "\n<0|1> Automatic 'ovcamchip' module loading."
-                "\n0 disabled, 1 enabled."
-                "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
-                "\nmodule in the system, according to its configuration, and"
-                "\nattempts to load that module automatically. This action is"
-                "\nperformed once as soon as the 'w9968cf' module is loaded"
-                "\ninto memory."
-                "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
-                "\n");
-#endif
 MODULE_PARM_DESC(simcams,
                 "\n<n> Number of cameras allowed to stream simultaneously."
                 "\nn may vary from 0 to "
@@ -398,13 +384,13 @@ MODULE_PARM_DESC(specific_debug,
  ****************************************************************************/
 
 /* Video4linux interface */
-static const struct file_operations w9968cf_fops;
-static int w9968cf_open(struct inode*, struct file*);
-static int w9968cf_release(struct inode*, struct file*);
-static int w9968cf_mmap(struct file*, struct vm_area_struct*);
-static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);
-static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int,
+static const struct v4l2_file_operations w9968cf_fops;
+static int w9968cf_open(struct file *);
+static int w9968cf_release(struct file *);
+static int w9968cf_mmap(struct file *, struct vm_area_struct *);
+static long w9968cf_ioctl(struct file *, unsigned, unsigned long);
+static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *);
+static long w9968cf_v4l_ioctl(struct file *, unsigned int,
                             void __user *);
 
 /* USB-specific */
@@ -442,8 +428,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
                                  unsigned short flags, char read_write,
                                  u8 command, int size, union i2c_smbus_data*);
 static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
 
 /* Memory management */
 static void* rvmalloc(unsigned long size);
@@ -476,7 +460,7 @@ static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
 static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
 static int w9968cf_postprocess_frame(struct w9968cf_device*,
                                     struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
+static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
 static void w9968cf_init_framelist(struct w9968cf_device*);
 static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
 static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
@@ -910,7 +894,6 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
 
        for (i = 0; i < W9968CF_URBS; i++) {
                urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
                if (!urb) {
                        for (j = 0; j < i; j++)
                                usb_free_urb(cam->urb[j]);
@@ -918,6 +901,7 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
                        return -ENOMEM;
                }
 
+               cam->urb[i] = urb;
                urb->dev = udev;
                urb->context = (void*)cam;
                urb->pipe = usb_rcvisocpipe(udev, 1);
@@ -1442,19 +1426,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                       unsigned short flags, char read_write, u8 command,
                       int size, union i2c_smbus_data *data)
 {
-       struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+       struct w9968cf_device *cam = to_cam(v4l2_dev);
        u8 i;
        int err = 0;
 
-       switch (addr) {
-               case OV6xx0_SID:
-               case OV7xx0_SID:
-                       break;
-               default:
-                       DBG(4, "Rejected slave ID 0x%04X", addr)
-                       return -EINVAL;
-       }
-
        if (size == I2C_SMBUS_BYTE) {
                /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
                addr <<= 1;
@@ -1462,8 +1438,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                if (read_write == I2C_SMBUS_WRITE)
                        err = w9968cf_i2c_adap_write_byte(cam, addr, command);
                else if (read_write == I2C_SMBUS_READ)
-                       err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
+                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+                               err = w9968cf_i2c_adap_read_byte(cam, addr,
+                                                        &data->byte);
+                               if (err) {
+                                       if (w9968cf_smbus_refresh_bus(cam)) {
+                                               err = -EIO;
+                                               break;
+                                       }
+                               } else
+                                       break;
+                       }
        } else if (size == I2C_SMBUS_BYTE_DATA) {
                addr <<= 1;
 
@@ -1490,7 +1475,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
                DBG(4, "Unsupported I2C transfer mode (%d)", size)
                return -EINVAL;
        }
-
        return err;
 }
 
@@ -1503,44 +1487,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
 }
 
 
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-       int id = client->driver->id, err = 0;
-
-       if (id == I2C_DRIVERID_OVCAMCHIP) {
-               cam->sensor_client = client;
-               err = w9968cf_sensor_init(cam);
-               if (err) {
-                       cam->sensor_client = NULL;
-                       return err;
-               }
-       } else {
-               DBG(4, "Rejected client [%s] with driver [%s]",
-                   client->name, client->driver->driver.name)
-               return -EINVAL;
-       }
-
-       DBG(5, "I2C attach client [%s] with driver [%s]",
-           client->name, client->driver->driver.name)
-
-       return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
-       if (cam->sensor_client == client)
-               cam->sensor_client = NULL;
-
-       DBG(5, "I2C detach client [%s]", client->name)
-
-       return 0;
-}
-
-
 static int w9968cf_i2c_init(struct w9968cf_device* cam)
 {
        int err = 0;
@@ -1551,18 +1497,14 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
        };
 
        static struct i2c_adapter adap = {
-               .id =                I2C_HW_SMBUS_W9968CF,
-               .class =             I2C_CLASS_CAM_DIGITAL,
                .owner =             THIS_MODULE,
-               .client_register =   w9968cf_i2c_attach_inform,
-               .client_unregister = w9968cf_i2c_detach_inform,
                .algo =              &algo,
        };
 
        memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
        strcpy(cam->i2c_adapter.name, "w9968cf");
        cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
-       i2c_set_adapdata(&cam->i2c_adapter, cam);
+       i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
 
        DBG(6, "Registering I2C adapter with kernel...")
 
@@ -1820,8 +1762,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
        #define UNSC(x) ((x) >> 10)
 
        /* Make sure we are using a supported resolution */
-       if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
-                                             (u16*)&win.height)))
+       if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
                goto error;
 
        /* Scaling factors */
@@ -1971,12 +1912,9 @@ error:
   Return 0 on success, -1 otherwise.
   --------------------------------------------------------------------------*/
 static int
-w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
+w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
 {
-       u16 maxw, maxh;
-
-       if ((*width < cam->minwidth) || (*height < cam->minheight))
-               return -ERANGE;
+       unsigned int maxw, maxh, align;
 
        maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
               w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
@@ -1984,16 +1922,10 @@ w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
        maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
               w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
                           : cam->maxheight;
+       align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
 
-       if (*width > maxw)
-               *width = maxw;
-       if (*height > maxh)
-               *height = maxh;
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               *width  &= ~15L; /* multiple of 16 */
-               *height &= ~15L;
-       }
+       v4l_bound_align_image(width, cam->minwidth, maxw, align,
+                             height, cam->minheight, maxh, align, 0);
 
        PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
 
@@ -2165,13 +2097,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
 static int
 w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
 {
-       struct i2c_client* c = cam->sensor_client;
-       int rc = 0;
-
-       if (!c || !c->driver || !c->driver->command)
-               return -EINVAL;
+       int rc;
 
-       rc = c->driver->command(c, cmd, arg);
+       rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
        /* The I2C driver returns -EPERM on non-supported controls */
        return (rc < 0 && rc != -EPERM) ? rc : 0;
 }
@@ -2346,7 +2274,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam)
                goto error;
 
        /* NOTE: Make sure width and height are a multiple of 16 */
-       switch (cam->sensor_client->addr) {
+       switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
                case OV6xx0_SID:
                        cam->maxwidth = 352;
                        cam->maxheight = 288;
@@ -2397,7 +2325,7 @@ error:
        cam->sensor = CC_UNKNOWN;
        DBG(1, "Image sensor initialization failed for %s (/dev/video%d). "
               "Try to detach and attach this device again",
-           symbolic(camlist, cam->id), cam->v4ldev->minor)
+           symbolic(camlist, cam->id), cam->v4ldev->num)
        return err;
 }
 
@@ -2643,7 +2571,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
 {
        mutex_lock(&w9968cf_devlist_mutex);
 
-       DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
+       DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num)
 
        video_unregister_device(cam->v4ldev);
        list_del(&cam->v4llist);
@@ -2651,6 +2579,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
        w9968cf_deallocate_memory(cam);
        kfree(cam->control_buffer);
        kfree(cam->data_buffer);
+       v4l2_device_unregister(&cam->v4l2_dev);
 
        mutex_unlock(&w9968cf_devlist_mutex);
 }
@@ -2661,7 +2590,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
  * Video4Linux interface                                                    *
  ****************************************************************************/
 
-static int w9968cf_open(struct inode* inode, struct file* filp)
+static int w9968cf_open(struct file *filp)
 {
        struct w9968cf_device* cam;
        int err;
@@ -2678,7 +2607,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
                DBG(2, "No supported image sensor has been detected by the "
                       "'ovcamchip' module for the %s (/dev/video%d). Make "
                       "sure it is loaded *before* (re)connecting the camera.",
-                   symbolic(camlist, cam->id), cam->v4ldev->minor)
+                   symbolic(camlist, cam->id), cam->v4ldev->num)
                mutex_unlock(&cam->dev_mutex);
                up_read(&w9968cf_disconnect);
                return -ENODEV;
@@ -2686,7 +2615,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
 
        if (cam->users) {
                DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
-                   symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
+                   symbolic(camlist, cam->id), cam->v4ldev->num, cam->command)
                if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
                        mutex_unlock(&cam->dev_mutex);
                        up_read(&w9968cf_disconnect);
@@ -2708,7 +2637,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
        }
 
        DBG(5, "Opening '%s', /dev/video%d ...",
-           symbolic(camlist, cam->id), cam->v4ldev->minor)
+           symbolic(camlist, cam->id), cam->v4ldev->num)
 
        cam->streaming = 0;
        cam->misconfigured = 0;
@@ -2747,7 +2676,7 @@ deallocate_memory:
 }
 
 
-static int w9968cf_release(struct inode* inode, struct file* filp)
+static int w9968cf_release(struct file *filp)
 {
        struct w9968cf_device* cam;
 
@@ -2884,12 +2813,12 @@ static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
 }
 
 
-static int
-w9968cf_ioctl(struct inode* inode, struct file* filp,
+static long
+w9968cf_ioctl(struct file *filp,
              unsigned int cmd, unsigned long arg)
 {
        struct w9968cf_device* cam;
-       int err;
+       long err;
 
        cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
@@ -2908,15 +2837,15 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
                return -EIO;
        }
 
-       err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
+       err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg);
 
        mutex_unlock(&cam->fileop_mutex);
        return err;
 }
 
 
-static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
-                            unsigned int cmd, void __user * arg)
+static long w9968cf_v4l_ioctl(struct file *filp,
+                            unsigned int cmd, void __user *arg)
 {
        struct w9968cf_device* cam;
        const char* v4l1_ioctls[] = {
@@ -2946,7 +2875,7 @@ static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
                        .minheight = cam->minheight,
                };
                sprintf(cap.name, "W996[87]CF USB Camera #%d",
-                       cam->v4ldev->minor);
+                       cam->v4ldev->num);
                cap.maxwidth = (cam->upscaling && w9968cf_vpp)
                               ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
                                 : cam->maxwidth;
@@ -3103,8 +3032,8 @@ static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
                if (win.clipcount != 0 || win.flags != 0)
                        return -EINVAL;
 
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
-                                                     (u16*)&win.height))) {
+               if ((err = w9968cf_adjust_window_size(cam, &win.width,
+                                                     &win.height))) {
                        DBG(4, "Resolution not supported (%ux%u). "
                               "VIDIOCSWIN failed", win.width, win.height)
                        return err;
@@ -3176,6 +3105,7 @@ static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
        {
                struct video_mmap mmap;
                struct w9968cf_frame_t* fr;
+               u32 w, h;
                int err = 0;
 
                if (copy_from_user(&mmap, arg, sizeof(mmap)))
@@ -3224,8 +3154,10 @@ static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
                   }
                }
 
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width,
-                                                     (u16*)&mmap.height))) {
+               w = mmap.width; h = mmap.height;
+               err = w9968cf_adjust_window_size(cam, &w, &h);
+               mmap.width = w; mmap.height = h;
+               if (err) {
                        DBG(4, "Resolution not supported (%dx%d). "
                               "VIDIOCMCAPTURE failed",
                            mmap.width, mmap.height)
@@ -3455,15 +3387,13 @@ ioctl_fail:
 }
 
 
-static const struct file_operations w9968cf_fops = {
+static const struct v4l2_file_operations w9968cf_fops = {
        .owner =   THIS_MODULE,
        .open =    w9968cf_open,
        .release = w9968cf_release,
        .read =    w9968cf_read,
        .ioctl =   w9968cf_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
        .mmap =    w9968cf_mmap,
-       .llseek =  no_llseek,
 };
 
 
@@ -3482,6 +3412,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        struct list_head* ptr;
        u8 sc = 0; /* number of simultaneous cameras */
        static unsigned short dev_nr; /* 0 - we are handling device number n */
+       static unsigned short addrs[] = {
+               OV7xx0_SID,
+               OV6xx0_SID,
+               I2C_CLIENT_END
+       };
 
        if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
            le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
@@ -3497,12 +3432,14 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        if (!cam)
                return -ENOMEM;
 
+       err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
+       if (err)
+               goto fail0;
+
        mutex_init(&cam->dev_mutex);
        mutex_lock(&cam->dev_mutex);
 
        cam->usbdev = udev;
-       /* NOTE: a local copy is used to avoid possible race conditions */
-       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
 
        DBG(2, "%s detected", symbolic(camlist, mod_id))
 
@@ -3547,13 +3484,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        }
 
        strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
        cam->v4ldev->fops = &w9968cf_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
-       cam->v4ldev->dev = &cam->dev;
+       cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -3566,7 +3501,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
+       DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num)
 
        /* Set some basic constants */
        w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
@@ -3580,9 +3515,14 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        w9968cf_turn_on_led(cam);
 
        w9968cf_i2c_init(cam);
+       cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
+                       &cam->i2c_adapter,
+                       "ovcamchip", "ovcamchip", 0, addrs);
 
        usb_set_intfdata(intf, cam);
        mutex_unlock(&cam->dev_mutex);
+
+       err = w9968cf_sensor_init(cam);
        return 0;
 
 fail: /* Free unused memory */
@@ -3591,6 +3531,8 @@ fail: /* Free unused memory */
        if (cam->v4ldev)
                video_device_release(cam->v4ldev);
        mutex_unlock(&cam->dev_mutex);
+       v4l2_device_unregister(&cam->v4l2_dev);
+fail0:
        kfree(cam);
        return err;
 }
@@ -3601,15 +3543,16 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
        struct w9968cf_device* cam =
           (struct w9968cf_device*)usb_get_intfdata(intf);
 
-       down_write(&w9968cf_disconnect);
-
        if (cam) {
+               down_write(&w9968cf_disconnect);
                /* Prevent concurrent accesses to data */
                mutex_lock(&cam->dev_mutex);
 
                cam->disconnected = 1;
 
-               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
+               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
+
+               v4l2_device_disconnect(&cam->v4l2_dev);
 
                wake_up_interruptible_all(&cam->open);
 
@@ -3617,7 +3560,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
                        DBG(2, "The device is open (/dev/video%d)! "
                               "Process name: %s. Deregistration and memory "
                               "deallocation are deferred on close.",
-                           cam->v4ldev->minor, cam->command)
+                           cam->v4ldev->num, cam->command)
                        cam->misconfigured = 1;
                        w9968cf_stop_transfer(cam);
                        wake_up_interruptible(&cam->wait_queue);
@@ -3625,12 +3568,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
                        w9968cf_release_resources(cam);
 
                mutex_unlock(&cam->dev_mutex);
+               up_write(&w9968cf_disconnect);
 
-               if (!cam->users)
+               if (!cam->users) {
                        kfree(cam);
+               }
        }
-
-       up_write(&w9968cf_disconnect);
 }
 
 
@@ -3654,9 +3597,6 @@ static int __init w9968cf_module_init(void)
        KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
        KDBG(3, W9968CF_MODULE_AUTHOR)
 
-       if (ovmod_load)
-               request_module("ovcamchip");
-
        if ((err = usb_register(&w9968cf_usb_driver)))
                return err;