linux/drivers/usb/usbip/vudc_sysfs.c
<<
>>
Prefs
   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 */
  35int 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;
  70giveback_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));
  74out:
  75        return ret;
  76}
  77
  78/*
  79 * Exposes device descriptor from the gadget driver.
  80 */
  81static 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;
  99unlock:
 100        spin_unlock_irqrestore(&udc->lock, flags);
 101        return ret;
 102}
 103static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));
 104
 105static 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
 188unlock_ud:
 189        spin_unlock_irq(&udc->ud.lock);
 190unlock:
 191        spin_unlock_irqrestore(&udc->lock, flags);
 192
 193        return ret;
 194}
 195static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
 196
 197static 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}
 213static DEVICE_ATTR_RO(usbip_status);
 214
 215static struct attribute *dev_attrs[] = {
 216        &dev_attr_usbip_sockfd.attr,
 217        &dev_attr_usbip_status.attr,
 218        NULL,
 219};
 220
 221static struct bin_attribute *dev_bin_attrs[] = {
 222        &bin_attr_dev_desc,
 223        NULL,
 224};
 225
 226const struct attribute_group vudc_attr_group = {
 227        .attrs = dev_attrs,
 228        .bin_attrs = dev_bin_attrs,
 229};
 230