summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2002-07-05 09:27:11 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2002-07-05 09:27:11 -0700
commitdcc9843349a236aad6520a5cb0f2e4fc5cdc356d (patch)
tree353b766eb4591a6f9b931b1ac6e93cf5412effea /drivers/usb/core
parent7970f12d1e175e93a23416a55b87f28356d91188 (diff)
[PATCH] usb driverfs, +misc
This fixes a couple issues I noted when I finally spent some time looking at the first version of driverfs support for usb: - "name" fields (really descriptions) aren't very useful. * for devices, they always said "USB device 0000:0000" --> Now they'll only say that when there's nothing better to be said ... --> ... and it's really device 0000:0000! It was using device descriptor fields before they were fetched from the device. --> Uses product and/or manufacturer strings, which most devices have, much like PCI uses the PCI ID database (when it's compiled in) * for interfaces, it was "figure out some name..." --> Now it combines the strings used in the usb_make_path() call with interface number --> Or in the remote chance a device provides an interface string, that's preferred. --> In general, I think the driver for each interface is best suited to describe it; I modified the hub driver to do so. - "bus_id" field * For hub ports, it was wasting code: we know the port already, no need to search for it. Plus, it used 0-index ids not the 1-index ones matching physical labels on hubs, and other user-visible diagnostics. * For interfaces, it mixed the device address with the interface number ... producing unstable IDs that were moreover rather cryptic. Changed: "if0" now, using the interface ID (not index). * For busses, left "usb_bus" alone ... :) - Adds two files exposing current configuration (for devices) and altsetting (for interfaces). - I was getting a useless diagnostic from the hub driver, now it's less useless (it fully identifies the hub)
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c24
-rw-r--r--drivers/usb/core/usb.c133
2 files changed, 133 insertions, 24 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6138dc4d44a5..ad1422fabdfa 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -490,8 +490,11 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
list_add(&hub->hub_list, &hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
- if (usb_hub_configure(hub, endpoint) >= 0)
+ if (usb_hub_configure(hub, endpoint) >= 0) {
+ strcpy (dev->actconfig->interface[i].dev.name,
+ "Hub/Port Status Changes");
return hub;
+ }
err("hub configuration failed for device at %s", dev->devpath);
@@ -637,7 +640,8 @@ static int usb_hub_port_status(struct usb_device *hub, int port,
if (portsts) {
ret = usb_get_port_status(hub, port + 1, portsts);
if (ret < 0)
- err("%s(%s) failed (err = %d)", __FUNCTION__, hub->devpath, ret);
+ err("%s(%s-%s) failed (err = %d)", __FUNCTION__,
+ hub->bus->bus_name, hub->devpath, ret);
else {
*status = le16_to_cpu(portsts->wPortStatus);
*change = le16_to_cpu(portsts->wPortChange);
@@ -884,19 +888,11 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
info("new USB device %s-%s, assigned address %d",
dev->bus->bus_name, dev->devpath, dev->devnum);
- /* put the device in the global device tree */
+ /* put the device in the global device tree. the hub port
+ * is the "bus_id"; hubs show in hierarchy like bridges
+ */
dev->dev.parent = &dev->parent->dev;
- sprintf (&dev->dev.name[0], "USB device %04x:%04x",
- dev->descriptor.idVendor,
- dev->descriptor.idProduct);
- /* find the number of the port this device is connected to */
- sprintf (&dev->dev.bus_id[0], "unknown_port_%03d", dev->devnum);
- for (i = 0; i < USB_MAXCHILDREN; ++i) {
- if (dev->parent->children[i] == dev) {
- sprintf (&dev->dev.bus_id[0], "%02d", i);
- break;
- }
- }
+ sprintf (&dev->dev.bus_id[0], "%d", port + 1);
/* Run it through the hoops (find a driver, etc) */
if (!usb_new_device(dev))
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 10591d54aebb..5ef9e9f56a5c 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -748,6 +748,46 @@ call_policy (char *verb, struct usb_device *dev)
#endif /* CONFIG_HOTPLUG */
+/* driverfs files */
+
+/* devices have one current configuration, with one
+ * or more interfaces that are used concurrently
+ */
+static ssize_t
+show_config (struct device *dev, char *buf, size_t count, loff_t off)
+{
+ struct usb_device *udev;
+
+ if (off)
+ return 0;
+ udev = list_entry (dev, struct usb_device, dev);
+ return sprintf (buf, "%u\n", udev->actconfig->bConfigurationValue);
+}
+static struct driver_file_entry usb_config_entry = {
+ name: "configuration",
+ mode: S_IRUGO,
+ show: show_config,
+};
+
+/* interfaces have one current setting; alternates
+ * can have different endpoints and class info.
+ */
+static ssize_t
+show_altsetting (struct device *dev, char *buf, size_t count, loff_t off)
+{
+ struct usb_interface *interface;
+
+ if (off)
+ return 0;
+ interface = list_entry (dev, struct usb_interface, dev);
+ return sprintf (buf, "%u\n", interface->altsetting->bAlternateSetting);
+}
+static struct driver_file_entry usb_altsetting_entry = {
+ name: "altsetting",
+ mode: S_IRUGO,
+ show: show_altsetting,
+};
+
/*
* This entrypoint gets called for each new device.
@@ -760,15 +800,35 @@ static void usb_find_drivers(struct usb_device *dev)
unsigned rejected = 0;
unsigned claimed = 0;
+ /* FIXME should get called for each new configuration not just the
+ * first one for a device. switching configs (or altesettings) should
+ * undo driverfs and HCD state for the previous interfaces.
+ */
for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
struct usb_interface *interface = &dev->actconfig->interface[ifnum];
+ struct usb_interface_descriptor *desc = interface->altsetting;
/* register this interface with driverfs */
interface->dev.parent = &dev->dev;
interface->dev.bus = &usb_bus_type;
- sprintf (&interface->dev.bus_id[0], "%03d%03d", dev->devnum,ifnum);
- sprintf (&interface->dev.name[0], "figure out some name...");
+ sprintf (&interface->dev.bus_id[0], "if%d",
+ interface->altsetting->bInterfaceNumber);
+ if (!desc->iInterface
+ || usb_string (dev, desc->iInterface,
+ interface->dev.name,
+ sizeof interface->dev.name) <= 0) {
+ /* typically devices won't bother with interface
+ * descriptions; this is the normal case. an
+ * interface's driver might describe it better.
+ * (also: iInterface is per-altsetting ...)
+ */
+ sprintf (&interface->dev.name[0],
+ "usb-%s-%s interface %d",
+ dev->bus->bus_name, dev->devpath,
+ interface->altsetting->bInterfaceNumber);
+ }
device_register (&interface->dev);
+ device_create_file (&interface->dev, &usb_altsetting_entry);
/* if this interface hasn't already been claimed */
if (!usb_interface_claimed(interface)) {
@@ -1081,10 +1141,6 @@ void usb_connect(struct usb_device *dev)
}
}
-/*
- * These are the actual routines to send
- * and receive control messages.
- */
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally, for usb_new_device()
@@ -1096,6 +1152,64 @@ int usb_set_address(struct usb_device *dev)
}
+/* improve on the default device description, if we can ... and
+ * while we're at it, maybe show the vendor and product strings.
+ */
+static void set_device_description (struct usb_device *dev)
+{
+ char *buf, *here, *end;
+ int mfgr = dev->descriptor.iManufacturer;
+ int prod = dev->descriptor.iProduct;
+
+ /* set default; keep it if there are no strings */
+ sprintf (dev->dev.name, "USB device %04x:%04x",
+ dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ if (!mfgr && !prod)
+ return;
+
+ if (!(buf = kmalloc(256, GFP_KERNEL)))
+ return;
+ here = dev->dev.name;
+ end = here + sizeof dev->dev.name - 2;
+ *end = 0;
+
+ /* much like pci ... describe as either:
+ * - both strings: 'product descr (vendor descr)'
+ * - product only: 'product descr (USB device vvvv:pppp)'
+ * - vendor only: 'USB device vvvv:pppp (vendor descr)'
+ * - neither string: 'USB device vvvv:pppp'
+ */
+ if (prod && usb_string (dev, prod, buf, 256) > 0) {
+ strncpy (here, buf, end - here);
+#ifdef DEBUG
+ printk (KERN_INFO "Product: %s\n", buf);
+#endif
+ } else {
+ buf [0] = 0;
+ prod = -1;
+ }
+ here = strchr (here, 0);
+ if (mfgr && usb_string (dev, mfgr, buf, 256) > 0) {
+ *here++ = ' ';
+ *here++ = '(';
+ strncpy (here, buf, end - here - 1);
+ here = strchr (here, 0);
+ *here++ = ')';
+#ifdef DEBUG
+ printk (KERN_INFO "Manufacturer: %s\n", buf);
+#endif
+ } else {
+ if (prod != -1)
+ snprintf (here, end - here - 1,
+ " (USB device %04x:%04x)",
+ dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ /* both strings unavailable, keep the default */
+ }
+ kfree(buf);
+}
+
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
@@ -1193,11 +1307,9 @@ int usb_new_device(struct usb_device *dev)
dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+ set_device_description (dev);
+
#ifdef DEBUG
- if (dev->descriptor.iManufacturer)
- usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
- if (dev->descriptor.iProduct)
- usb_show_string(dev, "Product", dev->descriptor.iProduct);
if (dev->descriptor.iSerialNumber)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
@@ -1206,6 +1318,7 @@ int usb_new_device(struct usb_device *dev)
err = device_register (&dev->dev);
if (err)
return err;
+ device_create_file (&dev->dev, &usb_config_entry);
/* now that the basic setup is over, add a /proc/bus/usb entry */
usbfs_add_device(dev);