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 static void cdev_terminate(struct cdev
*dev
);
53 MALLOC_DEFINE(M_DEVT
, "cdev_t", "dev_t storage");
56 * SYSREF Integration - reference counting, allocation,
57 * sysid and syslink integration.
59 static struct sysref_class cdev_sysref_class
= {
62 .proto
= SYSREF_PROTO_DEV
,
63 .offset
= offsetof(struct cdev
, si_sysref
),
64 .objsize
= sizeof(struct cdev
),
68 .terminate
= (sysref_terminate_func_t
)cdev_terminate
73 * This is the number of hash-buckets. Experiements with 'real-life'
74 * udev_t's show that a prime halfway between two powers of two works
77 #define DEVT_HASH 128 /* must be power of 2 */
78 static LIST_HEAD(, cdev
) dev_hash
[DEVT_HASH
];
81 SYSCTL_INT(_debug
, OID_AUTO
, free_devt
, CTLFLAG_RW
, &free_devt
, 0, "");
82 int dev_ref_debug
= 0;
83 SYSCTL_INT(_debug
, OID_AUTO
, dev_refs
, CTLFLAG_RW
, &dev_ref_debug
, 0, "");
86 * cdev_t and u_dev_t primitives. Note that the major number is always
87 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
88 * when a device is destroyed.
95 return(dev
->si_umajor
);
103 return(dev
->si_uminor
);
107 * Compatibility function with old udev_t format to convert the
108 * non-consecutive minor space into a consecutive minor space.
120 return ((y
& 0xff) | (y
>> 8));
124 * This is a bit complex because devices are always created relative to
125 * a particular cdevsw, including 'hidden' cdevsw's (such as the raw device
126 * backing a disk subsystem overlay), so we have to compare both the
127 * devsw and udev fields to locate the correct device.
129 * The device is created if it does not already exist. If SI_ADHOC is not
130 * set the device will be referenced (once) and SI_ADHOC will be set.
131 * The caller must explicitly add additional references to the device if
132 * the caller wishes to track additional references.
134 * NOTE: The passed ops vector must normally match the device. This is
135 * because the kernel may create shadow devices that are INVISIBLE TO
136 * USERLAND. For example, the block device backing a disk is created
137 * as a shadow underneath the user-visible disklabel management device.
138 * Sometimes a device ops vector can be overridden, such as by /dev/console.
139 * In this case and this case only we allow a match when the ops vector
140 * otherwise would not match.
144 __devthash(int x
, int y
)
146 return(((x
<< 2) ^ y
) & (DEVT_HASH
- 1));
151 hashdev(struct dev_ops
*ops
, int x
, int y
, int allow_intercept
)
156 hash
= __devthash(x
, y
);
157 LIST_FOREACH(si
, &dev_hash
[hash
], si_hash
) {
158 if (si
->si_umajor
== x
&& si
->si_uminor
== y
) {
159 if (si
->si_ops
== ops
)
161 if (allow_intercept
&& (si
->si_flags
& SI_INTERCEPTED
))
165 si
= sysref_alloc(&cdev_sysref_class
);
167 si
->si_flags
|= SI_HASHED
| SI_ADHOC
;
170 LIST_INSERT_HEAD(&dev_hash
[hash
], si
, si_hash
);
171 sysref_activate(&si
->si_sysref
);
174 if (ops
!= &dead_dev_ops
)
177 kprintf("create dev %p %s(minor=%08x) refs=%d\n",
178 si
, devtoname(si
), y
,
179 si
->si_sysref
.refcnt
);
185 * Convert a device pointer to an old style device number. Return NOUDEV
186 * if the device is invalid or if the device (maj,min) cannot be converted
187 * to an old style udev_t.
194 if ((dev
->si_umajor
& 0xffffff00) ||
195 (dev
->si_uminor
& 0x0000ff00)) {
198 return((dev
->si_umajor
<< 8) | dev
->si_uminor
);
202 * Convert a device number to a device pointer. The device is referenced
203 * ad-hoc, meaning that the caller should call reference_dev() if it wishes
204 * to keep ahold of the returned structure long term.
206 * The returned device is associated with the currently installed cdevsw
207 * for the requested major number. NULL is returned if the major number
208 * has not been registered.
211 udev2dev(udev_t x
, int b
)
216 if (x
== NOUDEV
|| b
!= 0)
218 ops
= dev_ops_get(umajor(x
), uminor(x
));
221 dev
= hashdev(ops
, umajor(x
), uminor(x
), TRUE
);
226 dev_is_good(cdev_t dev
)
228 if (dev
!= NULL
&& dev
->si_ops
!= &dead_dev_ops
)
234 * Various user device number extraction and conversion routines
241 return(dev
& 0xffff00ff);
249 return((dev
& 0xff00) >> 8);
253 makeudev(int x
, int y
)
255 if ((x
& 0xffffff00) || (y
& 0x0000ff00))
257 return ((x
<< 8) | y
);
261 * Create an internal or external device.
263 * Device majors can be overloaded and used directly by the kernel without
264 * conflict, but userland will only see the particular device major that
265 * has been installed with dev_ops_add().
267 * This routine creates and returns an unreferenced ad-hoc entry for the
268 * device which will remain intact until the device is destroyed. If the
269 * caller intends to store the device pointer it must call reference_dev()
270 * to retain a real reference to the device.
272 * If an entry already exists, this function will set (or override)
273 * its cred requirements and name (XXX DEVFS interface).
276 make_dev(struct dev_ops
*ops
, int minor
, uid_t uid
, gid_t gid
,
277 int perms
, const char *fmt
, ...)
284 * compile the cdevsw and install the device
286 compile_dev_ops(ops
);
287 dev
= hashdev(ops
, ops
->head
.maj
, minor
, FALSE
);
290 * Set additional fields (XXX DEVFS interface goes here)
293 i
= kvcprintf(fmt
, NULL
, dev
->si_name
, 32, ap
);
294 dev
->si_name
[i
] = '\0';
301 * This function is similar to make_dev() but no cred information or name
305 make_adhoc_dev(struct dev_ops
*ops
, int minor
)
309 dev
= hashdev(ops
, ops
->head
.maj
, minor
, FALSE
);
314 * This function is similar to make_dev() except the new device is created
315 * using an old device as a template.
318 make_sub_dev(cdev_t odev
, int minor
)
322 dev
= hashdev(odev
->si_ops
, odev
->si_umajor
, minor
, FALSE
);
325 * Copy cred requirements and name info XXX DEVFS.
327 if (dev
->si_name
[0] == 0 && odev
->si_name
[0])
328 bcopy(odev
->si_name
, dev
->si_name
, sizeof(dev
->si_name
));
333 get_dev(int x
, int y
)
340 ops
= dev_ops_get(x
, y
);
343 dev
= hashdev(ops
, x
, y
, TRUE
);
348 * destroy_dev() removes the adhoc association for a device and revectors
349 * its ops to &dead_dev_ops.
351 * This routine releases the reference count associated with the ADHOC
352 * entry, plus releases the reference count held by the caller. What this
353 * means is that you should not call destroy_dev(make_dev(...)), because
354 * make_dev() does not bump the reference count (beyond what it needs to
355 * create the ad-hoc association). Any procedure that intends to destroy
356 * a device must have its own reference to it first.
359 destroy_dev(cdev_t dev
)
365 if ((dev
->si_flags
& SI_ADHOC
) == 0) {
370 kprintf("destroy dev %p %s(minor=%08x) refs=%d\n",
371 dev
, devtoname(dev
), dev
->si_uminor
,
372 dev
->si_sysref
.refcnt
);
374 if (dev
->si_sysref
.refcnt
< 2) {
375 kprintf("destroy_dev(): too few references on device! "
376 "%p %s(minor=%08x) refs=%d\n",
377 dev
, devtoname(dev
), dev
->si_uminor
,
378 dev
->si_sysref
.refcnt
);
380 dev
->si_flags
&= ~SI_ADHOC
;
381 if (dev
->si_flags
& SI_HASHED
) {
382 hash
= __devthash(dev
->si_umajor
, dev
->si_uminor
);
383 LIST_REMOVE(dev
, si_hash
);
384 dev
->si_flags
&= ~SI_HASHED
;
388 * We have to release the ops reference before we replace the
389 * device switch with dead_dev_ops.
391 if (dead_dev_ops
.d_strategy
== NULL
)
392 compile_dev_ops(&dead_dev_ops
);
393 if (dev
->si_ops
&& dev
->si_ops
!= &dead_dev_ops
)
394 dev_ops_release(dev
->si_ops
);
397 dev
->si_ops
= &dead_dev_ops
;
398 sysref_put(&dev
->si_sysref
); /* release adhoc association */
399 release_dev(dev
); /* release callers reference */
403 * Destroy all ad-hoc device associations associated with a domain within a
404 * device switch. Only the minor numbers are included in the mask/match
407 * Unlike the ops functions whos link structures do not contain
408 * any major bits, this function scans through the dev list via
409 * si_umajor/si_uminor.
411 * The caller must not include any major bits in the match value.
414 destroy_all_devs(struct dev_ops
*ops
, u_int mask
, u_int match
)
420 for (i
= 0; i
< DEVT_HASH
; ++i
) {
421 ndev
= LIST_FIRST(&dev_hash
[i
]);
422 while ((dev
= ndev
) != NULL
) {
423 ndev
= LIST_NEXT(dev
, si_hash
);
424 KKASSERT(dev
->si_flags
& SI_ADHOC
);
425 if (dev
->si_ops
== ops
&&
426 ((u_int
)dev
->si_uminor
& mask
) == match
436 * Add a reference to a device. Callers generally add their own references
437 * when they are going to store a device node in a variable for long periods
438 * of time, to prevent a disassociation from free()ing the node.
440 * Also note that a caller that intends to call destroy_dev() must first
441 * obtain a reference on the device. The ad-hoc reference you get with
442 * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
445 reference_dev(cdev_t dev
)
448 sysref_get(&dev
->si_sysref
);
450 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
451 dev
, devtoname(dev
), dev
->si_uminor
,
452 dev
->si_sysref
.refcnt
);
459 * release a reference on a device. The device will be terminated when the
460 * last reference has been released.
462 * NOTE: we must use si_umajor to figure out the original major number,
463 * because si_ops could already be pointing at dead_dev_ops.
466 release_dev(cdev_t dev
)
470 sysref_put(&dev
->si_sysref
);
475 cdev_terminate(struct cdev
*dev
)
480 kprintf("release dev %p %s(minor=%08x) refs=%d\n",
481 dev
, devtoname(dev
), dev
->si_uminor
,
482 dev
->si_sysref
.refcnt
);
484 if (dev
->si_flags
& SI_ADHOC
) {
485 kprintf("Warning: illegal final release on ADHOC"
486 " device %p(%s), the device was never"
488 dev
, devtoname(dev
));
491 if (dev
->si_flags
& SI_HASHED
) {
492 kprintf("Warning: last release on device, no call"
493 " to destroy_dev() was made! dev %p(%s)\n",
494 dev
, devtoname(dev
));
499 if (SLIST_FIRST(&dev
->si_hlist
) != NULL
) {
500 kprintf("Warning: last release on device, vnode"
501 " associations still exist! dev %p(%s)\n",
502 dev
, devtoname(dev
));
505 if (dev
->si_ops
&& dev
->si_ops
!= &dead_dev_ops
) {
506 dev_ops_release(dev
->si_ops
);
510 sysref_put(&dev
->si_sysref
);
514 devtoname(cdev_t dev
)
523 if (dev
->si_name
[0] == '#' || dev
->si_name
[0] == '\0') {
525 len
= sizeof(dev
->si_name
);
526 if ((dname
= dev_dname(dev
)) != NULL
)
527 ksnprintf(p
, len
, "#%s/", dname
);
529 ksnprintf(p
, len
, "#%d/", major(dev
));
533 if (mynor
< 0 || mynor
> 255)
534 ksnprintf(p
, len
, "%#x", (u_int
)mynor
);
536 ksnprintf(p
, len
, "%d", mynor
);
538 return (dev
->si_name
);