xf86pciBus.c revision e005038a
1/* 2 * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the copyright holder(s) 23 * and author(s) shall not be used in advertising or otherwise to promote 24 * the sale, use or other dealings in this Software without prior written 25 * authorization from the copyright holder(s) and author(s). 26 */ 27 28/* 29 * This file contains the interfaces to the bus-specific code 30 */ 31#ifdef HAVE_XORG_CONFIG_H 32#include <xorg-config.h> 33#endif 34 35#include <ctype.h> 36#include <stdlib.h> 37#include <unistd.h> 38#include <X11/X.h> 39#include <pciaccess.h> 40#include "os.h" 41#include "Pci.h" 42#include "xf86.h" 43#include "xf86Priv.h" 44#include "dirent.h" /* DIR, FILE type definitions */ 45 46/* Bus-specific headers */ 47#include "xf86Bus.h" 48 49#define XF86_OS_PRIVS 50#include "xf86_OSproc.h" 51 52#define PCI_VENDOR_GENERIC 0x00FF 53 54/* Bus-specific globals */ 55int pciSlotClaimed = 0; 56 57#define PCIINFOCLASSES(c) \ 58 ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \ 59 || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \ 60 || ((((c) & 0x00ffff00) \ 61 == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \ 62 || ((((c) & 0x00ffff00) \ 63 == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) ) 64 65/* 66 * PCI classes that have messages printed always. The others are only 67 * have a message printed when the vendor/dev IDs are recognised. 68 */ 69#define PCIALWAYSPRINTCLASSES(c) \ 70 ( (((c) & 0x00ffff00) \ 71 == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \ 72 || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \ 73 || ((((c) & 0x00ffff00) \ 74 == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) ) 75 76#define IS_VGA(c) \ 77 (((c) & 0x00ffff00) \ 78 == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8))) 79 80static struct pci_slot_match xf86IsolateDevice = { 81 PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0 82}; 83 84/* 85 * xf86Bus.c interface 86 */ 87 88void 89xf86PciProbe(void) 90{ 91 int i = 0, k; 92 int num = 0; 93 struct pci_device *info; 94 struct pci_device_iterator *iter; 95 struct pci_device **xf86PciVideoInfo = NULL; 96 97 if (!xf86scanpci()) { 98 xf86PciVideoInfo = NULL; 99 return; 100 } 101 102 iter = pci_slot_match_iterator_create(&xf86IsolateDevice); 103 while ((info = pci_device_next(iter)) != NULL) { 104 if (PCIINFOCLASSES(info->device_class)) { 105 num++; 106 xf86PciVideoInfo = xnfreallocarray(xf86PciVideoInfo, 107 num + 1, 108 sizeof(struct pci_device *)); 109 xf86PciVideoInfo[num] = NULL; 110 xf86PciVideoInfo[num - 1] = info; 111 112 pci_device_probe(info); 113 if (primaryBus.type == BUS_NONE && pci_device_is_boot_vga(info)) { 114 primaryBus.type = BUS_PCI; 115 primaryBus.id.pci = info; 116 } 117 info->user_data = 0; 118 } 119 } 120 free(iter); 121 122 /* If we haven't found a primary device try a different heuristic */ 123 if (primaryBus.type == BUS_NONE && num) { 124 for (i = 0; i < num; i++) { 125 uint16_t command; 126 127 info = xf86PciVideoInfo[i]; 128 pci_device_cfg_read_u16(info, &command, 4); 129 130 if ((command & PCI_CMD_MEM_ENABLE) 131 && ((num == 1) || IS_VGA(info->device_class))) { 132 if (primaryBus.type == BUS_NONE) { 133 primaryBus.type = BUS_PCI; 134 primaryBus.id.pci = info; 135 } 136 else { 137 xf86Msg(X_NOTICE, 138 "More than one possible primary device found\n"); 139 primaryBus.type ^= (BusType) (-1); 140 } 141 } 142 } 143 } 144 145 /* Print a summary of the video devices found */ 146 for (k = 0; k < num; k++) { 147 const char *prim = " "; 148 Bool memdone = FALSE, iodone = FALSE; 149 150 info = xf86PciVideoInfo[k]; 151 152 if (!PCIALWAYSPRINTCLASSES(info->device_class)) 153 continue; 154 155 if (xf86IsPrimaryPci(info)) 156 prim = "*"; 157 158 xf86Msg(X_PROBED, "PCI:%s(%u@%u:%u:%u) %04x:%04x:%04x:%04x ", prim, 159 info->bus, info->domain, info->dev, info->func, 160 info->vendor_id, info->device_id, 161 info->subvendor_id, info->subdevice_id); 162 163 xf86ErrorF("rev %d", info->revision); 164 165 for (i = 0; i < 6; i++) { 166 struct pci_mem_region *r = &info->regions[i]; 167 168 if (r->size && !r->is_IO) { 169 if (!memdone) { 170 xf86ErrorF(", Mem @ "); 171 memdone = TRUE; 172 } 173 else 174 xf86ErrorF(", "); 175 xf86ErrorF("0x%08lx/%ld", (long) r->base_addr, (long) r->size); 176 } 177 } 178 179 for (i = 0; i < 6; i++) { 180 struct pci_mem_region *r = &info->regions[i]; 181 182 if (r->size && r->is_IO) { 183 if (!iodone) { 184 xf86ErrorF(", I/O @ "); 185 iodone = TRUE; 186 } 187 else 188 xf86ErrorF(", "); 189 xf86ErrorF("0x%08lx/%ld", (long) r->base_addr, (long) r->size); 190 } 191 } 192 193 if (info->rom_size) { 194 xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld", 195 (long) info->rom_size); 196 } 197 198 xf86ErrorF("\n"); 199 } 200 free(xf86PciVideoInfo); 201} 202 203/* 204 * If the slot requested is already in use, return -1. 205 * Otherwise, claim the slot for the screen requesting it. 206 */ 207 208int 209xf86ClaimPciSlot(struct pci_device *d, DriverPtr drvp, 210 int chipset, GDevPtr dev, Bool active) 211{ 212 EntityPtr p = NULL; 213 int num; 214 215 if (xf86CheckPciSlot(d)) { 216 num = xf86AllocateEntity(); 217 p = xf86Entities[num]; 218 p->driver = drvp; 219 p->chipset = chipset; 220 p->bus.type = BUS_PCI; 221 p->bus.id.pci = d; 222 p->active = active; 223 p->inUse = FALSE; 224 if (dev) 225 xf86AddDevToEntity(num, dev); 226 pciSlotClaimed++; 227 228 return num; 229 } 230 else 231 return -1; 232} 233 234/* 235 * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim. 236 */ 237void 238xf86UnclaimPciSlot(struct pci_device *d, GDevPtr dev) 239{ 240 int i; 241 242 for (i = 0; i < xf86NumEntities; i++) { 243 const EntityPtr p = xf86Entities[i]; 244 245 if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) { 246 /* Probably the slot should be deallocated? */ 247 xf86RemoveDevFromEntity(i, dev); 248 pciSlotClaimed--; 249 p->bus.type = BUS_NONE; 250 return; 251 } 252 } 253} 254 255/* 256 * Parse a BUS ID string, and return the PCI bus parameters if it was 257 * in the correct format for a PCI bus id. 258 */ 259 260Bool 261xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func) 262{ 263 /* 264 * The format is assumed to be "bus[@domain]:device[:func]", where domain, 265 * bus, device and func are decimal integers. domain and func may be 266 * omitted and assumed to be zero, although doing this isn't encouraged. 267 */ 268 269 char *p, *s, *d; 270 const char *id; 271 int i; 272 273 if (StringToBusType(busID, &id) != BUS_PCI) 274 return FALSE; 275 276 s = xstrdup(id); 277 p = strtok(s, ":"); 278 if (p == NULL || *p == 0) { 279 free(s); 280 return FALSE; 281 } 282 d = strpbrk(p, "@"); 283 if (d != NULL) { 284 *(d++) = 0; 285 for (i = 0; d[i] != 0; i++) { 286 if (!isdigit(d[i])) { 287 free(s); 288 return FALSE; 289 } 290 } 291 } 292 for (i = 0; p[i] != 0; i++) { 293 if (!isdigit(p[i])) { 294 free(s); 295 return FALSE; 296 } 297 } 298 *bus = atoi(p); 299 if (d != NULL && *d != 0) 300 *bus += atoi(d) << 8; 301 p = strtok(NULL, ":"); 302 if (p == NULL || *p == 0) { 303 free(s); 304 return FALSE; 305 } 306 for (i = 0; p[i] != 0; i++) { 307 if (!isdigit(p[i])) { 308 free(s); 309 return FALSE; 310 } 311 } 312 *device = atoi(p); 313 *func = 0; 314 p = strtok(NULL, ":"); 315 if (p == NULL || *p == 0) { 316 free(s); 317 return TRUE; 318 } 319 for (i = 0; p[i] != 0; i++) { 320 if (!isdigit(p[i])) { 321 free(s); 322 return FALSE; 323 } 324 } 325 *func = atoi(p); 326 free(s); 327 return TRUE; 328} 329 330/* 331 * Compare a BUS ID string with a PCI bus id. Return TRUE if they match. 332 */ 333 334Bool 335xf86ComparePciBusString(const char *busID, int bus, int device, int func) 336{ 337 int ibus, idevice, ifunc; 338 339 if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) { 340 return bus == ibus && device == idevice && func == ifunc; 341 } 342 else { 343 return FALSE; 344 } 345} 346 347/* 348 * xf86IsPrimaryPci() -- return TRUE if primary device 349 * is PCI and bus, dev and func numbers match. 350 */ 351 352Bool 353xf86IsPrimaryPci(struct pci_device *pPci) 354{ 355 /* Add max. 1 screen for the IgnorePrimary fallback path */ 356 if (xf86ProbeIgnorePrimary && xf86NumScreens == 0) 357 return TRUE; 358 359 if (primaryBus.type == BUS_PCI) 360 return pPci == primaryBus.id.pci; 361#ifdef XSERVER_PLATFORM_BUS 362 if (primaryBus.type == BUS_PLATFORM) 363 if (primaryBus.id.plat->pdev) 364 if (MATCH_PCI_DEVICES(primaryBus.id.plat->pdev, pPci)) 365 return TRUE; 366#endif 367 return FALSE; 368} 369 370/* 371 * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity. 372 */ 373struct pci_device * 374xf86GetPciInfoForEntity(int entityIndex) 375{ 376 EntityPtr p; 377 378 if (entityIndex >= xf86NumEntities) 379 return NULL; 380 381 p = xf86Entities[entityIndex]; 382 switch (p->bus.type) { 383 case BUS_PCI: 384 return p->bus.id.pci; 385 case BUS_PLATFORM: 386 return p->bus.id.plat->pdev; 387 default: 388 break; 389 } 390 return NULL; 391} 392 393/* 394 * xf86CheckPciMemBase() checks that the memory base value matches one of the 395 * PCI base address register values for the given PCI device. 396 */ 397Bool 398xf86CheckPciMemBase(struct pci_device *pPci, memType base) 399{ 400 int i; 401 402 for (i = 0; i < 6; i++) 403 if (base == pPci->regions[i].base_addr) 404 return TRUE; 405 return FALSE; 406} 407 408/* 409 * Check if the slot requested is free. If it is already in use, return FALSE. 410 */ 411 412Bool 413xf86CheckPciSlot(const struct pci_device *d) 414{ 415 int i; 416 417 for (i = 0; i < xf86NumEntities; i++) { 418 const EntityPtr p = xf86Entities[i]; 419 420 if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) { 421 return FALSE; 422 } 423#ifdef XSERVER_PLATFORM_BUS 424 if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat->pdev)) { 425 struct pci_device *ud = p->bus.id.plat->pdev; 426 if (MATCH_PCI_DEVICES(ud, d)) 427 return FALSE; 428 } 429#endif 430 } 431 return TRUE; 432} 433 434#define END_OF_MATCHES(m) \ 435 (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0)) 436 437Bool 438xf86PciAddMatchingDev(DriverPtr drvp) 439{ 440 const struct pci_id_match *const devices = drvp->supported_devices; 441 int j; 442 struct pci_device *pPci; 443 struct pci_device_iterator *iter; 444 int numFound = 0; 445 446 iter = pci_id_match_iterator_create(NULL); 447 while ((pPci = pci_device_next(iter)) != NULL) { 448 /* Determine if this device is supported by the driver. If it is, 449 * add it to the list of devices to configure. 450 */ 451 for (j = 0; !END_OF_MATCHES(devices[j]); j++) { 452 if (PCI_ID_COMPARE(devices[j].vendor_id, pPci->vendor_id) 453 && PCI_ID_COMPARE(devices[j].device_id, pPci->device_id) 454 && ((devices[j].device_class_mask & pPci->device_class) 455 == devices[j].device_class)) { 456 if (xf86CheckPciSlot(pPci)) { 457 GDevPtr pGDev = 458 xf86AddBusDeviceToConfigure(drvp->driverName, BUS_PCI, 459 pPci, -1); 460 if (pGDev != NULL) { 461 /* After configure pass 1, chipID and chipRev are 462 * treated as over-rides, so clobber them here. 463 */ 464 pGDev->chipID = -1; 465 pGDev->chipRev = -1; 466 } 467 468 numFound++; 469 } 470 471 break; 472 } 473 } 474 } 475 476 pci_iterator_destroy(iter); 477 478 return numFound != 0; 479} 480 481Bool 482xf86PciProbeDev(DriverPtr drvp) 483{ 484 int i, j; 485 struct pci_device *pPci; 486 Bool foundScreen = FALSE; 487 const struct pci_id_match *const devices = drvp->supported_devices; 488 GDevPtr *devList; 489 const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList); 490 491 for (i = 0; i < numDevs; i++) { 492 struct pci_device_iterator *iter; 493 unsigned device_id; 494 495 /* Find the pciVideoRec associated with this device section. 496 */ 497 iter = pci_id_match_iterator_create(NULL); 498 while ((pPci = pci_device_next(iter)) != NULL) { 499 if (devList[i]->busID && *devList[i]->busID) { 500 if (xf86ComparePciBusString(devList[i]->busID, 501 ((pPci->domain << 8) 502 | pPci->bus), 503 pPci->dev, pPci->func)) { 504 break; 505 } 506 } 507 else if (xf86IsPrimaryPci(pPci)) { 508 break; 509 } 510 } 511 512 pci_iterator_destroy(iter); 513 514 if (pPci == NULL) { 515 continue; 516 } 517 device_id = (devList[i]->chipID > 0) 518 ? devList[i]->chipID : pPci->device_id; 519 520 /* Once the pciVideoRec is found, determine if the device is supported 521 * by the driver. If it is, probe it! 522 */ 523 for (j = 0; !END_OF_MATCHES(devices[j]); j++) { 524 if (PCI_ID_COMPARE(devices[j].vendor_id, pPci->vendor_id) 525 && PCI_ID_COMPARE(devices[j].device_id, device_id) 526 && ((devices[j].device_class_mask & pPci->device_class) 527 == devices[j].device_class)) { 528 int entry; 529 530 /* Allow the same entity to be used more than once for 531 * devices with multiple screens per entity. This assumes 532 * implicitly that there will be a screen == 0 instance. 533 * 534 * FIXME Need to make sure that two different drivers don't 535 * FIXME claim the same screen > 0 instance. 536 */ 537 if ((devList[i]->screen == 0) && !xf86CheckPciSlot(pPci)) 538 continue; 539 540 DebugF("%s: card at %d:%d:%d is claimed by a Device section\n", 541 drvp->driverName, pPci->bus, pPci->dev, pPci->func); 542 543 /* Allocate an entry in the lists to be returned */ 544 entry = xf86ClaimPciSlot(pPci, drvp, device_id, 545 devList[i], devList[i]->active); 546 547 if ((entry == -1) && (devList[i]->screen > 0)) { 548 unsigned k; 549 550 for (k = 0; k < xf86NumEntities; k++) { 551 EntityPtr pEnt = xf86Entities[k]; 552 553 if (pEnt->bus.type != BUS_PCI) 554 continue; 555 if (pEnt->bus.id.pci == pPci) { 556 entry = k; 557 xf86AddDevToEntity(k, devList[i]); 558 break; 559 } 560 } 561 } 562 563 if (entry != -1) { 564 if ((*drvp->PciProbe) (drvp, entry, pPci, 565 devices[j].match_data)) { 566 foundScreen = TRUE; 567 } 568 else 569 xf86UnclaimPciSlot(pPci, devList[i]); 570 } 571 572 break; 573 } 574 } 575 } 576 free(devList); 577 578 return foundScreen; 579} 580 581void 582xf86PciIsolateDevice(const char *argument) 583{ 584 int bus, device, func; 585 586 if (sscanf(argument, "PCI:%d:%d:%d", &bus, &device, &func) == 3) { 587 xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus); 588 xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus); 589 xf86IsolateDevice.dev = device; 590 xf86IsolateDevice.func = func; 591 } 592 else 593 FatalError("Invalid isolated device specification\n"); 594} 595 596static Bool 597pciDeviceHasBars(struct pci_device *pci) 598{ 599 int i; 600 601 for (i = 0; i < 6; i++) 602 if (pci->regions[i].size) 603 return TRUE; 604 605 if (pci->rom_size) 606 return TRUE; 607 608 return FALSE; 609} 610 611struct Inst { 612 struct pci_device *pci; 613 GDevPtr dev; 614 Bool foundHW; /* PCIid in list of supported chipsets */ 615 Bool claimed; /* BusID matches with a device section */ 616 int chip; 617 int screen; 618}; 619 620/** 621 * Find set of unclaimed devices matching a given vendor ID. 622 * 623 * Used by drivers to find as yet unclaimed devices matching the specified 624 * vendor ID. 625 * 626 * \param driverName Name of the driver. This is used to find Device 627 * sections in the config file. 628 * \param vendorID PCI vendor ID of associated devices. If zero, then 629 * the true vendor ID must be encoded in the \c PCIid 630 * fields of the \c PCIchipsets entries. 631 * \param chipsets Symbol table used to associate chipset names with 632 * PCI IDs. 633 * \param devList List of Device sections parsed from the config file. 634 * \param numDevs Number of entries in \c devList. 635 * \param drvp Pointer the driver's control structure. 636 * \param foundEntities Returned list of entity indicies associated with the 637 * driver. 638 * 639 * \returns 640 * The number of elements in returned in \c foundEntities on success or zero 641 * on failure. 642 * 643 * \todo 644 * This function does a bit more than short description says. Fill in some 645 * more of the details of its operation. 646 * 647 * \todo 648 * The \c driverName parameter is redundant. It is the same as 649 * \c DriverRec::driverName. In a future version of this function, remove 650 * that parameter. 651 */ 652int 653xf86MatchPciInstances(const char *driverName, int vendorID, 654 SymTabPtr chipsets, PciChipsets * PCIchipsets, 655 GDevPtr * devList, int numDevs, DriverPtr drvp, 656 int **foundEntities) 657{ 658 int i, j; 659 struct pci_device *pPci; 660 struct pci_device_iterator *iter; 661 struct Inst *instances = NULL; 662 int numClaimedInstances = 0; 663 int allocatedInstances = 0; 664 int numFound = 0; 665 SymTabRec *c; 666 PciChipsets *id; 667 int *retEntities = NULL; 668 669 *foundEntities = NULL; 670 671 /* Each PCI device will contribute at least one entry. Each device 672 * section can contribute at most one entry. The sum of the two is 673 * guaranteed to be larger than the maximum possible number of entries. 674 * Do this calculation and memory allocation once now to eliminate the 675 * need for realloc calls inside the loop. 676 */ 677 if (!(xf86DoConfigure && xf86DoConfigurePass1)) { 678 unsigned max_entries = numDevs; 679 680 iter = pci_slot_match_iterator_create(NULL); 681 while ((pPci = pci_device_next(iter)) != NULL) { 682 max_entries++; 683 } 684 685 pci_iterator_destroy(iter); 686 instances = xnfallocarray(max_entries, sizeof(struct Inst)); 687 } 688 689 iter = pci_slot_match_iterator_create(NULL); 690 while ((pPci = pci_device_next(iter)) != NULL) { 691 unsigned device_class = pPci->device_class; 692 Bool foundVendor = FALSE; 693 694 /* Convert the pre-PCI 2.0 device class for a VGA adapter to the 695 * 2.0 version of the same class. 696 */ 697 if (device_class == 0x00000101) { 698 device_class = 0x00030000; 699 } 700 701 /* Find PCI devices that match the given vendor ID. The vendor ID is 702 * either specified explicitly as a parameter to the function or 703 * implicitly encoded in the high bits of id->PCIid. 704 * 705 * The first device with a matching vendor is recorded, even if the 706 * device ID doesn't match. This is done because the Device section 707 * in the xorg.conf file can over-ride the device ID. A matching PCI 708 * ID might not be found now, but after the device ID over-ride is 709 * applied there /might/ be a match. 710 */ 711 for (id = PCIchipsets; id->PCIid != -1; id++) { 712 const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16) 713 | vendorID; 714 const unsigned device_id = (id->PCIid & 0x0000FFFF); 715 const unsigned match_class = 0x00030000 | id->PCIid; 716 717 if ((vendor_id == pPci->vendor_id) 718 || ((vendorID == PCI_VENDOR_GENERIC) && 719 (match_class == device_class))) { 720 if (!foundVendor && (instances != NULL)) { 721 ++allocatedInstances; 722 instances[allocatedInstances - 1].pci = pPci; 723 instances[allocatedInstances - 1].dev = NULL; 724 instances[allocatedInstances - 1].claimed = FALSE; 725 instances[allocatedInstances - 1].foundHW = FALSE; 726 instances[allocatedInstances - 1].screen = 0; 727 } 728 729 foundVendor = TRUE; 730 731 if ((device_id == pPci->device_id) 732 || ((vendorID == PCI_VENDOR_GENERIC) 733 && (match_class == device_class))) { 734 if (instances != NULL) { 735 instances[allocatedInstances - 1].foundHW = TRUE; 736 instances[allocatedInstances - 1].chip = id->numChipset; 737 } 738 739 if (xf86DoConfigure && xf86DoConfigurePass1) { 740 if (xf86CheckPciSlot(pPci)) { 741 GDevPtr pGDev = 742 xf86AddBusDeviceToConfigure(drvp->driverName, 743 BUS_PCI, pPci, -1); 744 745 if (pGDev) { 746 /* After configure pass 1, chipID and chipRev 747 * are treated as over-rides, so clobber them 748 * here. 749 */ 750 pGDev->chipID = -1; 751 pGDev->chipRev = -1; 752 } 753 754 numFound++; 755 } 756 } 757 else { 758 numFound++; 759 } 760 761 break; 762 } 763 } 764 } 765 } 766 767 pci_iterator_destroy(iter); 768 769 /* In "probe only" or "configure" mode (signaled by instances being NULL), 770 * our work is done. Return the number of detected devices. 771 */ 772 if (instances == NULL) { 773 return numFound; 774 } 775 776 /* 777 * This may be debatable, but if no PCI devices with a matching vendor 778 * type is found, return zero now. It is probably not desirable to 779 * allow the config file to override this. 780 */ 781 if (allocatedInstances <= 0) { 782 free(instances); 783 return 0; 784 } 785 786 DebugF("%s instances found: %d\n", driverName, allocatedInstances); 787 788 /* 789 * Check for devices that need duplicated instances. This is required 790 * when there is more than one screen per entity. 791 * 792 * XXX This currently doesn't work for cases where the BusID isn't 793 * specified explicitly in the config file. 794 */ 795 796 for (j = 0; j < numDevs; j++) { 797 if (devList[j]->screen > 0 && devList[j]->busID && *devList[j]->busID) { 798 for (i = 0; i < allocatedInstances; i++) { 799 pPci = instances[i].pci; 800 if (xf86ComparePciBusString(devList[j]->busID, 801 PCI_MAKE_BUS(pPci->domain, 802 pPci->bus), pPci->dev, 803 pPci->func)) { 804 allocatedInstances++; 805 instances[allocatedInstances - 1] = instances[i]; 806 instances[allocatedInstances - 1].screen = 807 devList[j]->screen; 808 numFound++; 809 break; 810 } 811 } 812 } 813 } 814 815 for (i = 0; i < allocatedInstances; i++) { 816 GDevPtr dev = NULL; 817 GDevPtr devBus = NULL; 818 819 pPci = instances[i].pci; 820 for (j = 0; j < numDevs; j++) { 821 if (devList[j]->busID && *devList[j]->busID) { 822 if (xf86ComparePciBusString(devList[j]->busID, 823 PCI_MAKE_BUS(pPci->domain, 824 pPci->bus), pPci->dev, 825 pPci->func) && 826 devList[j]->screen == instances[i].screen) { 827 828 if (devBus) 829 xf86MsgVerb(X_WARNING, 0, 830 "%s: More than one matching Device section for " 831 "instances\n\t(BusID: %s) found: %s\n", 832 driverName, devList[j]->busID, 833 devList[j]->identifier); 834 else 835 devBus = devList[j]; 836 } 837 } 838 else { 839 /* 840 * if device section without BusID is found 841 * only assign to it to the primary device. 842 */ 843 if (xf86IsPrimaryPci(pPci)) { 844 xf86Msg(X_PROBED, "Assigning device section with no busID" 845 " to primary device\n"); 846 if (dev || devBus) 847 xf86MsgVerb(X_WARNING, 0, 848 "%s: More than one matching Device section " 849 "found: %s\n", driverName, 850 devList[j]->identifier); 851 else 852 dev = devList[j]; 853 } 854 } 855 } 856 if (devBus) 857 dev = devBus; /* busID preferred */ 858 if (!dev) { 859 if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) { 860 xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section " 861 "for instance (BusID PCI:%u@%u:%u:%u) found\n", 862 driverName, pPci->bus, pPci->domain, pPci->dev, 863 pPci->func); 864 } 865 } 866 else { 867 numClaimedInstances++; 868 instances[i].claimed = TRUE; 869 instances[i].dev = dev; 870 } 871 } 872 DebugF("%s instances found: %d\n", driverName, numClaimedInstances); 873 /* 874 * Now check that a chipset or chipID override in the device section 875 * is valid. Chipset has precedence over chipID. 876 * If chipset is not valid ignore BusSlot completely. 877 */ 878 for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { 879 MessageType from = X_PROBED; 880 881 if (!instances[i].claimed) { 882 continue; 883 } 884 if (instances[i].dev->chipset) { 885 for (c = chipsets; c->token >= 0; c++) { 886 if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0) 887 break; 888 } 889 if (c->token == -1) { 890 instances[i].claimed = FALSE; 891 numClaimedInstances--; 892 xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device " 893 "section \"%s\" isn't valid for this driver\n", 894 driverName, instances[i].dev->chipset, 895 instances[i].dev->identifier); 896 } 897 else { 898 instances[i].chip = c->token; 899 900 for (id = PCIchipsets; id->numChipset >= 0; id++) { 901 if (id->numChipset == instances[i].chip) 902 break; 903 } 904 if (id->numChipset >= 0) { 905 xf86Msg(X_CONFIG, "Chipset override: %s\n", 906 instances[i].dev->chipset); 907 from = X_CONFIG; 908 } 909 else { 910 instances[i].claimed = FALSE; 911 numClaimedInstances--; 912 xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device " 913 "section \"%s\" isn't a valid PCI chipset\n", 914 driverName, instances[i].dev->chipset, 915 instances[i].dev->identifier); 916 } 917 } 918 } 919 else if (instances[i].dev->chipID > 0) { 920 for (id = PCIchipsets; id->numChipset >= 0; id++) { 921 if (id->PCIid == instances[i].dev->chipID) 922 break; 923 } 924 if (id->numChipset == -1) { 925 instances[i].claimed = FALSE; 926 numClaimedInstances--; 927 xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device " 928 "section \"%s\" isn't valid for this driver\n", 929 driverName, instances[i].dev->chipID, 930 instances[i].dev->identifier); 931 } 932 else { 933 instances[i].chip = id->numChipset; 934 935 xf86Msg(X_CONFIG, "ChipID override: 0x%04X\n", 936 instances[i].dev->chipID); 937 from = X_CONFIG; 938 } 939 } 940 else if (!instances[i].foundHW) { 941 /* 942 * This means that there was no override and the PCI chipType 943 * doesn't match one that is supported 944 */ 945 instances[i].claimed = FALSE; 946 numClaimedInstances--; 947 } 948 if (instances[i].claimed == TRUE) { 949 for (c = chipsets; c->token >= 0; c++) { 950 if (c->token == instances[i].chip) 951 break; 952 } 953 xf86Msg(from, "Chipset %s found\n", c->name); 954 } 955 } 956 957 /* 958 * Of the claimed instances, check that another driver hasn't already 959 * claimed its slot. 960 */ 961 numFound = 0; 962 for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) { 963 if (!instances[i].claimed) 964 continue; 965 pPci = instances[i].pci; 966 967 /* 968 * Allow the same entity to be used more than once for devices with 969 * multiple screens per entity. This assumes implicitly that there 970 * will be a screen == 0 instance. 971 * 972 * XXX Need to make sure that two different drivers don't claim 973 * the same screen > 0 instance. 974 */ 975 if (instances[i].screen == 0 && !xf86CheckPciSlot(pPci)) 976 continue; 977 978 DebugF("%s: card at %d:%d:%d is claimed by a Device section\n", 979 driverName, pPci->bus, pPci->dev, pPci->func); 980 981 /* Allocate an entry in the lists to be returned */ 982 numFound++; 983 retEntities = xnfreallocarray(retEntities, numFound, sizeof(int)); 984 retEntities[numFound - 1] = xf86ClaimPciSlot(pPci, drvp, 985 instances[i].chip, 986 instances[i].dev, 987 instances[i].dev->active); 988 if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) { 989 for (j = 0; j < xf86NumEntities; j++) { 990 EntityPtr pEnt = xf86Entities[j]; 991 992 if (pEnt->bus.type != BUS_PCI) 993 continue; 994 if (pEnt->bus.id.pci == pPci) { 995 retEntities[numFound - 1] = j; 996 xf86AddDevToEntity(j, instances[i].dev); 997 break; 998 } 999 } 1000 } 1001 } 1002 free(instances); 1003 if (numFound > 0) { 1004 *foundEntities = retEntities; 1005 } 1006 1007 return numFound; 1008} 1009 1010/* 1011 * xf86ConfigPciEntityInactive() -- This function can be used 1012 * to configure an inactive entity as well as to reconfigure an 1013 * previously active entity inactive. If the entity has been 1014 * assigned to a screen before it will be removed. If p_chip is 1015 * non-NULL all static resources listed there will be registered. 1016 */ 1017static void 1018xf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets * p_chip, 1019 EntityProc init, EntityProc enter, 1020 EntityProc leave, void *private) 1021{ 1022 ScrnInfoPtr pScrn; 1023 1024 if ((pScrn = xf86FindScreenForEntity(pEnt->index))) 1025 xf86RemoveEntityFromScreen(pScrn, pEnt->index); 1026} 1027 1028ScrnInfoPtr 1029xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex, 1030 PciChipsets * p_chip, void *dummy, EntityProc init, 1031 EntityProc enter, EntityProc leave, void *private) 1032{ 1033 EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); 1034 1035 if (dummy || init || enter || leave) 1036 FatalError("Legacy entity access functions are unsupported\n"); 1037 1038 if (!pEnt) 1039 return pScrn; 1040 1041 if (!(pEnt->location.type == BUS_PCI) 1042 || !xf86GetPciInfoForEntity(entityIndex)) { 1043 free(pEnt); 1044 return pScrn; 1045 } 1046 if (!pEnt->active) { 1047 xf86ConfigPciEntityInactive(pEnt, p_chip, init, enter, leave, private); 1048 free(pEnt); 1049 return pScrn; 1050 } 1051 1052 if (!pScrn) 1053 pScrn = xf86AllocateScreen(pEnt->driver, scrnFlag); 1054 if (xf86IsEntitySharable(entityIndex)) { 1055 xf86SetEntityShared(entityIndex); 1056 } 1057 xf86AddEntityToScreen(pScrn, entityIndex); 1058 if (xf86IsEntityShared(entityIndex)) { 1059 return pScrn; 1060 } 1061 free(pEnt); 1062 1063 return pScrn; 1064} 1065 1066void 1067xf86VideoPtrToDriverList(struct pci_device *dev, XF86MatchedDrivers *md) 1068{ 1069 int i; 1070 1071 /* Add more entries here if we ever return more than 4 drivers for 1072 any device */ 1073 const char *driverList[5] = { NULL, NULL, NULL, NULL, NULL }; 1074 1075 switch (dev->vendor_id) { 1076 /* AMD Geode LX */ 1077 case 0x1022: 1078 if (dev->device_id == 0x2081) 1079 driverList[0] = "geode"; 1080 break; 1081 /* older Geode products acquired by AMD still carry an NSC vendor_id */ 1082 case 0x100b: 1083 if (dev->device_id == 0x0030) { 1084 /* NSC Geode GX2 specifically */ 1085 driverList[0] = "geode"; 1086 /* GX2 support started its life in the NSC tree and was later 1087 forked by AMD for GEODE so we keep it as a backup */ 1088 driverList[1] = "nsc"; 1089 } 1090 else 1091 /* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */ 1092 driverList[0] = "nsc"; 1093 break; 1094 /* Cyrix Geode GX1 */ 1095 case 0x1078: 1096 if (dev->device_id == 0x0104) 1097 driverList[0] = "cyrix"; 1098 break; 1099 case 0x1142: 1100 driverList[0] = "apm"; 1101 break; 1102 case 0xedd8: 1103 driverList[0] = "ark"; 1104 break; 1105 case 0x1a03: 1106 driverList[0] = "ast"; 1107 break; 1108 case 0x1002: 1109 driverList[0] = "ati"; 1110 break; 1111 case 0x102c: 1112 driverList[0] = "chips"; 1113 break; 1114 case 0x1013: 1115 driverList[0] = "cirrus"; 1116 break; 1117 case 0x3d3d: 1118 driverList[0] = "glint"; 1119 break; 1120 case 0x105d: 1121 driverList[0] = "i128"; 1122 break; 1123 case 0x8086: 1124 switch (dev->device_id) 1125 { 1126 /* Intel i740 */ 1127 case 0x00d1: 1128 case 0x7800: 1129 driverList[0] = "i740"; 1130 break; 1131 /* GMA500/Poulsbo */ 1132 case 0x8108: 1133 case 0x8109: 1134 /* Try psb driver on Poulsbo - if available */ 1135 driverList[0] = "psb"; 1136 driverList[1] = "psb_drv"; 1137 break; 1138 /* GMA600/Oaktrail */ 1139 case 0x4100: 1140 case 0x4101: 1141 case 0x4102: 1142 case 0x4103: 1143 case 0x4104: 1144 case 0x4105: 1145 case 0x4106: 1146 case 0x4107: 1147 /* Atom E620/Oaktrail */ 1148 case 0x4108: 1149 /* Medfield */ 1150 case 0x0130: 1151 case 0x0131: 1152 case 0x0132: 1153 case 0x0133: 1154 case 0x0134: 1155 case 0x0135: 1156 case 0x0136: 1157 case 0x0137: 1158 /* GMA 3600/CDV */ 1159 case 0x0be0: 1160 case 0x0be1: 1161 case 0x0be2: 1162 case 0x0be3: 1163 case 0x0be4: 1164 case 0x0be5: 1165 case 0x0be6: 1166 case 0x0be7: 1167 case 0x0be8: 1168 case 0x0be9: 1169 case 0x0bea: 1170 case 0x0beb: 1171 case 0x0bec: 1172 case 0x0bed: 1173 case 0x0bee: 1174 case 0x0bef: 1175 /* Use fbdev/vesa driver on Oaktrail, Medfield, CDV */ 1176 break; 1177 default: 1178 driverList[0] = "intel"; 1179 break; 1180 } 1181 break; 1182 case 0x102b: 1183 driverList[0] = "mga"; 1184 break; 1185 case 0x10c8: 1186 driverList[0] = "neomagic"; 1187 break; 1188 case 0x10de: 1189 case 0x12d2: 1190 { 1191 int idx = 0; 1192 1193#if defined(__linux__) || defined(__NetBSD__) 1194 driverList[idx++] = "nouveau"; 1195#endif 1196 driverList[idx++] = "nv"; 1197 break; 1198 } 1199 case 0x1106: 1200 driverList[0] = "openchrome"; 1201 break; 1202 case 0x1b36: 1203 driverList[0] = "qxl"; 1204 break; 1205 case 0x1163: 1206 driverList[0] = "rendition"; 1207 break; 1208 case 0x5333: 1209 switch (dev->device_id) { 1210 case 0x88d0: 1211 case 0x88d1: 1212 case 0x88f0: 1213 case 0x8811: 1214 case 0x8812: 1215 case 0x8814: 1216 case 0x8901: 1217 driverList[0] = "s3"; 1218 break; 1219 case 0x5631: 1220 case 0x883d: 1221 case 0x8a01: 1222 case 0x8a10: 1223 case 0x8c01: 1224 case 0x8c03: 1225 case 0x8904: 1226 case 0x8a13: 1227 driverList[0] = "s3virge"; 1228 break; 1229 default: 1230 driverList[0] = "savage"; 1231 break; 1232 } 1233 break; 1234 case 0x1039: 1235 driverList[0] = "sis"; 1236 break; 1237 case 0x126f: 1238 driverList[0] = "siliconmotion"; 1239 break; 1240 case 0x121a: 1241 if (dev->device_id < 0x0003) 1242 driverList[0] = "voodoo"; 1243 else 1244 driverList[0] = "tdfx"; 1245 break; 1246 case 0x1011: 1247 driverList[0] = "tga"; 1248 break; 1249 case 0x1023: 1250 driverList[0] = "trident"; 1251 break; 1252 case 0x100c: 1253 driverList[0] = "tseng"; 1254 break; 1255 case 0x80ee: 1256 driverList[0] = "vboxvideo"; 1257 break; 1258 case 0x15ad: 1259 driverList[0] = "vmware"; 1260 break; 1261 case 0x18ca: 1262 if (dev->device_id == 0x47) 1263 driverList[0] = "xgixp"; 1264 else 1265 driverList[0] = "xgi"; 1266 break; 1267 default: 1268 break; 1269 } 1270 for (i = 0; driverList[i] != NULL; i++) { 1271 xf86AddMatchedDriver(md, driverList[i]); 1272 } 1273} 1274 1275#ifdef __linux__ 1276static int 1277xchomp(char *line) 1278{ 1279 size_t len = 0; 1280 1281 if (!line) { 1282 return 1; 1283 } 1284 1285 len = strlen(line); 1286 if (line[len - 1] == '\n' && len > 0) { 1287 line[len - 1] = '\0'; 1288 } 1289 return 0; 1290} 1291 1292/* This function is used to provide a workaround for binary drivers that 1293 * don't export their PCI ID's properly. If distros don't end up using this 1294 * feature it can and should be removed because the symbol-based resolution 1295 * scheme should be the primary one */ 1296void 1297xf86MatchDriverFromFiles(uint16_t match_vendor, uint16_t match_chip, 1298 XF86MatchedDrivers *md) 1299{ 1300 DIR *idsdir; 1301 FILE *fp; 1302 struct dirent *direntry; 1303 char *line = NULL, *tmpMatch; 1304 size_t len; 1305 ssize_t read; 1306 char path_name[512], vendor_str[5], chip_str[5]; 1307 uint16_t vendor, chip; 1308 int j; 1309 1310 idsdir = opendir(PCI_TXT_IDS_PATH); 1311 if (!idsdir) 1312 return; 1313 1314 xf86Msg(X_INFO, 1315 "Scanning %s directory for additional PCI ID's supported by the drivers\n", 1316 PCI_TXT_IDS_PATH); 1317 direntry = readdir(idsdir); 1318 /* Read the directory */ 1319 while (direntry) { 1320 if (direntry->d_name[0] == '.') { 1321 direntry = readdir(idsdir); 1322 continue; 1323 } 1324 len = strlen(direntry->d_name); 1325 /* A tiny bit of sanity checking. We should probably do better */ 1326 if (strncmp(&(direntry->d_name[len - 4]), ".ids", 4) == 0) { 1327 /* We need the full path name to open the file */ 1328 snprintf(path_name, sizeof(path_name), "%s/%s", 1329 PCI_TXT_IDS_PATH, direntry->d_name); 1330 fp = fopen(path_name, "r"); 1331 if (fp == NULL) { 1332 xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", 1333 path_name); 1334 goto end; 1335 } 1336 /* Read the file */ 1337#ifdef __GLIBC__ 1338 while ((read = getline(&line, &len, fp)) != -1) { 1339#else 1340 while ((line = fgetln(fp, &len)) != (char *) NULL) { 1341#endif /* __GLIBC __ */ 1342 xchomp(line); 1343 if (isdigit(line[0])) { 1344 strlcpy(vendor_str, line, sizeof(vendor_str)); 1345 vendor = (int) strtol(vendor_str, NULL, 16); 1346 if ((strlen(&line[4])) == 0) { 1347 chip_str[0] = '\0'; 1348 chip = -1; 1349 } 1350 else { 1351 /* Handle trailing whitespace */ 1352 if (isspace(line[4])) { 1353 chip_str[0] = '\0'; 1354 chip = -1; 1355 } 1356 else { 1357 /* Ok, it's a real ID */ 1358 strlcpy(chip_str, &line[4], sizeof(chip_str)); 1359 chip = (int) strtol(chip_str, NULL, 16); 1360 } 1361 } 1362 if (vendor == match_vendor && chip == match_chip) { 1363 tmpMatch = 1364 (char *) malloc(sizeof(char) * 1365 strlen(direntry->d_name) - 3); 1366 if (!tmpMatch) { 1367 xf86Msg(X_ERROR, 1368 "Could not allocate space for the module name. Exiting.\n"); 1369 goto end; 1370 } 1371 /* hack off the .ids suffix. This should guard 1372 * against other problems, but it will end up 1373 * taking off anything after the first '.' */ 1374 for (j = 0; j < (strlen(direntry->d_name) - 3); j++) { 1375 if (direntry->d_name[j] == '.') { 1376 tmpMatch[j] = '\0'; 1377 break; 1378 } 1379 else { 1380 tmpMatch[j] = direntry->d_name[j]; 1381 } 1382 } 1383 xf86AddMatchedDriver(md, tmpMatch); 1384 xf86Msg(X_INFO, "Matched %s from file name %s\n", 1385 tmpMatch, direntry->d_name); 1386 free(tmpMatch); 1387 } 1388 } 1389 else { 1390 /* TODO Handle driver overrides here */ 1391 } 1392 } 1393 fclose(fp); 1394 } 1395 direntry = readdir(idsdir); 1396 } 1397 end: 1398 free(line); 1399 closedir(idsdir); 1400} 1401#endif /* __linux__ */ 1402 1403void 1404xf86PciMatchDriver(XF86MatchedDrivers *md) 1405{ 1406 struct pci_device *info = NULL; 1407 struct pci_device_iterator *iter; 1408 1409 /* Find the primary device, and get some information about it. */ 1410 iter = pci_slot_match_iterator_create(NULL); 1411 while ((info = pci_device_next(iter)) != NULL) { 1412 if (xf86IsPrimaryPci(info)) { 1413 break; 1414 } 1415 } 1416 1417 pci_iterator_destroy(iter); 1418#ifdef __linux__ 1419 if (info) 1420 xf86MatchDriverFromFiles(info->vendor_id, info->device_id, md); 1421#endif 1422 1423 if (info != NULL) { 1424 xf86VideoPtrToDriverList(info, md); 1425 } 1426} 1427 1428Bool 1429xf86PciConfigure(void *busData, struct pci_device *pDev) 1430{ 1431 struct pci_device *pVideo = NULL; 1432 1433 pVideo = (struct pci_device *) busData; 1434 if (pDev && 1435 (pDev->domain == pVideo->domain) && 1436 (pDev->bus == pVideo->bus) && 1437 (pDev->dev == pVideo->dev) && (pDev->func == pVideo->func)) 1438 return 0; 1439 1440 return 1; 1441} 1442 1443void 1444xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo, 1445 GDevRec * GDev, int *chipset) 1446{ 1447 char busnum[8]; 1448 char *tmp; 1449 1450 pVideo = (struct pci_device *) busData; 1451 1452 snprintf(busnum, sizeof(busnum), "%d", pVideo->bus); 1453 1454 XNFasprintf(&tmp, "PCI:%s:%d:%d", 1455 busnum, pVideo->dev, pVideo->func); 1456 GDev->busID = tmp; 1457 1458 GDev->chipID = pVideo->device_id; 1459 GDev->chipRev = pVideo->revision; 1460 1461 if (*chipset < 0) 1462 *chipset = (pVideo->vendor_id << 16) | pVideo->device_id; 1463} 1464 1465char * 1466DRICreatePCIBusID(const struct pci_device *dev) 1467{ 1468 char *busID; 1469 1470 if (asprintf(&busID, "pci:%04x:%02x:%02x.%d", 1471 dev->domain, dev->bus, dev->dev, dev->func) == -1) 1472 return NULL; 1473 1474 return busID; 1475} 1476