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