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>
47 #include <machine/stdarg.h>
49 #include <sys/sysref2.h>
51 #include <vfs/devfs/devfs.h>
53 MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage");
56 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
57 int dev_ref_debug = 0;
58 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, "");
61 * cdev_t and u_dev_t primitives. Note that the major number is always
62 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
63 * when a device is destroyed.
70 return(dev->si_umajor);
78 return(dev->si_uminor);
82 * Compatibility function with old udev_t format to convert the
83 * non-consecutive minor space into a consecutive minor space.
95 return ((y & 0xff) | (y >> 8));
99 * Convert a device pointer to an old style device number. Return NOUDEV
100 * if the device is invalid or if the device (maj,min) cannot be converted
101 * to an old style udev_t.
109 return (udev_t)dev->si_inode;
113 * Convert a device number to a device pointer. The device is referenced
114 * ad-hoc, meaning that the caller should call reference_dev() if it wishes
115 * to keep ahold of the returned structure long term.
117 * The returned device is associated with the currently installed cdevsw
118 * for the requested major number. NULL is returned if the major number
119 * has not been registered.
122 udev2dev(udev_t x, int b)
124 if (x == NOUDEV || b != 0)
127 return devfs_find_device_by_udev(x);
131 dev_is_good(cdev_t dev)
133 if (dev != NULL && dev->si_ops != &dead_dev_ops)
139 * Various user device number extraction and conversion routines
146 return(dev & 0xffff00ff);
154 return((dev & 0xff00) >> 8);
158 makeudev(int x, int y)
160 if ((x & 0xffffff00) || (y & 0x0000ff00))
162 return ((x << 8) | y);
166 * Create an internal or external device.
168 * This routine creates and returns an unreferenced ad-hoc entry for the
169 * device which will remain intact until the device is destroyed. If the
170 * caller intends to store the device pointer it must call reference_dev()
171 * to retain a real reference to the device.
173 * If an entry already exists, this function will set (or override)
174 * its cred requirements and name (XXX DEVFS interface).
177 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
178 int perms, const char *fmt, ...)
183 char dev_name[PATH_MAX+1];
186 * compile the cdevsw and install the device
188 compile_dev_ops(ops);
191 * Set additional fields (XXX DEVFS interface goes here)
194 i = kvcprintf(fmt, NULL, dev_name, 32, ap);
199 if ((devfs_dev = devfs_find_device_by_name(dev_name)) != NULL) {
200 kprintf("make_dev: Device %s already exists, returning old dev without creating new node\n", dev_name);
205 devfs_dev = devfs_new_cdev(ops, minor);
206 memcpy(devfs_dev->si_name, dev_name, i+1);
208 devfs_debug(DEVFS_DEBUG_INFO,
209 "make_dev called for %s\n",
211 devfs_create_dev(devfs_dev, uid, gid, perms);
218 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
219 int perms, const char *fmt, ...)
227 * compile the cdevsw and install the device
229 compile_dev_ops(ops);
230 devfs_dev = devfs_new_cdev(ops, minor);
233 * Set additional fields (XXX DEVFS interface goes here)
236 i = kvcprintf(fmt, NULL, devfs_dev->si_name, 32, ap);
237 devfs_dev->si_name[i] = '\0';
241 devfs_create_dev(devfs_dev, uid, gid, perms);
248 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
249 int perms, const char *fmt, ...)
257 * compile the cdevsw and install the device
259 compile_dev_ops(ops);
260 devfs_dev = devfs_new_cdev(ops, minor);
261 devfs_dev->si_perms = perms;
262 devfs_dev->si_uid = uid;
263 devfs_dev->si_gid = gid;
266 * Set additional fields (XXX DEVFS interface goes here)
269 i = kvcprintf(fmt, NULL, devfs_dev->si_name, 32, ap);
270 devfs_dev->si_name[i] = '\0';
273 reference_dev(devfs_dev);
279 destroy_only_dev(cdev_t dev)
287 * destroy_dev() removes the adhoc association for a device and revectors
288 * its ops to &dead_dev_ops.
290 * This routine releases the reference count associated with the ADHOC
291 * entry, plus releases the reference count held by the caller. What this
292 * means is that you should not call destroy_dev(make_dev(...)), because
293 * make_dev() does not bump the reference count (beyond what it needs to
294 * create the ad-hoc association). Any procedure that intends to destroy
295 * a device must have its own reference to it first.
298 destroy_dev(cdev_t dev)
301 devfs_debug(DEVFS_DEBUG_DEBUG,
302 "destroy_dev called for %s\n",
304 devfs_destroy_dev(dev);
309 make_dev_alias(cdev_t target, const char *fmt, ...)
311 char name[PATH_MAX + 1];
316 i = kvcprintf(fmt, NULL, name, 32, ap);
320 devfs_make_alias(name, target);
325 extern struct dev_ops default_dev_ops;
328 make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap,
329 d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
332 char name[PATH_MAX + 1];
337 i = kvcprintf(fmt, NULL, name, 32, ap);
342 devfs_clone_bitmap_init(bitmap);
344 devfs_clone_handler_add(name, nhandler);
345 dev = make_dev(&default_dev_ops, 0xffff00ff, uid, gid, perms, name);
351 destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap)
356 devfs_clone_handler_del(dev->si_name);
359 devfs_clone_bitmap_uninit(bitmap);
366 * Add a reference to a device. Callers generally add their own references
367 * when they are going to store a device node in a variable for long periods
368 * of time, to prevent a disassociation from free()ing the node.
370 * Also note that a caller that intends to call destroy_dev() must first
371 * obtain a reference on the device. The ad-hoc reference you get with
372 * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
375 reference_dev(cdev_t dev)
377 //kprintf("reference_dev\n");
380 sysref_get(&dev->si_sysref);
381 if (dev_ref_debug & 2) {
382 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
383 dev, devtoname(dev), dev->si_uminor,
384 dev->si_sysref.refcnt);
391 * release a reference on a device. The device will be terminated when the
392 * last reference has been released.
394 * NOTE: we must use si_umajor to figure out the original major number,
395 * because si_ops could already be pointing at dead_dev_ops.
398 release_dev(cdev_t dev)
400 //kprintf("release_dev\n");
404 sysref_put(&dev->si_sysref);
408 devtoname(cdev_t dev)
417 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
419 len = sizeof(dev->si_name);
420 if ((dname = dev_dname(dev)) != NULL)
421 ksnprintf(p, len, "#%s/", dname);
423 ksnprintf(p, len, "#%d/", major(dev));
427 if (mynor < 0 || mynor > 255)
428 ksnprintf(p, len, "%#x", (u_int)mynor);
430 ksnprintf(p, len, "%d", mynor);
432 return (dev->si_name);