[ALSA] emu10k1: Partial support for Creative emu1212m
[linux-2.6] / kernel / intermodule.c
1 /* Deprecated, do not use.  Moved from module.c to here. --RR */
2
3 /* Written by Keith Owens <kaos@ocs.com.au> Oct 2000 */
4 #include <linux/module.h>
5 #include <linux/kmod.h>
6 #include <linux/spinlock.h>
7 #include <linux/list.h>
8 #include <linux/slab.h>
9
10 /* inter_module functions are always available, even when the kernel is
11  * compiled without modules.  Consumers of inter_module_xxx routines
12  * will always work, even when both are built into the kernel, this
13  * approach removes lots of #ifdefs in mainline code.
14  */
15
16 static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
17 static DEFINE_SPINLOCK(ime_lock);
18 static int kmalloc_failed;
19
20 struct inter_module_entry {
21         struct list_head list;
22         const char *im_name;
23         struct module *owner;
24         const void *userdata;
25 };
26
27 /**
28  * inter_module_register - register a new set of inter module data.
29  * @im_name: an arbitrary string to identify the data, must be unique
30  * @owner: module that is registering the data, always use THIS_MODULE
31  * @userdata: pointer to arbitrary userdata to be registered
32  *
33  * Description: Check that the im_name has not already been registered,
34  * complain if it has.  For new data, add it to the inter_module_entry
35  * list.
36  */
37 void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
38 {
39         struct list_head *tmp;
40         struct inter_module_entry *ime, *ime_new;
41
42         if (!(ime_new = kzalloc(sizeof(*ime), GFP_KERNEL))) {
43                 /* Overloaded kernel, not fatal */
44                 printk(KERN_ERR
45                         "Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
46                         im_name);
47                 kmalloc_failed = 1;
48                 return;
49         }
50         ime_new->im_name = im_name;
51         ime_new->owner = owner;
52         ime_new->userdata = userdata;
53
54         spin_lock(&ime_lock);
55         list_for_each(tmp, &ime_list) {
56                 ime = list_entry(tmp, struct inter_module_entry, list);
57                 if (strcmp(ime->im_name, im_name) == 0) {
58                         spin_unlock(&ime_lock);
59                         kfree(ime_new);
60                         /* Program logic error, fatal */
61                         printk(KERN_ERR "inter_module_register: duplicate im_name '%s'", im_name);
62                         BUG();
63                 }
64         }
65         list_add(&(ime_new->list), &ime_list);
66         spin_unlock(&ime_lock);
67 }
68
69 /**
70  * inter_module_unregister - unregister a set of inter module data.
71  * @im_name: an arbitrary string to identify the data, must be unique
72  *
73  * Description: Check that the im_name has been registered, complain if
74  * it has not.  For existing data, remove it from the
75  * inter_module_entry list.
76  */
77 void inter_module_unregister(const char *im_name)
78 {
79         struct list_head *tmp;
80         struct inter_module_entry *ime;
81
82         spin_lock(&ime_lock);
83         list_for_each(tmp, &ime_list) {
84                 ime = list_entry(tmp, struct inter_module_entry, list);
85                 if (strcmp(ime->im_name, im_name) == 0) {
86                         list_del(&(ime->list));
87                         spin_unlock(&ime_lock);
88                         kfree(ime);
89                         return;
90                 }
91         }
92         spin_unlock(&ime_lock);
93         if (kmalloc_failed) {
94                 printk(KERN_ERR
95                         "inter_module_unregister: no entry for '%s', "
96                         "probably caused by previous kmalloc failure\n",
97                         im_name);
98                 return;
99         }
100         else {
101                 /* Program logic error, fatal */
102                 printk(KERN_ERR "inter_module_unregister: no entry for '%s'", im_name);
103                 BUG();
104         }
105 }
106
107 /**
108  * inter_module_get - return arbitrary userdata from another module.
109  * @im_name: an arbitrary string to identify the data, must be unique
110  *
111  * Description: If the im_name has not been registered, return NULL.
112  * Try to increment the use count on the owning module, if that fails
113  * then return NULL.  Otherwise return the userdata.
114  */
115 static const void *inter_module_get(const char *im_name)
116 {
117         struct list_head *tmp;
118         struct inter_module_entry *ime;
119         const void *result = NULL;
120
121         spin_lock(&ime_lock);
122         list_for_each(tmp, &ime_list) {
123                 ime = list_entry(tmp, struct inter_module_entry, list);
124                 if (strcmp(ime->im_name, im_name) == 0) {
125                         if (try_module_get(ime->owner))
126                                 result = ime->userdata;
127                         break;
128                 }
129         }
130         spin_unlock(&ime_lock);
131         return(result);
132 }
133
134 /**
135  * inter_module_get_request - im get with automatic request_module.
136  * @im_name: an arbitrary string to identify the data, must be unique
137  * @modname: module that is expected to register im_name
138  *
139  * Description: If inter_module_get fails, do request_module then retry.
140  */
141 const void *inter_module_get_request(const char *im_name, const char *modname)
142 {
143         const void *result = inter_module_get(im_name);
144         if (!result) {
145                 request_module("%s", modname);
146                 result = inter_module_get(im_name);
147         }
148         return(result);
149 }
150
151 /**
152  * inter_module_put - release use of data from another module.
153  * @im_name: an arbitrary string to identify the data, must be unique
154  *
155  * Description: If the im_name has not been registered, complain,
156  * otherwise decrement the use count on the owning module.
157  */
158 void inter_module_put(const char *im_name)
159 {
160         struct list_head *tmp;
161         struct inter_module_entry *ime;
162
163         spin_lock(&ime_lock);
164         list_for_each(tmp, &ime_list) {
165                 ime = list_entry(tmp, struct inter_module_entry, list);
166                 if (strcmp(ime->im_name, im_name) == 0) {
167                         if (ime->owner)
168                                 module_put(ime->owner);
169                         spin_unlock(&ime_lock);
170                         return;
171                 }
172         }
173         spin_unlock(&ime_lock);
174         printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name);
175         BUG();
176 }
177
178 EXPORT_SYMBOL(inter_module_register);
179 EXPORT_SYMBOL(inter_module_unregister);
180 EXPORT_SYMBOL(inter_module_get_request);
181 EXPORT_SYMBOL(inter_module_put);