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