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