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 Mark Watson; 7 Rudolf Cornelissen 3/2002-11/2003. 8 */ 9 10 /* standard kernel driver stuff */ 11 #include <KernelExport.h> 12 #include <PCI.h> 13 #include <OS.h> 14 #include <driver_settings.h> 15 #include <malloc.h> 16 #include <stdlib.h> // for strtoXX 17 18 /* this is for the standardized portion of the driver API */ 19 /* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */ 20 #include <graphic_driver.h> 21 22 /* this is for sprintf() */ 23 #include <stdio.h> 24 25 /* this is for string compares */ 26 #include <string.h> 27 28 /* The private interface between the accelerant and the kernel driver. */ 29 #include "DriverInterface.h" 30 #include "mga_macros.h" 31 32 #define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s)) 33 #define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v)) 34 35 #define MAX_DEVICES 8 36 37 #ifndef __HAIKU__ 38 # undef B_USER_CLONEABLE_AREA 39 # define B_USER_CLONEABLE_AREA 0 40 #endif 41 42 #define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" // apsed 43 44 /* Tell the kernel what revision of the driver API we support */ 45 int32 api_version = B_CUR_DRIVER_API_VERSION; // apsed, was 2, is 2 in R5 46 47 /* these structures are private to the kernel driver */ 48 typedef struct device_info device_info; 49 50 typedef struct { 51 timer te; /* timer entry for add_timer() */ 52 device_info *di; /* pointer to the owning device */ 53 bigtime_t when_target; /* when we're supposed to wake up */ 54 } timer_info; 55 56 struct device_info { 57 uint32 is_open; /* a count of how many times the devices has been opened */ 58 area_id shared_area; /* the area shared between the driver and all of the accelerants */ 59 shared_info *si; /* a pointer to the shared area, for convenience */ 60 vuint32 *regs; /* kernel's pointer to memory mapped registers */ 61 pci_info pcii; /* a convenience copy of the pci info for this device */ 62 char name[B_OS_NAME_LENGTH]; /* where we keep the name of the device for publishing and comparing */ 63 }; 64 65 typedef struct { 66 uint32 count; /* number of devices actually found */ 67 benaphore kernel; /* for serializing opens/closes */ 68 char *device_names[MAX_DEVICES+1]; /* device name pointer storage */ 69 device_info di[MAX_DEVICES]; /* device specific stuff */ 70 } DeviceData; 71 72 /* prototypes for our private functions */ 73 static status_t open_hook (const char* name, uint32 flags, void** cookie); 74 static status_t close_hook (void* dev); 75 static status_t free_hook (void* dev); 76 static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len); 77 static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len); 78 static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len); 79 static status_t map_device(device_info *di); 80 static void unmap_device(device_info *di); 81 static void probe_devices(void); 82 static int32 gx00_interrupt(void *data); 83 84 static DeviceData *pd; 85 static pci_module_info *pci_bus; 86 static device_hooks graphics_device_hooks = { 87 open_hook, 88 close_hook, 89 free_hook, 90 control_hook, 91 read_hook, 92 write_hook, 93 NULL, 94 NULL, 95 NULL, 96 NULL 97 }; 98 99 #define VENDOR_ID 0x102b /* Matrox graphics inc. */ 100 101 static uint16 gx00_device_list[] = { 102 0x2527, /* G450AGP, G550AGP */ 103 0x0525, /* G400AGP */ 104 0x0520, /* G200PCI */ 105 0x0521, /* G200AGP */ 106 0x1000, /* G100PCI */ 107 0x1001, /* G100AGP */ 108 0x051B, /* MGA-2164 PCI Millennium 2 */ 109 0x051F, /* MGA-2164 AGP Millennium 2 */ 110 0x0519, /* MGA-2064 PCI Millennium 1 */ 111 //fixme? only support Mystique once we are sure we actually support it... 112 // 0x051A, /* MGA-1064 PCI Mystique 170/220 */ 113 0 114 }; 115 116 static struct { 117 uint16 vendor; 118 uint16 *devices; 119 } SupportedDevices[] = { 120 {VENDOR_ID, gx00_device_list}, 121 {0x0000, NULL} 122 }; 123 124 static settings current_settings = { // see comments in mga.settings 125 // for driver 126 DRIVER_PREFIX ".accelerant", 127 false, // dumprom 128 // for accelerant 129 0x00000000, // logmask 130 0, // memory 131 false, // usebios 132 false, // hardcursor 133 false, // greensync 134 }; 135 136 static void dumprom (void *rom, size_t size) 137 { 138 int fd = open ("/boot/home/" DRIVER_PREFIX ".rom", O_WRONLY | O_CREAT, 0666); 139 if (fd < 0) return; 140 write (fd, rom, size); 141 close (fd); 142 } 143 144 /*return 1, is interrupt has occured*/ 145 static int caused_vbi(vuint32 * regs) 146 { 147 return (ACCR(STATUS)&0x20); 148 } 149 150 /*clear the interrupt*/ 151 static void clear_vbi(vuint32 * regs) 152 { 153 ACCW(ICLEAR,0x20); 154 } 155 156 static void enable_vbi(vuint32 * regs) 157 { 158 ACCW(IEN,ACCR(IEN)|0x20); 159 } 160 161 static void disable_vbi(vuint32 * regs) 162 { 163 ACCW(IEN,(ACCR(IEN)&~0x20)); 164 ACCW(ICLEAR,0x20); 165 } 166 167 168 /* 169 init_hardware() - Returns B_OK if one is 170 found, otherwise returns B_ERROR so the driver will be unloaded. 171 */ 172 status_t 173 init_hardware(void) { 174 long pci_index = 0; 175 pci_info pcii; 176 bool found_one = FALSE; 177 178 /* choke if we can't find the PCI bus */ 179 if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK) 180 return B_ERROR; 181 182 /* while there are more pci devices */ 183 while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) { 184 int vendor = 0; 185 186 /* if we match a supported vendor */ 187 while (SupportedDevices[vendor].vendor) { 188 if (SupportedDevices[vendor].vendor == pcii.vendor_id) { 189 uint16 *devices = SupportedDevices[vendor].devices; 190 /* while there are more supported devices */ 191 while (*devices) { 192 /* if we match a supported device */ 193 if (*devices == pcii.device_id ) { 194 195 found_one = TRUE; 196 goto done; 197 } 198 /* next supported device */ 199 devices++; 200 } 201 } 202 vendor++; 203 } 204 /* next pci_info struct, please */ 205 pci_index++; 206 } 207 208 done: 209 /* put away the module manager */ 210 put_module(B_PCI_MODULE_NAME); 211 return (found_one ? B_OK : B_ERROR); 212 } 213 214 status_t 215 init_driver(void) { 216 void *settings_handle; 217 218 // get driver/accelerant settings, apsed 219 settings_handle = load_driver_settings (DRIVER_PREFIX ".settings"); 220 if (settings_handle != NULL) { 221 const char *item; 222 char *end; 223 uint32 value; 224 225 // for driver 226 item = get_driver_parameter (settings_handle, "accelerant", "", ""); 227 if ((strlen (item) > 0) && (strlen (item) < sizeof (current_settings.accelerant) - 1)) { 228 strcpy (current_settings.accelerant, item); 229 } 230 current_settings.dumprom = get_driver_boolean_parameter (settings_handle, "dumprom", false, false); 231 232 // for accelerant 233 item = get_driver_parameter (settings_handle, "logmask", "0x00000000", "0x00000000"); 234 value = strtoul (item, &end, 0); 235 if (*end == '\0') current_settings.logmask = value; 236 237 item = get_driver_parameter (settings_handle, "memory", "0", "0"); 238 value = strtoul (item, &end, 0); 239 if (*end == '\0') current_settings.memory = value; 240 241 current_settings.hardcursor = get_driver_boolean_parameter (settings_handle, "hardcursor", false, false); 242 current_settings.usebios = get_driver_boolean_parameter (settings_handle, "usebios", false, false); 243 current_settings.greensync = get_driver_boolean_parameter (settings_handle, "greensync", false, false); 244 245 unload_driver_settings (settings_handle); 246 } 247 248 /* get a handle for the pci bus */ 249 if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK) 250 return B_ERROR; 251 252 /* driver private data */ 253 pd = (DeviceData *)calloc(1, sizeof(DeviceData)); 254 if (!pd) { 255 put_module(B_PCI_MODULE_NAME); 256 return B_ERROR; 257 } 258 /* initialize the benaphore */ 259 INIT_BEN(pd->kernel); 260 /* find all of our supported devices */ 261 probe_devices(); 262 return B_OK; 263 } 264 265 const char ** 266 publish_devices(void) { 267 /* return the list of supported devices */ 268 return (const char **)pd->device_names; 269 } 270 271 device_hooks * 272 find_device(const char *name) { 273 int index = 0; 274 while (pd->device_names[index]) { 275 if (strcmp(name, pd->device_names[index]) == 0) 276 return &graphics_device_hooks; 277 index++; 278 } 279 return NULL; 280 281 } 282 283 void uninit_driver(void) { 284 285 /* free the driver data */ 286 DELETE_BEN(pd->kernel); 287 free(pd); 288 pd = NULL; 289 290 /* put the pci module away */ 291 put_module(B_PCI_MODULE_NAME); 292 } 293 294 static status_t map_device(device_info *di) 295 { 296 char buffer[B_OS_NAME_LENGTH]; /*memory for device name*/ 297 shared_info *si = di->si; 298 uint32 tmpUlong; 299 pci_info *pcii = &(di->pcii); 300 system_info sysinfo; 301 302 /*storage for the physical to virtual table (used for dma buffer)*/ 303 // physical_entry physical_memory[2]; 304 // #define G400_DMA_BUFFER_SIZE 1024*1024 305 306 /*variables for making copy of ROM*/ 307 char * rom_temp; 308 area_id rom_area; 309 310 /* MIL1 has frame_buffer in [1], control_regs in [0], and nothing in [2], while 311 * MIL2 and later have frame_buffer in [0], control_regs in [1], pseudo_dma in [2] */ 312 int frame_buffer = 0; 313 int registers = 1; 314 int pseudo_dma = 2; 315 316 /* correct layout for MIL1 */ 317 //fixme: checkout Mystique 170 and 220... 318 if (di->pcii.device_id == 0x0519) 319 { 320 frame_buffer = 1; 321 registers = 0; 322 } 323 324 /* enable memory mapped IO, disable VGA I/O - this is standard*/ 325 tmpUlong = get_pci(PCI_command, 4); 326 tmpUlong |= 0x00000002; 327 tmpUlong &= 0xfffffffe; 328 set_pci(PCI_command, 4, tmpUlong); 329 330 /*work out which version of BeOS is running*/ 331 get_system_info(&sysinfo); 332 if (0)//sysinfo.kernel_build_date[0]=='J')/*FIXME - better ID version*/ 333 { 334 si->use_clone_bugfix = 1; 335 } 336 else 337 { 338 si->use_clone_bugfix = 0; 339 } 340 341 /* work out a name for the register mapping */ 342 sprintf(buffer, DEVICE_FORMAT " regs", 343 di->pcii.vendor_id, di->pcii.device_id, 344 di->pcii.bus, di->pcii.device, di->pcii.function); 345 346 /* get a virtual memory address for the registers*/ 347 si->regs_area = map_physical_memory( 348 buffer, 349 (void *) di->pcii.u.h0.base_registers[registers], 350 di->pcii.u.h0.base_register_sizes[registers], 351 B_ANY_KERNEL_ADDRESS, 352 B_USER_CLONEABLE_AREA | (si->use_clone_bugfix ? B_READ_AREA|B_WRITE_AREA : 0), 353 (void **)&(di->regs)); 354 si->clone_bugfix_regs = (uint32 *) di->regs; 355 356 /* if mapping registers to vmem failed then pass on error */ 357 if (si->regs_area < 0) return si->regs_area; 358 359 /* work out a name for the ROM mapping*/ 360 sprintf(buffer, DEVICE_FORMAT " rom", 361 di->pcii.vendor_id, di->pcii.device_id, 362 di->pcii.bus, di->pcii.device, di->pcii.function); 363 364 /*place ROM over the fbspace (this is definately safe)*/ 365 tmpUlong = di->pcii.u.h0.base_registers[frame_buffer]; 366 tmpUlong |= 0x00000001; 367 set_pci(PCI_rom_base, 4, tmpUlong); 368 369 rom_area = map_physical_memory( 370 buffer, 371 (void *)di->pcii.u.h0.base_registers[frame_buffer], 372 32768, 373 B_ANY_KERNEL_ADDRESS, 374 B_READ_AREA, 375 (void **)&(rom_temp) 376 ); 377 378 /* if mapping ROM to vmem failed then clean up and pass on error */ 379 if (rom_area < 0) { 380 delete_area(si->regs_area); 381 si->regs_area = -1; 382 return rom_area; 383 } 384 385 /* make a copy of ROM for future reference*/ 386 memcpy (si->rom_mirror, rom_temp, 32768); 387 if (current_settings.dumprom) dumprom (rom_temp, 32768); 388 389 /*disable ROM and delete the area*/ 390 set_pci(PCI_rom_base,4,0); 391 delete_area(rom_area); 392 393 /* (pseudo)DMA does not exist on MIL1 */ 394 //fixme: checkout Mystique 170 and 220... 395 if (di->pcii.device_id != 0x0519) 396 { 397 /* work out a name for the pseudo dma mapping*/ 398 sprintf(buffer, DEVICE_FORMAT " pseudodma", 399 di->pcii.vendor_id, di->pcii.device_id, 400 di->pcii.bus, di->pcii.device, di->pcii.function); 401 402 /* map the pseudo dma into vmem (write-only)*/ 403 si->pseudo_dma_area = map_physical_memory( 404 buffer, 405 (void *) di->pcii.u.h0.base_registers[pseudo_dma], 406 di->pcii.u.h0.base_register_sizes[pseudo_dma], 407 B_ANY_KERNEL_ADDRESS, 408 B_WRITE_AREA, 409 &(si->pseudo_dma)); 410 411 /* if there was an error, delete our other areas and pass on error*/ 412 if (si->pseudo_dma_area < 0) { 413 delete_area(si->regs_area); 414 si->regs_area = -1; 415 return si->pseudo_dma_area; 416 } 417 418 /* work out a name for the a dma buffer*/ 419 // sprintf(buffer, DEVICE_FORMAT " dmabuffer", 420 // di->pcii.vendor_id, di->pcii.device_id, 421 // di->pcii.bus, di->pcii.device, di->pcii.function); 422 423 /* create an area for the dma buffer*/ 424 // si->dma_buffer_area = create_area( 425 // buffer, 426 // &si->dma_buffer, 427 // B_ANY_ADDRESS, 428 // G400_DMA_BUFFER_SIZE, 429 // B_FULL_LOCK|B_CONTIGUOUS, 430 // B_READ_AREA|B_WRITE_AREA); 431 432 /* if there was an error, delete our other areas and pass on error*/ 433 // if (si->dma_buffer_area < 0) { 434 // delete_area(si->pseudo_dma_area); 435 // si->pseudo_dma_area = -1; 436 // delete_area(si->regs_area); 437 // si->regs_area = -1; 438 // return si->dma_buffer_area; 439 // } 440 441 /*find where it is in real memory*/ 442 // get_memory_map(si->dma_buffer,4,physical_memory,1); 443 // si->dma_buffer_pci = physical_memory[0].address; /*addr from PCI space*/ 444 } 445 446 /* work out a name for the framebuffer mapping*/ 447 sprintf(buffer, DEVICE_FORMAT " framebuffer", 448 di->pcii.vendor_id, di->pcii.device_id, 449 di->pcii.bus, di->pcii.device, di->pcii.function); 450 451 /* map the framebuffer into vmem, using Write Combining*/ 452 si->fb_area = map_physical_memory( 453 buffer, 454 (void *) di->pcii.u.h0.base_registers[frame_buffer], 455 di->pcii.u.h0.base_register_sizes[frame_buffer], 456 B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, 457 B_READ_AREA | B_WRITE_AREA, 458 &(si->framebuffer)); 459 460 /*if failed with write combining try again without*/ 461 if (si->fb_area < 0) { 462 si->fb_area = map_physical_memory( 463 buffer, 464 (void *) di->pcii.u.h0.base_registers[frame_buffer], 465 di->pcii.u.h0.base_register_sizes[frame_buffer], 466 B_ANY_KERNEL_BLOCK_ADDRESS, 467 B_READ_AREA | B_WRITE_AREA, 468 &(si->framebuffer)); 469 } 470 471 /* if there was an error, delete our other areas and pass on error*/ 472 if (si->fb_area < 0) 473 { 474 /* (pseudo)DMA does not exist on MIL1 */ 475 //fixme: checkout Mystique 170 and 220... 476 if (di->pcii.device_id != 0x0519) 477 { 478 delete_area(si->dma_buffer_area); 479 si->dma_buffer_area = -1; 480 delete_area(si->pseudo_dma_area); 481 si->pseudo_dma_area = -1; 482 } 483 delete_area(si->regs_area); 484 si->regs_area = -1; 485 return si->fb_area; 486 } 487 /* remember the DMA address of the frame buffer for BDirectWindow?? purposes */ 488 si->framebuffer_pci = (void *) di->pcii.u.h0.base_registers_pci[frame_buffer]; 489 490 // remember settings for use here and in accelerant 491 si->settings = current_settings; 492 493 /* in any case, return the result */ 494 return si->fb_area; 495 } 496 497 static void unmap_device(device_info *di) { 498 shared_info *si = di->si; 499 uint32 tmpUlong; 500 pci_info *pcii = &(di->pcii); 501 502 /* disable memory mapped IO */ 503 tmpUlong = get_pci(PCI_command, 4); 504 tmpUlong &= 0xfffffffc; 505 set_pci(PCI_command, 4, tmpUlong); 506 /* delete the areas */ 507 if (si->regs_area >= 0) delete_area(si->regs_area); 508 if (si->fb_area >= 0) delete_area(si->fb_area); 509 si->regs_area = si->fb_area = -1; 510 511 /* (pseudo)DMA does not exist on MIL1 */ 512 //fixme: checkout Mystique 170 and 220... 513 if (di->pcii.device_id != 0x0519) 514 { 515 delete_area(si->dma_buffer_area); 516 si->dma_buffer_area = -1; 517 delete_area(si->pseudo_dma_area); 518 si->pseudo_dma_area = -1; 519 } 520 521 si->framebuffer = NULL; 522 di->regs = NULL; 523 } 524 525 static void probe_devices(void) { 526 uint32 pci_index = 0; 527 uint32 count = 0; 528 device_info *di = pd->di; 529 530 /* while there are more pci devices */ 531 while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) { 532 int vendor = 0; 533 534 /* if we match a supported vendor */ 535 while (SupportedDevices[vendor].vendor) { 536 if (SupportedDevices[vendor].vendor == di->pcii.vendor_id) { 537 uint16 *devices = SupportedDevices[vendor].devices; 538 /* while there are more supported devices */ 539 while (*devices) { 540 /* if we match a supported device */ 541 if (*devices == di->pcii.device_id ) { 542 /* publish the device name */ 543 sprintf(di->name, "graphics/" DEVICE_FORMAT, 544 di->pcii.vendor_id, di->pcii.device_id, 545 di->pcii.bus, di->pcii.device, di->pcii.function); 546 547 /* remember the name */ 548 pd->device_names[count] = di->name; 549 /* mark the driver as available for R/W open */ 550 di->is_open = 0; 551 /* mark areas as not yet created */ 552 di->shared_area = -1; 553 /* mark pointer to shared data as invalid */ 554 di->si = NULL; 555 /* inc pointer to device info */ 556 di++; 557 /* inc count */ 558 count++; 559 /* break out of these while loops */ 560 goto next_device; 561 } 562 /* next supported device */ 563 devices++; 564 } 565 } 566 vendor++; 567 } 568 next_device: 569 /* next pci_info struct, please */ 570 pci_index++; 571 } 572 /* propagate count */ 573 pd->count = count; 574 /* terminate list of device names with a null pointer */ 575 pd->device_names[pd->count] = NULL; 576 } 577 578 static uint32 thread_interrupt_work(int32 *flags, vuint32 *regs, shared_info *si) { 579 uint32 handled = B_HANDLED_INTERRUPT; 580 /* release the vblank semaphore */ 581 if (si->vblank >= 0) { 582 int32 blocked; 583 if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) { 584 release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE); 585 handled = B_INVOKE_SCHEDULER; 586 } 587 } 588 return handled; 589 } 590 591 static int32 592 gx00_interrupt(void *data) 593 { 594 int32 handled = B_UNHANDLED_INTERRUPT; 595 device_info *di = (device_info *)data; 596 shared_info *si = di->si; 597 int32 *flags = &(si->flags); 598 vuint32 *regs; 599 600 /* is someone already handling an interrupt for this device? */ 601 if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) { 602 goto exit0; 603 } 604 /* get regs */ 605 regs = di->regs; 606 607 /* was it a VBI? */ 608 if (caused_vbi(regs)) { 609 /*clear the interrupt*/ 610 clear_vbi(regs); 611 /*release the semaphore*/ 612 handled = thread_interrupt_work(flags, regs, si); 613 } 614 615 /* note that we're not in the handler any more */ 616 atomic_and(flags, ~SKD_HANDLER_INSTALLED); 617 618 exit0: 619 return handled; 620 } 621 622 static status_t open_hook (const char* name, uint32 flags, void** cookie) { 623 int32 index = 0; 624 device_info *di; 625 shared_info *si; 626 thread_id thid; 627 thread_info thinfo; 628 status_t result = B_OK; 629 vuint32 *regs; 630 char shared_name[B_OS_NAME_LENGTH]; 631 632 /* find the device name in the list of devices */ 633 /* we're never passed a name we didn't publish */ 634 while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++; 635 636 /* for convienience */ 637 di = &(pd->di[index]); 638 639 /* make sure no one else has write access to the common data */ 640 AQUIRE_BEN(pd->kernel); 641 642 /* if it's already open for writing */ 643 if (di->is_open) { 644 /* mark it open another time */ 645 goto mark_as_open; 646 } 647 /* create the shared area */ 648 sprintf(shared_name, DEVICE_FORMAT " shared", 649 di->pcii.vendor_id, di->pcii.device_id, 650 di->pcii.bus, di->pcii.device, di->pcii.function); 651 /* create this area with NO user-space read or write permissions, to prevent accidental dammage */ 652 di->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, 653 ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, 654 B_USER_CLONEABLE_AREA); 655 if (di->shared_area < 0) { 656 /* return the error */ 657 result = di->shared_area; 658 goto done; 659 } 660 661 /* save a few dereferences */ 662 si = di->si; 663 664 /* save the vendor and device IDs */ 665 si->vendor_id = di->pcii.vendor_id; 666 si->device_id = di->pcii.device_id; 667 si->revision = di->pcii.revision; 668 669 /* map the device */ 670 result = map_device(di); 671 if (result < 0) goto free_shared; 672 result = B_OK; 673 674 /* create a semaphore for vertical blank management */ 675 si->vblank = create_sem(0, di->name); 676 if (si->vblank < 0) { 677 result = si->vblank; 678 goto unmap; 679 } 680 681 /* change the owner of the semaphores to the opener's team */ 682 /* this is required because apps can't aquire kernel semaphores */ 683 thid = find_thread(NULL); 684 get_thread_info(thid, &thinfo); 685 set_sem_owner(si->vblank, thinfo.team); 686 687 /* assign local regs pointer for SAMPLExx() macros */ 688 regs = di->regs; 689 690 /* disable and clear any pending interrupts */ 691 disable_vbi(regs); 692 693 /* If there is a valid interrupt line assigned then set up interrupts */ 694 if ((di->pcii.u.h0.interrupt_pin == 0x00) || 695 (di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */ 696 (di->pcii.u.h0.interrupt_line <= 0x02)) /* system IRQ assigned */ 697 { 698 /* we are aborting! */ 699 /* Note: the R4 graphics driver kit lacks this statement!! */ 700 result = B_ERROR; 701 /* interrupt does not exist so exit without installing our handler */ 702 goto delete_the_sem; 703 } 704 else 705 { 706 /* otherwise install our interrupt handler */ 707 result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, gx00_interrupt, (void *)di, 0); 708 /* bail if we couldn't install the handler */ 709 if (result != B_OK) goto delete_the_sem; 710 } 711 712 mark_as_open: 713 /* mark the device open */ 714 di->is_open++; 715 716 /* send the cookie to the opener */ 717 *cookie = di; 718 719 goto done; 720 721 722 delete_the_sem: 723 delete_sem(si->vblank); 724 725 unmap: 726 unmap_device(di); 727 728 free_shared: 729 /* clean up our shared area */ 730 delete_area(di->shared_area); 731 di->shared_area = -1; 732 di->si = NULL; 733 734 done: 735 /* end of critical section */ 736 RELEASE_BEN(pd->kernel); 737 738 /* all done, return the status */ 739 return result; 740 } 741 742 /* ---------- 743 read_hook - does nothing, gracefully 744 ----- */ 745 static status_t 746 read_hook (void* dev, off_t pos, void* buf, size_t* len) 747 { 748 *len = 0; 749 return B_NOT_ALLOWED; 750 } 751 752 753 /* ---------- 754 write_hook - does nothing, gracefully 755 ----- */ 756 static status_t 757 write_hook (void* dev, off_t pos, const void* buf, size_t* len) 758 { 759 *len = 0; 760 return B_NOT_ALLOWED; 761 } 762 763 /* ---------- 764 close_hook - does nothing, gracefully 765 ----- */ 766 static status_t 767 close_hook (void* dev) 768 { 769 /* we don't do anything on close: there might be dup'd fd */ 770 return B_NO_ERROR; 771 } 772 773 /* ----------- 774 free_hook - close down the device 775 ----------- */ 776 static status_t 777 free_hook (void* dev) { 778 device_info *di = (device_info *)dev; 779 shared_info *si = di->si; 780 vuint32 *regs = di->regs; 781 782 /* lock the driver */ 783 AQUIRE_BEN(pd->kernel); 784 785 /* if opened multiple times, decrement the open count and exit */ 786 if (di->is_open > 1) 787 goto unlock_and_exit; 788 789 /* disable and clear any pending interrupts */ 790 disable_vbi(regs); 791 792 /* remove interrupt handler */ 793 remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, gx00_interrupt, di); 794 795 /* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */ 796 delete_sem(si->vblank); 797 si->vblank = -1; 798 799 /* free regs and framebuffer areas */ 800 unmap_device(di); 801 802 /* clean up our shared area */ 803 delete_area(di->shared_area); 804 di->shared_area = -1; 805 di->si = NULL; 806 807 unlock_and_exit: 808 /* mark the device available */ 809 di->is_open--; 810 /* unlock the driver */ 811 RELEASE_BEN(pd->kernel); 812 /* all done */ 813 return B_OK; 814 } 815 816 /* ----------- 817 control_hook - where the real work is done 818 ----------- */ 819 static status_t 820 control_hook (void* dev, uint32 msg, void *buf, size_t len) { 821 device_info *di = (device_info *)dev; 822 status_t result = B_DEV_INVALID_IOCTL; 823 824 switch (msg) { 825 /* the only PUBLIC ioctl */ 826 case B_GET_ACCELERANT_SIGNATURE: { 827 char *sig = (char *)buf; 828 strcpy(sig, current_settings.accelerant); 829 result = B_OK; 830 } break; 831 832 /* PRIVATE ioctl from here on */ 833 case GX00_GET_PRIVATE_DATA: { 834 gx00_get_private_data *gpd = (gx00_get_private_data *)buf; 835 if (gpd->magic == GX00_PRIVATE_DATA_MAGIC) { 836 gpd->shared_info_area = di->shared_area; 837 result = B_OK; 838 } 839 } break; 840 case GX00_GET_PCI: { 841 gx00_get_set_pci *gsp = (gx00_get_set_pci *)buf; 842 if (gsp->magic == GX00_PRIVATE_DATA_MAGIC) { 843 pci_info *pcii = &(di->pcii); 844 gsp->value = get_pci(gsp->offset, gsp->size); 845 result = B_OK; 846 } 847 } break; 848 case GX00_SET_PCI: { 849 gx00_get_set_pci *gsp = (gx00_get_set_pci *)buf; 850 if (gsp->magic == GX00_PRIVATE_DATA_MAGIC) { 851 pci_info *pcii = &(di->pcii); 852 set_pci(gsp->offset, gsp->size, gsp->value); 853 result = B_OK; 854 } 855 } break; 856 case GX00_DEVICE_NAME: { // apsed 857 gx00_device_name *dn = (gx00_device_name *)buf; 858 if (dn->magic == GX00_PRIVATE_DATA_MAGIC) { 859 strcpy(dn->name, di->name); 860 result = B_OK; 861 } 862 } break; 863 case GX00_RUN_INTERRUPTS: { 864 gx00_set_bool_state *ri = (gx00_set_bool_state *)buf; 865 if (ri->magic == GX00_PRIVATE_DATA_MAGIC) { 866 vuint32 *regs = di->regs; 867 if (ri->do_it) { 868 enable_vbi(regs); 869 } else { 870 disable_vbi(regs); 871 } 872 result = B_OK; 873 } 874 } break; 875 } 876 return result; 877 } 878 879