ChangeSet 1.1005.1.11, 2003/06/27 16:01:00-07:00, oliver@neukum.org

[PATCH] USB: disconnect of v4l devices in 2.4

in 2.4 video_unregister_device() has lost its magic properties
breaking most USB v4l drivers. IMHO they should be converted
to delayed freeing resources just like ordinary character devices.
Here's the change for vicam.c.


 drivers/usb/vicam.c |   43 +++++++++++++++++++++++++++++++++----------
 1 files changed, 33 insertions(+), 10 deletions(-)


diff -Nru a/drivers/usb/vicam.c b/drivers/usb/vicam.c
--- a/drivers/usb/vicam.c	Fri Jun 27 16:27:04 2003
+++ b/drivers/usb/vicam.c	Fri Jun 27 16:27:04 2003
@@ -367,7 +367,8 @@
 	struct semaphore busy_lock;	// guard against SMP multithreading
 
 	bool is_initialized;
-	u8 open_count;
+	bool is_removed;
+	bool is_opened;
 	u8 bulkEndpoint;
 	bool needsDummyRead;
 
@@ -704,6 +705,7 @@
 {
 	struct vicam_camera *cam =
 	    (struct vicam_camera *) dev->priv;
+	int intr;
 	DBG("open\n");
 
 	if (!cam) {
@@ -711,9 +713,11 @@
 		       "vicam video_device improperly initialized");
 	}
 
-	down_interruptible(&cam->busy_lock);
+	intr = down_interruptible(&cam->busy_lock);
+	if (intr)
+		return -EINTR;
 
-	if (cam->open_count > 0) {
+	if (cam->is_opened) {
 		printk(KERN_INFO
 		       "vicam_open called on already opened camera");
 		up(&cam->busy_lock);
@@ -748,7 +752,7 @@
 	set_camera_power(cam, 1);
 
 	cam->needsDummyRead = 1;
-	cam->open_count++;
+	cam->is_opened = 1;
 
 	up(&cam->busy_lock);
 
@@ -759,9 +763,13 @@
 vicam_close(struct video_device *dev)
 {
 	DBG("close\n");
-	set_camera_power((struct vicam_camera *) dev->priv, 0);
+	struct vicam_camera *cam = (struct vicam_camera *) dev->priv;
 
-	((struct vicam_camera *) dev->priv)->open_count--;
+	set_camera_power(cam, 0);
+	if (cam->is_removed)
+		vicam_purge(cam);
+	else
+		cam->is_opened = 0;
 }
 
 inline int pin(int x)
@@ -772,7 +780,7 @@
 inline void writepixel(char *rgb, int Y, int Cr, int Cb)
 {
 	Y = 1160 * (Y - 16);
-	
+
 	rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
 	rgb[1] = pin( ( ( Y - (  392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
 	rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
@@ -939,6 +947,7 @@
 		 unsigned long count, int noblock)
 {
 	struct vicam_camera *cam = dev->priv;
+	int intr;
 	DBG("read %d bytes.\n", (int) count);
 
 	if (!buf)
@@ -975,7 +984,9 @@
 		}
 	}
 
-	down_interruptible(&cam->busy_lock);
+	intr = down_interruptible(&cam->busy_lock);
+	if (intr)
+		return -EINTR;
 
 	if (cam->needsDummyRead) {
 		read_frame(cam, 0);
@@ -1306,10 +1317,10 @@
 	return cam;
 }
 
+
 static void
-vicam_disconnect(struct usb_device *dev, void *ptr)
+vicam_purge(struct vicam_camera *cam)
 {
-	struct vicam_camera *cam = ptr;
 	video_unregister_device(&cam->vdev);
 
 #ifdef CONFIG_PROC_FS
@@ -1325,6 +1336,18 @@
 	kfree(cam);
 
 	printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
+}
+
+static void
+vicam_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct vicam_camera *cam = ptr;
+
+	if (cam->is_opened) {
+		cam->is_removed = 1;
+	} else {
+		vicam_purge(cam);
+	}
 }
 
 /*