1 /* 2 * Copyright (c) 2010 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Alex Hornung <ahornung@gmail.com> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/proc.h> 38 #include <sys/buf.h> 39 #include <sys/conf.h> 40 #include <sys/poll.h> 41 #include <sys/event.h> 42 #include <sys/ioccom.h> 43 #include <sys/malloc.h> 44 #include <sys/ctype.h> 45 #include <sys/syslog.h> 46 #include <sys/udev.h> 47 #include <sys/devfs.h> 48 #include <libprop/proplib.h> 49 50 #include <sys/thread2.h> 51 52 MALLOC_DEFINE(M_UDEV, "udev", "udev allocs"); 53 54 /* XXX: use UUIDs for identification; would need help from devfs */ 55 56 static cdev_t udev_dev; 57 static d_open_t udev_dev_open; 58 static d_close_t udev_dev_close; 59 static d_read_t udev_dev_read; 60 static d_poll_t udev_dev_poll; 61 static d_kqfilter_t udev_dev_kqfilter; 62 static d_ioctl_t udev_dev_ioctl; 63 64 static int _udev_dict_set_cstr(prop_dictionary_t, const char *, char *); 65 static int _udev_dict_set_int(prop_dictionary_t, const char *, int64_t); 66 static int _udev_dict_set_uint(prop_dictionary_t, const char *, uint64_t); 67 static int _udev_dict_delete_key(prop_dictionary_t, const char *); 68 static prop_dictionary_t udev_init_dict_event(cdev_t, const char *); 69 static int udev_init_dict(cdev_t); 70 static int udev_destroy_dict(cdev_t); 71 static void udev_event_insert(int, prop_dictionary_t); 72 static struct udev_event_kernel *udev_event_remove(void); 73 static void udev_event_free(struct udev_event_kernel *); 74 static char *udev_event_externalize(struct udev_event_kernel *); 75 static void udev_getdevs_scan_callback(cdev_t, void *); 76 static int udev_getdevs_ioctl(struct plistref *, u_long, prop_dictionary_t); 77 static void udev_dev_filter_detach(struct knote *); 78 static int udev_dev_filter_read(struct knote *, long); 79 80 struct cmd_function { 81 const char *cmd; 82 int (*fn)(struct plistref *, u_long, prop_dictionary_t); 83 }; 84 85 struct udev_prop_ctx { 86 prop_array_t cdevs; 87 int error; 88 }; 89 90 struct udev_event_kernel { 91 struct udev_event ev; 92 TAILQ_ENTRY(udev_event_kernel) link; 93 }; 94 95 struct udev_softc { 96 int opened; 97 int initiated; 98 99 struct selinfo sel; 100 101 int qlen; 102 struct lock lock; 103 TAILQ_HEAD(, udev_event_kernel) ev_queue; /* list of thread_io */ 104 } udevctx; 105 106 static struct dev_ops udev_dev_ops = { 107 { "udev", 0, D_KQFILTER }, 108 .d_open = udev_dev_open, 109 .d_close = udev_dev_close, 110 .d_read = udev_dev_read, 111 .d_poll = udev_dev_poll, 112 .d_kqfilter = udev_dev_kqfilter, 113 .d_ioctl = udev_dev_ioctl 114 }; 115 116 struct cmd_function cmd_fn[] = { 117 { .cmd = "getdevs", .fn = udev_getdevs_ioctl}, 118 {NULL, NULL} 119 }; 120 121 static int 122 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) 123 { 124 prop_string_t ps; 125 126 KKASSERT(dict != NULL); 127 128 ps = prop_string_create_cstring(str); 129 if (ps == NULL) 130 return ENOMEM; 131 132 if (prop_dictionary_set(dict, key, ps) == false) { 133 prop_object_release(ps); 134 return ENOMEM; 135 } 136 137 prop_object_release(ps); 138 return 0; 139 } 140 141 static int 142 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) 143 { 144 prop_number_t pn; 145 146 KKASSERT(dict != NULL); 147 148 pn = prop_number_create_integer(val); 149 if (pn == NULL) 150 return ENOMEM; 151 152 if (prop_dictionary_set(dict, key, pn) == false) { 153 prop_object_release(pn); 154 return ENOMEM; 155 } 156 157 prop_object_release(pn); 158 return 0; 159 } 160 161 static int 162 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) 163 { 164 prop_number_t pn; 165 166 KKASSERT(dict != NULL); 167 168 pn = prop_number_create_unsigned_integer(val); 169 if (pn == NULL) 170 return ENOMEM; 171 172 if (prop_dictionary_set(dict, key, pn) == false) { 173 prop_object_release(pn); 174 return ENOMEM; 175 } 176 177 prop_object_release(pn); 178 return 0; 179 } 180 181 static int 182 _udev_dict_delete_key(prop_dictionary_t dict, const char *key) 183 { 184 KKASSERT(dict != NULL); 185 186 prop_dictionary_remove(dict, key); 187 188 return 0; 189 } 190 191 /* 192 * Initialize an event dictionary, which contains three parameters to 193 * identify the device referred to (name, devnum, kptr) and the affected key. 194 */ 195 static prop_dictionary_t 196 udev_init_dict_event(cdev_t dev, const char *key) 197 { 198 prop_dictionary_t dict; 199 uint64_t kptr; 200 int error; 201 202 kptr = (uint64_t)(uintptr_t)dev; 203 KKASSERT(dev != NULL); 204 205 dict = prop_dictionary_create(); 206 if (dict == NULL) { 207 log(LOG_DEBUG, "udev_init_dict_event: prop_dictionary_create() failed\n"); 208 return NULL; 209 } 210 211 if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name))) 212 goto error_out; 213 if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode))) 214 goto error_out; 215 if ((error = _udev_dict_set_uint(dict, "kptr", kptr))) 216 goto error_out; 217 if ((error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key)))) 218 goto error_out; 219 220 error_out: 221 prop_object_release(dict); 222 return NULL; 223 } 224 225 int 226 udev_dict_set_cstr(cdev_t dev, const char *key, char *str) 227 { 228 prop_dictionary_t dict; 229 int error; 230 231 KKASSERT(dev != NULL); 232 233 /* Queue a key update event */ 234 dict = udev_init_dict_event(dev, key); 235 if (dict == NULL) 236 return ENOMEM; 237 if ((error = _udev_dict_set_cstr(dict, "value", str))) { 238 prop_object_release(dict); 239 return error; 240 } 241 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 242 prop_object_release(dict); 243 244 return _udev_dict_set_cstr(dev->si_dict, key, str); 245 } 246 247 int 248 udev_dict_set_int(cdev_t dev, const char *key, int64_t val) 249 { 250 prop_dictionary_t dict; 251 int error; 252 253 KKASSERT(dev != NULL); 254 255 /* Queue a key update event */ 256 dict = udev_init_dict_event(dev, key); 257 if (dict == NULL) 258 return ENOMEM; 259 if ((error = _udev_dict_set_int(dict, "value", val))) { 260 prop_object_release(dict); 261 return error; 262 } 263 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 264 prop_object_release(dict); 265 266 return _udev_dict_set_int(dev->si_dict, key, val); 267 } 268 269 int 270 udev_dict_set_uint(cdev_t dev, const char *key, uint64_t val) 271 { 272 prop_dictionary_t dict; 273 int error; 274 275 KKASSERT(dev != NULL); 276 277 /* Queue a key update event */ 278 dict = udev_init_dict_event(dev, key); 279 if (dict == NULL) 280 return ENOMEM; 281 if ((error = _udev_dict_set_uint(dict, "value", val))) { 282 prop_object_release(dict); 283 return error; 284 } 285 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 286 prop_object_release(dict); 287 288 return _udev_dict_set_uint(dev->si_dict, key, val); 289 } 290 291 int 292 udev_dict_delete_key(cdev_t dev, const char *key) 293 { 294 prop_dictionary_t dict; 295 296 KKASSERT(dev != NULL); 297 298 /* Queue a key removal event */ 299 dict = udev_init_dict_event(dev, key); 300 if (dict == NULL) 301 return ENOMEM; 302 udev_event_insert(UDEV_EV_KEY_REMOVE, dict); 303 prop_object_release(dict); 304 305 return _udev_dict_delete_key(dev->si_dict, key); 306 } 307 308 static int 309 udev_init_dict(cdev_t dev) 310 { 311 prop_dictionary_t dict; 312 uint64_t kptr; 313 int error; 314 315 kptr = (uint64_t)(uintptr_t)dev; 316 317 KKASSERT(dev != NULL); 318 dict = prop_dictionary_create(); 319 if (dict == NULL) { 320 log(LOG_DEBUG, "udev_init_dict: prop_dictionary_create() failed\n"); 321 return ENOMEM; 322 } 323 324 if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name))) 325 goto error_out; 326 if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode))) 327 goto error_out; 328 if ((error = _udev_dict_set_uint(dict, "kptr", kptr))) 329 goto error_out; 330 331 /* XXX: The next 3 are marginallly useful, if at all */ 332 if ((error = _udev_dict_set_uint(dict, "uid", dev->si_uid))) 333 goto error_out; 334 if ((error = _udev_dict_set_uint(dict, "gid", dev->si_gid))) 335 goto error_out; 336 if ((error = _udev_dict_set_int(dict, "mode", dev->si_perms))) 337 goto error_out; 338 339 if ((error = _udev_dict_set_int(dict, "major", umajor(dev->si_inode)))) 340 goto error_out; 341 if ((error = _udev_dict_set_int(dict, "minor", dev->si_uminor))) 342 goto error_out; 343 344 dev->si_dict = dict; 345 return 0; 346 347 error_out: 348 dev->si_dict = NULL; 349 prop_object_release(dict); 350 return error; 351 } 352 353 static int 354 udev_destroy_dict(cdev_t dev) 355 { 356 KKASSERT(dev != NULL); 357 358 if (dev->si_dict != NULL) { 359 prop_object_release(dev->si_dict); 360 dev->si_dict = NULL; 361 } 362 363 return 0; 364 } 365 366 static void 367 udev_event_insert(int ev_type, prop_dictionary_t dict) 368 { 369 struct udev_event_kernel *ev; 370 371 /* Only start queing events after client has initiated properly */ 372 if (!udevctx.initiated) 373 return; 374 375 /* XXX: use objcache eventually */ 376 ev = kmalloc(sizeof(*ev), M_UDEV, M_WAITOK); 377 ev->ev.ev_dict = prop_dictionary_copy(dict); 378 if (ev->ev.ev_dict == NULL) { 379 kfree(ev, M_UDEV); 380 return; 381 } 382 ev->ev.ev_type = ev_type; 383 384 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 385 TAILQ_INSERT_TAIL(&udevctx.ev_queue, ev, link); 386 ++udevctx.qlen; 387 lockmgr(&udevctx.lock, LK_RELEASE); 388 389 wakeup(&udevctx); 390 selwakeup(&udevctx.sel); 391 } 392 393 static struct udev_event_kernel * 394 udev_event_remove(void) 395 { 396 struct udev_event_kernel *ev; 397 398 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 399 if (TAILQ_EMPTY(&udevctx.ev_queue)) { 400 lockmgr(&udevctx.lock, LK_RELEASE); 401 return NULL; 402 } 403 404 ev = TAILQ_FIRST(&udevctx.ev_queue); 405 TAILQ_REMOVE(&udevctx.ev_queue, ev, link); 406 --udevctx.qlen; 407 lockmgr(&udevctx.lock, LK_RELEASE); 408 409 return ev; 410 } 411 412 static void 413 udev_event_free(struct udev_event_kernel *ev) 414 { 415 /* XXX: use objcache eventually */ 416 kfree(ev, M_UDEV); 417 } 418 419 static char * 420 udev_event_externalize(struct udev_event_kernel *ev) 421 { 422 prop_dictionary_t dict; 423 char *xml; 424 int error; 425 426 427 dict = prop_dictionary_create(); 428 if (dict == NULL) { 429 log(LOG_DEBUG, "udev_event_externalize: prop_dictionary_create() failed\n"); 430 return NULL; 431 } 432 433 if ((error = _udev_dict_set_int(dict, "evtype", ev->ev.ev_type))) { 434 prop_object_release(dict); 435 return NULL; 436 } 437 438 if (prop_dictionary_set(dict, "evdict", ev->ev.ev_dict) == false) { 439 prop_object_release(dict); 440 return NULL; 441 } 442 443 prop_object_release(ev->ev.ev_dict); 444 445 xml = prop_dictionary_externalize(dict); 446 447 prop_object_release(dict); 448 449 return xml; 450 } 451 452 int 453 udev_event_attach(cdev_t dev, char *name, int alias) 454 { 455 prop_dictionary_t dict; 456 int error; 457 458 KKASSERT(dev != NULL); 459 460 error = udev_init_dict(dev); 461 if (error) 462 goto error_out; 463 464 if (alias) { 465 dict = prop_dictionary_copy(dev->si_dict); 466 if (dict == NULL) 467 goto error_out; 468 469 if ((error = _udev_dict_set_cstr(dict, "name", name))) { 470 prop_object_release(dict); 471 goto error_out; 472 } 473 474 _udev_dict_set_int(dict, "alias", 1); 475 476 udev_event_insert(UDEV_EVENT_ATTACH, dict); 477 prop_object_release(dict); 478 } else { 479 _udev_dict_set_int(dev->si_dict, "alias", 0); 480 udev_event_insert(UDEV_EVENT_ATTACH, dev->si_dict); 481 } 482 483 error_out: 484 return error; 485 } 486 487 int 488 udev_event_detach(cdev_t dev, char *name, int alias) 489 { 490 prop_dictionary_t dict; 491 492 KKASSERT(dev != NULL); 493 494 if (alias) { 495 dict = prop_dictionary_copy(dev->si_dict); 496 if (dict == NULL) 497 goto error_out; 498 499 if (_udev_dict_set_cstr(dict, "name", name)) { 500 prop_object_release(dict); 501 goto error_out; 502 } 503 504 _udev_dict_set_int(dict, "alias", 1); 505 506 udev_event_insert(UDEV_EVENT_DETACH, dict); 507 prop_object_release(dict); 508 } else { 509 udev_event_insert(UDEV_EVENT_DETACH, dev->si_dict); 510 } 511 512 error_out: 513 udev_destroy_dict(dev); 514 515 return 0; 516 } 517 518 /* 519 * dev stuff 520 */ 521 static int 522 udev_dev_open(struct dev_open_args *ap) 523 { 524 if (udevctx.opened) 525 return EBUSY; 526 527 udevctx.opened = 1; 528 529 return 0; 530 } 531 532 static int 533 udev_dev_close(struct dev_close_args *ap) 534 { 535 udevctx.opened = 0; 536 udevctx.initiated = 0; 537 wakeup(&udevctx); 538 539 return 0; 540 } 541 542 static int 543 udev_dev_poll(struct dev_poll_args *ap) 544 { 545 int revents = 0; 546 547 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 548 if (ap->a_events & (POLLIN | POLLRDNORM)) { 549 if (!TAILQ_EMPTY(&udevctx.ev_queue)) 550 revents = ap->a_events & (POLLIN | POLLRDNORM); 551 else 552 selrecord(curthread, &udevctx.sel); 553 } 554 lockmgr(&udevctx.lock, LK_RELEASE); 555 556 ap->a_events = revents; 557 return 0; 558 } 559 560 static struct filterops udev_dev_read_filtops = 561 { 1, NULL, udev_dev_filter_detach, udev_dev_filter_read }; 562 563 static int 564 udev_dev_kqfilter(struct dev_kqfilter_args *ap) 565 { 566 struct knote *kn = ap->a_kn; 567 struct klist *klist; 568 569 ap->a_result = 0; 570 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 571 572 switch (kn->kn_filter) { 573 case EVFILT_READ: 574 kn->kn_fop = &udev_dev_read_filtops; 575 break; 576 default: 577 ap->a_result = 1; 578 lockmgr(&udevctx.lock, LK_RELEASE); 579 return (0); 580 } 581 582 crit_enter(); 583 klist = &udevctx.sel.si_note; 584 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 585 crit_exit(); 586 587 lockmgr(&udevctx.lock, LK_RELEASE); 588 589 return (0); 590 } 591 592 static void 593 udev_dev_filter_detach(struct knote *kn) 594 { 595 struct klist *klist; 596 597 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 598 crit_enter(); 599 klist = &udevctx.sel.si_note; 600 SLIST_REMOVE(klist, kn, knote, kn_selnext); 601 crit_exit(); 602 lockmgr(&udevctx.lock, LK_RELEASE); 603 } 604 605 static int 606 udev_dev_filter_read(struct knote *kn, long hint) 607 { 608 int ready = 0; 609 610 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 611 if (!TAILQ_EMPTY(&udevctx.ev_queue)) 612 ready = 1; 613 lockmgr(&udevctx.lock, LK_RELEASE); 614 615 return (ready); 616 } 617 618 static int 619 udev_dev_read(struct dev_read_args *ap) 620 { 621 struct udev_event_kernel *ev; 622 struct uio *uio = ap->a_uio; 623 char *xml; 624 size_t len; 625 int error; 626 627 628 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 629 630 for (;;) { 631 if ((ev = udev_event_remove()) != NULL) { 632 if ((xml = udev_event_externalize(ev)) == NULL) { 633 lockmgr(&udevctx.lock, LK_RELEASE); 634 return ENOMEM; 635 } 636 637 len = strlen(xml) + 1; /* account for NULL-termination */ 638 if (uio->uio_resid < len) { 639 error = ENOMEM; 640 } else { 641 error = uiomove((caddr_t)xml, len, uio); 642 } 643 644 kfree(xml, M_TEMP); 645 udev_event_free(ev); 646 lockmgr(&udevctx.lock, LK_RELEASE); 647 return error; 648 } 649 650 if ((error = lksleep(&udevctx, &udevctx.lock, 0, "udevq", 0))) { 651 lockmgr(&udevctx.lock, LK_RELEASE); 652 return error; 653 } 654 } 655 656 lockmgr(&udevctx.lock, LK_RELEASE); 657 658 } 659 660 static int 661 udev_dev_ioctl(struct dev_ioctl_args *ap) 662 { 663 prop_dictionary_t dict; 664 prop_object_t po; 665 prop_string_t ps; 666 struct plistref *pref; 667 int i, error; 668 669 error = 0; 670 671 switch(ap->a_cmd) { 672 case UDEVPROP: 673 /* Use proplib(3) for userspace/kernel communication */ 674 pref = (struct plistref *)ap->a_data; 675 error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd, &dict); 676 if (error) 677 return error; 678 679 po = prop_dictionary_get(dict, "command"); 680 if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) { 681 log(LOG_DEBUG, "udev: prop_dictionary_get() failed\n"); 682 prop_object_release(dict); 683 return EINVAL; 684 } 685 686 ps = po; 687 /* Handle cmd */ 688 for(i = 0; cmd_fn[i].cmd != NULL; i++) { 689 if (prop_string_equals_cstring(ps, cmd_fn[i].cmd)) 690 break; 691 } 692 693 if (cmd_fn[i].cmd != NULL) { 694 log(LOG_DEBUG, "udev: ioctl %s called\n", cmd_fn[i].cmd); 695 error = cmd_fn[i].fn(pref, ap->a_cmd, dict); 696 } else { 697 error = EINVAL; 698 } 699 700 //prop_object_release(po); 701 kprintf("foo\n"); 702 prop_object_release(dict); 703 break; 704 default: 705 error = ENOTTY; /* Inappropriate ioctl for device */ 706 break; 707 } 708 709 return(error); 710 } 711 712 static void 713 udev_getdevs_scan_callback(cdev_t cdev, void *arg) 714 { 715 struct udev_prop_ctx *ctx = arg; 716 717 KKASSERT(arg != NULL); 718 719 if (cdev->si_dict == NULL) 720 return; 721 722 if (prop_array_add(ctx->cdevs, cdev->si_dict) == false) { 723 ctx->error = EINVAL; 724 return; 725 } 726 } 727 728 static int 729 udev_getdevs_ioctl(struct plistref *pref, u_long cmd, prop_dictionary_t dict) 730 { 731 prop_dictionary_t odict; 732 struct udev_prop_ctx ctx; 733 int error; 734 735 ctx.error = 0; 736 ctx.cdevs = prop_array_create(); 737 if (ctx.cdevs == NULL) { 738 log(LOG_DEBUG, "udev_getdevs_ioctl: prop_array_create() failed\n"); 739 return EINVAL; 740 } 741 742 /* XXX: need devfs_scan_alias_callback() */ 743 devfs_scan_callback(udev_getdevs_scan_callback, &ctx); 744 745 if (ctx.error != 0) { 746 prop_object_release(ctx.cdevs); 747 return (ctx.error); 748 } 749 udevctx.initiated = 1; 750 751 odict = prop_dictionary_create(); 752 if (odict == NULL) { 753 return ENOMEM; 754 } 755 756 if ((prop_dictionary_set(odict, "array", ctx.cdevs)) == 0) { 757 log(LOG_DEBUG, "udev_getdevs_ioctl: prop_dictionary_set failed\n"); 758 prop_object_release(odict); 759 return ENOMEM; 760 } 761 762 error = prop_dictionary_copyout_ioctl(pref, cmd, odict); 763 764 /* XXX: need to release ctx.cdevs? */ 765 prop_object_release(odict); 766 return error; 767 } 768 769 770 /* 771 * SYSINIT stuff 772 */ 773 static void 774 udev_init(void) 775 { 776 lockinit(&udevctx.lock, "udevevq", 0, LK_CANRECURSE); 777 TAILQ_INIT(&udevctx.ev_queue); 778 } 779 780 static void 781 udev_uninit(void) 782 { 783 } 784 785 static void 786 udev_dev_init(void) 787 { 788 udev_dev = make_dev(&udev_dev_ops, 789 0, 790 UID_ROOT, 791 GID_WHEEL, 792 0600, 793 "udev"); 794 } 795 796 static void 797 udev_dev_uninit(void) 798 { 799 destroy_dev(udev_dev); 800 } 801 802 SYSINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY, udev_init, NULL); 803 SYSUNINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY, udev_uninit, NULL); 804 SYSINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY, udev_dev_init, NULL); 805 SYSUNINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY, udev_dev_uninit, NULL); 806