1 | /* $NetBSD: putter.c,v 1.35 2014/07/25 08:10:38 dholland Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved. |
5 | * |
6 | * Development of this software was supported by the |
7 | * Ulla Tuominen Foundation and the Finnish Cultural Foundation and the |
8 | * Research Foundation of Helsinki University of Technology |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
20 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Pass-to-Userspace TransporTER: generic kernel-user request-response |
34 | * transport interface. |
35 | */ |
36 | |
37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: putter.c,v 1.35 2014/07/25 08:10:38 dholland Exp $" ); |
39 | |
40 | #include <sys/param.h> |
41 | #include <sys/systm.h> |
42 | #include <sys/conf.h> |
43 | #include <sys/file.h> |
44 | #include <sys/filedesc.h> |
45 | #include <sys/kmem.h> |
46 | #include <sys/poll.h> |
47 | #include <sys/stat.h> |
48 | #include <sys/socketvar.h> |
49 | #include <sys/module.h> |
50 | #include <sys/kauth.h> |
51 | |
52 | #include <dev/putter/putter_sys.h> |
53 | |
54 | /* |
55 | * Device routines. These are for when /dev/putter is initially |
56 | * opened before it has been cloned. |
57 | */ |
58 | |
59 | dev_type_open(puttercdopen); |
60 | dev_type_close(puttercdclose); |
61 | dev_type_ioctl(puttercdioctl); |
62 | |
63 | /* dev */ |
64 | const struct cdevsw putter_cdevsw = { |
65 | .d_open = puttercdopen, |
66 | .d_close = puttercdclose, |
67 | .d_read = noread, |
68 | .d_write = nowrite, |
69 | .d_ioctl = noioctl, |
70 | .d_stop = nostop, |
71 | .d_tty = notty, |
72 | .d_poll = nopoll, |
73 | .d_mmap = nommap, |
74 | .d_kqfilter = nokqfilter, |
75 | .d_discard = nodiscard, |
76 | .d_flag = D_OTHER |
77 | }; |
78 | |
79 | /* |
80 | * Configuration data. |
81 | * |
82 | * This is static-size for now. Will be redone for devfs. |
83 | */ |
84 | |
85 | #define PUTTER_CONFSIZE 16 |
86 | |
87 | static struct putter_config { |
88 | int pc_minor; |
89 | int (*pc_config)(int, int, int); |
90 | } putterconf[PUTTER_CONFSIZE]; |
91 | |
92 | static int |
93 | putter_configure(dev_t dev, int flags, int fmt, int fd) |
94 | { |
95 | struct putter_config *pc; |
96 | |
97 | /* are we the catch-all node? */ |
98 | if (minor(dev) == PUTTER_MINOR_WILDCARD |
99 | || minor(dev) == PUTTER_MINOR_COMPAT) |
100 | return 0; |
101 | |
102 | /* nopes? try to configure us */ |
103 | for (pc = putterconf; pc->pc_config; pc++) |
104 | if (minor(dev) == pc->pc_minor) |
105 | return pc->pc_config(fd, flags, fmt); |
106 | return ENXIO; |
107 | } |
108 | |
109 | int |
110 | putter_register(putter_config_fn pcfn, int minor) |
111 | { |
112 | int i; |
113 | |
114 | for (i = 0; i < PUTTER_CONFSIZE; i++) |
115 | if (putterconf[i].pc_config == NULL) |
116 | break; |
117 | if (i == PUTTER_CONFSIZE) |
118 | return EBUSY; |
119 | |
120 | putterconf[i].pc_minor = minor; |
121 | putterconf[i].pc_config = pcfn; |
122 | return 0; |
123 | } |
124 | |
125 | /* |
126 | * putter instance structures. these are always allocated and freed |
127 | * from the context of the transport user. |
128 | */ |
129 | struct putter_instance { |
130 | pid_t pi_pid; |
131 | int pi_idx; |
132 | int pi_fd; |
133 | struct selinfo pi_sel; |
134 | |
135 | void *pi_private; |
136 | struct putter_ops *pi_pop; |
137 | |
138 | uint8_t *pi_curput; |
139 | size_t pi_curres; |
140 | void *pi_curopaq; |
141 | struct timespec pi_atime; |
142 | struct timespec pi_mtime; |
143 | struct timespec pi_btime; |
144 | |
145 | TAILQ_ENTRY(putter_instance) pi_entries; |
146 | }; |
147 | #define PUTTER_EMBRYO ((void *)-1) /* before attach */ |
148 | #define PUTTER_DEAD ((void *)-2) /* after detach */ |
149 | |
150 | static TAILQ_HEAD(, putter_instance) putter_ilist |
151 | = TAILQ_HEAD_INITIALIZER(putter_ilist); |
152 | |
153 | static int get_pi_idx(struct putter_instance *); |
154 | |
155 | #ifdef DEBUG |
156 | #ifndef PUTTERDEBUG |
157 | #define PUTTERDEBUG |
158 | #endif |
159 | #endif |
160 | |
161 | #ifdef PUTTERDEBUG |
162 | int putterdebug = 0; |
163 | #define DPRINTF(x) if (putterdebug > 0) printf x |
164 | #define DPRINTF_VERBOSE(x) if (putterdebug > 1) printf x |
165 | #else |
166 | #define DPRINTF(x) |
167 | #define DPRINTF_VERBOSE(x) |
168 | #endif |
169 | |
170 | /* |
171 | * public init / deinit |
172 | */ |
173 | |
174 | /* protects both the list and the contents of the list elements */ |
175 | static kmutex_t pi_mtx; |
176 | |
177 | void putterattach(void); |
178 | |
179 | void |
180 | putterattach(void) |
181 | { |
182 | |
183 | mutex_init(&pi_mtx, MUTEX_DEFAULT, IPL_NONE); |
184 | } |
185 | |
186 | #if 0 |
187 | void |
188 | putter_destroy(void) |
189 | { |
190 | |
191 | mutex_destroy(&pi_mtx); |
192 | } |
193 | #endif |
194 | |
195 | /* |
196 | * fd routines, for cloner |
197 | */ |
198 | static int putter_fop_read(file_t *, off_t *, struct uio *, |
199 | kauth_cred_t, int); |
200 | static int putter_fop_write(file_t *, off_t *, struct uio *, |
201 | kauth_cred_t, int); |
202 | static int putter_fop_ioctl(file_t*, u_long, void *); |
203 | static int putter_fop_poll(file_t *, int); |
204 | static int putter_fop_stat(file_t *, struct stat *); |
205 | static int putter_fop_close(file_t *); |
206 | static int putter_fop_kqfilter(file_t *, struct knote *); |
207 | |
208 | |
209 | static const struct fileops putter_fileops = { |
210 | .fo_read = putter_fop_read, |
211 | .fo_write = putter_fop_write, |
212 | .fo_ioctl = putter_fop_ioctl, |
213 | .fo_fcntl = fnullop_fcntl, |
214 | .fo_poll = putter_fop_poll, |
215 | .fo_stat = putter_fop_stat, |
216 | .fo_close = putter_fop_close, |
217 | .fo_kqfilter = putter_fop_kqfilter, |
218 | .fo_restart = fnullop_restart, |
219 | }; |
220 | |
221 | static int |
222 | putter_fop_read(file_t *fp, off_t *off, struct uio *uio, |
223 | kauth_cred_t cred, int flags) |
224 | { |
225 | struct putter_instance *pi = fp->f_data; |
226 | size_t origres, moved; |
227 | int error; |
228 | |
229 | KERNEL_LOCK(1, NULL); |
230 | getnanotime(&pi->pi_atime); |
231 | |
232 | if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { |
233 | printf("putter_fop_read: private %d not inited\n" , pi->pi_idx); |
234 | KERNEL_UNLOCK_ONE(NULL); |
235 | return ENOENT; |
236 | } |
237 | |
238 | if (pi->pi_curput == NULL) { |
239 | error = pi->pi_pop->pop_getout(pi->pi_private, uio->uio_resid, |
240 | fp->f_flag & O_NONBLOCK, &pi->pi_curput, |
241 | &pi->pi_curres, &pi->pi_curopaq); |
242 | if (error) { |
243 | KERNEL_UNLOCK_ONE(NULL); |
244 | return error; |
245 | } |
246 | } |
247 | |
248 | origres = uio->uio_resid; |
249 | error = uiomove(pi->pi_curput, pi->pi_curres, uio); |
250 | moved = origres - uio->uio_resid; |
251 | DPRINTF(("putter_fop_read (%p): moved %zu bytes from %p, error %d\n" , |
252 | pi, moved, pi->pi_curput, error)); |
253 | |
254 | KASSERT(pi->pi_curres >= moved); |
255 | pi->pi_curres -= moved; |
256 | pi->pi_curput += moved; |
257 | |
258 | if (pi->pi_curres == 0) { |
259 | pi->pi_pop->pop_releaseout(pi->pi_private, |
260 | pi->pi_curopaq, error); |
261 | pi->pi_curput = NULL; |
262 | } |
263 | |
264 | KERNEL_UNLOCK_ONE(NULL); |
265 | return error; |
266 | } |
267 | |
268 | static int |
269 | putter_fop_write(file_t *fp, off_t *off, struct uio *uio, |
270 | kauth_cred_t cred, int flags) |
271 | { |
272 | struct putter_instance *pi = fp->f_data; |
273 | struct putter_hdr pth; |
274 | uint8_t *buf; |
275 | size_t frsize; |
276 | int error; |
277 | |
278 | KERNEL_LOCK(1, NULL); |
279 | getnanotime(&pi->pi_mtime); |
280 | |
281 | DPRINTF(("putter_fop_write (%p): writing response, resid %zu\n" , |
282 | pi->pi_private, uio->uio_resid)); |
283 | |
284 | if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { |
285 | printf("putter_fop_write: putter %d not inited\n" , pi->pi_idx); |
286 | KERNEL_UNLOCK_ONE(NULL); |
287 | return ENOENT; |
288 | } |
289 | |
290 | error = uiomove(&pth, sizeof(struct putter_hdr), uio); |
291 | if (error) { |
292 | KERNEL_UNLOCK_ONE(NULL); |
293 | return error; |
294 | } |
295 | |
296 | /* Sorry mate, the kernel doesn't buffer. */ |
297 | frsize = pth.pth_framelen - sizeof(struct putter_hdr); |
298 | if (uio->uio_resid < frsize) { |
299 | KERNEL_UNLOCK_ONE(NULL); |
300 | return EINVAL; |
301 | } |
302 | |
303 | buf = kmem_alloc(frsize + sizeof(struct putter_hdr), KM_SLEEP); |
304 | memcpy(buf, &pth, sizeof(pth)); |
305 | error = uiomove(buf+sizeof(struct putter_hdr), frsize, uio); |
306 | if (error == 0) { |
307 | pi->pi_pop->pop_dispatch(pi->pi_private, |
308 | (struct putter_hdr *)buf); |
309 | } |
310 | kmem_free(buf, frsize + sizeof(struct putter_hdr)); |
311 | |
312 | KERNEL_UNLOCK_ONE(NULL); |
313 | return error; |
314 | } |
315 | |
316 | /* |
317 | * Poll query interface. The question is only if an event |
318 | * can be read from us. |
319 | */ |
320 | #define PUTTERPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) |
321 | static int |
322 | putter_fop_poll(file_t *fp, int events) |
323 | { |
324 | struct putter_instance *pi = fp->f_data; |
325 | int revents; |
326 | |
327 | KERNEL_LOCK(1, NULL); |
328 | |
329 | if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { |
330 | printf("putter_fop_ioctl: putter %d not inited\n" , pi->pi_idx); |
331 | KERNEL_UNLOCK_ONE(NULL); |
332 | return ENOENT; |
333 | } |
334 | |
335 | revents = events & (POLLOUT | POLLWRNORM | POLLWRBAND); |
336 | if ((events & PUTTERPOLL_EVSET) == 0) { |
337 | KERNEL_UNLOCK_ONE(NULL); |
338 | return revents; |
339 | } |
340 | |
341 | /* check queue */ |
342 | if (pi->pi_pop->pop_waitcount(pi->pi_private)) |
343 | revents |= PUTTERPOLL_EVSET; |
344 | else |
345 | selrecord(curlwp, &pi->pi_sel); |
346 | |
347 | KERNEL_UNLOCK_ONE(NULL); |
348 | return revents; |
349 | } |
350 | |
351 | /* |
352 | * device close = forced unmount. |
353 | * |
354 | * unmounting is a frightfully complex operation to avoid races |
355 | */ |
356 | static int |
357 | putter_fop_close(file_t *fp) |
358 | { |
359 | struct putter_instance *pi = fp->f_data; |
360 | int rv; |
361 | |
362 | DPRINTF(("putter_fop_close: device closed\n" )); |
363 | |
364 | KERNEL_LOCK(1, NULL); |
365 | |
366 | restart: |
367 | mutex_enter(&pi_mtx); |
368 | /* |
369 | * First check if the driver was never born. In that case |
370 | * remove the instance from the list. If mount is attempted later, |
371 | * it will simply fail. |
372 | */ |
373 | if (pi->pi_private == PUTTER_EMBRYO) { |
374 | TAILQ_REMOVE(&putter_ilist, pi, pi_entries); |
375 | mutex_exit(&pi_mtx); |
376 | |
377 | DPRINTF(("putter_fop_close: data associated with fp %p was " |
378 | "embryonic\n" , fp)); |
379 | |
380 | goto out; |
381 | } |
382 | |
383 | /* |
384 | * Next, analyze if unmount was called and the instance is dead. |
385 | * In this case we can just free the structure and go home, it |
386 | * was removed from the list by putter_rmprivate(). |
387 | */ |
388 | if (pi->pi_private == PUTTER_DEAD) { |
389 | mutex_exit(&pi_mtx); |
390 | |
391 | DPRINTF(("putter_fop_close: putter associated with fp %p (%d) " |
392 | "dead, freeing\n" , fp, pi->pi_idx)); |
393 | |
394 | goto out; |
395 | } |
396 | |
397 | /* |
398 | * So we have a reference. Proceed to unravel the |
399 | * underlying driver. |
400 | */ |
401 | mutex_exit(&pi_mtx); |
402 | |
403 | /* hmm? suspicious locking? */ |
404 | if (pi->pi_curput != NULL) { |
405 | pi->pi_pop->pop_releaseout(pi->pi_private, pi->pi_curopaq, |
406 | ENXIO); |
407 | pi->pi_curput = NULL; |
408 | } |
409 | while ((rv = pi->pi_pop->pop_close(pi->pi_private)) == ERESTART) |
410 | goto restart; |
411 | |
412 | out: |
413 | KERNEL_UNLOCK_ONE(NULL); |
414 | /* |
415 | * Finally, release the instance information. It was already |
416 | * removed from the list by putter_rmprivate() and we know it's |
417 | * dead, so no need to lock. |
418 | */ |
419 | kmem_free(pi, sizeof(struct putter_instance)); |
420 | |
421 | return 0; |
422 | } |
423 | |
424 | static int |
425 | putter_fop_stat(file_t *fp, struct stat *st) |
426 | { |
427 | struct putter_instance *pi = fp->f_data; |
428 | |
429 | (void)memset(st, 0, sizeof(*st)); |
430 | KERNEL_LOCK(1, NULL); |
431 | st->st_dev = makedev(cdevsw_lookup_major(&putter_cdevsw), pi->pi_idx); |
432 | st->st_atimespec = pi->pi_atime; |
433 | st->st_mtimespec = pi->pi_mtime; |
434 | st->st_ctimespec = st->st_birthtimespec = pi->pi_btime; |
435 | st->st_uid = kauth_cred_geteuid(fp->f_cred); |
436 | st->st_gid = kauth_cred_getegid(fp->f_cred); |
437 | st->st_mode = S_IFCHR; |
438 | KERNEL_UNLOCK_ONE(NULL); |
439 | return 0; |
440 | } |
441 | |
442 | static int |
443 | putter_fop_ioctl(file_t *fp, u_long cmd, void *data) |
444 | { |
445 | |
446 | /* |
447 | * work already done in sys_ioctl(). skip sanity checks to enable |
448 | * setting non-blocking fd on an embryotic driver. |
449 | */ |
450 | if (cmd == FIONBIO) |
451 | return 0; |
452 | |
453 | return EINVAL; |
454 | } |
455 | |
456 | /* kqueue stuff */ |
457 | |
458 | static void |
459 | filt_putterdetach(struct knote *kn) |
460 | { |
461 | struct putter_instance *pi = kn->kn_hook; |
462 | |
463 | KERNEL_LOCK(1, NULL); |
464 | mutex_enter(&pi_mtx); |
465 | SLIST_REMOVE(&pi->pi_sel.sel_klist, kn, knote, kn_selnext); |
466 | mutex_exit(&pi_mtx); |
467 | KERNEL_UNLOCK_ONE(NULL); |
468 | } |
469 | |
470 | static int |
471 | filt_putter(struct knote *kn, long hint) |
472 | { |
473 | struct putter_instance *pi = kn->kn_hook; |
474 | int error, rv; |
475 | |
476 | KERNEL_LOCK(1, NULL); |
477 | error = 0; |
478 | mutex_enter(&pi_mtx); |
479 | if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) |
480 | error = 1; |
481 | mutex_exit(&pi_mtx); |
482 | if (error) { |
483 | KERNEL_UNLOCK_ONE(NULL); |
484 | return 0; |
485 | } |
486 | |
487 | kn->kn_data = pi->pi_pop->pop_waitcount(pi->pi_private); |
488 | rv = kn->kn_data != 0; |
489 | KERNEL_UNLOCK_ONE(NULL); |
490 | return rv; |
491 | } |
492 | |
493 | static const struct filterops putter_filtops = |
494 | { 1, NULL, filt_putterdetach, filt_putter }; |
495 | |
496 | static int |
497 | putter_fop_kqfilter(file_t *fp, struct knote *kn) |
498 | { |
499 | struct putter_instance *pi = fp->f_data; |
500 | struct klist *klist; |
501 | |
502 | KERNEL_LOCK(1, NULL); |
503 | |
504 | switch (kn->kn_filter) { |
505 | case EVFILT_READ: |
506 | klist = &pi->pi_sel.sel_klist; |
507 | kn->kn_fop = &putter_filtops; |
508 | kn->kn_hook = pi; |
509 | |
510 | mutex_enter(&pi_mtx); |
511 | SLIST_INSERT_HEAD(klist, kn, kn_selnext); |
512 | mutex_exit(&pi_mtx); |
513 | |
514 | break; |
515 | case EVFILT_WRITE: |
516 | kn->kn_fop = &seltrue_filtops; |
517 | break; |
518 | default: |
519 | KERNEL_UNLOCK_ONE(NULL); |
520 | return EINVAL; |
521 | } |
522 | |
523 | KERNEL_UNLOCK_ONE(NULL); |
524 | return 0; |
525 | } |
526 | |
527 | int |
528 | puttercdopen(dev_t dev, int flags, int fmt, struct lwp *l) |
529 | { |
530 | struct putter_instance *pi; |
531 | file_t *fp; |
532 | int error, fd, idx; |
533 | proc_t *p; |
534 | |
535 | p = curproc; |
536 | pi = kmem_alloc(sizeof(struct putter_instance), KM_SLEEP); |
537 | mutex_enter(&pi_mtx); |
538 | idx = get_pi_idx(pi); |
539 | |
540 | pi->pi_pid = p->p_pid; |
541 | pi->pi_idx = idx; |
542 | pi->pi_curput = NULL; |
543 | pi->pi_curres = 0; |
544 | pi->pi_curopaq = NULL; |
545 | getnanotime(&pi->pi_btime); |
546 | pi->pi_atime = pi->pi_mtime = pi->pi_btime; |
547 | selinit(&pi->pi_sel); |
548 | mutex_exit(&pi_mtx); |
549 | |
550 | if ((error = fd_allocfile(&fp, &fd)) != 0) |
551 | goto bad1; |
552 | |
553 | if ((error = putter_configure(dev, flags, fmt, fd)) != 0) |
554 | goto bad2; |
555 | |
556 | DPRINTF(("puttercdopen: registered embryonic pmp for pid: %d\n" , |
557 | pi->pi_pid)); |
558 | |
559 | error = fd_clone(fp, fd, FREAD|FWRITE, &putter_fileops, pi); |
560 | KASSERT(error == EMOVEFD); |
561 | return error; |
562 | |
563 | bad2: |
564 | fd_abort(p, fp, fd); |
565 | bad1: |
566 | putter_detach(pi); |
567 | kmem_free(pi, sizeof(struct putter_instance)); |
568 | return error; |
569 | } |
570 | |
571 | int |
572 | puttercdclose(dev_t dev, int flags, int fmt, struct lwp *l) |
573 | { |
574 | |
575 | panic("puttercdclose impossible\n" ); |
576 | |
577 | return 0; |
578 | } |
579 | |
580 | |
581 | /* |
582 | * Set the private structure for the file descriptor. This is |
583 | * typically done immediately when the counterpart has knowledge |
584 | * about the private structure's address and the file descriptor |
585 | * (e.g. vfs mount routine). |
586 | * |
587 | * We only want to make sure that the caller had the right to open the |
588 | * device, we don't so much care about which context it gets in case |
589 | * the same process opened multiple (since they are equal at this point). |
590 | */ |
591 | struct putter_instance * |
592 | putter_attach(pid_t pid, int fd, void *ppriv, struct putter_ops *pop) |
593 | { |
594 | struct putter_instance *pi = NULL; |
595 | |
596 | mutex_enter(&pi_mtx); |
597 | TAILQ_FOREACH(pi, &putter_ilist, pi_entries) { |
598 | if (pi->pi_pid == pid && pi->pi_private == PUTTER_EMBRYO) { |
599 | pi->pi_private = ppriv; |
600 | pi->pi_fd = fd; |
601 | pi->pi_pop = pop; |
602 | break; |
603 | } |
604 | } |
605 | mutex_exit(&pi_mtx); |
606 | |
607 | DPRINTF(("putter_setprivate: pi at %p (%d/%d)\n" , pi, |
608 | pi ? pi->pi_pid : 0, pi ? pi->pi_fd : 0)); |
609 | |
610 | return pi; |
611 | } |
612 | |
613 | /* |
614 | * Remove fp <-> private mapping. |
615 | */ |
616 | void |
617 | putter_detach(struct putter_instance *pi) |
618 | { |
619 | |
620 | mutex_enter(&pi_mtx); |
621 | TAILQ_REMOVE(&putter_ilist, pi, pi_entries); |
622 | pi->pi_private = PUTTER_DEAD; |
623 | mutex_exit(&pi_mtx); |
624 | seldestroy(&pi->pi_sel); |
625 | |
626 | DPRINTF(("putter_nukebypmp: nuked %p\n" , pi)); |
627 | } |
628 | |
629 | void |
630 | putter_notify(struct putter_instance *pi) |
631 | { |
632 | |
633 | selnotify(&pi->pi_sel, 0, 0); |
634 | } |
635 | |
636 | /* search sorted list of instances for free minor, sorted insert arg */ |
637 | static int |
638 | get_pi_idx(struct putter_instance *pi_i) |
639 | { |
640 | struct putter_instance *pi; |
641 | int i; |
642 | |
643 | KASSERT(mutex_owned(&pi_mtx)); |
644 | |
645 | i = 0; |
646 | TAILQ_FOREACH(pi, &putter_ilist, pi_entries) { |
647 | if (i != pi->pi_idx) |
648 | break; |
649 | i++; |
650 | } |
651 | |
652 | pi_i->pi_private = PUTTER_EMBRYO; |
653 | |
654 | if (pi == NULL) |
655 | TAILQ_INSERT_TAIL(&putter_ilist, pi_i, pi_entries); |
656 | else |
657 | TAILQ_INSERT_BEFORE(pi, pi_i, pi_entries); |
658 | |
659 | return i; |
660 | } |
661 | |
662 | MODULE(MODULE_CLASS_DRIVER, putter, NULL); |
663 | |
664 | static int |
665 | putter_modcmd(modcmd_t cmd, void *arg) |
666 | { |
667 | #ifdef _MODULE |
668 | devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; |
669 | |
670 | switch (cmd) { |
671 | case MODULE_CMD_INIT: |
672 | putterattach(); |
673 | return devsw_attach("putter" , NULL, &bmajor, |
674 | &putter_cdevsw, &cmajor); |
675 | case MODULE_CMD_FINI: |
676 | return ENOTTY; /* XXX: putterdetach */ |
677 | default: |
678 | return ENOTTY; |
679 | } |
680 | #else |
681 | if (cmd == MODULE_CMD_INIT) |
682 | return 0; |
683 | return ENOTTY; |
684 | #endif |
685 | } |
686 | |