On Sun, Mar 21, David Brownell wrote:
> Olaf Hering wrote:
> >
> >the mouse will not disappear from /proc/bus/usb/devices, even if I
> >unplug the mouse. Same for the keyspan device, it seems the ports are
> >dead for some reason.
>
> Sounds more like "khubd" is wedged. It's annoying, but that's
> a single-point-of-failure for the entire USB stack. Alt-SysRq-t
> is often informative at such times.
Please revert of improve the attached patch. It is the culprit.
--
USB is for mice, FireWire is for men!
sUse lINUX ag, nÃRNBERG
Return-Path: <[EMAIL PROTECTED]>
Received: from hermes.suse.de (hermes.suse.de [10.0.0.1])
by wotan.suse.de (Postfix) with ESMTP id 7E7BA6D1B
for <[EMAIL PROTECTED]>; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
Received: by hermes.suse.de (Postfix)
id 799D98C50; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
Received: from mandarine.suse.de (mandarine.suse.de [10.10.3.21])
by hermes.suse.de (Postfix) with ESMTP
id 6C4B13F25; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
Received: by mandarine.suse.de (Postfix, from userid 90)
id 4B575468E5; Wed, 17 Mar 2004 06:46:06 +0100 (CET)
To: [EMAIL PROTECTED], [EMAIL PROTECTED]
Subject: Incoming changes to linux-2.5 cset 1.1608.24.34
mandarine.suse.de:/olaf/sources/tree/linux-2.5
Message-Id: <[EMAIL PROTECTED]>
Date: Wed, 17 Mar 2004 06:46:06 +0100 (CET)
From: [EMAIL PROTECTED] (Olaf Hering)
X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on wotan.suse.de
X-Spam-Level:
X-Spam-Status: No, hits=-4.8 required=5.0 tests=AWL,BAYES_00 autolearn=ham
version=2.63
Content-Length: 12130
old status OK
ChangeSet
1.1608.24.34 04/03/03 11:16:57 [EMAIL PROTECTED] +3 -0
[PATCH] USB: Don't add/del interfaces, register/unregister them
On Fri, 27 Feb 2004, Greg KH wrote:
> On Wed, Feb 25, 2004 at 10:05:37AM -0500, Alan Stern wrote:
>
> > Why would anyone want to do this, you ask? Well the USB subsystem does it
> > already. Each USB device can have several configurations, only one of
> > which is active at any time. Corresponding to each configuration is a set
> > of struct devices, and they (together with their embedded kobjects) are
> > allocated and initialized when the USB device is first detected. The
> > struct devices are add()'ed and del()'ed as configurations are activated
> > and deactivated, leading to just the sort of call sequence shown above.
>
> Then we need to fix this.
The driver model does not support repeated device_add(), device_del(),
device_add(), device_del(), ... calls for the same device. But that's
what happens to an interface's embedded struct device when we change
configurations.
Accordingly, this patch changes the device_add()/device_del() calls for
interfaces to device_register()/device_unregister(). When the interface
is unregistered the new code waits for the release method to run, so that
it will be safe to re-register the interface should the former
configuration be reinstated.
Greg, please check this out to make sure I haven't made some dumb mistake.
It works on my system and it fixes a memory leak in the USB system.
include/linux/usb.h
1.96 04/02/27 08:46:19 [EMAIL PROTECTED] +3 -0
USB: Don't add/del interfaces, register/unregister them
drivers/usb/core/message.c
1.42 04/02/27 08:46:19 [EMAIL PROTECTED] +14 -2
USB: Don't add/del interfaces, register/unregister them
drivers/usb/core/config.c
1.17 04/02/27 08:46:19 [EMAIL PROTECTED] +2 -7
USB: Don't add/del interfaces, register/unregister them
.........................................................................
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1608.24.33 -> 1.1608.24.34
# drivers/usb/core/config.c 1.16 -> 1.17
# drivers/usb/core/message.c 1.41 -> 1.42
# include/linux/usb.h 1.95 -> 1.96
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.58.1
# Merge nuts.davemloft.net:/disk1/BK/sparcwork-2.6
# into nuts.davemloft.net:/disk1/BK/sparc-2.6
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.58.2
# [SPARC64]: Update defconfig.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.1
# [PATCH] parport: move exports to where they are defined
#
# Exports moved from parport/init.c to files where functions are
# actually defined.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.2
# [PATCH] parport: use module_init()
#
# Init of low-level drivers (except parport_pc) turned into module_init().
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.3
# [PATCH] parport: sysctl registration
#
# Registration of sysctls turned into module_init().
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.4
# [PATCH] parport: option parsing cleanup
#
# parport_pc options parsing moved to parport_pc.c; parport/init.c is
# gone.
# Warning fixes from -mm added.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.5
# [PATCH] parport: fix probe leaks
#
# parport_pc_probe_port() sanitized; leaks fixed.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.6
# [PATCH] parport: slave port cleanups
#
# references to slave ports of mux added to struct parport.
# parport_daisy_init() doesn't go through parport_announce_port() for mux
# slaves anymore; parport_annouce_port() deals with found ones itself.
# Error handling sanitized, races on unregistration fixed.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.7
# [PATCH] parport: fix parport_unregister_port
#
# parport_unregister_port() is split; parport_remove_port() does
# what parport_unregister_port() used to do sans the final parport_put_port()
# call.
# Callers updated; many of them needed only parport_put_port() (failure
# exit paths where we never had the port announced to drivers).
# Fixed multiple races on port removal by shifting parport_remove_port()
# in front of the code that releases irq/io ports/etc.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.8
# [PATCH] parport: clean up parport_announce_port and friends
#
# parport_announce_port() was always called right after
# parport_proc_register(). Call shifted into parport_announce_port().
# Similar for parport_remove_port() and parport_proc_unregister().
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.9
# [PATCH] parport: keep track of parport_pc ports
#
# parport_pc switched to keeping track of the ports it had
# created; in module_exit it uses the private list instead of messing
# with parport_enumerate().
# Added compile fix for configs that have CONFIG_PARPORT_PC_FIFO turned
# off (from -mm).
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.10
# [PATCH] parport: keep track of parport_sunbpp ports
#
# parport_sunbpp switched to keeping track of the ports it had
# created; in module_exit it uses the private list instead of messing
# with parport_enumerate(). Added check for sbus_ioremap() failure in
# port initialization.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.11
# [PATCH] parport: get rid of parport_enumerate
#
# parport_enumerate() is gone. The last caller was under ifdef that
# never had been true. Function itself is removed, port list handling
# cleaned up (now we can do that, since drivers don't mess with the list
# directly), tons of racy crap removed from parport/share.c
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.59.12
# [PATCH] parport: list cleanups
#
# parport driver list turned into list.h one; parport/share.c code that
# works with that list got cleaned up.
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.1.24
# Merge bk://gkernel.bkbits.net/libata-2.5
# into ppc970.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 04/03/03 [EMAIL PROTECTED] 1.1608.24.34
# [PATCH] USB: Don't add/del interfaces, register/unregister them
#
# On Fri, 27 Feb 2004, Greg KH wrote:
#
# > On Wed, Feb 25, 2004 at 10:05:37AM -0500, Alan Stern wrote:
# >
# > > Why would anyone want to do this, you ask? Well the USB subsystem does it
# > > already. Each USB device can have several configurations, only one of
# > > which is active at any time. Corresponding to each configuration is a set
# > > of struct devices, and they (together with their embedded kobjects) are
# > > allocated and initialized when the USB device is first detected. The
# > > struct devices are add()'ed and del()'ed as configurations are activated
# > > and deactivated, leading to just the sort of call sequence shown above.
# >
# > Then we need to fix this.
#
# The driver model does not support repeated device_add(), device_del(),
# device_add(), device_del(), ... calls for the same device. But that's
# what happens to an interface's embedded struct device when we change
# configurations.
#
# Accordingly, this patch changes the device_add()/device_del() calls for
# interfaces to device_register()/device_unregister(). When the interface
# is unregistered the new code waits for the release method to run, so that
# it will be safe to re-register the interface should the former
# configuration be reinstated.
#
# Greg, please check this out to make sure I haven't made some dumb mistake.
# It works on my system and it fixes a memory leak in the USB system.
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c Wed Mar 17 06:46:04 2004
+++ b/drivers/usb/core/config.c Wed Mar 17 06:46:04 2004
@@ -72,13 +72,10 @@
return buffer - buffer0;
}
-static void usb_release_intf(struct device *dev)
+static void usb_free_intf(struct usb_interface *intf)
{
- struct usb_interface *intf;
int j;
- intf = to_usb_interface(dev);
-
if (intf->altsetting) {
for (j = 0; j < intf->num_altsetting; j++) {
struct usb_host_interface *as = &intf->altsetting[j];
@@ -235,8 +232,6 @@
return -ENOMEM;
}
memset(interface, 0, sizeof(struct usb_interface));
- interface->dev.release = usb_release_intf;
- device_initialize(&interface->dev);
}
/* Go through the descriptors, checking their length and counting the
@@ -374,7 +369,7 @@
struct usb_interface *ifp = cf->interface[i];
if (ifp)
- put_device(&ifp->dev);
+ usb_free_intf(ifp);
}
}
kfree(dev->config);
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c Wed Mar 17 06:46:04 2004
+++ b/drivers/usb/core/message.c Wed Mar 17 06:46:04 2004
@@ -793,6 +793,13 @@
}
}
+static void release_interface(struct device *dev)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+
+ complete(interface->released);
+}
+
/*
* usb_disable_device - Disable all the endpoints for a USB device
* @dev: the device whose endpoints are being disabled
@@ -822,12 +829,16 @@
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *interface;
+ struct completion intf_completion;
/* remove this interface */
interface = dev->actconfig->interface[i];
dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
- device_del(&interface->dev);
+ init_completion (&intf_completion);
+ interface->released = &intf_completion;
+ device_unregister (&interface->dev);
+ wait_for_completion (&intf_completion);
}
dev->actconfig = 0;
if (dev->state == USB_STATE_CONFIGURED)
@@ -1145,6 +1156,7 @@
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.dma_mask = dev->dev.dma_mask;
+ intf->dev.release = release_interface;
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration,
@@ -1153,7 +1165,7 @@
"registering %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration,
desc->bInterfaceNumber);
- device_add (&intf->dev);
+ device_register (&intf->dev);
usb_create_driverfs_intf_files (intf);
}
}
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h Wed Mar 17 06:46:04 2004
+++ b/include/linux/usb.h Wed Mar 17 06:46:04 2004
@@ -89,6 +89,8 @@
* number from the USB core by calling usb_register_dev().
* @dev: driver model's view of this device
* @class_dev: driver model's class view of this device.
+ * @released: wait for the interface to be released when changing
+ * configurations.
*
* USB device drivers attach to interfaces on a physical device. Each
* interface encapsulates a single high level function, such as feeding
@@ -122,6 +124,7 @@
int minor; /* minor number this interface is bound to */
struct device dev; /* interface specific device info */
struct class_device *class_dev;
+ struct completion *released; /* wait for release */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
#define interface_to_usbdev(intf) \
.........................................................................
# vim: syntax=diff