1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting Layer (SPL) Module Implementation.
25 \*****************************************************************************/
27 #include <sys/sunddi.h>
28 #include <spl-debug.h>
30 #ifdef SS_DEBUG_SUBSYS
31 #undef SS_DEBUG_SUBSYS
34 #define SS_DEBUG_SUBSYS SS_MODULE
36 static spinlock_t dev_info_lock
= SPIN_LOCK_UNLOCKED
;
37 static LIST_HEAD(dev_info_list
);
39 static struct dev_info
*
40 get_dev_info(dev_t dev
)
44 spin_lock(&dev_info_lock
);
46 list_for_each_entry(di
, &dev_info_list
, di_list
)
47 if (di
->di_dev
== dev
)
52 spin_unlock(&dev_info_lock
);
57 mod_generic_unlocked_ioctl(struct file
*file
,
58 unsigned int cmd
, unsigned long arg
)
60 struct inode
*ino
= file
->f_dentry
->d_inode
;
62 int rc
, flags
= 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
,
73 * The Solaris the kernel returns positive error codes to indicate
74 * a failure. Under linux the kernel is expected to return a
75 * small negative value which is trapped by libc and used to
76 * set errno correctly. For this reason we negate the Solaris
77 * return code to ensure errno gets set correctly.
83 /* Compatibility handler for ioctls from 32-bit ELF binaries */
85 mod_generic_compat_ioctl(struct file
*file
,
86 unsigned int cmd
, unsigned long arg
)
88 return mod_generic_unlocked_ioctl(file
, cmd
, arg
);
90 #endif /* CONFIG_COMPAT */
93 __ddi_create_minor_node(dev_info_t
*di
, char *name
, int spec_type
,
94 minor_t minor_num
, char *node_type
,
95 int flags
, struct module
*mod
)
98 struct dev_ops
*dev_ops
;
99 struct cb_ops
*cb_ops
;
100 struct file_operations
*fops
;
104 ASSERT(spec_type
== S_IFCHR
);
105 ASSERT(minor_num
< di
->di_minors
);
106 ASSERT(!strcmp(node_type
, DDI_PSEUDO
));
108 fops
= kzalloc(sizeof(struct file_operations
), GFP_KERNEL
);
110 SRETURN(DDI_FAILURE
);
115 SRETURN(DDI_FAILURE
);
120 mutex_enter(&di
->di_lock
);
121 dev_ops
= di
->di_ops
;
123 cb_ops
= di
->di_ops
->devo_cb_ops
;
126 /* Setup the fops to cb_ops mapping */
128 if (cb_ops
->cb_ioctl
) {
129 fops
->unlocked_ioctl
= mod_generic_unlocked_ioctl
;
131 fops
->compat_ioctl
= mod_generic_compat_ioctl
;
137 fops
->open
= mod_generic_open
;
139 if (cb_ops
->cb_close
)
140 fops
->release
= mod_generic_close
;
143 fops
->read
= mod_generic_read
;
145 if (cb_ops
->cb_write
)
146 fops
->write
= mod_generic_write
;
148 /* XXX: Currently unsupported operations */
149 ASSERT(cb_ops
->cb_open
== NULL
);
150 ASSERT(cb_ops
->cb_close
== NULL
);
151 ASSERT(cb_ops
->cb_read
== NULL
);
152 ASSERT(cb_ops
->cb_write
== NULL
);
153 ASSERT(cb_ops
->cb_strategy
== NULL
);
154 ASSERT(cb_ops
->cb_print
== NULL
);
155 ASSERT(cb_ops
->cb_dump
== NULL
);
156 ASSERT(cb_ops
->cb_devmap
== NULL
);
157 ASSERT(cb_ops
->cb_mmap
== NULL
);
158 ASSERT(cb_ops
->cb_segmap
== NULL
);
159 ASSERT(cb_ops
->cb_chpoll
== NULL
);
160 ASSERT(cb_ops
->cb_prop_op
== NULL
);
161 ASSERT(cb_ops
->cb_str
== NULL
);
162 ASSERT(cb_ops
->cb_aread
== NULL
);
163 ASSERT(cb_ops
->cb_awrite
== NULL
);
165 snprintf(di
->di_name
, DDI_MAX_NAME_LEN
-1, "/dev/%s", name
);
167 di
->di_flags
= flags
;
168 di
->di_minor
= minor_num
;
169 di
->di_dev
= MKDEV(di
->di_major
, di
->di_minor
);
171 rc
= cdev_add(cdev
, di
->di_dev
, 1);
173 SERROR("Error adding cdev, %d\n", rc
);
176 mutex_exit(&di
->di_lock
);
177 SRETURN(DDI_FAILURE
);
180 spin_lock(&dev_info_lock
);
181 list_add(&di
->di_list
, &dev_info_list
);
182 spin_unlock(&dev_info_lock
);
184 mutex_exit(&di
->di_lock
);
186 SRETURN(DDI_SUCCESS
);
188 EXPORT_SYMBOL(__ddi_create_minor_node
);
191 __ddi_remove_minor_node_locked(dev_info_t
*di
, char *name
)
194 cdev_del(di
->di_cdev
);
198 spin_lock(&dev_info_lock
);
199 list_del_init(&di
->di_list
);
200 spin_unlock(&dev_info_lock
);
204 __ddi_remove_minor_node(dev_info_t
*di
, char *name
)
207 mutex_enter(&di
->di_lock
);
208 __ddi_remove_minor_node_locked(di
, name
);
209 mutex_exit(&di
->di_lock
);
212 EXPORT_SYMBOL(__ddi_remove_minor_node
);
215 ddi_quiesce_not_needed(dev_info_t
*dip
)
217 SRETURN(DDI_SUCCESS
);
219 EXPORT_SYMBOL(ddi_quiesce_not_needed
);
223 mod_generic_open(struct inode
*, struct file
*)
225 open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
);
229 mod_generic_close(struct inode
*, struct file
*)
231 close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
);
235 mod_generic_read(struct file
*, char __user
*, size_t, loff_t
*)
237 read(dev_t dev
, struct uio
*uiop
, cred_t
*credp
);
241 mod_generic_write(struct file
*, const char __user
*, size_t, loff_t
*)
243 write(dev_t dev
, struct uio
*uiop
, cred_t
*credp
);
247 static struct dev_info
*
248 dev_info_alloc(major_t major
, minor_t minors
, struct dev_ops
*ops
) {
251 di
= kmalloc(sizeof(struct dev_info
), GFP_KERNEL
);
255 mutex_init(&di
->di_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
256 INIT_LIST_HEAD(&di
->di_list
);
260 di
->di_major
= major
;
262 di
->di_minors
= minors
;
269 dev_info_free(struct dev_info
*di
)
271 mutex_enter(&di
->di_lock
);
272 __ddi_remove_minor_node_locked(di
, NULL
);
273 mutex_exit(&di
->di_lock
);
274 mutex_destroy(&di
->di_lock
);
279 __mod_install(struct modlinkage
*modlp
)
281 struct modldrv
*drv
= modlp
->ml_modldrv
;
286 di
= dev_info_alloc(modlp
->ml_major
, modlp
->ml_minors
,
291 /* XXX: Really we need to be calling devo_probe if it's available
292 * and then calling devo_attach for each device discovered. However
293 * for now we just call it once and let the app sort it out.
295 rc
= drv
->drv_dev_ops
->devo_attach(di
, DDI_ATTACH
);
296 if (rc
!= DDI_SUCCESS
) {
301 drv
->drv_dev_info
= di
;
303 SRETURN(DDI_SUCCESS
);
305 EXPORT_SYMBOL(__mod_install
);
308 __mod_mknod(char *name
, char *type
, int major
, int minor
)
310 char cmd
[] = "/bin/mknod";
313 char *argv
[] = { cmd
,
319 char *envp
[] = { "HOME=/",
321 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
324 snprintf(major_str
, 8, "%d", major
);
325 snprintf(minor_str
, 8, "%d", minor
);
327 return call_usermodehelper(cmd
, argv
, envp
, 1);
329 EXPORT_SYMBOL(__mod_mknod
);
332 __mod_remove(struct modlinkage
*modlp
)
334 struct modldrv
*drv
= modlp
->ml_modldrv
;
335 struct dev_info
*di
= drv
->drv_dev_info
;
339 rc
= drv
->drv_dev_ops
->devo_detach(di
, DDI_DETACH
);
340 if (rc
!= DDI_SUCCESS
)
344 drv
->drv_dev_info
= NULL
;
346 SRETURN(DDI_SUCCESS
);
348 EXPORT_SYMBOL(__mod_remove
);
351 ldi_ident_from_mod(struct modlinkage
*modlp
, ldi_ident_t
*lip
)
359 li
= kmalloc(sizeof(struct ldi_ident
), GFP_KERNEL
);
363 li
->li_dev
= MKDEV(modlp
->ml_major
, 0);
368 EXPORT_SYMBOL(ldi_ident_from_mod
);
371 ldi_ident_release(ldi_ident_t lip
)
378 EXPORT_SYMBOL(ldi_ident_release
);