Commit 3aeea3c5 authored by Andrzej Pietrasiewicz's avatar Andrzej Pietrasiewicz Committed by Felipe Balbi

usb: gadget: f_uac2: add configfs support

Add support for using f_uac2 function as a component of a gadget
composed with configfs.
Tested-by: default avatarSebastian Reimers <sebastian.reimers@googlemail.com>
Signed-off-by: default avatarAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 065a107c
What: /config/usb-gadget/gadget/functions/uac2.name
Date: Sep 2014
KernelVersion: 3.18
Description:
The attributes:
c_chmask - capture channel mask
c_srate - capture sampling rate
c_ssize - capture sample size (bytes)
p_chmask - playback channel mask
p_srate - playback sampling rate
p_ssize - playback sample size (bytes)
...@@ -1330,6 +1330,93 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) ...@@ -1330,6 +1330,93 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr)
return value; return value;
} }
static inline struct f_uac2_opts *to_f_uac2_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_uac2_opts,
func_inst.group);
}
CONFIGFS_ATTR_STRUCT(f_uac2_opts);
CONFIGFS_ATTR_OPS(f_uac2_opts);
static void f_uac2_attr_release(struct config_item *item)
{
struct f_uac2_opts *opts = to_f_uac2_opts(item);
usb_put_function_instance(&opts->func_inst);
}
static struct configfs_item_operations f_uac2_item_ops = {
.release = f_uac2_attr_release,
.show_attribute = f_uac2_opts_attr_show,
.store_attribute = f_uac2_opts_attr_store,
};
#define UAC2_ATTRIBUTE(name) \
static ssize_t f_uac2_opts_##name##_show(struct f_uac2_opts *opts, \
char *page) \
{ \
int result; \
\
mutex_lock(&opts->lock); \
result = sprintf(page, "%u\n", opts->name); \
mutex_unlock(&opts->lock); \
\
return result; \
} \
\
static ssize_t f_uac2_opts_##name##_store(struct f_uac2_opts *opts, \
const char *page, size_t len) \
{ \
int ret; \
u32 num; \
\
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
ret = -EBUSY; \
goto end; \
} \
\
ret = kstrtou32(page, 0, &num); \
if (ret) \
goto end; \
\
opts->name = num; \
ret = len; \
\
end: \
mutex_unlock(&opts->lock); \
return ret; \
} \
\
static struct f_uac2_opts_attribute f_uac2_opts_##name = \
__CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
f_uac2_opts_##name##_show, \
f_uac2_opts_##name##_store)
UAC2_ATTRIBUTE(p_chmask);
UAC2_ATTRIBUTE(p_srate);
UAC2_ATTRIBUTE(p_ssize);
UAC2_ATTRIBUTE(c_chmask);
UAC2_ATTRIBUTE(c_srate);
UAC2_ATTRIBUTE(c_ssize);
static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_p_chmask.attr,
&f_uac2_opts_p_srate.attr,
&f_uac2_opts_p_ssize.attr,
&f_uac2_opts_c_chmask.attr,
&f_uac2_opts_c_srate.attr,
&f_uac2_opts_c_ssize.attr,
NULL,
};
static struct config_item_type f_uac2_func_type = {
.ct_item_ops = &f_uac2_item_ops,
.ct_attrs = f_uac2_attrs,
.ct_owner = THIS_MODULE,
};
static void afunc_free_inst(struct usb_function_instance *f) static void afunc_free_inst(struct usb_function_instance *f)
{ {
struct f_uac2_opts *opts; struct f_uac2_opts *opts;
...@@ -1346,17 +1433,32 @@ static struct usb_function_instance *afunc_alloc_inst(void) ...@@ -1346,17 +1433,32 @@ static struct usb_function_instance *afunc_alloc_inst(void)
if (!opts) if (!opts)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = afunc_free_inst; opts->func_inst.free_func_inst = afunc_free_inst;
config_group_init_type_name(&opts->func_inst.group, "",
&f_uac2_func_type);
opts->p_chmask = UAC2_DEF_PCHMASK;
opts->p_srate = UAC2_DEF_PSRATE;
opts->p_ssize = UAC2_DEF_PSSIZE;
opts->c_chmask = UAC2_DEF_CCHMASK;
opts->c_srate = UAC2_DEF_CSRATE;
opts->c_ssize = UAC2_DEF_CSSIZE;
return &opts->func_inst; return &opts->func_inst;
} }
static void afunc_free(struct usb_function *f) static void afunc_free(struct usb_function *f)
{ {
struct audio_dev *agdev; struct audio_dev *agdev;
struct f_uac2_opts *opts;
agdev = func_to_agdev(f); agdev = func_to_agdev(f);
opts = container_of(f->fi, struct f_uac2_opts, func_inst);
kfree(agdev); kfree(agdev);
mutex_lock(&opts->lock);
--opts->refcnt;
mutex_unlock(&opts->lock);
} }
static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
...@@ -1389,6 +1491,9 @@ struct usb_function *afunc_alloc(struct usb_function_instance *fi) ...@@ -1389,6 +1491,9 @@ struct usb_function *afunc_alloc(struct usb_function_instance *fi)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_uac2_opts, func_inst); opts = container_of(fi, struct f_uac2_opts, func_inst);
mutex_lock(&opts->lock);
++opts->refcnt;
mutex_unlock(&opts->lock);
agdev->func.name = "uac2_func"; agdev->func.name = "uac2_func";
agdev->func.bind = afunc_bind; agdev->func.bind = afunc_bind;
......
...@@ -34,6 +34,9 @@ struct f_uac2_opts { ...@@ -34,6 +34,9 @@ struct f_uac2_opts {
int c_srate; int c_srate;
int c_ssize; int c_ssize;
bool bound; bool bound;
struct mutex lock;
int refcnt;
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment