-
这部分的思想是和字符设备驱动是一样的,注册好设备function,然后初始化好结构体,设备与驱动匹配,执行相应文件描述符设置好的回调函数
-
下边是f_fs.c文件中代码大致捋了一下,我觉着这样看调用更直观一些
- `
DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc){
//我们把宏定义化简之后,注册什么的都有了
static struct usb_function_driver ffsusb_func = { //这里定义的是一个usb_function_driver驱动
.name = __stringify(ffs),
.mod = THIS_MODULE,
.alloc_inst = ffs_alloc_inst,
.alloc_func = ffs_alloc,
};
MODULE_ALIAS("usbfunc:"__stringify(ffs));
static int __init ffsmod_init(void)
{
return usb_function_register(&ffsusb_func); //这里主要是把这个uac2usb_func这个usb_function_driver放入func_list链表
}
static void __exit ffsmod_exit(void)
{
usb_function_unregister(&ffsusb_func);
}
module_init(ffsmod_init);
module_exit(ffsmod_init)
}
static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
{
struct ffs_function *func;
ENTER();
func = kzalloc(sizeof(*func), GFP_KERNEL);
if (unlikely(!func))
return ERR_PTR(-ENOMEM);
func->function.name = "Function FS Gadget";
func->function.bind = ffs_func_bind;
func->function.unbind = ffs_func_unbind;
func->function.set_alt = ffs_func_set_alt;
func->function.disable = ffs_func_disable;
func->function.setup = ffs_func_setup;
func->function.req_match = ffs_func_req_match;
func->function.suspend = ffs_func_suspend;
func->function.resume = ffs_func_resume;
func->function.free_func = ffs_free;
return &func->function;
}
/* Devices management *******************************************************/
static LIST_HEAD(ffs_devices);
static struct usb_function_instance *ffs_alloc_inst(void){
ffs_devices
struct f_fs_opts *opts;
struct ffs_dev *dev;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.set_inst_name = ffs_set_inst_name;
opts->func_inst.free_func_inst = ffs_free_inst;
dev = _ffs_alloc_dev(){
/* Driver's main init/cleanup functions */
functionfs_init(){
static struct file_system_type ffs_fs_type = {
.owner = THIS_MODULE,
.name = "functionfs",
.init_fs_context = ffs_fs_init_fs_context,
.parameters = &ffs_fs_fs_parameters,
.kill_sb = ffs_fs_kill_sb,
};
MODULE_ALIAS_FS("functionfs");
ret = register_filesystem(&ffs_fs_type);
pr_info("file system registered\n");
}
list_add(&dev->entry, &ffs_devices);
}
opts->dev = dev;
dev->opts = opts;
config_group_init_type_name(&opts->func_inst.group, "",
&ffs_func_type);
}
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
struct ffs_function *func = ffs_func_from_usb(f){
return container_of(f, struct ffs_function, function);
}
..
ffs->func = func;
ffs_func_eps_enable(func){
config_ep_by_speed(func->gadget, &func->function, ep->ep);
}
}
int ffs_func_bind(struct usb_configuration *c,
struct usb_function *f)
{
struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);{
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to ffs_opts->bound access
*/
ret = functionfs_bind(func->ffs, c->cdev);{
first_id = usb_string_ids_n(cdev, ffs->strings_count);
ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
ffs->ep0req->complete = ffs_ep0_complete;
ffs->ep0req->context = ffs;
ffs->gadget = cdev->gadget;
ffs_data_get(ffs);{
refcount_inc(&ffs->ref);
}
}
}
struct ffs_function *func = ffs_func_from_usb(f);
_ffs_func_bind(c, f){
struct ffs_function *func = ffs_func_from_usb(f);
vla_group(d);
vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
full ? ffs->fs_descs_count + 1 : 0);
vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
high ? ffs->hs_descs_count + 1 : 0);
vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
super ? ffs->ss_descs_count + 1 : 0);
if (likely(full)) {
func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
fs_len = ffs_do_descs(ffs->fs_descs_count,
vla_ptr(vlabuf, d, raw_descs),
d_raw_descs__sz,
__ffs_func_bind_do_descs, func);
}
}
===========
int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv){
}
static const struct fs_context_operations ffs_fs_context_ops = {
.free = ffs_fs_free_fc,
.parse_param = ffs_fs_parse_param,
.get_tree = ffs_fs_get_tree,
};
/*
* Set up the superblock for a mount.
*/
static int ffs_fs_get_tree(struct fs_context *fc){
struct ffs_data *ffs;
ffs = ffs_data_new(fc->source){
ffs->state = FFS_READ_DESCRIPTORS;
}
ffs->dev_name = kstrdup(fc->source, GFP_KERNEL);
ffs_dev = ffs_acquire_dev(ffs->dev_name);{
struct ffs_dev *ffs_dev;
ffs_dev = _ffs_find_dev(dev_name);
}
return get_tree_nodev(fc, ffs_sb_fill){
//设备树??
int ffs_sb_fill(struct super_block *sb, struct fs_context *fc){
struct ffs_sb_fill_data *data = fc->fs_private;
struct inode *inode;
struct ffs_data *ffs = data->ffs_data;
sb->s_fs_info = ffs;
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
/* EP0 file */
ffs_sb_create_file(sb, "ep0", ffs,&ffs_ep0_operations)
return 0;
}
}
}
static const struct file_operations ffs_ep0_operations = {
.llseek = no_llseek,
.open = ffs_ep0_open,
.write = ffs_ep0_write,
.read = ffs_ep0_read,
.release = ffs_ep0_release,
.unlocked_ioctl = ffs_ep0_ioctl,
.poll = ffs_ep0_poll,
};
ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
size_t len, loff_t *ptr)
{
char *data;
/* Check state */
switch (ffs->state) {
case FFS_READ_DESCRIPTORS:
case FFS_READ_STRINGS:
data = ffs_prepare_buffer(buf, len){
char *data;
data = kmalloc(len, GFP_KERNEL);
copy_from_user(data, buf, len)
}
/* Handle data */
if (ffs->state == FFS_READ_DESCRIPTORS) {
pr_info("read descriptors\n");
ret = __ffs_data_got_descs(ffs, data, len){
ret = ffs_do_descs(counts[i], data, len,
__ffs_data_do_entity, &helper){
/* Record "descriptor" entity */
ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
ret = ffs_do_single_desc(data, len, entity, priv,¤t_class);
}
}
ffs->state = FFS_READ_STRINGS;
ret = len;
} else {
pr_info("read strings\n");
ret = __ffs_data_got_strings(ffs, data, len);
ret = ffs_epfiles_create(ffs);
ffs->state = FFS_ACTIVE;
ret = ffs_ready(ffs);
return len;
}
break;
}
}`
更细节的地方还没研究明白,现在是一边看代码一边猜,因为这部分调用是再device端的deamon执行时的,所以结合了相应的程序看,主要是想通过裸usb节点传输,现在速度慢,想提速,看了这部分代码,找不到能提速的点啊!