1#include <linux/kernel.h> 2#include <linux/slab.h> 3#include <linux/module.h> 4#include <linux/err.h> 5 6#include <linux/usb/composite.h> 7 8static LIST_HEAD(func_list); 9static DEFINE_MUTEX(func_lock); 10 11static struct usb_function_instance *try_get_usb_function_instance(const char *name) 12{ 13 struct usb_function_driver *fd; 14 struct usb_function_instance *fi; 15 16 fi = ERR_PTR(-ENOENT); 17 mutex_lock(&func_lock); 18 list_for_each_entry(fd, &func_list, list) { 19 20 if (strcmp(name, fd->name)) 21 continue; 22 23 if (!try_module_get(fd->mod)) { 24 fi = ERR_PTR(-EBUSY); 25 break; 26 } 27 fi = fd->alloc_inst(); 28 if (IS_ERR(fi)) 29 module_put(fd->mod); 30 else 31 fi->fd = fd; 32 break; 33 } 34 mutex_unlock(&func_lock); 35 return fi; 36} 37 38struct usb_function_instance *usb_get_function_instance(const char *name) 39{ 40 struct usb_function_instance *fi; 41 int ret; 42 43 fi = try_get_usb_function_instance(name); 44 if (!IS_ERR(fi)) 45 return fi; 46 ret = PTR_ERR(fi); 47 if (ret != -ENOENT) 48 return fi; 49 ret = request_module("usbfunc:%s", name); 50 if (ret < 0) 51 return ERR_PTR(ret); 52 return try_get_usb_function_instance(name); 53} 54EXPORT_SYMBOL_GPL(usb_get_function_instance); 55 56struct usb_function *usb_get_function(struct usb_function_instance *fi) 57{ 58 struct usb_function *f; 59 60 f = fi->fd->alloc_func(fi); 61 if (IS_ERR(f)) 62 return f; 63 f->fi = fi; 64 return f; 65} 66EXPORT_SYMBOL_GPL(usb_get_function); 67 68void usb_put_function_instance(struct usb_function_instance *fi) 69{ 70 struct module *mod; 71 72 if (!fi) 73 return; 74 75 mod = fi->fd->mod; 76 fi->free_func_inst(fi); 77 module_put(mod); 78} 79EXPORT_SYMBOL_GPL(usb_put_function_instance); 80 81void usb_put_function(struct usb_function *f) 82{ 83 if (!f) 84 return; 85 86 f->free_func(f); 87} 88EXPORT_SYMBOL_GPL(usb_put_function); 89 90int usb_function_register(struct usb_function_driver *newf) 91{ 92 struct usb_function_driver *fd; 93 int ret; 94 95 ret = -EEXIST; 96 97 mutex_lock(&func_lock); 98 list_for_each_entry(fd, &func_list, list) { 99 if (!strcmp(fd->name, newf->name)) 100 goto out; 101 } 102 ret = 0; 103 list_add_tail(&newf->list, &func_list); 104out: 105 mutex_unlock(&func_lock); 106 return ret; 107} 108EXPORT_SYMBOL_GPL(usb_function_register); 109 110void usb_function_unregister(struct usb_function_driver *fd) 111{ 112 mutex_lock(&func_lock); 113 list_del(&fd->list); 114 mutex_unlock(&func_lock); 115} 116EXPORT_SYMBOL_GPL(usb_function_unregister); 117