/*
  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
  *               2005-2007 Takahiro Hirofuchi
+ * Copyright (C) 2015-2016 Samsung Electronics
+ *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
+ *               Krzysztof Opasiak <k.opasiak@samsung.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 static const char usbip_attach_usage_string[] =
        "usbip attach <args>\n"
        "    -r, --remote=<host>      The machine with exported USB devices\n"
-       "    -b, --busid=<busid>    Busid of the device on <host>\n";
+       "    -b, --busid=<busid>    Busid of the device on <host>\n"
+       "    -d, --device=<devid>    Id of the virtual UDC on <host>\n";
 
 void usbip_attach_usage(void)
 {
        static const struct option opts[] = {
                { "remote", required_argument, NULL, 'r' },
                { "busid",  required_argument, NULL, 'b' },
+               { "device",  required_argument, NULL, 'd' },
                { NULL, 0,  NULL, 0 }
        };
        char *host = NULL;
        int ret = -1;
 
        for (;;) {
-               opt = getopt_long(argc, argv, "r:b:", opts, NULL);
+               opt = getopt_long(argc, argv, "d:r:b:", opts, NULL);
 
                if (opt == -1)
                        break;
                case 'r':
                        host = optarg;
                        break;
+               case 'd':
                case 'b':
                        busid = optarg;
                        break;
 
 /*
  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
  *               2005-2007 Takahiro Hirofuchi
+ * Copyright (C) 2015-2016 Samsung Electronics
+ *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
+ *               Krzysztof Opasiak <k.opasiak@samsung.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <netdb.h>
 #include <unistd.h>
 
+#include <dirent.h>
+
+#include <linux/usb/ch9.h>
+
 #include "usbip_common.h"
 #include "usbip_network.h"
 #include "usbip.h"
                /* Get device information. */
                idVendor = udev_device_get_sysattr_value(dev, "idVendor");
                idProduct = udev_device_get_sysattr_value(dev, "idProduct");
-               bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
-               bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
+               bConfValue = udev_device_get_sysattr_value(dev,
+                               "bConfigurationValue");
+               bNumIntfs = udev_device_get_sysattr_value(dev,
+                               "bNumInterfaces");
                busid = udev_device_get_sysname(dev);
                if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
                        err("problem getting device attributes: %s",
        return ret;
 }
 
+static int list_gadget_devices(bool parsable)
+{
+       int ret = -1;
+       struct udev *udev;
+       struct udev_enumerate *enumerate;
+       struct udev_list_entry *devices, *dev_list_entry;
+       struct udev_device *dev;
+       const char *path;
+       const char *driver;
+
+       const struct usb_device_descriptor *d_desc;
+       const char *descriptors;
+       char product_name[128];
+
+       uint16_t idVendor;
+       char idVendor_buf[8];
+       uint16_t idProduct;
+       char idProduct_buf[8];
+       const char *busid;
+
+       udev = udev_new();
+       enumerate = udev_enumerate_new(udev);
+
+       udev_enumerate_add_match_subsystem(enumerate, "platform");
+
+       udev_enumerate_scan_devices(enumerate);
+       devices = udev_enumerate_get_list_entry(enumerate);
+
+       udev_list_entry_foreach(dev_list_entry, devices) {
+               path = udev_list_entry_get_name(dev_list_entry);
+               dev = udev_device_new_from_syspath(udev, path);
+
+               driver = udev_device_get_driver(dev);
+               /* We only have mechanism to enumerate gadgets bound to vudc */
+               if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME))
+                       continue;
+
+               /* Get device information. */
+               descriptors = udev_device_get_sysattr_value(dev,
+                               VUDC_DEVICE_DESCR_FILE);
+
+               if (!descriptors) {
+                       err("problem getting device attributes: %s",
+                           strerror(errno));
+                       goto err_out;
+               }
+
+               d_desc = (const struct usb_device_descriptor *) descriptors;
+
+               idVendor = le16toh(d_desc->idVendor);
+               sprintf(idVendor_buf, "0x%4x", idVendor);
+               idProduct = le16toh(d_desc->idProduct);
+               sprintf(idProduct_buf, "0x%4x", idVendor);
+               busid = udev_device_get_sysname(dev);
+
+               /* Get product name. */
+               usbip_names_get_product(product_name, sizeof(product_name),
+                                       le16toh(idVendor),
+                                       le16toh(idProduct));
+
+               /* Print information. */
+               print_device(busid, idVendor_buf, idProduct_buf, parsable);
+               print_product_name(product_name, parsable);
+
+               printf("\n");
+
+               udev_device_unref(dev);
+       }
+       ret = 0;
+
+err_out:
+       udev_enumerate_unref(enumerate);
+       udev_unref(udev);
+
+       return ret;
+}
+
 int usbip_list(int argc, char *argv[])
 {
        static const struct option opts[] = {
                { "parsable", no_argument,       NULL, 'p' },
                { "remote",   required_argument, NULL, 'r' },
                { "local",    no_argument,       NULL, 'l' },
+               { "device",    no_argument,       NULL, 'd' },
                { NULL,       0,                 NULL,  0  }
        };
 
                err("failed to open %s", USBIDS_FILE);
 
        for (;;) {
-               opt = getopt_long(argc, argv, "pr:l", opts, NULL);
+               opt = getopt_long(argc, argv, "pr:ld", opts, NULL);
 
                if (opt == -1)
                        break;
                case 'l':
                        ret = list_devices(parsable);
                        goto out;
+               case 'd':
+                       ret = list_gadget_devices(parsable);
+                       goto out;
                default:
                        goto err_out;
                }
 
 
 #include "usbip_host_driver.h"
 #include "usbip_host_common.h"
+#include "usbip_device_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
 #include "list.h"
        "       -6, --ipv6\n"
        "               Bind to IPv6. Default is both.\n"
        "\n"
+       "       -e, --device\n"
+       "               Run in device mode.\n"
+       "               Rather than drive an attached device, create\n"
+       "               a virtual UDC to bind gadgets to.\n"
+       "\n"
        "       -D, --daemon\n"
        "               Run as a daemon process.\n"
        "\n"
                { "daemon",   no_argument,       NULL, 'D' },
                { "daemon",   no_argument,       NULL, 'D' },
                { "debug",    no_argument,       NULL, 'd' },
+               { "device",   no_argument,       NULL, 'e' },
                { "pid",      optional_argument, NULL, 'P' },
                { "tcp-port", required_argument, NULL, 't' },
                { "help",     no_argument,       NULL, 'h' },
        cmd = cmd_standalone_mode;
        driver = &host_driver;
        for (;;) {
-               opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
+               opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL);
 
                if (opt == -1)
                        break;
                case 'v':
                        cmd = cmd_version;
                        break;
+               case 'e':
+                       driver = &device_driver;
+                       break;
                case '?':
                        usbipd_help();
                default: