1 /* 2 Copyright 2007-2008 Haiku, Inc. All rights reserved. 3 Distributed under the terms of the MIT license. 4 5 Authors: 6 Gerald Zajac 2007-2008 7 */ 8 9 #include <KernelExport.h> 10 #include <PCI.h> 11 #ifdef __HAIKU__ 12 #include <drivers/bios.h> 13 #endif // __HAIKU__ 14 #include <malloc.h> 15 #include <stdio.h> 16 #include <string.h> 17 #include <graphic_driver.h> 18 19 #include "DriverInterface.h" 20 21 22 #undef TRACE 23 24 #ifdef ENABLE_DEBUG_TRACE 25 # define TRACE(x...) dprintf("S3: " x) 26 #else 27 # define TRACE(x...) ; 28 #endif 29 30 31 32 #define SKD_HANDLER_INSTALLED 0x80000000 33 #define MAX_DEVICES 4 34 #define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" 35 36 int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support 37 38 #define VENDOR_ID 0x5333 // S3 vendor ID 39 40 41 struct ChipInfo { 42 uint16 chipID; // PCI device id of the chip 43 uint16 chipType; // assigned chip type identifier 44 const char* chipName; // user recognizable name for chip (must be < 32 45 // chars) 46 }; 47 48 // This table maps a PCI device ID to a chip type identifier and the chip name. 49 // Note that the Trio64 and Trio64V+ chips have the same ID, but have a different 50 // revision number. After the revision number is examined, the Trio64V+ will 51 // have a different chip type code and name assigned. 52 53 static const ChipInfo chipTable[] = { 54 { 0x8811, S3_TRIO64, "Trio64" }, // see comment above 55 { 0x8814, S3_TRIO64_UVP, "Trio64 UV+" }, 56 { 0x8901, S3_TRIO64_V2, "Trio64 V2/DX/GX" }, 57 58 { 0x5631, S3_VIRGE, "Virge" }, 59 { 0x883D, S3_VIRGE_VX, "Virge VX" }, 60 { 0x8A01, S3_VIRGE_DXGX, "Virge DX/GX" }, 61 { 0x8A10, S3_VIRGE_GX2, "Virge GX2" }, 62 { 0x8C01, S3_VIRGE_MX, "Virge MX" }, 63 { 0x8C03, S3_VIRGE_MXP, "Virge MX+" }, 64 { 0x8904, S3_TRIO_3D, "Trio 3D" }, 65 { 0x8A13, S3_TRIO_3D_2X, "Trio 3D/2X" }, 66 67 { 0x8a20, S3_SAVAGE_3D, "Savage3D" }, 68 { 0x8a21, S3_SAVAGE_3D, "Savage3D-MV" }, 69 { 0x8a22, S3_SAVAGE4, "Savage4" }, 70 { 0x8a25, S3_PROSAVAGE, "ProSavage PM133" }, 71 { 0x8a26, S3_PROSAVAGE, "ProSavage KM133" }, 72 { 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" }, 73 { 0x8c11, S3_SAVAGE_MX, "Savage/MX" }, 74 { 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" }, 75 { 0x8c13, S3_SAVAGE_MX, "Savage/IX" }, 76 { 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" }, 77 { 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" }, 78 { 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" }, 79 { 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" }, 80 { 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" }, 81 { 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" }, 82 { 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" }, 83 { 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" }, 84 { 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" }, 85 { 0x8d01, S3_TWISTER, "Twister PN133" }, 86 { 0x8d02, S3_TWISTER, "Twister KN133" }, 87 { 0x8d03, S3_PROSAVAGE_DDR, "ProSavage DDR" }, 88 { 0x8d04, S3_PROSAVAGE_DDR, "ProSavage DDR-K" }, 89 { 0x9102, S3_SAVAGE2000, "Savage2000" }, 90 { 0, 0, NULL } 91 }; 92 93 94 struct DeviceInfo { 95 uint32 openCount; // count of how many times device has been opened 96 int32 flags; 97 area_id sharedArea; // area shared between driver and all accelerants 98 SharedInfo* sharedInfo; // pointer to shared info area memory 99 vuint8* regs; // pointer to memory mapped registers 100 const ChipInfo* pChipInfo; // info about the selected chip 101 pci_info pciInfo; // copy of pci info for this device 102 char name[B_OS_NAME_LENGTH]; // name of device 103 }; 104 105 106 static Benaphore gLock; 107 static DeviceInfo gDeviceInfo[MAX_DEVICES]; 108 static char* gDeviceNames[MAX_DEVICES + 1]; 109 static pci_module_info* gPCI; 110 111 112 // Prototypes for device hook functions. 113 114 static status_t device_open(const char* name, uint32 flags, void** cookie); 115 static status_t device_close(void* dev); 116 static status_t device_free(void* dev); 117 static status_t device_read(void* dev, off_t pos, void* buf, size_t* len); 118 static status_t device_write(void* dev, off_t pos, const void* buf, size_t* len); 119 static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len); 120 121 static device_hooks gDeviceHooks = 122 { 123 device_open, 124 device_close, 125 device_free, 126 device_ioctl, 127 device_read, 128 device_write, 129 NULL, 130 NULL, 131 NULL, 132 NULL 133 }; 134 135 136 137 static inline uint32 138 GetPCI(pci_info& info, uint8 offset, uint8 size) 139 { 140 return gPCI->read_pci_config(info.bus, info.device, info.function, offset, size); 141 } 142 143 144 static inline void 145 SetPCI(pci_info& info, uint8 offset, uint8 size, uint32 value) 146 { 147 gPCI->write_pci_config(info.bus, info.device, info.function, offset, size, value); 148 } 149 150 151 // Functions for dealing with Vertical Blanking Interrupts. Currently, I do 152 // not know the commands to handle these operations; thus, these functions 153 // currently do nothing. 154 155 static bool 156 InterruptIsVBI() 157 { 158 // return true only if a vertical blanking interrupt has occured 159 return false; 160 } 161 162 163 static void 164 ClearVBI() 165 { 166 } 167 168 static void 169 EnableVBI() 170 { 171 } 172 173 static void 174 DisableVBI() 175 { 176 } 177 178 179 static status_t 180 MapDevice(DeviceInfo& di) 181 { 182 char areaName[B_OS_NAME_LENGTH]; 183 SharedInfo& si = *(di.sharedInfo); 184 pci_info& pciInfo = di.pciInfo; 185 186 TRACE("enter MapDevice()\n"); 187 188 // Enable memory mapped IO and bus master. 189 190 SetPCI(pciInfo, PCI_command, 2, GetPCI(pciInfo, PCI_command, 2) 191 | PCI_command_io | PCI_command_memory | PCI_command_master); 192 193 const uint32 SavageMmioRegBaseOld = 0x1000000; // 16 MB 194 const uint32 SavageMmioRegBaseNew = 0x0000000; 195 const uint32 SavageMmioRegSize = 0x0080000; // 512 KB reg area size 196 197 const uint32 VirgeMmioRegBase = 0x1000000; // 16 MB 198 const uint32 VirgeMmioRegSize = 0x10000; // 64 KB reg area size 199 200 uint32 videoRamAddr = 0; 201 uint32 videoRamSize = 0; 202 uint32 regsBase = 0; 203 uint32 regAreaSize = 0; 204 205 // Since we do not know at this point the actual size of the video 206 // memory, set it to the largest value that the respective chipset 207 // family can have. 208 209 if (S3_SAVAGE_FAMILY(di.pChipInfo->chipType)) { 210 if (S3_SAVAGE_3D_SERIES(di.pChipInfo->chipType)) { 211 // Savage 3D & Savage MX chips. 212 213 regsBase = pciInfo.u.h0.base_registers[0] + SavageMmioRegBaseOld; 214 regAreaSize = SavageMmioRegSize; 215 216 videoRamAddr = pciInfo.u.h0.base_registers[0]; 217 videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series 218 si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[0]); 219 } else { 220 // All other Savage chips. 221 222 regsBase = pciInfo.u.h0.base_registers[0] + SavageMmioRegBaseNew; 223 regAreaSize = SavageMmioRegSize; 224 225 videoRamAddr = pciInfo.u.h0.base_registers[1]; 226 videoRamSize = pciInfo.u.h0.base_register_sizes[1]; 227 si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[1]); 228 } 229 } else { 230 // Trio/Virge chips. 231 232 regsBase = pciInfo.u.h0.base_registers[0] + VirgeMmioRegBase; 233 regAreaSize = VirgeMmioRegSize; 234 235 videoRamAddr = pciInfo.u.h0.base_registers[0]; 236 videoRamSize = 8 * 1024 * 1024; // 8 MB is max for Trio/Virge chips 237 si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[0]); 238 } 239 240 // Map the MMIO register area. 241 242 sprintf(areaName, DEVICE_FORMAT " regs", 243 pciInfo.vendor_id, pciInfo.device_id, 244 pciInfo.bus, pciInfo.device, pciInfo.function); 245 246 si.regsArea = map_physical_memory(areaName, regsBase, regAreaSize, 247 B_ANY_KERNEL_ADDRESS, 248 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA, 249 (void**)(&(di.regs))); 250 251 if (si.regsArea < 0) 252 return si.regsArea; // return error code 253 254 // Map the video memory. 255 256 sprintf(areaName, DEVICE_FORMAT " framebuffer", 257 pciInfo.vendor_id, pciInfo.device_id, 258 pciInfo.bus, pciInfo.device, pciInfo.function); 259 260 si.videoMemArea = map_physical_memory( 261 areaName, 262 videoRamAddr, 263 videoRamSize, 264 B_ANY_KERNEL_BLOCK_ADDRESS | B_WRITE_COMBINING_MEMORY, 265 B_READ_AREA + B_WRITE_AREA, 266 &(si.videoMemAddr)); 267 268 if (si.videoMemArea < 0) { 269 // Try to map this time without write combining. 270 si.videoMemArea = map_physical_memory( 271 areaName, 272 videoRamAddr, 273 videoRamSize, 274 B_ANY_KERNEL_BLOCK_ADDRESS, 275 B_READ_AREA + B_WRITE_AREA, 276 &(si.videoMemAddr)); 277 } 278 279 TRACE("Video memory, area: %ld, addr: 0x%" B_PRIXADDR "\n", 280 si.videoMemArea, (addr_t)(si.videoMemAddr)); 281 282 // If there was an error, delete other areas. 283 if (si.videoMemArea < 0) { 284 delete_area(si.regsArea); 285 si.regsArea = -1; 286 } 287 288 TRACE("leave MapDevice(); result: %ld\n", si.videoMemArea); 289 return si.videoMemArea; 290 } 291 292 293 static void 294 UnmapDevice(DeviceInfo& di) 295 { 296 SharedInfo& si = *(di.sharedInfo); 297 298 TRACE("enter UnmapDevice()\n"); 299 300 if (si.regsArea >= 0) 301 delete_area(si.regsArea); 302 if (si.videoMemArea >= 0) 303 delete_area(si.videoMemArea); 304 305 si.regsArea = si.videoMemArea = -1; 306 si.videoMemAddr = NULL; 307 di.regs = NULL; 308 309 TRACE("exit UnmapDevice()\n"); 310 } 311 312 313 static int32 314 InterruptHandler(void* data) 315 { 316 int32 handled = B_UNHANDLED_INTERRUPT; 317 DeviceInfo& di = *((DeviceInfo*)data); 318 int32* flags = &(di.flags); 319 320 // Is someone already handling an interrupt for this device? 321 if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) 322 return B_UNHANDLED_INTERRUPT; 323 324 if (InterruptIsVBI()) { // was interrupt a VBI? 325 ClearVBI(); // clear interrupt 326 327 handled = B_HANDLED_INTERRUPT; 328 329 // Release vertical blanking semaphore. 330 sem_id& sem = di.sharedInfo->vertBlankSem; 331 332 if (sem >= 0) { 333 int32 blocked; 334 if ((get_sem_count(sem, &blocked) == B_OK) && (blocked < 0)) { 335 release_sem_etc(sem, -blocked, B_DO_NOT_RESCHEDULE); 336 handled = B_INVOKE_SCHEDULER; 337 } 338 } 339 } 340 341 atomic_and(flags, ~SKD_HANDLER_INSTALLED); // note we're not in handler anymore 342 343 return handled; 344 } 345 346 347 static void 348 InitInterruptHandler(DeviceInfo& di) 349 { 350 SharedInfo& si = *(di.sharedInfo); 351 352 TRACE("enter InitInterruptHandler()\n"); 353 354 DisableVBI(); // disable & clear any pending interrupts 355 si.bInterruptAssigned = false; // indicate interrupt not assigned yet 356 357 // Create a semaphore for vertical blank management. 358 si.vertBlankSem = create_sem(0, di.name); 359 if (si.vertBlankSem < 0) 360 return; 361 362 // Change the owner of the semaphores to the calling team (usually the 363 // app_server). This is required because apps can't aquire kernel 364 // semaphores. 365 366 thread_id threadID = find_thread(NULL); 367 thread_info threadInfo; 368 status_t status = get_thread_info(threadID, &threadInfo); 369 if (status == B_OK) 370 status = set_sem_owner(si.vertBlankSem, threadInfo.team); 371 372 // If there is a valid interrupt assigned, set up interrupts. 373 374 if (status == B_OK && di.pciInfo.u.h0.interrupt_pin != 0x00 375 && di.pciInfo.u.h0.interrupt_line != 0xff) { 376 // We have a interrupt line to use. 377 378 status = install_io_interrupt_handler(di.pciInfo.u.h0.interrupt_line, 379 InterruptHandler, (void*)(&di), 0); 380 381 if (status == B_OK) 382 si.bInterruptAssigned = true; // we can use interrupt related functions 383 } 384 385 if (status != B_OK) { 386 // Interrupt does not exist; thus delete semaphore as it won't be used. 387 delete_sem(si.vertBlankSem); 388 si.vertBlankSem = -1; 389 } 390 } 391 392 393 static status_t 394 InitDevice(DeviceInfo& di) 395 { 396 // Perform initialization and mapping of the device, and return B_OK if 397 // sucessful; else, return error code. 398 399 // Create the area for shared info with NO user-space read or write 400 // permissions, to prevent accidental damage. 401 402 TRACE("enter InitDevice()\n"); 403 404 pci_info& pciInfo = di.pciInfo; 405 char sharedName[B_OS_NAME_LENGTH]; 406 407 sprintf(sharedName, DEVICE_FORMAT " shared", 408 pciInfo.vendor_id, pciInfo.device_id, 409 pciInfo.bus, pciInfo.device, pciInfo.function); 410 411 di.sharedArea = create_area(sharedName, (void**) &(di.sharedInfo), 412 B_ANY_KERNEL_ADDRESS, 413 ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), 414 B_FULL_LOCK, 415 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 416 if (di.sharedArea < 0) 417 return di.sharedArea; // return error code 418 419 SharedInfo& si = *(di.sharedInfo); 420 421 si.vendorID = pciInfo.vendor_id; 422 si.deviceID = pciInfo.device_id; 423 si.revision = pciInfo.revision; 424 si.chipType = di.pChipInfo->chipType; 425 strcpy(si.chipName, di.pChipInfo->chipName); 426 427 // Trio64 and Trio64V+ chips have the same ID but different revision numbers. 428 // Since the Trio64V+ supports MMIO, better performance can be obtained 429 // from it if it is distinguished from the Trio64. 430 431 if (si.chipType == S3_TRIO64 && si.revision & 0x40) { 432 si.chipType = S3_TRIO64_VP; 433 strcpy(si.chipName, "Trio64 V+"); 434 } 435 436 status_t status = MapDevice(di); 437 if (status < 0) { 438 delete_area(di.sharedArea); 439 di.sharedArea = -1; 440 di.sharedInfo = NULL; 441 return status; // return error code 442 } 443 444 InitInterruptHandler(di); 445 446 TRACE("Interrupt assigned: %s\n", si.bInterruptAssigned ? "yes" : "no"); 447 return B_OK; 448 } 449 450 451 static const ChipInfo* 452 GetNextSupportedDevice(uint32& pciIndex, pci_info& pciInfo) 453 { 454 // Search the PCI devices for a device that is supported by this driver. 455 // The search starts at the device specified by argument pciIndex, and 456 // continues until a supported device is found or there are no more devices 457 // to examine. Argument pciIndex is incremented after each device is 458 // examined. 459 460 // If a supported device is found, return a pointer to the struct containing 461 // the chip info; else return NULL. 462 463 while (gPCI->get_nth_pci_info(pciIndex, &pciInfo) == B_OK) { 464 if (pciInfo.vendor_id == VENDOR_ID) { 465 // Search the table of supported devices to find a chip/device that 466 // matches device ID of the current PCI device. 467 468 const ChipInfo* pDevice = chipTable; 469 470 while (pDevice->chipID != 0) { // end of table? 471 if (pDevice->chipID == pciInfo.device_id) { 472 pciIndex++; 473 return pDevice; // matching device/chip found 474 } 475 476 pDevice++; 477 } 478 } 479 480 pciIndex++; 481 } 482 483 return NULL; // no supported device found found 484 } 485 486 487 488 #ifdef __HAIKU__ 489 490 static status_t 491 GetEdidFromBIOS(edid1_raw& edidRaw) 492 { 493 // Get the EDID info from the video BIOS, and return B_OK if successful. 494 495 #define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4) 496 #define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf) 497 498 bios_module_info* biosModule; 499 status_t status = get_module(B_BIOS_MODULE_NAME, (module_info**)&biosModule); 500 if (status != B_OK) { 501 TRACE("GetEdidFromBIOS(): failed to get BIOS module: 0x%" B_PRIx32 "\n", 502 status); 503 return status; 504 } 505 506 bios_state* state; 507 status = biosModule->prepare(&state); 508 if (status != B_OK) { 509 TRACE("GetEdidFromBIOS(): bios_prepare() failed: 0x%" B_PRIx32 "\n", 510 status); 511 put_module(B_BIOS_MODULE_NAME); 512 return status; 513 } 514 515 bios_regs regs = {}; 516 regs.eax = 0x4f15; 517 regs.ebx = 0; // 0 = report DDC service 518 regs.ecx = 0; 519 regs.es = 0; 520 regs.edi = 0; 521 522 status = biosModule->interrupt(state, 0x10, ®s); 523 if (status == B_OK) { 524 // AH contains the error code, and AL determines whether or not the 525 // function is supported. 526 if (regs.eax != 0x4f) 527 status = B_NOT_SUPPORTED; 528 529 // Test if DDC is supported by the monitor. 530 if ((regs.ebx & 3) == 0) 531 status = B_NOT_SUPPORTED; 532 } 533 534 if (status == B_OK) { 535 edid1_raw* edid = (edid1_raw*)biosModule->allocate_mem(state, 536 sizeof(edid1_raw)); 537 if (edid == NULL) { 538 status = B_NO_MEMORY; 539 goto out; 540 } 541 542 regs.eax = 0x4f15; 543 regs.ebx = 1; // 1 = read EDID 544 regs.ecx = 0; 545 regs.edx = 0; 546 regs.es = ADDRESS_SEGMENT(edid); 547 regs.edi = ADDRESS_OFFSET(edid); 548 549 status = biosModule->interrupt(state, 0x10, ®s); 550 if (status == B_OK) { 551 if (regs.eax != 0x4f) { 552 status = B_NOT_SUPPORTED; 553 } else { 554 // Copy the EDID info to the caller's location, and compute the 555 // checksum of the EDID info while copying. 556 557 uint8 sum = 0; 558 uint8 allOr = 0; 559 uint8* dest = (uint8*)&edidRaw; 560 uint8* src = (uint8*)edid; 561 562 for (uint32 j = 0; j < sizeof(edidRaw); j++) { 563 sum += *src; 564 allOr |= *src; 565 *dest++ = *src++; 566 } 567 568 if (allOr == 0) { 569 TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n"); 570 status = B_ERROR; 571 } else if (sum != 0) { 572 TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n"); 573 status = B_ERROR; 574 } 575 } 576 } 577 } 578 579 out: 580 biosModule->finish(state); 581 put_module(B_BIOS_MODULE_NAME); 582 583 TRACE("GetEdidFromBIOS() status: 0x%" B_PRIx32 "\n", status); 584 return status; 585 } 586 587 #endif // __HAIKU__ 588 589 590 591 // #pragma mark - Kernel Interface 592 593 594 status_t 595 init_hardware(void) 596 { 597 // Return B_OK if a device supported by this driver is found; otherwise, 598 // return B_ERROR so the driver will be unloaded. 599 600 if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK) 601 return B_ERROR; // unable to access PCI bus 602 603 // Check pci devices for a device supported by this driver. 604 605 uint32 pciIndex = 0; 606 pci_info pciInfo; 607 const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, pciInfo); 608 609 TRACE("init_hardware() - %s\n", pDevice == NULL ? "no supported devices" : "device supported"); 610 611 put_module(B_PCI_MODULE_NAME); // put away the module manager 612 613 return (pDevice == NULL ? B_ERROR : B_OK); 614 } 615 616 617 status_t init_driver(void) 618 { 619 // Get handle for the pci bus. 620 621 if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK) 622 return B_ERROR; 623 624 status_t status = gLock.Init("S3 driver lock"); 625 if (status < B_OK) 626 return status; 627 628 // Get info about all the devices supported by this driver. 629 630 uint32 pciIndex = 0; 631 uint32 count = 0; 632 633 while (count < MAX_DEVICES) { 634 DeviceInfo& di = gDeviceInfo[count]; 635 636 const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, di.pciInfo); 637 if (pDevice == NULL) 638 break; // all supported devices have been obtained 639 640 // Compose device name. 641 sprintf(di.name, "graphics/" DEVICE_FORMAT, 642 di.pciInfo.vendor_id, di.pciInfo.device_id, 643 di.pciInfo.bus, di.pciInfo.device, di.pciInfo.function); 644 TRACE("init_driver() match found; name: %s\n", di.name); 645 646 gDeviceNames[count] = di.name; 647 di.openCount = 0; // mark driver as available for R/W open 648 di.sharedArea = -1; // indicate shared area not yet created 649 di.sharedInfo = NULL; 650 di.pChipInfo = pDevice; 651 count++; 652 } 653 654 gDeviceNames[count] = NULL; // terminate list with null pointer 655 656 TRACE("init_driver() %ld supported devices\n", count); 657 658 return B_OK; 659 } 660 661 662 void 663 uninit_driver(void) 664 { 665 // Free the driver data. 666 667 gLock.Delete(); 668 put_module(B_PCI_MODULE_NAME); // put the pci module away 669 } 670 671 672 const char** 673 publish_devices(void) 674 { 675 return (const char**)gDeviceNames; // return list of supported devices 676 } 677 678 679 device_hooks* 680 find_device(const char* name) 681 { 682 int index = 0; 683 while (gDeviceNames[index] != NULL) { 684 if (strcmp(name, gDeviceNames[index]) == 0) 685 return &gDeviceHooks; 686 index++; 687 } 688 689 return NULL; 690 } 691 692 693 694 // #pragma mark - Device Hooks 695 696 697 static status_t 698 device_open(const char* name, uint32 /*flags*/, void** cookie) 699 { 700 status_t status = B_OK; 701 702 TRACE("device_open() - name: %s, cookie: 0x%" B_PRIXADDR "\n", name, 703 (addr_t)cookie); 704 705 // Find the device name in the list of devices. 706 707 int32 index = 0; 708 while (gDeviceNames[index] != NULL && (strcmp(name, gDeviceNames[index]) != 0)) 709 index++; 710 711 if (gDeviceNames[index] == NULL) 712 return B_BAD_VALUE; // device name not found in list of devices 713 714 DeviceInfo& di = gDeviceInfo[index]; 715 716 gLock.Acquire(); // make sure no one else has write access to common data 717 718 if (di.openCount == 0) 719 status = InitDevice(di); 720 721 gLock.Release(); 722 723 if (status == B_OK) { 724 di.openCount++; // mark device open 725 *cookie = &di; // send cookie to opener 726 } 727 728 TRACE("device_open() returning 0x%lx, open count: %ld\n", status, di.openCount); 729 return status; 730 } 731 732 733 static status_t 734 device_read(void* dev, off_t pos, void* buf, size_t* len) 735 { 736 // Following 3 lines of code are here to eliminate "unused parameter" warnings. 737 (void)dev; 738 (void)pos; 739 (void)buf; 740 741 *len = 0; 742 return B_NOT_ALLOWED; 743 } 744 745 746 static status_t 747 device_write(void* dev, off_t pos, const void* buf, size_t* len) 748 { 749 // Following 3 lines of code are here to eliminate "unused parameter" warnings. 750 (void)dev; 751 (void)pos; 752 (void)buf; 753 754 *len = 0; 755 return B_NOT_ALLOWED; 756 } 757 758 759 static status_t 760 device_close(void* dev) 761 { 762 (void)dev; // avoid compiler warning for unused arg 763 764 TRACE("device_close()\n"); 765 return B_NO_ERROR; 766 } 767 768 769 static status_t 770 device_free(void* dev) 771 { 772 DeviceInfo& di = *((DeviceInfo*)dev); 773 SharedInfo& si = *(di.sharedInfo); 774 pci_info& pciInfo = di.pciInfo; 775 776 TRACE("enter device_free()\n"); 777 778 gLock.Acquire(); // lock driver 779 780 // If opened multiple times, merely decrement the open count and exit. 781 782 if (di.openCount <= 1) { 783 DisableVBI(); // disable & clear any pending interrupts 784 785 if (si.bInterruptAssigned) { 786 remove_io_interrupt_handler(pciInfo.u.h0.interrupt_line, InterruptHandler, &di); 787 } 788 789 // Delete the semaphores, ignoring any errors because the owning team may have died. 790 if (si.vertBlankSem >= 0) 791 delete_sem(si.vertBlankSem); 792 si.vertBlankSem = -1; 793 794 UnmapDevice(di); // free regs and frame buffer areas 795 796 delete_area(di.sharedArea); 797 di.sharedArea = -1; 798 di.sharedInfo = NULL; 799 } 800 801 if (di.openCount > 0) 802 di.openCount--; // mark device available 803 804 gLock.Release(); // unlock driver 805 806 TRACE("exit device_free() openCount: %ld\n", di.openCount); 807 return B_OK; 808 } 809 810 811 static status_t 812 device_ioctl(void* dev, uint32 msg, void* buf, size_t len) 813 { 814 DeviceInfo& di = *((DeviceInfo*)dev); 815 816 (void)len; // avoid compiler warning for unused arg 817 818 // TRACE("device_ioctl(); ioctl: %lu, buf: 0x%08lx, len: %lu\n", msg, (uint32)buf, len); 819 820 switch (msg) { 821 case B_GET_ACCELERANT_SIGNATURE: 822 strcpy((char*)buf, "s3.accelerant"); 823 return B_OK; 824 825 case S3_DEVICE_NAME: 826 strncpy((char*)buf, di.name, B_OS_NAME_LENGTH); 827 ((char*)buf)[B_OS_NAME_LENGTH -1] = '\0'; 828 return B_OK; 829 830 case S3_GET_PRIVATE_DATA: 831 { 832 S3GetPrivateData* gpd = (S3GetPrivateData*)buf; 833 if (gpd->magic == S3_PRIVATE_DATA_MAGIC) { 834 gpd->sharedInfoArea = di.sharedArea; 835 return B_OK; 836 } 837 break; 838 } 839 840 case S3_GET_EDID: 841 { 842 #ifdef __HAIKU__ 843 S3GetEDID* ged = (S3GetEDID*)buf; 844 if (ged->magic == S3_PRIVATE_DATA_MAGIC) { 845 edid1_raw rawEdid; 846 status_t status = GetEdidFromBIOS(rawEdid); 847 if (status == B_OK) 848 user_memcpy(&ged->rawEdid, &rawEdid, sizeof(rawEdid)); 849 return status; 850 } 851 #else 852 return B_UNSUPPORTED; 853 #endif 854 break; 855 } 856 857 case S3_GET_PIO: 858 { 859 S3GetSetPIO* gsp = (S3GetSetPIO*)buf; 860 if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { 861 switch (gsp->size) { 862 case 1: 863 gsp->value = gPCI->read_io_8(gsp->offset); 864 break; 865 case 2: 866 gsp->value = gPCI->read_io_16(gsp->offset); 867 break; 868 case 4: 869 gsp->value = gPCI->read_io_32(gsp->offset); 870 break; 871 default: 872 TRACE("device_ioctl() S3_GET_PIO invalid size: %ld\n", gsp->size); 873 return B_ERROR; 874 } 875 return B_OK; 876 } 877 break; 878 } 879 880 case S3_SET_PIO: 881 { 882 S3GetSetPIO* gsp = (S3GetSetPIO*)buf; 883 if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { 884 switch (gsp->size) { 885 case 1: 886 gPCI->write_io_8(gsp->offset, gsp->value); 887 break; 888 case 2: 889 gPCI->write_io_16(gsp->offset, gsp->value); 890 break; 891 case 4: 892 gPCI->write_io_32(gsp->offset, gsp->value); 893 break; 894 default: 895 TRACE("device_ioctl() S3_SET_PIO invalid size: %ld\n", gsp->size); 896 return B_ERROR; 897 } 898 return B_OK; 899 } 900 break; 901 } 902 903 case S3_RUN_INTERRUPTS: 904 { 905 S3SetBoolState* ri = (S3SetBoolState*)buf; 906 if (ri->magic == S3_PRIVATE_DATA_MAGIC) { 907 if (ri->bEnable) 908 EnableVBI(); 909 else 910 DisableVBI(); 911 } 912 return B_OK; 913 } 914 } 915 916 return B_DEV_INVALID_IOCTL; 917 } 918