]>
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 | ||
df3334c2 CIK |
108 | if (!udc) { |
109 | dev_err(dev, "no device"); | |
110 | return -ENODEV; | |
111 | } | |
ea6873a4 IK |
112 | spin_lock_irqsave(&udc->lock, flags); |
113 | /* Don't export what we don't have */ | |
df3334c2 CIK |
114 | if (!udc->driver || !udc->pullup) { |
115 | dev_err(dev, "gadget not bound"); | |
ea6873a4 IK |
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 | ||
6c51441c | 156 | ktime_get_ts64(&udc->start_time); |
ea6873a4 IK |
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 | ||
180 | unlock_ud: | |
181 | spin_unlock_irq(&udc->ud.lock); | |
182 | unlock: | |
183 | spin_unlock_irqrestore(&udc->lock, flags); | |
184 | ||
185 | return ret; | |
186 | } | |
ca35910a | 187 | static DEVICE_ATTR_WO(usbip_sockfd); |
ea6873a4 IK |
188 | |
189 | static 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) { | |
442ee366 | 196 | dev_err(dev, "no device"); |
ea6873a4 IK |
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 | } | |
205 | static DEVICE_ATTR_RO(usbip_status); | |
206 | ||
207 | static struct attribute *dev_attrs[] = { | |
ea6873a4 IK |
208 | &dev_attr_usbip_sockfd.attr, |
209 | &dev_attr_usbip_status.attr, | |
210 | NULL, | |
211 | }; | |
212 | ||
2a7a10b8 IK |
213 | static struct bin_attribute *dev_bin_attrs[] = { |
214 | &bin_attr_dev_desc, | |
215 | NULL, | |
216 | }; | |
217 | ||
ea6873a4 IK |
218 | const struct attribute_group vudc_attr_group = { |
219 | .attrs = dev_attrs, | |
2a7a10b8 | 220 | .bin_attrs = dev_bin_attrs, |
ea6873a4 | 221 | }; |