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