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