diff options
Diffstat (limited to 'linux/drivers/media/video/pwc')
| -rw-r--r-- | linux/drivers/media/video/pwc/pwc-if.c | 52 | ||||
| -rw-r--r-- | linux/drivers/media/video/pwc/pwc.h | 1 | 
2 files changed, 36 insertions, 17 deletions
| diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index 2becc489a..56d4b5f0f 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -1232,12 +1232,19 @@ static int pwc_video_open(struct inode *inode, struct file *file)  	return 0;  } + +static void pwc_cleanup(struct pwc_device *pdev) +{ +	pwc_remove_sysfs_files(pdev->vdev); +	video_unregister_device(pdev->vdev); +} +  /* Note that all cleanup is done in the reverse order as in _open */  static int pwc_video_close(struct inode *inode, struct file *file)  {  	struct video_device *vdev = file->private_data;  	struct pwc_device *pdev; -	int i; +	int i, hint;  	PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); @@ -1260,8 +1267,9 @@ static int pwc_video_close(struct inode *inode, struct file *file)  	pwc_isoc_cleanup(pdev);  	pwc_free_buffers(pdev); +	lock_kernel();  	/* Turn off LEDS and power down camera, but only when not unplugged */ -	if (pdev->error_status != EPIPE) { +	if (!pdev->unplugged) {  		/* Turn LEDs off */  		if (pwc_set_leds(pdev, 0, 0) < 0)  			PWC_DEBUG_MODULE("Failed to set LED on/off time.\n"); @@ -1270,9 +1278,19 @@ static int pwc_video_close(struct inode *inode, struct file *file)  			if (i < 0)  				PWC_ERROR("Failed to power down camera (%d)\n", i);  		} +		pdev->vopen--; +		PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", i); +	} else { +		pwc_cleanup(pdev); +		/* Free memory (don't set pdev to 0 just yet) */ +		kfree(pdev); +		/* search device_hint[] table if we occupy a slot, by any chance */ +		for (hint = 0; hint < MAX_DEV_HINTS; hint++) +			if (device_hint[hint].pdev == pdev) +				device_hint[hint].pdev = NULL;  	} -	pdev->vopen--; -	PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); +	unlock_kernel(); +  	return 0;  } @@ -1842,21 +1860,21 @@ static void usb_pwc_disconnect(struct usb_interface *intf)  	/* Alert waiting processes */  	wake_up_interruptible(&pdev->frameq);  	/* Wait until device is closed */ -	while (pdev->vopen) -		schedule(); -	/* Device is now closed, so we can safely unregister it */ -	PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); -	pwc_remove_sysfs_files(pdev->vdev); -	video_unregister_device(pdev->vdev); - -	/* Free memory (don't set pdev to 0 just yet) */ -	kfree(pdev); +	if(pdev->vopen) { +		pdev->unplugged = 1; +	} else { +		/* Device is closed, so we can safely unregister it */ +		PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); +		pwc_cleanup(pdev); +		/* Free memory (don't set pdev to 0 just yet) */ +		kfree(pdev);  disconnect_out: -	/* search device_hint[] table if we occupy a slot, by any chance */ -	for (hint = 0; hint < MAX_DEV_HINTS; hint++) -		if (device_hint[hint].pdev == pdev) -			device_hint[hint].pdev = NULL; +		/* search device_hint[] table if we occupy a slot, by any chance */ +		for (hint = 0; hint < MAX_DEV_HINTS; hint++) +			if (device_hint[hint].pdev == pdev) +				device_hint[hint].pdev = NULL; +	}  	unlock_kernel();  } diff --git a/linux/drivers/media/video/pwc/pwc.h b/linux/drivers/media/video/pwc/pwc.h index 0c77c3019..a01dcb282 100644 --- a/linux/drivers/media/video/pwc/pwc.h +++ b/linux/drivers/media/video/pwc/pwc.h @@ -197,6 +197,7 @@ struct pwc_device     char vsnapshot;		/* snapshot mode */     char vsync;			/* used by isoc handler */     char vmirror;		/* for ToUCaM series */ +	char unplugged;     int cmd_len;     unsigned char cmd_buf[13]; | 
