aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-06-14 23:17:51 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-14 23:17:51 -0700
commit79054bca4f34ac6630d91a2282b1b3bc500eb963 (patch)
tree3b564867a0fec4459d7ad27730f0569997bed614 /usb
parent1f649e96b8c05b60b68f036fedccd8bed9625477 (diff)
downloadpatches-79054bca4f34ac6630d91a2282b1b3bc500eb963.tar.gz
usb-endpoint-mess is now "real"
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-endpoint-mess.patch376
1 files changed, 376 insertions, 0 deletions
diff --git a/usb/usb-endpoint-mess.patch b/usb/usb-endpoint-mess.patch
new file mode 100644
index 0000000000000..72f3be475f43b
--- /dev/null
+++ b/usb/usb-endpoint-mess.patch
@@ -0,0 +1,376 @@
+From foo@baz Tue Apr 9 12:12:43 2002
+Date: Wed, 14 Jun 2006 12:14:34 -0700
+To: Greg KH <greg@kroah.com>
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Subject: USB: make endpoints real struct devices
+
+This will allow for us to give endpoints a major/minor to create a
+"usbfs2-like" way to access endpoints directly from userspace in an
+easier manner than the current usbfs provides us.
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/endpoint.c | 238 +++++++++++++++++++++++++++-----------------
+ include/linux/usb.h | 4
+ 2 files changed, 151 insertions(+), 91 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/core/endpoint.c
++++ gregkh-2.6/drivers/usb/core/endpoint.c
+@@ -14,13 +14,14 @@
+ #include "usb.h"
+
+ /* endpoint stuff */
+-struct ep_object {
++
++struct ep_device {
+ struct usb_endpoint_descriptor *desc;
+ struct usb_device *udev;
+- struct kobject kobj;
++ struct device dev;
+ };
+-#define to_ep_object(_kobj) \
+- container_of(_kobj, struct ep_object, kobj)
++#define to_ep_device(_dev) \
++ container_of(_dev, struct ep_device, dev)
+
+ struct ep_attribute {
+ struct attribute attr;
+@@ -30,40 +31,37 @@ struct ep_attribute {
+ #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) \
++static ssize_t show_ep_##field(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
+ { \
+- return sprintf(buf, format_string, desc->field); \
++ struct ep_device *ep = to_ep_device(dev); \
++ return sprintf(buf, format_string, ep->desc->field); \
+ } \
+-static EP_ATTR(field);
++static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL);
+
+ 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)
++static ssize_t show_ep_wMaxPacketSize(struct device *dev,
++ struct device_attribute *attr, char *buf)
+ {
++ struct ep_device *ep = to_ep_device(dev);
+ return sprintf(buf, "%04x\n",
+- le16_to_cpu(desc->wMaxPacketSize) & 0x07ff);
++ le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
+ }
+-static EP_ATTR(wMaxPacketSize);
++static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
+
+-static ssize_t show_ep_type(struct usb_device *udev,
+- struct usb_endpoint_descriptor *desc, char *buf)
++static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
++ char *buf)
+ {
++ struct ep_device *ep = to_ep_device(dev);
+ char *type = "unknown";
+
+- switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++ switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ type = "Control";
+ break;
+@@ -79,37 +77,38 @@ static ssize_t show_ep_type(struct usb_d
+ }
+ return sprintf(buf, "%s\n", type);
+ }
+-static EP_ATTR(type);
++static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL);
+
+-static ssize_t show_ep_interval(struct usb_device *udev,
+- struct usb_endpoint_descriptor *desc, char *buf)
++static ssize_t show_ep_interval(struct device *dev,
++ struct device_attribute *attr, char *buf)
+ {
++ struct ep_device *ep = to_ep_device(dev);
+ char unit;
+ unsigned interval = 0;
+ unsigned in;
+
+- in = (desc->bEndpointAddress & USB_DIR_IN);
++ in = (ep->desc->bEndpointAddress & USB_DIR_IN);
+
+- switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++ switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+- if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
+- interval = desc->bInterval;
++ if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
++ interval = ep->desc->bInterval;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+- interval = 1 << (desc->bInterval - 1);
++ interval = 1 << (ep->desc->bInterval - 1);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+- if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
+- interval = desc->bInterval;
++ if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
++ interval = ep->desc->bInterval;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+- if (udev->speed == USB_SPEED_HIGH)
+- interval = 1 << (desc->bInterval - 1);
++ if (ep->udev->speed == USB_SPEED_HIGH)
++ interval = 1 << (ep->desc->bInterval - 1);
+ else
+- interval = desc->bInterval;
++ interval = ep->desc->bInterval;
+ break;
+ }
+- interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
++ interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
+ if (interval % 1000)
+ unit = 'u';
+ else {
+@@ -119,95 +118,154 @@ static ssize_t show_ep_interval(struct u
+
+ return sprintf(buf, "%d%cs\n", interval, unit);
+ }
+-static EP_ATTR(interval);
++static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL);
+
+-static ssize_t show_ep_direction(struct usb_device *udev,
+- struct usb_endpoint_descriptor *desc, char *buf)
++static ssize_t show_ep_direction(struct device *dev,
++ struct device_attribute *attr, char *buf)
+ {
++ struct ep_device *ep = to_ep_device(dev);
+ char *direction;
+
+- if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL)
+ direction = "both";
+- else if (desc->bEndpointAddress & USB_DIR_IN)
++ else if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ direction = "in";
+ else
+ direction = "out";
+ return sprintf(buf, "%s\n", direction);
+ }
+-static EP_ATTR(direction);
++static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL);
+
+-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,
++static struct attribute *ep_dev_attrs[] = {
++ &dev_attr_bLength.attr,
++ &dev_attr_bEndpointAddress.attr,
++ &dev_attr_bmAttributes.attr,
++ &dev_attr_bInterval.attr,
++ &dev_attr_wMaxPacketSize.attr,
++ &dev_attr_interval.attr,
++ &dev_attr_type.attr,
++ &dev_attr_direction.attr,
+ NULL,
+ };
++static struct attribute_group ep_dev_attr_grp = {
++ .attrs = ep_dev_attrs,
++};
+
+-static void ep_object_release(struct kobject *kobj)
++static struct endpoint_class {
++ struct kref kref;
++ struct class *class;
++} *ep_class;
++
++static int init_endpoint_class(void)
+ {
+- kfree(to_ep_object(kobj));
++ 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 = IS_ERR(ep_class->class);
++ kfree(ep_class);
++ ep_class = NULL;
++ goto exit;
++ }
++
++exit:
++ return result;
+ }
+
+-static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr,
+- char *buf)
++static void release_endpoint_class(struct kref *kref)
+ {
+- struct ep_object *ep_obj = to_ep_object(kobj);
+- struct ep_attribute *ep_attr = to_ep_attribute(attr);
++ /* Ok, we cheat as we know we only have on ep_class */
++ class_destroy(ep_class->class);
++ kfree(ep_class);
++ ep_class = NULL;
++}
+
+- return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf);
++static void destroy_endpoint_class(void)
++{
++ if (ep_class)
++ kref_put(&ep_class->kref, release_endpoint_class);
+ }
+
+-static struct sysfs_ops ep_object_sysfs_ops = {
+- .show = ep_object_show,
+-};
++static void ep_device_release(struct device *dev)
++{
++ struct ep_device *ep_dev = to_ep_device(dev);
+
+-static struct kobj_type ep_object_ktype = {
+- .release = ep_object_release,
+- .sysfs_ops = &ep_object_sysfs_ops,
+- .default_attrs = ep_attrs,
+-};
++ dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
++ kfree(ep_dev);
++}
+
+ void usb_create_ep_files(struct device *parent,
+ struct usb_host_endpoint *endpoint,
+ struct usb_device *udev)
+ {
+- struct ep_object *ep_obj;
+- struct kobject *kobj;
++ char name[8];
++ struct ep_device *ep_dev;
++ int minor;
++ int retval;
++
++ retval = init_endpoint_class();
++ if (retval)
++ goto exit;
++
++ ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
++ if (!ep_dev) {
++ retval = -ENOMEM;
++ goto exit;
++ }
+
+- 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;
+- 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);
++ /* fun calculation to determine the minor of this endpoint */
++ minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1);
++
++ ep_dev->desc = &endpoint->desc;
++ ep_dev->udev = udev;
++ ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number...
++ ep_dev->dev.class = ep_class->class;
++ ep_dev->dev.parent = parent;
++ ep_dev->dev.release = ep_device_release;
++ snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x",
++ udev->bus->busnum, udev->devnum,
++ endpoint->desc.bEndpointAddress);
++
++ retval = device_register(&ep_dev->dev);
++ if (retval)
++ goto error;
++ sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
++
++ endpoint->ep_dev = ep_dev;
++
++ /* create the symlink to the old-style "ep_XX" directory */
++ sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
++ sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name);
++
++exit:
++ return;
++error:
++ kfree(ep_dev);
++ goto exit;
+ }
+
+ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
+ {
+
+- if (endpoint->kobj) {
+- kobject_del(endpoint->kobj);
+- kobject_put(endpoint->kobj);
+- endpoint->kobj = NULL;
++ if (endpoint->ep_dev) {
++ sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
++ device_unregister(&endpoint->ep_dev->dev);
++ endpoint->ep_dev = NULL;
+ }
++ destroy_endpoint_class();
+ }
+
+
+--- gregkh-2.6.orig/include/linux/usb.h
++++ gregkh-2.6/include/linux/usb.h
+@@ -41,6 +41,8 @@ struct usb_driver;
+ * Devices may also have class-specific or vendor-specific descriptors.
+ */
+
++struct ep_device;
++
+ /**
+ * struct usb_host_endpoint - host-side endpoint descriptor and queue
+ * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
+@@ -58,7 +60,7 @@ struct usb_host_endpoint {
+ struct usb_endpoint_descriptor desc;
+ struct list_head urb_list;
+ void *hcpriv;
+- struct kobject *kobj; /* For sysfs info */
++ struct ep_device *ep_dev; /* For sysfs info */
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;