]>
git.proxmox.com Git - mirror_spl.git/blob - modules/spl/spl-module.c
2 * This file is part of the SPL: Solaris Porting Layer.
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
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.
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
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.
27 #include <sys/sysmacros.h>
28 #include <sys/sunddi.h>
31 #ifdef DEBUG_SUBSYSTEM
32 #undef DEBUG_SUBSYSTEM
35 #define DEBUG_SUBSYSTEM S_MODULE
37 static spinlock_t dev_info_lock
= SPIN_LOCK_UNLOCKED
;
38 static LIST_HEAD(dev_info_list
);
40 static struct dev_info
*
41 get_dev_info(dev_t dev
)
45 spin_lock(&dev_info_lock
);
47 list_for_each_entry(di
, &dev_info_list
, di_list
)
48 if (di
->di_dev
== dev
)
53 spin_unlock(&dev_info_lock
);
58 mod_generic_ioctl(struct inode
*ino
, struct file
*filp
,
59 unsigned int cmd
, unsigned long arg
)
62 int rc
, flag
= 0, rvalp
= 0;
65 di
= get_dev_info(MKDEV(imajor(ino
), iminor(ino
)));
69 rc
= di
->di_ops
->devo_cb_ops
->cb_ioctl(di
->di_dev
,
70 (int)cmd
,(intptr_t)arg
,
76 __ddi_create_minor_node(dev_info_t
*di
, char *name
, int spec_type
,
77 minor_t minor_num
, char *node_type
,
78 int flag
, struct module
*mod
)
81 struct dev_ops
*dev_ops
;
82 struct cb_ops
*cb_ops
;
83 struct file_operations
*fops
;
87 ASSERT(spec_type
== S_IFCHR
);
88 ASSERT(minor_num
< di
->di_minors
);
89 ASSERT(!strcmp(node_type
, DDI_PSEUDO
));
92 fops
= kzalloc(sizeof(struct file_operations
), GFP_KERNEL
);
104 mutex_enter(&di
->di_lock
);
105 dev_ops
= di
->di_ops
;
107 cb_ops
= di
->di_ops
->devo_cb_ops
;
110 /* Setup the fops to cb_ops mapping */
112 if (cb_ops
->cb_ioctl
)
113 fops
->ioctl
= mod_generic_ioctl
;
117 fops
->open
= mod_generic_open
;
119 if (cb_ops
->cb_close
)
120 fops
->release
= mod_generic_close
;
123 fops
->read
= mod_generic_read
;
125 if (cb_ops
->cb_write
)
126 fops
->write
= mod_generic_write
;
128 /* XXX: Currently unsupported operations */
129 ASSERT(cb_ops
->cb_open
== NULL
);
130 ASSERT(cb_ops
->cb_close
== NULL
);
131 ASSERT(cb_ops
->cb_read
== NULL
);
132 ASSERT(cb_ops
->cb_write
== NULL
);
133 ASSERT(cb_ops
->cb_strategy
== NULL
);
134 ASSERT(cb_ops
->cb_print
== NULL
);
135 ASSERT(cb_ops
->cb_dump
== NULL
);
136 ASSERT(cb_ops
->cb_devmap
== NULL
);
137 ASSERT(cb_ops
->cb_mmap
== NULL
);
138 ASSERT(cb_ops
->cb_segmap
== NULL
);
139 ASSERT(cb_ops
->cb_chpoll
== NULL
);
140 ASSERT(cb_ops
->cb_prop_op
== NULL
);
141 ASSERT(cb_ops
->cb_str
== NULL
);
142 ASSERT(cb_ops
->cb_aread
== NULL
);
143 ASSERT(cb_ops
->cb_awrite
== NULL
);
145 di
->di_minor
= minor_num
;
146 di
->di_dev
= MKDEV(di
->di_major
, di
->di_minor
);
148 rc
= cdev_add(cdev
, di
->di_dev
, 1);
150 CERROR("Error adding cdev, %d\n", rc
);
153 mutex_exit(&di
->di_lock
);
157 di
->di_class
= class_create(THIS_MODULE
, name
);
158 if (IS_ERR(di
->di_class
)) {
159 rc
= PTR_ERR(di
->di_class
);
160 CERROR("Error creating %s class, %d\n", name
, rc
);
162 cdev_del(di
->di_cdev
);
163 mutex_exit(&di
->di_lock
);
167 /* Do not append a 0 to devices with minor nums of 0 */
168 if (di
->di_minor
== 0) {
169 class_device_create(di
->di_class
, NULL
, di
->di_dev
,
172 class_device_create(di
->di_class
, NULL
, di
->di_dev
,
173 NULL
, "%s%d", name
, di
->di_minor
);
178 spin_lock(&dev_info_lock
);
179 list_add(&di
->di_list
, &dev_info_list
);
180 spin_unlock(&dev_info_lock
);
182 mutex_exit(&di
->di_lock
);
186 EXPORT_SYMBOL(__ddi_create_minor_node
);
189 __ddi_remove_minor_node_locked(dev_info_t
*di
, char *name
)
192 class_device_destroy(di
->di_class
, di
->di_dev
);
193 class_destroy(di
->di_class
);
200 cdev_del(di
->di_cdev
);
204 spin_lock(&dev_info_lock
);
205 list_del_init(&di
->di_list
);
206 spin_unlock(&dev_info_lock
);
210 __ddi_remove_minor_node(dev_info_t
*di
, char *name
)
213 mutex_enter(&di
->di_lock
);
214 __ddi_remove_minor_node_locked(di
, name
);
215 mutex_exit(&di
->di_lock
);
218 EXPORT_SYMBOL(ddi_remove_minor_node
);
222 mod_generic_open(struct inode
*, struct file
*)
224 open(dev_t
*devp
, int flag
, int otyp
, cred_t
*credp
);
228 mod_generic_close(struct inode
*, struct file
*)
230 close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
);
234 mod_generic_read(struct file
*, char __user
*, size_t, loff_t
*)
236 read(dev_t dev
, struct uio
*uiop
, cred_t
*credp
);
240 mod_generic_write(struct file
*, const char __user
*, size_t, loff_t
*)
242 write(dev_t dev
, struct uio
*uiop
, cred_t
*credp
);
246 static struct dev_info
*
247 dev_info_alloc(major_t major
, minor_t minors
, struct dev_ops
*ops
) {
250 di
= kmalloc(sizeof(struct dev_info
), GFP_KERNEL
);
254 mutex_init(&di
->di_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
255 INIT_LIST_HEAD(&di
->di_list
);
259 di
->di_major
= major
;
261 di
->di_minors
= minors
;
268 dev_info_free(struct dev_info
*di
)
270 mutex_enter(&di
->di_lock
);
271 __ddi_remove_minor_node_locked(di
, NULL
);
272 mutex_exit(&di
->di_lock
);
273 mutex_destroy(&di
->di_lock
);
278 __mod_install(struct modlinkage
*modlp
)
280 struct modldrv
*drv
= modlp
->ml_modldrv
;
285 di
= dev_info_alloc(modlp
->ml_major
, modlp
->ml_minors
,
290 /* XXX: Really we need to be calling devo_probe if it's available
291 * and then calling devo_attach for each device discovered. However
292 * for now we just call it once and let the app sort it out.
294 rc
= drv
->drv_dev_ops
->devo_attach(di
, DDI_ATTACH
);
295 if (rc
!= DDI_SUCCESS
) {
300 drv
->drv_dev_info
= di
;
304 EXPORT_SYMBOL(__mod_install
);
307 __mod_remove(struct modlinkage
*modlp
)
309 struct modldrv
*drv
= modlp
->ml_modldrv
;
310 struct dev_info
*di
= drv
->drv_dev_info
;
314 rc
= drv
->drv_dev_ops
->devo_detach(di
, DDI_DETACH
);
315 if (rc
!= DDI_SUCCESS
)
319 drv
->drv_dev_info
= NULL
;
323 EXPORT_SYMBOL(__mod_remove
);
326 ldi_ident_from_mod(struct modlinkage
*modlp
, ldi_ident_t
*lip
)
334 li
= kmalloc(sizeof(struct ldi_ident
), GFP_KERNEL
);
338 li
->li_dev
= MKDEV(modlp
->ml_major
, 0);
343 EXPORT_SYMBOL(ldi_ident_from_mod
);
346 ldi_ident_release(ldi_ident_t lip
)
353 EXPORT_SYMBOL(ldi_ident_release
);