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 */ |
23 | int get_gadget_descs(struct vudc *udc) |
24 | { |
25 | struct vrequest *usb_req; |
26 | struct vep *ep0 = to_vep(ep: 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(lock: &udc->lock); |
41 | ret = udc->driver->setup(&(udc->gadget), &req); |
42 | spin_lock(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(entry: &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(ep: &(ep0->ep), req: &(usb_req->req)); |
62 | out: |
63 | return ret; |
64 | } |
65 | |
66 | /* |
67 | * Exposes device descriptor from the gadget driver. |
68 | */ |
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) |
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; |
87 | unlock: |
88 | spin_unlock_irqrestore(lock: &udc->lock, flags); |
89 | return ret; |
90 | } |
91 | static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor)); |
92 | |
93 | static ssize_t usbip_sockfd_store(struct device *dev, |
94 | struct device_attribute *attr, |
95 | const char *in, size_t count) |
96 | { |
97 | struct vudc *udc = (struct vudc *) dev_get_drvdata(dev); |
98 | int rv; |
99 | int sockfd = 0; |
100 | int err; |
101 | struct socket *socket; |
102 | unsigned long flags; |
103 | int ret; |
104 | struct task_struct *tcp_rx = NULL; |
105 | struct task_struct *tcp_tx = NULL; |
106 | |
107 | rv = kstrtoint(s: in, base: 0, res: &sockfd); |
108 | if (rv != 0) |
109 | return -EINVAL; |
110 | |
111 | if (!udc) { |
112 | dev_err(dev, "no device" ); |
113 | return -ENODEV; |
114 | } |
115 | mutex_lock(&udc->ud.sysfs_lock); |
116 | spin_lock_irqsave(&udc->lock, flags); |
117 | /* Don't export what we don't have */ |
118 | if (!udc->driver || !udc->pullup) { |
119 | dev_err(dev, "gadget not bound" ); |
120 | ret = -ENODEV; |
121 | goto unlock; |
122 | } |
123 | |
124 | if (sockfd != -1) { |
125 | if (udc->connected) { |
126 | dev_err(dev, "Device already connected" ); |
127 | ret = -EBUSY; |
128 | goto unlock; |
129 | } |
130 | |
131 | spin_lock(lock: &udc->ud.lock); |
132 | |
133 | if (udc->ud.status != SDEV_ST_AVAILABLE) { |
134 | ret = -EINVAL; |
135 | goto unlock_ud; |
136 | } |
137 | |
138 | socket = sockfd_lookup(fd: sockfd, err: &err); |
139 | if (!socket) { |
140 | dev_err(dev, "failed to lookup sock" ); |
141 | ret = -EINVAL; |
142 | goto unlock_ud; |
143 | } |
144 | |
145 | if (socket->type != SOCK_STREAM) { |
146 | dev_err(dev, "Expecting SOCK_STREAM - found %d" , |
147 | socket->type); |
148 | ret = -EINVAL; |
149 | goto sock_err; |
150 | } |
151 | |
152 | /* unlock and create threads and get tasks */ |
153 | spin_unlock(lock: &udc->ud.lock); |
154 | spin_unlock_irqrestore(lock: &udc->lock, flags); |
155 | |
156 | tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx" ); |
157 | if (IS_ERR(ptr: tcp_rx)) { |
158 | sockfd_put(socket); |
159 | mutex_unlock(lock: &udc->ud.sysfs_lock); |
160 | return -EINVAL; |
161 | } |
162 | tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx" ); |
163 | if (IS_ERR(ptr: tcp_tx)) { |
164 | kthread_stop(k: tcp_rx); |
165 | sockfd_put(socket); |
166 | mutex_unlock(lock: &udc->ud.sysfs_lock); |
167 | return -EINVAL; |
168 | } |
169 | |
170 | /* get task structs now */ |
171 | get_task_struct(t: tcp_rx); |
172 | get_task_struct(t: tcp_tx); |
173 | |
174 | /* lock and update udc->ud state */ |
175 | spin_lock_irqsave(&udc->lock, flags); |
176 | spin_lock(lock: &udc->ud.lock); |
177 | |
178 | udc->ud.tcp_socket = socket; |
179 | udc->ud.tcp_rx = tcp_rx; |
180 | udc->ud.tcp_tx = tcp_tx; |
181 | udc->ud.status = SDEV_ST_USED; |
182 | |
183 | spin_unlock(lock: &udc->ud.lock); |
184 | |
185 | ktime_get_ts64(ts: &udc->start_time); |
186 | v_start_timer(udc); |
187 | udc->connected = 1; |
188 | |
189 | spin_unlock_irqrestore(lock: &udc->lock, flags); |
190 | |
191 | wake_up_process(tsk: udc->ud.tcp_rx); |
192 | wake_up_process(tsk: udc->ud.tcp_tx); |
193 | |
194 | mutex_unlock(lock: &udc->ud.sysfs_lock); |
195 | return count; |
196 | |
197 | } else { |
198 | if (!udc->connected) { |
199 | dev_err(dev, "Device not connected" ); |
200 | ret = -EINVAL; |
201 | goto unlock; |
202 | } |
203 | |
204 | spin_lock(lock: &udc->ud.lock); |
205 | if (udc->ud.status != SDEV_ST_USED) { |
206 | ret = -EINVAL; |
207 | goto unlock_ud; |
208 | } |
209 | spin_unlock(lock: &udc->ud.lock); |
210 | |
211 | usbip_event_add(ud: &udc->ud, VUDC_EVENT_DOWN); |
212 | } |
213 | |
214 | spin_unlock_irqrestore(lock: &udc->lock, flags); |
215 | mutex_unlock(lock: &udc->ud.sysfs_lock); |
216 | |
217 | return count; |
218 | |
219 | sock_err: |
220 | sockfd_put(socket); |
221 | unlock_ud: |
222 | spin_unlock(lock: &udc->ud.lock); |
223 | unlock: |
224 | spin_unlock_irqrestore(lock: &udc->lock, flags); |
225 | mutex_unlock(lock: &udc->ud.sysfs_lock); |
226 | |
227 | return ret; |
228 | } |
229 | static DEVICE_ATTR_WO(usbip_sockfd); |
230 | |
231 | static ssize_t usbip_status_show(struct device *dev, |
232 | struct device_attribute *attr, char *out) |
233 | { |
234 | struct vudc *udc = (struct vudc *) dev_get_drvdata(dev); |
235 | int status; |
236 | |
237 | if (!udc) { |
238 | dev_err(dev, "no device" ); |
239 | return -ENODEV; |
240 | } |
241 | spin_lock_irq(lock: &udc->ud.lock); |
242 | status = udc->ud.status; |
243 | spin_unlock_irq(lock: &udc->ud.lock); |
244 | |
245 | return sysfs_emit(buf: out, fmt: "%d\n" , status); |
246 | } |
247 | static DEVICE_ATTR_RO(usbip_status); |
248 | |
249 | static struct attribute *dev_attrs[] = { |
250 | &dev_attr_usbip_sockfd.attr, |
251 | &dev_attr_usbip_status.attr, |
252 | NULL, |
253 | }; |
254 | |
255 | static struct bin_attribute *dev_bin_attrs[] = { |
256 | &bin_attr_dev_desc, |
257 | NULL, |
258 | }; |
259 | |
260 | static const struct attribute_group vudc_attr_group = { |
261 | .attrs = dev_attrs, |
262 | .bin_attrs = dev_bin_attrs, |
263 | }; |
264 | |
265 | const struct attribute_group *vudc_groups[] = { |
266 | &vudc_attr_group, |
267 | NULL, |
268 | }; |
269 | |