Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
  4 * Copyright (C) 2015-2016 Samsung Electronics
  5 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
  6 *               Krzysztof Opasiak <k.opasiak@samsung.com>
  7 */
  8
  9#include <linux/device.h>
 10#include <linux/list.h>
 11#include <linux/usb/gadget.h>
 12#include <linux/usb/ch9.h>
 13#include <linux/sysfs.h>
 14#include <linux/kthread.h>
 15#include <linux/byteorder/generic.h>
 16
 17#include "usbip_common.h"
 18#include "vudc.h"
 19
 20#include <net/sock.h>
 21
 22/* called with udc->lock held */
 23int get_gadget_descs(struct vudc *udc)
 24{
 25	struct vrequest *usb_req;
 26	struct vep *ep0 = to_vep(udc->gadget.ep0);
 27	struct usb_device_descriptor *ddesc = &udc->dev_desc;
 28	struct usb_ctrlrequest req;
 29	int ret;
 30
 31	if (!udc->driver || !udc->pullup)
 32		return -EINVAL;
 33
 34	req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
 35	req.bRequest = USB_REQ_GET_DESCRIPTOR;
 36	req.wValue = cpu_to_le16(USB_DT_DEVICE << 8);
 37	req.wIndex = cpu_to_le16(0);
 38	req.wLength = cpu_to_le16(sizeof(*ddesc));
 39
 40	spin_unlock(&udc->lock);
 41	ret = udc->driver->setup(&(udc->gadget), &req);
 42	spin_lock(&udc->lock);
 43	if (ret < 0)
 44		goto out;
 45
 46	/* assuming request queue is empty; request is now on top */
 47	usb_req = list_last_entry(&ep0->req_queue, struct vrequest, req_entry);
 48	list_del(&usb_req->req_entry);
 49
 50	if (usb_req->req.length > sizeof(*ddesc)) {
 51		ret = -EOVERFLOW;
 52		goto giveback_req;
 53	}
 54
 55	memcpy(ddesc, usb_req->req.buf, sizeof(*ddesc));
 56	udc->desc_cached = 1;
 57	ret = 0;
 58giveback_req:
 59	usb_req->req.status = 0;
 60	usb_req->req.actual = usb_req->req.length;
 61	usb_gadget_giveback_request(&(ep0->ep), &(usb_req->req));
 62out:
 63	return ret;
 64}
 65
 66/*
 67 * Exposes device descriptor from the gadget driver.
 68 */
 69static ssize_t dev_desc_read(struct file *file, struct kobject *kobj,
 70			     struct bin_attribute *attr, char *out,
 71			     loff_t off, size_t count)
 72{
 73	struct device *dev = kobj_to_dev(kobj);
 74	struct vudc *udc = (struct vudc *)dev_get_drvdata(dev);
 75	char *desc_ptr = (char *) &udc->dev_desc;
 76	unsigned long flags;
 77	int ret;
 78
 79	spin_lock_irqsave(&udc->lock, flags);
 80	if (!udc->desc_cached) {
 81		ret = -ENODEV;
 82		goto unlock;
 83	}
 84
 85	memcpy(out, desc_ptr + off, count);
 86	ret = count;
 87unlock:
 88	spin_unlock_irqrestore(&udc->lock, flags);
 89	return ret;
 90}
 91static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));
 92
 93static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *attr,
 94		     const char *in, size_t count)
 95{
 96	struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
 97	int rv;
 98	int sockfd = 0;
 99	int err;
100	struct socket *socket;
101	unsigned long flags;
102	int ret;
103
104	rv = kstrtoint(in, 0, &sockfd);
105	if (rv != 0)
106		return -EINVAL;
107
108	if (!udc) {
109		dev_err(dev, "no device");
110		return -ENODEV;
111	}
112	spin_lock_irqsave(&udc->lock, flags);
113	/* Don't export what we don't have */
114	if (!udc->driver || !udc->pullup) {
115		dev_err(dev, "gadget not bound");
116		ret = -ENODEV;
117		goto unlock;
118	}
119
120	if (sockfd != -1) {
121		if (udc->connected) {
122			dev_err(dev, "Device already connected");
123			ret = -EBUSY;
124			goto unlock;
125		}
126
127		spin_lock_irq(&udc->ud.lock);
128
129		if (udc->ud.status != SDEV_ST_AVAILABLE) {
130			ret = -EINVAL;
131			goto unlock_ud;
132		}
133
134		socket = sockfd_lookup(sockfd, &err);
135		if (!socket) {
136			dev_err(dev, "failed to lookup sock");
137			ret = -EINVAL;
138			goto unlock_ud;
139		}
140
141		udc->ud.tcp_socket = socket;
142
143		spin_unlock_irq(&udc->ud.lock);
144		spin_unlock_irqrestore(&udc->lock, flags);
145
146		udc->ud.tcp_rx = kthread_get_run(&v_rx_loop,
147						    &udc->ud, "vudc_rx");
148		udc->ud.tcp_tx = kthread_get_run(&v_tx_loop,
149						    &udc->ud, "vudc_tx");
150
151		spin_lock_irqsave(&udc->lock, flags);
152		spin_lock_irq(&udc->ud.lock);
153		udc->ud.status = SDEV_ST_USED;
154		spin_unlock_irq(&udc->ud.lock);
155
156		ktime_get_ts64(&udc->start_time);
157		v_start_timer(udc);
158		udc->connected = 1;
159	} else {
160		if (!udc->connected) {
161			dev_err(dev, "Device not connected");
162			ret = -EINVAL;
163			goto unlock;
164		}
165
166		spin_lock_irq(&udc->ud.lock);
167		if (udc->ud.status != SDEV_ST_USED) {
168			ret = -EINVAL;
169			goto unlock_ud;
170		}
171		spin_unlock_irq(&udc->ud.lock);
172
173		usbip_event_add(&udc->ud, VUDC_EVENT_DOWN);
174	}
175
176	spin_unlock_irqrestore(&udc->lock, flags);
177
178	return count;
179
180unlock_ud:
181	spin_unlock_irq(&udc->ud.lock);
182unlock:
183	spin_unlock_irqrestore(&udc->lock, flags);
184
185	return ret;
186}
187static DEVICE_ATTR_WO(usbip_sockfd);
188
189static ssize_t usbip_status_show(struct device *dev,
190			       struct device_attribute *attr, char *out)
191{
192	struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
193	int status;
194
195	if (!udc) {
196		dev_err(dev, "no device");
197		return -ENODEV;
198	}
199	spin_lock_irq(&udc->ud.lock);
200	status = udc->ud.status;
201	spin_unlock_irq(&udc->ud.lock);
202
203	return snprintf(out, PAGE_SIZE, "%d\n", status);
204}
205static DEVICE_ATTR_RO(usbip_status);
206
207static struct attribute *dev_attrs[] = {
208	&dev_attr_usbip_sockfd.attr,
209	&dev_attr_usbip_status.attr,
210	NULL,
211};
212
213static struct bin_attribute *dev_bin_attrs[] = {
214	&bin_attr_dev_desc,
215	NULL,
216};
217
218static const struct attribute_group vudc_attr_group = {
219	.attrs = dev_attrs,
220	.bin_attrs = dev_bin_attrs,
221};
222
223const struct attribute_group *vudc_groups[] = {
224	&vudc_attr_group,
225	NULL,
226};