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