Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/usb/usbip/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  vudc_sysfs.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
 * Copyright (C) 2015-2016 Samsung Electronics
 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
 *               Krzysztof Opasiak <k.opasiak@samsung.com>
 */


#include <linux/device.h>
#include <linux/list.h>
#include <linux/usb/gadget.h>
#include <linux/usb/ch9.h>
#include <linux/sysfs.h>
#include <linux/kthread.h>
#include <linux/byteorder/generic.h>

#include "usbip_common.h"
#include "vudc.h"

#include <net/sock.h>

/* called with udc->lock held */
int get_gadget_descs(struct vudc *udc)
{
 struct vrequest *usb_req;
 struct vep *ep0 = to_vep(udc->gadget.ep0);
 struct usb_device_descriptor *ddesc = &udc->dev_desc;
 struct usb_ctrlrequest req;
 int ret;

 if (!udc->driver || !udc->pullup)
  return -EINVAL;

 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
 req.bRequest = USB_REQ_GET_DESCRIPTOR;
 req.wValue = cpu_to_le16(USB_DT_DEVICE << 8);
 req.wIndex = cpu_to_le16(0);
 req.wLength = cpu_to_le16(sizeof(*ddesc));

 spin_unlock(&udc->lock);
 ret = udc->driver->setup(&(udc->gadget), &req);
 spin_lock(&udc->lock);
 if (ret < 0)
  goto out;

 /* assuming request queue is empty; request is now on top */
 usb_req = list_last_entry(&ep0->req_queue, struct vrequest, req_entry);
 list_del(&usb_req->req_entry);

 if (usb_req->req.length > sizeof(*ddesc)) {
  ret = -EOVERFLOW;
  goto giveback_req;
 }

 memcpy(ddesc, usb_req->req.buf, sizeof(*ddesc));
 udc->desc_cached = 1;
 ret = 0;
giveback_req:
 usb_req->req.status = 0;
 usb_req->req.actual = usb_req->req.length;
 usb_gadget_giveback_request(&(ep0->ep), &(usb_req->req));
out:
 return ret;
}

/*
 * Exposes device descriptor from the gadget driver.
 */

static ssize_t dev_desc_read(struct file *file, struct kobject *kobj,
        const struct bin_attribute *attr, char *out,
        loff_t off, size_t count)
{
 struct device *dev = kobj_to_dev(kobj);
 struct vudc *udc = (struct vudc *)dev_get_drvdata(dev);
 char *desc_ptr = (char *) &udc->dev_desc;
 unsigned long flags;
 int ret;

 spin_lock_irqsave(&udc->lock, flags);
 if (!udc->desc_cached) {
  ret = -ENODEV;
  goto unlock;
 }

 memcpy(out, desc_ptr + off, count);
 ret = count;
unlock:
 spin_unlock_irqrestore(&udc->lock, flags);
 return ret;
}
static const BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));

