2 Copyright 1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
7 Rudolf Cornelissen 3/2002-1/2006.
10 /* standard kernel driver stuff */
11 #include <KernelExport.h>
14 #include <directories.h>
15 #include <driver_settings.h>
17 #include <stdlib.h> // for strtoXX
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>
23 /* this is for sprintf() */
26 /* this is for string compares */
29 /* The private interface between the accelerant and the kernel driver. */
30 #include "DriverInterface.h"
31 #include "mga_macros.h"
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))
39 # undef B_USER_CLONEABLE_AREA
40 # define B_USER_CLONEABLE_AREA 0
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
46 /* these structures are private to the kernel driver */
47 typedef struct device_info device_info
;
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 */
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) */
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 */
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
);
85 static DeviceData
*pd
;
86 static pci_module_info
*pci_bus
;
87 static device_hooks graphics_device_hooks
= {
100 #define VENDOR_ID 0x102b /* Matrox graphics inc. */
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 */
120 } SupportedDevices
[] = {
121 {VENDOR_ID
, gx00_device_list
},
125 /* see comments in mga.settings */
126 static settings current_settings
=
128 /* for kerneldriver */
129 DRIVER_PREFIX
".accelerant",
133 0x00000000, // logmask
140 static void dumprom (void *rom
, size_t size
, pci_info pcii
)
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
);
149 fd
= open (fname
, O_WRONLY
| O_CREAT
, 0666);
151 write (fd
, rom
, size
);
155 /*return 1, is interrupt has occured*/
156 static int caused_vbi(vuint32
* regs
)
158 return (ACCR(STATUS
)&0x20);
161 /*clear the interrupt*/
162 static void clear_vbi(vuint32
* regs
)
167 static void enable_vbi(vuint32
* regs
)
169 ACCW(IEN
,ACCR(IEN
)|0x20);
172 static void disable_vbi(vuint32
* regs
)
174 ACCW(IEN
,(ACCR(IEN
)&~0x20));
180 init_hardware() - Returns B_OK if one is
181 found, otherwise returns B_ERROR so the driver will be unloaded.
184 init_hardware(void) {
187 bool found_one
= FALSE
;
189 /* choke if we can't find the PCI bus */
190 if (get_module(B_PCI_MODULE_NAME
, (module_info
**)&pci_bus
) != B_OK
)
193 /* while there are more pci devices */
194 while ((*pci_bus
->get_nth_pci_info
)(pci_index
, &pcii
) == B_NO_ERROR
) {
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 */
203 /* if we match a supported device */
204 if (*devices
== pcii
.device_id
) {
209 /* next supported device */
215 /* next pci_info struct, please */
220 /* put away the module manager */
221 put_module(B_PCI_MODULE_NAME
);
222 return (found_one
? B_OK
: B_ERROR
);
227 void *settings_handle
;
229 // get driver/accelerant settings, apsed
230 settings_handle
= load_driver_settings (DRIVER_PREFIX
".settings");
231 if (settings_handle
!= NULL
) {
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
);
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
);
245 current_settings
.dumprom
= get_driver_boolean_parameter (settings_handle
, "dumprom", false, false);
248 item
= get_driver_parameter (settings_handle
, "logmask", "0x00000000", "0x00000000");
249 value
= strtoul (item
, &end
, 0);
250 if (*end
== '\0') current_settings
.logmask
= value
;
252 item
= get_driver_parameter (settings_handle
, "memory", "0", "0");
253 value
= strtoul (item
, &end
, 0);
254 if (*end
== '\0') current_settings
.memory
= value
;
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);
260 unload_driver_settings (settings_handle
);
263 /* get a handle for the pci bus */
264 if (get_module(B_PCI_MODULE_NAME
, (module_info
**)&pci_bus
) != B_OK
)
267 /* driver private data */
268 pd
= (DeviceData
*)calloc(1, sizeof(DeviceData
));
270 put_module(B_PCI_MODULE_NAME
);
273 /* initialize the benaphore */
274 INIT_BEN(pd
->kernel
);
275 /* find all of our supported devices */
281 publish_devices(void) {
282 /* return the list of supported devices */
283 return (const char **)pd
->device_names
;
287 find_device(const char *name
) {
289 while (pd
->device_names
[index
]) {
290 if (strcmp(name
, pd
->device_names
[index
]) == 0)
291 return &graphics_device_hooks
;
298 void uninit_driver(void) {
300 /* free the driver data */
301 DELETE_BEN(pd
->kernel
);
305 /* put the pci module away */
306 put_module(B_PCI_MODULE_NAME
);
309 static status_t
map_device(device_info
*di
)
311 char buffer
[B_OS_NAME_LENGTH
]; /*memory for device name*/
312 shared_info
*si
= di
->si
;
314 pci_info
*pcii
= &(di
->pcii
);
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
321 /*variables for making copy of ROM*/
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;
331 /* correct layout for MIL1 */
332 //fixme: checkout Mystique 170 and 220...
333 if (di
->pcii
.device_id
== 0x0519)
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
);
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*/
349 si
->use_clone_bugfix
= 1;
353 si
->use_clone_bugfix
= 0;
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
);
361 /* get a virtual memory address for the registers*/
362 si
->regs_area
= map_physical_memory(
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
;
371 /* if mapping registers to vmem failed then pass on error */
372 if (si
->regs_area
< 0) return si
->regs_area
;
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
);
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
);
384 rom_area
= map_physical_memory(
386 di
->pcii
.u
.h0
.base_registers
[frame_buffer
],
388 B_ANY_KERNEL_ADDRESS
,
393 /* if mapping ROM to vmem failed then clean up and pass on error */
395 delete_area(si
->regs_area
);
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
)
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). */
411 for (index
= 0; index
< pd
->count
; index
++)
413 if ((pd
->di
[index
].pcii
.bus
== di
->pcii
.bus
) &&
414 (pd
->di
[index
].pcii
.device
== 0x00))
422 /* make the copy from the primary VGA card on our bus */
423 memcpy (si
->rom_mirror
, pd
->di
[index
].rom_mirror
, 32768);
427 /* make a copy of 'non-ok' ROM area for future reference just in case */
428 memcpy (si
->rom_mirror
, rom_temp
, 32768);
433 /* make a copy of ROM for future reference */
434 memcpy (si
->rom_mirror
, rom_temp
, 32768);
437 if (current_settings
.dumprom
) dumprom (si
->rom_mirror
, 32768, di
->pcii
);
439 /*disable ROM and delete the area*/
440 set_pci(PCI_rom_base
,4,0);
441 delete_area(rom_area
);
443 /* (pseudo)DMA does not exist on MIL1 */
444 //fixme: checkout Mystique 170 and 220...
445 if (di
->pcii
.device_id
!= 0x0519)
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
);
452 /* map the pseudo dma into vmem (write-only)*/
453 si
->pseudo_dma_area
= map_physical_memory(
455 di
->pcii
.u
.h0
.base_registers
[pseudo_dma
],
456 di
->pcii
.u
.h0
.base_register_sizes
[pseudo_dma
],
457 B_ANY_KERNEL_ADDRESS
,
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
);
465 return si
->pseudo_dma_area
;
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);
473 /* create an area for the dma buffer*/
474 // si->dma_buffer_area = create_area(
478 // G400_DMA_BUFFER_SIZE,
480 // B_READ_AREA|B_WRITE_AREA);
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;
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*/
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
);
501 /* map the framebuffer into vmem, using Write Combining*/
502 si
->fb_area
= map_physical_memory(
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
,
510 /*if failed with write combining try again without*/
511 if (si
->fb_area
< 0) {
512 si
->fb_area
= map_physical_memory(
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
,
521 /* if there was an error, delete our other areas and pass on error*/
524 /* (pseudo)DMA does not exist on MIL1 */
525 //fixme: checkout Mystique 170 and 220...
526 if (di
->pcii
.device_id
!= 0x0519)
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;
533 delete_area(si
->regs_area
);
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
];
540 // remember settings for use here and in accelerant
541 si
->settings
= current_settings
;
543 /* in any case, return the result */
547 static void unmap_device(device_info
*di
) {
548 shared_info
*si
= di
->si
;
550 pci_info
*pcii
= &(di
->pcii
);
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;
561 /* (pseudo)DMA does not exist on MIL1 */
562 //fixme: checkout Mystique 170 and 220...
563 if (di
->pcii
.device_id
!= 0x0519)
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;
571 si
->framebuffer
= NULL
;
575 static void copy_rom(device_info
*di
)
577 char buffer
[B_OS_NAME_LENGTH
];
581 pci_info
*pcii
= &(di
->pcii
);
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;
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
);
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
);
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
);
605 rom_area
= map_physical_memory(
607 di
->pcii
.u
.h0
.base_registers
[frame_buffer
],
609 B_ANY_KERNEL_ADDRESS
,
614 /* if mapping ROM to vmem was successfull copy it */
617 /* copy ROM for future reference (MMS cards) */
618 memcpy (di
->rom_mirror
, rom_temp
, 32768);
620 /* disable ROM and delete the area */
621 set_pci(PCI_rom_base
, 4, 0);
622 delete_area(rom_area
);
625 /* disable memory mapped IO */
626 tmpUlong
= get_pci(PCI_command
, 4);
627 tmpUlong
&= 0xfffffffc;
628 set_pci(PCI_command
, 4, tmpUlong
);
631 static void probe_devices(void)
633 uint32 pci_index
= 0;
635 device_info
*di
= pd
->di
;
636 char tmp_name
[B_OS_NAME_LENGTH
];
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
))
643 /* if we match a supported vendor */
644 while (SupportedDevices
[vendor
].vendor
)
646 if (SupportedDevices
[vendor
].vendor
== di
->pcii
.vendor_id
)
648 uint16
*devices
= SupportedDevices
[vendor
].devices
;
649 /* while there are more supported devices */
652 /* if we match a supported device */
653 if (*devices
== di
->pcii
.device_id
)
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 */
670 /* mark areas as not yet created */
671 di
->shared_area
= -1;
672 /* mark pointer to shared data as invalid */
674 /* copy ROM for MMS (multihead with multiple GPU) cards:
675 * they might only have a ROM on the primary adaptor.
676 * (Confirmed G200MMS.) */
678 /* inc pointer to device info */
682 /* break out of these while loops */
685 /* next supported device */
692 /* next pci_info struct, please */
696 /* propagate count */
698 /* terminate list of device names with a null pointer */
699 pd
->device_names
[pd
->count
] = NULL
;
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) {
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
;
716 gx00_interrupt(void *data
)
718 int32 handled
= B_UNHANDLED_INTERRUPT
;
719 device_info
*di
= (device_info
*)data
;
720 shared_info
*si
= di
->si
;
721 int32
*flags
= &(si
->flags
);
724 /* is someone already handling an interrupt for this device? */
725 if (atomic_or(flags
, SKD_HANDLER_INSTALLED
) & SKD_HANDLER_INSTALLED
) {
732 if (caused_vbi(regs
)) {
733 /*clear the interrupt*/
735 /*release the semaphore*/
736 handled
= thread_interrupt_work(flags
, regs
, si
);
739 /* note that we're not in the handler any more */
740 atomic_and(flags
, ~SKD_HANDLER_INSTALLED
);
746 static status_t
open_hook (const char* name
, uint32 flags
, void** cookie
) {
752 status_t result
= B_OK
;
753 char shared_name
[B_OS_NAME_LENGTH
];
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
++;
759 /* for convienience */
760 di
= &(pd
->di
[index
]);
762 /* make sure no one else has write access to the common data */
763 AQUIRE_BEN(pd
->kernel
);
765 /* if it's already open for writing */
767 /* mark it open another time */
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
;
784 /* save a few dereferences */
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
;
795 /* ensure that the accelerant's INIT_ACCELERANT function can be executed */
796 si
->accelerant_in_use
= false;
799 result
= map_device(di
);
800 if (result
< 0) goto free_shared
;
802 /* we will be returning OK status for sure now */
805 /* disable and clear any pending interrupts */
806 disable_vbi(di
->regs
);
808 /* preset we can't use INT related functions */
809 si
->ps
.int_assigned
= false;
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
;
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
);
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 */
826 /* delete the semaphore as it won't be used */
827 delete_sem(si
->vblank
);
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 */
837 /* delete the semaphore as it won't be used */
838 delete_sem(si
->vblank
);
843 /* inform accelerant(s) we can use INT related functions */
844 si
->ps
.int_assigned
= true;
849 /* mark the device open */
852 /* send the cookie to the opener */
859 /* clean up our shared area */
860 delete_area(di
->shared_area
);
861 di
->shared_area
= -1;
865 /* end of critical section */
866 RELEASE_BEN(pd
->kernel
);
868 /* all done, return the status */
873 read_hook - does nothing, gracefully
876 read_hook (void* dev
, off_t pos
, void* buf
, size_t* len
)
879 return B_NOT_ALLOWED
;
884 write_hook - does nothing, gracefully
887 write_hook (void* dev
, off_t pos
, const void* buf
, size_t* len
)
890 return B_NOT_ALLOWED
;
894 close_hook - does nothing, gracefully
897 close_hook (void* dev
)
899 /* we don't do anything on close: there might be dup'd fd */
904 free_hook - close down the device
907 free_hook (void* dev
) {
908 device_info
*di
= (device_info
*)dev
;
909 shared_info
*si
= di
->si
;
910 vuint32
*regs
= di
->regs
;
912 /* lock the driver */
913 AQUIRE_BEN(pd
->kernel
);
915 /* if opened multiple times, decrement the open count and exit */
917 goto unlock_and_exit
;
919 /* disable and clear any pending interrupts */
922 if (si
->ps
.int_assigned
)
924 /* remove interrupt handler */
925 remove_io_interrupt_handler(di
->pcii
.u
.h0
.interrupt_line
, gx00_interrupt
, di
);
927 /* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */
928 delete_sem(si
->vblank
);
932 /* free regs and framebuffer areas */
935 /* clean up our shared area */
936 delete_area(di
->shared_area
);
937 di
->shared_area
= -1;
941 /* mark the device available */
943 /* unlock the driver */
944 RELEASE_BEN(pd
->kernel
);
950 control_hook - where the real work is done
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
;
958 /* the only PUBLIC ioctl */
959 case B_GET_ACCELERANT_SIGNATURE
: {
960 char *sig
= (char *)buf
;
961 strcpy(sig
, current_settings
.accelerant
);
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
;
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
);
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
);
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
);
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
;