kern_conf.c revision 71342
1100966Siwasaki/*-
2100966Siwasaki * Parts Copyright (c) 1995 Terrence R. Lambert
3100966Siwasaki * Copyright (c) 1995 Julian R. Elischer
4100966Siwasaki * All rights reserved.
5100966Siwasaki *
6100966Siwasaki * Redistribution and use in source and binary forms, with or without
7217365Sjkim * modification, are permitted provided that the following conditions
8245582Sjkim * are met:
9100966Siwasaki * 1. Redistributions of source code must retain the above copyright
10100966Siwasaki *    notice, this list of conditions and the following disclaimer.
11217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright
12217365Sjkim *    notice, this list of conditions and the following disclaimer in the
13217365Sjkim *    documentation and/or other materials provided with the distribution.
14217365Sjkim * 3. All advertising materials mentioning features or use of this software
15217365Sjkim *    must display the following acknowledgement:
16217365Sjkim *      This product includes software developed by Terrence R. Lambert.
17217365Sjkim * 4. The name Terrence R. Lambert may not be used to endorse or promote
18217365Sjkim *    products derived from this software without specific prior written
19217365Sjkim *    permission.
20217365Sjkim *
21217365Sjkim * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22217365Sjkim * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24217365Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25100966Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29100966Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31217365Sjkim * SUCH DAMAGE.
32217365Sjkim *
33217365Sjkim * $FreeBSD: head/sys/kern/kern_conf.c 71342 2001-01-21 21:19:49Z phk $
34217365Sjkim */
35217365Sjkim
36217365Sjkim#include <sys/param.h>
37217365Sjkim#include <sys/kernel.h>
38217365Sjkim#include <sys/sysctl.h>
39217365Sjkim#include <sys/systm.h>
40217365Sjkim#include <sys/module.h>
41217365Sjkim#include <sys/malloc.h>
42217365Sjkim#include <sys/conf.h>
43100966Siwasaki#include <sys/vnode.h>
44100966Siwasaki#include <sys/queue.h>
45193341Sjkim#include <sys/ctype.h>
46193341Sjkim#include <machine/stdarg.h>
47193341Sjkim
48100966Siwasaki#define cdevsw_ALLOCSTART	(NUMCDEVSW/2)
49100966Siwasaki
50100966Siwasakistruct cdevsw 	*cdevsw[NUMCDEVSW];
51100966Siwasaki
52102550Siwasakistatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
53100966Siwasaki
54100966Siwasaki/*
55100966Siwasaki * This is the number of hash-buckets.  Experiements with 'real-life'
56151937Sjkim * udev_t's show that a prime halfway between two powers of two works
57151937Sjkim * best.
58151937Sjkim */
59151937Sjkim#define DEVT_HASH 83
60167802Sjkim
61167802Sjkim/* The number of dev_t's we can create before malloc(9) kick in.  */
62167802Sjkim#define DEVT_STASH 50
63167802Sjkim
64167802Sjkimstatic struct specinfo devt_stash[DEVT_STASH];
65151937Sjkim
66151937Sjkimstatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH];
67151937Sjkim
68151937Sjkimstatic LIST_HEAD(, specinfo) dev_free;
69167802Sjkim
70167802Sjkimdevfs_create_t *devfs_create_hook;
71167802Sjkimdevfs_destroy_t *devfs_destroy_hook;
72167802Sjkimint devfs_present;
73151937Sjkim
74151937Sjkimstatic int free_devt;
75151937SjkimSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
76151937Sjkim
77151937Sjkimstruct cdevsw *
78151937Sjkimdevsw(dev_t dev)
79151937Sjkim{
80151937Sjkim	if (dev->si_devsw)
81151937Sjkim		return (dev->si_devsw);
82151937Sjkim        return(cdevsw[major(dev)]);
83151937Sjkim}
84151937Sjkim
85151937Sjkim/*
86151937Sjkim *  Add a cdevsw entry
87151937Sjkim */
88151937Sjkim
89151937Sjkimint
90151937Sjkimcdevsw_add(struct cdevsw *newentry)
91151937Sjkim{
92151937Sjkim
93151937Sjkim	if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
94151937Sjkim		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
95151937Sjkim		    newentry->d_name, newentry->d_maj);
96151937Sjkim		return (EINVAL);
97151937Sjkim	}
98151937Sjkim
99151937Sjkim	if (cdevsw[newentry->d_maj]) {
100151937Sjkim		printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
101151937Sjkim		    newentry->d_name, cdevsw[newentry->d_maj]->d_name);
102151937Sjkim	}
103151937Sjkim
104151937Sjkim	cdevsw[newentry->d_maj] = newentry;
105151937Sjkim
106151937Sjkim	return (0);
107151937Sjkim}
108151937Sjkim
109151937Sjkim/*
110151937Sjkim *  Remove a cdevsw entry
111151937Sjkim */
112151937Sjkim
113151937Sjkimint
114151937Sjkimcdevsw_remove(struct cdevsw *oldentry)
115151937Sjkim{
116151937Sjkim	if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
117151937Sjkim		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
118151937Sjkim		    oldentry->d_name, oldentry->d_maj);
119151937Sjkim		return EINVAL;
120151937Sjkim	}
121151937Sjkim
122151937Sjkim	cdevsw[oldentry->d_maj] = NULL;
123151937Sjkim
124151937Sjkim	return 0;
125151937Sjkim}
126100966Siwasaki
127100966Siwasaki/*
128151937Sjkim * dev_t and u_dev_t primitives
129151937Sjkim */
130151937Sjkim
131151937Sjkimint
132151937Sjkimmajor(dev_t x)
133151937Sjkim{
134151937Sjkim	if (x == NODEV)
135151937Sjkim		return NOUDEV;
136151937Sjkim	return((x->si_udev >> 8) & 0xff);
137151937Sjkim}
138151937Sjkim
139151937Sjkimint
140151937Sjkimminor(dev_t x)
141151937Sjkim{
142151937Sjkim	if (x == NODEV)
143151937Sjkim		return NOUDEV;
144151937Sjkim	return(x->si_udev & 0xffff00ff);
145151937Sjkim}
146193267Sjkim
147151937Sjkimint
148151937Sjkimdev2unit(dev_t x)
149151937Sjkim{
150151937Sjkim	int i;
151151937Sjkim
152151937Sjkim	if (x == NODEV)
153151937Sjkim		return NOUDEV;
154151937Sjkim	i = minor(x);
155151937Sjkim	return ((i & 0xff) | (i >> 8));
156250838Sjkim}
157167802Sjkim
158167802Sjkimint
159151937Sjkimunit2minor(int unit)
160151937Sjkim{
161151937Sjkim
162250838Sjkim	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
163167802Sjkim}
164167802Sjkim
165151937Sjkimstatic dev_t
166151937Sjkimallocdev(void)
167151937Sjkim{
168250838Sjkim	static int stashed;
169151937Sjkim	struct specinfo *si;
170151937Sjkim
171151937Sjkim	if (stashed >= DEVT_STASH) {
172151937Sjkim		MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
173151937Sjkim		    M_USE_RESERVE | M_ZERO);
174151937Sjkim	} else if (LIST_FIRST(&dev_free)) {
175151937Sjkim		si = LIST_FIRST(&dev_free);
176151937Sjkim		LIST_REMOVE(si, si_hash);
177167802Sjkim	} else {
178151937Sjkim		si = devt_stash + stashed++;
179151937Sjkim		si->si_flags |= SI_STASHED;
180151937Sjkim	}
181151937Sjkim	LIST_INIT(&si->si_names);
182151937Sjkim	return (si);
183151937Sjkim}
184151937Sjkim
185151937Sjkimdev_t
186151937Sjkimmakedev(int x, int y)
187151937Sjkim{
188151937Sjkim	struct specinfo *si;
189151937Sjkim	udev_t	udev;
190151937Sjkim	int hash;
191151937Sjkim
192151937Sjkim	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
193151937Sjkim		panic("makedev of NOUDEV");
194151937Sjkim	udev = (x << 8) | y;
195193267Sjkim	hash = udev % DEVT_HASH;
196151937Sjkim	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
197151937Sjkim		if (si->si_udev == udev)
198151937Sjkim			return (si);
199151937Sjkim	}
200151937Sjkim	si = allocdev();
201151937Sjkim	si->si_udev = udev;
202151937Sjkim	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
203151937Sjkim        return (si);
204151937Sjkim}
205151937Sjkim
206151937Sjkimvoid
207250838Sjkimfreedev(dev_t dev)
208167802Sjkim{
209167802Sjkim	dev_t adev;
210151937Sjkim
211151937Sjkim	if (!free_devt)
212151937Sjkim		return;
213250838Sjkim	if (SLIST_FIRST(&dev->si_hlist))
214167802Sjkim		return;
215167802Sjkim	if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
216151937Sjkim		return;
217151937Sjkim	while (!LIST_EMPTY(&dev->si_names)) {
218151937Sjkim		adev = LIST_FIRST(&dev->si_names);
219250838Sjkim		adev->si_drv1 = NULL;
220167802Sjkim		freedev(adev);
221167802Sjkim	}
222151937Sjkim	LIST_REMOVE(dev, si_hash);
223151937Sjkim	if (dev->si_flags & SI_STASHED) {
224151937Sjkim		bzero(dev, sizeof(*dev));
225250838Sjkim		LIST_INSERT_HEAD(&dev_free, dev, si_hash);
226151937Sjkim	} else {
227151937Sjkim		FREE(dev, M_DEVT);
228151937Sjkim	}
229151937Sjkim}
230151937Sjkim
231151937Sjkimudev_t
232151937Sjkimdev2udev(dev_t x)
233151937Sjkim{
234151937Sjkim	if (x == NODEV)
235151937Sjkim		return NOUDEV;
236151937Sjkim	return (x->si_udev);
237151937Sjkim}
238151937Sjkim
239151937Sjkimdev_t
240151937Sjkimudev2dev(udev_t x, int b)
241151937Sjkim{
242151937Sjkim
243151937Sjkim	if (x == NOUDEV)
244151937Sjkim		return (NODEV);
245151937Sjkim	switch (b) {
246151937Sjkim		case 0:
247151937Sjkim			return makedev(umajor(x), uminor(x));
248151937Sjkim		case 1:
249151937Sjkim			return (NODEV);
250151937Sjkim		default:
251151937Sjkim			Debugger("udev2dev(...,X)");
252250838Sjkim			return NODEV;
253151937Sjkim	}
254151937Sjkim}
255151937Sjkim
256151937Sjkimint
257250838Sjkimuminor(udev_t dev)
258151937Sjkim{
259151937Sjkim	return(dev & 0xffff00ff);
260151937Sjkim}
261151937Sjkim
262250838Sjkimint
263151937Sjkimumajor(udev_t dev)
264151937Sjkim{
265151937Sjkim	return((dev & 0xff00) >> 8);
266151937Sjkim}
267250838Sjkim
268151937Sjkimudev_t
269151937Sjkimmakeudev(int x, int y)
270151937Sjkim{
271151937Sjkim        return ((x << 8) | y);
272250838Sjkim}
273151937Sjkim
274151937Sjkimdev_t
275151937Sjkimmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)
276151937Sjkim{
277151937Sjkim	dev_t	dev;
278151937Sjkim	va_list ap;
279151937Sjkim	int i;
280151937Sjkim
281151937Sjkim	dev = makedev(devsw->d_maj, minor);
282151937Sjkim	if (dev->si_flags & SI_NAMED) {
283151937Sjkim		printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n",
284151937Sjkim		    dev->si_name);
285151937Sjkim		return (dev);
286151937Sjkim	}
287151937Sjkim	va_start(ap, fmt);
288151937Sjkim	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
289151937Sjkim	dev->si_name[i] = '\0';
290151937Sjkim	va_end(ap);
291151937Sjkim	dev->si_devsw = devsw;
292151937Sjkim	dev->si_uid = uid;
293151937Sjkim	dev->si_gid = gid;
294151937Sjkim	dev->si_mode = perms;
295151937Sjkim	dev->si_flags |= SI_NAMED;
296151937Sjkim
297151937Sjkim	if (devfs_create_hook)
298151937Sjkim		devfs_create_hook(dev);
299151937Sjkim	return (dev);
300151937Sjkim}
301151937Sjkim
302151937Sjkimdev_t
303151937Sjkimmake_dev_alias(dev_t pdev, char *fmt, ...)
304151937Sjkim{
305151937Sjkim	dev_t	dev;
306151937Sjkim	va_list ap;
307151937Sjkim	int i;
308151937Sjkim
309151937Sjkim	dev = allocdev();
310151937Sjkim	dev->si_flags |= SI_ALIAS;
311151937Sjkim	dev->si_flags |= SI_NAMED;
312151937Sjkim	dev->si_drv1 = pdev;
313151937Sjkim	LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash);
314151937Sjkim
315151937Sjkim	va_start(ap, fmt);
316151937Sjkim	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
317151937Sjkim	dev->si_name[i] = '\0';
318151937Sjkim	va_end(ap);
319151937Sjkim
320151937Sjkim	if (devfs_create_hook)
321151937Sjkim		devfs_create_hook(dev);
322151937Sjkim	return (dev);
323151937Sjkim}
324151937Sjkim
325151937Sjkimvoid
326151937Sjkimdestroy_dev(dev_t dev)
327151937Sjkim{
328151937Sjkim
329151937Sjkim	if (!(dev->si_flags & SI_NAMED)) {
330151937Sjkim		printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
331151937Sjkim		    major(dev), minor(dev));
332151937Sjkim		return;
333243347Sjkim	}
334151937Sjkim
335151937Sjkim	if (devfs_destroy_hook)
336151937Sjkim		devfs_destroy_hook(dev);
337151937Sjkim	dev->si_drv1 = 0;
338151937Sjkim	dev->si_drv2 = 0;
339151937Sjkim	dev->si_devsw = 0;
340151937Sjkim	dev->si_flags &= ~SI_NAMED;
341151937Sjkim	dev->si_flags &= ~SI_ALIAS;
342151937Sjkim	freedev(dev);
343151937Sjkim}
344151937Sjkim
345151937Sjkimconst char *
346243347Sjkimdevtoname(dev_t dev)
347151937Sjkim{
348151937Sjkim	char *p;
349151937Sjkim	int mynor;
350151937Sjkim
351151937Sjkim	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
352151937Sjkim		p = dev->si_name;
353151937Sjkim		if (devsw(dev))
354151937Sjkim			sprintf(p, "#%s/", devsw(dev)->d_name);
355151937Sjkim		else
356151937Sjkim			sprintf(p, "#%d/", major(dev));
357151937Sjkim		p += strlen(p);
358151937Sjkim		mynor = minor(dev);
359151937Sjkim		if (mynor < 0 || mynor > 255)
360151937Sjkim			sprintf(p, "%#x", (u_int)mynor);
361151937Sjkim		else
362151937Sjkim			sprintf(p, "%d", mynor);
363151937Sjkim	}
364151937Sjkim	return (dev->si_name);
365151937Sjkim}
366151937Sjkim
367151937Sjkimint
368151937Sjkimdev_stdclone(char *name, char **namep, char *stem, int *unit)
369151937Sjkim{
370151937Sjkim	int u, i;
371151937Sjkim
372151937Sjkim	if (bcmp(stem, name, strlen(stem)) != 0)
373151937Sjkim		return (0);
374151937Sjkim	i = strlen(stem);
375151937Sjkim	if (!isdigit(name[i]))
376151937Sjkim		return (0);
377151937Sjkim	u = 0;
378151937Sjkim	while (isdigit(name[i])) {
379151937Sjkim		u *= 10;
380151937Sjkim		u += name[i++] - '0';
381151937Sjkim	}
382151937Sjkim	*unit = u;
383151937Sjkim	if (namep)
384151937Sjkim		*namep = &name[i];
385151937Sjkim	if (name[i])
386151937Sjkim		return (2);
387151937Sjkim	return (1);
388151937Sjkim}
389151937Sjkim
390151937Sjkim/*
391151937Sjkim * Helper sysctl for devname(3).  We're given a {u}dev_t and return
392151937Sjkim * the name, if any, registered by the device driver.
393151937Sjkim */
394151937Sjkimstatic int
395151937Sjkimsysctl_devname(SYSCTL_HANDLER_ARGS)
396151937Sjkim{
397151937Sjkim	int error;
398243347Sjkim	udev_t ud;
399243347Sjkim	dev_t dev;
400243347Sjkim
401243347Sjkim	error = SYSCTL_IN(req, &ud, sizeof (ud));
402151937Sjkim	if (error)
403151937Sjkim		return (error);
404151937Sjkim	if (ud == NOUDEV)
405151937Sjkim		return(EINVAL);
406151937Sjkim	dev = makedev(umajor(ud), uminor(ud));
407100966Siwasaki	if (dev->si_name[0] == '\0')
408100966Siwasaki		error = ENOENT;
409100966Siwasaki	else
410100966Siwasaki		error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
411100966Siwasaki	freedev(dev);
412100966Siwasaki	return (error);
413100966Siwasaki}
414100966Siwasaki
415100966SiwasakiSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
416100966Siwasaki	NULL, 0, sysctl_devname, "", "devname(3) handler");
417151937Sjkim
418100966Siwasaki