linux/drivers/usb/usbip/vudc_sysfs.c
<<
>>
Prefs
   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 */
  23int 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
  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(&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;
  58giveback_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));
  62out:
  63        return ret;
  64}
  65
  66/*
  67 * Exposes device descriptor from the gadget driver.
  68 */
  69static 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;
  87unlock:
  88        spin_unlock_irqrestore(&udc->lock, flags);
  89        return ret;
  90}
  91static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));
  92
  93static 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(in, 0, &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_irq(&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(sockfd, &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_irq(&udc->ud.lock);
 154                spin_unlock_irqrestore(&udc->lock, flags);
 155
 156                tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx");
 157                if (IS_ERR(tcp_rx)) {
 158                        sockfd_put(socket);
 159                        mutex_unlock(&udc->ud.sysfs_lock);
 160                        return -EINVAL;
 161                }
 162                tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx");
 163                if (IS_ERR(tcp_tx)) {
 164                        kthread_stop(tcp_rx);
 165                        sockfd_put(socket);
 166                        mutex_unlock(&udc->ud.sysfs_lock);
 167                        return -EINVAL;
 168                }
 169
 170                /* get task structs now */
 171                get_task_struct(tcp_rx);
 172                get_task_struct(tcp_tx);
 173
 174                /* lock and update udc->ud state */
 175                spin_lock_irqsave(&udc->lock, flags);
 176                spin_lock_irq(&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_irq(&udc->ud.lock);
 184
 185                ktime_get_ts64(&udc->start_time);
 186                v_start_timer(udc);
 187                udc->connected = 1;
 188
 189                spin_unlock_irqrestore(&udc->lock, flags);
 190
 191                wake_up_process(udc->ud.tcp_rx);
 192                wake_up_process(udc->ud.tcp_tx);
 193
 194                mutex_unlock(&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_irq(&udc->ud.lock);
 205                if (udc->ud.status != SDEV_ST_USED) {
 206                        ret = -EINVAL;
 207                        goto unlock_ud;
 208                }
 209                spin_unlock_irq(&udc->ud.lock);
 210
 211                usbip_event_add(&udc->ud, VUDC_EVENT_DOWN);
 212        }
 213
 214        spin_unlock_irqrestore(&udc->lock, flags);
 215        mutex_unlock(&udc->ud.sysfs_lock);
 216
 217        return count;
 218
 219sock_err:
 220        sockfd_put(socket);
 221unlock_ud:
 222        spin_unlock_irq(&udc->ud.lock);
 223unlock:
 224        spin_unlock_irqrestore(&udc->lock, flags);
 225        mutex_unlock(&udc->ud.sysfs_lock);
 226
 227        return ret;
 228}
 229static DEVICE_ATTR_WO(usbip_sockfd);
 230
 231static 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(&udc->ud.lock);
 242        status = udc->ud.status;
 243        spin_unlock_irq(&udc->ud.lock);
 244
 245        return snprintf(out, PAGE_SIZE, "%d\n", status);
 246}
 247static DEVICE_ATTR_RO(usbip_status);
 248
 249static struct attribute *dev_attrs[] = {
 250        &dev_attr_usbip_sockfd.attr,
 251        &dev_attr_usbip_status.attr,
 252        NULL,
 253};
 254
 255static struct bin_attribute *dev_bin_attrs[] = {
 256        &bin_attr_dev_desc,
 257        NULL,
 258};
 259
 260static const struct attribute_group vudc_attr_group = {
 261        .attrs = dev_attrs,
 262        .bin_attrs = dev_bin_attrs,
 263};
 264
 265const struct attribute_group *vudc_groups[] = {
 266        &vudc_attr_group,
 267        NULL,
 268};
 269