Sun May 3 22:39:50 2009 UTC ()
Pull up following revision(s) (requested by joerg in ticket #675):
	sys/kern/kern_drvctl.c: revision 1.24
Allow querying for root devices in the tree by specifying an empty
device name. Ensure that l_devname is NUL-terminated and fail otherwise.
OK cube@


(snj)
diff -r1.19.6.2 -r1.19.6.3 src/sys/kern/kern_drvctl.c

cvs diff -r1.19.6.2 -r1.19.6.3 src/sys/kern/kern_drvctl.c (switch to unified diff)

--- src/sys/kern/kern_drvctl.c 2009/04/04 23:36:27 1.19.6.2
+++ src/sys/kern/kern_drvctl.c 2009/05/03 22:39:49 1.19.6.3
@@ -1,554 +1,558 @@ @@ -1,554 +1,558 @@
1/* $NetBSD: kern_drvctl.c,v 1.19.6.2 2009/04/04 23:36:27 snj Exp $ */ 1/* $NetBSD: kern_drvctl.c,v 1.19.6.3 2009/05/03 22:39:49 snj Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2004 4 * Copyright (c) 2004
5 * Matthias Drochner. All rights reserved. 5 * Matthias Drochner. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer. 11 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 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 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 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 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 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE. 26 * SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.19.6.2 2009/04/04 23:36:27 snj Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.19.6.3 2009/05/03 22:39:49 snj Exp $");
31 31
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/systm.h> 33#include <sys/systm.h>
34#include <sys/kernel.h> 34#include <sys/kernel.h>
35#include <sys/conf.h> 35#include <sys/conf.h>
36#include <sys/device.h> 36#include <sys/device.h>
37#include <sys/event.h> 37#include <sys/event.h>
38#include <sys/malloc.h> 38#include <sys/malloc.h>
39#include <sys/kmem.h> 39#include <sys/kmem.h>
40#include <sys/ioctl.h> 40#include <sys/ioctl.h>
41#include <sys/fcntl.h> 41#include <sys/fcntl.h>
42#include <sys/file.h> 42#include <sys/file.h>
43#include <sys/filedesc.h> 43#include <sys/filedesc.h>
44#include <sys/select.h> 44#include <sys/select.h>
45#include <sys/poll.h> 45#include <sys/poll.h>
46#include <sys/drvctlio.h> 46#include <sys/drvctlio.h>
47#include <sys/devmon.h> 47#include <sys/devmon.h>
48 48
49struct drvctl_event { 49struct drvctl_event {
50 TAILQ_ENTRY(drvctl_event) dce_link; 50 TAILQ_ENTRY(drvctl_event) dce_link;
51 prop_dictionary_t dce_event; 51 prop_dictionary_t dce_event;
52}; 52};
53 53
54TAILQ_HEAD(drvctl_queue, drvctl_event); 54TAILQ_HEAD(drvctl_queue, drvctl_event);
55 55
56static struct drvctl_queue drvctl_eventq; /* FIFO */ 56static struct drvctl_queue drvctl_eventq; /* FIFO */
57static kcondvar_t drvctl_cond; 57static kcondvar_t drvctl_cond;
58static kmutex_t drvctl_lock; 58static kmutex_t drvctl_lock;
59static int drvctl_nopen = 0, drvctl_eventcnt = 0; 59static int drvctl_nopen = 0, drvctl_eventcnt = 0;
60static struct selinfo drvctl_rdsel; 60static struct selinfo drvctl_rdsel;
61 61
62#define DRVCTL_EVENTQ_DEPTH 64 /* arbitrary queue limit */ 62#define DRVCTL_EVENTQ_DEPTH 64 /* arbitrary queue limit */
63 63
64dev_type_open(drvctlopen); 64dev_type_open(drvctlopen);
65 65
66const struct cdevsw drvctl_cdevsw = { 66const struct cdevsw drvctl_cdevsw = {
67 drvctlopen, nullclose, nullread, nullwrite, noioctl, 67 drvctlopen, nullclose, nullread, nullwrite, noioctl,
68 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER 68 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
69}; 69};
70 70
71void drvctlattach(int); 71void drvctlattach(int);
72 72
73static int drvctl_read(struct file *, off_t *, struct uio *, 73static int drvctl_read(struct file *, off_t *, struct uio *,
74 kauth_cred_t, int); 74 kauth_cred_t, int);
75static int drvctl_write(struct file *, off_t *, struct uio *, 75static int drvctl_write(struct file *, off_t *, struct uio *,
76 kauth_cred_t, int); 76 kauth_cred_t, int);
77static int drvctl_ioctl(struct file *, u_long, void *); 77static int drvctl_ioctl(struct file *, u_long, void *);
78static int drvctl_poll(struct file *, int); 78static int drvctl_poll(struct file *, int);
79static int drvctl_close(struct file *); 79static int drvctl_close(struct file *);
80 80
81static const struct fileops drvctl_fileops = { 81static const struct fileops drvctl_fileops = {
82 .fo_read = drvctl_read, 82 .fo_read = drvctl_read,
83 .fo_write = drvctl_write, 83 .fo_write = drvctl_write,
84 .fo_ioctl = drvctl_ioctl, 84 .fo_ioctl = drvctl_ioctl,
85 .fo_fcntl = fnullop_fcntl, 85 .fo_fcntl = fnullop_fcntl,
86 .fo_poll = drvctl_poll, 86 .fo_poll = drvctl_poll,
87 .fo_stat = fbadop_stat, 87 .fo_stat = fbadop_stat,
88 .fo_close = drvctl_close, 88 .fo_close = drvctl_close,
89 .fo_kqfilter = fnullop_kqfilter, 89 .fo_kqfilter = fnullop_kqfilter,
90 .fo_drain = fnullop_drain, 90 .fo_drain = fnullop_drain,
91}; 91};
92 92
93#define MAXLOCATORS 100 93#define MAXLOCATORS 100
94 94
95static int drvctl_command(struct lwp *, struct plistref *, u_long, int); 95static int drvctl_command(struct lwp *, struct plistref *, u_long, int);
96static int drvctl_getevent(struct lwp *, struct plistref *, u_long, int); 96static int drvctl_getevent(struct lwp *, struct plistref *, u_long, int);
97 97
98void 98void
99drvctl_init(void) 99drvctl_init(void)
100{ 100{
101 TAILQ_INIT(&drvctl_eventq); 101 TAILQ_INIT(&drvctl_eventq);
102 mutex_init(&drvctl_lock, MUTEX_DEFAULT, IPL_NONE); 102 mutex_init(&drvctl_lock, MUTEX_DEFAULT, IPL_NONE);
103 cv_init(&drvctl_cond, "devmon"); 103 cv_init(&drvctl_cond, "devmon");
104 selinit(&drvctl_rdsel); 104 selinit(&drvctl_rdsel);
105} 105}
106 106
107void 107void
108devmon_insert(const char *event, prop_dictionary_t ev) 108devmon_insert(const char *event, prop_dictionary_t ev)
109{ 109{
110 struct drvctl_event *dce, *odce;; 110 struct drvctl_event *dce, *odce;;
111 111
112 mutex_enter(&drvctl_lock); 112 mutex_enter(&drvctl_lock);
113 113
114 if (drvctl_nopen == 0) { 114 if (drvctl_nopen == 0) {
115 mutex_exit(&drvctl_lock); 115 mutex_exit(&drvctl_lock);
116 return; 116 return;
117 } 117 }
118 118
119 /* Fill in mandatory member */ 119 /* Fill in mandatory member */
120 if (!prop_dictionary_set_cstring_nocopy(ev, "event", event)) { 120 if (!prop_dictionary_set_cstring_nocopy(ev, "event", event)) {
121 prop_object_release(ev); 121 prop_object_release(ev);
122 mutex_exit(&drvctl_lock); 122 mutex_exit(&drvctl_lock);
123 return; 123 return;
124 } 124 }
125 125
126 dce = kmem_alloc(sizeof(*dce), KM_SLEEP); 126 dce = kmem_alloc(sizeof(*dce), KM_SLEEP);
127 if (dce == NULL) { 127 if (dce == NULL) {
128 mutex_exit(&drvctl_lock); 128 mutex_exit(&drvctl_lock);
129 return; 129 return;
130 } 130 }
131 131
132 dce->dce_event = ev; 132 dce->dce_event = ev;
133 133
134 if (drvctl_eventcnt == DRVCTL_EVENTQ_DEPTH) { 134 if (drvctl_eventcnt == DRVCTL_EVENTQ_DEPTH) {
135 odce = TAILQ_FIRST(&drvctl_eventq); 135 odce = TAILQ_FIRST(&drvctl_eventq);
136 TAILQ_REMOVE(&drvctl_eventq, odce, dce_link); 136 TAILQ_REMOVE(&drvctl_eventq, odce, dce_link);
137 prop_object_release(odce->dce_event); 137 prop_object_release(odce->dce_event);
138 kmem_free(odce, sizeof(*odce)); 138 kmem_free(odce, sizeof(*odce));
139 --drvctl_eventcnt; 139 --drvctl_eventcnt;
140 } 140 }
141 141
142 TAILQ_INSERT_TAIL(&drvctl_eventq, dce, dce_link); 142 TAILQ_INSERT_TAIL(&drvctl_eventq, dce, dce_link);
143 ++drvctl_eventcnt; 143 ++drvctl_eventcnt;
144 cv_broadcast(&drvctl_cond); 144 cv_broadcast(&drvctl_cond);
145 selnotify(&drvctl_rdsel, 0, 0); 145 selnotify(&drvctl_rdsel, 0, 0);
146 146
147 mutex_exit(&drvctl_lock); 147 mutex_exit(&drvctl_lock);
148} 148}
149 149
150int 150int
151drvctlopen(dev_t dev, int flags, int mode, struct lwp *l) 151drvctlopen(dev_t dev, int flags, int mode, struct lwp *l)
152{ 152{
153 struct file *fp; 153 struct file *fp;
154 int fd; 154 int fd;
155 int ret; 155 int ret;
156 156
157 ret = fd_allocfile(&fp, &fd); 157 ret = fd_allocfile(&fp, &fd);
158 if (ret) 158 if (ret)
159 return (ret); 159 return (ret);
160 160
161 /* XXX setup context */ 161 /* XXX setup context */
162 mutex_enter(&drvctl_lock); 162 mutex_enter(&drvctl_lock);
163 ret = fd_clone(fp, fd, flags, &drvctl_fileops, /* context */NULL); 163 ret = fd_clone(fp, fd, flags, &drvctl_fileops, /* context */NULL);
164 ++drvctl_nopen; 164 ++drvctl_nopen;
165 mutex_exit(&drvctl_lock); 165 mutex_exit(&drvctl_lock);
166 166
167 return ret; 167 return ret;
168} 168}
169 169
170static int 170static int
171pmdevbyname(u_long cmd, struct devpmargs *a) 171pmdevbyname(u_long cmd, struct devpmargs *a)
172{ 172{
173 struct device *d; 173 struct device *d;
174 174
175 if ((d = device_find_by_xname(a->devname)) == NULL) 175 if ((d = device_find_by_xname(a->devname)) == NULL)
176 return ENXIO; 176 return ENXIO;
177 177
178 switch (cmd) { 178 switch (cmd) {
179 case DRVSUSPENDDEV: 179 case DRVSUSPENDDEV:
180 return pmf_device_recursive_suspend(d, PMF_F_NONE) ? 0 : EBUSY; 180 return pmf_device_recursive_suspend(d, PMF_F_NONE) ? 0 : EBUSY;
181 case DRVRESUMEDEV: 181 case DRVRESUMEDEV:
182 if (a->flags & DEVPM_F_SUBTREE) { 182 if (a->flags & DEVPM_F_SUBTREE) {
183 return pmf_device_resume_subtree(d, PMF_F_NONE) 183 return pmf_device_resume_subtree(d, PMF_F_NONE)
184 ? 0 : EBUSY; 184 ? 0 : EBUSY;
185 } else { 185 } else {
186 return pmf_device_recursive_resume(d, PMF_F_NONE) 186 return pmf_device_recursive_resume(d, PMF_F_NONE)
187 ? 0 : EBUSY; 187 ? 0 : EBUSY;
188 } 188 }
189 default: 189 default:
190 return EPASSTHROUGH; 190 return EPASSTHROUGH;
191 } 191 }
192} 192}
193 193
194static int 194static int
195listdevbyname(struct devlistargs *l) 195listdevbyname(struct devlistargs *l)
196{ 196{
197 device_t d, child; 197 device_t d, child;
198 deviter_t di; 198 deviter_t di;
199 int cnt = 0, idx, error = 0; 199 int cnt = 0, idx, error = 0;
200 200
201 if ((d = device_find_by_xname(l->l_devname)) == NULL) 201 if (*l->l_devname == '\0')
 202 d = (device_t)NULL;
 203 else if (memchr(l->l_devname, 0, sizeof(l->l_devname)) == NULL)
 204 return EINVAL;
 205 else if ((d = device_find_by_xname(l->l_devname)) == NULL)
202 return ENXIO; 206 return ENXIO;
203 207
204 for (child = deviter_first(&di, 0); child != NULL; 208 for (child = deviter_first(&di, 0); child != NULL;
205 child = deviter_next(&di)) { 209 child = deviter_next(&di)) {
206 if (device_parent(child) != d) 210 if (device_parent(child) != d)
207 continue; 211 continue;
208 idx = cnt++; 212 idx = cnt++;
209 if (l->l_childname == NULL || idx >= l->l_children) 213 if (l->l_childname == NULL || idx >= l->l_children)
210 continue; 214 continue;
211 error = copyoutstr(device_xname(child), l->l_childname[idx], 215 error = copyoutstr(device_xname(child), l->l_childname[idx],
212 sizeof(l->l_childname[idx]), NULL); 216 sizeof(l->l_childname[idx]), NULL);
213 if (error != 0) 217 if (error != 0)
214 break; 218 break;
215 } 219 }
216 deviter_release(&di); 220 deviter_release(&di);
217 221
218 l->l_children = cnt; 222 l->l_children = cnt;
219 return error; 223 return error;
220} 224}
221 225
222static int 226static int
223detachdevbyname(const char *devname) 227detachdevbyname(const char *devname)
224{ 228{
225 struct device *d; 229 struct device *d;
226 230
227 if ((d = device_find_by_xname(devname)) == NULL) 231 if ((d = device_find_by_xname(devname)) == NULL)
228 return ENXIO; 232 return ENXIO;
229 233
230#ifndef XXXFULLRISK 234#ifndef XXXFULLRISK
231 /* 235 /*
232 * If the parent cannot be notified, it might keep 236 * If the parent cannot be notified, it might keep
233 * pointers to the detached device. 237 * pointers to the detached device.
234 * There might be a private notification mechanism, 238 * There might be a private notification mechanism,
235 * but better play save here. 239 * but better play save here.
236 */ 240 */
237 if (d->dv_parent && !d->dv_parent->dv_cfattach->ca_childdetached) 241 if (d->dv_parent && !d->dv_parent->dv_cfattach->ca_childdetached)
238 return (ENOTSUP); 242 return (ENOTSUP);
239#endif 243#endif
240 return (config_detach(d, 0)); 244 return (config_detach(d, 0));
241} 245}
242 246
243static int 247static int
244rescanbus(const char *busname, const char *ifattr, 248rescanbus(const char *busname, const char *ifattr,
245 int numlocators, const int *locators) 249 int numlocators, const int *locators)
246{ 250{
247 int i, rc; 251 int i, rc;
248 struct device *d; 252 struct device *d;
249 const struct cfiattrdata * const *ap; 253 const struct cfiattrdata * const *ap;
250 254
251 /* XXX there should be a way to get limits and defaults (per device) 255 /* XXX there should be a way to get limits and defaults (per device)
252 from config generated data */ 256 from config generated data */
253 int locs[MAXLOCATORS]; 257 int locs[MAXLOCATORS];
254 for (i = 0; i < MAXLOCATORS; i++) 258 for (i = 0; i < MAXLOCATORS; i++)
255 locs[i] = -1; 259 locs[i] = -1;
256 260
257 for (i = 0; i < numlocators;i++) 261 for (i = 0; i < numlocators;i++)
258 locs[i] = locators[i]; 262 locs[i] = locators[i];
259 263
260 if ((d = device_find_by_xname(busname)) == NULL) 264 if ((d = device_find_by_xname(busname)) == NULL)
261 return ENXIO; 265 return ENXIO;
262 266
263 /* 267 /*
264 * must support rescan, and must have something 268 * must support rescan, and must have something
265 * to attach to 269 * to attach to
266 */ 270 */
267 if (!d->dv_cfattach->ca_rescan || 271 if (!d->dv_cfattach->ca_rescan ||
268 !d->dv_cfdriver->cd_attrs) 272 !d->dv_cfdriver->cd_attrs)
269 return (ENODEV); 273 return (ENODEV);
270 274
271 /* allow to omit attribute if there is exactly one */ 275 /* allow to omit attribute if there is exactly one */
272 if (!ifattr) { 276 if (!ifattr) {
273 if (d->dv_cfdriver->cd_attrs[1]) 277 if (d->dv_cfdriver->cd_attrs[1])
274 return (EINVAL); 278 return (EINVAL);
275 ifattr = d->dv_cfdriver->cd_attrs[0]->ci_name; 279 ifattr = d->dv_cfdriver->cd_attrs[0]->ci_name;
276 } else { 280 } else {
277 /* check for valid attribute passed */ 281 /* check for valid attribute passed */
278 for (ap = d->dv_cfdriver->cd_attrs; *ap; ap++) 282 for (ap = d->dv_cfdriver->cd_attrs; *ap; ap++)
279 if (!strcmp((*ap)->ci_name, ifattr)) 283 if (!strcmp((*ap)->ci_name, ifattr))
280 break; 284 break;
281 if (!*ap) 285 if (!*ap)
282 return (EINVAL); 286 return (EINVAL);
283 } 287 }
284 288
285 rc = (*d->dv_cfattach->ca_rescan)(d, ifattr, locs); 289 rc = (*d->dv_cfattach->ca_rescan)(d, ifattr, locs);
286 config_deferred(NULL); 290 config_deferred(NULL);
287 return rc; 291 return rc;
288} 292}
289 293
290static int 294static int
291drvctl_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, 295drvctl_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
292 int flags) 296 int flags)
293{ 297{
294 return (ENODEV); 298 return (ENODEV);
295} 299}
296 300
297static int 301static int
298drvctl_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, 302drvctl_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
299 int flags) 303 int flags)
300{ 304{
301 return (ENODEV); 305 return (ENODEV);
302} 306}
303 307
304static int 308static int
305drvctl_ioctl(struct file *fp, u_long cmd, void *data) 309drvctl_ioctl(struct file *fp, u_long cmd, void *data)
306{ 310{
307 int res; 311 int res;
308 char *ifattr; 312 char *ifattr;
309 int *locs; 313 int *locs;
310 314
311 switch (cmd) { 315 switch (cmd) {
312 case DRVSUSPENDDEV: 316 case DRVSUSPENDDEV:
313 case DRVRESUMEDEV: 317 case DRVRESUMEDEV:
314#define d ((struct devpmargs *)data) 318#define d ((struct devpmargs *)data)
315 res = pmdevbyname(cmd, d); 319 res = pmdevbyname(cmd, d);
316#undef d 320#undef d
317 break; 321 break;
318 case DRVLISTDEV: 322 case DRVLISTDEV:
319 res = listdevbyname((struct devlistargs *)data); 323 res = listdevbyname((struct devlistargs *)data);
320 break; 324 break;
321 case DRVDETACHDEV: 325 case DRVDETACHDEV:
322#define d ((struct devdetachargs *)data) 326#define d ((struct devdetachargs *)data)
323 res = detachdevbyname(d->devname); 327 res = detachdevbyname(d->devname);
324#undef d 328#undef d
325 break; 329 break;
326 case DRVRESCANBUS: 330 case DRVRESCANBUS:
327#define d ((struct devrescanargs *)data) 331#define d ((struct devrescanargs *)data)
328 d->busname[sizeof(d->busname) - 1] = '\0'; 332 d->busname[sizeof(d->busname) - 1] = '\0';
329 333
330 /* XXX better copyin? */ 334 /* XXX better copyin? */
331 if (d->ifattr[0]) { 335 if (d->ifattr[0]) {
332 d->ifattr[sizeof(d->ifattr) - 1] = '\0'; 336 d->ifattr[sizeof(d->ifattr) - 1] = '\0';
333 ifattr = d->ifattr; 337 ifattr = d->ifattr;
334 } else 338 } else
335 ifattr = 0; 339 ifattr = 0;
336 340
337 if (d->numlocators) { 341 if (d->numlocators) {
338 if (d->numlocators > MAXLOCATORS) 342 if (d->numlocators > MAXLOCATORS)
339 return (EINVAL); 343 return (EINVAL);
340 locs = malloc(d->numlocators * sizeof(int), M_DEVBUF, 344 locs = malloc(d->numlocators * sizeof(int), M_DEVBUF,
341 M_WAITOK); 345 M_WAITOK);
342 res = copyin(d->locators, locs, 346 res = copyin(d->locators, locs,
343 d->numlocators * sizeof(int)); 347 d->numlocators * sizeof(int));
344 if (res) { 348 if (res) {
345 free(locs, M_DEVBUF); 349 free(locs, M_DEVBUF);
346 return (res); 350 return (res);
347 } 351 }
348 } else 352 } else
349 locs = 0; 353 locs = 0;
350 res = rescanbus(d->busname, ifattr, d->numlocators, locs); 354 res = rescanbus(d->busname, ifattr, d->numlocators, locs);
351 if (locs) 355 if (locs)
352 free(locs, M_DEVBUF); 356 free(locs, M_DEVBUF);
353#undef d 357#undef d
354 break; 358 break;
355 case DRVCTLCOMMAND: 359 case DRVCTLCOMMAND:
356 res = drvctl_command(curlwp, (struct plistref *)data, cmd, 360 res = drvctl_command(curlwp, (struct plistref *)data, cmd,
357 fp->f_flag); 361 fp->f_flag);
358 break; 362 break;
359 case DRVGETEVENT: 363 case DRVGETEVENT:
360 res = drvctl_getevent(curlwp, (struct plistref *)data, cmd, 364 res = drvctl_getevent(curlwp, (struct plistref *)data, cmd,
361 fp->f_flag); 365 fp->f_flag);
362 break; 366 break;
363 default: 367 default:
364 return (EPASSTHROUGH); 368 return (EPASSTHROUGH);
365 } 369 }
366 return (res); 370 return (res);
367} 371}
368 372
369static int 373static int
370drvctl_poll(struct file *fp, int events) 374drvctl_poll(struct file *fp, int events)
371{ 375{
372 int revents = 0; 376 int revents = 0;
373 377
374 if (!TAILQ_EMPTY(&drvctl_eventq)) 378 if (!TAILQ_EMPTY(&drvctl_eventq))
375 revents |= events & (POLLIN | POLLRDNORM); 379 revents |= events & (POLLIN | POLLRDNORM);
376 else 380 else
377 selrecord(curlwp, &drvctl_rdsel); 381 selrecord(curlwp, &drvctl_rdsel);
378 382
379 return revents; 383 return revents;
380} 384}
381 385
382static int 386static int
383drvctl_close(struct file *fp) 387drvctl_close(struct file *fp)
384{ 388{
385 struct drvctl_event *dce; 389 struct drvctl_event *dce;
386 390
387 /* XXX free context */ 391 /* XXX free context */
388 mutex_enter(&drvctl_lock); 392 mutex_enter(&drvctl_lock);
389 KASSERT(drvctl_nopen > 0); 393 KASSERT(drvctl_nopen > 0);
390 --drvctl_nopen; 394 --drvctl_nopen;
391 if (drvctl_nopen == 0) { 395 if (drvctl_nopen == 0) {
392 /* flush queue */ 396 /* flush queue */
393 while ((dce = TAILQ_FIRST(&drvctl_eventq)) != NULL) { 397 while ((dce = TAILQ_FIRST(&drvctl_eventq)) != NULL) {
394 TAILQ_REMOVE(&drvctl_eventq, dce, dce_link); 398 TAILQ_REMOVE(&drvctl_eventq, dce, dce_link);
395 KASSERT(drvctl_eventcnt > 0); 399 KASSERT(drvctl_eventcnt > 0);
396 --drvctl_eventcnt; 400 --drvctl_eventcnt;
397 prop_object_release(dce->dce_event); 401 prop_object_release(dce->dce_event);
398 kmem_free(dce, sizeof(*dce)); 402 kmem_free(dce, sizeof(*dce));
399 } 403 }
400 } 404 }
401 mutex_exit(&drvctl_lock); 405 mutex_exit(&drvctl_lock);
402 406
403 return (0); 407 return (0);
404} 408}
405 409
406void 410void
407drvctlattach(int arg) 411drvctlattach(int arg)
408{ 412{
409} 413}
410 414
411/***************************************************************************** 415/*****************************************************************************
412 * Driver control command processing engine 416 * Driver control command processing engine
413 *****************************************************************************/ 417 *****************************************************************************/
414 418
415static int 419static int
416drvctl_command_get_properties(struct lwp *l, 420drvctl_command_get_properties(struct lwp *l,
417 prop_dictionary_t command_dict, 421 prop_dictionary_t command_dict,
418 prop_dictionary_t results_dict) 422 prop_dictionary_t results_dict)
419{ 423{
420 prop_dictionary_t args_dict; 424 prop_dictionary_t args_dict;
421 prop_string_t devname_string; 425 prop_string_t devname_string;
422 device_t dev; 426 device_t dev;
423 deviter_t di; 427 deviter_t di;
424  428
425 args_dict = prop_dictionary_get(command_dict, "drvctl-arguments"); 429 args_dict = prop_dictionary_get(command_dict, "drvctl-arguments");
426 if (args_dict == NULL) 430 if (args_dict == NULL)
427 return (EINVAL); 431 return (EINVAL);
428 432
429 devname_string = prop_dictionary_get(args_dict, "device-name"); 433 devname_string = prop_dictionary_get(args_dict, "device-name");
430 if (devname_string == NULL) 434 if (devname_string == NULL)
431 return (EINVAL); 435 return (EINVAL);
432  436
433 for (dev = deviter_first(&di, 0); dev != NULL; 437 for (dev = deviter_first(&di, 0); dev != NULL;
434 dev = deviter_next(&di)) { 438 dev = deviter_next(&di)) {
435 if (prop_string_equals_cstring(devname_string, 439 if (prop_string_equals_cstring(devname_string,
436 device_xname(dev))) { 440 device_xname(dev))) {
437 prop_dictionary_set(results_dict, "drvctl-result-data", 441 prop_dictionary_set(results_dict, "drvctl-result-data",
438 device_properties(dev)); 442 device_properties(dev));
439 break; 443 break;
440 } 444 }
441 } 445 }
442 446
443 deviter_release(&di); 447 deviter_release(&di);
444 448
445 if (dev == NULL) 449 if (dev == NULL)
446 return (ESRCH); 450 return (ESRCH);
447 451
448 return (0); 452 return (0);
449} 453}
450 454
451struct drvctl_command_desc { 455struct drvctl_command_desc {
452 const char *dcd_name; /* command name */ 456 const char *dcd_name; /* command name */
453 int (*dcd_func)(struct lwp *, /* handler function */ 457 int (*dcd_func)(struct lwp *, /* handler function */
454 prop_dictionary_t, 458 prop_dictionary_t,
455 prop_dictionary_t); 459 prop_dictionary_t);
456 int dcd_rw; /* read or write required */ 460 int dcd_rw; /* read or write required */
457}; 461};
458 462
459static const struct drvctl_command_desc drvctl_command_table[] = { 463static const struct drvctl_command_desc drvctl_command_table[] = {
460 { .dcd_name = "get-properties", 464 { .dcd_name = "get-properties",
461 .dcd_func = drvctl_command_get_properties, 465 .dcd_func = drvctl_command_get_properties,
462 .dcd_rw = FREAD, 466 .dcd_rw = FREAD,
463 }, 467 },
464 468
465 { .dcd_name = NULL } 469 { .dcd_name = NULL }
466}; 470};
467 471
468static int 472static int
469drvctl_command(struct lwp *l, struct plistref *pref, u_long ioctl_cmd, 473drvctl_command(struct lwp *l, struct plistref *pref, u_long ioctl_cmd,
470 int fflag) 474 int fflag)
471{ 475{
472 prop_dictionary_t command_dict, results_dict; 476 prop_dictionary_t command_dict, results_dict;
473 prop_string_t command_string; 477 prop_string_t command_string;
474 const struct drvctl_command_desc *dcd; 478 const struct drvctl_command_desc *dcd;
475 int error; 479 int error;
476 480
477 error = prop_dictionary_copyin_ioctl(pref, ioctl_cmd, &command_dict); 481 error = prop_dictionary_copyin_ioctl(pref, ioctl_cmd, &command_dict);
478 if (error) 482 if (error)
479 return (error); 483 return (error);
480 484
481 results_dict = prop_dictionary_create(); 485 results_dict = prop_dictionary_create();
482 if (results_dict == NULL) { 486 if (results_dict == NULL) {
483 prop_object_release(command_dict); 487 prop_object_release(command_dict);
484 return (ENOMEM); 488 return (ENOMEM);
485 } 489 }
486  490
487 command_string = prop_dictionary_get(command_dict, "drvctl-command"); 491 command_string = prop_dictionary_get(command_dict, "drvctl-command");
488 if (command_string == NULL) { 492 if (command_string == NULL) {
489 error = EINVAL; 493 error = EINVAL;
490 goto out; 494 goto out;
491 } 495 }
492 496
493 for (dcd = drvctl_command_table; dcd->dcd_name != NULL; dcd++) { 497 for (dcd = drvctl_command_table; dcd->dcd_name != NULL; dcd++) {
494 if (prop_string_equals_cstring(command_string, 498 if (prop_string_equals_cstring(command_string,
495 dcd->dcd_name)) 499 dcd->dcd_name))
496 break; 500 break;
497 } 501 }
498 502
499 if (dcd->dcd_name == NULL) { 503 if (dcd->dcd_name == NULL) {
500 error = EINVAL; 504 error = EINVAL;
501 goto out; 505 goto out;
502 } 506 }
503 507
504 if ((fflag & dcd->dcd_rw) == 0) { 508 if ((fflag & dcd->dcd_rw) == 0) {
505 error = EPERM; 509 error = EPERM;
506 goto out; 510 goto out;
507 } 511 }
508 512
509 error = (*dcd->dcd_func)(l, command_dict, results_dict); 513 error = (*dcd->dcd_func)(l, command_dict, results_dict);
510 514
511 prop_dictionary_set_int32(results_dict, "drvctl-error", error); 515 prop_dictionary_set_int32(results_dict, "drvctl-error", error);
512 516
513 error = prop_dictionary_copyout_ioctl(pref, ioctl_cmd, results_dict); 517 error = prop_dictionary_copyout_ioctl(pref, ioctl_cmd, results_dict);
514 out: 518 out:
515 prop_object_release(command_dict); 519 prop_object_release(command_dict);
516 prop_object_release(results_dict); 520 prop_object_release(results_dict);
517 return (error); 521 return (error);
518} 522}
519 523
520static int 524static int
521drvctl_getevent(struct lwp *l, struct plistref *pref, u_long ioctl_cmd, 525drvctl_getevent(struct lwp *l, struct plistref *pref, u_long ioctl_cmd,
522 int fflag) 526 int fflag)
523{ 527{
524 struct drvctl_event *dce; 528 struct drvctl_event *dce;
525 int ret; 529 int ret;
526 530
527 if ((fflag & (FREAD|FWRITE)) != (FREAD|FWRITE)) 531 if ((fflag & (FREAD|FWRITE)) != (FREAD|FWRITE))
528 return (EPERM); 532 return (EPERM);
529 533
530 mutex_enter(&drvctl_lock); 534 mutex_enter(&drvctl_lock);
531 while ((dce = TAILQ_FIRST(&drvctl_eventq)) == NULL) { 535 while ((dce = TAILQ_FIRST(&drvctl_eventq)) == NULL) {
532 if (fflag & O_NONBLOCK) { 536 if (fflag & O_NONBLOCK) {
533 mutex_exit(&drvctl_lock); 537 mutex_exit(&drvctl_lock);
534 return (EWOULDBLOCK); 538 return (EWOULDBLOCK);
535 } 539 }
536 540
537 ret = cv_wait_sig(&drvctl_cond, &drvctl_lock); 541 ret = cv_wait_sig(&drvctl_cond, &drvctl_lock);
538 if (ret) { 542 if (ret) {
539 mutex_exit(&drvctl_lock); 543 mutex_exit(&drvctl_lock);
540 return (ret); 544 return (ret);
541 } 545 }
542 } 546 }
543 TAILQ_REMOVE(&drvctl_eventq, dce, dce_link); 547 TAILQ_REMOVE(&drvctl_eventq, dce, dce_link);
544 KASSERT(drvctl_eventcnt > 0); 548 KASSERT(drvctl_eventcnt > 0);
545 --drvctl_eventcnt; 549 --drvctl_eventcnt;
546 mutex_exit(&drvctl_lock); 550 mutex_exit(&drvctl_lock);
547 551
548 ret = prop_dictionary_copyout_ioctl(pref, ioctl_cmd, dce->dce_event); 552 ret = prop_dictionary_copyout_ioctl(pref, ioctl_cmd, dce->dce_event);
549 553
550 prop_object_release(dce->dce_event); 554 prop_object_release(dce->dce_event);
551 kmem_free(dce, sizeof(*dce)); 555 kmem_free(dce, sizeof(*dce));
552 556
553 return (ret); 557 return (ret);
554} 558}