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