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