[PATCH v2 1/2] usb: gadgetfs: introduce feature control mechanism

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Feature control mechanism allows addition of dynamic features to
gadgetfs.

It provides a user-mode driver the ability to control those
features, by querying the supported and enabled features and
enable/disable features in runtime via ioctl on ep0 fd.

All user operations are done on the entire set of features.
e.g. in order to check a specific feature, a user needs to read
the supported and enabled features, set the desired bitmap on
the read bitmap and call the "set enabled features" ioctl with
the modified bitmap.

Signed-off-by: Binyamin Sharet <bsharet@xxxxxxxxx>
---
 drivers/usb/gadget/legacy/inode.c | 120
+++++++++++++++++++++++++++++++++++++-
 include/uapi/linux/usb/gadgetfs.h |  42 +++++++++++++
 2 files changed, 160 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/legacy/inode.c
b/drivers/usb/gadget/legacy/inode.c
index 16104b5e..ba2f6f4 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -77,6 +77,8 @@ MODULE_LICENSE ("GPL");
 
 static int ep_open(struct inode *, struct file *);
 
+static bool feature_set(struct usb_gadgetfs_features *,
+        enum usb_gadgetfs_feature_bits feature);
 
 /*----------------------------------------------------------------------*/
 
@@ -144,6 +146,8 @@ struct dev_data {
     wait_queue_head_t        wait;
     struct super_block        *sb;
     struct dentry            *dentry;
+    struct usb_gadgetfs_features    enabled_features;
+    struct usb_gadgetfs_features    supported_features;
 
     /* except this scratch i/o buffer for ep0 */
     u8                rbuf [256];
@@ -175,6 +179,9 @@ static struct dev_data *dev_new (void)
     spin_lock_init (&dev->lock);
     INIT_LIST_HEAD (&dev->epfiles);
     init_waitqueue_head (&dev->wait);
+    feature_set(&dev->supported_features,
+            GADGETFS_FEATURE_FEATURES0_SUPPORTED);
+
     return dev;
 }
 
@@ -1235,14 +1242,120 @@ out:
        return mask;
 }
 
+/* feature control */
+
+/* get a features unit, e.g. one u64 bitmap */
+static u64 *
+features_get_unit(struct usb_gadgetfs_features *features,
+        enum usb_gadgetfs_feature_bits feature_bit)
+{
+    if (feature_bit < GADGETFS_FEATURE_RESERVED)
+        if ((feature_bit / 64) == 0)
+            return &features->features0;
+    return NULL;
+}
+
+#ifdef CONFIG_USB_GADGETFS_ALLOW_DELEGATE_DESCRIPTORS
+/* check if a feature is set in a feature bitmap */
+static bool
+feature_is_set(struct usb_gadgetfs_features *features,
+        enum usb_gadgetfs_feature_bits feature_bit)
+{
+    u64 *p_unit;
+    u64 feature_mask;
+
+    p_unit = features_get_unit(features, feature_bit);
+    if (p_unit == NULL)
+        return false;
+    feature_mask = 1 << (feature_bit % 64);
+    return (*p_unit & feature_mask) != 0;
+}
+#endif
+
+#ifdef CONFIG_USB_GADGETFS_ALLOW_DELEGATE_DESCRIPTORS
+/* clear a feature in a feature bitmap */
+static bool
+feature_clear(struct usb_gadgetfs_features *features,
+        enum usb_gadgetfs_feature_bits feature_bit)
+{
+    u64 *p_unit;
+    u64 feature_mask;
+
+    p_unit = features_get_unit(features, feature_bit);
+    if (p_unit == NULL)
+        return false;
+    if (feature_bit == GADGETFS_FEATURE_FEATURES0_SUPPORTED)
+        return false;
+    feature_mask = 1 << (feature_bit % 64);
+    *p_unit &= ~feature_mask;
+    return true;
+}
+#endif
+
+/* set a feature in a feature bitmap */
+static bool
+feature_set(struct usb_gadgetfs_features *features,
+        enum usb_gadgetfs_feature_bits feature_bit)
+{
+    u64 *p_unit;
+    u64 feature_mask;
+
+    p_unit = features_get_unit(features, feature_bit);
+    if (p_unit == NULL)
+        return false;
+    feature_mask = 1 << (feature_bit % 64);
+    *p_unit |= feature_mask;
+    return true;
+}
+
+/* set features based on user input */
+static void
+set_user_features(struct dev_data *dev, struct usb_gadgetfs_features *src)
+{
+    /* only set supported features */
+    src->features0 &= dev->supported_features.features0;
+    /* always set FEATURES0 */
+    src->features0 |= (1 << GADGETFS_FEATURE_FEATURES0_SUPPORTED);
+    dev->enabled_features.features0 = src->features0;
+}
+
 static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
 {
     struct dev_data        *dev = fd->private_data;
     struct usb_gadget    *gadget = dev->gadget;
     long ret = -ENOTTY;
 
-    if (gadget->ops->ioctl)
-        ret = gadget->ops->ioctl (gadget, code, value);
+    switch (code) {
+    case GADGETFS_GET_SUPPORTED_FEATURES:
+        ret = copy_to_user((void *)value, &dev->supported_features,
+                sizeof(dev->supported_features));
+        if (ret != 0)
+            ret = -EFAULT;
+        break;
+    case GADGETFS_GET_ENABLED_FEATURES:
+        ret = copy_to_user((void *)value, &dev->enabled_features,
+                sizeof(dev->enabled_features));
+        if (ret != 0)
+            ret = -EFAULT;
+        break;
+    case GADGETFS_SET_ENABLED_FEATURES:
+        {
+            struct usb_gadgetfs_features user_features;
+
+            ret = copy_from_user(&user_features, (void *)value,
+                    sizeof(user_features));
+            if (ret != 0)
+                ret = -EFAULT;
+            else
+                set_user_features(dev, &user_features);
+        }
+        break;
+    default:
+        /* pass unknown ioctl codes to UDC */
+        if (gadget && gadget->ops && gadget->ops->ioctl)
+            ret = gadget->ops->ioctl(gadget, code, value);
+        break;
+    }
 
     return ret;
 }
