2 * Parts Copyright (c) 1995 Terrence R. Lambert
3 * Copyright (c) 1995 Julian R. Elischer
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Terrence R. Lambert.
17 * 4. The name Terrence R. Lambert may not be used to endorse or promote
18 * products derived from this software without specific prior written
21 * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $
34 * $DragonFly: src/sys/kern/kern_conf.c,v 1.23 2007/05/09 00:53:34 dillon Exp $
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/sysctl.h>
40 #include <sys/systm.h>
41 #include <sys/module.h>
42 #include <sys/malloc.h>
44 #include <sys/vnode.h>
45 #include <sys/queue.h>
46 #include <sys/device.h>
48 #include <machine/stdarg.h>
50 #include <sys/sysref2.h>
52 #include <sys/devfs.h>
54 MALLOC_DEFINE(M_DEVT
, "cdev_t", "dev_t storage");
57 SYSCTL_INT(_debug
, OID_AUTO
, free_devt
, CTLFLAG_RW
, &free_devt
, 0, "");
58 int dev_ref_debug
= 0;
59 SYSCTL_INT(_debug
, OID_AUTO
, dev_refs
, CTLFLAG_RW
, &dev_ref_debug
, 0, "");
62 * cdev_t and u_dev_t primitives. Note that the major number is always
63 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
64 * when a device is destroyed.
71 return(dev
->si_umajor
);
79 return(dev
->si_uminor
);
83 * Compatibility function with old udev_t format to convert the
84 * non-consecutive minor space into a consecutive minor space.
96 return ((y
& 0xff) | (y
>> 8));
100 * Convert a device pointer to an old style device number. Return NOUDEV
101 * if the device is invalid or if the device (maj,min) cannot be converted
102 * to an old style udev_t.
110 return (udev_t
)dev
->si_inode
;
114 * Convert a device number to a device pointer. The device is referenced
115 * ad-hoc, meaning that the caller should call reference_dev() if it wishes
116 * to keep ahold of the returned structure long term.
118 * The returned device is associated with the currently installed cdevsw
119 * for the requested major number. NULL is returned if the major number
120 * has not been registered.
123 udev2dev(udev_t x
, int b
)
125 if (x
== NOUDEV
|| b
!= 0)
128 return devfs_find_device_by_udev(x
);
132 dev_is_good(cdev_t dev
)
134 if (dev
!= NULL
&& dev
->si_ops
!= &dead_dev_ops
)
140 * Various user device number extraction and conversion routines
147 return(dev
& 0xffff00ff);
155 return((dev
& 0xff00) >> 8);
159 makeudev(int x
, int y
)
161 if ((x
& 0xffffff00) || (y
& 0x0000ff00))
163 return ((x
<< 8) | y
);
167 * Create an internal or external device.
169 * This routine creates and returns an unreferenced ad-hoc entry for the
170 * device which will remain intact until the device is destroyed. If the
171 * caller intends to store the device pointer it must call reference_dev()
172 * to retain a real reference to the device.
174 * If an entry already exists, this function will set (or override)
175 * its cred requirements and name (XXX DEVFS interface).
178 make_dev(struct dev_ops
*ops
, int minor
, uid_t uid
, gid_t gid
,
179 int perms
, const char *fmt
, ...)
185 * compile the cdevsw and install the device
187 compile_dev_ops(ops
);
189 devfs_dev
= devfs_new_cdev(ops
, minor
, NULL
);
191 kvsnrprintf(devfs_dev
->si_name
, sizeof(devfs_dev
->si_name
),
195 devfs_debug(DEVFS_DEBUG_INFO
,
196 "make_dev called for %s\n",
198 devfs_create_dev(devfs_dev
, uid
, gid
, perms
);
204 * make_dev_covering has equivalent functionality to make_dev, except that it
205 * also takes the cdev of the underlying device. Hence this function should
206 * only be used by systems and drivers which create devices covering others
209 make_dev_covering(struct dev_ops
*ops
, struct dev_ops
*bops
, int minor
,
210 uid_t uid
, gid_t gid
, int perms
, const char *fmt
, ...)
216 * compile the cdevsw and install the device
218 compile_dev_ops(ops
);
220 devfs_dev
= devfs_new_cdev(ops
, minor
, bops
);
222 kvsnrprintf(devfs_dev
->si_name
, sizeof(devfs_dev
->si_name
),
226 devfs_debug(DEVFS_DEBUG_INFO
,
227 "make_dev called for %s\n",
229 devfs_create_dev(devfs_dev
, uid
, gid
, perms
);
237 make_only_devfs_dev(struct dev_ops
*ops
, int minor
, uid_t uid
, gid_t gid
,
238 int perms
, const char *fmt
, ...)
244 * compile the cdevsw and install the device
246 compile_dev_ops(ops
);
247 devfs_dev
= devfs_new_cdev(ops
, minor
, NULL
);
250 * Set additional fields (XXX DEVFS interface goes here)
253 kvsnrprintf(devfs_dev
->si_name
, sizeof(devfs_dev
->si_name
),
257 devfs_create_dev(devfs_dev
, uid
, gid
, perms
);
264 make_only_dev(struct dev_ops
*ops
, int minor
, uid_t uid
, gid_t gid
,
265 int perms
, const char *fmt
, ...)
271 * compile the cdevsw and install the device
273 compile_dev_ops(ops
);
274 devfs_dev
= devfs_new_cdev(ops
, minor
, NULL
);
275 devfs_dev
->si_perms
= perms
;
276 devfs_dev
->si_uid
= uid
;
277 devfs_dev
->si_gid
= gid
;
280 * Set additional fields (XXX DEVFS interface goes here)
283 kvsnrprintf(devfs_dev
->si_name
, sizeof(devfs_dev
->si_name
),
287 reference_dev(devfs_dev
);
293 destroy_only_dev(cdev_t dev
)
301 * destroy_dev() removes the adhoc association for a device and revectors
302 * its ops to &dead_dev_ops.
304 * This routine releases the reference count associated with the ADHOC
305 * entry, plus releases the reference count held by the caller. What this
306 * means is that you should not call destroy_dev(make_dev(...)), because
307 * make_dev() does not bump the reference count (beyond what it needs to
308 * create the ad-hoc association). Any procedure that intends to destroy
309 * a device must have its own reference to it first.
312 destroy_dev(cdev_t dev
)
315 devfs_debug(DEVFS_DEBUG_DEBUG
,
316 "destroy_dev called for %s\n",
318 devfs_destroy_dev(dev
);
323 * Make sure all asynchronous disk and devfs related operations have
326 * Typically called prior to mountroot to ensure that all disks have
327 * been completely probed and on module unload to ensure that ops
328 * structures have been dereferenced.
340 make_dev_alias(cdev_t target
, const char *fmt
, ...)
346 kvasnrprintf(&name
, PATH_MAX
, 32, fmt
, ap
);
349 devfs_make_alias(name
, target
);
355 extern struct dev_ops default_dev_ops
;
358 make_autoclone_dev(struct dev_ops
*ops
, struct devfs_bitmap
*bitmap
,
359 d_clone_t
*nhandler
, uid_t uid
, gid_t gid
, int perms
, const char *fmt
, ...)
366 kvasnrprintf(&name
, PATH_MAX
, 32, fmt
, ap
);
370 devfs_clone_bitmap_init(bitmap
);
372 devfs_clone_handler_add(name
, nhandler
);
373 dev
= make_dev_covering(&default_dev_ops
, ops
, 0xffff00ff,
374 uid
, gid
, perms
, "%s", name
);
380 destroy_autoclone_dev(cdev_t dev
, struct devfs_bitmap
*bitmap
)
385 devfs_clone_handler_del(dev
->si_name
);
388 devfs_clone_bitmap_uninit(bitmap
);
395 * Add a reference to a device. Callers generally add their own references
396 * when they are going to store a device node in a variable for long periods
397 * of time, to prevent a disassociation from free()ing the node.
399 * Also note that a caller that intends to call destroy_dev() must first
400 * obtain a reference on the device. The ad-hoc reference you get with
401 * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
404 reference_dev(cdev_t dev
)
406 //kprintf("reference_dev\n");
409 sysref_get(&dev
->si_sysref
);
410 if (dev_ref_debug
& 2) {
411 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
412 dev
, devtoname(dev
), dev
->si_uminor
,
413 dev
->si_sysref
.refcnt
);
420 * release a reference on a device. The device will be terminated when the
421 * last reference has been released.
423 * NOTE: we must use si_umajor to figure out the original major number,
424 * because si_ops could already be pointing at dead_dev_ops.
427 release_dev(cdev_t dev
)
429 //kprintf("release_dev\n");
433 sysref_put(&dev
->si_sysref
);
437 devtoname(cdev_t dev
)
446 if (dev
->si_name
[0] == '#' || dev
->si_name
[0] == '\0') {
448 len
= sizeof(dev
->si_name
);
449 if ((dname
= dev_dname(dev
)) != NULL
)
450 ksnprintf(p
, len
, "#%s/", dname
);
452 ksnprintf(p
, len
, "#%d/", major(dev
));
456 if (mynor
< 0 || mynor
> 255)
457 ksnprintf(p
, len
, "%#x", (u_int
)mynor
);
459 ksnprintf(p
, len
, "%d", mynor
);
461 return (dev
->si_name
);