Deleted Added
full compact
kern_conf.c (90736) kern_conf.c (90737)
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 *
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: head/sys/kern/kern_conf.c 90736 2002-02-16 17:35:05Z green $
33 * $FreeBSD: head/sys/kern/kern_conf.c 90737 2002-02-16 17:44:43Z green $
34 */
35
36#include <sys/param.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
34 */
35
36#include <sys/param.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
39#include <sys/lock.h>
40#include <sys/mutex.h>
39#include <sys/sysctl.h>
40#include <sys/module.h>
41#include <sys/malloc.h>
42#include <sys/conf.h>
43#include <sys/vnode.h>
44#include <sys/queue.h>
45#include <sys/ctype.h>
46#include <machine/stdarg.h>
47
48#define cdevsw_ALLOCSTART (NUMCDEVSW/2)
49
50static struct cdevsw *cdevsw[NUMCDEVSW];
51
52static MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
53
54/*
55 * This is the number of hash-buckets. Experiements with 'real-life'
56 * udev_t's show that a prime halfway between two powers of two works
57 * best.
58 */
59#define DEVT_HASH 83
60
61/* The number of dev_t's we can create before malloc(9) kick in. */
62#define DEVT_STASH 50
63
64static struct specinfo devt_stash[DEVT_STASH];
65
66static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH];
67
68static LIST_HEAD(, specinfo) dev_free;
69
70devfs_create_t *devfs_create_hook;
71devfs_destroy_t *devfs_destroy_hook;
72int devfs_present;
73
74static int ready_for_devs;
75
76static int free_devt;
77SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
78
79/* XXX: This is a hack */
80void disk_dev_synth(dev_t dev);
81
82struct cdevsw *
83devsw(dev_t dev)
84{
85 if (dev->si_devsw)
86 return (dev->si_devsw);
87 /* XXX: Hack around our backwards disk code */
88 disk_dev_synth(dev);
89 if (dev->si_devsw)
90 return (dev->si_devsw);
91 if (devfs_present)
92 return (NULL);
93 return(cdevsw[major(dev)]);
94}
95
96/*
97 * Add a cdevsw entry
98 */
99
100int
101cdevsw_add(struct cdevsw *newentry)
102{
103
104 if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
105 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
106 newentry->d_name, newentry->d_maj);
107 return (EINVAL);
108 }
109
110 if (cdevsw[newentry->d_maj]) {
111 printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
112 newentry->d_name, cdevsw[newentry->d_maj]->d_name);
113 }
114
115 cdevsw[newentry->d_maj] = newentry;
116
117 return (0);
118}
119
120/*
121 * Remove a cdevsw entry
122 */
123
124int
125cdevsw_remove(struct cdevsw *oldentry)
126{
127 if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
128 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
129 oldentry->d_name, oldentry->d_maj);
130 return EINVAL;
131 }
132
133 cdevsw[oldentry->d_maj] = NULL;
134
135 return 0;
136}
137
138/*
139 * dev_t and u_dev_t primitives
140 */
141
142int
143major(dev_t x)
144{
145 if (x == NODEV)
146 return NOUDEV;
147 return((x->si_udev >> 8) & 0xff);
148}
149
150int
151minor(dev_t x)
152{
153 if (x == NODEV)
154 return NOUDEV;
155 return(x->si_udev & 0xffff00ff);
156}
157
158int
159dev2unit(dev_t x)
160{
161 int i;
162
163 if (x == NODEV)
164 return NOUDEV;
165 i = minor(x);
166 return ((i & 0xff) | (i >> 8));
167}
168
169int
170unit2minor(int unit)
171{
172
173 KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
174 return ((unit & 0xff) | ((unit << 8) & ~0xffff));
175}
176
177static dev_t
178allocdev(void)
179{
180 static int stashed;
181 struct specinfo *si;
182
183 if (stashed >= DEVT_STASH) {
184 MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
185 M_USE_RESERVE | M_ZERO);
186 } else if (LIST_FIRST(&dev_free)) {
187 si = LIST_FIRST(&dev_free);
188 LIST_REMOVE(si, si_hash);
189 } else {
190 si = devt_stash + stashed++;
191 bzero(si, sizeof *si);
192 si->si_flags |= SI_STASHED;
193 }
194 LIST_INIT(&si->si_children);
195 TAILQ_INIT(&si->si_snapshots);
196 return (si);
197}
198
199dev_t
200makedev(int x, int y)
201{
202 struct specinfo *si;
203 udev_t udev;
204 int hash;
205
206 if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
207 panic("makedev of NOUDEV");
208 udev = (x << 8) | y;
209 hash = udev % DEVT_HASH;
210 LIST_FOREACH(si, &dev_hash[hash], si_hash) {
211 if (si->si_udev == udev)
212 return (si);
213 }
214 si = allocdev();
215 si->si_udev = udev;
216 LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
217 return (si);
218}
219
220void
221freedev(dev_t dev)
222{
223
224 if (!free_devt)
225 return;
226 if (SLIST_FIRST(&dev->si_hlist))
227 return;
228 if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
229 return;
230 LIST_REMOVE(dev, si_hash);
231 if (dev->si_flags & SI_STASHED) {
232 bzero(dev, sizeof(*dev));
233 dev->si_flags |= SI_STASHED;
234 LIST_INSERT_HEAD(&dev_free, dev, si_hash);
235 } else {
236 FREE(dev, M_DEVT);
237 }
238}
239
240udev_t
241dev2udev(dev_t x)
242{
243 if (x == NODEV)
244 return NOUDEV;
245 return (x->si_udev);
246}
247
248dev_t
249udev2dev(udev_t x, int b)
250{
251
252 if (x == NOUDEV)
253 return (NODEV);
254 switch (b) {
255 case 0:
256 return makedev(umajor(x), uminor(x));
257 case 1:
258 return (NODEV);
259 default:
260 Debugger("udev2dev(...,X)");
261 return NODEV;
262 }
263}
264
265int
266uminor(udev_t dev)
267{
268 return(dev & 0xffff00ff);
269}
270
271int
272umajor(udev_t dev)
273{
274 return((dev & 0xff00) >> 8);
275}
276
277udev_t
278makeudev(int x, int y)
279{
280 return ((x << 8) | y);
281}
282
283dev_t
284make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
285{
286 dev_t dev;
287 va_list ap;
288 int i;
289
290 KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj,
291 ("Invalid minor (%d) in make_dev", minor));
292
293 if (!ready_for_devs) {
294 printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n",
295 fmt);
296 /* XXX panic here once drivers are cleaned up */
297 }
298
299 dev = makedev(devsw->d_maj, minor);
300 if (dev->si_flags & SI_NAMED) {
301 printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n",
302 dev->si_name);
303 panic("don't do that");
304 return (dev);
305 }
306 va_start(ap, fmt);
307 i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
308 dev->si_name[i] = '\0';
309 va_end(ap);
310 dev->si_devsw = devsw;
311 dev->si_uid = uid;
312 dev->si_gid = gid;
313 dev->si_mode = perms;
314 dev->si_flags |= SI_NAMED;
315
316 if (devfs_create_hook)
317 devfs_create_hook(dev);
318 return (dev);
319}
320
321int
322dev_named(dev_t pdev, const char *name)
323{
324 dev_t cdev;
325
326 if (strcmp(devtoname(pdev), name) == 0)
327 return (1);
328 LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
329 if (strcmp(devtoname(cdev), name) == 0)
330 return (1);
331 return (0);
332}
333
334void
335dev_depends(dev_t pdev, dev_t cdev)
336{
337
338 cdev->si_parent = pdev;
339 cdev->si_flags |= SI_CHILD;
340 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
341}
342
343dev_t
344make_dev_alias(dev_t pdev, const char *fmt, ...)
345{
346 dev_t dev;
347 va_list ap;
348 int i;
349
350 dev = allocdev();
351 dev->si_flags |= SI_ALIAS;
352 dev->si_flags |= SI_NAMED;
353 dev_depends(pdev, dev);
354 va_start(ap, fmt);
355 i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
356 dev->si_name[i] = '\0';
357 va_end(ap);
358
359 if (devfs_create_hook)
360 devfs_create_hook(dev);
361 return (dev);
362}
363
364void
365revoke_and_destroy_dev(dev_t dev)
366{
367 struct vnode *vp;
368
369 GIANT_REQUIRED;
370
371 vp = SLIST_FIRST(&dev->si_hlist);
372 if (vp != NULL)
373 VOP_REVOKE(vp, REVOKEALL);
374 destroy_dev(dev);
375}
376
377void
378destroy_dev(dev_t dev)
379{
380
381 if (!(dev->si_flags & SI_NAMED)) {
382 printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
383 major(dev), minor(dev));
384 panic("don't do that");
385 return;
386 }
387
388 if (devfs_destroy_hook)
389 devfs_destroy_hook(dev);
390 if (dev->si_flags & SI_CHILD) {
391 LIST_REMOVE(dev, si_siblings);
392 dev->si_flags &= ~SI_CHILD;
393 }
394 while (!LIST_EMPTY(&dev->si_children))
395 destroy_dev(LIST_FIRST(&dev->si_children));
396 dev->si_drv1 = 0;
397 dev->si_drv2 = 0;
398 dev->si_devsw = 0;
399 dev->si_flags &= ~SI_NAMED;
400 dev->si_flags &= ~SI_ALIAS;
401 freedev(dev);
402}
403
404const char *
405devtoname(dev_t dev)
406{
407 char *p;
408 int mynor;
409
410 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
411 p = dev->si_name;
412 if (devsw(dev))
413 sprintf(p, "#%s/", devsw(dev)->d_name);
414 else
415 sprintf(p, "#%d/", major(dev));
416 p += strlen(p);
417 mynor = minor(dev);
418 if (mynor < 0 || mynor > 255)
419 sprintf(p, "%#x", (u_int)mynor);
420 else
421 sprintf(p, "%d", mynor);
422 }
423 return (dev->si_name);
424}
425
426int
427dev_stdclone(char *name, char **namep, char *stem, int *unit)
428{
429 int u, i;
430
431 i = strlen(stem);
432 if (bcmp(stem, name, i) != 0)
433 return (0);
434 if (!isdigit(name[i]))
435 return (0);
436 u = 0;
437 if (name[i] == '0' && isdigit(name[i+1]))
438 return (0);
439 while (isdigit(name[i])) {
440 u *= 10;
441 u += name[i++] - '0';
442 }
443 *unit = u;
444 if (namep)
445 *namep = &name[i];
446 if (name[i])
447 return (2);
448 return (1);
449}
450
451/*
452 * Helper sysctl for devname(3). We're given a {u}dev_t and return
453 * the name, if any, registered by the device driver.
454 */
455static int
456sysctl_devname(SYSCTL_HANDLER_ARGS)
457{
458 int error;
459 udev_t ud;
460 dev_t dev;
461
462 error = SYSCTL_IN(req, &ud, sizeof (ud));
463 if (error)
464 return (error);
465 if (ud == NOUDEV)
466 return(EINVAL);
467 dev = makedev(umajor(ud), uminor(ud));
468 if (dev->si_name[0] == '\0')
469 error = ENOENT;
470 else
471 error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
472 freedev(dev);
473 return (error);
474}
475
476SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
477 NULL, 0, sysctl_devname, "", "devname(3) handler");
478
479/*
480 * Set ready_for_devs; prior to this point, device creation is not allowed.
481 */
482static void
483dev_set_ready(void *junk)
484{
485 ready_for_devs = 1;
486}
487
488SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL);
41#include <sys/sysctl.h>
42#include <sys/module.h>
43#include <sys/malloc.h>
44#include <sys/conf.h>
45#include <sys/vnode.h>
46#include <sys/queue.h>
47#include <sys/ctype.h>
48#include <machine/stdarg.h>
49
50#define cdevsw_ALLOCSTART (NUMCDEVSW/2)
51
52static struct cdevsw *cdevsw[NUMCDEVSW];
53
54static MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
55
56/*
57 * This is the number of hash-buckets. Experiements with 'real-life'
58 * udev_t's show that a prime halfway between two powers of two works
59 * best.
60 */
61#define DEVT_HASH 83
62
63/* The number of dev_t's we can create before malloc(9) kick in. */
64#define DEVT_STASH 50
65
66static struct specinfo devt_stash[DEVT_STASH];
67
68static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH];
69
70static LIST_HEAD(, specinfo) dev_free;
71
72devfs_create_t *devfs_create_hook;
73devfs_destroy_t *devfs_destroy_hook;
74int devfs_present;
75
76static int ready_for_devs;
77
78static int free_devt;
79SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
80
81/* XXX: This is a hack */
82void disk_dev_synth(dev_t dev);
83
84struct cdevsw *
85devsw(dev_t dev)
86{
87 if (dev->si_devsw)
88 return (dev->si_devsw);
89 /* XXX: Hack around our backwards disk code */
90 disk_dev_synth(dev);
91 if (dev->si_devsw)
92 return (dev->si_devsw);
93 if (devfs_present)
94 return (NULL);
95 return(cdevsw[major(dev)]);
96}
97
98/*
99 * Add a cdevsw entry
100 */
101
102int
103cdevsw_add(struct cdevsw *newentry)
104{
105
106 if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
107 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
108 newentry->d_name, newentry->d_maj);
109 return (EINVAL);
110 }
111
112 if (cdevsw[newentry->d_maj]) {
113 printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
114 newentry->d_name, cdevsw[newentry->d_maj]->d_name);
115 }
116
117 cdevsw[newentry->d_maj] = newentry;
118
119 return (0);
120}
121
122/*
123 * Remove a cdevsw entry
124 */
125
126int
127cdevsw_remove(struct cdevsw *oldentry)
128{
129 if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
130 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
131 oldentry->d_name, oldentry->d_maj);
132 return EINVAL;
133 }
134
135 cdevsw[oldentry->d_maj] = NULL;
136
137 return 0;
138}
139
140/*
141 * dev_t and u_dev_t primitives
142 */
143
144int
145major(dev_t x)
146{
147 if (x == NODEV)
148 return NOUDEV;
149 return((x->si_udev >> 8) & 0xff);
150}
151
152int
153minor(dev_t x)
154{
155 if (x == NODEV)
156 return NOUDEV;
157 return(x->si_udev & 0xffff00ff);
158}
159
160int
161dev2unit(dev_t x)
162{
163 int i;
164
165 if (x == NODEV)
166 return NOUDEV;
167 i = minor(x);
168 return ((i & 0xff) | (i >> 8));
169}
170
171int
172unit2minor(int unit)
173{
174
175 KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
176 return ((unit & 0xff) | ((unit << 8) & ~0xffff));
177}
178
179static dev_t
180allocdev(void)
181{
182 static int stashed;
183 struct specinfo *si;
184
185 if (stashed >= DEVT_STASH) {
186 MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
187 M_USE_RESERVE | M_ZERO);
188 } else if (LIST_FIRST(&dev_free)) {
189 si = LIST_FIRST(&dev_free);
190 LIST_REMOVE(si, si_hash);
191 } else {
192 si = devt_stash + stashed++;
193 bzero(si, sizeof *si);
194 si->si_flags |= SI_STASHED;
195 }
196 LIST_INIT(&si->si_children);
197 TAILQ_INIT(&si->si_snapshots);
198 return (si);
199}
200
201dev_t
202makedev(int x, int y)
203{
204 struct specinfo *si;
205 udev_t udev;
206 int hash;
207
208 if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
209 panic("makedev of NOUDEV");
210 udev = (x << 8) | y;
211 hash = udev % DEVT_HASH;
212 LIST_FOREACH(si, &dev_hash[hash], si_hash) {
213 if (si->si_udev == udev)
214 return (si);
215 }
216 si = allocdev();
217 si->si_udev = udev;
218 LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
219 return (si);
220}
221
222void
223freedev(dev_t dev)
224{
225
226 if (!free_devt)
227 return;
228 if (SLIST_FIRST(&dev->si_hlist))
229 return;
230 if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
231 return;
232 LIST_REMOVE(dev, si_hash);
233 if (dev->si_flags & SI_STASHED) {
234 bzero(dev, sizeof(*dev));
235 dev->si_flags |= SI_STASHED;
236 LIST_INSERT_HEAD(&dev_free, dev, si_hash);
237 } else {
238 FREE(dev, M_DEVT);
239 }
240}
241
242udev_t
243dev2udev(dev_t x)
244{
245 if (x == NODEV)
246 return NOUDEV;
247 return (x->si_udev);
248}
249
250dev_t
251udev2dev(udev_t x, int b)
252{
253
254 if (x == NOUDEV)
255 return (NODEV);
256 switch (b) {
257 case 0:
258 return makedev(umajor(x), uminor(x));
259 case 1:
260 return (NODEV);
261 default:
262 Debugger("udev2dev(...,X)");
263 return NODEV;
264 }
265}
266
267int
268uminor(udev_t dev)
269{
270 return(dev & 0xffff00ff);
271}
272
273int
274umajor(udev_t dev)
275{
276 return((dev & 0xff00) >> 8);
277}
278
279udev_t
280makeudev(int x, int y)
281{
282 return ((x << 8) | y);
283}
284
285dev_t
286make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
287{
288 dev_t dev;
289 va_list ap;
290 int i;
291
292 KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj,
293 ("Invalid minor (%d) in make_dev", minor));
294
295 if (!ready_for_devs) {
296 printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n",
297 fmt);
298 /* XXX panic here once drivers are cleaned up */
299 }
300
301 dev = makedev(devsw->d_maj, minor);
302 if (dev->si_flags & SI_NAMED) {
303 printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n",
304 dev->si_name);
305 panic("don't do that");
306 return (dev);
307 }
308 va_start(ap, fmt);
309 i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
310 dev->si_name[i] = '\0';
311 va_end(ap);
312 dev->si_devsw = devsw;
313 dev->si_uid = uid;
314 dev->si_gid = gid;
315 dev->si_mode = perms;
316 dev->si_flags |= SI_NAMED;
317
318 if (devfs_create_hook)
319 devfs_create_hook(dev);
320 return (dev);
321}
322
323int
324dev_named(dev_t pdev, const char *name)
325{
326 dev_t cdev;
327
328 if (strcmp(devtoname(pdev), name) == 0)
329 return (1);
330 LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
331 if (strcmp(devtoname(cdev), name) == 0)
332 return (1);
333 return (0);
334}
335
336void
337dev_depends(dev_t pdev, dev_t cdev)
338{
339
340 cdev->si_parent = pdev;
341 cdev->si_flags |= SI_CHILD;
342 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
343}
344
345dev_t
346make_dev_alias(dev_t pdev, const char *fmt, ...)
347{
348 dev_t dev;
349 va_list ap;
350 int i;
351
352 dev = allocdev();
353 dev->si_flags |= SI_ALIAS;
354 dev->si_flags |= SI_NAMED;
355 dev_depends(pdev, dev);
356 va_start(ap, fmt);
357 i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
358 dev->si_name[i] = '\0';
359 va_end(ap);
360
361 if (devfs_create_hook)
362 devfs_create_hook(dev);
363 return (dev);
364}
365
366void
367revoke_and_destroy_dev(dev_t dev)
368{
369 struct vnode *vp;
370
371 GIANT_REQUIRED;
372
373 vp = SLIST_FIRST(&dev->si_hlist);
374 if (vp != NULL)
375 VOP_REVOKE(vp, REVOKEALL);
376 destroy_dev(dev);
377}
378
379void
380destroy_dev(dev_t dev)
381{
382
383 if (!(dev->si_flags & SI_NAMED)) {
384 printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
385 major(dev), minor(dev));
386 panic("don't do that");
387 return;
388 }
389
390 if (devfs_destroy_hook)
391 devfs_destroy_hook(dev);
392 if (dev->si_flags & SI_CHILD) {
393 LIST_REMOVE(dev, si_siblings);
394 dev->si_flags &= ~SI_CHILD;
395 }
396 while (!LIST_EMPTY(&dev->si_children))
397 destroy_dev(LIST_FIRST(&dev->si_children));
398 dev->si_drv1 = 0;
399 dev->si_drv2 = 0;
400 dev->si_devsw = 0;
401 dev->si_flags &= ~SI_NAMED;
402 dev->si_flags &= ~SI_ALIAS;
403 freedev(dev);
404}
405
406const char *
407devtoname(dev_t dev)
408{
409 char *p;
410 int mynor;
411
412 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
413 p = dev->si_name;
414 if (devsw(dev))
415 sprintf(p, "#%s/", devsw(dev)->d_name);
416 else
417 sprintf(p, "#%d/", major(dev));
418 p += strlen(p);
419 mynor = minor(dev);
420 if (mynor < 0 || mynor > 255)
421 sprintf(p, "%#x", (u_int)mynor);
422 else
423 sprintf(p, "%d", mynor);
424 }
425 return (dev->si_name);
426}
427
428int
429dev_stdclone(char *name, char **namep, char *stem, int *unit)
430{
431 int u, i;
432
433 i = strlen(stem);
434 if (bcmp(stem, name, i) != 0)
435 return (0);
436 if (!isdigit(name[i]))
437 return (0);
438 u = 0;
439 if (name[i] == '0' && isdigit(name[i+1]))
440 return (0);
441 while (isdigit(name[i])) {
442 u *= 10;
443 u += name[i++] - '0';
444 }
445 *unit = u;
446 if (namep)
447 *namep = &name[i];
448 if (name[i])
449 return (2);
450 return (1);
451}
452
453/*
454 * Helper sysctl for devname(3). We're given a {u}dev_t and return
455 * the name, if any, registered by the device driver.
456 */
457static int
458sysctl_devname(SYSCTL_HANDLER_ARGS)
459{
460 int error;
461 udev_t ud;
462 dev_t dev;
463
464 error = SYSCTL_IN(req, &ud, sizeof (ud));
465 if (error)
466 return (error);
467 if (ud == NOUDEV)
468 return(EINVAL);
469 dev = makedev(umajor(ud), uminor(ud));
470 if (dev->si_name[0] == '\0')
471 error = ENOENT;
472 else
473 error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
474 freedev(dev);
475 return (error);
476}
477
478SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
479 NULL, 0, sysctl_devname, "", "devname(3) handler");
480
481/*
482 * Set ready_for_devs; prior to this point, device creation is not allowed.
483 */
484static void
485dev_set_ready(void *junk)
486{
487 ready_for_devs = 1;
488}
489
490SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL);