Index: usb-devel/drivers/media/usb/usbvision/usbvision-video.c =================================================================== --- usb-devel.orig/drivers/media/usb/usbvision/usbvision-video.c +++ usb-devel/drivers/media/usb/usbvision/usbvision-video.c @@ -131,6 +131,25 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(USBVISION_VERSION_STRING); MODULE_ALIAS(DRIVER_ALIAS); +#include +#include + +static void usbvision_check(struct usb_usbvision *usbvision, char *msg) +{ + struct kernfs_node *kn; + + if (!video_is_registered(&usbvision->rdev)) { + dev_info(&usbvision->rdev.dev, "Not registered: %s\n", msg); + } else { + kn = kernfs_find_and_get(usbvision->rdev.dev.kobj.sd, "power"); + if (kn) { + kernfs_put(kn); + dev_info(&usbvision->rdev.dev, "Power ok: %s\n", msg); + } else { + dev_err(&usbvision->rdev.dev, "Power gone: %s\n", msg); + } + } +} /*****************************************************************************/ /* SYSFS Code - Copied from the stv680.c usb module. */ @@ -314,6 +333,11 @@ static int usbvision_v4l2_open(struct fi if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + if (usbvision->remove_pending) { + err_code = -ENODEV; + goto unlock; + } + usbvision_check(usbvision, "v4l2 open"); if (usbvision->user) { err_code = -EBUSY; } else { @@ -377,10 +401,12 @@ unlock: static int usbvision_v4l2_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, "close"); mutex_lock(&usbvision->v4l2_lock); + usbvision_check(usbvision, "v4l2 close 1"); usbvision_audio_off(usbvision); usbvision_restart_isoc(usbvision); usbvision_stop_isoc(usbvision); @@ -389,11 +415,13 @@ static int usbvision_v4l2_close(struct f usbvision_frames_free(usbvision); usbvision_empty_framequeues(usbvision); usbvision_scratch_free(usbvision); + usbvision_check(usbvision, "v4l2 close 2"); usbvision->user--; + r = usbvision->remove_pending; mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->remove_pending) { + if (r) { printk(KERN_INFO "%s: Final disconnect\n", __func__); usbvision_release(usbvision); return 0; @@ -453,6 +481,9 @@ static int vidioc_querycap(struct file * { struct usb_usbvision *usbvision = video_drvdata(file); + if (!usbvision->dev) + return -ENODEV; + strscpy(vc->driver, "USBVision", sizeof(vc->driver)); strscpy(vc->card, usbvision_device_data[usbvision->dev_model].model_string, @@ -1073,6 +1104,12 @@ static int usbvision_radio_open(struct f if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + + if (usbvision->remove_pending) { + err_code = -ENODEV; + goto out; + } + usbvision_check(usbvision, "radio open"); err_code = v4l2_fh_open(file); if (err_code) goto out; @@ -1105,21 +1142,25 @@ out: static int usbvision_radio_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, ""); mutex_lock(&usbvision->v4l2_lock); + usbvision_check(usbvision, "radio close"); /* Set packet size to 0 */ usbvision->iface_alt = 0; - usb_set_interface(usbvision->dev, usbvision->iface, + if (usbvision->dev) + usb_set_interface(usbvision->dev, usbvision->iface, usbvision->iface_alt); usbvision_audio_off(usbvision); usbvision->radio = 0; usbvision->user--; + r = usbvision->remove_pending; mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->remove_pending) { + if (r) { printk(KERN_INFO "%s: Final disconnect\n", __func__); v4l2_fh_release(file); usbvision_release(usbvision); @@ -1233,10 +1274,13 @@ static void usbvision_vdev_init(struct u static void usbvision_unregister_video(struct usb_usbvision *usbvision) { /* Radio Device: */ + usbvision_check(usbvision, "unregister video"); if (video_is_registered(&usbvision->rdev)) { PDEBUG(DBG_PROBE, "unregister %s [v4l2]", video_device_node_name(&usbvision->rdev)); + dev_info(&usbvision->rdev.dev, "Unregister\n"); video_unregister_device(&usbvision->rdev); + printk(KERN_INFO "Unregister done\n"); } /* Video Device: */ @@ -1283,6 +1327,7 @@ static int usbvision_register_video(stru usbvision->nr, video_device_node_name(&usbvision->rdev)); } /* all done */ + usbvision_check(usbvision, "register video"); return 0; err_exit: @@ -1346,6 +1391,7 @@ static void usbvision_release(struct usb { PDEBUG(DBG_PROBE, ""); + usbvision_check(usbvision, "release"); usbvision->initialized = 0; usbvision_remove_sysfs(&usbvision->vdev); @@ -1551,6 +1597,7 @@ err_usb: static void usbvision_disconnect(struct usb_interface *intf) { struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf)); + int u; PDEBUG(DBG_PROBE, ""); @@ -1560,6 +1607,7 @@ static void usbvision_disconnect(struct } mutex_lock(&usbvision->v4l2_lock); + usbvision_check(usbvision, "disconnect 1"); /* At this time we ask to cancel outstanding URBs */ usbvision_stop_isoc(usbvision); @@ -1567,13 +1615,15 @@ static void usbvision_disconnect(struct v4l2_device_disconnect(&usbvision->v4l2_dev); usbvision_i2c_unregister(usbvision); usbvision->remove_pending = 1; /* Now all ISO data will be ignored */ + u = usbvision->user; usb_put_dev(usbvision->dev); usbvision->dev = NULL; /* USB device is no more */ + usbvision_check(usbvision, "disconnect 2"); mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->user) { + if (u) { printk(KERN_INFO "%s: In use, disconnect pending\n", __func__); wake_up_interruptible(&usbvision->wait_frame); Index: usb-devel/fs/sysfs/group.c =================================================================== --- usb-devel.orig/fs/sysfs/group.c +++ usb-devel/fs/sysfs/group.c @@ -125,6 +125,12 @@ static int internal_create_group(struct } kobject_get_ownership(kobj, &uid, &gid); if (grp->name) { + const char *kname = kobject_name(kobj); + + if (strcmp(grp->name, "power") == 0 && + strncmp(kname, "radio", 5) == 0) + pr_info("Adding '%s' to '%s'\n", grp->name, kname); + if (update) { kn = kernfs_find_and_get(kobj->sd, grp->name); if (!kn) { @@ -273,6 +279,12 @@ void sysfs_remove_group(struct kobject * struct kernfs_node *kn; if (grp->name) { + const char *kname = kobject_name(kobj); + + if (strcmp(grp->name, "power") == 0 && + strncmp(kname, "radio", 5) == 0) + pr_info("Removing '%s' from '%s'\n", grp->name, kname); + kn = kernfs_find_and_get(parent, grp->name); if (!kn) { WARN(!kn, KERN_WARNING Index: usb-devel/drivers/base/power/sysfs.c =================================================================== --- usb-devel.orig/drivers/base/power/sysfs.c +++ usb-devel/drivers/base/power/sysfs.c @@ -642,14 +642,18 @@ static const struct attribute_group pm_q int dpm_sysfs_add(struct device *dev) { int rc; + int m = !strncmp(dev_name(dev), "radio", 5); /* No need to create PM sysfs if explicitly disabled. */ if (device_pm_not_required(dev)) return 0; + if (m) dev_info(dev, "Registering 'power' group\n"); rc = sysfs_create_group(&dev->kobj, &pm_attr_group); - if (rc) + if (rc) { + if (m) dev_info(dev, "Registration failed\n"); return rc; + } if (pm_runtime_callbacks_present(dev)) { rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); @@ -674,6 +678,7 @@ int dpm_sysfs_add(struct device *dev) err_runtime: sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); err_out: + if (m) dev_info(dev, "Undo registration\n"); sysfs_remove_group(&dev->kobj, &pm_attr_group); return rc; }