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