]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/spl/spl-module.c
Rename modules to module and update references
[mirror_spl-debian.git] / module / spl / spl-module.c
1 /*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #include <sys/sysmacros.h>
28 #include <sys/sunddi.h>
29
30 #ifdef DEBUG_SUBSYSTEM
31 #undef DEBUG_SUBSYSTEM
32 #endif
33
34 #define DEBUG_SUBSYSTEM S_MODULE
35
36 static spinlock_t dev_info_lock = SPIN_LOCK_UNLOCKED;
37 static LIST_HEAD(dev_info_list);
38
39 static struct dev_info *
40 get_dev_info(dev_t dev)
41 {
42 struct dev_info *di;
43
44 spin_lock(&dev_info_lock);
45
46 list_for_each_entry(di, &dev_info_list, di_list)
47 if (di->di_dev == dev)
48 goto out;
49
50 di = NULL;
51 out:
52 spin_unlock(&dev_info_lock);
53 return di;
54 }
55
56 static int
57 mod_generic_ioctl(struct inode *ino, struct file *filp,
58 unsigned int cmd, unsigned long arg)
59 {
60 struct dev_info *di;
61 int rc, flags = 0, rvalp = 0;
62 cred_t *cr = NULL;
63
64 di = get_dev_info(MKDEV(imajor(ino), iminor(ino)));
65 if (di == NULL)
66 return EINVAL;
67
68 rc = di->di_ops->devo_cb_ops->cb_ioctl(di->di_dev,
69 (int)cmd,(intptr_t)arg,
70 flags, cr, &rvalp);
71 return rc;
72 }
73
74 int
75 __ddi_create_minor_node(dev_info_t *di, char *name, int spec_type,
76 minor_t minor_num, char *node_type,
77 int flags, struct module *mod)
78 {
79 struct cdev *cdev;
80 struct dev_ops *dev_ops;
81 struct cb_ops *cb_ops;
82 struct file_operations *fops;
83 int rc;
84 ENTRY;
85
86 ASSERT(spec_type == S_IFCHR);
87 ASSERT(minor_num < di->di_minors);
88 ASSERT(!strcmp(node_type, DDI_PSEUDO));
89
90 fops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
91 if (fops == NULL)
92 RETURN(DDI_FAILURE);
93
94 cdev = cdev_alloc();
95 if (cdev == NULL) {
96 kfree(fops);
97 RETURN(DDI_FAILURE);
98 }
99
100 cdev->ops = fops;
101
102 mutex_enter(&di->di_lock);
103 dev_ops = di->di_ops;
104 ASSERT(dev_ops);
105 cb_ops = di->di_ops->devo_cb_ops;
106 ASSERT(cb_ops);
107
108 /* Setup the fops to cb_ops mapping */
109 fops->owner = mod;
110 if (cb_ops->cb_ioctl)
111 fops->ioctl = mod_generic_ioctl;
112
113 #if 0
114 if (cb_ops->cb_open)
115 fops->open = mod_generic_open;
116
117 if (cb_ops->cb_close)
118 fops->release = mod_generic_close;
119
120 if (cb_ops->cb_read)
121 fops->read = mod_generic_read;
122
123 if (cb_ops->cb_write)
124 fops->write = mod_generic_write;
125 #endif
126 /* XXX: Currently unsupported operations */
127 ASSERT(cb_ops->cb_open == NULL);
128 ASSERT(cb_ops->cb_close == NULL);
129 ASSERT(cb_ops->cb_read == NULL);
130 ASSERT(cb_ops->cb_write == NULL);
131 ASSERT(cb_ops->cb_strategy == NULL);
132 ASSERT(cb_ops->cb_print == NULL);
133 ASSERT(cb_ops->cb_dump == NULL);
134 ASSERT(cb_ops->cb_devmap == NULL);
135 ASSERT(cb_ops->cb_mmap == NULL);
136 ASSERT(cb_ops->cb_segmap == NULL);
137 ASSERT(cb_ops->cb_chpoll == NULL);
138 ASSERT(cb_ops->cb_prop_op == NULL);
139 ASSERT(cb_ops->cb_str == NULL);
140 ASSERT(cb_ops->cb_aread == NULL);
141 ASSERT(cb_ops->cb_awrite == NULL);
142
143 di->di_cdev = cdev;
144 di->di_flags = flags;
145 di->di_minor = minor_num;
146 di->di_dev = MKDEV(di->di_major, di->di_minor);
147
148 rc = cdev_add(cdev, di->di_dev, 1);
149 if (rc) {
150 CERROR("Error adding cdev, %d\n", rc);
151 kfree(fops);
152 cdev_del(cdev);
153 mutex_exit(&di->di_lock);
154 RETURN(DDI_FAILURE);
155 }
156
157 spin_lock(&dev_info_lock);
158 list_add(&di->di_list, &dev_info_list);
159 spin_unlock(&dev_info_lock);
160
161 mutex_exit(&di->di_lock);
162
163 RETURN(DDI_SUCCESS);
164 }
165 EXPORT_SYMBOL(__ddi_create_minor_node);
166
167 static void
168 __ddi_remove_minor_node_locked(dev_info_t *di, char *name)
169 {
170 if (di->di_cdev) {
171 cdev_del(di->di_cdev);
172 di->di_cdev = NULL;
173 }
174
175 spin_lock(&dev_info_lock);
176 list_del_init(&di->di_list);
177 spin_unlock(&dev_info_lock);
178 }
179
180 void
181 __ddi_remove_minor_node(dev_info_t *di, char *name)
182 {
183 ENTRY;
184 mutex_enter(&di->di_lock);
185 __ddi_remove_minor_node_locked(di, name);
186 mutex_exit(&di->di_lock);
187 EXIT;
188 }
189 EXPORT_SYMBOL(__ddi_remove_minor_node);
190
191 int
192 ddi_quiesce_not_needed(dev_info_t *dip)
193 {
194 RETURN(DDI_SUCCESS);
195 }
196 EXPORT_SYMBOL(ddi_quiesce_not_needed);
197
198 #if 0
199 static int
200 mod_generic_open(struct inode *, struct file *)
201 {
202 open(dev_t *devp, int flags, int otyp, cred_t *credp);
203 }
204
205 static int
206 mod_generic_close(struct inode *, struct file *)
207 {
208 close(dev_t dev, int flags, int otyp, cred_t *credp);
209 }
210
211 static ssize_t
212 mod_generic_read(struct file *, char __user *, size_t, loff_t *)
213 {
214 read(dev_t dev, struct uio *uiop, cred_t *credp);
215 }
216
217 static ssize_t
218 mod_generic_write(struct file *, const char __user *, size_t, loff_t *)
219 {
220 write(dev_t dev, struct uio *uiop, cred_t *credp);
221 }
222 #endif
223
224 static struct dev_info *
225 dev_info_alloc(major_t major, minor_t minors, struct dev_ops *ops) {
226 struct dev_info *di;
227
228 di = kmalloc(sizeof(struct dev_info), GFP_KERNEL);
229 if (di == NULL)
230 return NULL;
231
232 mutex_init(&di->di_lock, NULL, MUTEX_DEFAULT, NULL);
233 INIT_LIST_HEAD(&di->di_list);
234 di->di_ops = ops;
235 di->di_class = NULL;
236 di->di_cdev = NULL;
237 di->di_major = major;
238 di->di_minor = 0;
239 di->di_minors = minors;
240 di->di_dev = 0;
241
242 return di;
243 }
244
245 static void
246 dev_info_free(struct dev_info *di)
247 {
248 mutex_enter(&di->di_lock);
249 __ddi_remove_minor_node_locked(di, NULL);
250 mutex_exit(&di->di_lock);
251 mutex_destroy(&di->di_lock);
252 kfree(di);
253 }
254
255 int
256 __mod_install(struct modlinkage *modlp)
257 {
258 struct modldrv *drv = modlp->ml_modldrv;
259 struct dev_info *di;
260 int rc;
261 ENTRY;
262
263 di = dev_info_alloc(modlp->ml_major, modlp->ml_minors,
264 drv->drv_dev_ops);
265 if (di == NULL)
266 RETURN(ENOMEM);
267
268 /* XXX: Really we need to be calling devo_probe if it's available
269 * and then calling devo_attach for each device discovered. However
270 * for now we just call it once and let the app sort it out.
271 */
272 rc = drv->drv_dev_ops->devo_attach(di, DDI_ATTACH);
273 if (rc != DDI_SUCCESS) {
274 dev_info_free(di);
275 RETURN(rc);
276 }
277
278 drv->drv_dev_info = di;
279
280 RETURN(DDI_SUCCESS);
281 }
282 EXPORT_SYMBOL(__mod_install);
283
284 int
285 __mod_remove(struct modlinkage *modlp)
286 {
287 struct modldrv *drv = modlp->ml_modldrv;
288 struct dev_info *di = drv->drv_dev_info;
289 int rc;
290 ENTRY;
291
292 rc = drv->drv_dev_ops->devo_detach(di, DDI_DETACH);
293 if (rc != DDI_SUCCESS)
294 RETURN(rc);
295
296 dev_info_free(di);
297 drv->drv_dev_info = NULL;
298
299 RETURN(DDI_SUCCESS);
300 }
301 EXPORT_SYMBOL(__mod_remove);
302
303 int
304 ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
305 {
306 ldi_ident_t li;
307 ENTRY;
308
309 ASSERT(modlp);
310 ASSERT(lip);
311
312 li = kmalloc(sizeof(struct ldi_ident), GFP_KERNEL);
313 if (li == NULL)
314 RETURN(ENOMEM);
315
316 li->li_dev = MKDEV(modlp->ml_major, 0);
317 *lip = li;
318
319 RETURN(0);
320 }
321 EXPORT_SYMBOL(ldi_ident_from_mod);
322
323 void
324 ldi_ident_release(ldi_ident_t lip)
325 {
326 ENTRY;
327 ASSERT(lip);
328 kfree(lip);
329 EXIT;
330 }
331 EXPORT_SYMBOL(ldi_ident_release);