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