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