Skip to content

Commit

Permalink
[PATCH] USB: move the endpoint specific sysfs code to it's own file
Browse files Browse the repository at this point in the history
This makes it easier to modify in the future without touching anything else.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Greg Kroah-Hartman committed Jun 21, 2006
1 parent ae0dadc commit 84412f6
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 198 deletions.
3 changes: 2 additions & 1 deletion drivers/usb/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#

usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o devio.o notify.o
config.o file.o buffer.o sysfs.o endpoint.o \
devio.o notify.o

ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
Expand Down
213 changes: 213 additions & 0 deletions drivers/usb/core/endpoint.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*
* drivers/usb/core/endpoint.c
*
* (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
* (C) Copyright 2002,2004 IBM Corp.
* (C) Copyright 2006 Novell Inc.
*
* Endpoint sysfs stuff
*
*/

#include <linux/kernel.h>
#include <linux/usb.h>
#include "usb.h"

/* endpoint stuff */
struct ep_object {
struct usb_endpoint_descriptor *desc;
struct usb_device *udev;
struct kobject kobj;
};
#define to_ep_object(_kobj) \
container_of(_kobj, struct ep_object, kobj)

struct ep_attribute {
struct attribute attr;
ssize_t (*show)(struct usb_device *,
struct usb_endpoint_descriptor *, char *);
};
#define to_ep_attribute(_attr) \
container_of(_attr, struct ep_attribute, attr)

#define EP_ATTR(_name) \
struct ep_attribute ep_##_name = { \
.attr = {.name = #_name, .owner = THIS_MODULE, \
.mode = S_IRUGO}, \
.show = show_ep_##_name}

#define usb_ep_attr(field, format_string) \
static ssize_t show_ep_##field(struct usb_device *udev, \
struct usb_endpoint_descriptor *desc, \
char *buf) \
{ \
return sprintf(buf, format_string, desc->field); \
} \
static EP_ATTR(field);

usb_ep_attr(bLength, "%02x\n")
usb_ep_attr(bEndpointAddress, "%02x\n")
usb_ep_attr(bmAttributes, "%02x\n")
usb_ep_attr(bInterval, "%02x\n")

static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
return sprintf(buf, "%04x\n",
le16_to_cpu(desc->wMaxPacketSize) & 0x07ff);
}
static EP_ATTR(wMaxPacketSize);

static ssize_t show_ep_type(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
char *type = "unknown";

switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_CONTROL:
type = "Control";
break;
case USB_ENDPOINT_XFER_ISOC:
type = "Isoc";
break;
case USB_ENDPOINT_XFER_BULK:
type = "Bulk";
break;
case USB_ENDPOINT_XFER_INT:
type = "Interrupt";
break;
}
return sprintf(buf, "%s\n", type);
}
static EP_ATTR(type);

static ssize_t show_ep_interval(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
char unit;
unsigned interval = 0;
unsigned in;

in = (desc->bEndpointAddress & USB_DIR_IN);

switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_CONTROL:
if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
interval = desc->bInterval;
break;
case USB_ENDPOINT_XFER_ISOC:
interval = 1 << (desc->bInterval - 1);
break;
case USB_ENDPOINT_XFER_BULK:
if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
interval = desc->bInterval;
break;
case USB_ENDPOINT_XFER_INT:
if (udev->speed == USB_SPEED_HIGH)
interval = 1 << (desc->bInterval - 1);
else
interval = desc->bInterval;
break;
}
interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
if (interval % 1000)
unit = 'u';
else {
unit = 'm';
interval /= 1000;
}

return sprintf(buf, "%d%cs\n", interval, unit);
}
static EP_ATTR(interval);

static ssize_t show_ep_direction(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
char *direction;

if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL)
direction = "both";
else if (desc->bEndpointAddress & USB_DIR_IN)
direction = "in";
else
direction = "out";
return sprintf(buf, "%s\n", direction);
}
static EP_ATTR(direction);

static struct attribute *ep_attrs[] = {
&ep_bLength.attr,
&ep_bEndpointAddress.attr,
&ep_bmAttributes.attr,
&ep_bInterval.attr,
&ep_wMaxPacketSize.attr,
&ep_type.attr,
&ep_interval.attr,
&ep_direction.attr,
NULL,
};

static void ep_object_release(struct kobject *kobj)
{
kfree(to_ep_object(kobj));
}

static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct ep_object *ep_obj = to_ep_object(kobj);
struct ep_attribute *ep_attr = to_ep_attribute(attr);

return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf);
}

static struct sysfs_ops ep_object_sysfs_ops = {
.show = ep_object_show,
};

static struct kobj_type ep_object_ktype = {
.release = ep_object_release,
.sysfs_ops = &ep_object_sysfs_ops,
.default_attrs = ep_attrs,
};

void usb_create_ep_files(struct kobject *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
{
struct ep_object *ep_obj;
struct kobject *kobj;

ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL);
if (!ep_obj)
return;

ep_obj->desc = &endpoint->desc;
ep_obj->udev = udev;

kobj = &ep_obj->kobj;
kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress);
kobj->parent = parent;
kobj->ktype = &ep_object_ktype;

/* Don't use kobject_register, because it generates a hotplug event */
kobject_init(kobj);
if (kobject_add(kobj) == 0)
endpoint->kobj = kobj;
else
kobject_put(kobj);
}

void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
{

if (endpoint->kobj) {
kobject_del(endpoint->kobj);
kobject_put(endpoint->kobj);
endpoint->kobj = NULL;
}
}


Loading

0 comments on commit 84412f6

Please sign in to comment.