subr_bus.c revision 37592
1/*- 2 * Copyright (c) 1997,1998 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: subr_bus.c,v 1.2 1998/06/14 13:45:58 dfr Exp $ 27 */ 28 29#include <sys/param.h> 30#include <sys/queue.h> 31#include <sys/malloc.h> 32#include <sys/kernel.h> 33#include <sys/module.h> 34#include <sys/bus_private.h> 35#include <sys/systm.h> 36 37/* 38 * Method table handling 39 */ 40 41static int next_method_offset = 1; 42static int methods_count = 0; 43static int methods_size = 0; 44 45struct method { 46 int offset; 47 char* name; 48}; 49 50static struct method *methods = 0; 51 52static void 53register_method(struct device_op_desc *desc) 54{ 55 int i; 56 struct method* m; 57 58 for (i = 0; i < methods_count; i++) 59 if (!strcmp(methods[i].name, desc->name)) { 60 desc->offset = methods[i].offset; 61 return; 62 } 63 64 if (methods_count == methods_size) { 65 struct method* p; 66 67 methods_size += 10; 68 p = (struct method*) malloc(methods_size * sizeof(struct method), 69 M_DEVBUF, M_NOWAIT); 70 if (!p) 71 panic("register_method: out of memory"); 72 if (methods) { 73 bcopy(methods, p, methods_count * sizeof(struct method)); 74 free(methods, M_DEVBUF); 75 } 76 methods = p; 77 } 78 m = &methods[methods_count++]; 79 m->name = malloc(strlen(desc->name) + 1, M_DEVBUF, M_NOWAIT); 80 if (!m->name) 81 panic("register_method: out of memory"); 82 strcpy(m->name, desc->name); 83 desc->offset = m->offset = next_method_offset++; 84} 85 86static int error_method(void) 87{ 88 return ENXIO; 89} 90 91static struct device_ops null_ops = { 92 1, 93 { error_method } 94}; 95 96static void 97compile_methods(driver_t *driver) 98{ 99 device_ops_t ops; 100 struct device_method *m; 101 int i; 102 103 /* 104 * First register any methods which need it. 105 */ 106 for (i = 0, m = driver->methods; m->desc; i++, m++) 107 if (!m->desc->offset) 108 register_method(m->desc); 109 110 /* 111 * Then allocate the compiled op table. 112 */ 113 ops = malloc(sizeof(struct device_ops) + (next_method_offset-1) * sizeof(devop_t), 114 M_DEVBUF, M_NOWAIT); 115 if (!ops) 116 panic("compile_methods: out of memory"); 117 ops->maxoffset = next_method_offset; 118 for (i = 0; i < next_method_offset; i++) 119 ops->methods[i] = error_method; 120 for (i = 0, m = driver->methods; m->desc; i++, m++) 121 ops->methods[m->desc->offset] = m->func; 122 driver->ops = ops; 123} 124 125/* 126 * Devclass implementation 127 */ 128 129static devclass_list_t devclasses; 130 131static void 132devclass_init(void) 133{ 134 TAILQ_INIT(&devclasses); 135} 136 137static devclass_t 138devclass_find_internal(const char *classname, int create) 139{ 140 devclass_t dc; 141 142 for (dc = TAILQ_FIRST(&devclasses); dc; dc = TAILQ_NEXT(dc, link)) 143 if (!strcmp(dc->name, classname)) 144 return dc; 145 146 if (create) { 147 dc = malloc(sizeof(struct devclass) + strlen(classname) + 1, 148 M_DEVBUF, M_NOWAIT); 149 if (!dc) 150 return NULL; 151 dc->name = (char*) (dc + 1); 152 strcpy(dc->name, classname); 153 dc->devices = NULL; 154 dc->maxunit = 0; 155 dc->nextunit = 0; 156 TAILQ_INIT(&dc->drivers); 157 TAILQ_INSERT_TAIL(&devclasses, dc, link); 158 } 159 160 return dc; 161} 162 163devclass_t 164devclass_find(const char *classname) 165{ 166 return devclass_find_internal(classname, FALSE); 167} 168 169int 170devclass_add_driver(devclass_t dc, driver_t *driver) 171{ 172 /* 173 * Compile the drivers methods. 174 */ 175 compile_methods(driver); 176 177 /* 178 * Make sure the devclass which the driver is implementing exists. 179 */ 180 devclass_find_internal(driver->name, TRUE); 181 182 TAILQ_INSERT_TAIL(&dc->drivers, driver, link); 183 184 return 0; 185} 186 187int 188devclass_delete_driver(devclass_t dc, driver_t *driver) 189{ 190 device_t bus; 191 device_t dev; 192 int i; 193 int error; 194 195 /* 196 * Disassociate from any devices. We iterate through all the 197 * devices attached to any bus in this class. 198 */ 199 for (i = 0; i < dc->maxunit; i++) { 200 if (dc->devices[i]) { 201 bus = dc->devices[i]->parent; 202 for (dev = TAILQ_FIRST(&bus->children); dev; 203 dev = TAILQ_NEXT(dev, link)) 204 if (dev->driver == driver) { 205 if (error = DEVICE_DETACH(dev)) 206 return error; 207 device_set_driver(dev, NULL); 208 } 209 } 210 } 211 212 TAILQ_REMOVE(&dc->drivers, driver, link); 213 return 0; 214} 215 216driver_t * 217devclass_find_driver(devclass_t dc, const char *classname) 218{ 219 driver_t *driver; 220 221 for (driver = TAILQ_FIRST(&dc->drivers); driver; 222 driver = TAILQ_NEXT(driver, link)) 223 if (!strcmp(driver->name, classname)) 224 return driver; 225 226 return NULL; 227} 228 229const char * 230devclass_get_name(devclass_t dc) 231{ 232 return dc->name; 233} 234 235device_t 236devclass_get_device(devclass_t dc, int unit) 237{ 238 if (unit < 0 || unit >= dc->maxunit) 239 return NULL; 240 return dc->devices[unit]; 241} 242 243void * 244devclass_get_softc(devclass_t dc, int unit) 245{ 246 device_t dev; 247 248 if (unit < 0 || unit >= dc->maxunit) 249 return NULL; 250 dev = dc->devices[unit]; 251 if (!dev || dev->state < DS_ATTACHED) 252 return NULL; 253 return dev->softc; 254} 255 256int 257devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) 258{ 259 int i; 260 int count; 261 device_t dev; 262 device_t *list; 263 264 count = 0; 265 for (i = 0; i < dc->maxunit; i++) 266 if (dc->devices[i]) 267 count++; 268 269 list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT); 270 if (!list) 271 return ENOMEM; 272 273 count = 0; 274 for (i = 0; i < dc->maxunit; i++) 275 if (dc->devices[i]) { 276 list[count] = dc->devices[i]; 277 count++; 278 } 279 280 *devlistp = list; 281 *devcountp = count; 282 283 return 0; 284} 285 286int 287devclass_get_maxunit(devclass_t dc) 288{ 289 return dc->maxunit; 290} 291 292static int 293devclass_alloc_unit(devclass_t dc, int *unitp) 294{ 295 int unit = *unitp; 296 297 /* 298 * If we have been given a wired unit number, check for existing 299 * device. 300 */ 301 if (unit != -1) { 302 device_t dev; 303 dev = devclass_get_device(dc, unit); 304 if (dev) { 305 printf("devclass_alloc_unit: %s%d already exists, using next available unit number\n", dc->name, unit); 306 unit = -1; 307 } 308 } 309 310 if (unit == -1) { 311 unit = dc->nextunit; 312 dc->nextunit++; 313 } else if (dc->nextunit <= unit) 314 dc->nextunit = unit + 1; 315 316 if (unit >= dc->maxunit) { 317 device_t *newlist; 318 int newsize; 319 320 newsize = (dc->maxunit ? 2 * dc->maxunit 321 : MINALLOCSIZE / sizeof(device_t)); 322 newlist = malloc(sizeof(device_t) * newsize, M_DEVBUF, M_NOWAIT); 323 if (!newlist) 324 return ENOMEM; 325 bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit); 326 bzero(newlist + dc->maxunit, 327 sizeof(device_t) * (newsize - dc->maxunit)); 328 if (dc->devices) 329 free(dc->devices, M_DEVBUF); 330 dc->devices = newlist; 331 dc->maxunit = newsize; 332 } 333 334 *unitp = unit; 335 return 0; 336} 337 338static int 339devclass_add_device(devclass_t dc, device_t dev) 340{ 341 int error; 342 343 if (error = devclass_alloc_unit(dc, &dev->unit)) 344 return error; 345 dc->devices[dev->unit] = dev; 346 dev->devclass = dc; 347 return 0; 348} 349 350static int 351devclass_delete_device(devclass_t dc, device_t dev) 352{ 353 if (dev->devclass != dc 354 || dc->devices[dev->unit] != dev) 355 panic("devclass_delete_device: inconsistent device class"); 356 dc->devices[dev->unit] = NULL; 357 if (dev->flags & DF_WILDCARD) 358 dev->unit = -1; 359 dev->devclass = NULL; 360 while (dc->nextunit > 0 && dc->devices[dc->nextunit - 1] == NULL) 361 dc->nextunit--; 362 return 0; 363} 364 365static device_t 366make_device(device_t parent, const char *name, 367 int unit, void *ivars) 368{ 369 driver_t *driver; 370 device_t dev; 371 devclass_t dc; 372 int error; 373 374 if (name) { 375 dc = devclass_find_internal(name, TRUE); 376 if (!dc) { 377 printf("make_device: can't find device class %s\n", name); 378 return NULL; 379 } 380 381 if (error = devclass_alloc_unit(dc, &unit)) 382 return NULL; 383 } else 384 dc = NULL; 385 386 dev = malloc(sizeof(struct device), M_DEVBUF, M_NOWAIT); 387 if (!dev) 388 return 0; 389 390 dev->parent = parent; 391 TAILQ_INIT(&dev->children); 392 dev->ops = &null_ops; 393 dev->driver = NULL; 394 dev->devclass = dc; 395 dev->unit = unit; 396 dev->desc = NULL; 397 dev->busy = 0; 398 dev->flags = DF_ENABLED; 399 if (unit == -1) 400 dev->flags |= DF_WILDCARD; 401 if (name) 402 dev->flags |= DF_FIXEDCLASS; 403 dev->ivars = ivars; 404 dev->softc = NULL; 405 406 if (dc) 407 dc->devices[unit] = dev; 408 409 dev->state = DS_NOTPRESENT; 410 411 return dev; 412} 413 414static void 415device_print_child(device_t dev, device_t child) 416{ 417 printf("%s%d", device_get_name(child), device_get_unit(child)); 418 if (device_is_alive(child)) { 419 if (device_get_desc(child)) 420 printf(": <%s>", device_get_desc(child)); 421 BUS_PRINT_CHILD(dev, child); 422 } else 423 printf(" not found"); 424 printf("\n"); 425} 426 427device_t 428device_add_child(device_t dev, const char *name, int unit, void *ivars) 429{ 430 device_t child; 431 432 child = make_device(dev, name, unit, ivars); 433 434 TAILQ_INSERT_TAIL(&dev->children, child, link); 435 436 return child; 437} 438 439device_t 440device_add_child_after(device_t dev, device_t place, const char *name, 441 int unit, void *ivars) 442{ 443 device_t child; 444 445 child = make_device(dev, name, unit, ivars); 446 447 if (place) { 448 TAILQ_INSERT_AFTER(&dev->children, place, dev, link); 449 } else { 450 TAILQ_INSERT_HEAD(&dev->children, dev, link); 451 } 452 453 return child; 454} 455 456int 457device_delete_child(device_t dev, device_t child) 458{ 459 int error; 460 461 if (error = DEVICE_DETACH(child)) 462 return error; 463 if (child->devclass) 464 devclass_delete_device(child->devclass, child); 465 TAILQ_REMOVE(&dev->children, child, link); 466 free(dev, M_DEVBUF); 467 468 return 0; 469} 470 471/* 472 * Find only devices attached to this bus. 473 */ 474device_t 475device_find_child(device_t dev, const char *classname, int unit) 476{ 477 devclass_t dc; 478 device_t child; 479 480 dc = devclass_find(classname); 481 if (!dc) 482 return NULL; 483 484 child = devclass_get_device(dc, unit); 485 if (child && child->parent == dev) 486 return child; 487 return NULL; 488} 489 490static driver_t * 491first_matching_driver(devclass_t dc, device_t dev) 492{ 493 if (dev->devclass) 494 return devclass_find_driver(dc, dev->devclass->name); 495 else 496 return TAILQ_FIRST(&dc->drivers); 497} 498 499static driver_t * 500next_matching_driver(devclass_t dc, device_t dev, driver_t *last) 501{ 502 if (dev->devclass) { 503 driver_t *driver; 504 for (driver = TAILQ_NEXT(last, link); driver; 505 driver = TAILQ_NEXT(driver, link)) 506 if (!strcmp(dev->devclass->name, driver->name)) 507 return driver; 508 return NULL; 509 } else 510 return TAILQ_NEXT(last, link); 511} 512 513static int 514device_probe_child(device_t dev, device_t child) 515{ 516 devclass_t dc; 517 driver_t *driver; 518 void *softc; 519 520 dc = dev->devclass; 521 if (dc == NULL) 522 panic("device_probe_child: parent device has no devclass"); 523 524 if (child->state == DS_ALIVE) 525 return 0; 526 527 for (driver = first_matching_driver(dc, child); 528 driver; 529 driver = next_matching_driver(dc, child, driver)) { 530 device_set_driver(child, driver); 531 if (DEVICE_PROBE(child) == 0) { 532 if (!child->devclass) 533 device_set_devclass(child, driver->name); 534 child->state = DS_ALIVE; 535 return 0; 536 } 537 } 538 539 return ENXIO; 540} 541 542device_t 543device_get_parent(device_t dev) 544{ 545 return dev->parent; 546} 547 548driver_t * 549device_get_driver(device_t dev) 550{ 551 return dev->driver; 552} 553 554devclass_t 555device_get_devclass(device_t dev) 556{ 557 return dev->devclass; 558} 559 560const char * 561device_get_name(device_t dev) 562{ 563 if (dev->devclass) 564 return devclass_get_name(dev->devclass); 565 return NULL; 566} 567 568int 569device_get_unit(device_t dev) 570{ 571 return dev->unit; 572} 573 574const char * 575device_get_desc(device_t dev) 576{ 577 return dev->desc; 578} 579 580void 581device_set_desc(device_t dev, const char* desc) 582{ 583 dev->desc = desc; 584} 585 586void * 587device_get_softc(device_t dev) 588{ 589 return dev->softc; 590} 591 592void * 593device_get_ivars(device_t dev) 594{ 595 return dev->ivars; 596} 597 598device_state_t 599device_get_state(device_t dev) 600{ 601 return dev->state; 602} 603 604void 605device_enable(device_t dev) 606{ 607 dev->flags |= DF_ENABLED; 608} 609 610void 611device_disable(device_t dev) 612{ 613 dev->flags &= ~DF_ENABLED; 614} 615 616void 617device_busy(device_t dev) 618{ 619 if (dev->state < DS_ATTACHED) 620 panic("device_busy: called for unattached device"); 621 if (dev->busy == 0 && dev->parent) 622 device_busy(dev->parent); 623 dev->busy++; 624 dev->state = DS_BUSY; 625} 626 627void 628device_unbusy(device_t dev) 629{ 630 if (dev->state != DS_BUSY) 631 panic("device_unbusy: called for non-busy device"); 632 dev->busy--; 633 if (dev->busy == 0) { 634 if (dev->parent) 635 device_unbusy(dev->parent); 636 dev->state = DS_ATTACHED; 637 } 638} 639 640int 641device_is_enabled(device_t dev) 642{ 643 return (dev->flags & DF_ENABLED) != 0; 644} 645 646int 647device_is_alive(device_t dev) 648{ 649 return dev->state >= DS_ALIVE; 650} 651 652int 653device_set_devclass(device_t dev, const char *classname) 654{ 655 devclass_t dc; 656 657 if (dev->devclass) { 658 printf("device_set_devclass: device class already set\n"); 659 return EINVAL; 660 } 661 662 dc = devclass_find_internal(classname, TRUE); 663 if (!dc) 664 return ENOMEM; 665 666 return devclass_add_device(dc, dev); 667} 668 669int 670device_set_driver(device_t dev, driver_t *driver) 671{ 672 if (dev->state >= DS_ATTACHED) 673 return EBUSY; 674 675 if (dev->driver == driver) 676 return 0; 677 678 if (dev->softc) { 679 free(dev->softc, M_DEVBUF); 680 dev->softc = NULL; 681 } 682 dev->ops = &null_ops; 683 dev->driver = driver; 684 if (driver) { 685 dev->ops = driver->ops; 686 dev->softc = malloc(driver->softc, M_DEVBUF, M_NOWAIT); 687 bzero(dev->softc, driver->softc); 688 } 689 return 0; 690} 691 692int 693device_probe_and_attach(device_t dev) 694{ 695 device_t bus = dev->parent; 696 int error; 697 698 if (dev->state >= DS_ALIVE) 699 return 0; 700 701 if (dev->flags & DF_ENABLED) { 702 device_probe_child(bus, dev); 703 device_print_child(bus, dev); 704 if (dev->state == DS_ALIVE) { 705 error = DEVICE_ATTACH(dev); 706 if (!error) 707 dev->state = DS_ATTACHED; 708 else { 709 printf("device_probe_and_attach: %s%n attach returned %d\n", 710 dev->driver->name, dev->unit, error); 711 device_set_driver(dev, NULL); 712 dev->state = DS_NOTPRESENT; 713 } 714 } 715 } else 716 printf("%s%d: disabled, not probed.\n", 717 dev->devclass->name, dev->unit); 718 719 return 0; 720} 721 722int 723device_detach(device_t dev) 724{ 725 int error; 726 727 if (dev->state == DS_BUSY) 728 return EBUSY; 729 if (dev->state != DS_ATTACHED) 730 return 0; 731 732 if (error = DEVICE_DETACH(dev)) 733 return error; 734 735 if (!(dev->flags & DF_FIXEDCLASS)) 736 devclass_delete_device(dev->devclass, dev); 737 738 dev->state = DS_NOTPRESENT; 739 device_set_driver(dev, NULL); 740 741 return 0; 742} 743 744int 745device_shutdown(device_t dev) 746{ 747 if (dev->state < DS_ATTACHED) 748 return 0; 749 return DEVICE_SHUTDOWN(dev); 750} 751 752/* 753 * Some useful method implementations to make life easier for bus drivers. 754 */ 755int 756bus_generic_attach(device_t dev) 757{ 758 device_t child; 759 int error; 760 761 for (child = TAILQ_FIRST(&dev->children); 762 child; child = TAILQ_NEXT(child, link)) 763 device_probe_and_attach(child); 764 765 return 0; 766} 767 768int 769bus_generic_detach(device_t dev) 770{ 771 device_t child; 772 int error; 773 774 if (dev->state != DS_ATTACHED) 775 return EBUSY; 776 777 for (child = TAILQ_FIRST(&dev->children); 778 child; child = TAILQ_NEXT(child, link)) 779 DEVICE_DETACH(child); 780 781 return 0; 782} 783 784int 785bus_generic_shutdown(device_t dev) 786{ 787 device_t child; 788 789 for (child = TAILQ_FIRST(&dev->children); 790 child; child = TAILQ_NEXT(child, link)) 791 DEVICE_SHUTDOWN(child); 792 793 return 0; 794} 795 796void 797bus_generic_print_child(device_t dev, device_t child) 798{ 799} 800 801int 802bus_generic_read_ivar(device_t dev, device_t child, int index, u_long* result) 803{ 804 return ENOENT; 805} 806 807int 808bus_generic_write_ivar(device_t dev, device_t child, int index, u_long value) 809{ 810 return ENOENT; 811} 812 813void * 814bus_generic_create_intr(device_t dev, device_t child, int irq, driver_intr_t *intr, void *arg) 815{ 816 /* Propagate up the bus hierarchy until someone handles it. */ 817 if (dev->parent) 818 return BUS_CREATE_INTR(dev->parent, dev, irq, intr, arg); 819 else 820 return NULL; 821} 822 823int 824bus_generic_connect_intr(device_t dev, void *ih) 825{ 826 /* Propagate up the bus hierarchy until someone handles it. */ 827 if (dev->parent) 828 return BUS_CONNECT_INTR(dev->parent, ih); 829 else 830 return EINVAL; 831} 832 833static int root_create_intr(device_t dev, device_t child, 834 driver_intr_t *intr, void *arg) 835{ 836 /* 837 * If an interrupt mapping gets to here something bad has happened. 838 * Should probably panic. 839 */ 840 return EINVAL; 841} 842 843static device_method_t root_methods[] = { 844 /* Bus interface */ 845 DEVMETHOD(bus_print_child, bus_generic_print_child), 846 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 847 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 848 DEVMETHOD(bus_create_intr, root_create_intr), 849 850 { 0, 0 } 851}; 852 853static driver_t root_driver = { 854 "root", 855 root_methods, 856 DRIVER_TYPE_MISC, 857 1, /* no softc */ 858}; 859 860device_t root_bus; 861devclass_t root_devclass; 862 863static int 864root_bus_module_handler(module_t mod, modeventtype_t what, void* arg) 865{ 866 switch (what) { 867 case MOD_LOAD: 868 devclass_init(); 869 compile_methods(&root_driver); 870 root_bus = make_device(NULL, "root", 0, NULL); 871 root_bus->ops = root_driver.ops; 872 root_bus->driver = &root_driver; 873 root_bus->state = DS_ATTACHED; 874 root_devclass = devclass_find("root"); 875 return 0; 876 } 877 878 return 0; 879} 880 881static moduledata_t root_bus_mod = { 882 "rootbus", 883 root_bus_module_handler, 884 0 885}; 886DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 887 888void 889root_bus_configure() 890{ 891 device_t dev; 892 int error; 893 894 for (dev = TAILQ_FIRST(&root_bus->children); dev; 895 dev = TAILQ_NEXT(dev, link)) { 896 device_probe_and_attach(dev); 897 } 898} 899 900int 901driver_module_handler(module_t mod, modeventtype_t what, void* arg) 902{ 903 struct driver_module_data* data = (struct driver_module_data*) arg; 904 devclass_t bus_devclass = devclass_find_internal(data->busname, TRUE); 905 int error; 906 907 switch (what) { 908 case MOD_LOAD: 909 if (error = devclass_add_driver(bus_devclass, 910 data->driver)) 911 return error; 912 *data->devclass = 913 devclass_find_internal(data->driver->name, TRUE); 914 break; 915 916 case MOD_UNLOAD: 917 if (error = devclass_delete_driver(bus_devclass, 918 data->driver)) 919 return error; 920 break; 921 } 922 923 if (data->chainevh) 924 return data->chainevh(mod, what, data->chainarg); 925 else 926 return 0; 927} 928