Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[usb:android.c] Add functionfs support to usb gadget. Fixes: NEMO#811 #9

Merged
merged 1 commit into from Aug 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
206 changes: 197 additions & 9 deletions drivers/usb/gadget/android.c
Expand Up @@ -93,6 +93,7 @@
#endif
#include "f_ncm.c"
#include "f_laf.c"
#include "f_fs.c"

MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
Expand Down Expand Up @@ -206,6 +207,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;
Expand All @@ -226,6 +229,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);
Expand Down Expand Up @@ -2088,6 +2092,163 @@ static struct android_usb_function uasp_function = {
.bind_config = uasp_function_bind_config,
};

/* 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,
Expand Down Expand Up @@ -2118,6 +2279,7 @@ static struct android_usb_function *supported_functions[] = {
&audio_source_function,
#endif
&uasp_function,
&ffs_function,
NULL
};

Expand Down Expand Up @@ -2394,9 +2556,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);

Expand Down Expand Up @@ -2438,14 +2603,37 @@ 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);
}
}

/* Free uneeded configurations if exists */
while (curr_conf->next != &dev->configs) {
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/gadget/f_fs.c
Expand Up @@ -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 */
Expand Down