| |
| #include <linux/kernel.h> |
| #include <linux/slab.h> |
| #include <linux/module.h> |
| #include <linux/err.h> |
| |
| #include <linux/usb/composite.h> |
| |
| static LIST_HEAD(func_list); |
| static DEFINE_MUTEX(func_lock); |
| |
| static struct usb_function_instance *try_get_usb_function_instance(const char *name) |
| { |
| <------>struct usb_function_driver *fd; |
| <------>struct usb_function_instance *fi; |
| |
| <------>fi = ERR_PTR(-ENOENT); |
| <------>mutex_lock(&func_lock); |
| <------>list_for_each_entry(fd, &func_list, list) { |
| |
| <------><------>if (strcmp(name, fd->name)) |
| <------><------><------>continue; |
| |
| <------><------>if (!try_module_get(fd->mod)) { |
| <------><------><------>fi = ERR_PTR(-EBUSY); |
| <------><------><------>break; |
| <------><------>} |
| <------><------>fi = fd->alloc_inst(); |
| <------><------>if (IS_ERR(fi)) |
| <------><------><------>module_put(fd->mod); |
| <------><------>else |
| <------><------><------>fi->fd = fd; |
| <------><------>break; |
| <------>} |
| <------>mutex_unlock(&func_lock); |
| <------>return fi; |
| } |
| |
| struct usb_function_instance *usb_get_function_instance(const char *name) |
| { |
| <------>struct usb_function_instance *fi; |
| <------>int ret; |
| |
| <------>fi = try_get_usb_function_instance(name); |
| <------>if (!IS_ERR(fi)) |
| <------><------>return fi; |
| <------>ret = PTR_ERR(fi); |
| <------>if (ret != -ENOENT) |
| <------><------>return fi; |
| <------>ret = request_module("usbfunc:%s", name); |
| <------>if (ret < 0) |
| <------><------>return ERR_PTR(ret); |
| <------>return try_get_usb_function_instance(name); |
| } |
| EXPORT_SYMBOL_GPL(usb_get_function_instance); |
| |
| struct usb_function *usb_get_function(struct usb_function_instance *fi) |
| { |
| <------>struct usb_function *f; |
| |
| <------>f = fi->fd->alloc_func(fi); |
| <------>if (IS_ERR(f)) |
| <------><------>return f; |
| <------>f->fi = fi; |
| <------>return f; |
| } |
| EXPORT_SYMBOL_GPL(usb_get_function); |
| |
| void usb_put_function_instance(struct usb_function_instance *fi) |
| { |
| <------>struct module *mod; |
| |
| <------>if (!fi) |
| <------><------>return; |
| |
| <------>mod = fi->fd->mod; |
| <------>fi->free_func_inst(fi); |
| <------>module_put(mod); |
| } |
| EXPORT_SYMBOL_GPL(usb_put_function_instance); |
| |
| void usb_put_function(struct usb_function *f) |
| { |
| <------>if (!f) |
| <------><------>return; |
| |
| <------>f->free_func(f); |
| } |
| EXPORT_SYMBOL_GPL(usb_put_function); |
| |
| int usb_function_register(struct usb_function_driver *newf) |
| { |
| <------>struct usb_function_driver *fd; |
| <------>int ret; |
| |
| <------>ret = -EEXIST; |
| |
| <------>mutex_lock(&func_lock); |
| <------>list_for_each_entry(fd, &func_list, list) { |
| <------><------>if (!strcmp(fd->name, newf->name)) |
| <------><------><------>goto out; |
| <------>} |
| <------>ret = 0; |
| <------>list_add_tail(&newf->list, &func_list); |
| out: |
| <------>mutex_unlock(&func_lock); |
| <------>return ret; |
| } |
| EXPORT_SYMBOL_GPL(usb_function_register); |
| |
| void usb_function_unregister(struct usb_function_driver *fd) |
| { |
| <------>mutex_lock(&func_lock); |
| <------>list_del(&fd->list); |
| <------>mutex_unlock(&func_lock); |
| } |
| EXPORT_SYMBOL_GPL(usb_function_unregister); |
| |