Replace NOCDEV with NULL. NOCDEV was ((void *)-1) and as inherited
[games.git] / sys / kern / kern_conf.c
CommitLineData
984263bc
MD
1/*-
2 * Parts Copyright (c) 1995 Terrence R. Lambert
3 * Copyright (c) 1995 Julian R. Elischer
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
19 * permission.
20 *
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
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $
028066b1 34 * $DragonFly: src/sys/kern/kern_conf.c,v 1.22 2007/05/08 02:31:42 dillon Exp $
984263bc
MD
35 */
36
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>
43#include <sys/conf.h>
44#include <sys/vnode.h>
45#include <sys/queue.h>
335dda38 46#include <sys/device.h>
984263bc
MD
47#include <machine/stdarg.h>
48
028066b1
MD
49#include <sys/sysref2.h>
50
984263bc
MD
51#define cdevsw_ALLOCSTART (NUMCDEVSW/2)
52
028066b1
MD
53static void cdev_terminate(struct cdev *dev);
54
b13267a5 55MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage");
984263bc 56
028066b1
MD
57/*
58 * SYSREF Integration - reference counting, allocation,
59 * sysid and syslink integration.
60 */
61static struct sysref_class cdev_sysref_class = {
62 .name = "cdev",
63 .mtype = M_DEVT,
64 .proto = SYSREF_PROTO_DEV,
65 .offset = offsetof(struct cdev, si_sysref),
66 .objsize = sizeof(struct cdev),
67 .mag_capacity = 32,
68 .flags = 0,
69 .ops = {
70 .terminate = (sysref_terminate_func_t)cdev_terminate
71 }
72};
73
984263bc
MD
74/*
75 * This is the number of hash-buckets. Experiements with 'real-life'
76 * udev_t's show that a prime halfway between two powers of two works
77 * best.
78 */
79#define DEVT_HASH 83
0de08e6d 80static LIST_HEAD(, cdev) dev_hash[DEVT_HASH];
984263bc
MD
81
82static int free_devt;
83SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
e4c9c0c8
MD
84int dev_ref_debug = 0;
85SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, "");
984263bc 86
984263bc 87/*
b13267a5 88 * cdev_t and u_dev_t primitives. Note that the major number is always
e4c9c0c8
MD
89 * extracted from si_udev, not from si_devsw, because si_devsw is replaced
90 * when a device is destroyed.
984263bc 91 */
984263bc 92int
028066b1 93major(cdev_t dev)
984263bc 94{
028066b1 95 if (dev == NULL)
984263bc 96 return NOUDEV;
028066b1 97 return((dev->si_udev >> 8) & 0xff);
984263bc
MD
98}
99
100int
028066b1 101minor(cdev_t dev)
984263bc 102{
028066b1 103 if (dev == NULL)
984263bc 104 return NOUDEV;
028066b1 105 return(dev->si_udev & 0xffff00ff);
984263bc
MD
106}
107
108int
028066b1 109lminor(cdev_t dev)
984263bc
MD
110{
111 int i;
112
028066b1 113 if (dev == NULL)
984263bc 114 return NOUDEV;
028066b1 115 i = minor(dev);
984263bc
MD
116 return ((i & 0xff) | (i >> 8));
117}
118
e4c9c0c8
MD
119/*
120 * This is a bit complex because devices are always created relative to
121 * a particular cdevsw, including 'hidden' cdevsw's (such as the raw device
122 * backing a disk subsystem overlay), so we have to compare both the
123 * devsw and udev fields to locate the correct device.
124 *
125 * The device is created if it does not already exist. If SI_ADHOC is not
126 * set the device will be referenced (once) and SI_ADHOC will be set.
127 * The caller must explicitly add additional references to the device if
128 * the caller wishes to track additional references.
a13d2b31
MD
129 *
130 * NOTE: The passed ops vector must normally match the device. This is
131 * because the kernel may create shadow devices that are INVISIBLE TO
132 * USERLAND. For example, the block device backing a disk is created
133 * as a shadow underneath the user-visible disklabel management device.
134 * Sometimes a device ops vector can be overridden, such as by /dev/console.
135 * In this case and this case only we allow a match when the ops vector
136 * otherwise would not match.
e4c9c0c8
MD
137 */
138static
b13267a5 139cdev_t
a13d2b31 140hashdev(struct dev_ops *ops, int x, int y, int allow_intercept)
984263bc 141{
0de08e6d 142 struct cdev *si;
984263bc
MD
143 udev_t udev;
144 int hash;
984263bc 145
e4c9c0c8 146 udev = makeudev(x, y);
984263bc
MD
147 hash = udev % DEVT_HASH;
148 LIST_FOREACH(si, &dev_hash[hash], si_hash) {
a13d2b31
MD
149 if (si->si_udev == udev) {
150 if (si->si_ops == ops)
151 return (si);
152 if (allow_intercept && (si->si_flags & SI_INTERCEPTED))
153 return (si);
d4569e90 154 }
984263bc 155 }
028066b1 156 si = sysref_alloc(&cdev_sysref_class);
fef8985e 157 si->si_ops = ops;
e4c9c0c8 158 si->si_flags |= SI_HASHED | SI_ADHOC;
984263bc
MD
159 si->si_udev = udev;
160 LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
028066b1 161 sysref_activate(&si->si_sysref);
fef8985e
MD
162
163 dev_dclone(si);
164 if (ops != &dead_dev_ops)
165 ++ops->head.refs;
e4c9c0c8 166 if (dev_ref_debug) {
6ea70f76 167 kprintf("create dev %p %s(minor=%08x) refs=%d\n",
e4c9c0c8 168 si, devtoname(si), uminor(si->si_udev),
028066b1 169 si->si_sysref.refcnt);
984263bc 170 }
e4c9c0c8 171 return (si);
984263bc
MD
172}
173
e4c9c0c8
MD
174/*
175 * Convert a device pointer to a device number
176 */
984263bc 177udev_t
028066b1 178dev2udev(cdev_t dev)
984263bc 179{
028066b1 180 if (dev == NULL)
984263bc 181 return NOUDEV;
028066b1 182 return (dev->si_udev);
984263bc
MD
183}
184
e4c9c0c8
MD
185/*
186 * Convert a device number to a device pointer. The device is referenced
187 * ad-hoc, meaning that the caller should call reference_dev() if it wishes
188 * to keep ahold of the returned structure long term.
189 *
190 * The returned device is associated with the currently installed cdevsw
028066b1 191 * for the requested major number. NULL is returned if the major number
e4c9c0c8
MD
192 * has not been registered.
193 */
b13267a5 194cdev_t
984263bc
MD
195udev2dev(udev_t x, int b)
196{
b13267a5 197 cdev_t dev;
fef8985e 198 struct dev_ops *ops;
984263bc 199
e4c9c0c8 200 if (x == NOUDEV || b != 0)
028066b1 201 return(NULL);
fef8985e
MD
202 ops = dev_ops_get(umajor(x), uminor(x));
203 if (ops == NULL)
028066b1 204 return(NULL);
d4569e90 205 dev = hashdev(ops, umajor(x), uminor(x), TRUE);
e4c9c0c8 206 return(dev);
984263bc
MD
207}
208
e4c9c0c8 209int
b13267a5 210dev_is_good(cdev_t dev)
e4c9c0c8 211{
028066b1 212 if (dev != NULL && dev->si_ops != &dead_dev_ops)
e4c9c0c8
MD
213 return(1);
214 return(0);
215}
216
217/*
218 * Various user device number extraction and conversion routines
219 */
984263bc
MD
220int
221uminor(udev_t dev)
222{
223 return(dev & 0xffff00ff);
224}
225
226int
227umajor(udev_t dev)
228{
229 return((dev & 0xff00) >> 8);
230}
231
232udev_t
233makeudev(int x, int y)
234{
235 return ((x << 8) | y);
236}
237
e4c9c0c8
MD
238/*
239 * Create an internal or external device.
240 *
241 * Device majors can be overloaded and used directly by the kernel without
242 * conflict, but userland will only see the particular device major that
fef8985e 243 * has been installed with dev_ops_add().
e4c9c0c8 244 *
32beb3ff
MD
245 * This routine creates and returns an unreferenced ad-hoc entry for the
246 * device which will remain intact until the device is destroyed. If the
247 * caller intends to store the device pointer it must call reference_dev()
248 * to retain a real reference to the device.
249 *
250 * If an entry already exists, this function will set (or override)
e4c9c0c8
MD
251 * its cred requirements and name (XXX DEVFS interface).
252 */
b13267a5 253cdev_t
fef8985e 254make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
e4c9c0c8 255 int perms, const char *fmt, ...)
984263bc 256{
b13267a5 257 cdev_t dev;
e2565a42 258 __va_list ap;
984263bc
MD
259 int i;
260
e4c9c0c8
MD
261 /*
262 * compile the cdevsw and install the device
263 */
fef8985e 264 compile_dev_ops(ops);
d4569e90 265 dev = hashdev(ops, ops->head.maj, minor, FALSE);
e4c9c0c8
MD
266
267 /*
268 * Set additional fields (XXX DEVFS interface goes here)
269 */
e2565a42 270 __va_start(ap, fmt);
379210cb 271 i = kvcprintf(fmt, NULL, dev->si_name, 32, ap);
984263bc 272 dev->si_name[i] = '\0';
e2565a42 273 __va_end(ap);
984263bc
MD
274
275 return (dev);
276}
277
217ff971 278/*
e4c9c0c8
MD
279 * This function is similar to make_dev() but no cred information or name
280 * need be specified.
281 */
b13267a5 282cdev_t
fef8985e 283make_adhoc_dev(struct dev_ops *ops, int minor)
e4c9c0c8 284{
b13267a5 285 cdev_t dev;
e4c9c0c8 286
d4569e90 287 dev = hashdev(ops, ops->head.maj, minor, FALSE);
e4c9c0c8
MD
288 return(dev);
289}
290
291/*
292 * This function is similar to make_dev() except the new device is created
293 * using an old device as a template.
294 */
b13267a5
MD
295cdev_t
296make_sub_dev(cdev_t odev, int minor)
e4c9c0c8 297{
b13267a5 298 cdev_t dev;
e4c9c0c8 299
d4569e90 300 dev = hashdev(odev->si_ops, umajor(odev->si_udev), minor, FALSE);
e4c9c0c8
MD
301
302 /*
303 * Copy cred requirements and name info XXX DEVFS.
304 */
305 if (dev->si_name[0] == 0 && odev->si_name[0])
306 bcopy(odev->si_name, dev->si_name, sizeof(dev->si_name));
307 return (dev);
308}
309
310/*
311 * destroy_dev() removes the adhoc association for a device and revectors
fef8985e 312 * its ops to &dead_dev_ops.
e4c9c0c8
MD
313 *
314 * This routine releases the reference count associated with the ADHOC
315 * entry, plus releases the reference count held by the caller. What this
316 * means is that you should not call destroy_dev(make_dev(...)), because
317 * make_dev() does not bump the reference count (beyond what it needs to
318 * create the ad-hoc association). Any procedure that intends to destroy
319 * a device must have its own reference to it first.
217ff971 320 */
984263bc 321void
b13267a5 322destroy_dev(cdev_t dev)
984263bc 323{
e4c9c0c8 324 int hash;
217ff971 325
028066b1 326 if (dev == NULL)
e4c9c0c8
MD
327 return;
328 if ((dev->si_flags & SI_ADHOC) == 0) {
329 release_dev(dev);
330 return;
331 }
332 if (dev_ref_debug) {
6ea70f76 333 kprintf("destroy dev %p %s(minor=%08x) refs=%d\n",
e4c9c0c8 334 dev, devtoname(dev), uminor(dev->si_udev),
028066b1 335 dev->si_sysref.refcnt);
e4c9c0c8 336 }
028066b1 337 if (dev->si_sysref.refcnt < 2) {
6ea70f76 338 kprintf("destroy_dev(): too few references on device! "
e4c9c0c8
MD
339 "%p %s(minor=%08x) refs=%d\n",
340 dev, devtoname(dev), uminor(dev->si_udev),
028066b1 341 dev->si_sysref.refcnt);
e4c9c0c8
MD
342 }
343 dev->si_flags &= ~SI_ADHOC;
344 if (dev->si_flags & SI_HASHED) {
345 hash = dev->si_udev % DEVT_HASH;
346 LIST_REMOVE(dev, si_hash);
347 dev->si_flags &= ~SI_HASHED;
348 }
32beb3ff
MD
349
350 /*
fef8985e
MD
351 * We have to release the ops reference before we replace the
352 * device switch with dead_dev_ops.
32beb3ff 353 */
fef8985e
MD
354 if (dead_dev_ops.d_strategy == NULL)
355 compile_dev_ops(&dead_dev_ops);
356 if (dev->si_ops && dev->si_ops != &dead_dev_ops)
357 dev_ops_release(dev->si_ops);
dd98570a
MD
358 dev->si_drv1 = NULL;
359 dev->si_drv2 = NULL;
fef8985e 360 dev->si_ops = &dead_dev_ops;
028066b1
MD
361 sysref_put(&dev->si_sysref); /* release adhoc association */
362 release_dev(dev); /* release callers reference */
e4c9c0c8
MD
363}
364
365/*
366 * Destroy all ad-hoc device associations associated with a domain within a
d969b138
MD
367 * device switch. Only the minor numbers are included in the mask/match
368 * values.
369 *
fef8985e 370 * Unlike the ops functions whos link structures do not contain
d969b138
MD
371 * any major bits, this function scans through the dev list via si_udev
372 * which is a 32 bit field that contains both major and minor bits.
373 * Because of this, we must mask the minor bits in the passed mask variable
374 * to allow -1 to be specified generically.
375 *
376 * The caller must not include any major bits in the match value.
e4c9c0c8
MD
377 */
378void
fef8985e 379destroy_all_devs(struct dev_ops *ops, u_int mask, u_int match)
e4c9c0c8
MD
380{
381 int i;
b13267a5
MD
382 cdev_t dev;
383 cdev_t ndev;
e4c9c0c8 384
d969b138 385 mask = uminor(mask);
e4c9c0c8
MD
386 for (i = 0; i < DEVT_HASH; ++i) {
387 ndev = LIST_FIRST(&dev_hash[i]);
388 while ((dev = ndev) != NULL) {
389 ndev = LIST_NEXT(dev, si_hash);
390 KKASSERT(dev->si_flags & SI_ADHOC);
fef8985e 391 if (dev->si_ops == ops &&
e4c9c0c8
MD
392 (dev->si_udev & mask) == match
393 ) {
028066b1 394 reference_dev(dev);
e4c9c0c8
MD
395 destroy_dev(dev);
396 }
397 }
398 }
399}
400
401/*
402 * Add a reference to a device. Callers generally add their own references
403 * when they are going to store a device node in a variable for long periods
404 * of time, to prevent a disassociation from free()ing the node.
405 *
406 * Also note that a caller that intends to call destroy_dev() must first
407 * obtain a reference on the device. The ad-hoc reference you get with
408 * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
409 */
b13267a5
MD
410cdev_t
411reference_dev(cdev_t dev)
e4c9c0c8 412{
028066b1
MD
413 if (dev != NULL) {
414 sysref_get(&dev->si_sysref);
e4c9c0c8 415 if (dev_ref_debug) {
6ea70f76 416 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
e4c9c0c8 417 dev, devtoname(dev), uminor(dev->si_udev),
028066b1 418 dev->si_sysref.refcnt);
e4c9c0c8
MD
419 }
420 }
421 return(dev);
422}
423
424/*
028066b1
MD
425 * release a reference on a device. The device will be terminated when the
426 * last reference has been released.
e4c9c0c8
MD
427 *
428 * NOTE: we must use si_udev to figure out the original (major, minor),
fef8985e 429 * because si_ops could already be pointing at dead_dev_ops.
e4c9c0c8
MD
430 */
431void
b13267a5 432release_dev(cdev_t dev)
e4c9c0c8 433{
028066b1 434 if (dev == NULL)
e4c9c0c8 435 return;
028066b1
MD
436 sysref_put(&dev->si_sysref);
437}
438
439static
440void
441cdev_terminate(struct cdev *dev)
442{
443 int messedup = 0;
444
e4c9c0c8 445 if (dev_ref_debug) {
6ea70f76 446 kprintf("release dev %p %s(minor=%08x) refs=%d\n",
e4c9c0c8 447 dev, devtoname(dev), uminor(dev->si_udev),
028066b1 448 dev->si_sysref.refcnt);
e4c9c0c8 449 }
028066b1
MD
450 if (dev->si_flags & SI_ADHOC) {
451 kprintf("Warning: illegal final release on ADHOC"
452 " device %p(%s), the device was never"
453 " destroyed!\n",
454 dev, devtoname(dev));
455 messedup = 1;
456 }
457 if (dev->si_flags & SI_HASHED) {
458 kprintf("Warning: last release on device, no call"
459 " to destroy_dev() was made! dev %p(%s)\n",
460 dev, devtoname(dev));
461 reference_dev(dev);
462 destroy_dev(dev);
463 messedup = 1;
464 }
465 if (SLIST_FIRST(&dev->si_hlist) != NULL) {
466 kprintf("Warning: last release on device, vnode"
467 " associations still exist! dev %p(%s)\n",
468 dev, devtoname(dev));
469 messedup = 1;
470 }
471 if (dev->si_ops && dev->si_ops != &dead_dev_ops) {
472 dev_ops_release(dev->si_ops);
473 dev->si_ops = NULL;
e4c9c0c8 474 }
028066b1
MD
475 if (messedup == 0)
476 sysref_put(&dev->si_sysref);
984263bc
MD
477}
478
479const char *
b13267a5 480devtoname(cdev_t dev)
984263bc 481{
984263bc 482 int mynor;
335dda38
MD
483 int len;
484 char *p;
485 const char *dname;
984263bc 486
028066b1 487 if (dev == NULL)
e4c9c0c8 488 return("#nodev");
984263bc
MD
489 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
490 p = dev->si_name;
335dda38
MD
491 len = sizeof(dev->si_name);
492 if ((dname = dev_dname(dev)) != NULL)
f8c7a42d 493 ksnprintf(p, len, "#%s/", dname);
984263bc 494 else
f8c7a42d 495 ksnprintf(p, len, "#%d/", major(dev));
335dda38 496 len -= strlen(p);
984263bc
MD
497 p += strlen(p);
498 mynor = minor(dev);
499 if (mynor < 0 || mynor > 255)
f8c7a42d 500 ksnprintf(p, len, "%#x", (u_int)mynor);
984263bc 501 else
f8c7a42d 502 ksnprintf(p, len, "%d", mynor);
984263bc
MD
503 }
504 return (dev->si_name);
505}
e4c9c0c8 506