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