• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
try_get_usb_function_instance(const char * name)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  
usb_get_function_instance(const char * name)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  
usb_get_function(struct usb_function_instance * fi)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  
usb_put_function_instance(struct usb_function_instance * fi)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  
usb_put_function(struct usb_function * f)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  
usb_function_register(struct usb_function_driver * newf)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  
usb_function_unregister(struct usb_function_driver * fd)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