subr_bus.c revision 36849
1/*- 2 * Copyright (c) 1997 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$ 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 37device_t 38bus_get_device(bus_t bus) 39{ 40 return bus->dev; 41} 42 43void 44bus_print_device(bus_t bus, device_t dev) 45{ 46 printf("%s%d", device_get_name(dev), device_get_unit(dev)); 47 if (device_is_alive(dev)) { 48 if (device_get_desc(dev)) 49 printf(": <%s>", device_get_desc(dev)); 50 bus->ops->print_device(bus, dev); 51 } else 52 printf(" not found"); 53 printf("\n"); 54} 55 56int 57bus_read_ivar(bus_t bus, device_t dev, 58 int index, u_long *result) 59{ 60 return bus->ops->read_ivar(bus, dev, index, result); 61} 62 63int 64bus_write_ivar(bus_t bus, device_t dev, 65 int index, u_long value) 66{ 67 return bus->ops->write_ivar(bus, dev, index, value); 68} 69 70int 71bus_map_intr(bus_t bus, device_t dev, driver_intr_t *intr, void *arg) 72{ 73 return bus->ops->map_intr(bus, dev, intr, arg); 74} 75 76static devclass_list_t devclasses; 77 78static void 79devclass_init(void) 80{ 81 TAILQ_INIT(&devclasses); 82} 83 84static devclass_t 85devclass_find_internal(const char *classname, int create) 86{ 87 devclass_t dc; 88 89 for (dc = TAILQ_FIRST(&devclasses); dc; dc = TAILQ_NEXT(dc, link)) 90 if (!strcmp(dc->name, classname)) 91 return dc; 92 93 if (create) { 94 dc = malloc(sizeof(struct devclass) + strlen(classname) + 1, 95 M_DEVBUF, M_NOWAIT); 96 if (!dc) 97 return NULL; 98 dc->name = (char*) (dc + 1); 99 strcpy(dc->name, classname); 100 dc->devices = NULL; 101 dc->maxunit = 0; 102 dc->nextunit = 0; 103 TAILQ_INIT(&dc->drivers); 104 TAILQ_INSERT_TAIL(&devclasses, dc, link); 105 } 106 107 return dc; 108} 109 110devclass_t 111devclass_find(const char *classname) 112{ 113 return devclass_find_internal(classname, FALSE); 114} 115 116int 117devclass_add_driver(devclass_t dc, driver_t *driver) 118{ 119 /* 120 * Make sure the devclass which the driver is implementing exists. 121 */ 122 devclass_find_internal(driver->name, TRUE); 123 124 TAILQ_INSERT_TAIL(&dc->drivers, driver, link); 125 126 return 0; 127} 128 129int 130devclass_delete_driver(devclass_t dc, driver_t *driver) 131{ 132 bus_t bus; 133 device_t dev; 134 int i; 135 int error; 136 137 /* 138 * Disassociate from any devices. We iterate through all the 139 * devices attached to any bus in this class. 140 */ 141 for (i = 0; i < dc->maxunit; i++) { 142 if (dc->devices[i]) { 143 bus = dc->devices[i]->softc; 144 for (dev = TAILQ_FIRST(&bus->devices); dev; 145 dev = TAILQ_NEXT(dev, link)) 146 if (dev->driver == driver) { 147 if (error = device_detach(dev)) 148 return error; 149 device_set_driver(dev, NULL); 150 } 151 } 152 } 153 154 TAILQ_REMOVE(&dc->drivers, driver, link); 155 return 0; 156} 157 158driver_t * 159devclass_find_driver(devclass_t dc, const char *classname) 160{ 161 driver_t *driver; 162 163 for (driver = TAILQ_FIRST(&dc->drivers); driver; 164 driver = TAILQ_NEXT(driver, link)) 165 if (!strcmp(driver->name, classname)) 166 return driver; 167 168 return NULL; 169} 170 171const char * 172devclass_get_name(devclass_t dc) 173{ 174 return dc->name; 175} 176 177device_t 178devclass_get_device(devclass_t dc, int unit) 179{ 180 if (unit < 0 || unit >= dc->maxunit) 181 return NULL; 182 return dc->devices[unit]; 183} 184 185void * 186devclass_get_softc(devclass_t dc, int unit) 187{ 188 device_t dev; 189 190 if (unit < 0 || unit >= dc->maxunit) 191 return NULL; 192 dev = dc->devices[unit]; 193 if (!dev || dev->state < DS_ATTACHED) 194 return NULL; 195 return dev->softc; 196} 197 198int 199devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) 200{ 201 int i; 202 int count; 203 device_t dev; 204 device_t *list; 205 206 count = 0; 207 for (i = 0; i < dc->maxunit; i++) 208 if (dc->devices[i]) 209 count++; 210 211 list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT); 212 if (!list) 213 return ENOMEM; 214 215 count = 0; 216 for (i = 0; i < dc->maxunit; i++) 217 if (dc->devices[i]) { 218 list[count] = dc->devices[i]; 219 count++; 220 } 221 222 *devlistp = list; 223 *devcountp = count; 224 225 return 0; 226} 227 228int 229devclass_get_maxunit(devclass_t dc) 230{ 231 return dc->maxunit; 232} 233 234static int 235devclass_alloc_unit(devclass_t dc, int *unitp) 236{ 237 int unit = *unitp; 238 239 /* 240 * If we have been given a wired unit number, check for existing 241 * device. 242 */ 243 if (unit != -1) { 244 device_t dev; 245 dev = devclass_get_device(dc, unit); 246 if (dev) { 247 printf("devclass_alloc_unit: %s%d already exists, using next available unit number\n", dc->name, unit); 248 unit = -1; 249 } 250 } 251 252 if (unit == -1) { 253 unit = dc->nextunit; 254 dc->nextunit++; 255 } else if (dc->nextunit <= unit) 256 dc->nextunit = unit + 1; 257 258 if (unit >= dc->maxunit) { 259 device_t *newlist; 260 int newsize; 261 262 newsize = (dc->maxunit ? 2 * dc->maxunit 263 : MINALLOCSIZE / sizeof(device_t)); 264 newlist = malloc(sizeof(device_t) * newsize, M_DEVBUF, M_NOWAIT); 265 if (!newlist) 266 return ENOMEM; 267 bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit); 268 bzero(newlist + dc->maxunit, 269 sizeof(device_t) * (newsize - dc->maxunit)); 270 if (dc->devices) 271 free(dc->devices, M_DEVBUF); 272 dc->devices = newlist; 273 dc->maxunit = newsize; 274 } 275 276 *unitp = unit; 277 return 0; 278} 279 280static int 281devclass_add_device(devclass_t dc, device_t dev) 282{ 283 int error; 284 285 if (error = devclass_alloc_unit(dc, &dev->unit)) 286 return error; 287 dc->devices[dev->unit] = dev; 288 dev->devclass = dc; 289 return 0; 290} 291 292static int 293devclass_delete_device(devclass_t dc, device_t dev) 294{ 295 if (dev->devclass != dc 296 || dc->devices[dev->unit] != dev) 297 panic("devclass_delete_device: inconsistent device class"); 298 dc->devices[dev->unit] = NULL; 299 if (dev->flags & DF_WILDCARD) 300 dev->unit = -1; 301 dev->devclass = NULL; 302 while (dc->nextunit > 0 && dc->devices[dc->nextunit - 1] == NULL) 303 dc->nextunit--; 304 return 0; 305} 306 307static device_t 308make_device(bus_t bus, const char *name, 309 int unit, void *ivars) 310{ 311 driver_t *driver; 312 device_t dev; 313 devclass_t dc; 314 int error; 315 316 if (name) { 317 dc = devclass_find_internal(name, TRUE); 318 if (!dc) { 319 printf("make_device: can't find device class %s\n", name); 320 return NULL; 321 } 322 323 if (error = devclass_alloc_unit(dc, &unit)) 324 return NULL; 325 } else 326 dc = NULL; 327 328 dev = malloc(sizeof(struct device), M_DEVBUF, M_NOWAIT); 329 if (!dev) 330 return 0; 331 332 dev->parent = bus; 333 dev->driver = NULL; 334 dev->devclass = dc; 335 dev->unit = unit; 336 dev->desc = NULL; 337 dev->busy = 0; 338 dev->flags = DF_ENABLED; 339 if (unit == -1) 340 dev->flags |= DF_WILDCARD; 341 if (name) 342 dev->flags |= DF_FIXEDCLASS; 343 dev->ivars = ivars; 344 dev->softc = NULL; 345 346 if (dc) 347 dc->devices[unit] = dev; 348 349 dev->state = DS_NOTPRESENT; 350 351 return dev; 352} 353 354void 355bus_init(bus_t bus, device_t dev, bus_ops_t *ops) 356{ 357 bus->ops = ops; 358 bus->dev = dev; 359 TAILQ_INIT(&bus->devices); 360} 361 362device_t 363bus_add_device(bus_t bus, const char *name, int unit, void *ivars) 364{ 365 device_t dev; 366 367 dev = make_device(bus, name, unit, ivars); 368 369 TAILQ_INSERT_TAIL(&bus->devices, dev, link); 370 371 return dev; 372} 373 374device_t 375bus_add_device_after(bus_t bus, device_t place, const char *name, 376 int unit, void *ivars) 377{ 378 device_t dev; 379 380 dev = make_device(bus, name, unit, ivars); 381 382 if (place) { 383 TAILQ_INSERT_AFTER(&bus->devices, place, dev, link); 384 } else { 385 TAILQ_INSERT_HEAD(&bus->devices, dev, link); 386 } 387 388 return dev; 389} 390 391int 392bus_delete_device(bus_t bus, device_t dev) 393{ 394 int error; 395 396 if (error = device_detach(dev)) 397 return error; 398 if (dev->devclass) 399 devclass_delete_device(dev->devclass, dev); 400 TAILQ_REMOVE(&bus->devices, dev, link); 401 free(dev, M_DEVBUF); 402 403 return 0; 404} 405 406/* 407 * Find only devices attached to this bus. 408 */ 409device_t 410bus_find_device(bus_t bus, const char *classname, int unit) 411{ 412 devclass_t dc; 413 device_t dev; 414 415 dc = devclass_find(classname); 416 if (!dc) 417 return NULL; 418 419 dev = devclass_get_device(dc, unit); 420 if (dev && dev->parent == bus) 421 return dev; 422 return NULL; 423} 424 425static driver_t * 426first_matching_driver(devclass_t dc, device_t dev) 427{ 428 if (dev->devclass) 429 return devclass_find_driver(dc, dev->devclass->name); 430 else 431 return TAILQ_FIRST(&dc->drivers); 432} 433 434static driver_t * 435next_matching_driver(devclass_t dc, device_t dev, driver_t *last) 436{ 437 if (dev->devclass) { 438 driver_t *driver; 439 for (driver = TAILQ_NEXT(last, link); driver; 440 driver = TAILQ_NEXT(driver, link)) 441 if (!strcmp(dev->devclass->name, driver->name)) 442 return driver; 443 return NULL; 444 } else 445 return TAILQ_NEXT(last, link); 446} 447 448static int 449bus_probe_device(bus_t bus, device_t dev) 450{ 451 devclass_t dc; 452 driver_t *driver; 453 void *softc; 454 455 dc = bus->dev->devclass; 456 if (dc == NULL) 457 panic("bus_probe_device: bus' device has no devclass"); 458 459 if (dev->state == DS_ALIVE) 460 return 0; 461 462 for (driver = first_matching_driver(dc, dev); 463 driver; 464 driver = next_matching_driver(dc, dev, driver)) { 465 device_set_driver(dev, driver); 466 if (driver->probe(bus, dev) == 0) { 467 if (!dev->devclass) 468 device_set_devclass(dev, driver->name); 469 dev->state = DS_ALIVE; 470 return 0; 471 } 472 } 473 474 return ENXIO; 475} 476 477int 478bus_generic_attach(bus_t parent, device_t busdev) 479{ 480 bus_t bus = busdev->softc; 481 device_t dev; 482 int error; 483 484 for (dev = TAILQ_FIRST(&bus->devices); 485 dev; dev = TAILQ_NEXT(dev, link)) 486 device_probe_and_attach(dev); 487 488 return 0; 489} 490 491int 492bus_generic_detach(bus_t parent, device_t busdev) 493{ 494 bus_t bus = busdev->softc; 495 device_t dev; 496 int error; 497 498 if (busdev->state != DS_ATTACHED) 499 return EBUSY; 500 501 for (dev = TAILQ_FIRST(&bus->devices); 502 dev; dev = TAILQ_NEXT(dev, link)) 503 device_detach(dev); 504 505 return 0; 506} 507 508int 509bus_generic_shutdown(bus_t parent, device_t busdev) 510{ 511 bus_t bus = busdev->softc; 512 device_t dev; 513 514 for (dev = TAILQ_FIRST(&bus->devices); 515 dev; dev = TAILQ_NEXT(dev, link)) 516 device_shutdown(dev); 517 518 return 0; 519} 520 521bus_t 522device_get_parent(device_t dev) 523{ 524 return dev->parent; 525} 526 527driver_t * 528device_get_driver(device_t dev) 529{ 530 return dev->driver; 531} 532 533devclass_t 534device_get_devclass(device_t dev) 535{ 536 return dev->devclass; 537} 538 539const char * 540device_get_name(device_t dev) 541{ 542 if (dev->devclass) 543 return devclass_get_name(dev->devclass); 544 return NULL; 545} 546 547int 548device_get_unit(device_t dev) 549{ 550 return dev->unit; 551} 552 553const char * 554device_get_desc(device_t dev) 555{ 556 return dev->desc; 557} 558 559void 560device_set_desc(device_t dev, const char* desc) 561{ 562 dev->desc = desc; 563} 564 565void * 566device_get_softc(device_t dev) 567{ 568 return dev->softc; 569} 570 571void * 572device_get_ivars(device_t dev) 573{ 574 return dev->ivars; 575} 576 577device_state_t 578device_get_state(device_t dev) 579{ 580 return dev->state; 581} 582 583void 584device_enable(device_t dev) 585{ 586 dev->flags |= DF_ENABLED; 587} 588 589void 590device_disable(device_t dev) 591{ 592 dev->flags &= ~DF_ENABLED; 593} 594 595void 596device_busy(device_t dev) 597{ 598 if (dev->state < DS_ATTACHED) 599 panic("device_busy: called for unattached device"); 600 if (dev->busy == 0 && dev->parent) 601 device_busy(dev->parent->dev); 602 dev->busy++; 603 dev->state = DS_BUSY; 604} 605 606void 607device_unbusy(device_t dev) 608{ 609 if (dev->state != DS_BUSY) 610 panic("device_unbusy: called for non-busy device"); 611 dev->busy--; 612 if (dev->busy == 0) { 613 if (dev->parent->dev) 614 device_unbusy(dev->parent->dev); 615 dev->state = DS_ATTACHED; 616 } 617} 618 619int 620device_is_enabled(device_t dev) 621{ 622 return (dev->flags & DF_ENABLED) != 0; 623} 624 625int 626device_is_alive(device_t dev) 627{ 628 return dev->state >= DS_ALIVE; 629} 630 631int 632device_set_devclass(device_t dev, const char *classname) 633{ 634 devclass_t dc; 635 636 if (dev->devclass) { 637 printf("device_set_devclass: device class already set\n"); 638 return EINVAL; 639 } 640 641 dc = devclass_find_internal(classname, TRUE); 642 if (!dc) 643 return ENOMEM; 644 645 return devclass_add_device(dc, dev); 646} 647 648int 649device_set_driver(device_t dev, driver_t *driver) 650{ 651 if (dev->state >= DS_ATTACHED) 652 return EBUSY; 653 654 if (dev->driver == driver) 655 return 0; 656 657 if (dev->softc) { 658 free(dev->softc, M_DEVBUF); 659 dev->softc = NULL; 660 } 661 dev->driver = driver; 662 if (driver) { 663 dev->softc = malloc(driver->softc, M_DEVBUF, M_NOWAIT); 664 bzero(dev->softc, driver->softc); 665 } 666 return 0; 667} 668 669int 670device_probe_and_attach(device_t dev) 671{ 672 bus_t bus = dev->parent; 673 int error; 674 675 if (dev->state >= DS_ALIVE) 676 return 0; 677 678 if (dev->flags & DF_ENABLED) { 679 bus_probe_device(bus, dev); 680 bus_print_device(bus, dev); 681 if (dev->state == DS_ALIVE) { 682 error = dev->driver->attach(bus, dev); 683 if (!error) 684 dev->state = DS_ATTACHED; 685 else { 686 printf("device_probe_and_attach: %s%n attach returned %d\n", 687 dev->driver->name, dev->unit, error); 688 device_set_driver(dev, NULL); 689 dev->state = DS_NOTPRESENT; 690 } 691 } 692 } else 693 printf("%s%d: disabled, not probed.\n", 694 dev->devclass->name, dev->unit); 695 696 return 0; 697} 698 699int 700device_detach(device_t dev) 701{ 702 int error; 703 704 if (dev->state == DS_BUSY) 705 return EBUSY; 706 if (dev->state != DS_ATTACHED) 707 return 0; 708 709 if (dev->driver->detach) { 710 if (error = dev->driver->detach(dev->parent, dev)) 711 return error; 712 } else 713 return EBUSY; 714 715 if (!(dev->flags & DF_FIXEDCLASS)) 716 devclass_delete_device(dev->devclass, dev); 717 718 dev->state = DS_NOTPRESENT; 719 device_set_driver(dev, NULL); 720 721 return 0; 722} 723 724int 725device_shutdown(device_t dev) 726{ 727 if (dev->state < DS_ATTACHED) 728 return 0; 729 if (dev->driver->shutdown) 730 return dev->driver->shutdown(dev->parent, dev); 731 else 732 return 0; 733} 734 735void 736null_print_device(bus_t bus, device_t dev) 737{ 738} 739 740int 741null_read_ivar(bus_t bus, device_t dev, int index, u_long* result) 742{ 743 return ENOENT; 744} 745 746int 747null_write_ivar(bus_t bus, device_t dev, int index, u_long value) 748{ 749 return ENOENT; 750} 751 752int 753null_map_intr(bus_t bus, device_t dev, driver_intr_t *intr, void *arg) 754{ 755 /* Propagate up the bus hierarchy until someone handles it. */ 756 if (bus->dev) 757 return bus_map_intr(bus->dev->parent, bus->dev, intr, arg); 758 else 759 return EINVAL; 760} 761 762bus_ops_t null_bus_ops = { 763 null_print_device, 764 null_read_ivar, 765 null_write_ivar, 766 null_map_intr, 767}; 768 769static void 770root_bus_print_device(bus_t bus, device_t dev) 771{ 772} 773 774static int root_bus_map_intr(bus_t bus, device_t dev, 775 driver_intr_t *intr, void *arg) 776{ 777 return EINVAL; 778} 779 780static bus_ops_t root_bus_ops = { 781 root_bus_print_device, 782 null_read_ivar, 783 null_write_ivar, 784 root_bus_map_intr, 785}; 786 787static struct bus the_root_bus; 788bus_t root_bus = &the_root_bus; 789device_t root_device; 790devclass_t root_devclass; 791 792static int 793root_bus_module_handler(module_t mod, modeventtype_t what, void* arg) 794{ 795 switch (what) { 796 case MOD_LOAD: 797 devclass_init(); 798 root_device = make_device(NULL, "root", 0, NULL); 799 root_device->state = DS_ATTACHED; 800 bus_init(root_bus, root_device, &root_bus_ops); 801 root_devclass = devclass_find("root"); 802 return 0; 803 } 804 805 return 0; 806} 807 808static moduledata_t root_bus_mod = { 809 "rootbus", 810 root_bus_module_handler, 811 0 812}; 813DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 814 815void 816root_bus_configure() 817{ 818 device_t dev; 819 int error; 820 821 for (dev = TAILQ_FIRST(&root_bus->devices); dev; 822 dev = TAILQ_NEXT(dev, link)) { 823 device_probe_and_attach(dev); 824 } 825} 826 827int 828driver_module_handler(module_t mod, modeventtype_t what, void* arg) 829{ 830 struct driver_module_data* data = (struct driver_module_data*) arg; 831 devclass_t bus_devclass = devclass_find_internal(data->busname, TRUE); 832 int error; 833 834 switch (what) { 835 case MOD_LOAD: 836 if (error = devclass_add_driver(bus_devclass, 837 data->driver)) 838 return error; 839 *data->devclass = 840 devclass_find_internal(data->driver->name, TRUE); 841 break; 842 843 case MOD_UNLOAD: 844 if (error = devclass_delete_driver(bus_devclass, 845 data->driver)) 846 return error; 847 break; 848 } 849 850 if (data->chainevh) 851 return data->chainevh(mod, what, data->chainarg); 852 else 853 return 0; 854} 855