@@ -1859,6 +1972,9 @@ dev_open (struct inode *inode, struct file *fd)
         dev->ev_next = 0;
         dev->state = STATE_DEV_OPENED;
         fd->private_data = dev;
+        feature_set(&dev->enabled_features,
+                GADGETFS_FEATURE_FEATURES0_SUPPORTED);
+
         get_dev (dev);
         value = 0;
     }
diff --git a/include/uapi/linux/usb/gadgetfs.h
b/include/uapi/linux/usb/gadgetfs.h
index 0bb12e0..3abe3d3 100644
--- a/include/uapi/linux/usb/gadgetfs.h
+++ b/include/uapi/linux/usb/gadgetfs.h
@@ -85,4 +85,46 @@ struct usb_gadgetfs_event {
  */
 #define    GADGETFS_CLEAR_HALT    _IO('g', 3)
 
+/* GadgetFS features.
+ * each feature is the bit number in the feature bitmap
+ */
+enum usb_gadgetfs_feature_bits {
+    /* indicates that gadgetfs supports features
+     * This should always be on
+     */
+    GADGETFS_FEATURE_FEATURES0_SUPPORTED,
+    /* reserved features.
+     * any new feature should be added BEFORE this one.
+     */
+    GADGETFS_FEATURE_RESERVED
+};
+
+struct usb_gadgetfs_features {
+    uint64_t features0;
+    /* keep 24 bytes reserved for possible future usage */
+    uint8_t RESERVED[24];
+};
+
+/* device ioctls */
+
+/*
+ * Those IOCTLs are called on the control endpoint fd.
+ */
+
+/*
+ * Returns the supported features bitmap
+ */
+#define GADGETFS_GET_SUPPORTED_FEATURES    _IOW('g', 0x10, \
+        struct usb_gadgetfs_features)
+
+/*
+ * Returns enabled features as a bitmap
+ */
+#define GADGETFS_GET_ENABLED_FEATURES    _IOW('g', 0x11, \
+        struct usb_gadgetfs_features)
+
+/* sets the enabled features bitmap */
+#define GADGETFS_SET_ENABLED_FEATURES    _IOR('g', 0x12, \
+        struct usb_gadgetfs_features)
+
 #endif /* __LINUX_USB_GADGETFS_H */
-- 
2.5.0

-- 
Binyamin Sharet,
Cisco, STARE-C

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux