Skip to content

Commit

Permalink
usb: convert endpoint devices to bus-less childs of the usb interface
Browse files Browse the repository at this point in the history
The endpoint devices look like simple attribute groups now, and no longer
like devices with a specific subsystem. They will also no longer emit uevents.

It also removes the device node requests for endpoint devices, which are not
implemented for now.

Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Kay Sievers authored and Greg Kroah-Hartman committed Jun 16, 2009
1 parent 9636b68 commit 5512966
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 170 deletions.
25 changes: 9 additions & 16 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,11 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
static int usb_probe_device(struct device *dev)
{
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
struct usb_device *udev;
struct usb_device *udev = to_usb_device(dev);
int error = -ENODEV;

dev_dbg(dev, "%s\n", __func__);

if (!is_usb_device(dev)) /* Sanity check */
return error;

udev = to_usb_device(dev);

/* TODO: Add real matching code */

/* The device should always appear to be in use
Expand Down Expand Up @@ -203,18 +198,13 @@ static void usb_cancel_queued_reset(struct usb_interface *iface)
static int usb_probe_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf;
struct usb_device *udev;
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;

dev_dbg(dev, "%s\n", __func__);

if (is_usb_device(dev)) /* Sanity check */
return error;

intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
intf->needs_binding = 0;

if (udev->authorized == 0) {
Expand Down Expand Up @@ -593,7 +583,7 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
/* TODO: Add real matching code */
return 1;

} else {
} else if (is_usb_interface(dev)) {
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
Expand Down Expand Up @@ -625,11 +615,14 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
/* driver is often null here; dev_dbg() would oops */
pr_debug("usb %s: uevent\n", dev_name(dev));

if (is_usb_device(dev))
if (is_usb_device(dev)) {
usb_dev = to_usb_device(dev);
else {
} else if (is_usb_interface(dev)) {
struct usb_interface *intf = to_usb_interface(dev);

usb_dev = interface_to_usbdev(intf);
} else {
return 0;
}

if (usb_dev->devnum < 0) {
Expand Down
160 changes: 8 additions & 152 deletions drivers/usb/core/endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@
#include <linux/usb.h>
#include "usb.h"

#define MAX_ENDPOINT_MINORS (64*128*32)
static int usb_endpoint_major;
static DEFINE_IDR(endpoint_idr);

struct ep_device {
struct usb_endpoint_descriptor *desc;
struct usb_device *udev;
struct device dev;
int minor;
};
#define to_ep_device(_dev) \
container_of(_dev, struct ep_device, dev)

struct device_type usb_ep_device_type = {
.name = "usb_endpoint",
};

struct ep_attribute {
struct attribute attr;
ssize_t (*show)(struct usb_device *,
Expand Down Expand Up @@ -160,181 +159,43 @@ static struct attribute_group *ep_dev_groups[] = {
NULL
};

static int usb_endpoint_major_init(void)
{
dev_t dev;
int error;

error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS,
"usb_endpoint");
if (error) {
printk(KERN_ERR "Unable to get a dynamic major for "
"usb endpoints.\n");
return error;
}
usb_endpoint_major = MAJOR(dev);

return error;
}

static void usb_endpoint_major_cleanup(void)
{
unregister_chrdev_region(MKDEV(usb_endpoint_major, 0),
MAX_ENDPOINT_MINORS);
}

static int endpoint_get_minor(struct ep_device *ep_dev)
{
static DEFINE_MUTEX(minor_lock);
int retval = -ENOMEM;
int id;

mutex_lock(&minor_lock);
if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0)
goto exit;

retval = idr_get_new(&endpoint_idr, ep_dev, &id);
if (retval < 0) {
if (retval == -EAGAIN)
retval = -ENOMEM;
goto exit;
}
ep_dev->minor = id & MAX_ID_MASK;
exit:
mutex_unlock(&minor_lock);
return retval;
}

static void endpoint_free_minor(struct ep_device *ep_dev)
{
idr_remove(&endpoint_idr, ep_dev->minor);
}

static struct endpoint_class {
struct kref kref;
struct class *class;
} *ep_class;

static int init_endpoint_class(void)
{
int result = 0;

if (ep_class != NULL) {
kref_get(&ep_class->kref);
goto exit;
}

ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL);
if (!ep_class) {
result = -ENOMEM;
goto exit;
}

kref_init(&ep_class->kref);
ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
if (IS_ERR(ep_class->class)) {
result = PTR_ERR(ep_class->class);
goto class_create_error;
}

result = usb_endpoint_major_init();
if (result)
goto endpoint_major_error;

goto exit;

endpoint_major_error:
class_destroy(ep_class->class);
class_create_error:
kfree(ep_class);
ep_class = NULL;
exit:
return result;
}

static void release_endpoint_class(struct kref *kref)
{
/* Ok, we cheat as we know we only have one ep_class */
class_destroy(ep_class->class);
kfree(ep_class);
ep_class = NULL;
usb_endpoint_major_cleanup();
}

static void destroy_endpoint_class(void)
{
if (ep_class)
kref_put(&ep_class->kref, release_endpoint_class);
}

static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);

endpoint_free_minor(ep_dev);
kfree(ep_dev);
}

int usb_create_ep_devs(struct device *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
{
char name[8];
struct ep_device *ep_dev;
int retval;

retval = init_endpoint_class();
if (retval)
goto exit;

ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
if (!ep_dev) {
retval = -ENOMEM;
goto error_alloc;
}

retval = endpoint_get_minor(ep_dev);
if (retval) {
dev_err(parent, "can not allocate minor number for %s\n",
dev_name(&ep_dev->dev));
goto error_register;
goto exit;
}

ep_dev->desc = &endpoint->desc;
ep_dev->udev = udev;
ep_dev->dev.groups = ep_dev_groups;
ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
ep_dev->dev.class = ep_class->class;
ep_dev->dev.type = &usb_ep_device_type;
ep_dev->dev.parent = parent;
ep_dev->dev.release = ep_device_release;
dev_set_name(&ep_dev->dev, "usbdev%d.%d_ep%02x",
udev->bus->busnum, udev->devnum,
endpoint->desc.bEndpointAddress);
dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);

retval = device_register(&ep_dev->dev);
if (retval)
goto error_chrdev;
goto error_register;

/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
if (retval)
goto error_link;
endpoint->ep_dev = ep_dev;
return retval;

error_link:
device_unregister(&ep_dev->dev);
destroy_endpoint_class();
return retval;

error_chrdev:
endpoint_free_minor(ep_dev);

error_register:
kfree(ep_dev);
error_alloc:
destroy_endpoint_class();
exit:
return retval;
}
Expand All @@ -344,12 +205,7 @@ void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
struct ep_device *ep_dev = endpoint->ep_dev;

if (ep_dev) {
char name[8];

sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
device_unregister(&ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
}
}
3 changes: 1 addition & 2 deletions drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ static int __find_interface(struct device *dev, void *data)
struct find_interface_arg *arg = data;
struct usb_interface *intf;

/* can't look at usb devices, only interfaces */
if (is_usb_device(dev))
if (!is_usb_interface(dev))
return 0;

intf = to_usb_interface(dev);
Expand Down
11 changes: 11 additions & 0 deletions drivers/usb/core/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,24 @@ extern struct workqueue_struct *ksuspend_usb_wq;
extern struct bus_type usb_bus_type;
extern struct device_type usb_device_type;
extern struct device_type usb_if_device_type;
extern struct device_type usb_ep_device_type;
extern struct usb_device_driver usb_generic_driver;

static inline int is_usb_device(const struct device *dev)
{
return dev->type == &usb_device_type;
}

static inline int is_usb_interface(const struct device *dev)
{
return dev->type == &usb_if_device_type;
}

static inline int is_usb_endpoint(const struct device *dev)
{
return dev->type == &usb_ep_device_type;
}

/* Do the same for device drivers and interface drivers. */

static inline int is_usb_device_driver(struct device_driver *drv)
Expand Down

0 comments on commit 5512966

Please sign in to comment.