Skip to content
Permalink
Browse files
Add functionfs support to usb gadget
  • Loading branch information
piggz committed Mar 28, 2016
1 parent 5459f77 commit 3131f16e32e509b6b6989beebbbc8fa0ff339844
Showing with 195 additions and 7 deletions.
  1. +194 −7 drivers/usb/gadget/android.c
  2. +1 −0 drivers/usb/gadget/f_fs.c
@@ -94,6 +94,7 @@
#include "f_uac1.c"
#endif
#include "f_ncm.c"
#include "f_fs.c"

MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -207,6 +208,8 @@ struct android_dev {
struct pm_qos_request pm_qos_req_dma;
struct work_struct work;

char ffs_aliases[256];

/* A list of struct android_configuration */
struct list_head configs;
int configs_num;
@@ -235,6 +238,7 @@ struct android_configuration {

struct dload_struct __iomem *diag_dload;
static struct class *android_class;
static struct android_dev *_android_dev;
static struct list_head android_dev_list;
static int android_dev_count;
static int android_bind_config(struct usb_configuration *c);
@@ -2159,6 +2163,162 @@ static struct android_usb_function usbnet_function = {
.ctrlrequest = usbnet_function_ctrlrequest,
};

/* functionfs */
struct functionfs_config {
bool opened;
bool enabled;
struct ffs_data *data;
};

static int functionfs_check_dev_callback(const char *dev_name)
{
return 0;
}

static int ffs_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
if(!_android_dev)
_android_dev = cdev_to_android_dev(cdev);

f->config = kzalloc(sizeof(struct functionfs_config), GFP_KERNEL);
if (!f->config)
return -ENOMEM;

return functionfs_init();
}

static void ffs_function_cleanup(struct android_usb_function *f)
{
functionfs_cleanup();
kfree(f->config);
_android_dev = NULL;
}

static void ffs_function_enable(struct android_usb_function *f)
{
struct android_dev *dev = _android_dev;
struct functionfs_config *config = f->config;

config->enabled = true;

/* Disable the gadget until the function is ready */
if (!config->opened)
android_disable(dev);
}

static void ffs_function_disable(struct android_usb_function *f)
{
struct android_dev *dev = _android_dev;
struct functionfs_config *config = f->config;

config->enabled = false;

/* Balance the disable that was called in closed_callback */
if (!config->opened)
android_enable(dev);
}

static int ffs_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
struct functionfs_config *config = f->config;
return functionfs_bind_config(c->cdev, c, config->data);
}

static ssize_t
ffs_aliases_show(struct device *pdev, struct device_attribute *attr, char *buf)
{
struct android_dev *dev = _android_dev;
int ret;

mutex_lock(&dev->mutex);
ret = sprintf(buf, "%s\n", dev->ffs_aliases);
mutex_unlock(&dev->mutex);

return ret;
}

static ssize_t
ffs_aliases_store(struct device *pdev, struct device_attribute *attr,
const char *buf, size_t size)
{
struct android_dev *dev = _android_dev;
char buff[256];

mutex_lock(&dev->mutex);

if (dev->enabled) {
mutex_unlock(&dev->mutex);
return -EBUSY;
}

strlcpy(buff, buf, sizeof(buff));
strlcpy(dev->ffs_aliases, strim(buff), sizeof(dev->ffs_aliases));

mutex_unlock(&dev->mutex);

return size;
}

static DEVICE_ATTR(aliases, S_IRUGO | S_IWUSR, ffs_aliases_show,
ffs_aliases_store);
static struct device_attribute *ffs_function_attributes[] = {
&dev_attr_aliases,
NULL
};

static struct android_usb_function ffs_function = {
.name = "ffs",
.init = ffs_function_init,
.enable = ffs_function_enable,
.disable = ffs_function_disable,
.cleanup = ffs_function_cleanup,
.bind_config = ffs_function_bind_config,
.attributes = ffs_function_attributes,
};

static int functionfs_ready_callback(struct ffs_data *ffs)
{
struct android_dev *dev = _android_dev;
struct functionfs_config *config = ffs_function.config;
int ret = 0;

mutex_lock(&dev->mutex);

ret = functionfs_bind(ffs, dev->cdev);
if (ret)
goto err;

config->data = ffs;
config->opened = true;

if (config->enabled)
android_enable(dev);

err:
mutex_unlock(&dev->mutex);
return ret;
}

static void functionfs_closed_callback(struct ffs_data *ffs)
{
struct android_dev *dev =_android_dev;
struct functionfs_config *config = ffs_function.config;

mutex_lock(&dev->mutex);

if (config->enabled)
android_disable(dev);

config->opened = false;
config->data = NULL;

functionfs_unbind(ffs);

mutex_unlock(&dev->mutex);
}

static struct android_usb_function *supported_functions[] = {
&mbim_function,
&ecm_qc_function,
@@ -2189,6 +2349,7 @@ static struct android_usb_function *supported_functions[] = {
#endif
&uasp_function,
&usbnet_function,
&ffs_function,
NULL
};

@@ -2465,9 +2626,12 @@ functions_store(struct device *pdev, struct device_attribute *attr,
struct android_configuration *conf;
char *conf_str;
struct android_usb_function_holder *f_holder;
char *name;
char *name = NULL;
char aliases[256], *a;
char buf[256], *b;
int err;
int is_ffs;
int ffs_enabled = 0;

mutex_lock(&dev->mutex);

@@ -2510,12 +2674,35 @@ functions_store(struct device *pdev, struct device_attribute *attr,

while (conf_str) {
name = strsep(&conf_str, ",");
if (name) {
err = android_enable_function(dev, conf, name);
if (err)
pr_err("android_usb: Cannot enable %s",
name);
}
if (!name)
continue;

is_ffs = 0;
strlcpy(aliases, dev->ffs_aliases, sizeof(aliases));
a = aliases;

while (a) {
char *alias = strsep(&a, ",");
if (alias && !strcmp(name, alias)) {
is_ffs = 1;
break;
}
}

if (is_ffs) {
if (ffs_enabled)
continue;
err = android_enable_function(dev, conf, "ffs");
if (err)
pr_err("android_usb: Cannot enable ffs (%d)", err);
else
ffs_enabled = 1;
continue;
}

err = android_enable_function(dev, conf, name);
if (err)
pr_err("android_usb: Cannot enable %s (%d)", name, err);
}
}

@@ -37,6 +37,7 @@
# define ffs_dump_mem(prefix, ptr, len) \
print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
#else
#undef pr_vdebug
# define pr_vdebug(...) do { } while (0)
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
#endif /* VERBOSE_DEBUG */

0 comments on commit 3131f16

Please sign in to comment.