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,26 @@ 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, "AS 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, "AS Power ok: %s\n", msg); + } else { + dev_err(&usbvision->rdev.dev, "AS Power gone: %s\n", msg); + } + } +} + /*****************************************************************************/ /* SYSFS Code - Copied from the stv680.c usb module. */ @@ -314,6 +334,10 @@ 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; + } if (usbvision->user) { err_code = -EBUSY; } else { @@ -377,6 +401,7 @@ unlock: static int usbvision_v4l2_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, "close"); @@ -391,9 +416,10 @@ static int usbvision_v4l2_close(struct f usbvision_scratch_free(usbvision); 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 +479,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 +1102,11 @@ 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; + } err_code = v4l2_fh_open(file); if (err_code) goto out; @@ -1105,21 +1139,28 @@ out: static int usbvision_radio_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, ""); + usbvision_check(usbvision, "radio close 1"); mutex_lock(&usbvision->v4l2_lock); + usbvision_check(usbvision, "radio close 2"); /* 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_check(usbvision, "radio close 3"); usbvision_audio_off(usbvision); usbvision->radio = 0; usbvision->user--; + r = usbvision->remove_pending; + usbvision_check(usbvision, "radio close 4"); 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); @@ -1236,6 +1277,7 @@ static void usbvision_unregister_video(s if (video_is_registered(&usbvision->rdev)) { PDEBUG(DBG_PROBE, "unregister %s [v4l2]", video_device_node_name(&usbvision->rdev)); + usbvision_check(usbvision, "unregister_video"); video_unregister_device(&usbvision->rdev); } @@ -1551,6 +1593,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, ""); @@ -1567,13 +1610,14 @@ 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 */ 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/drivers/base/power/sysfs.c =================================================================== --- usb-devel.orig/drivers/base/power/sysfs.c +++ usb-devel/drivers/base/power/sysfs.c @@ -11,6 +11,10 @@ #include #include "power.h" +#include +extern void ASadd(struct kernfs_node *parent); +extern void ASremove(struct kernfs_node *parent); + /* * control - Report/change current runtime PM setting of the device * @@ -652,6 +656,8 @@ int dpm_sysfs_add(struct device *dev) rc = sysfs_create_group(&dev->kobj, &pm_attr_group); if (rc) return rc; + if (strncmp(dev_name(dev), "radio", 5) == 0) + ASadd(&dev->kobj.sd); if (pm_runtime_callbacks_present(dev)) { rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); @@ -676,6 +682,8 @@ int dpm_sysfs_add(struct device *dev) err_runtime: sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); err_out: + if (strncmp(dev_name(dev), "radio", 5) == 0) + ASremove(&dev->kobj.sd); sysfs_remove_group(&dev->kobj, &pm_attr_group); return rc; } @@ -734,5 +742,7 @@ void dpm_sysfs_remove(struct device *dev dev_pm_qos_constraints_destroy(dev); rpm_sysfs_remove(dev); sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); + if (strncmp(dev_name(dev), "radio", 5) == 0) + ASremove(&dev->kobj.sd); sysfs_remove_group(&dev->kobj, &pm_attr_group); } Index: usb-devel/fs/kernfs/dir.c =================================================================== --- usb-devel.orig/fs/kernfs/dir.c +++ usb-devel/fs/kernfs/dir.c @@ -25,6 +25,46 @@ static DEFINE_SPINLOCK(kernfs_idr_lock); #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) +static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, + const unsigned char *name, + const void *ns); + +static LIST_HEAD(ASlist); +static DEFINE_MUTEX(ASmutex); + +void ASadd(struct kernfs_node *parent) +{ + mutex_lock(&ASmutex); + list_add(&parent->ASnode, &ASlist); + mutex_unlock(&ASmutex); +} +EXPORT_SYMBOL_GPL(ASadd); + +void ASremove(struct kernfs_node *parent) +{ + mutex_lock(&ASmutex); + list_del(&parent->ASnode); + mutex_unlock(&ASmutex); +} +EXPORT_SYMBOL_GPL(ASremove); + +static void AScheck(void) +{ + struct kernfs_node *parent, *tmp; + kernfs_node *kn; + + mutex_lock(&ASmutex); + list_for_each_entry_safe(parent, tmp, &ASlist, ASnode) { + kn = kernfs_find_ns(parent, "power", NULL); + if (!kn) { + printk(KERN_WARNING "Missing power for %s\n", parent->name); + dump_stack(); + list_del_init(&parent->ASnode); + } + } + mutex_unlock(&ASmutex); +} + static bool kernfs_active(struct kernfs_node *kn) { lockdep_assert_held(&kernfs_mutex); @@ -462,6 +502,7 @@ static void kernfs_drain(struct kernfs_n lockdep_assert_held(&kernfs_mutex); WARN_ON_ONCE(kernfs_active(kn)); + AScheck(); mutex_unlock(&kernfs_mutex); if (kernfs_lockdep(kn)) { @@ -482,6 +523,7 @@ static void kernfs_drain(struct kernfs_n kernfs_drain_open_files(kn); mutex_lock(&kernfs_mutex); + AScheck(); } /** @@ -568,6 +610,7 @@ static int kernfs_dop_revalidate(struct kn = kernfs_dentry_node(dentry); mutex_lock(&kernfs_mutex); + AScheck(); /* The kernfs node has been deactivated */ if (!kernfs_active(kn)) @@ -586,9 +629,11 @@ static int kernfs_dop_revalidate(struct kernfs_info(dentry->d_sb)->ns != kn->ns) goto out_bad; + AScheck(); mutex_unlock(&kernfs_mutex); return 1; out_bad: + AScheck(); mutex_unlock(&kernfs_mutex); out_bad_unlocked: return 0; @@ -769,6 +814,7 @@ int kernfs_add_one(struct kernfs_node *k int ret; mutex_lock(&kernfs_mutex); + AScheck(); ret = -EINVAL; has_ns = kernfs_ns_enabled(parent); @@ -800,6 +846,7 @@ int kernfs_add_one(struct kernfs_node *k ps_iattrs->ia_mtime = ps_iattrs->ia_ctime; } + AScheck(); mutex_unlock(&kernfs_mutex); /* @@ -814,6 +861,7 @@ int kernfs_add_one(struct kernfs_node *k return 0; out_unlock: + AScheck(); mutex_unlock(&kernfs_mutex); return ret; } @@ -932,8 +980,10 @@ struct kernfs_node *kernfs_walk_and_get_ struct kernfs_node *kn; mutex_lock(&kernfs_mutex); + AScheck(); kn = kernfs_walk_ns(parent, path, ns); kernfs_get(kn); + AScheck(); mutex_unlock(&kernfs_mutex); return kn; @@ -1080,6 +1130,7 @@ static struct dentry *kernfs_iop_lookup( const void *ns = NULL; mutex_lock(&kernfs_mutex); + AScheck(); if (kernfs_ns_enabled(parent)) ns = kernfs_info(dir->i_sb)->ns; @@ -1102,6 +1153,7 @@ static struct dentry *kernfs_iop_lookup( /* instantiate and hash dentry */ ret = d_splice_alias(inode, dentry); out_unlock: + AScheck(); mutex_unlock(&kernfs_mutex); return ret; } @@ -1258,6 +1310,7 @@ void kernfs_activate(struct kernfs_node struct kernfs_node *pos; mutex_lock(&kernfs_mutex); + AScheck(); pos = NULL; while ((pos = kernfs_next_descendant_post(pos, kn))) { @@ -1271,6 +1324,7 @@ void kernfs_activate(struct kernfs_node pos->flags |= KERNFS_ACTIVATED; } + AScheck(); mutex_unlock(&kernfs_mutex); } @@ -1350,7 +1404,9 @@ static void __kernfs_remove(struct kernf void kernfs_remove(struct kernfs_node *kn) { mutex_lock(&kernfs_mutex); + AScheck(); __kernfs_remove(kn); + AScheck(); mutex_unlock(&kernfs_mutex); } @@ -1439,6 +1495,7 @@ bool kernfs_remove_self(struct kernfs_no bool ret; mutex_lock(&kernfs_mutex); + AScheck(); kernfs_break_active_protection(kn); /* @@ -1466,9 +1523,11 @@ bool kernfs_remove_self(struct kernfs_no atomic_read(&kn->active) == KN_DEACTIVATED_BIAS) break; + AScheck(); mutex_unlock(&kernfs_mutex); schedule(); mutex_lock(&kernfs_mutex); + AScheck(); } finish_wait(waitq, &wait); WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb)); @@ -1481,6 +1540,7 @@ bool kernfs_remove_self(struct kernfs_no */ kernfs_unbreak_active_protection(kn); + AScheck(); mutex_unlock(&kernfs_mutex); return ret; } @@ -1506,11 +1566,13 @@ int kernfs_remove_by_name_ns(struct kern } mutex_lock(&kernfs_mutex); + AScheck(); kn = kernfs_find_ns(parent, name, ns); if (kn) __kernfs_remove(kn); + AScheck(); mutex_unlock(&kernfs_mutex); if (kn) @@ -1538,6 +1600,7 @@ int kernfs_rename_ns(struct kernfs_node return -EINVAL; mutex_lock(&kernfs_mutex); + AScheck(); error = -ENOENT; if (!kernfs_active(kn) || !kernfs_active(new_parent) || @@ -1591,6 +1654,7 @@ int kernfs_rename_ns(struct kernfs_node error = 0; out: + AScheck(); mutex_unlock(&kernfs_mutex); return error; } @@ -1667,6 +1731,7 @@ static int kernfs_fop_readdir(struct fil if (!dir_emit_dots(file, ctx)) return 0; mutex_lock(&kernfs_mutex); + AScheck(); if (kernfs_ns_enabled(parent)) ns = kernfs_info(dentry->d_sb)->ns; @@ -1683,11 +1748,14 @@ static int kernfs_fop_readdir(struct fil file->private_data = pos; kernfs_get(pos); + AScheck(); mutex_unlock(&kernfs_mutex); if (!dir_emit(ctx, name, len, ino, type)) return 0; mutex_lock(&kernfs_mutex); + AScheck(); } + AScheck(); mutex_unlock(&kernfs_mutex); file->private_data = NULL; ctx->pos = INT_MAX; Index: usb-devel/include/linux/kernfs.h =================================================================== --- usb-devel.orig/include/linux/kernfs.h +++ usb-devel/include/linux/kernfs.h @@ -160,6 +160,7 @@ struct kernfs_node { unsigned short flags; umode_t mode; struct kernfs_iattrs *iattr; + struct list_head ASnode; }; /*