Commit 4f62efe6 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] usbcore: Fix handling of sysfs strings and other attributes

This patch (as592) makes a few small improvements to the way device
strings are handled, and it fixes some bugs in a couple of other sysfs
attribute routines.  (Look at show_configuration_string() to see what I
mean.)
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 16f16d11
...@@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref) ...@@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref)
struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
int j; int j;
for (j = 0; j < intfc->num_altsetting; j++) for (j = 0; j < intfc->num_altsetting; j++) {
kfree(intfc->altsetting[j].endpoint); struct usb_host_interface *alt = &intfc->altsetting[j];
kfree(alt->endpoint);
kfree(alt->string);
}
kfree(intfc); kfree(intfc);
} }
...@@ -420,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev) ...@@ -420,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev)
struct usb_host_config *cf = &dev->config[c]; struct usb_host_config *cf = &dev->config[c];
kfree(cf->string); kfree(cf->string);
cf->string = NULL;
for (i = 0; i < cf->desc.bNumInterfaces; i++) { for (i = 0; i < cf->desc.bNumInterfaces; i++) {
if (cf->intf_cache[i]) if (cf->intf_cache[i])
kref_put(&cf->intf_cache[i]->ref, kref_put(&cf->intf_cache[i]->ref,
......
...@@ -1204,21 +1204,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) ...@@ -1204,21 +1204,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
{} {}
#endif #endif
static void get_string(struct usb_device *udev, char **string, int index)
{
char *buf;
if (!index)
return;
buf = kmalloc(256, GFP_KERNEL);
if (!buf)
return;
if (usb_string(udev, index, buf, 256) > 0)
*string = buf;
else
kfree(buf);
}
#ifdef CONFIG_USB_OTG #ifdef CONFIG_USB_OTG
#include "otg_whitelist.h" #include "otg_whitelist.h"
...@@ -1257,9 +1242,10 @@ int usb_new_device(struct usb_device *udev) ...@@ -1257,9 +1242,10 @@ int usb_new_device(struct usb_device *udev)
} }
/* read the standard strings and cache them if present */ /* read the standard strings and cache them if present */
get_string(udev, &udev->product, udev->descriptor.iProduct); udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer); udev->manufacturer = usb_cache_string(udev,
get_string(udev, &udev->serial, udev->descriptor.iSerialNumber); udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
/* Tell the world! */ /* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
......
...@@ -787,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) ...@@ -787,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
return err; return err;
} }
/**
* usb_cache_string - read a string descriptor and cache it for later use
* @udev: the device whose string descriptor is being read
* @index: the descriptor index
*
* Returns a pointer to a kmalloc'ed buffer containing the descriptor string,
* or NULL if the index is 0 or the string could not be read.
*/
char *usb_cache_string(struct usb_device *udev, int index)
{
char *buf;
char *smallbuf = NULL;
int len;
if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) {
if ((len = usb_string(udev, index, buf, 256)) > 0) {
if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL)
return buf;
memcpy(smallbuf, buf, len);
}
kfree(buf);
}
return smallbuf;
}
/* /*
* usb_get_device_descriptor - (re)reads the device descriptor (usbcore) * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
* @dev: the device whose device descriptor is being updated * @dev: the device whose device descriptor is being updated
...@@ -1008,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) ...@@ -1008,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
dev_dbg (&dev->dev, "unregistering interface %s\n", dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id); interface->dev.bus_id);
usb_remove_sysfs_intf_files(interface); usb_remove_sysfs_intf_files(interface);
kfree(interface->cur_altsetting->string);
interface->cur_altsetting->string = NULL;
device_del (&interface->dev); device_del (&interface->dev);
} }
...@@ -1422,12 +1445,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1422,12 +1445,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
} }
kfree(new_interfaces); kfree(new_interfaces);
if ((cp->desc.iConfiguration) && if (cp->string == NULL)
(cp->string == NULL)) { cp->string = usb_cache_string(dev,
cp->string = kmalloc(256, GFP_KERNEL); cp->desc.iConfiguration);
if (cp->string)
usb_string(dev, cp->desc.iConfiguration, cp->string, 256);
}
/* Now that all the interfaces are set up, register them /* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe() * to trigger binding of drivers to interfaces. probe()
...@@ -1437,13 +1457,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1437,13 +1457,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
*/ */
for (i = 0; i < nintf; ++i) { for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i]; struct usb_interface *intf = cp->interface[i];
struct usb_interface_descriptor *desc; struct usb_host_interface *alt = intf->cur_altsetting;
desc = &intf->altsetting [0].desc;
dev_dbg (&dev->dev, dev_dbg (&dev->dev,
"adding %s (config #%d, interface %d)\n", "adding %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration, intf->dev.bus_id, configuration,
desc->bInterfaceNumber); alt->desc.bInterfaceNumber);
ret = device_add (&intf->dev); ret = device_add (&intf->dev);
if (ret != 0) { if (ret != 0) {
dev_err(&dev->dev, dev_err(&dev->dev,
...@@ -1452,13 +1471,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1452,13 +1471,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
ret); ret);
continue; continue;
} }
if ((intf->cur_altsetting->desc.iInterface) &&
(intf->cur_altsetting->string == NULL)) {
intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL);
if (intf->cur_altsetting->string)
usb_string(dev, intf->cur_altsetting->desc.iInterface,
intf->cur_altsetting->string, 256);
}
usb_create_sysfs_intf_files (intf); usb_create_sysfs_intf_files (intf);
} }
} }
......
...@@ -249,18 +249,12 @@ static ssize_t show_configuration_string(struct device *dev, ...@@ -249,18 +249,12 @@ static ssize_t show_configuration_string(struct device *dev,
{ {
struct usb_device *udev; struct usb_device *udev;
struct usb_host_config *actconfig; struct usb_host_config *actconfig;
int len;
udev = to_usb_device (dev); udev = to_usb_device (dev);
actconfig = udev->actconfig; actconfig = udev->actconfig;
if ((!actconfig) || (!actconfig->string)) if ((!actconfig) || (!actconfig->string))
return 0; return 0;
len = sprintf(buf, actconfig->string, PAGE_SIZE); return sprintf(buf, "%s\n", actconfig->string);
if (len < 0)
return 0;
buf[len] = '\n';
buf[len+1] = 0;
return len+1;
} }
static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
...@@ -291,15 +285,9 @@ static ssize_t show_##name(struct device *dev, \ ...@@ -291,15 +285,9 @@ static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
int len; \
\ \
udev = to_usb_device (dev); \ udev = to_usb_device (dev); \
len = snprintf(buf, 256, "%s", udev->name); \ return sprintf(buf, "%s\n", udev->name); \
if (len < 0) \
return 0; \
buf[len] = '\n'; \
buf[len+1] = 0; \
return len+1; \
} \ } \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
...@@ -449,11 +437,11 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) ...@@ -449,11 +437,11 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
usb_remove_ep_files(&udev->ep0); usb_remove_ep_files(&udev->ep0);
sysfs_remove_group(&dev->kobj, &dev_attr_grp); sysfs_remove_group(&dev->kobj, &dev_attr_grp);
if (udev->descriptor.iManufacturer) if (udev->manufacturer)
device_remove_file(dev, &dev_attr_manufacturer); device_remove_file(dev, &dev_attr_manufacturer);
if (udev->descriptor.iProduct) if (udev->product)
device_remove_file(dev, &dev_attr_product); device_remove_file(dev, &dev_attr_product);
if (udev->descriptor.iSerialNumber) if (udev->serial)
device_remove_file(dev, &dev_attr_serial); device_remove_file(dev, &dev_attr_serial);
device_remove_file (dev, &dev_attr_configuration); device_remove_file (dev, &dev_attr_configuration);
} }
...@@ -535,7 +523,8 @@ static struct attribute_group intf_attr_grp = { ...@@ -535,7 +523,8 @@ static struct attribute_group intf_attr_grp = {
.attrs = intf_attrs, .attrs = intf_attrs,
}; };
static inline void usb_create_intf_ep_files(struct usb_interface *intf) static inline void usb_create_intf_ep_files(struct usb_interface *intf,
struct usb_device *udev)
{ {
struct usb_host_interface *iface_desc; struct usb_host_interface *iface_desc;
int i; int i;
...@@ -543,7 +532,7 @@ static inline void usb_create_intf_ep_files(struct usb_interface *intf) ...@@ -543,7 +532,7 @@ static inline void usb_create_intf_ep_files(struct usb_interface *intf)
iface_desc = intf->cur_altsetting; iface_desc = intf->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i],
interface_to_usbdev(intf)); udev);
} }
static inline void usb_remove_intf_ep_files(struct usb_interface *intf) static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
...@@ -558,11 +547,16 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf) ...@@ -558,11 +547,16 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
void usb_create_sysfs_intf_files (struct usb_interface *intf) void usb_create_sysfs_intf_files (struct usb_interface *intf)
{ {
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
if (intf->cur_altsetting->string) if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
device_create_file(&intf->dev, &dev_attr_interface); device_create_file(&intf->dev, &dev_attr_interface);
usb_create_intf_ep_files(intf); usb_create_intf_ep_files(intf, udev);
} }
void usb_remove_sysfs_intf_files (struct usb_interface *intf) void usb_remove_sysfs_intf_files (struct usb_interface *intf)
......
...@@ -13,6 +13,7 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0); ...@@ -13,6 +13,7 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern int usb_get_device_descriptor(struct usb_device *dev, extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size); unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_lock_all_devices(void); extern void usb_lock_all_devices(void);
......
...@@ -231,7 +231,7 @@ struct usb_interface_cache { ...@@ -231,7 +231,7 @@ struct usb_interface_cache {
struct usb_host_config { struct usb_host_config {
struct usb_config_descriptor desc; struct usb_config_descriptor desc;
char *string; char *string; /* iConfiguration string, if present */
/* the interfaces associated with this configuration, /* the interfaces associated with this configuration,
* stored in no particular order */ * stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES]; struct usb_interface *interface[USB_MAXINTERFACES];
...@@ -351,9 +351,11 @@ struct usb_device { ...@@ -351,9 +351,11 @@ struct usb_device {
int have_langid; /* whether string_langid is valid */ int have_langid; /* whether string_langid is valid */
int string_langid; /* language ID for strings */ int string_langid; /* language ID for strings */
char *product; /* static strings from the device */
char *manufacturer; char *product; /* iProduct string, if present */
char *serial; /* static strings from the device */ char *manufacturer; /* iManufacturer string, if present */
char *serial; /* iSerialNumber string, if present */
struct list_head filelist; struct list_head filelist;
struct class_device *class_dev; struct class_device *class_dev;
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment