xref: /linux/drivers/usb/core/endpoint.c (revision d6a093c3bf0e4e073b87022ac34b261979325228)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * drivers/usb/core/endpoint.c
4  *
5  * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
6  * (C) Copyright 2002,2004 IBM Corp.
7  * (C) Copyright 2006 Novell Inc.
8  *
9  * Released under the GPLv2 only.
10  *
11  * Endpoint sysfs stuff
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/spinlock.h>
16 #include <linux/slab.h>
17 #include <linux/sysfs.h>
18 #include <linux/usb.h>
19 #include "usb.h"
20 
21 struct ep_device {
22 	struct usb_endpoint_descriptor *desc;
23 	struct usb_device *udev;
24 	struct device dev;
25 };
26 #define to_ep_device(_dev) \
27 	container_of(_dev, struct ep_device, dev)
28 
29 #define usb_ep_attr(field, format_string)			\
30 static ssize_t field##_show(struct device *dev,			\
31 			       struct device_attribute *attr,	\
32 			       char *buf)			\
33 {								\
34 	struct ep_device *ep = to_ep_device(dev);		\
35 	return sysfs_emit(buf, format_string, ep->desc->field);	\
36 }								\
37 static DEVICE_ATTR_RO(field)
38 
39 usb_ep_attr(bLength, "%02x\n");
40 usb_ep_attr(bEndpointAddress, "%02x\n");
41 usb_ep_attr(bmAttributes, "%02x\n");
42 usb_ep_attr(bInterval, "%02x\n");
43 
44 static ssize_t wMaxPacketSize_show(struct device *dev,
45 				   struct device_attribute *attr, char *buf)
46 {
47 	struct ep_device *ep = to_ep_device(dev);
48 	return sysfs_emit(buf, "%04x\n", usb_endpoint_maxp(ep->desc));
49 }
50 static DEVICE_ATTR_RO(wMaxPacketSize);
51 
52 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
53 			 char *buf)
54 {
55 	struct ep_device *ep = to_ep_device(dev);
56 	char *type = "unknown";
57 
58 	switch (usb_endpoint_type(ep->desc)) {
59 	case USB_ENDPOINT_XFER_CONTROL:
60 		type = "Control";
61 		break;
62 	case USB_ENDPOINT_XFER_ISOC:
63 		type = "Isoc";
64 		break;
65 	case USB_ENDPOINT_XFER_BULK:
66 		type = "Bulk";
67 		break;
68 	case USB_ENDPOINT_XFER_INT:
69 		type = "Interrupt";
70 		break;
71 	}
72 	return sysfs_emit(buf, "%s\n", type);
73 }
74 static DEVICE_ATTR_RO(type);
75 
76 static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
77 			     char *buf)
78 {
79 	struct ep_device *ep = to_ep_device(dev);
80 	unsigned int interval;
81 	char unit;
82 
83 	interval = usb_decode_interval(ep->desc, ep->udev->speed);
84 	if (interval % 1000) {
85 		unit = 'u';
86 	} else {
87 		unit = 'm';
88 		interval /= 1000;
89 	}
90 
91 	return sysfs_emit(buf, "%d%cs\n", interval, unit);
92 }
93 static DEVICE_ATTR_RO(interval);
94 
95 static ssize_t direction_show(struct device *dev, struct device_attribute *attr,
96 			      char *buf)
97 {
98 	struct ep_device *ep = to_ep_device(dev);
99 	char *direction;
100 
101 	if (usb_endpoint_xfer_control(ep->desc))
102 		direction = "both";
103 	else if (usb_endpoint_dir_in(ep->desc))
104 		direction = "in";
105 	else
106 		direction = "out";
107 	return sysfs_emit(buf, "%s\n", direction);
108 }
109 static DEVICE_ATTR_RO(direction);
110 
111 static struct attribute *ep_dev_attrs[] = {
112 	&dev_attr_bLength.attr,
113 	&dev_attr_bEndpointAddress.attr,
114 	&dev_attr_bmAttributes.attr,
115 	&dev_attr_bInterval.attr,
116 	&dev_attr_wMaxPacketSize.attr,
117 	&dev_attr_interval.attr,
118 	&dev_attr_type.attr,
119 	&dev_attr_direction.attr,
120 	NULL,
121 };
122 static const struct attribute_group ep_dev_attr_grp = {
123 	.attrs = ep_dev_attrs,
124 };
125 static const struct attribute_group *ep_dev_groups[] = {
126 	&ep_dev_attr_grp,
127 	NULL
128 };
129 
130 static void ep_device_release(struct device *dev)
131 {
132 	struct ep_device *ep_dev = to_ep_device(dev);
133 
134 	kfree(ep_dev);
135 }
136 
137 const struct device_type usb_ep_device_type = {
138 	.name =		"usb_endpoint",
139 	.release = ep_device_release,
140 };
141 
142 int usb_create_ep_devs(struct device *parent,
143 			struct usb_host_endpoint *endpoint,
144 			struct usb_device *udev)
145 {
146 	struct ep_device *ep_dev;
147 	int retval;
148 
149 	ep_dev = kzalloc_obj(*ep_dev);
150 	if (!ep_dev) {
151 		retval = -ENOMEM;
152 		goto exit;
153 	}
154 
155 	ep_dev->desc = &endpoint->desc;
156 	ep_dev->udev = udev;
157 	ep_dev->dev.groups = ep_dev_groups;
158 	ep_dev->dev.type = &usb_ep_device_type;
159 	ep_dev->dev.parent = parent;
160 	dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
161 
162 	retval = device_register(&ep_dev->dev);
163 	if (retval)
164 		goto error_register;
165 
166 	device_enable_async_suspend(&ep_dev->dev);
167 	endpoint->ep_dev = ep_dev;
168 	return retval;
169 
170 error_register:
171 	put_device(&ep_dev->dev);
172 exit:
173 	return retval;
174 }
175 
176 void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
177 {
178 	struct ep_device *ep_dev = endpoint->ep_dev;
179 
180 	if (ep_dev) {
181 		device_unregister(&ep_dev->dev);
182 		endpoint->ep_dev = NULL;
183 	}
184 }
185