1aa1f3bb5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
284412f62SGreg Kroah-Hartman /*
384412f62SGreg Kroah-Hartman * drivers/usb/core/endpoint.c
484412f62SGreg Kroah-Hartman *
584412f62SGreg Kroah-Hartman * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
684412f62SGreg Kroah-Hartman * (C) Copyright 2002,2004 IBM Corp.
784412f62SGreg Kroah-Hartman * (C) Copyright 2006 Novell Inc.
884412f62SGreg Kroah-Hartman *
9b65fba3dSGreg Kroah-Hartman * Released under the GPLv2 only.
1084412f62SGreg Kroah-Hartman *
11b65fba3dSGreg Kroah-Hartman * Endpoint sysfs stuff
1284412f62SGreg Kroah-Hartman */
1384412f62SGreg Kroah-Hartman
1484412f62SGreg Kroah-Hartman #include <linux/kernel.h>
157e27780fSSarah Bailey #include <linux/spinlock.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
1784412f62SGreg Kroah-Hartman #include <linux/usb.h>
1884412f62SGreg Kroah-Hartman #include "usb.h"
1984412f62SGreg Kroah-Hartman
209bde7497SGreg Kroah-Hartman struct ep_device {
2184412f62SGreg Kroah-Hartman struct usb_endpoint_descriptor *desc;
2284412f62SGreg Kroah-Hartman struct usb_device *udev;
239bde7497SGreg Kroah-Hartman struct device dev;
2484412f62SGreg Kroah-Hartman };
259bde7497SGreg Kroah-Hartman #define to_ep_device(_dev) \
269bde7497SGreg Kroah-Hartman container_of(_dev, struct ep_device, dev)
2784412f62SGreg Kroah-Hartman
2884412f62SGreg Kroah-Hartman struct ep_attribute {
2984412f62SGreg Kroah-Hartman struct attribute attr;
3084412f62SGreg Kroah-Hartman ssize_t (*show)(struct usb_device *,
3184412f62SGreg Kroah-Hartman struct usb_endpoint_descriptor *, char *);
3284412f62SGreg Kroah-Hartman };
3384412f62SGreg Kroah-Hartman #define to_ep_attribute(_attr) \
3484412f62SGreg Kroah-Hartman container_of(_attr, struct ep_attribute, attr)
3584412f62SGreg Kroah-Hartman
3684412f62SGreg Kroah-Hartman #define usb_ep_attr(field, format_string) \
37d03f254fSGreg Kroah-Hartman static ssize_t field##_show(struct device *dev, \
389bde7497SGreg Kroah-Hartman struct device_attribute *attr, \
3984412f62SGreg Kroah-Hartman char *buf) \
4084412f62SGreg Kroah-Hartman { \
419bde7497SGreg Kroah-Hartman struct ep_device *ep = to_ep_device(dev); \
429bde7497SGreg Kroah-Hartman return sprintf(buf, format_string, ep->desc->field); \
4384412f62SGreg Kroah-Hartman } \
44d03f254fSGreg Kroah-Hartman static DEVICE_ATTR_RO(field)
4584412f62SGreg Kroah-Hartman
46d03f254fSGreg Kroah-Hartman usb_ep_attr(bLength, "%02x\n");
47d03f254fSGreg Kroah-Hartman usb_ep_attr(bEndpointAddress, "%02x\n");
48d03f254fSGreg Kroah-Hartman usb_ep_attr(bmAttributes, "%02x\n");
49d03f254fSGreg Kroah-Hartman usb_ep_attr(bInterval, "%02x\n");
5084412f62SGreg Kroah-Hartman
wMaxPacketSize_show(struct device * dev,struct device_attribute * attr,char * buf)51d03f254fSGreg Kroah-Hartman static ssize_t wMaxPacketSize_show(struct device *dev,
529bde7497SGreg Kroah-Hartman struct device_attribute *attr, char *buf)
5384412f62SGreg Kroah-Hartman {
549bde7497SGreg Kroah-Hartman struct ep_device *ep = to_ep_device(dev);
555f9492ffSFelipe Balbi return sprintf(buf, "%04x\n", usb_endpoint_maxp(ep->desc));
5684412f62SGreg Kroah-Hartman }
57d03f254fSGreg Kroah-Hartman static DEVICE_ATTR_RO(wMaxPacketSize);
5884412f62SGreg Kroah-Hartman
type_show(struct device * dev,struct device_attribute * attr,char * buf)59d03f254fSGreg Kroah-Hartman static ssize_t type_show(struct device *dev, struct device_attribute *attr,
609bde7497SGreg Kroah-Hartman char *buf)
6184412f62SGreg Kroah-Hartman {
629bde7497SGreg Kroah-Hartman struct ep_device *ep = to_ep_device(dev);
6384412f62SGreg Kroah-Hartman char *type = "unknown";
6484412f62SGreg Kroah-Hartman
652e0fe709SJulia Lawall switch (usb_endpoint_type(ep->desc)) {
6684412f62SGreg Kroah-Hartman case USB_ENDPOINT_XFER_CONTROL:
6784412f62SGreg Kroah-Hartman type = "Control";
6884412f62SGreg Kroah-Hartman break;
6984412f62SGreg Kroah-Hartman case USB_ENDPOINT_XFER_ISOC:
7084412f62SGreg Kroah-Hartman type = "Isoc";
7184412f62SGreg Kroah-Hartman break;
7284412f62SGreg Kroah-Hartman case USB_ENDPOINT_XFER_BULK:
7384412f62SGreg Kroah-Hartman type = "Bulk";
7484412f62SGreg Kroah-Hartman break;
7584412f62SGreg Kroah-Hartman case USB_ENDPOINT_XFER_INT:
7684412f62SGreg Kroah-Hartman type = "Interrupt";
7784412f62SGreg Kroah-Hartman break;
7884412f62SGreg Kroah-Hartman }
7984412f62SGreg Kroah-Hartman return sprintf(buf, "%s\n", type);
8084412f62SGreg Kroah-Hartman }
81d03f254fSGreg Kroah-Hartman static DEVICE_ATTR_RO(type);
8284412f62SGreg Kroah-Hartman
interval_show(struct device * dev,struct device_attribute * attr,char * buf)83d03f254fSGreg Kroah-Hartman static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
84d03f254fSGreg Kroah-Hartman char *buf)
8584412f62SGreg Kroah-Hartman {
869bde7497SGreg Kroah-Hartman struct ep_device *ep = to_ep_device(dev);
87*fb95c7cfSChunfeng Yun unsigned int interval;
8884412f62SGreg Kroah-Hartman char unit;
8984412f62SGreg Kroah-Hartman
90*fb95c7cfSChunfeng Yun interval = usb_decode_interval(ep->desc, ep->udev->speed);
91*fb95c7cfSChunfeng Yun if (interval % 1000) {
9284412f62SGreg Kroah-Hartman unit = 'u';
93*fb95c7cfSChunfeng Yun } else {
9484412f62SGreg Kroah-Hartman unit = 'm';
9584412f62SGreg Kroah-Hartman interval /= 1000;
9684412f62SGreg Kroah-Hartman }
9784412f62SGreg Kroah-Hartman
9884412f62SGreg Kroah-Hartman return sprintf(buf, "%d%cs\n", interval, unit);
9984412f62SGreg Kroah-Hartman }
100d03f254fSGreg Kroah-Hartman static DEVICE_ATTR_RO(interval);
10184412f62SGreg Kroah-Hartman
direction_show(struct device * dev,struct device_attribute * attr,char * buf)102d03f254fSGreg Kroah-Hartman static ssize_t direction_show(struct device *dev, struct device_attribute *attr,
103d03f254fSGreg Kroah-Hartman char *buf)
10484412f62SGreg Kroah-Hartman {
1059bde7497SGreg Kroah-Hartman struct ep_device *ep = to_ep_device(dev);
10684412f62SGreg Kroah-Hartman char *direction;
10784412f62SGreg Kroah-Hartman
1082e0fe709SJulia Lawall if (usb_endpoint_xfer_control(ep->desc))
10984412f62SGreg Kroah-Hartman direction = "both";
1102e0fe709SJulia Lawall else if (usb_endpoint_dir_in(ep->desc))
11184412f62SGreg Kroah-Hartman direction = "in";
11284412f62SGreg Kroah-Hartman else
11384412f62SGreg Kroah-Hartman direction = "out";
11484412f62SGreg Kroah-Hartman return sprintf(buf, "%s\n", direction);
11584412f62SGreg Kroah-Hartman }
116d03f254fSGreg Kroah-Hartman static DEVICE_ATTR_RO(direction);
11784412f62SGreg Kroah-Hartman
1189bde7497SGreg Kroah-Hartman static struct attribute *ep_dev_attrs[] = {
1199bde7497SGreg Kroah-Hartman &dev_attr_bLength.attr,
1209bde7497SGreg Kroah-Hartman &dev_attr_bEndpointAddress.attr,
1219bde7497SGreg Kroah-Hartman &dev_attr_bmAttributes.attr,
1229bde7497SGreg Kroah-Hartman &dev_attr_bInterval.attr,
1239bde7497SGreg Kroah-Hartman &dev_attr_wMaxPacketSize.attr,
1249bde7497SGreg Kroah-Hartman &dev_attr_interval.attr,
1259bde7497SGreg Kroah-Hartman &dev_attr_type.attr,
1269bde7497SGreg Kroah-Hartman &dev_attr_direction.attr,
12784412f62SGreg Kroah-Hartman NULL,
12884412f62SGreg Kroah-Hartman };
1294154a4f7SRikard Falkeborn static const struct attribute_group ep_dev_attr_grp = {
1309bde7497SGreg Kroah-Hartman .attrs = ep_dev_attrs,
13184412f62SGreg Kroah-Hartman };
132a4dbd674SDavid Brownell static const struct attribute_group *ep_dev_groups[] = {
1332e5f10e4SAlan Stern &ep_dev_attr_grp,
1342e5f10e4SAlan Stern NULL
1352e5f10e4SAlan Stern };
13684412f62SGreg Kroah-Hartman
ep_device_release(struct device * dev)1379bde7497SGreg Kroah-Hartman static void ep_device_release(struct device *dev)
1389bde7497SGreg Kroah-Hartman {
1399bde7497SGreg Kroah-Hartman struct ep_device *ep_dev = to_ep_device(dev);
1409bde7497SGreg Kroah-Hartman
1419bde7497SGreg Kroah-Hartman kfree(ep_dev);
1429bde7497SGreg Kroah-Hartman }
14384412f62SGreg Kroah-Hartman
1442d366846SLan Tianyu struct device_type usb_ep_device_type = {
1452d366846SLan Tianyu .name = "usb_endpoint",
1462d366846SLan Tianyu .release = ep_device_release,
1472d366846SLan Tianyu };
1482d366846SLan Tianyu
usb_create_ep_devs(struct device * parent,struct usb_host_endpoint * endpoint,struct usb_device * udev)1493b23dd6fSAlan Stern int usb_create_ep_devs(struct device *parent,
15084412f62SGreg Kroah-Hartman struct usb_host_endpoint *endpoint,
15184412f62SGreg Kroah-Hartman struct usb_device *udev)
15284412f62SGreg Kroah-Hartman {
1539bde7497SGreg Kroah-Hartman struct ep_device *ep_dev;
1549bde7497SGreg Kroah-Hartman int retval;
15584412f62SGreg Kroah-Hartman
1569bde7497SGreg Kroah-Hartman ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
1579bde7497SGreg Kroah-Hartman if (!ep_dev) {
1589bde7497SGreg Kroah-Hartman retval = -ENOMEM;
15955129666SKay Sievers goto exit;
1607e27780fSSarah Bailey }
1619bde7497SGreg Kroah-Hartman
1629bde7497SGreg Kroah-Hartman ep_dev->desc = &endpoint->desc;
1639bde7497SGreg Kroah-Hartman ep_dev->udev = udev;
1642e5f10e4SAlan Stern ep_dev->dev.groups = ep_dev_groups;
16555129666SKay Sievers ep_dev->dev.type = &usb_ep_device_type;
1669bde7497SGreg Kroah-Hartman ep_dev->dev.parent = parent;
16755129666SKay Sievers dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
1689bde7497SGreg Kroah-Hartman
1699bde7497SGreg Kroah-Hartman retval = device_register(&ep_dev->dev);
1709bde7497SGreg Kroah-Hartman if (retval)
17155129666SKay Sievers goto error_register;
1729bde7497SGreg Kroah-Hartman
17395622712SPeter Chen device_enable_async_suspend(&ep_dev->dev);
174d5477c11SAlan Stern endpoint->ep_dev = ep_dev;
1751b21d5e1SGreg Kroah-Hartman return retval;
1761b21d5e1SGreg Kroah-Hartman
177d5477c11SAlan Stern error_register:
1787b3a766cSRahul Ruikar put_device(&ep_dev->dev);
179d5477c11SAlan Stern exit:
1801b21d5e1SGreg Kroah-Hartman return retval;
18184412f62SGreg Kroah-Hartman }
18284412f62SGreg Kroah-Hartman
usb_remove_ep_devs(struct usb_host_endpoint * endpoint)1833b23dd6fSAlan Stern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
18484412f62SGreg Kroah-Hartman {
1857e27780fSSarah Bailey struct ep_device *ep_dev = endpoint->ep_dev;
18684412f62SGreg Kroah-Hartman
1877e27780fSSarah Bailey if (ep_dev) {
1887e27780fSSarah Bailey device_unregister(&ep_dev->dev);
1899bde7497SGreg Kroah-Hartman endpoint->ep_dev = NULL;
19084412f62SGreg Kroah-Hartman }
191c40fd5eaSAlan Stern }
192