1 /* 2 Copyright 1999, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4 5 Other 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 16 #include "DriverInterface.h" 17 18 19 #undef TRACE 20 21 #ifdef ENABLE_DEBUG_TRACE 22 # define TRACE(x...) dprintf("S3: " x) 23 #else 24 # define TRACE(x...) ; 25 #endif 26 27 28 #define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s)) 29 #define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v)) 30 31 #define SKD_HANDLER_INSTALLED 0x80000000 32 #define MAX_DEVICES 8 33 #define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" 34 35 int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support 36 37 38 struct ChipInfo { 39 uint16 chipID; // PCI device id of the chip 40 uint16 chipType; // assigned chip type identifier 41 char* chipName; // user recognizable name for chip (must be < 32 chars) 42 }; 43 44 // This table maps a PCI device ID to a chip type identifier and the chip name. 45 // Note that the Trio64 and Trio64V+ chips have the same ID, but have a different 46 // revision number. After the revision number is examined, the Trio64V+ will 47 // have a different chip type code and name assigned. 48 49 static const ChipInfo S3_ChipTable[] = { 50 { 0x8811, S3_TRIO64, "Trio64" }, // see comment above 51 { 0x8814, S3_TRIO64_UVP, "Trio64 UV+" }, 52 { 0x8901, S3_TRIO64_V2, "Trio64 V2/DX/GX" }, 53 54 { 0x5631, S3_VIRGE, "Virge" }, 55 { 0x883D, S3_VIRGE_VX, "Virge VX" }, 56 { 0x8A01, S3_VIRGE_DXGX, "Virge DX/GX" }, 57 { 0x8A10, S3_VIRGE_GX2, "Virge GX2" }, 58 { 0x8C01, S3_VIRGE_MX, "Virge MX" }, 59 { 0x8C03, S3_VIRGE_MXP, "Virge MX+" }, 60 { 0x8904, S3_TRIO_3D, "Trio 3D" }, 61 { 0x8A13, S3_TRIO_3D_2X, "Trio 3D/2X" }, 62 63 { 0x8a20, S3_SAVAGE_3D, "Savage3D" }, 64 { 0x8a21, S3_SAVAGE_3D, "Savage3D-MV" }, 65 { 0x8a22, S3_SAVAGE4, "Savage4" }, 66 { 0x8a25, S3_PROSAVAGE, "ProSavage PM133" }, 67 { 0x8a26, S3_PROSAVAGE, "ProSavage KM133" }, 68 { 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" }, 69 { 0x8c11, S3_SAVAGE_MX, "Savage/MX" }, 70 { 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" }, 71 { 0x8c13, S3_SAVAGE_MX, "Savage/IX" }, 72 { 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" }, 73 { 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" }, 74 { 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" }, 75 { 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" }, 76 { 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" }, 77 { 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" }, 78 { 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" }, 79 { 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" }, 80 { 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" }, 81 { 0x8d01, S3_TWISTER, "Twister PN133" }, 82 { 0x8d02, S3_TWISTER, "Twister KN133" }, 83 { 0x8d03, S3_PROSAVAGE_DDR, "ProSavage DDR" }, 84 { 0x8d04, S3_PROSAVAGE_DDR, "ProSavage DDR-K" }, 85 { 0x9102, S3_SAVAGE2000, "Savage2000" }, 86 { 0, 0, NULL } 87 }; 88 89 90 #define VENDOR_ID 0x5333 // S3 vendor ID 91 92 static struct { 93 uint16 vendorID; 94 const ChipInfo* devices; 95 } SupportedDevices[] = { 96 { VENDOR_ID, S3_ChipTable }, 97 { 0x0000, NULL } 98 }; 99 100 101 struct DeviceInfo { 102 uint32 openCount; // count of how many times device has been opened 103 int32 flags; 104 area_id sharedArea; // area shared between driver and all accelerants 105 SharedInfo* si; // pointer to the shared area 106 vuint8* regs; // kernel's pointer to memory mapped registers 107 const ChipInfo* pChipInfo; // info about the selected chip 108 pci_info pcii; // copy of pci info for this device 109 char name[B_OS_NAME_LENGTH]; // name of device 110 }; 111 112 113 struct DeviceData { 114 uint32 count; // number of devices actually found 115 benaphore kernel; // for serializing opens/closes 116 char* deviceNames[MAX_DEVICES + 1]; // device name pointer storage 117 DeviceInfo di[MAX_DEVICES]; // device specific stuff 118 }; 119 120 121 // Prototypes for our private functions. 122 123 static status_t open_hook (const char* name, uint32 flags, void** cookie); 124 static status_t close_hook (void* dev); 125 static status_t free_hook (void* dev); 126 static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len); 127 static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len); 128 static status_t control_hook (void* dev, uint32 msg, void* buf, size_t len); 129 static status_t map_device(DeviceInfo* di); 130 static void unmap_device(DeviceInfo* di); 131 static void probe_devices(void); 132 static int32 s3_interrupt(void* data); 133 134 static DeviceData* pd; 135 static pci_module_info* pci_bus; 136 static device_hooks graphics_device_hooks = 137 { 138 open_hook, 139 close_hook, 140 free_hook, 141 control_hook, 142 read_hook, 143 write_hook, 144 NULL, 145 NULL, 146 NULL, 147 NULL 148 }; 149 150 151 152 // Functions for dealing with Vertical Blanking Interrupts. Currently, I do 153 // not know the commands to handle these operations; thus, these functions 154 // currently do nothing. 155 156 static bool 157 InterruptIsVBI() 158 { 159 // return true only if a vertical blanking interrupt has occured 160 return false; 161 } 162 163 164 static void 165 ClearVBI() 166 { 167 } 168 169 static void 170 EnableVBI() 171 { 172 } 173 174 static void 175 DisableVBI() 176 { 177 } 178 179 180 181 static const ChipInfo* 182 FindDeviceMatch(uint16 vendorID, uint16 deviceID) 183 { 184 // Search the table of supported devices to find a chip/device that 185 // matches the vendor ID and device ID passed by the caller. 186 // Return pointer to the struct containing the chip info if match 187 // is found; else return NULL. 188 189 int vendor = 0; 190 191 while (SupportedDevices[vendor].vendorID != 0) { // end of table? 192 if (SupportedDevices[vendor].vendorID == vendorID) { 193 const ChipInfo* pDevice = SupportedDevices[vendor].devices; 194 195 while (pDevice->chipID != 0) { // end of table? 196 if (pDevice->chipID == deviceID) 197 return pDevice; // matching device/chip found 198 199 pDevice++; 200 } 201 } 202 vendor++; 203 } 204 205 return NULL; // no match found 206 } 207 208 209 status_t 210 init_hardware(void) 211 { 212 // Return B_OK if a device supported by this driver is found; otherwise, 213 // return B_ERROR so the driver will be unloaded. 214 215 long pci_index = 0; 216 pci_info pcii; 217 const ChipInfo* pDevice = NULL; 218 219 if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK) 220 return B_ERROR; // unable to access PCI bus 221 222 // Check all pci devices for a device supported by this driver. 223 224 while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) { 225 pDevice = FindDeviceMatch(pcii.vendor_id, pcii.device_id); 226 if (pDevice != NULL) 227 break; 228 229 pci_index++; 230 } 231 232 TRACE("init_hardware() - %s\n", pDevice == NULL ? "no supported devices" : "device supported"); 233 234 put_module(B_PCI_MODULE_NAME); // put away the module manager 235 return (pDevice == NULL ? B_ERROR : B_OK); 236 } 237 238 239 status_t init_driver(void) 240 { 241 // Get handle for the pci bus. 242 243 if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK) 244 return B_ERROR; 245 246 pd = (DeviceData*)calloc(1, sizeof(DeviceData)); 247 if (NULL == pd) { 248 put_module(B_PCI_MODULE_NAME); 249 return B_ERROR; 250 } 251 252 INIT_BEN(pd->kernel); // initialize the benaphore 253 probe_devices(); // find all devices supported by this driver 254 255 return B_OK; 256 } 257 258 259 const char** 260 publish_devices(void) 261 { 262 return (const char**)pd->deviceNames; // return list of supported devices 263 } 264 265 266 device_hooks* 267 find_device(const char* name) 268 { 269 int index = 0; 270 while (pd->deviceNames[index]) { 271 if (strcmp(name, pd->deviceNames[index]) == 0) 272 return &graphics_device_hooks; 273 index++; 274 } 275 return NULL; 276 } 277 278 279 void 280 uninit_driver(void) 281 { 282 // Free the driver data. 283 284 DELETE_BEN(pd->kernel); 285 free(pd); 286 pd = NULL; 287 288 put_module(B_PCI_MODULE_NAME); // put the pci module away 289 } 290 291 292 static status_t 293 map_device(DeviceInfo* di) 294 { 295 char areaName[B_OS_NAME_LENGTH]; 296 SharedInfo* si = di->si; 297 pci_info* pcii = &(di->pcii); 298 299 TRACE("enter map_device()\n"); 300 301 // enable memory mapped IO and VGA I/O 302 303 uint32 tmpUlong = get_pci(PCI_command, 2); 304 tmpUlong |= PCI_command_io | PCI_command_memory | PCI_command_master; 305 set_pci(PCI_command, 2, tmpUlong); 306 307 const uint32 SavageMmioRegBaseOld = 0x1000000; // 16 MB 308 const uint32 SavageMmioRegBaseNew = 0x0000000; 309 const uint32 SavageMmioRegSize = 0x0080000; // 512 KB reg area size 310 311 const uint32 VirgeMmioRegBase = 0x1000000; // 16 MB 312 const uint32 VirgeMmioRegSize = 0x10000; // 64 KB reg area size 313 314 uint32 videoRamAddr = 0; 315 uint32 videoRamSize = 0; 316 uint32 regsBase = 0; 317 uint32 regAreaSize = 0; 318 319 // Since we do not know at this point the actual size of the video 320 // memory, set it to the largest value that the respective chipset 321 // family can have. 322 323 if (S3_SAVAGE_FAMILY(di->pChipInfo->chipType)) { 324 if (S3_SAVAGE_3D_SERIES(di->pChipInfo->chipType)) { 325 // Savage 3D & Savage MX chips. 326 327 regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseOld; 328 regAreaSize = SavageMmioRegSize; 329 330 videoRamAddr = di->pcii.u.h0.base_registers[0]; 331 videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series 332 si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); 333 } else { 334 // All other Savage chips. 335 336 regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseNew; 337 regAreaSize = SavageMmioRegSize; 338 339 videoRamAddr = di->pcii.u.h0.base_registers[1]; 340 videoRamSize = di->pcii.u.h0.base_register_sizes[1]; 341 si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[1]); 342 } 343 } else { 344 // Trio/Virge chips. 345 346 regsBase = di->pcii.u.h0.base_registers[0] + VirgeMmioRegBase; 347 regAreaSize = VirgeMmioRegSize; 348 349 videoRamAddr = di->pcii.u.h0.base_registers[0]; 350 videoRamSize = 8 * 1024 * 1024; // 8 MB is max for Trio/Virge chips 351 si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); 352 } 353 354 // Map the MMIO register area. 355 356 sprintf(areaName, DEVICE_FORMAT " regs", 357 di->pcii.vendor_id, di->pcii.device_id, 358 di->pcii.bus, di->pcii.device, di->pcii.function); 359 360 si->regsArea = map_physical_memory(areaName, (void*)regsBase, regAreaSize, 361 B_ANY_KERNEL_ADDRESS, 362 0, // neither read nor write, to hide it from user space apps 363 (void**)(&(di->regs))); 364 365 if (si->regsArea < 0) 366 return si->regsArea; // return error code 367 368 // Map the video memory. 369 370 sprintf(areaName, DEVICE_FORMAT " framebuffer", 371 di->pcii.vendor_id, di->pcii.device_id, 372 di->pcii.bus, di->pcii.device, di->pcii.function); 373 374 si->videoMemArea = map_physical_memory( 375 areaName, 376 (void*)videoRamAddr, 377 videoRamSize, 378 B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, 379 B_READ_AREA + B_WRITE_AREA, 380 &(si->videoMemAddr)); 381 382 if (si->videoMemArea < 0) { 383 // Try to map this time without write combining. 384 si->videoMemArea = map_physical_memory( 385 areaName, 386 (void*)videoRamAddr, 387 videoRamSize, 388 B_ANY_KERNEL_BLOCK_ADDRESS, 389 B_READ_AREA + B_WRITE_AREA, 390 &(si->videoMemAddr)); 391 } 392 393 TRACE("Video memory, area: %ld, addr: 0x%lX, size: %ld\n", si->videoMemArea, 394 (uint32)(si->videoMemAddr), videoRamSize); 395 396 // If there was an error, delete other areas. 397 if (si->videoMemArea < 0) { 398 delete_area(si->regsArea); 399 si->regsArea = -1; 400 } 401 402 TRACE("leave map_device(); result: %ld\n", si->videoMemArea); 403 return si->videoMemArea; 404 } 405 406 407 static void 408 unmap_device(DeviceInfo* di) 409 { 410 SharedInfo* si = di->si; 411 pci_info* pcii = &(di->pcii); 412 413 TRACE("enter unmap_device()\n"); 414 415 // Disable memory mapped IO. 416 uint32 tmpUlong = get_pci(PCI_command, 2); 417 tmpUlong &= ~(PCI_command_io | PCI_command_memory); 418 set_pci(PCI_command, 2, tmpUlong); 419 420 if (si->regsArea >= 0) 421 delete_area(si->regsArea); 422 if (si->videoMemArea >= 0) 423 delete_area(si->videoMemArea); 424 425 si->regsArea = si->videoMemArea = -1; 426 si->videoMemAddr = NULL; 427 di->regs = NULL; 428 429 TRACE("exit unmap_device()\n"); 430 } 431 432 433 static void 434 probe_devices(void) 435 { 436 uint32 pci_index = 0; 437 uint32 count = 0; 438 DeviceInfo* di = pd->di; 439 const ChipInfo* pDevice; 440 441 while ((count < MAX_DEVICES) 442 && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) { 443 444 pDevice = FindDeviceMatch(di->pcii.vendor_id, di->pcii.device_id); 445 if (pDevice != NULL) { 446 // Compose device name. 447 sprintf(di->name, "graphics/" DEVICE_FORMAT, 448 di->pcii.vendor_id, di->pcii.device_id, 449 di->pcii.bus, di->pcii.device, di->pcii.function); 450 TRACE("probe_devices() match found; name: %s\n", di->name); 451 452 pd->deviceNames[count] = di->name; 453 di->openCount = 0; // mark driver as available for R/W open 454 di->sharedArea = -1; // indicate shared area not yet created 455 di->si = NULL; 456 di->pChipInfo = pDevice; 457 di++; 458 count++; 459 } 460 461 pci_index++; 462 } 463 464 pd->count = count; 465 pd->deviceNames[pd->count] = NULL; // terminate list with null pointer 466 467 TRACE("probe_devices() %ld supported devices\n", pd->count); 468 } 469 470 471 static uint32 472 thread_interrupt_work(DeviceInfo* di) 473 { 474 SharedInfo* si = di->si; 475 uint32 handled = B_HANDLED_INTERRUPT; 476 477 // Release vertical blanking semaphore. 478 if (si->vertBlankSem >= 0) { 479 int32 blocked; 480 if ((get_sem_count(si->vertBlankSem, &blocked) == B_OK) && (blocked < 0)) { 481 release_sem_etc(si->vertBlankSem, -blocked, B_DO_NOT_RESCHEDULE); 482 handled = B_INVOKE_SCHEDULER; 483 } 484 } 485 return handled; 486 } 487 488 489 static int32 490 s3_interrupt(void* data) 491 { 492 int32 handled = B_UNHANDLED_INTERRUPT; 493 DeviceInfo* di = (DeviceInfo*)data; 494 int32* flags = &(di->flags); 495 496 // Is someone already handling an interrupt for this device? 497 if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) 498 return B_UNHANDLED_INTERRUPT; 499 500 if (InterruptIsVBI()) { // was interrupt a VBI? 501 ClearVBI(); // clear interrupt 502 503 handled = thread_interrupt_work(di); // release semaphore 504 } 505 506 atomic_and(flags, ~SKD_HANDLER_INSTALLED); // note we're not in handler anymore 507 508 return handled; 509 } 510 511 512 // #pragma mark - Device Hooks 513 514 515 static status_t 516 open_hook(const char* name, uint32 flags, void** cookie) 517 { 518 int32 index = 0; 519 SharedInfo* si; 520 thread_id thid; 521 thread_info thinfo; 522 status_t result = B_OK; 523 char sharedName[B_OS_NAME_LENGTH]; 524 525 (void)flags; // avoid compiler warning for unused arg 526 527 TRACE("open_hook() - name: %s, cookie: 0x%08lx)\n", name, (uint32)cookie); 528 529 // Find the device name in the list of devices. 530 while (pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0)) 531 index++; 532 533 DeviceInfo* di = &(pd->di[index]); 534 535 // Make sure no one else has write access to the common data. 536 AQUIRE_BEN(pd->kernel); 537 538 if (di->openCount > 0) 539 goto mark_as_open; 540 541 // Create the area for shared info with NO user-space read or write permissions, 542 // to prevent accidental damage. 543 544 sprintf(sharedName, DEVICE_FORMAT " shared", 545 di->pcii.vendor_id, di->pcii.device_id, 546 di->pcii.bus, di->pcii.device, di->pcii.function); 547 548 di->sharedArea = create_area(sharedName, (void**) &(di->si), B_ANY_KERNEL_ADDRESS, 549 ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), 550 B_FULL_LOCK, 0); 551 if (di->sharedArea < 0) { 552 result = di->sharedArea; // return error 553 goto done; 554 } 555 556 si = di->si; 557 558 si->vendorID = di->pcii.vendor_id; 559 si->deviceID = di->pcii.device_id; 560 si->revision = di->pcii.revision; 561 si->chipType = di->pChipInfo->chipType; 562 strcpy(si->chipName, di->pChipInfo->chipName); 563 564 // Trio64 and Trio64V+ chips have the same ID but different revision numbers. 565 // Since the Trio64V+ supports MMIO, better performance can be obtained 566 // from it if it is distinguished from the Trio64. 567 568 if (si->chipType == S3_TRIO64 && si->revision & 0x40) { 569 si->chipType = S3_TRIO64_VP; 570 strcpy(si->chipName, "Trio64 V+"); 571 } 572 573 574 result = map_device(di); 575 if (result < 0) 576 goto free_shared; 577 578 result = B_OK; 579 580 DisableVBI(); // disable & clear any pending interrupts 581 si->bInterruptAssigned = false; // indicate interrupt not assigned yet 582 583 // Create a semaphore for vertical blank management. 584 si->vertBlankSem = create_sem(0, di->name); 585 if (si->vertBlankSem < 0) 586 goto mark_as_open; 587 588 // Change the owner of the semaphores to the opener's team. 589 // This is required because apps can't aquire kernel semaphores. 590 thid = find_thread(NULL); 591 get_thread_info(thid, &thinfo); 592 set_sem_owner(si->vertBlankSem, thinfo.team); 593 594 // If there is a valid interrupt assigned, set up interrupts. 595 596 if ((di->pcii.u.h0.interrupt_pin == 0x00) || 597 (di->pcii.u.h0.interrupt_line == 0xff) || // no IRQ assigned 598 (di->pcii.u.h0.interrupt_line <= 0x02)) { // system IRQ assigned 599 // Interrupt does not exist; thus delete semaphore as it won't be used. 600 delete_sem(si->vertBlankSem); 601 si->vertBlankSem = -1; 602 } else { 603 result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, (void*)di, 0); 604 if (result != B_OK) { 605 // Delete semaphore as it won't be used. 606 delete_sem(si->vertBlankSem); 607 si->vertBlankSem = -1; 608 } else { 609 // Inform accelerant(s) we can use interrupt related functions. 610 si->bInterruptAssigned = true; 611 } 612 } 613 614 mark_as_open: 615 di->openCount++; // mark device open 616 *cookie = di; // send cookie to opener 617 goto done; 618 619 free_shared: 620 delete_area(di->sharedArea); 621 di->sharedArea = -1; 622 di->si = NULL; 623 624 done: 625 // End of critical section. 626 RELEASE_BEN(pd->kernel); 627 628 TRACE("open_hook() returning 0x%08lx\n", result); 629 return result; 630 } 631 632 633 static status_t 634 read_hook(void* dev, off_t pos, void* buf, size_t* len) 635 { 636 // Following 3 lines of code are here to eliminate "unused parameter" warnings. 637 (void)dev; 638 (void)pos; 639 (void)buf; 640 641 *len = 0; 642 return B_NOT_ALLOWED; 643 } 644 645 646 static status_t 647 write_hook(void* dev, off_t pos, const void* buf, size_t* len) 648 { 649 // Following 3 lines of code are here to eliminate "unused parameter" warnings. 650 (void)dev; 651 (void)pos; 652 (void)buf; 653 654 *len = 0; 655 return B_NOT_ALLOWED; 656 } 657 658 659 static status_t 660 close_hook(void* dev) 661 { 662 (void)dev; // avoid compiler warning for unused arg 663 664 TRACE("close_hook()\n"); 665 return B_NO_ERROR; 666 } 667 668 669 static status_t 670 free_hook(void* dev) 671 { 672 DeviceInfo* di = (DeviceInfo*)dev; 673 SharedInfo* si = di->si; 674 675 TRACE("enter free_hook()\n"); 676 677 AQUIRE_BEN(pd->kernel); // lock driver 678 679 // If opened multiple times, decrement the open count and exit. 680 if (di->openCount > 1) 681 goto unlock_and_exit; 682 683 DisableVBI(); // disable & clear any pending interrupts 684 685 if (si->bInterruptAssigned) { 686 remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, di); 687 } 688 689 // Delete the semaphores, ignoring any errors because the owning team may have died. 690 if (si->vertBlankSem >= 0) 691 delete_sem(si->vertBlankSem); 692 si->vertBlankSem = -1; 693 694 unmap_device(di); // free regs and frame buffer areas 695 696 delete_area(di->sharedArea); 697 di->sharedArea = -1; 698 di->si = NULL; 699 700 unlock_and_exit: 701 if (di->openCount > 0) 702 di->openCount--; // mark device available 703 704 RELEASE_BEN(pd->kernel); // unlock driver 705 706 TRACE("exit free_hook()\n"); 707 return B_OK; 708 } 709 710 711 static status_t 712 control_hook(void* dev, uint32 msg, void* buf, size_t len) 713 { 714 DeviceInfo* di = (DeviceInfo*)dev; 715 716 (void)len; // avoid compiler warning for unused arg 717 718 switch (msg) { 719 case B_GET_ACCELERANT_SIGNATURE: 720 strcpy((char*)buf, "s3.accelerant"); 721 return B_OK; 722 723 case S3_DEVICE_NAME: 724 strncpy((char*)buf, di->name, B_OS_NAME_LENGTH); 725 ((char*)buf)[B_OS_NAME_LENGTH -1] = '\0'; 726 return B_OK; 727 728 case S3_GET_PRIVATE_DATA: 729 { 730 S3GetPrivateData* gpd = (S3GetPrivateData*)buf; 731 if (gpd->magic == S3_PRIVATE_DATA_MAGIC) { 732 gpd->sharedInfoArea = di->sharedArea; 733 return B_OK; 734 } 735 break; 736 } 737 738 case S3_RUN_INTERRUPTS: 739 { 740 S3SetBoolState* ri = (S3SetBoolState*)buf; 741 if (ri->magic == S3_PRIVATE_DATA_MAGIC) { 742 if (ri->bEnable) 743 EnableVBI(); 744 else 745 DisableVBI(); 746 } 747 return B_OK; 748 } 749 750 case S3_GET_PIO: 751 { 752 S3GetSetPIO* gsp = (S3GetSetPIO*)buf; 753 if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { 754 switch (gsp->size) { 755 case 1: 756 gsp->value = pci_bus->read_io_8(gsp->offset); 757 break; 758 case 2: 759 gsp->value = pci_bus->read_io_16(gsp->offset); 760 break; 761 case 4: 762 gsp->value = pci_bus->read_io_32(gsp->offset); 763 break; 764 default: 765 TRACE("control_hook() S3_GET_PIO invalid size: %ld\n", gsp->size); 766 return B_ERROR; 767 } 768 return B_OK; 769 } 770 break; 771 } 772 773 case S3_SET_PIO: 774 { 775 S3GetSetPIO* gsp = (S3GetSetPIO*)buf; 776 if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { 777 switch (gsp->size) { 778 case 1: 779 pci_bus->write_io_8(gsp->offset, gsp->value); 780 break; 781 case 2: 782 pci_bus->write_io_16(gsp->offset, gsp->value); 783 break; 784 case 4: 785 pci_bus->write_io_32(gsp->offset, gsp->value); 786 break; 787 default: 788 TRACE("control_hook() S3_SET_PIO invalid size: %ld\n", gsp->size); 789 return B_ERROR; 790 } 791 return B_OK; 792 } 793 break; 794 } 795 } 796 797 return B_DEV_INVALID_IOCTL; 798 } 799 800