]>
Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0+ |
ea6873a4 IK |
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> | |
ea6873a4 IK |
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 */ | |
23 | int 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 | ||
7c348f1c | 31 | if (!udc->driver || !udc->pullup) |
ea6873a4 IK |
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; | |
58 | giveback_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)); | |
62 | out: | |
63 | return ret; | |
64 | } | |
65 | ||
66 | /* | |
67 | * Exposes device descriptor from the gadget driver. | |
68 | */ | |
2a7a10b8 IK |
69 | static 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) | |
ea6873a4 | 72 | { |
2a7a10b8 | 73 | struct device *dev = kobj_to_dev(kobj); |
ea6873a4 | 74 | struct vudc *udc = (struct vudc *)dev_get_drvdata(dev); |
2a7a10b8 | 75 | char *desc_ptr = (char *) &udc->dev_desc; |
ea6873a4 IK |
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 | ||
2a7a10b8 IK |
85 | memcpy(out, desc_ptr + off, count); |
86 | ret = count; | |
ea6873a4 IK |
87 | unlock: |
88 | spin_unlock_irqrestore(&udc->lock, flags); | |
89 | return ret; | |
90 | } | |
2a7a10b8 | 91 | static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor)); |
ea6873a4 | 92 | |
ca35910a | 93 | static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *attr, |
ea6873a4 IK |
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 | spin_lock_irqsave(&udc->lock, flags); | |
109 | /* Don't export what we don't have */ | |
110 | if (!udc || !udc->driver || !udc->pullup) { | |
111 | dev_err(dev, "no device or gadget not bound"); | |
112 | ret = -ENODEV; | |
113 | goto unlock; | |
114 | } | |
115 | ||
116 | if (sockfd != -1) { | |
117 | if (udc->connected) { | |
118 | dev_err(dev, "Device already connected"); | |
119 | ret = -EBUSY; | |
120 | goto unlock; | |
121 | } | |
122 | ||
123 | spin_lock_irq(&udc->ud.lock); | |
124 | ||
125 | if (udc->ud.status != SDEV_ST_AVAILABLE) { | |
126 | ret = -EINVAL; | |
127 | goto unlock_ud; | |
128 | } | |
129 | ||
130 | socket = sockfd_lookup(sockfd, &err); | |
131 | if (!socket) { | |
132 | dev_err(dev, "failed to lookup sock"); | |
133 | ret = -EINVAL; | |
134 | goto unlock_ud; | |
135 | } | |
136 | ||
137 | udc->ud.tcp_socket = socket; | |
138 | ||
139 | spin_unlock_irq(&udc->ud.lock); | |
140 | spin_unlock_irqrestore(&udc->lock, flags); | |
141 | ||
142 | udc->ud.tcp_rx = kthread_get_run(&v_rx_loop, | |
143 | &udc->ud, "vudc_rx"); | |
144 | udc->ud.tcp_tx = kthread_get_run(&v_tx_loop, | |
145 | &udc->ud, "vudc_tx"); | |
146 | ||
147 | spin_lock_irqsave(&udc->lock, flags); | |
148 | spin_lock_irq(&udc->ud.lock); | |
149 | udc->ud.status = SDEV_ST_USED; | |
150 | spin_unlock_irq(&udc->ud.lock); | |
151 | ||
6c51441c | 152 | ktime_get_ts64(&udc->start_time); |
ea6873a4 IK |
153 | v_start_timer(udc); |
154 | udc->connected = 1; | |
155 | } else { | |
156 | if (!udc->connected) { | |
157 | dev_err(dev, "Device not connected"); | |
158 | ret = -EINVAL; | |
159 | goto unlock; | |
160 | } | |
161 | ||
162 | spin_lock_irq(&udc->ud.lock); | |
163 | if (udc->ud.status != SDEV_ST_USED) { | |
164 | ret = -EINVAL; | |
165 | goto unlock_ud; | |
166 | } | |
167 | spin_unlock_irq(&udc->ud.lock); | |
168 | ||
169 | usbip_event_add(&udc->ud, VUDC_EVENT_DOWN); | |
170 | } | |
171 | ||
172 | spin_unlock_irqrestore(&udc->lock, flags); | |
173 | ||
174 | return count; | |
175 | ||
176 | unlock_ud: | |
177 | spin_unlock_irq(&udc->ud.lock); | |
178 | unlock: | |
179 | spin_unlock_irqrestore(&udc->lock, flags); | |
180 | ||
181 | return ret; | |
182 | } | |
ca35910a | 183 | static DEVICE_ATTR_WO(usbip_sockfd); |
ea6873a4 IK |
184 | |
185 | static ssize_t usbip_status_show(struct device *dev, | |
186 | struct device_attribute *attr, char *out) | |
187 | { | |
188 | struct vudc *udc = (struct vudc *) dev_get_drvdata(dev); | |
189 | int status; | |
190 | ||
191 | if (!udc) { | |
442ee366 | 192 | dev_err(dev, "no device"); |
ea6873a4 IK |
193 | return -ENODEV; |
194 | } | |
195 | spin_lock_irq(&udc->ud.lock); | |
196 | status = udc->ud.status; | |
197 | spin_unlock_irq(&udc->ud.lock); | |
198 | ||
199 | return snprintf(out, PAGE_SIZE, "%d\n", status); | |
200 | } | |
201 | static DEVICE_ATTR_RO(usbip_status); | |
202 | ||
203 | static struct attribute *dev_attrs[] = { | |
ea6873a4 IK |
204 | &dev_attr_usbip_sockfd.attr, |
205 | &dev_attr_usbip_status.attr, | |
206 | NULL, | |
207 | }; | |
208 | ||
2a7a10b8 IK |
209 | static struct bin_attribute *dev_bin_attrs[] = { |
210 | &bin_attr_dev_desc, | |
211 | NULL, | |
212 | }; | |
213 | ||
ea6873a4 IK |
214 | const struct attribute_group vudc_attr_group = { |
215 | .attrs = dev_attrs, | |
2a7a10b8 | 216 | .bin_attrs = dev_bin_attrs, |
ea6873a4 | 217 | }; |