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