functions.c (2307B)
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 9static LIST_HEAD(func_list); 10static DEFINE_MUTEX(func_lock); 11 12static 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 39struct 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} 55EXPORT_SYMBOL_GPL(usb_get_function_instance); 56 57struct 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} 67EXPORT_SYMBOL_GPL(usb_get_function); 68 69void 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} 80EXPORT_SYMBOL_GPL(usb_put_function_instance); 81 82void usb_put_function(struct usb_function *f) 83{ 84 if (!f) 85 return; 86 87 f->free_func(f); 88} 89EXPORT_SYMBOL_GPL(usb_put_function); 90 91int 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); 105out: 106 mutex_unlock(&func_lock); 107 return ret; 108} 109EXPORT_SYMBOL_GPL(usb_function_register); 110 111void 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} 117EXPORT_SYMBOL_GPL(usb_function_unregister);