static ssize_t usbip_sockfd_store(struct device *dev,
      struct device_attribute *attr,
      const char *in, size_t count)
{
 struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
 int rv;
 int sockfd = 0;
 int err;
 struct socket *socket;
 unsigned long flags;
 int ret;
 struct task_struct *tcp_rx = NULL;
 struct task_struct *tcp_tx = NULL;

 rv = kstrtoint(in, 0, &sockfd);
 if (rv != 0)
  return -EINVAL;

 if (!udc) {
  dev_err(dev, "no device");
  return -ENODEV;
 }
 mutex_lock(&udc->ud.sysfs_lock);
 spin_lock_irqsave(&udc->lock, flags);
 /* Don't export what we don't have */
 if (!udc->driver || !udc->pullup) {
  dev_err(dev, "gadget not bound");
  ret = -ENODEV;
  goto unlock;
 }

 if (sockfd != -1) {
  if (udc->connected) {
   dev_err(dev, "Device already connected");
   ret = -EBUSY;
   goto unlock;
  }

  spin_lock(&udc->ud.lock);

  if (udc->ud.status != SDEV_ST_AVAILABLE) {
   ret = -EINVAL;
   goto unlock_ud;
  }

  socket = sockfd_lookup(sockfd, &err);
  if (!socket) {
   dev_err(dev, "failed to lookup sock");
   ret = -EINVAL;
   goto unlock_ud;
  }

  if (socket->type != SOCK_STREAM) {
   dev_err(dev, "Expecting SOCK_STREAM - found %d",
    socket->type);
   ret = -EINVAL;
   goto sock_err;
  }

  /* unlock and create threads and get tasks */
  spin_unlock(&udc->ud.lock);
  spin_unlock_irqrestore(&udc->lock, flags);

  tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx");
  if (IS_ERR(tcp_rx)) {
   sockfd_put(socket);
   mutex_unlock(&udc->ud.sysfs_lock);
   return -EINVAL;
  }
  tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx");
  if (IS_ERR(tcp_tx)) {
   kthread_stop(tcp_rx);
   sockfd_put(socket);
   mutex_unlock(&udc->ud.sysfs_lock);
   return -EINVAL;
  }

  /* get task structs now */
  get_task_struct(tcp_rx);
  get_task_struct(tcp_tx);

  /* lock and update udc->ud state */
  spin_lock_irqsave(&udc->lock, flags);
  spin_lock(&udc->ud.lock);

  udc->ud.tcp_socket = socket;
  udc->ud.tcp_rx = tcp_rx;
  udc->ud.tcp_tx = tcp_tx;
  udc->ud.status = SDEV_ST_USED;

  spin_unlock(&udc->ud.lock);

  ktime_get_ts64(&udc->start_time);
  v_start_timer(udc);
  udc->connected = 1;

  spin_unlock_irqrestore(&udc->lock, flags);

  wake_up_process(udc->ud.tcp_rx);
  wake_up_process(udc->ud.tcp_tx);

  mutex_unlock(&udc->ud.sysfs_lock);
  return count;

 } else {
  if (!udc->connected) {
   dev_err(dev, "Device not connected");
   ret = -EINVAL;
   goto unlock;
  }

  spin_lock(&udc->ud.lock);
  if (udc->ud.status != SDEV_ST_USED) {
   ret = -EINVAL;
   goto unlock_ud;
  }
  spin_unlock(&udc->ud.lock);

  usbip_event_add(&udc->ud, VUDC_EVENT_DOWN);
 }

 spin_unlock_irqrestore(&udc->lock, flags);
 mutex_unlock(&udc->ud.sysfs_lock);

 return count;

sock_err:
 sockfd_put(socket);
unlock_ud:
 spin_unlock(&udc->ud.lock);
unlock:
 spin_unlock_irqrestore(&udc->lock, flags);
 mutex_unlock(&udc->ud.sysfs_lock);

 return ret;
}
static DEVICE_ATTR_WO(usbip_sockfd);

static ssize_t usbip_status_show(struct device *dev,
          struct device_attribute *attr, char *out)
{
 struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
 int status;

 if (!udc) {
  dev_err(dev, "no device");
  return -ENODEV;
 }
 spin_lock_irq(&udc->ud.lock);
 status = udc->ud.status;
 spin_unlock_irq(&udc->ud.lock);

 return sysfs_emit(out, "%d\n", status);
}
static DEVICE_ATTR_RO(usbip_status);

static struct attribute *dev_attrs[] = {
 &dev_attr_usbip_sockfd.attr,
 &dev_attr_usbip_status.attr,
 NULL,
};

static const struct bin_attribute *const dev_bin_attrs[] = {
 &bin_attr_dev_desc,
 NULL,
};

static const struct attribute_group vudc_attr_group = {
 .attrs = dev_attrs,
 .bin_attrs = dev_bin_attrs,
};

const struct attribute_group *vudc_groups[] = {
 &vudc_attr_group,
 NULL,
};

Messung V0.5
C=96 H=93 G=94

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.