xref: /netbsd-src/sys/kern/kern_drvctl.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /* $NetBSD: kern_drvctl.c,v 1.1 2004/08/18 12:19:29 drochner Exp $ */
2 
3 /*
4  * Copyright (c) 2004
5  * 	Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.1 2004/08/18 12:19:29 drochner Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/conf.h>
36 #include <sys/device.h>
37 #include <sys/event.h>
38 #include <sys/malloc.h>
39 #include <sys/ioctl.h>
40 #include <sys/drvctlio.h>
41 
42 dev_type_ioctl(drvctlioctl);
43 
44 const struct cdevsw drvctl_cdevsw = {
45 	nullopen, nullclose, nullread, nullwrite, drvctlioctl,
46 	nostop, notty, nopoll, nommap, nokqfilter,
47 };
48 
49 void drvctlattach(int);
50 
51 #define MAXLOCATORS 100
52 
53 static int
54 detachdevbyname(const char *devname)
55 {
56 	struct device *d;
57 
58 	TAILQ_FOREACH(d, &alldevs, dv_list) {
59 		if (!strcmp(devname, d->dv_xname)) {
60 #ifndef XXXFULLRISK
61 			/*
62 			 * If the parent cannot be notified, it might keep
63 			 * pointers to the detached device.
64 			 * There might be a private notification mechanism,
65 			 * but better play save here.
66 			 */
67 			if (d->dv_parent &&
68 			    !d->dv_parent->dv_cfattach->ca_childdetached)
69 				return (ENOTSUP);
70 #endif
71 			return (config_detach(d, 0));
72 		}
73 	}
74 
75 	return (ENXIO);
76 }
77 
78 static int
79 rescanbus(const char *busname, const char *ifattr,
80 	  int numlocators, const int *locators)
81 {
82 	int i;
83 	struct device *d;
84 	const char * const *ap;
85 
86 	/* XXX there should be a way to get limits and defaults (per device)
87 	   from config generated data */
88 	int locs[MAXLOCATORS];
89 	for (i = 0; i < MAXLOCATORS; i++)
90 		locs[i] = -1;
91 
92 	for (i = 0; i < numlocators;i++)
93 		locs[i] = locators[i];
94 
95 	TAILQ_FOREACH(d, &alldevs, dv_list) {
96 		if (!strcmp(busname, d->dv_xname)) {
97 			/*
98 			 * must support rescan, and must have something
99 			 * to attach to
100 			 */
101 			if (!d->dv_cfattach->ca_rescan ||
102 			    !d->dv_cfdriver->cd_attrs)
103 				return (ENODEV);
104 
105 			/* allow to omit attribute if there is exactly one */
106 			if (!ifattr) {
107 				if (d->dv_cfdriver->cd_attrs[1])
108 					return (EINVAL);
109 				ifattr = d->dv_cfdriver->cd_attrs[0];
110 			} else {
111 				/* check for valid attribute passed */
112 				for (ap = d->dv_cfdriver->cd_attrs; *ap; ap++)
113 					if (!strcmp(*ap, ifattr))
114 						break;
115 				if (!*ap)
116 					return (EINVAL);
117 			}
118 
119 			return (*d->dv_cfattach->ca_rescan)(d, ifattr, locs);
120 		}
121 	}
122 
123 	return (ENXIO);
124 }
125 
126 int
127 drvctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
128 {
129 	int res;
130 	char *ifattr;
131 	int *locs;
132 
133 	switch (cmd) {
134 	case DRVDETACHDEV:
135 #define d ((struct devdetachargs *)data)
136 		res = detachdevbyname(d->devname);
137 #undef d
138 		break;
139 	case DRVRESCANBUS:
140 #define d ((struct devrescanargs *)data)
141 		d->busname[sizeof(d->busname) - 1] = '\0';
142 
143 		/* XXX better copyin? */
144 		if (d->ifattr[0]) {
145 			d->ifattr[sizeof(d->ifattr) - 1] = '\0';
146 			ifattr = d->ifattr;
147 		} else
148 			ifattr = 0;
149 
150 		if (d->numlocators) {
151 			if (d->numlocators > MAXLOCATORS)
152 				return (EINVAL);
153 			locs = malloc(d->numlocators * sizeof(int), M_DEVBUF,
154 				      M_WAITOK);
155 			res = copyin(d->locators, locs,
156 				     d->numlocators * sizeof(int));
157 			if (res)
158 				return (res);
159 		} else
160 			locs = 0;
161 		res = rescanbus(d->busname, ifattr, d->numlocators, locs);
162 		if (locs)
163 			free(locs, M_DEVBUF);
164 #undef d
165 			break;
166 		default:
167 			return (EPASSTHROUGH);
168 	}
169 	return (res);
170 }
171 
172 void
173 drvctlattach(int arg)
174 {
175 }
176