1 /* 2 * Copyright 2007, Hugo Santos, hugosantos@gmail.com. All Rights Reserved. 3 * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved. 4 * Copyright 2004, Marcus Overhagen. All Rights Reserved. 5 * 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 #include "device.h" 11 12 #include <stdio.h> 13 14 #include <KernelExport.h> 15 #include <image.h> 16 #include <kernel/heap.h> 17 18 #include <compat/machine/resource.h> 19 #include <compat/dev/mii/mii.h> 20 #include <compat/sys/bus.h> 21 #include <compat/net/if_media.h> 22 23 #include <compat/dev/mii/miivar.h> 24 25 26 spinlock __haiku_intr_spinlock; 27 28 struct net_stack_module_info *gStack; 29 pci_module_info *gPci; 30 struct pci_x86_module_info *gPCIx86; 31 32 static struct list sRootDevices; 33 static int sNextUnit; 34 35 // #pragma mark - private functions 36 37 38 static device_t 39 init_device(device_t device, driver_t *driver) 40 { 41 list_init_etc(&device->children, offsetof(struct device, link)); 42 device->unit = sNextUnit++; 43 44 if (driver != NULL && device_set_driver(device, driver) < 0) 45 return NULL; 46 47 return device; 48 } 49 50 51 static device_t 52 new_device(driver_t *driver) 53 { 54 device_t dev = malloc(sizeof(struct device)); 55 if (dev == NULL) 56 return NULL; 57 58 memset(dev, 0, sizeof(struct device)); 59 60 if (init_device(dev, driver) == NULL) { 61 free(dev); 62 return NULL; 63 } 64 65 return dev; 66 } 67 68 69 static image_id 70 find_own_image() 71 { 72 int32 cookie = 0; 73 image_info info; 74 while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) { 75 if (((addr_t)info.text <= (addr_t)find_own_image 76 && (addr_t)info.text + (addr_t)info.text_size 77 > (addr_t)find_own_image)) { 78 // found our own image 79 return info.id; 80 } 81 } 82 83 return B_ENTRY_NOT_FOUND; 84 } 85 86 87 static device_method_signature_t 88 resolve_method(driver_t *driver, const char *name) 89 { 90 device_method_signature_t method = NULL; 91 int i; 92 93 for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) { 94 if (strcmp(driver->methods[i].name, name) == 0) 95 method = driver->methods[i].method; 96 } 97 98 if (method == NULL) 99 panic("resolve_method: method%s not found\n", name); 100 101 return method; 102 } 103 104 105 // #pragma mark - Device 106 107 108 void 109 driver_printf(const char *format, ...) 110 { 111 va_list vl; 112 va_start(vl, format); 113 driver_vprintf(format, vl); 114 va_end(vl); 115 } 116 117 118 static int 119 driver_vprintf_etc(const char *extra, const char *format, va_list vl) 120 { 121 char buf[256]; 122 int ret = vsnprintf(buf, sizeof(buf), format, vl); 123 124 if (extra) 125 dprintf("[%s] (%s) %s", gDriverName, extra, buf); 126 else 127 dprintf("[%s] %s", gDriverName, buf); 128 129 return ret; 130 } 131 132 133 int 134 driver_vprintf(const char *format, va_list vl) 135 { 136 return driver_vprintf_etc(NULL, format, vl); 137 } 138 139 140 int 141 device_printf(device_t dev, const char *format, ...) 142 { 143 va_list vl; 144 145 va_start(vl, format); 146 driver_vprintf_etc(dev->device_name, format, vl); 147 va_end(vl); 148 return 0; 149 } 150 151 152 void 153 device_set_desc(device_t dev, const char *desc) 154 { 155 dev->description = desc; 156 } 157 158 159 void 160 device_set_desc_copy(device_t dev, const char *desc) 161 { 162 dev->description = strdup(desc); 163 dev->flags |= DEVICE_DESC_ALLOCED; 164 } 165 166 167 const char * 168 device_get_desc(device_t dev) 169 { 170 return dev->description; 171 } 172 173 174 device_t 175 device_get_parent(device_t dev) 176 { 177 return dev->parent; 178 } 179 180 181 devclass_t 182 device_get_devclass(device_t dev) 183 { 184 // TODO find out what to do 185 return 0; 186 } 187 188 189 int 190 device_get_children(device_t dev, device_t **devlistp, int *devcountp) 191 { 192 int count; 193 device_t child = NULL; 194 device_t *list; 195 196 count = 0; 197 while ((child = list_get_next_item(&dev->children, child)) != NULL) { 198 count++; 199 } 200 201 list = malloc(count * sizeof(device_t)); 202 if (!list) 203 return (ENOMEM); 204 205 count = 0; 206 while ((child = list_get_next_item(&dev->children, child)) != NULL) { 207 list[count] = child; 208 count++; 209 } 210 211 *devlistp = list; 212 *devcountp = count; 213 214 return (0); 215 } 216 217 218 void 219 device_set_ivars(device_t dev, void *ivars) 220 { 221 dev->ivars = ivars; 222 } 223 224 225 void * 226 device_get_ivars(device_t dev) 227 { 228 return dev->ivars; 229 } 230 231 232 const char * 233 device_get_name(device_t dev) 234 { 235 if (dev == NULL) 236 return NULL; 237 238 return dev->device_name; 239 } 240 241 242 int 243 device_get_unit(device_t dev) 244 { 245 return dev->unit; 246 } 247 248 249 const char * 250 device_get_nameunit(device_t dev) 251 { 252 return dev->nameunit; 253 } 254 255 256 void * 257 device_get_softc(device_t dev) 258 { 259 return dev->softc; 260 } 261 262 263 void 264 device_set_softc(device_t dev, void *softc) 265 { 266 if (dev->softc == softc) 267 return; 268 269 if ((dev->flags & DEVICE_SOFTC_SET) == 0) { 270 // Not externally allocated. We own it so we must clean it up. 271 free(dev->softc); 272 } 273 274 dev->softc = softc; 275 if (dev->softc != NULL) 276 dev->flags |= DEVICE_SOFTC_SET; 277 else 278 dev->flags &= ~DEVICE_SOFTC_SET; 279 } 280 281 282 u_int32_t 283 device_get_flags(device_t dev) 284 { 285 return dev->flags; 286 } 287 288 289 int 290 device_set_driver(device_t dev, driver_t *driver) 291 { 292 int i; 293 294 dev->softc = malloc(driver->size); 295 if (dev->softc == NULL) 296 return -1; 297 298 memset(dev->softc, 0, driver->size); 299 dev->driver = driver; 300 301 for (i = 0; driver->methods[i].name != NULL; i++) { 302 device_method_t *mth = &driver->methods[i]; 303 304 if (strcmp(mth->name, "device_register") == 0) 305 dev->methods.device_register = (void *)mth->method; 306 else if (strcmp(mth->name, "device_probe") == 0) 307 dev->methods.probe = (void *)mth->method; 308 else if (strcmp(mth->name, "device_attach") == 0) 309 dev->methods.attach = (void *)mth->method; 310 else if (strcmp(mth->name, "device_detach") == 0) 311 dev->methods.detach = (void *)mth->method; 312 else if (strcmp(mth->name, "device_suspend") == 0) 313 dev->methods.suspend = (void *)mth->method; 314 else if (strcmp(mth->name, "device_resume") == 0) 315 dev->methods.resume = (void *)mth->method; 316 else if (strcmp(mth->name, "device_shutdown") == 0) 317 dev->methods.shutdown = (void *)mth->method; 318 else if (strcmp(mth->name, "miibus_readreg") == 0) 319 dev->methods.miibus_readreg = (void *)mth->method; 320 else if (strcmp(mth->name, "miibus_writereg") == 0) 321 dev->methods.miibus_writereg = (void *)mth->method; 322 else if (strcmp(mth->name, "miibus_statchg") == 0) 323 dev->methods.miibus_statchg = (void *)mth->method; 324 else if (!strcmp(mth->name, "miibus_linkchg")) 325 dev->methods.miibus_linkchg = (void *)mth->method; 326 else if (!strcmp(mth->name, "miibus_mediainit")) 327 dev->methods.miibus_mediainit = (void *)mth->method; 328 else if (!strcmp(mth->name, "bus_child_location_str")) 329 dev->methods.bus_child_location_str = (void *)mth->method; 330 else if (!strcmp(mth->name, "bus_child_pnpinfo_str")) 331 dev->methods.bus_child_pnpinfo_str = (void *)mth->method; 332 else if (!strcmp(mth->name, "bus_hinted_child")) 333 dev->methods.bus_hinted_child = (void *)mth->method; 334 else if (!strcmp(mth->name, "bus_print_child")) 335 dev->methods.bus_print_child = (void *)mth->method; 336 else if (!strcmp(mth->name, "bus_read_ivar")) 337 dev->methods.bus_read_ivar = (void *)mth->method; 338 else if (!strcmp(mth->name, "bus_get_dma_tag")) 339 dev->methods.bus_get_dma_tag = (void *)mth->method; 340 else 341 panic("device_set_driver: method %s not found\n", mth->name); 342 343 } 344 345 return 0; 346 } 347 348 349 int 350 device_is_alive(device_t device) 351 { 352 return (device->flags & DEVICE_ATTACHED) != 0; 353 } 354 355 356 device_t 357 device_add_child_driver(device_t parent, const char* name, driver_t* _driver, 358 int unit) 359 { 360 device_t child = NULL; 361 362 if (_driver == NULL && name != NULL) { 363 if (strcmp(name, "miibus") == 0) 364 child = new_device(&miibus_driver); 365 else { 366 // find matching driver structure 367 driver_t** driver; 368 char symbol[128]; 369 370 snprintf(symbol, sizeof(symbol), "__fbsd_%s_%s", name, 371 parent->driver->name); 372 if (get_image_symbol(find_own_image(), symbol, B_SYMBOL_TYPE_DATA, 373 (void**)&driver) == B_OK) { 374 child = new_device(*driver); 375 } else 376 device_printf(parent, "couldn't find symbol %s\n", symbol); 377 } 378 } else if (_driver != NULL) { 379 child = new_device(_driver); 380 } else 381 child = new_device(NULL); 382 383 if (child == NULL) 384 return NULL; 385 386 if (name != NULL) 387 strlcpy(child->device_name, name, sizeof(child->device_name)); 388 389 child->parent = parent; 390 391 if (parent != NULL) { 392 list_add_item(&parent->children, child); 393 child->root = parent->root; 394 } else { 395 if (sRootDevices.link.next == NULL) 396 list_init_etc(&sRootDevices, offsetof(struct device, link)); 397 list_add_item(&sRootDevices, child); 398 } 399 400 return child; 401 } 402 403 404 device_t 405 device_add_child(device_t parent, const char* name, int unit) 406 { 407 return device_add_child_driver(parent, name, NULL, unit); 408 } 409 410 411 /*! Delete the child and all of its children. Detach as necessary. 412 */ 413 int 414 device_delete_child(device_t parent, device_t child) 415 { 416 int status; 417 418 if (child == NULL) 419 return 0; 420 421 if (parent != NULL) 422 list_remove_item(&parent->children, child); 423 else 424 list_remove_item(&sRootDevices, child); 425 426 // We differentiate from the FreeBSD logic here - it will first delete 427 // the children, and will then detach the device. 428 // This has the problem that you cannot safely call device_delete_child() 429 // as you don't know if one of the children deletes its own children this 430 // way when it is detached. 431 // Therefore, we'll detach first, and then delete whatever is left. 432 433 parent = child; 434 child = NULL; 435 436 // detach children 437 while ((child = list_get_next_item(&parent->children, child)) != NULL) { 438 device_detach(child); 439 } 440 441 // detach device 442 status = device_detach(parent); 443 if (status != 0) 444 return status; 445 446 // delete children 447 while ((child = list_get_first_item(&parent->children)) != NULL) { 448 device_delete_child(parent, child); 449 } 450 451 // delete device 452 if (parent->flags & DEVICE_DESC_ALLOCED) 453 free((char *)parent->description); 454 455 // Delete softc if we were the ones to allocate it. 456 if ((parent->flags & DEVICE_SOFTC_SET) == 0) 457 free(parent->softc); 458 459 free(parent); 460 return 0; 461 } 462 463 464 int 465 device_is_attached(device_t device) 466 { 467 return (device->flags & DEVICE_ATTACHED) != 0; 468 } 469 470 471 int 472 device_attach(device_t device) 473 { 474 int result; 475 476 if (device->driver == NULL 477 || device->methods.attach == NULL) 478 return B_ERROR; 479 480 result = device->methods.attach(device); 481 482 if (result == 0) 483 atomic_or(&device->flags, DEVICE_ATTACHED); 484 485 if (result == 0 && HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE)) 486 result = start_wlan(device); 487 488 return result; 489 } 490 491 492 int 493 device_detach(device_t device) 494 { 495 if (device->driver == NULL) 496 return B_ERROR; 497 498 if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0 499 && device->methods.detach != NULL) { 500 int result = 0; 501 if (HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE)) 502 result = stop_wlan(device); 503 if (result != 0 && result != B_BAD_VALUE) { 504 atomic_or(&device->flags, DEVICE_ATTACHED); 505 return result; 506 } 507 508 result = device->methods.detach(device); 509 if (result != 0) { 510 atomic_or(&device->flags, DEVICE_ATTACHED); 511 return result; 512 } 513 } 514 515 return 0; 516 } 517 518 519 int 520 bus_generic_attach(device_t dev) 521 { 522 device_t child = NULL; 523 524 while ((child = list_get_next_item(&dev->children, child)) != NULL) { 525 if (child->driver == NULL) { 526 driver_t *driver = __haiku_select_miibus_driver(child); 527 if (driver == NULL) { 528 struct mii_attach_args *ma = device_get_ivars(child); 529 530 device_printf(dev, "No PHY module found (%x/%x)!\n", 531 MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2)); 532 } else 533 device_set_driver(child, driver); 534 } else 535 child->methods.probe(child); 536 537 if (child->driver != NULL) { 538 int result = device_attach(child); 539 if (result != 0) 540 return result; 541 } 542 } 543 544 return 0; 545 } 546 547 548 int 549 bus_generic_detach(device_t device) 550 { 551 device_t child = NULL; 552 553 if ((device->flags & DEVICE_ATTACHED) == 0) 554 return B_ERROR; 555 556 while (true) { 557 child = list_get_next_item(&device->children, child); 558 if (child == NULL) 559 break; 560 561 device_detach(child); 562 } 563 564 return 0; 565 } 566 567 568 // #pragma mark - Misc, Malloc 569 570 571 device_t 572 find_root_device(int unit) 573 { 574 device_t device = NULL; 575 576 while ((device = list_get_next_item(&sRootDevices, device)) != NULL) { 577 if (device->unit <= unit) 578 return device; 579 } 580 581 return NULL; 582 } 583 584 585 driver_t * 586 __haiku_probe_miibus(device_t dev, driver_t *drivers[]) 587 { 588 driver_t *selected = NULL; 589 int i, selectedResult = 0; 590 591 if (drivers == NULL) 592 return NULL; 593 594 for (i = 0; drivers[i]; i++) { 595 device_probe_t *probe = (device_probe_t *) 596 resolve_method(drivers[i], "device_probe"); 597 if (probe) { 598 int result = probe(dev); 599 if (result >= 0) { 600 if (selected == NULL || result < selectedResult) { 601 selected = drivers[i]; 602 selectedResult = result; 603 device_printf(dev, "Found MII: %s\n", selected->name); 604 } 605 } 606 } 607 } 608 609 return selected; 610 } 611 612 613 int 614 printf(const char *format, ...) 615 { 616 char buf[256]; 617 va_list vl; 618 va_start(vl, format); 619 vsnprintf(buf, sizeof(buf), format, vl); 620 va_end(vl); 621 dprintf(buf); 622 623 return 0; 624 } 625 626 627 int 628 resource_int_value(const char *name, int unit, const char *resname, 629 int *result) 630 { 631 /* no support for hints */ 632 return -1; 633 } 634 635 636 int 637 resource_disabled(const char *name, int unit) 638 { 639 int error, value; 640 641 error = resource_int_value(name, unit, "disabled", &value); 642 if (error) 643 return (0); 644 return (value); 645 } 646