Build system conversion and check in of ATI Mach64 driver for MYOB. Based on source written by Rene MacKinney.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8531 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -6,3 +6,5 @@ SubInclude OBOS_TOP src add-ons accelerants neomagic ;
|
||||
SubInclude OBOS_TOP src add-ons accelerants nvidia ;
|
||||
SubInclude OBOS_TOP src add-ons accelerants radeon ;
|
||||
SubInclude OBOS_TOP src add-ons accelerants tdfx ;
|
||||
|
||||
SubIncludeGPL OBOS_TOP src add-ons accelerants atimach64 ;
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
#define STICKY_REGS 1
|
||||
|
||||
#define WRITE_REG(x, y) outw(x, y)
|
||||
|
||||
#define wait_for_slots(num) WaitQueue(num)
|
||||
|
||||
/*#define wait_for_slots(numSlots) \
|
||||
{ \
|
||||
uint32 FifoReg; \
|
||||
\
|
||||
do \
|
||||
{ \
|
||||
READ_REG(FIFO_STAT, FifoReg); \
|
||||
} \
|
||||
while ((FifoReg & 0xFFFF) >> (16 - numSlots)); \
|
||||
}
|
||||
*/
|
||||
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
|
||||
|
||||
uint32 Offset, Pitch;
|
||||
uint32 BppEncoding;
|
||||
uint32 XDir;
|
||||
uint32 YDir;
|
||||
|
||||
uint32 src_top, src_left;
|
||||
uint32 dest_top, dest_left;
|
||||
uint32 width, height;
|
||||
|
||||
uint32 scissor_x = (si->dm.virtual_width - 1) << 16;
|
||||
uint32 scissor_y = (si->dm.virtual_height - 1) << 16;
|
||||
|
||||
// Perform required calculations and do the blit.
|
||||
// start of frame buffer
|
||||
Offset = 1024;
|
||||
Offset = Offset >> 3; // qword offset of the frame buffer in card memory; had
|
||||
// better be qword-aligned.
|
||||
|
||||
Pitch = si->dm.virtual_width;
|
||||
Pitch = (Pitch + 7) >> 3; // frame buffer stride in pixels*8
|
||||
|
||||
// encode pixel format
|
||||
switch (si->dm.space & ~0x3000)
|
||||
{
|
||||
case B_CMAP8:
|
||||
BppEncoding = 0x2;
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
BppEncoding = 0x3;
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
BppEncoding = 0x4;
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
default:
|
||||
BppEncoding = 0x6;
|
||||
}
|
||||
|
||||
BppEncoding = (BppEncoding << 28) | (BppEncoding << 16) | (BppEncoding << 8)
|
||||
| (BppEncoding << 4) | BppEncoding;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(10);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000300);
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(SRC_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
/* update fifo count */
|
||||
si->engine.count += 10;
|
||||
#endif
|
||||
|
||||
/* program the blit */
|
||||
while (count--) {
|
||||
src_left = list->src_left;
|
||||
src_top = list->src_top;
|
||||
dest_left = list->dest_left;
|
||||
dest_top = list->dest_top;
|
||||
width = list->width + 1; /* + 1 because it seems to be non-inclusive */
|
||||
height = list->height + 1;
|
||||
|
||||
// Adjust direction of blitting to allow for overlapping source and destination.
|
||||
if (src_left < dest_left)
|
||||
{
|
||||
XDir = 0; // right to left
|
||||
src_left += (width - 1);
|
||||
dest_left += (width - 1);
|
||||
}
|
||||
else
|
||||
XDir = 1; // left to right
|
||||
|
||||
if (src_top < dest_top)
|
||||
{
|
||||
YDir = 0; // bottom to top
|
||||
src_top += (height - 1);
|
||||
dest_top += (height - 1);
|
||||
}
|
||||
else
|
||||
YDir = 1; // top to bottom
|
||||
|
||||
|
||||
// Set up the rectangle blit
|
||||
|
||||
// Critital section - accessing card registers.
|
||||
//lock_card();
|
||||
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(5);
|
||||
#else
|
||||
wait_for_slots(15);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000300);
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(SRC_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
#endif
|
||||
|
||||
WRITE_REG(SRC_WIDTH1, width);
|
||||
WRITE_REG(SRC_Y_X, ((uint32)src_left << 16) | src_top);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_CNTL, (YDir << 1) | XDir);
|
||||
WRITE_REG(DST_Y_X, ((uint32)dest_left << 16) | dest_top);
|
||||
WRITE_REG(DST_HEIGHT_WIDTH, ((uint32)width << 16) | height); // This triggers drawing.
|
||||
|
||||
#if STICKY_REGS
|
||||
/* update fifo count */
|
||||
si->engine.count += 5;
|
||||
#else
|
||||
/* update fifo count */
|
||||
si->engine.count += 15;
|
||||
#endif
|
||||
/* next one */
|
||||
list++;
|
||||
}
|
||||
}
|
||||
|
||||
void hardware_rectangle(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count, uint32 ROP) {
|
||||
|
||||
uint32 Offset;
|
||||
uint32 Pitch;
|
||||
uint32 Y;
|
||||
uint32 X;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
uint32 Colour;
|
||||
uint32 BppEncoding;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
uint32 scissor_x = (si->dm.virtual_width - 1) << 16;
|
||||
uint32 scissor_y = (si->dm.virtual_height - 1) << 16;
|
||||
#endif
|
||||
|
||||
// Perform required calculations and do the blit.
|
||||
// start of frame buffer
|
||||
Offset = 1024;
|
||||
Offset = Offset >> 3; // qword offset of the frame buffer in card memory; had
|
||||
// better be qword-aligned.
|
||||
|
||||
Pitch = si->dm.virtual_width;
|
||||
Pitch = (Pitch + 7) >> 3; // frame buffer stride in pixels*8
|
||||
|
||||
// Don't need this - rectangle is in frame buffer co-ordinates.
|
||||
// X += (uint32) (CardInfo.Display.DisplayXPos);
|
||||
// Y += (uint32) (CardInfo.Display.DisplayYPos);
|
||||
|
||||
// Fill colour dword with specified colour, though only ls should be necessary.
|
||||
switch (si->dm.space & ~0x3000)
|
||||
{
|
||||
case B_CMAP8:
|
||||
BppEncoding = 0x2;
|
||||
colorIndex &= 0xFF;
|
||||
Colour = colorIndex | (colorIndex << 8) | (colorIndex << 16) | (colorIndex << 24);
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
BppEncoding = 0x3;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
BppEncoding = 0x4;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
default:
|
||||
BppEncoding = 0x6;
|
||||
Colour = colorIndex;
|
||||
}
|
||||
|
||||
BppEncoding = (BppEncoding << 28) | (BppEncoding << 16) | (BppEncoding << 8) | (BppEncoding << 4) | BppEncoding;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(11);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, ROP);
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
/* update fifo count */
|
||||
si->engine.count += 11;
|
||||
#endif
|
||||
|
||||
while (count--) {
|
||||
|
||||
X = list->left;
|
||||
Y = list->top;
|
||||
Width = list->right;
|
||||
Width = Width - X + 1;
|
||||
Height = list->bottom;
|
||||
Height = Height - Y + 1;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(2);
|
||||
#else
|
||||
wait_for_slots(13);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, ROP);
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, ((X + Width - 1) << 16) | X);
|
||||
WRITE_REG(SC_TOP_BOTTOM, ((Y + Height - 1) << 16) | Y);
|
||||
#endif
|
||||
|
||||
// X and Y should have been clipped to frame buffer, and so should be in range.
|
||||
WRITE_REG(DST_Y_X, (X << 16) | Y);
|
||||
WRITE_REG(DST_HEIGHT_WIDTH, (Width << 16) | Height); // This triggers drawing.
|
||||
|
||||
#if STICKY_REGS
|
||||
/* update fifo count */
|
||||
si->engine.count += 2;
|
||||
#else
|
||||
/* update fifo count */
|
||||
si->engine.count += 13;
|
||||
#endif
|
||||
|
||||
/* next rect */
|
||||
list++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) {
|
||||
hardware_rectangle(et, colorIndex, list, count, 0x00070007); // ROP = SRC
|
||||
}
|
||||
|
||||
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) {
|
||||
hardware_rectangle(et, 0xFFFFFFFF, list, count, 0x00000000); // ROP = !DST
|
||||
}
|
||||
|
||||
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) {
|
||||
uint32 Offset;
|
||||
uint32 Pitch;
|
||||
uint32 Y;
|
||||
uint32 X;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
uint32 Colour;
|
||||
uint32 BppEncoding;
|
||||
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
uint32 scissor_x = (si->dm.virtual_width - 1) << 16;
|
||||
uint32 scissor_y = (si->dm.virtual_height - 1) << 16;
|
||||
#endif
|
||||
|
||||
// Perform required calculations and do the blit.
|
||||
// start of frame buffer
|
||||
Offset = 1024;
|
||||
Offset = Offset >> 3; // qword offset of the frame buffer in card memory; had
|
||||
// better be qword-aligned.
|
||||
|
||||
Pitch = si->dm.virtual_width;
|
||||
Pitch = (Pitch + 7) >> 3; // frame buffer stride in pixels*8
|
||||
|
||||
// Fill colour dword with specified colour, though only ls should be necessary.
|
||||
switch (si->dm.space & ~0x3000)
|
||||
{
|
||||
case B_CMAP8:
|
||||
BppEncoding = 0x2;
|
||||
colorIndex &= 0xFF;
|
||||
Colour = colorIndex | (colorIndex << 8) | (colorIndex << 16) | (colorIndex << 24);
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
BppEncoding = 0x3;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
BppEncoding = 0x4;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
default:
|
||||
BppEncoding = 0x6;
|
||||
Colour = colorIndex;
|
||||
}
|
||||
|
||||
BppEncoding = (BppEncoding << 28) | (BppEncoding << 16) | (BppEncoding << 8) | (BppEncoding << 4) | BppEncoding;
|
||||
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(11);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
/* update fifo count */
|
||||
si->engine.count += 11;
|
||||
#endif
|
||||
/* span lines are always one pixel tall */
|
||||
Height = 1;
|
||||
while (count--) {
|
||||
|
||||
Y = (uint32)*list++;
|
||||
X = (uint32)*list++;
|
||||
Width = (uint32)*list++;
|
||||
Width = Width - X + 1;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(2);
|
||||
#else
|
||||
wait_for_slots(13);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, ((X + Width - 1) << 16) | X);
|
||||
WRITE_REG(SC_TOP_BOTTOM, ((Y + Height - 1) << 16) | Y);
|
||||
#endif
|
||||
|
||||
// X and Y should have been clipped to frame buffer, and so should be in range.
|
||||
WRITE_REG(DST_Y_X, (X << 16) | Y);
|
||||
WRITE_REG(DST_HEIGHT_WIDTH, (Width << 16) | Height); // This triggers drawing.
|
||||
|
||||
#if STICKY_REGS
|
||||
/* update fifo count */
|
||||
si->engine.count += 2;
|
||||
#else
|
||||
/* update fifo count */
|
||||
si->engine.count += 13;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
void set_cursor_colors(void);
|
||||
uint8 bit_mirror(uint8 bits);
|
||||
uint16 bit_merger(uint8 andbits, uint8 xorbits);
|
||||
|
||||
void set_cursor_colors(void) {
|
||||
/* a place-holder for a routine to set the cursor colors */
|
||||
/* In our sample driver, it's only called by the INIT_ACCELERANT() */
|
||||
|
||||
/* Cursor color 0 is black */
|
||||
|
||||
outw(CUR_CLR0, 0x00000000);
|
||||
|
||||
/* Cursor color 1 is white */
|
||||
|
||||
outw(CUR_CLR1, 0xffffffff);
|
||||
|
||||
}
|
||||
|
||||
uint8
|
||||
bit_mirror(uint8 bits)
|
||||
{
|
||||
int i;
|
||||
uint8 res = 0;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
res |= (1 & (bits>>i)) <<(7-i);
|
||||
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16
|
||||
bit_merger(uint8 andbits, uint8 xorbits)
|
||||
{
|
||||
int i;
|
||||
uint16 res = 0;
|
||||
uint8 bits = 0;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
bits = (((xorbits & (1<<i))>>i)<<1) | ((andbits & (1<<i))>>i);
|
||||
switch (bits){
|
||||
case 0: /* Transparent is 10 */
|
||||
res |= (2 << (i*2));
|
||||
break;
|
||||
case 2: /* Inversion is 11 */
|
||||
res |= (3 << (i*2));
|
||||
break;
|
||||
case 1: /* White is color 1 */
|
||||
res |= (1 << (i*2));
|
||||
break;
|
||||
case 3: /* Black is color 0 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask) {
|
||||
|
||||
int i, j, k;
|
||||
uint8 andM, xorM;
|
||||
uint16 *cdata = (uint16 *)si->cursor.data;
|
||||
|
||||
/* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */
|
||||
|
||||
if ((width != 16) || (height != 16))
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
else if ((hot_x >= width) || (hot_y >= height))
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Turn off cursor */
|
||||
SHOW_CURSOR(false);
|
||||
|
||||
|
||||
/* Fill up data */
|
||||
k = 0;
|
||||
for(i = 0; i < height; i++) {
|
||||
for(j = 0; j < (width / 8); j++) {
|
||||
andM = bit_mirror(~*(andMask++));
|
||||
xorM = bit_mirror(*(xorMask++));
|
||||
|
||||
/* convert 8 bits to 16 bits of mask */
|
||||
cdata[j + (i*8)] =
|
||||
bit_merger(andM, xorM);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/* Update cursor variables appropriately. */
|
||||
si->cursor.width = width;
|
||||
si->cursor.height = height;
|
||||
si->cursor.hot_x = hot_x;
|
||||
si->cursor.hot_y = hot_y;
|
||||
|
||||
/* Turn on cursor */
|
||||
SHOW_CURSOR(true);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Move the cursor to the specified position on the desktop. If we're
|
||||
using some kind of virtual desktop, adjust the display start position
|
||||
accordingly and position the cursor in the proper "virtual" location.
|
||||
*/
|
||||
void
|
||||
MOVE_CURSOR(uint16 x, uint16 y) {
|
||||
|
||||
bool move_screen = false;
|
||||
uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */
|
||||
uint16 vds = si->dm.v_display_start; /* the current vertical starting line */
|
||||
int xoff, yoff; /* offsets of cursor if it goes out of the screen */
|
||||
/*
|
||||
Most cards can't set the starting horizontal pixel to anything but a multiple
|
||||
of eight. If your card can, then you can change the adjustment factor here.
|
||||
Oftentimes the restriction is mode dependant, so you could be fancier and
|
||||
perhaps get smoother horizontal scrolling with more work. It's a sample driver,
|
||||
so we're going to be lazy here.
|
||||
*/
|
||||
uint16 h_adjust = 7; /* a mask to make horizontal values a multiple of 8 */
|
||||
|
||||
/* clamp cursor to virtual display */
|
||||
if (x >= si->dm.virtual_width) x = si->dm.virtual_width - 1;
|
||||
if (y >= si->dm.virtual_height) y = si->dm.virtual_height - 1;
|
||||
|
||||
/* adjust h/v_display_start to move cursor onto screen */
|
||||
if (x >= (si->dm.timing.h_display + hds)) {
|
||||
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
|
||||
move_screen = true;
|
||||
} else if (x < hds) {
|
||||
hds = x & ~h_adjust;
|
||||
move_screen = true;
|
||||
}
|
||||
if (y >= (si->dm.timing.v_display + vds)) {
|
||||
vds = y - si->dm.timing.v_display + 1;
|
||||
move_screen = true;
|
||||
} else if (y < vds) {
|
||||
vds = y;
|
||||
move_screen = true;
|
||||
}
|
||||
/* reposition the desktop on the display if required */
|
||||
if (move_screen) MOVE_DISPLAY(hds,vds);
|
||||
|
||||
/* put cursor in correct physical position */
|
||||
x -= hds;
|
||||
y -= vds;
|
||||
|
||||
/* Take care of hot_x hot_y */
|
||||
xoff = x - si->cursor.hot_x;
|
||||
yoff = y - si->cursor.hot_y;
|
||||
|
||||
/* Do we have to fake the cursor going out of the screen ? */
|
||||
if (xoff < 0) {
|
||||
xoff = -xoff;
|
||||
} else {
|
||||
xoff = 0;
|
||||
x -= si->cursor.hot_x;
|
||||
}
|
||||
|
||||
if (yoff < 0) {
|
||||
yoff = -yoff;
|
||||
} else {
|
||||
yoff = 0;
|
||||
y -= si->cursor.hot_y;
|
||||
}
|
||||
|
||||
/* Position the offset of the cursor */
|
||||
outw(CUR_HORZ_VERT_OFF, (yoff << 16) | xoff);
|
||||
|
||||
|
||||
/* position the cursor on the display */
|
||||
/* this will be card dependant */
|
||||
|
||||
/* printf(" Place %08x %d %d \n", si->regs + CUR_HORZ_VERT_POSN, x, y);*/
|
||||
|
||||
outw(CUR_HORZ_VERT_POSN, (y << 16) | x);
|
||||
|
||||
}
|
||||
|
||||
void SHOW_CURSOR(bool is_visible) {
|
||||
|
||||
if (is_visible) {
|
||||
/* add cursor showing code here */
|
||||
WaitQueue(4);
|
||||
while (!(inw(CRTC_VLINE_CRNT_VLINE) & CRTC_CRNT_VLINE));
|
||||
outb(GEN_TEST_CNTL, inb(GEN_TEST_CNTL) | HWCURSOR_ENABLE);
|
||||
} else {
|
||||
/* add cursor hiding code here */
|
||||
WaitQueue(4);
|
||||
outb(GEN_TEST_CNTL, inb(GEN_TEST_CNTL) & (~HWCURSOR_ENABLE));
|
||||
}
|
||||
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* record for our info */
|
||||
si->cursor.is_visible = is_visible;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
||||
static engine_token ati_engine_token = { 1, B_2D_ACCELERATION, NULL };
|
||||
|
||||
uint32 ACCELERANT_ENGINE_COUNT(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et) {
|
||||
/* acquire the shared benaphore */
|
||||
AQUIRE_BEN(si->engine.lock)
|
||||
/* sync if required */
|
||||
if (st) SYNC_TO_TOKEN(st);
|
||||
|
||||
/* return an engine token */
|
||||
*et = &ati_engine_token;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t RELEASE_ENGINE(engine_token *et, sync_token *st) {
|
||||
/* update the sync token, if any */
|
||||
if (st) {
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
}
|
||||
|
||||
/* release the shared benaphore */
|
||||
RELEASE_BEN(si->engine.lock)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void WAIT_ENGINE_IDLE(void) {
|
||||
|
||||
// Wait until engine finishes
|
||||
WaitIdleEmpty();
|
||||
// note our current possition
|
||||
si->engine.last_idle = si->engine.count;
|
||||
}
|
||||
|
||||
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) {
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t SYNC_TO_TOKEN(sync_token *st) {
|
||||
|
||||
uint64 fifo_diff;
|
||||
uint64 fifo_limit;
|
||||
|
||||
/* a quick out */
|
||||
if (st->counter < si->engine.last_idle) return B_OK;
|
||||
|
||||
/* the full monty */
|
||||
fifo_limit = si->engine.fifo_limit;
|
||||
/* fifo_mask = si->fifo_mask;*/
|
||||
do {
|
||||
/* calculate the age of the sync token */
|
||||
fifo_diff = (vuint64)(si->engine.count) - st->counter;
|
||||
/* add in the number of free slots in the fifo */
|
||||
fifo_diff += (uint64)((inw(GUI_STAT) >> 16) & 0x003f);
|
||||
/*
|
||||
The astute observer will notice that the free slot counter
|
||||
doesn't have enough bits to represent the full FIFO depth.
|
||||
This means that for "recent" operations, we end up waiting
|
||||
on engine idle :-(
|
||||
*/
|
||||
#if 1
|
||||
/* add one if the engine is idle (for when st->counter == si->engine.count) */
|
||||
if (!(inw(GUI_STAT) & 0x01)) fifo_diff++;
|
||||
#endif
|
||||
/* anything more than fifo_limit fifo slots ago is guaranteed done */
|
||||
/* if the engine is idle, bail out */
|
||||
} while ((fifo_diff <= fifo_limit) && (inw(GUI_STAT) & 0x01));
|
||||
|
||||
/* WAIT_ENGINE_IDLE(); */
|
||||
|
||||
si->engine.last_idle = st->counter;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "generic.h"
|
||||
|
||||
/*
|
||||
|
||||
The standard entry point. Given a uint32 feature identifier, this routine
|
||||
returns a pointer to the function that implements the feature. Some features
|
||||
require more information than just the identifier to select the proper
|
||||
function. The extra information (which is specific to the feature) is
|
||||
pointed at by the void *data parameter. By default, no extra information
|
||||
is available. Any extra information available to choose the function will be
|
||||
noted on a case by case below.
|
||||
|
||||
*/
|
||||
void * get_accelerant_hook(uint32 feature, void *data) {
|
||||
switch (feature) {
|
||||
/*
|
||||
These definitions are out of pure lazyness.
|
||||
*/
|
||||
#define HOOK(x) case B_##x: return (void *)x
|
||||
#define ZERO(x) case B_##x: return (void *)0
|
||||
|
||||
/*
|
||||
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
|
||||
subsequently called before any other hook is requested. All other feature
|
||||
hook selections can be predicated on variables assigned during the accelerant
|
||||
initialization process.
|
||||
*/
|
||||
/* initialization */
|
||||
HOOK(INIT_ACCELERANT);
|
||||
HOOK(CLONE_ACCELERANT);
|
||||
|
||||
HOOK(ACCELERANT_CLONE_INFO_SIZE);
|
||||
HOOK(GET_ACCELERANT_CLONE_INFO);
|
||||
HOOK(UNINIT_ACCELERANT);
|
||||
//HOOK(GET_ACCELERANT_DEVICE_INFO);
|
||||
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
|
||||
|
||||
/* mode configuration */
|
||||
HOOK(ACCELERANT_MODE_COUNT);
|
||||
HOOK(GET_MODE_LIST);
|
||||
HOOK(PROPOSE_DISPLAY_MODE);
|
||||
HOOK(SET_DISPLAY_MODE);
|
||||
HOOK(GET_DISPLAY_MODE);
|
||||
HOOK(GET_FRAME_BUFFER_CONFIG);
|
||||
HOOK(GET_PIXEL_CLOCK_LIMITS);
|
||||
HOOK(MOVE_DISPLAY);
|
||||
HOOK(SET_INDEXED_COLORS);
|
||||
//HOOK(GET_TIMING_CONSTRAINTS);
|
||||
|
||||
HOOK(DPMS_CAPABILITIES);
|
||||
HOOK(DPMS_MODE);
|
||||
HOOK(SET_DPMS_MODE);
|
||||
|
||||
/* cursor managment */
|
||||
HOOK(SET_CURSOR_SHAPE);
|
||||
HOOK(MOVE_CURSOR);
|
||||
HOOK(SHOW_CURSOR);
|
||||
|
||||
/* synchronization */
|
||||
HOOK(ACCELERANT_ENGINE_COUNT);
|
||||
HOOK(ACQUIRE_ENGINE);
|
||||
HOOK(RELEASE_ENGINE);
|
||||
HOOK(WAIT_ENGINE_IDLE);
|
||||
HOOK(GET_SYNC_TOKEN);
|
||||
HOOK(SYNC_TO_TOKEN);
|
||||
|
||||
/*
|
||||
When requesting an acceleration hook, the calling application provides a
|
||||
pointer to the display_mode for which the acceleration function will be used.
|
||||
Depending on the engine architecture, you may choose to provide a different
|
||||
function to be used with each bit-depth. In the sample driver we return
|
||||
the same function all the time.
|
||||
*/
|
||||
/* 2D acceleration */
|
||||
HOOK(SCREEN_TO_SCREEN_BLIT);
|
||||
HOOK(FILL_RECTANGLE);
|
||||
HOOK(INVERT_RECTANGLE);
|
||||
HOOK(FILL_SPAN);
|
||||
#undef HOOK
|
||||
#undef ZERO
|
||||
}
|
||||
/*
|
||||
Return a null pointer for any feature we don't understand.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
extern uint32 calcBitsPerPixel(uint32 cs);
|
||||
|
||||
/*
|
||||
Return the current display mode. The only time you might return an
|
||||
error is if a mode hasn't been set.
|
||||
*/
|
||||
status_t GET_DISPLAY_MODE(display_mode *current_mode) {
|
||||
/* easy for us, we return the last mode we set */
|
||||
*current_mode = si->dm;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the frame buffer configuration information.
|
||||
*/
|
||||
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb) {
|
||||
/* easy again, as the last mode set stored the info in a convienient form */
|
||||
*afb = si->fbc;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the maximum and minium pixel clock limits for the specified mode.
|
||||
*/
|
||||
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high) {
|
||||
/*
|
||||
Note that we're not making any guarantees about the ability of the attached
|
||||
display to handle pixel clocks within the limits we return. A future monitor
|
||||
capablilities database will post-process this information.
|
||||
*/
|
||||
uint32 total_pix = (uint32)dm->timing.h_total * (uint32)dm->timing.v_total;
|
||||
uint32 clock_limit;
|
||||
float i;
|
||||
|
||||
/* max pixel clock is pixel depth dependant */
|
||||
switch (calcBitsPerPixel(dm->space)) {
|
||||
case 32: clock_limit = si->pix_clk_max32; break;
|
||||
case 15:
|
||||
case 16: clock_limit = si->pix_clk_max16; break;
|
||||
case 8: clock_limit = si->pix_clk_max8; break;
|
||||
default:
|
||||
clock_limit = 0;
|
||||
}
|
||||
/* printf("low %d, high %d %d \n", *low, clock_limit, si->pix_clk_max8);*/
|
||||
/* lower limit of about 48Hz vertical refresh */
|
||||
*low = (total_pix * 48L) / 1000L;
|
||||
i = (total_pix * 48L) / 1000L;
|
||||
|
||||
/* printf("low %d, high %d %08X \n", *low, clock_limit, dm->space);*/
|
||||
|
||||
if (*low > clock_limit) return B_ERROR;
|
||||
*high = clock_limit;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the semaphore id that will be used to signal a vertical retrace
|
||||
occured.
|
||||
*/
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void) {
|
||||
/*
|
||||
NOTE:
|
||||
The kernel driver created this for us. We don't know if the system is
|
||||
using real interrupts, or if we're faking it, and we don't care.
|
||||
If we choose not to support this at all, we'd just return B_ERROR here,
|
||||
and the user wouldn't get any kind of vertical retrace support.
|
||||
*/
|
||||
/* return si->vblank;*/
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "GlobalData.h"
|
||||
|
||||
int fd;
|
||||
shared_info *si;
|
||||
area_id shared_info_area;
|
||||
vuint32 *regs;
|
||||
area_id regs_area;
|
||||
display_mode *atimach64_mode_list;
|
||||
area_id atimach64_mode_list_area;
|
||||
int accelerantIsClone;
|
||||
@@ -0,0 +1,16 @@
|
||||
#if !defined(GLOBALDATA_H)
|
||||
#define GLOBALDATA_H
|
||||
|
||||
#include "DriverInterface.h"
|
||||
#include "regmach64.h"
|
||||
|
||||
extern int fd;
|
||||
extern shared_info *si;
|
||||
extern area_id shared_info_area;
|
||||
extern vuint32 *regs;
|
||||
extern area_id regs_area;
|
||||
extern display_mode *atimach64_mode_list;
|
||||
extern area_id atimach64_mode_list_area;
|
||||
extern int accelerantIsClone;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,372 @@
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "Mach64.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "unistd.h"
|
||||
#include "sys/types.h"
|
||||
#include "sys/stat.h"
|
||||
#include "fcntl.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include "stdio.h"
|
||||
|
||||
/* defined in ProposeDisplayMode.c */
|
||||
extern status_t create_mode_list(void);
|
||||
/* defined in Cursor.c */
|
||||
extern void set_cursor_colors(void);
|
||||
|
||||
// Determines the amount of card memory available by seeing how far up the frame buffer
|
||||
// data can be written and read back reliably. Does a paranoia check to make sure that
|
||||
// It isn't just wrapping, either.
|
||||
unsigned long Get_Card_Mem_Size()
|
||||
{
|
||||
// Allowed sizes actually go up to 16 megs, but clip at the register window for now.
|
||||
const unsigned long AllowedSizes[] =
|
||||
{ 0x00080000, 0x00100000, 0x00180000, 0x00200000,
|
||||
0x00280000, 0x00300000, 0x00380000, 0x00400000,
|
||||
0x00500000, 0x00600000, 0x00700000, 0x007FF800,
|
||||
0x0 };
|
||||
|
||||
unsigned long MaxMem;
|
||||
unsigned long RWIndex;
|
||||
int iMaxIndex, iTestIndex, iX;
|
||||
unsigned long LTemp;
|
||||
int IsOk;
|
||||
uint32 *VramBase;
|
||||
|
||||
VramBase = (uint32 *)si->framebuffer;
|
||||
MaxMem = 0; // Default.
|
||||
IsOk = 1;
|
||||
// Step through ever-larger memory sizes, recording size if passes test and
|
||||
// ignoring otherwise.
|
||||
for (iMaxIndex = 0; (AllowedSizes[iMaxIndex] != 0) && IsOk; iMaxIndex++)
|
||||
{
|
||||
// Write test values to the linear aperature.
|
||||
// Only need to do this for the farthest location, as previous locations
|
||||
// already have been written to in previous passes.
|
||||
RWIndex = AllowedSizes[iMaxIndex];
|
||||
RWIndex = (RWIndex - 16384) >> 2;
|
||||
for (iX = 0; iX < 4096; iX++)
|
||||
{
|
||||
LTemp = RWIndex;
|
||||
// Hash LTemp. As the parameters for the hash are prime, it should
|
||||
// be extremely unlikely to get these values through a glitch, and
|
||||
// the pattern only repeats at prime intervals, so aliasing shouldn't
|
||||
// fool the test either.
|
||||
LTemp = (263 * (LTemp % 65521) + 29) % 65521;
|
||||
// Extend this to 32 bits.
|
||||
LTemp |= (LTemp ^ 0x0000FFFFul) << 16;
|
||||
VramBase[RWIndex] = LTemp;
|
||||
RWIndex++;
|
||||
}
|
||||
|
||||
// Verify that all test patterns are still intact. If values written past the
|
||||
// end of memory drop off the face of the frame buffer, the farthest pattern(s)
|
||||
// will not be what they should be. If values written past the end of memory
|
||||
// wrap, then previous patterns will be overwritten (or partly overwritten,
|
||||
// as the test location at 8 megs is actually at 8 megs - 2k).
|
||||
// As soon as an invalid value is detected, IsOk is set to 0, which should
|
||||
// quickly terminate the test loops.
|
||||
for (iTestIndex = 0; (iTestIndex <= iMaxIndex) && IsOk; iTestIndex++)
|
||||
{
|
||||
RWIndex = AllowedSizes[iTestIndex];
|
||||
RWIndex = (RWIndex - 16384) >> 2;
|
||||
for (iX = 0; (iX < 4096) && IsOk; iX++)
|
||||
{
|
||||
LTemp = RWIndex;
|
||||
// Hash LTemp. As the parameters for the hash are prime, it should
|
||||
// be extremely unlikely to get these values through a glitch, and
|
||||
// the pattern only repeats at prime intervals, so aliasing shouldn't
|
||||
// fool the test either.
|
||||
LTemp = (263 * (LTemp % 65521) + 29) % 65521;
|
||||
// Extend this to 32 bits.
|
||||
LTemp |= (LTemp ^ 0x0000FFFFul) << 16;
|
||||
// Test against the value read from the frame buffer.
|
||||
if (VramBase[RWIndex] != LTemp)
|
||||
IsOk = 0;
|
||||
RWIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// If the test patterns check out, update MaxMem accordingly.
|
||||
if (IsOk)
|
||||
MaxMem = AllowedSizes[iMaxIndex];
|
||||
}
|
||||
return MaxMem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static status_t init_common(int the_fd);
|
||||
|
||||
/* Initialization code shared between primary and cloned accelerants */
|
||||
static status_t init_common(int the_fd) {
|
||||
status_t result;
|
||||
atimach64_get_private_data gpd;
|
||||
|
||||
/* memorize the file descriptor */
|
||||
fd = the_fd;
|
||||
/* set the magic number so the driver knows we're for real */
|
||||
gpd.magic = ATIMACH64_PRIVATE_DATA_MAGIC;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, ATIMACH64_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
|
||||
|
||||
if (result != B_OK) goto error0;
|
||||
|
||||
/* clone the shared area for our use */
|
||||
shared_info_area = clone_area("ATIMACH64 shared info", (void **)&si, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
|
||||
if (shared_info_area < 0) {
|
||||
result = shared_info_area;
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* all done */
|
||||
goto error0;
|
||||
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Clean up code shared between primary and cloned accelrants */
|
||||
static void uninit_common(void) {
|
||||
/* release the memory mapped registers */
|
||||
/* delete_area(regs_area); */
|
||||
/* a little cheap paranoia */
|
||||
regs = 0;
|
||||
/* release our copy of the shared info from the kernel driver */
|
||||
delete_area(shared_info_area);
|
||||
/* more cheap paranoia */
|
||||
si = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the accelerant. the_fd is the file handle of the device (in
|
||||
/dev/graphics) that has been opened by the app_server (or some test harness).
|
||||
We need to determine if the kernel driver and the accelerant are compatible.
|
||||
If they are, get the accelerant ready to handle other hook functions and
|
||||
report success or failure.
|
||||
*/
|
||||
status_t INIT_ACCELERANT(int the_fd) {
|
||||
status_t result;
|
||||
|
||||
/* note that we're the primary accelerant (accelerantIsClone is global) */
|
||||
accelerantIsClone = 0;
|
||||
|
||||
/* do the initialization common to both the primary and the clones */
|
||||
result = init_common(the_fd);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error0;
|
||||
|
||||
/*
|
||||
If there is a possiblity that the kernel driver will recognize a card that
|
||||
the accelerant can't support, you should check for that here. Perhaps some
|
||||
odd memory configuration or some such.
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a good place to go and initialize your card. The details are so
|
||||
device specific, we're not even going to pretend to provide you with sample
|
||||
code. If this fails, we'll have to bail out, cleaning up the resources
|
||||
we've already allocated.
|
||||
*/
|
||||
/* call the device specific init code */
|
||||
if (si->mem_size != Get_Card_Mem_Size()){
|
||||
result = B_ERROR;
|
||||
}
|
||||
|
||||
mach64InitAperture();
|
||||
mach64ResetEngine();
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* Disable all interrupts */
|
||||
outw(CRTC_INT_CNTL, 0);
|
||||
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* bail out if it failed */
|
||||
if (result != B_OK) goto error1;
|
||||
|
||||
/*
|
||||
Now would be a good time to figure out what video modes your card supports.
|
||||
We'll place the list of modes in another shared area so all of the copies
|
||||
of the driver can see them. The primary copy of the accelerant (ie the one
|
||||
initialized with this routine) will own the "one true copy" of the list.
|
||||
Everybody else get's a read-only clone.
|
||||
*/
|
||||
|
||||
result = create_mode_list();
|
||||
if (result != B_OK) goto error2;
|
||||
|
||||
/*
|
||||
Initialize the frame buffer and cursor pointers. Most newer video cards
|
||||
have integrated the DAC into the graphics engine, and so the cursor shape
|
||||
is stored in the frame buffer RAM. Also, newer cards tend not to have as
|
||||
many restrictions about the placement of the start of the frame buffer in
|
||||
frame buffer RAM. If you're supporting an older card with frame buffer
|
||||
positioning restrictions, or one without an integrated DAC, you'll have to
|
||||
change this accordingly.
|
||||
*/
|
||||
|
||||
/*
|
||||
Put the cursor at the start of the frame buffer. The typical 64x64 4 color
|
||||
(black, white, transparent, inverse) takes up 1024 bytes of RAM.
|
||||
*/
|
||||
si->cursor.data = (uint8 *)si->framebuffer;
|
||||
|
||||
/* Initialize cursor as transparent */
|
||||
memset(si->cursor.data, 0xaa, 1024);
|
||||
|
||||
/* Initialize the rest of the cursor information while we're here */
|
||||
si->cursor.width = 0;
|
||||
si->cursor.height = 0;
|
||||
si->cursor.hot_x = 0;
|
||||
si->cursor.hot_y = 0;
|
||||
si->cursor.x = 0;
|
||||
si->cursor.y = 0;
|
||||
|
||||
/* Tell the hardware all the cursor info */
|
||||
|
||||
outw(CUR_OFFSET, 0x00000000); /* Where it is in memory */
|
||||
outw(CUR_HORZ_VERT_POSN, 0x00000000); /* Position in screen */
|
||||
outw(CUR_HORZ_VERT_OFF, 0x00000000); /* Hot x,y */
|
||||
|
||||
/*
|
||||
Put the frame buffer immediately following the cursor data. We store this
|
||||
info in a frame_buffer_config structure to make it convienient to return
|
||||
to the app_server later.
|
||||
*/
|
||||
si->fbc.frame_buffer = (void *)(((char *)si->framebuffer) + 1024);
|
||||
si->fbc.frame_buffer_dma = (void *)(((char *)si->framebuffer_pci) + 1024);
|
||||
|
||||
/* init the shared semaphore */
|
||||
INIT_BEN(si->engine.lock);
|
||||
/* initialize the engine synchronization variables */
|
||||
|
||||
/* count of issued parameters or commands */
|
||||
si->engine.last_idle = si->engine.count = 0;
|
||||
|
||||
/* bail out if something failed */
|
||||
if (result != B_OK) goto error3;
|
||||
|
||||
/* set the cursor colors. You may or may not have to do this, depending
|
||||
on the device. */
|
||||
set_cursor_colors();
|
||||
|
||||
/* ensure cursor state */
|
||||
SHOW_CURSOR(false);
|
||||
/* a winner! */
|
||||
result = B_OK;
|
||||
goto error0;
|
||||
|
||||
error3:
|
||||
/* free up the benaphore */
|
||||
DELETE_BEN(si->engine.lock);
|
||||
|
||||
error2:
|
||||
/*
|
||||
Clean up any resources allocated in your device specific initialization
|
||||
code.
|
||||
*/
|
||||
|
||||
error1:
|
||||
/*
|
||||
Initialization failed after init_common() succeeded, so we need to clean
|
||||
up before quiting.
|
||||
*/
|
||||
uninit_common();
|
||||
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the number of bytes required to hold the information required
|
||||
to clone the device.
|
||||
*/
|
||||
ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
|
||||
/*
|
||||
Since we're passing the name of the device as the only required
|
||||
info, return the size of the name buffer
|
||||
*/
|
||||
return MAX_ATIMACH64_DEVICE_NAME_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return the info required to clone the device. void *data points to
|
||||
a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
|
||||
*/
|
||||
void GET_ACCELERANT_CLONE_INFO(void *data) {
|
||||
atimach64_device_name dn;
|
||||
status_t result;
|
||||
|
||||
/* call the kernel driver to get the device name */
|
||||
dn.magic = ATIMACH64_PRIVATE_DATA_MAGIC;
|
||||
/* store the returned info directly into the passed buffer */
|
||||
dn.name = (char *)data;
|
||||
result = ioctl(fd, ATIMACH64_DEVICE_NAME, &dn, sizeof(dn));
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize a copy of the accelerant as a clone. void *data points to
|
||||
a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
|
||||
*/
|
||||
status_t CLONE_ACCELERANT(void *data) {
|
||||
status_t result;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
/* the data is the device name */
|
||||
strcpy(path, "/dev");
|
||||
strcat(path, (const char *)data);
|
||||
/* open the device, the permissions aren't important */
|
||||
fd = open(path, B_READ_WRITE);
|
||||
if (fd < 0) {
|
||||
result = fd;
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* note that we're a clone accelerant */
|
||||
accelerantIsClone = 1;
|
||||
|
||||
/* call the shared initialization code */
|
||||
result = init_common(fd);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error1;
|
||||
|
||||
/* get shared area for display modes */
|
||||
result = atimach64_mode_list_area = clone_area(
|
||||
"ATIMACH64 cloned display_modes",
|
||||
(void **)&atimach64_mode_list,
|
||||
B_ANY_ADDRESS,
|
||||
B_READ_AREA,
|
||||
si->mode_area
|
||||
);
|
||||
if (result < B_OK) goto error2;
|
||||
|
||||
/* all done */
|
||||
result = B_OK;
|
||||
goto error0;
|
||||
|
||||
error2:
|
||||
/* free up the areas we cloned */
|
||||
uninit_common();
|
||||
error1:
|
||||
/* close the device we opened */
|
||||
close(fd);
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
void UNINIT_ACCELERANT(void) {
|
||||
/* free our mode list area */
|
||||
delete_area(atimach64_mode_list_area);
|
||||
/* paranoia */
|
||||
atimach64_mode_list = 0;
|
||||
/* release our cloned data */
|
||||
uninit_common();
|
||||
/* close the file handle ONLY if we're the clone */
|
||||
if (accelerantIsClone) close(fd);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
SubDir OBOS_TOP src add-ons accelerants atimach64 ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics atimach64 ] ;
|
||||
|
||||
Addon atimach64.accelerant : accelerants :
|
||||
Acceleration.c
|
||||
Cursor.c
|
||||
EngineManagment.c
|
||||
GetAccelerantHook.c
|
||||
GlobalData.c
|
||||
GetModeInfo.c
|
||||
InitAccelerant.c
|
||||
Mach64.c
|
||||
Mach64fifo.c
|
||||
ProposeDisplayMode.c
|
||||
SetDisplayMode.c
|
||||
;
|
||||
|
||||
Depends atimach64.accelerant : atimach64.driver ;
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
/* All this code has been reversed engineered from Xfree86 Project :-)
|
||||
|
||||
Copyright 1999 by
|
||||
|
||||
Rene MacKinney <[email protected]>
|
||||
|
||||
7.May.99
|
||||
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/mach64/mach64.c,v 3.62.2.15 19
|
||||
98/10/18 20:42:04 hohndel Exp $ */
|
||||
/*
|
||||
* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
|
||||
* Copyright 1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Car
|
||||
olina.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Thomas Roell not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Thomas Roell makes no representations
|
||||
* about the suitability of this software for any purpose. It is provided
|
||||
* "as is" without express or implied warranty.
|
||||
*
|
||||
* THOMAS ROELL, KEVIN E. MARTIN, AND RICKARD E. FAITH DISCLAIM ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS
|
||||
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Thomas Roell, [email protected]
|
||||
*
|
||||
* Rewritten for the 8514/A by Kevin E. Martin ([email protected])
|
||||
* Modified for the Mach-8 by Rickard E. Faith ([email protected])
|
||||
* Rewritten for the Mach32 by Kevin E. Martin ([email protected])
|
||||
* Rewritten for the Mach64 by Kevin E. Martin ([email protected])
|
||||
* Support for the Mach64 CT added by David Dawes ([email protected])
|
||||
*
|
||||
*/
|
||||
/* $XConsortium: mach64.c /main/34 1996/10/28 04:46:47 kaleb $ */
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "Mach64fifo.h"
|
||||
#include "Mach64.h"
|
||||
|
||||
|
||||
/*
|
||||
* mach64FIFOdepth --
|
||||
* Calculates the correct FIFO depth for the Mach64 depending on the
|
||||
* color depth and clock selected.
|
||||
*/
|
||||
int mach64FIFOdepth(cdepth, clock, width)
|
||||
int cdepth;
|
||||
int clock;
|
||||
int width;
|
||||
{
|
||||
int fifo_depth;
|
||||
|
||||
if (si->device_id == MACH64_VT_ID) {
|
||||
if (si->revision == 0x48) { /* VTA4 */
|
||||
fifo_depth = mach64FIFOdepthVTA4(cdepth, clock, width);
|
||||
} else { /* VTA3 */
|
||||
fifo_depth = mach64FIFOdepthVTA3(cdepth, clock, width);
|
||||
}
|
||||
} else if (si->device_id == MACH64_GT_ID) {
|
||||
fifo_depth = mach64FIFOdepthGT(cdepth, clock, width);
|
||||
} else if (si->device_id == MACH64_CT_ID && si->revision == 0x0a) {
|
||||
/* CT-D has a larger FIFO and thus requires special code */
|
||||
fifo_depth = mach64FIFOdepthCTD(cdepth, clock, width);
|
||||
} else if (si->device_id == MACH64_CT_ID ||
|
||||
si->device_id == MACH64_ET_ID) {
|
||||
fifo_depth = mach64FIFOdepthCT(cdepth, clock, width);
|
||||
} else {
|
||||
fifo_depth = mach64FIFOdepthDefault(cdepth, clock, width);
|
||||
}
|
||||
|
||||
return(fifo_depth);
|
||||
}
|
||||
|
||||
/*
|
||||
* mach64ProgramClkMach64CT --
|
||||
*
|
||||
*/
|
||||
void mach64ProgramClkMach64CT(clkCntl, MHz100)
|
||||
int clkCntl;
|
||||
int MHz100;
|
||||
{
|
||||
char old_crtc_ext_disp;
|
||||
#ifdef DEBUG
|
||||
extern void mach64PrintCTPLL();
|
||||
#endif
|
||||
int M, N, P, R;
|
||||
float Q;
|
||||
int postDiv;
|
||||
int mhz100 = MHz100;
|
||||
unsigned char tmp1, tmp2;
|
||||
int ext_div = 0;
|
||||
float current_dot_clock;
|
||||
|
||||
old_crtc_ext_disp = inb(CRTC_GEN_CNTL+3);
|
||||
outb(CRTC_GEN_CNTL+3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24));
|
||||
|
||||
M = si->RefDivider;
|
||||
R = si->RefFreq;
|
||||
|
||||
if (clkCntl > 3) clkCntl = 3;
|
||||
|
||||
if (mhz100 < si->MinFreq) mhz100 = si->MinFreq;
|
||||
if (mhz100 > si->MaxFreq) mhz100 = si->MaxFreq;
|
||||
|
||||
Q = (mhz100 * M)/(2.0 * R);
|
||||
|
||||
if (false) { /* mach64HasDSP) { */
|
||||
if (Q > 255) {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q > 255\n");*/
|
||||
Q = 255;
|
||||
P = 0;
|
||||
postDiv = 1;
|
||||
} else if (Q > 127.5) {
|
||||
P = 0;
|
||||
postDiv = 1;
|
||||
} else if (Q > 85) {
|
||||
P = 1;
|
||||
postDiv = 2;
|
||||
} else if (Q > 63.75) {
|
||||
P = 0;
|
||||
postDiv = 3;
|
||||
ext_div = 1;
|
||||
} else if (Q > 42.5) {
|
||||
P = 2;
|
||||
postDiv = 4;
|
||||
} else if (Q > 31.875) {
|
||||
P = 2;
|
||||
postDiv = 6;
|
||||
ext_div = 1;
|
||||
} else if (Q > 21.25) {
|
||||
P = 3;
|
||||
postDiv = 8;
|
||||
} else if (Q >= 10.6666666667) {
|
||||
P = 3;
|
||||
postDiv = 12;
|
||||
ext_div = 1;
|
||||
} else {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q < 10.66666667\n");*/
|
||||
P = 3;
|
||||
postDiv = 12;
|
||||
ext_div = 1;
|
||||
}
|
||||
} else {
|
||||
if (Q > 255) {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q > 255\n");*/
|
||||
Q = 255;
|
||||
P = 0;
|
||||
}
|
||||
else if (Q > 127.5)
|
||||
P = 0;
|
||||
else if (Q > 63.75)
|
||||
P = 1;
|
||||
else if (Q > 31.875)
|
||||
P = 2;
|
||||
else if (Q >= 16)
|
||||
P = 3;
|
||||
else {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q < 16\n");*/
|
||||
P = 3;
|
||||
}
|
||||
postDiv = 1 << P;
|
||||
}
|
||||
N = (int)(Q * postDiv + 0.5);
|
||||
|
||||
current_dot_clock = (2.0 * R * N)/(M * postDiv);
|
||||
|
||||
#ifdef DEBUG_HARNESS
|
||||
printf("Q = %f N = %d P = %d, postDiv = %d R = %d M = %d\n", Q, N, P, postDiv, R, M);
|
||||
printf("New freq: %.2f\n", (double)((2 * R * N)/(M * postDiv)) / 100.0);
|
||||
#endif
|
||||
|
||||
outb(CLOCK_CNTL + 1, PLL_VCLK_CNTL << 2);
|
||||
#ifdef DEBUG_HARNESS
|
||||
printf("CLOCK_CNTL + 1 = 0x%08x\n",PLL_VCLK_CNTL << 2);
|
||||
#endif
|
||||
tmp1 = inb(CLOCK_CNTL + 2);
|
||||
outb(CLOCK_CNTL + 1, (PLL_VCLK_CNTL << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2, tmp1 | 0x04);
|
||||
outb(CLOCK_CNTL + 1, VCLK_POST_DIV << 2);
|
||||
tmp2 = inb(CLOCK_CNTL + 2);
|
||||
outb(CLOCK_CNTL + 1, ((VCLK0_FB_DIV + clkCntl) << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2, N);
|
||||
outb(CLOCK_CNTL + 1, (VCLK_POST_DIV << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2,
|
||||
(tmp2 & ~(0x03 << (2 * clkCntl))) | (P << (2 * clkCntl)));
|
||||
outb(CLOCK_CNTL + 1, (PLL_VCLK_CNTL << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2, tmp1 & ~0x04);
|
||||
|
||||
if (false) { /* mach64HasDSP) { */
|
||||
outb(CLOCK_CNTL + 1, PLL_XCLK_CNTL << 2);
|
||||
tmp1 = inb(CLOCK_CNTL + 2);
|
||||
outb(CLOCK_CNTL + 1, (PLL_XCLK_CNTL << 2) | PLL_WR_EN);
|
||||
if (ext_div)
|
||||
outb(CLOCK_CNTL + 2, tmp1 | (1 << (clkCntl + 4)));
|
||||
else
|
||||
outb(CLOCK_CNTL + 2, tmp1 & ~(1 << (clkCntl + 4)));
|
||||
}
|
||||
|
||||
snooze(5000);
|
||||
|
||||
(void)inb(DAC_REGS); /* Clear DAC Counter */
|
||||
outb(CRTC_GEN_CNTL+3, old_crtc_ext_disp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* CalcCRTCRegs --
|
||||
* Calculate appropiate values for CRTC Registers
|
||||
*/
|
||||
void
|
||||
CalcCRTCRegs(crtcRegs, mode)
|
||||
mach64CRTCRegPtr crtcRegs;
|
||||
display_mode *mode;
|
||||
{
|
||||
int h_pol = (mode->timing.flags & B_POSITIVE_HSYNC) ? 1 : 0;
|
||||
int v_pol = (mode->timing.flags & B_POSITIVE_VSYNC) ? 1 : 0;
|
||||
|
||||
/* Register CRTC_H_TOTAL_DISP
|
||||
bits 23-16 Horizontal total visible in character clocks (8 pixel units)
|
||||
bits 7-0 Horizontal display end in character clocks
|
||||
*/
|
||||
crtcRegs->h_total_disp = (((mode->timing.h_display >> 3) - 1) << 16) |
|
||||
((mode->timing.h_total >> 3) - 1);
|
||||
|
||||
/* Register CRTC_H_SYNC_STRT_WID
|
||||
bits 21 Horizontal sync polarity
|
||||
bits 20-16 Horizontal sync width in character clocks
|
||||
bits 10-8 Horizontal sync start delay in pixels
|
||||
bits 7-0 Horizontal sync start in character clocks
|
||||
*/
|
||||
crtcRegs->h_sync_strt_wid = h_pol << 21 |
|
||||
(((mode->timing.h_sync_end - mode->timing.h_sync_start) >> 3) << 16) |
|
||||
/* ((mode->timing.h_sync_start % 8) << 8) |*/
|
||||
((mode->timing.h_sync_start >> 3) - 1);
|
||||
|
||||
/* Register CRTC_V_TOTAL_DISP
|
||||
bits 23-16 Vertical total visible in lines
|
||||
bits 7-0 Vertical display end in lines
|
||||
*/
|
||||
crtcRegs->v_total_disp = ((mode->timing.v_display - 1) << 16) |
|
||||
(mode->timing.v_total - 1);
|
||||
|
||||
/* Register CRTC_V_SYNC_STRT_WID
|
||||
bits 21 Vertical sync polarity
|
||||
bits 20-16 Vertical sync width in lines
|
||||
bits 10-0 Vertical sync start in lines
|
||||
*/
|
||||
crtcRegs->v_sync_strt_wid = v_pol << 21 |
|
||||
((mode->timing.v_sync_end - mode->timing.v_sync_start) << 16) |
|
||||
(mode->timing.v_sync_start - 1);
|
||||
|
||||
switch (mode->space & 0x0fff) {
|
||||
case B_CMAP8:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_8BPP;
|
||||
break;
|
||||
case B_RGB15:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_15BPP;
|
||||
break;
|
||||
case B_RGB16:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_16BPP;
|
||||
break;
|
||||
case B_RGB32:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_32BPP;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
crtcRegs->crtc_gen_cntl = 0;
|
||||
if (mode->timing.flags & B_TIMING_INTERLACED)
|
||||
crtcRegs->crtc_gen_cntl |= CRTC_INTERLACE_EN;
|
||||
|
||||
|
||||
crtcRegs->clock_cntl = 0x03; /* Hack */
|
||||
crtcRegs->dot_clock = mode->timing.pixel_clock / 10;
|
||||
|
||||
crtcRegs->fifo_v1 = mach64FIFOdepth(crtcRegs->color_depth,
|
||||
crtcRegs->dot_clock, mode->timing.h_display);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* SetCRTCRegs
|
||||
* Write values to the CRTC Registers */
|
||||
void
|
||||
SetCRTCRegs(crtcRegs, mode)
|
||||
mach64CRTCRegPtr crtcRegs;
|
||||
display_mode *mode;
|
||||
{
|
||||
int crtcGenCntl;
|
||||
uint32 offset;
|
||||
|
||||
WaitIdleEmpty();
|
||||
crtcGenCntl = inw(CRTC_GEN_CNTL);
|
||||
outw(CRTC_GEN_CNTL, crtcGenCntl & ~(CRTC_EXT_EN | CRTC_LOCK_REGS));
|
||||
|
||||
/* Program the clock chip */
|
||||
mach64ProgramClkMach64CT(0x03, crtcRegs->dot_clock);
|
||||
|
||||
|
||||
/* Horizontal CRTC registers */
|
||||
outw(CRTC_H_TOTAL_DISP, crtcRegs->h_total_disp);
|
||||
outw(CRTC_H_SYNC_STRT_WID, crtcRegs->h_sync_strt_wid);
|
||||
|
||||
/* Vertical CRTC registers */
|
||||
outw(CRTC_V_TOTAL_DISP, crtcRegs->v_total_disp);
|
||||
outw(CRTC_V_SYNC_STRT_WID, crtcRegs->v_sync_strt_wid);
|
||||
|
||||
/* Clock select register */
|
||||
outw(CLOCK_CNTL, crtcRegs->clock_cntl | CLOCK_STROBE);
|
||||
|
||||
/* Zero overscan register to insure proper color */
|
||||
/* outw(OVR_CLR, 0);
|
||||
outw(OVR_WID_LEFT_RIGHT, 0);
|
||||
outw(OVR_WID_TOP_BOTTOM, 0);
|
||||
*/
|
||||
/* Set the offset and width of the display
|
||||
We could just use the offset value we already know (1024) but this
|
||||
will deal with any changes
|
||||
*/
|
||||
offset = (si->fbc.frame_buffer - si->framebuffer) >> 3;
|
||||
|
||||
outw(CRTC_OFF_PITCH, ((mode->virtual_width >> 3) << 22) | offset);
|
||||
outw(DST_OFF_PITCH, ((mode->virtual_width >> 3) << 22) | offset);
|
||||
outw(SRC_OFF_PITCH, ((mode->virtual_width >> 3) << 22) | offset);
|
||||
|
||||
|
||||
|
||||
/* Display control register -- this one turns on the display */
|
||||
|
||||
outw(CRTC_GEN_CNTL,
|
||||
(crtcGenCntl & 0xff0000ff &
|
||||
~(CRTC_PIX_BY_2_EN | CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN |
|
||||
CRTC_HSYNC_DIS | CRTC_VSYNC_DIS)) |
|
||||
(crtcRegs->crtc_gen_cntl & ~CRTC_PIX_BY_2_EN) |
|
||||
crtcRegs->color_depth |
|
||||
(((crtcRegs->fifo_v1 & 0x0f) << 16) |
|
||||
CRTC_EXT_DISP_EN | CRTC_EXT_EN));
|
||||
|
||||
/* printf(" crtcGenCntl 0x%08x\n", (crtcGenCntl & 0xff0000ff &
|
||||
~(CRTC_PIX_BY_2_EN | CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN |
|
||||
CRTC_HSYNC_DIS | CRTC_VSYNC_DIS)) |
|
||||
(crtcRegs->crtc_gen_cntl & ~CRTC_PIX_BY_2_EN) |
|
||||
crtcRegs->color_depth |
|
||||
(((crtcRegs->fifo_v1 & 0x0f) << 16) |
|
||||
CRTC_EXT_DISP_EN | CRTC_EXT_EN));*/
|
||||
|
||||
|
||||
/* Set the DAC for the currect mode */
|
||||
/* mach64SetRamdac(crtcRegs->color_depth, TRUE, crtcRegs->dot_clock);
|
||||
*/
|
||||
WaitIdleEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* mach64InitAperture --
|
||||
* Initialize the aperture for the Mach64.
|
||||
*/
|
||||
void mach64InitAperture()
|
||||
{
|
||||
ulong apaddr = (ulong) si->framebuffer_pci;
|
||||
|
||||
outw(CONFIG_CNTL, ((apaddr/(4*1024*1024)) << 4) | 2);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* mach64ResetEngine --
|
||||
* Resets the GUI engine and clears any FIFO errors.
|
||||
*/
|
||||
void mach64ResetEngine()
|
||||
{
|
||||
int temp;
|
||||
|
||||
/* Ensure engine is not locked up by clearing any FIFO errors */
|
||||
outw(BUS_CNTL, inw(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
|
||||
|
||||
/* Reset engine */
|
||||
temp = inw(GEN_TEST_CNTL);
|
||||
outw(GEN_TEST_CNTL, temp & ~GUI_ENGINE_ENABLE);
|
||||
|
||||
outw(GEN_TEST_CNTL, temp | GUI_ENGINE_ENABLE);
|
||||
|
||||
WaitIdleEmpty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
InitRAMDAC(uint32 colorDepth, uint32 flags)
|
||||
{
|
||||
int count;
|
||||
uint8 val;
|
||||
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* Initialize Acceleration Mode */
|
||||
|
||||
outb(CRTC_GEN_CNTL+3, ((CRTC_EXT_DISP_EN | CRTC_EXT_EN) >> 24));
|
||||
|
||||
switch(colorDepth){
|
||||
case 8:
|
||||
val = inb(DAC_CNTL+1);
|
||||
if (flags & B_8_BIT_DAC)
|
||||
outb(DAC_CNTL + 1, val | 0x01);
|
||||
else
|
||||
outb(DAC_CNTL + 1, val & ~0x01);
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
val = inb(DAC_CNTL + 1);
|
||||
outb(DAC_CNTL + 1, val | 0x01);
|
||||
outb(DAC_CNTL + 2, 0xff);
|
||||
outb(DAC_REGS, 0x00);
|
||||
for(count = 0; count < 256; count ++) {
|
||||
outb(DAC_REGS+1, count);
|
||||
outb(DAC_REGS+1, count);
|
||||
outb(DAC_REGS+1, count);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
extern void mach64InitAperture();
|
||||
extern void mach64ResetEngine();
|
||||
extern void CalcCRTCRegs(mach64CRTCRegPtr, display_mode *);
|
||||
extern void SetCRTCRegs(mach64CRTCRegPtr, display_mode *);
|
||||
void InitRAMDAC(uint32, uint32);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
/* $XConsortium: mach64fifo.h /main/1 1996/10/27 18:06:29 kaleb $ */
|
||||
/*
|
||||
* Copyright 1996 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of Kevin
|
||||
* E. Martin not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Kevin E. Martin makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* KEVIN E. MARTIN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/mach64/mach64fifo.h,v 3.1 1996/12/27 06:55:52 dawes Exp $ */
|
||||
|
||||
extern int mach64FIFOdepthDefault(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthVTA3(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthVTA4(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthGT(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthCT(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthCTD(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
@@ -0,0 +1,399 @@
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
||||
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
|
||||
#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS)
|
||||
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
|
||||
|
||||
static const display_mode mode_list[] = {
|
||||
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
|
||||
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
|
||||
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
|
||||
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
|
||||
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
|
||||
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
|
||||
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
|
||||
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
|
||||
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
|
||||
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */
|
||||
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
|
||||
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
|
||||
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
|
||||
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
|
||||
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
|
||||
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
|
||||
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
|
||||
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
|
||||
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
|
||||
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
|
||||
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
|
||||
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
|
||||
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
|
||||
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
|
||||
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
|
||||
};
|
||||
|
||||
|
||||
/* create a mask of one "bits" bits wide */
|
||||
#define MASKFROMWIDTH(bits) ((1 << bits) - 1)
|
||||
|
||||
/*
|
||||
Validate a target display mode is both
|
||||
a) a valid display mode for this device and
|
||||
b) falls between the contraints imposed by "low" and "high"
|
||||
|
||||
If the mode is not (or cannot) be made valid for this device, return B_ERROR.
|
||||
If a valid mode can be constructed, but it does not fall within the limits,
|
||||
return B_BAD_VALUE.
|
||||
If the mode is both valid AND falls within the limits, return B_OK.
|
||||
*/
|
||||
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) {
|
||||
|
||||
const uint16 h_display_bits = MASKFROMWIDTH(8);
|
||||
const uint16 h_sync_bits = MASKFROMWIDTH(5);
|
||||
const uint16 h_total_bits = MASKFROMWIDTH(9);
|
||||
const uint16 v_display_bits = MASKFROMWIDTH(11);
|
||||
const uint16 v_sync_bits = MASKFROMWIDTH(5);
|
||||
const uint16 v_total_bits = MASKFROMWIDTH(11);
|
||||
|
||||
int i, color_depth;
|
||||
|
||||
int mach64CDepths [] = { -1, 4, 8, 15, 16, 24, 32, -1 };
|
||||
|
||||
status_t
|
||||
result = B_ERROR;
|
||||
uint32
|
||||
row_bytes,
|
||||
limit_clock;
|
||||
double
|
||||
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / ((double)target->timing.h_total * (double)target->timing.v_total);
|
||||
bool
|
||||
want_same_width = target->timing.h_display == target->virtual_width,
|
||||
want_same_height = target->timing.v_display == target->virtual_height;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
Different devices provide different levels of control over the various CRTC values.
|
||||
This code should be used as a *GUIDELINE ONLY*. The device you're controling may
|
||||
have very different constraints, and the code below may be insufficient to insure
|
||||
that a particular display_mode is valid for your device. You would do well to
|
||||
spend quite a bit of time ensuring that you understand the limitations of your
|
||||
device, as setting these values incorrectly can create a display_mode that could
|
||||
turn your monitor into a useless slag of molten components, burn up your card,
|
||||
lock up the PCI bus, cause partialy or multiply repeating display images, or
|
||||
otherwise look just plain wierd. Honest.
|
||||
*/
|
||||
/*
|
||||
NOTE:
|
||||
This code doesn't explicitly support interlaced video modes.
|
||||
*/
|
||||
|
||||
/* validate horizontal timings */
|
||||
{
|
||||
/* for most devices, horizontal parameters must be multiples of 8 */
|
||||
uint16 h_display = target->timing.h_display >> 3;
|
||||
uint16 h_sync_start = target->timing.h_sync_start >> 3;
|
||||
uint16 h_sync_end = target->timing.h_sync_end >> 3;
|
||||
uint16 h_total = target->timing.h_total >> 3;
|
||||
|
||||
/* ensure reasonable minium display and sequential order of parms */
|
||||
|
||||
if (h_display < (320 >> 3)) h_display = 320 >> 3;
|
||||
if (h_display > (2048 >> 3)) h_display = 2048 >> 3;
|
||||
if (h_sync_start < (h_display + 2)) h_sync_start = h_display + 2;
|
||||
if (h_sync_end < (h_sync_start + 3)) h_sync_end = h_sync_start + 3; /*(0x001f >> 2);*/
|
||||
|
||||
if (h_total < (h_sync_end + 1)) h_total = h_sync_end + 1;
|
||||
/* adjust for register limitations: */
|
||||
/* h_total is 9 bits */
|
||||
|
||||
if (h_total > h_total_bits) h_total = h_total_bits;
|
||||
/* h_display is 8 bits - handled above */
|
||||
/* h_sync_start is 9 bits */
|
||||
/* h_sync_width is 5 bits */
|
||||
if ((h_sync_end - h_sync_start) > h_sync_bits) h_sync_end = h_sync_start + h_sync_bits;
|
||||
|
||||
/* shift back to the full width values */
|
||||
|
||||
target->timing.h_display = h_display << 3;
|
||||
target->timing.h_sync_start = h_sync_start << 3;
|
||||
target->timing.h_sync_end = h_sync_end << 3;
|
||||
target->timing.h_total = h_total << 3;
|
||||
}
|
||||
|
||||
/* did we fall out of one of the limits? */
|
||||
|
||||
if (
|
||||
(target->timing.h_display < low->timing.h_display) ||
|
||||
(target->timing.h_display > high->timing.h_display) ||
|
||||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
|
||||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
|
||||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
|
||||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
|
||||
(target->timing.h_total < low->timing.h_total) ||
|
||||
(target->timing.h_total > high->timing.h_total)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
|
||||
/* validate vertical timings */
|
||||
|
||||
{
|
||||
uint16 v_display = target->timing.v_display;
|
||||
uint16 v_sync_start = target->timing.v_sync_start;
|
||||
uint16 v_sync_end = target->timing.v_sync_end;
|
||||
uint16 v_total = target->timing.v_total;
|
||||
|
||||
/* ensure reasonable minium display and sequential order of parms */
|
||||
/* v_display is 11 bits */
|
||||
/* v_total is 11 bits */
|
||||
/* v_sync_start is 11 bits */
|
||||
/* v_sync_width is 5 bits */
|
||||
|
||||
if (v_display < 200) v_display = 200;
|
||||
if (v_display > (v_display_bits - 5)) v_display = (v_display_bits - 5); /* leave room for the sync pulse */
|
||||
if (v_sync_start < (v_display + 1)) v_sync_start = v_display + 1;
|
||||
if (v_sync_end < v_sync_start) v_sync_end = v_sync_start + 3;
|
||||
if (v_total < (v_sync_end + 1)) v_total = v_sync_end + 1;
|
||||
/* adjust for register limitations */
|
||||
|
||||
if ((v_sync_end - v_sync_start) > v_sync_bits) v_sync_end = v_sync_start + v_sync_bits;
|
||||
target->timing.v_display = v_display;
|
||||
target->timing.v_sync_start = v_sync_start;
|
||||
target->timing.v_sync_end = v_sync_end;
|
||||
target->timing.v_total = v_total;
|
||||
}
|
||||
|
||||
/* did we fall out of one of the limits? */
|
||||
|
||||
if (
|
||||
(target->timing.v_display < low->timing.v_display) ||
|
||||
(target->timing.v_display > high->timing.v_display) ||
|
||||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
|
||||
(target->timing.v_sync_start > high->timing.h_sync_start) ||
|
||||
(target->timing.v_sync_end < low->timing.v_sync_end) ||
|
||||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
|
||||
(target->timing.v_total < low->timing.v_total) ||
|
||||
(target->timing.v_total > high->timing.v_total)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
/* adjust pixel clock for DAC limits and target refresh rate */
|
||||
/*
|
||||
We're re-calcuating the pixel_clock here because we might have
|
||||
changed the h/v totals above. If we didn't change anything
|
||||
the calculation is wasted, but it's no big deal.
|
||||
*/
|
||||
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0 + .5;
|
||||
|
||||
/*
|
||||
Select the maximum pixel clock based on the color space. Your
|
||||
device may have other constraints. In this sample driver, we
|
||||
calculated the maximum pixel clock for this device in the
|
||||
initialization code.
|
||||
This is also a convienient place to determine the number of bytes
|
||||
per pixel for a later display pitch calculation.
|
||||
*/
|
||||
switch (target->space & 0x0fff) {
|
||||
case B_CMAP8:
|
||||
limit_clock = si->pix_clk_max8;
|
||||
row_bytes = 1;
|
||||
color_depth = 8;
|
||||
break;
|
||||
case B_RGB15:
|
||||
case B_RGB16:
|
||||
limit_clock = si->pix_clk_max16;
|
||||
row_bytes = 2;
|
||||
color_depth = 16;
|
||||
break;
|
||||
case B_RGB32:
|
||||
limit_clock = si->pix_clk_max32;
|
||||
row_bytes = 4;
|
||||
color_depth = 32;
|
||||
break;
|
||||
default:
|
||||
/* no amount of adjusting will fix not being able to support the pixel format */
|
||||
return B_ERROR;
|
||||
}
|
||||
/* make sure we don't generate more pixel bandwidth than the device can handle */
|
||||
|
||||
if (target->timing.pixel_clock > limit_clock) target->timing.pixel_clock = limit_clock;
|
||||
/* we probably ought to check against too low of a pixel rate, but I'm lazy */
|
||||
|
||||
/* note if we fell outside the limits */
|
||||
if (
|
||||
(target->timing.pixel_clock < low->timing.pixel_clock) ||
|
||||
(target->timing.pixel_clock > high->timing.pixel_clock)
|
||||
) return B_ERROR;
|
||||
|
||||
/* validate display vs. virtual */
|
||||
|
||||
if ((target->timing.h_display > target->virtual_width) || want_same_width)
|
||||
target->virtual_width = target->timing.h_display;
|
||||
if ((target->timing.v_display > target->virtual_height) || want_same_height)
|
||||
target->virtual_height = target->timing.v_display;
|
||||
if (target->virtual_width > 2048)
|
||||
target->virtual_width = 2048;
|
||||
|
||||
/* adjust virtual width for engine limitations */
|
||||
|
||||
target->virtual_width = (target->virtual_width + 7) & ~7;
|
||||
if (
|
||||
(target->virtual_width < low->virtual_width) ||
|
||||
(target->virtual_width > high->virtual_width)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
/* calculate rowbytes after we've nailed the virtual width */
|
||||
|
||||
row_bytes *= target->virtual_width;
|
||||
|
||||
/* memory requirement for frame buffer */
|
||||
|
||||
if ((row_bytes * target->virtual_height) > si->mem_size)
|
||||
target->virtual_height = si->mem_size / row_bytes;
|
||||
|
||||
if (target->virtual_height > 2048)
|
||||
target->virtual_height = 2048;
|
||||
|
||||
|
||||
if (target->virtual_height < target->timing.v_display){
|
||||
/* not enough frame buffer memory for the mode */
|
||||
return B_ERROR;}
|
||||
else if (
|
||||
(target->virtual_height < low->virtual_height) ||
|
||||
(target->virtual_height > high->virtual_height)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
/*
|
||||
Bit Flag Encoding
|
||||
|
||||
The way the bit flags works is as follows:
|
||||
|
||||
low high meaning
|
||||
--- ---- -------
|
||||
0 0 Feature must NOT be enabled
|
||||
0 1 Feature MAY be enabled, prefered enabled
|
||||
1 0 Feature MAY be enabled, prefered disabled
|
||||
1 1 Feature MUST be enabled
|
||||
|
||||
*/
|
||||
/* MORE WORK REQUIRED HERE. Current drivers mostly ignore the flags */
|
||||
|
||||
/* Look to see if there if the mode is doable */
|
||||
if (result != B_BAD_VALUE)
|
||||
for(i = 0; si->Freq_Table[i].h_disp != 0; i++) {
|
||||
|
||||
if ((si->Freq_Table[i].h_disp << 3 >= target->timing.h_display) &&
|
||||
(si->Freq_Table[i].dacmask >= si->DAC_SubType) &&
|
||||
(si->Freq_Table[i].max_dot_clock >= (target->timing.pixel_clock / 1000.0)) &&
|
||||
(mach64CDepths[si->Freq_Table[i].color_depth & 0x07] >= color_depth)){
|
||||
result = B_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Return the number of modes this device will return from GET_MODE_LIST().
|
||||
*/
|
||||
uint32 ACCELERANT_MODE_COUNT(void) {
|
||||
/* return the number of 'built-in' display modes */
|
||||
return si->mode_count;
|
||||
}
|
||||
|
||||
/*
|
||||
Copy the list of guaranteed supported video modes to the location
|
||||
provided.
|
||||
*/
|
||||
status_t GET_MODE_LIST(display_mode *dm) {
|
||||
/* copy them to the buffer pointed at by *dm */
|
||||
memcpy(dm, atimach64_mode_list, si->mode_count * sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t get_first_mode(display_mode *dm) {
|
||||
/* copy first valid mode to the buffer pointed at by *dm */
|
||||
memcpy(dm, atimach64_mode_list, sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Create a list of display_modes to pass back to the caller.
|
||||
*/
|
||||
status_t create_mode_list(void) {
|
||||
size_t max_size;
|
||||
uint32
|
||||
i, j,
|
||||
pix_clk_range;
|
||||
const display_mode
|
||||
*src;
|
||||
display_mode
|
||||
*dst,
|
||||
low,
|
||||
high;
|
||||
|
||||
/*
|
||||
We prefer frame buffers to have the same endianness as the host CPU, but it's
|
||||
not required. You can even return both, although there isn't a way for the
|
||||
current Screen preferences panel to allow the user to choose which one to use.
|
||||
*/
|
||||
#if defined(__INTEL__)
|
||||
color_space spaces[4] = {B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE};
|
||||
#else
|
||||
color_space spaces[4] = {B_CMAP8, B_RGB15_BIG, B_RGB16_BIG, B_RGB32_BIG};
|
||||
#endif
|
||||
|
||||
/* printf(" Mode count %ld \n", MODE_COUNT);*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE */
|
||||
max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
|
||||
/* create an area to hold the info */
|
||||
si->mode_area = atimach64_mode_list_area =
|
||||
create_area("ATIMACH64 accelerant mode info", (void **)&atimach64_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||
if (atimach64_mode_list_area < B_OK) return atimach64_mode_list_area;
|
||||
|
||||
/* walk through our predefined list and see which modes fit this device */
|
||||
src = mode_list;
|
||||
dst = atimach64_mode_list;
|
||||
si->mode_count = 0;
|
||||
for (i = 0; i < MODE_COUNT; i++) {
|
||||
/* set ranges for acceptable values */
|
||||
low = high = *src;
|
||||
/* range is 6.25% of default clock: arbitrarily picked */
|
||||
|
||||
pix_clk_range = low.timing.pixel_clock >> 5;
|
||||
low.timing.pixel_clock -= pix_clk_range;
|
||||
high.timing.pixel_clock += pix_clk_range;
|
||||
/* some cards need wider virtual widths for certain modes */
|
||||
high.virtual_width = 2048;
|
||||
/* do it once for each depth we want to support */
|
||||
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) {
|
||||
/* set target values */
|
||||
*dst = *src;
|
||||
/* poke the specific space */
|
||||
dst->space = low.space = high.space = spaces[j];
|
||||
/* ask for a compatible mode */
|
||||
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
|
||||
/* count it, and move on to next mode */
|
||||
dst++;
|
||||
si->mode_count++;
|
||||
}
|
||||
}
|
||||
/* advance to next mode */
|
||||
src++;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "Mach64.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
|
||||
/*
|
||||
Enable/Disable interrupts. Just a wrapper around the
|
||||
ioctl() to the kernel driver.
|
||||
*/
|
||||
static void interrupt_enable(bool flag) {
|
||||
status_t result;
|
||||
atimach64_set_bool_state sbs;
|
||||
|
||||
/* set the magic number so the driver knows we're for real */
|
||||
sbs.magic = ATIMACH64_PRIVATE_DATA_MAGIC;
|
||||
sbs.do_it = flag;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, ATIMACH64_RUN_INTERRUPTS, &sbs, sizeof(sbs));
|
||||
}
|
||||
|
||||
/*
|
||||
Calculates the number of bits for a given color_space.
|
||||
Usefull for mode setup routines, etc.
|
||||
*/
|
||||
uint32 calcBitsPerPixel(uint32 cs) {
|
||||
uint32 bpp = 0;
|
||||
|
||||
switch (cs) {
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
bpp = 32; break;
|
||||
case B_RGB24_BIG:
|
||||
case B_RGB24_LITTLE:
|
||||
bpp = 24; break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
bpp = 16; break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
bpp = 15; break;
|
||||
case B_CMAP8:
|
||||
bpp = 8; break;
|
||||
}
|
||||
return bpp;
|
||||
}
|
||||
|
||||
/*
|
||||
The code to actually configure the display. Unfortunately, there's not much
|
||||
that can be provided in the way of sample code. If you're lucky, you're writing
|
||||
a driver for a device that has all (or at least most) of the bits for a particular
|
||||
configuration value in the same register, rather than spread out over the standard
|
||||
VGA registers + a zillion expansion bits. In any case, I've found that the way
|
||||
to simplify this routine is to do all of the error checking in PROPOSE_DISPLAY_MODE(),
|
||||
and just assume that the values I get here are acceptable.
|
||||
*/
|
||||
static void do_set_display_mode(display_mode *dm) {
|
||||
|
||||
mach64CRTCRegRec Regs;
|
||||
|
||||
|
||||
CalcCRTCRegs(&Regs, dm);
|
||||
|
||||
/* disable interrupts using the kernel driver */
|
||||
interrupt_enable(false);
|
||||
|
||||
SetCRTCRegs(&Regs, dm);
|
||||
|
||||
/* Initialize RAMDAC */
|
||||
InitRAMDAC(calcBitsPerPixel(dm->space), dm->flags);
|
||||
|
||||
/* enable interrupts using the kernel driver */
|
||||
interrupt_enable(true);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
The exported mode setting routine. First validate the mode, then call our
|
||||
private routine to hammer the registers.
|
||||
*/
|
||||
status_t SET_DISPLAY_MODE(display_mode *mode_to_set) {
|
||||
display_mode bounds, target;
|
||||
|
||||
/* ask for the specific mode */
|
||||
target = bounds = *mode_to_set;
|
||||
if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR)
|
||||
return B_ERROR;
|
||||
|
||||
do_set_display_mode(&target);
|
||||
|
||||
/* update shared info */
|
||||
target.h_display_start = 0;
|
||||
target.v_display_start = 0;
|
||||
si->dm = target;
|
||||
|
||||
/* calculate bytes per row ans set it */
|
||||
si->fbc.bytes_per_row = ((calcBitsPerPixel(target.space) + 1) / 8)
|
||||
*target.virtual_width;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Set which pixel of the virtual frame buffer will show up in the
|
||||
top left corner of the display device. Used for page-flipping
|
||||
games and virtual desktops.
|
||||
*/
|
||||
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
|
||||
int byte_offset;
|
||||
/*
|
||||
Many devices have limitations on the granularity of the horizontal offset.
|
||||
Make any checks for this here. A future revision of the driver API will
|
||||
add a hook to return the granularity for a given display mode.
|
||||
*/
|
||||
/* most cards can handle multiples of 8 */
|
||||
if (h_display_start & 0x07)
|
||||
return B_ERROR;
|
||||
/* do not run past end of display */
|
||||
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
|
||||
return B_ERROR;
|
||||
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
|
||||
return B_ERROR;
|
||||
|
||||
/* everybody remember where we parked... */
|
||||
si->dm.h_display_start = h_display_start;
|
||||
si->dm.v_display_start = v_display_start;
|
||||
|
||||
/* Calculate offset remebering to include the cursor area */
|
||||
byte_offset = (si->fbc.frame_buffer - si->framebuffer) >> 3;
|
||||
byte_offset += ((h_display_start + v_display_start*si->dm.virtual_width) *
|
||||
(calcBitsPerPixel(si->dm.space) / 8)) >> 3;
|
||||
|
||||
/* actually set the registers */
|
||||
if (~(si->dm.flags & B_HARDWARE_CURSOR))
|
||||
SHOW_CURSOR(false);
|
||||
|
||||
outw(CRTC_OFF_PITCH, (inw(CRTC_OFF_PITCH) & 0xfff00000) | byte_offset);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Set the indexed color palette.
|
||||
*/
|
||||
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
|
||||
|
||||
/*
|
||||
Some cards use the indexed color regisers in the DAC for gamma correction.
|
||||
If this is true with your device (and it probably is), you need to protect
|
||||
against setting these registers when not in an indexed mode.
|
||||
*/
|
||||
if (si->dm.space != B_CMAP8) return;
|
||||
|
||||
/*
|
||||
There isn't any need to keep a copy of the data being stored, as the app_server
|
||||
will set the colors each time it switches to an 8bpp mode, or takes ownership
|
||||
of an 8bpp mode after a GameKit app has used it.
|
||||
*/
|
||||
|
||||
/*
|
||||
You're on your own from here. Chances are your code will look something like
|
||||
what follows:
|
||||
*/
|
||||
/*
|
||||
Due to the nature of the SAMPLE card, we need to do bytewise writes
|
||||
to the dac regs. Stupid, but there you go. So, we do it like we're
|
||||
supposed to.
|
||||
*/
|
||||
|
||||
WaitQueue(1);
|
||||
|
||||
outb(DAC_REGS, first);
|
||||
|
||||
while (count--) {
|
||||
outb(DAC_REGS+1, *color_data++);
|
||||
outb(DAC_REGS+1, *color_data++);
|
||||
outb(DAC_REGS+1, *color_data++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* masks for DPMS control bits */
|
||||
enum {
|
||||
H_SYNC_OFF = 0x01,
|
||||
V_SYNC_OFF = 0x02,
|
||||
DISPLAY_OFF = 0x04,
|
||||
BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF
|
||||
};
|
||||
|
||||
/*
|
||||
Put the display into one of the Display Power Management modes.
|
||||
*/
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags) {
|
||||
uint32 LTemp;
|
||||
|
||||
/*
|
||||
The register containing the horizontal and vertical sync control bits
|
||||
usually contains other control bits, so do a read-modify-write.
|
||||
*/
|
||||
/* read bits */
|
||||
LTemp = inw(CRTC_GEN_CNTL);
|
||||
/* mask them */
|
||||
LTemp &= ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); /* clear all disable bits (including display disable) */
|
||||
|
||||
/* now pick one of the DPMS configurations */
|
||||
switch(dpms_flags) {
|
||||
case B_DPMS_ON: /* H: on, V: on */
|
||||
/* do nothing, bits already clear */
|
||||
/* usually, but it may be different for your device */
|
||||
break;
|
||||
case B_DPMS_STAND_BY: /* H: off, V: on, display off */
|
||||
LTemp |= CRTC_HSYNC_DIS;
|
||||
break;
|
||||
case B_DPMS_SUSPEND: /* H: on, V: off, display off */
|
||||
LTemp |= CRTC_VSYNC_DIS;
|
||||
break;
|
||||
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||
LTemp |= CRTC_HSYNC_DIS | CRTC_VSYNC_DIS;
|
||||
break;
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
/* write the bits */
|
||||
outw(CRTC_GEN_CNTL, LTemp);
|
||||
|
||||
snooze(10000);
|
||||
|
||||
/*
|
||||
NOTE: if you're driving a device with a backlight (like a digital LCD),
|
||||
you may want to turn off the backlight here when in a DPMS power saving mode.
|
||||
*/
|
||||
if (dpms_flags == B_DPMS_ON)
|
||||
/* turn on the back light */
|
||||
;
|
||||
else
|
||||
/* turn off the back light */
|
||||
;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Report device DPMS capabilities. Most newer cards can do it all.
|
||||
I've only seen one older card that can do a subset (ON and OFF).
|
||||
Very early cards may not be able to do this at all.
|
||||
*/
|
||||
uint32 DPMS_CAPABILITIES(void) {
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return the current DPMS mode.
|
||||
*/
|
||||
uint32 DPMS_MODE(void) {
|
||||
uint32 LTemp;
|
||||
uint32 mode = B_DPMS_ON;
|
||||
|
||||
/* read the control bits from the device */
|
||||
/* read the bits */
|
||||
LTemp = inw(CRTC_GEN_CNTL);
|
||||
|
||||
/* what mode is set? */
|
||||
switch (LTemp & (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS)) {
|
||||
case 0: /* H: on, V: on */
|
||||
mode = B_DPMS_ON;
|
||||
break;
|
||||
case CRTC_HSYNC_DIS: /* H: off, V: on */
|
||||
mode = B_DPMS_STAND_BY;
|
||||
break;
|
||||
case CRTC_VSYNC_DIS: /* H: on, V: off */
|
||||
mode = B_DPMS_SUSPEND;
|
||||
break;
|
||||
case (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS): /* H: off, V: off */
|
||||
mode = B_DPMS_OFF;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#if !defined(GENERIC_H)
|
||||
#define GENERIC_H
|
||||
|
||||
#include <Accelerant.h>
|
||||
|
||||
status_t INIT_ACCELERANT(int fd);
|
||||
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
|
||||
void GET_ACCELERANT_CLONE_INFO(void *data);
|
||||
status_t CLONE_ACCELERANT(void *data);
|
||||
void UNINIT_ACCELERANT(void);
|
||||
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
|
||||
|
||||
uint32 ACCELERANT_MODE_COUNT(void);
|
||||
status_t GET_MODE_LIST(display_mode *dm);
|
||||
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
|
||||
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
|
||||
status_t GET_DISPLAY_MODE(display_mode *current_mode);
|
||||
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
|
||||
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
|
||||
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
|
||||
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
|
||||
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
|
||||
|
||||
uint32 DPMS_CAPABILITIES(void);
|
||||
uint32 DPMS_MODE(void);
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags);
|
||||
|
||||
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
|
||||
void MOVE_CURSOR(uint16 x, uint16 y);
|
||||
void SHOW_CURSOR(bool is_visible);
|
||||
|
||||
uint32 ACCELERANT_ENGINE_COUNT(void);
|
||||
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
|
||||
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
|
||||
void WAIT_ENGINE_IDLE(void);
|
||||
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
|
||||
status_t SYNC_TO_TOKEN(sync_token *st);
|
||||
|
||||
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
|
||||
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
|
||||
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
|
||||
|
||||
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
|
||||
|
||||
#endif
|
||||
@@ -6,3 +6,5 @@ SubInclude OBOS_TOP src add-ons kernel drivers graphics neomagic ;
|
||||
SubInclude OBOS_TOP src add-ons kernel drivers graphics nvidia ;
|
||||
SubInclude OBOS_TOP src add-ons kernel drivers graphics radeon ;
|
||||
SubInclude OBOS_TOP src add-ons kernel drivers graphics tdfx ;
|
||||
|
||||
SubIncludeGPL OBOS_TOP src add-ons kernel drivers graphics atimach64 ;
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,19 @@
|
||||
SubDir OBOS_TOP src add-ons kernel drivers graphics atimach64 ;
|
||||
SubDirCcFlags -DSEMAPHORE=1 ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics atimach64 ] ;
|
||||
|
||||
R5KernelAddon atimach64.driver : kernel drivers bin :
|
||||
driver.c
|
||||
m64info.c
|
||||
;
|
||||
|
||||
# Link to kernel/drivers/dev/graphics
|
||||
{
|
||||
local dir = [ FDirName $(OBOS_ADDON_DIR) kernel drivers dev graphics ] ;
|
||||
local instDriver = <kernel!drivers!dev!graphics>atimach64.driver ;
|
||||
MakeLocate $(instDriver) : $(dir) ;
|
||||
RelSymLink $(instDriver) : atimach64.driver ;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
|
||||
Driver for ATIMach64VT
|
||||
|
||||
Lots of rewriting to be able to work with other ATIMACH64 cards
|
||||
|
||||
Rene MacKinney <rene_@freenet.co.uk>
|
||||
|
||||
6.May.1999
|
||||
|
||||
|
||||
Based on GraphicDriverKit for R4 alpha release
|
||||
|
||||
Huge thanks to Trey for all the help
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* standard kernel driver stuff */
|
||||
#include <KernelExport.h>
|
||||
#include <PCI.h>
|
||||
#include <OS.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/* this is for the standardized portion of the driver API */
|
||||
/* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */
|
||||
#include <graphic_driver.h>
|
||||
|
||||
/* this is for sprintf() */
|
||||
#include <stdio.h>
|
||||
|
||||
/* this is for string compares */
|
||||
#include <string.h>
|
||||
|
||||
/* The private interface between the accelerant and the kernel driver. */
|
||||
#include "DriverInterface.h"
|
||||
|
||||
/* ATI Mach64 Definitions */
|
||||
#include "regmach64.h"
|
||||
#include "ATIMach64.h"
|
||||
|
||||
#if DEBUG > 0
|
||||
#define ddprintf(a) dprintf a
|
||||
#else
|
||||
#define ddprintf(a)
|
||||
#endif
|
||||
|
||||
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
|
||||
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
|
||||
|
||||
/* Given the fact that the VT is a motherboard integrated
|
||||
card we only support one */
|
||||
|
||||
#define MAX_DEVICES 1
|
||||
|
||||
/* The vertical retrace semaphore is not implemented instead of erasing
|
||||
all the code about it we simply don't compile it. Waiting for the
|
||||
implementation */
|
||||
|
||||
#define SEMAPHORE 0
|
||||
|
||||
|
||||
/* Tell the kernel what revision of the driver API we support */
|
||||
int32 api_version = 2;
|
||||
|
||||
/* these structures are private to the kernel driver */
|
||||
typedef struct device_info device_info;
|
||||
|
||||
#if defined(POST_R4_0)
|
||||
typedef struct {
|
||||
timer te; /* timer entry for add_timer() */
|
||||
device_info *di; /* pointer to the owning device */
|
||||
bigtime_t when_target; /* when we're supposed to wake up */
|
||||
} timer_info;
|
||||
#endif
|
||||
|
||||
struct device_info {
|
||||
uint32 is_open; /* a count of how many times the devices has been opened */
|
||||
area_id shared_area; /* the area shared between the driver and all of the accelerants */
|
||||
shared_info *si; /* a pointer to the shared area, for convenience */
|
||||
vuint32 *regs; /* kernel's pointer to memory mapped registers */
|
||||
int32 can_interrupt; /* when we're faking interrupts, let's us know if we should generate one */
|
||||
#if defined(POST_R4_0)
|
||||
timer_info ti_a; /* a pool of two timer managment buffers */
|
||||
timer_info ti_b;
|
||||
timer_info *current_timer; /* the timer buffer that's currently in use */
|
||||
#else
|
||||
thread_id tid;
|
||||
#endif
|
||||
#if DEBUG > 0
|
||||
uint32 interrupt_count; /* if we're debugging, a count of how many times the interrupt handler has
|
||||
been called for this device */
|
||||
#endif
|
||||
pci_info pcii; /* a convenience copy of the pci info for this device */
|
||||
char name[B_OS_NAME_LENGTH]; /* where we keep the name of the device for publishing and comparing */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
#if DEBUG > 0
|
||||
uint32 total_interrupts; /* total number of interrupts seen by our handler */
|
||||
#endif
|
||||
uint32 count; /* number of devices actually found */
|
||||
benaphore kernel; /* for serializing opens/closes */
|
||||
char *device_names[MAX_DEVICES+1]; /* device name pointer storage */
|
||||
device_info di[MAX_DEVICES]; /* device specific stuff */
|
||||
} DeviceData;
|
||||
|
||||
/* prototypes for our private functions */
|
||||
static status_t open_hook (const char* name, uint32 flags, void** cookie);
|
||||
static status_t close_hook (void* dev);
|
||||
static status_t free_hook (void* dev);
|
||||
static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len);
|
||||
static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len);
|
||||
static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len);
|
||||
static status_t map_device(device_info *di);
|
||||
static void unmap_device(device_info *di);
|
||||
static void probe_devices(void);
|
||||
static int32 atimach64_interrupt(void *data);
|
||||
|
||||
#if DEBUG > 0
|
||||
static int dump(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
static DeviceData *pd;
|
||||
static pci_module_info *pci_bus;
|
||||
static device_hooks graphics_device_hooks = {
|
||||
open_hook,
|
||||
close_hook,
|
||||
free_hook,
|
||||
control_hook,
|
||||
read_hook,
|
||||
write_hook,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static uint16 ati_device_list[] = {
|
||||
PCI_MACH64_VT_ID, /* Mach64 VT device */
|
||||
0
|
||||
};
|
||||
|
||||
static struct {
|
||||
uint16 vendor;
|
||||
uint16 *devices;
|
||||
} SupportedDevices[] = {
|
||||
{PCI_ATI_VENDOR_ID, ati_device_list},
|
||||
{0x0000, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
init_hardware() - Returns B_OK if one is
|
||||
found, otherwise returns B_ERROR so the driver will be unloaded.
|
||||
*/
|
||||
status_t
|
||||
init_hardware(void) {
|
||||
long pci_index = 0;
|
||||
pci_info pcii;
|
||||
bool found_one = FALSE;
|
||||
|
||||
|
||||
/* choke if we can't find the PCI bus */
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
/* while there are more pci devices */
|
||||
while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
|
||||
int vendor = 0;
|
||||
|
||||
ddprintf(("SKD init_hardware(): checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, pcii.vendor_id, pcii.device_id));
|
||||
/* if we match a supported vendor */
|
||||
while (SupportedDevices[vendor].vendor) {
|
||||
if (SupportedDevices[vendor].vendor == pcii.vendor_id) {
|
||||
uint16 *devices = SupportedDevices[vendor].devices;
|
||||
/* while there are more supported devices */
|
||||
while (*devices) {
|
||||
/* if we match a supported device */
|
||||
if (*devices == pcii.device_id ) {
|
||||
|
||||
ddprintf(("SKD: we support this device\n"));
|
||||
found_one = TRUE;
|
||||
goto done;
|
||||
}
|
||||
/* next supported device */
|
||||
devices++;
|
||||
}
|
||||
}
|
||||
vendor++;
|
||||
}
|
||||
/* next pci_info struct, please */
|
||||
pci_index++;
|
||||
}
|
||||
ddprintf(("SKD: init_hardware - no supported devices\n"));
|
||||
|
||||
done:
|
||||
/* put away the module manager */
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return (found_one ? B_OK : B_ERROR);
|
||||
}
|
||||
|
||||
status_t
|
||||
init_driver(void) {
|
||||
|
||||
/* get a handle for the pci bus */
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
/* driver private data */
|
||||
pd = (DeviceData *)calloc(1, sizeof(DeviceData));
|
||||
if (!pd) {
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return B_ERROR;
|
||||
}
|
||||
/* initialize the benaphore */
|
||||
INIT_BEN(pd->kernel);
|
||||
/* find all of our supported devices */
|
||||
probe_devices();
|
||||
#if DEBUG > 0
|
||||
add_debugger_command("dump", dump, "dump ATIMach64 kernel driver persistant data");
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
const char **
|
||||
publish_devices(void) {
|
||||
/* return the list of supported devices */
|
||||
return (const char **)pd->device_names;
|
||||
}
|
||||
|
||||
device_hooks *
|
||||
find_device(const char *name) {
|
||||
int index = 0;
|
||||
while (pd->device_names[index]) {
|
||||
if (strcmp(name, pd->device_names[index]) == 0)
|
||||
return &graphics_device_hooks;
|
||||
index++;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
uninit_driver(void) {
|
||||
|
||||
#if DEBUG > 0
|
||||
remove_debugger_command("dump", dump);
|
||||
#endif
|
||||
|
||||
/* free the driver data */
|
||||
DELETE_BEN(pd->kernel);
|
||||
free(pd);
|
||||
pd = NULL;
|
||||
|
||||
/* put the pci module away */
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
}
|
||||
|
||||
static status_t map_device(device_info *di) {
|
||||
/* default: frame buffer in [0], control regs in [1] */
|
||||
/* int regs = 1; */
|
||||
int fb = 0;
|
||||
char buffer[B_OS_NAME_LENGTH];
|
||||
shared_info *si = di->si;
|
||||
uint32 tmpUlong;
|
||||
pci_info *pcii = &(di->pcii);
|
||||
uint32 rom_base;
|
||||
|
||||
|
||||
/* enable memory mapped IO, disable VGA I/O */
|
||||
tmpUlong = get_pci(PCI_command, 4);
|
||||
tmpUlong |= PCI_command_memory;
|
||||
tmpUlong &= ~((uint32) PCI_command_io);
|
||||
set_pci(PCI_command, 4, tmpUlong);
|
||||
|
||||
/* enable ROM decoding */
|
||||
/* tmpUlong = get_pci(PCI_rom_base, 4);
|
||||
tmpUlong |= PCI_rom_enable;
|
||||
set_pci(PCI_rom_base, 4, tmpUlong); */
|
||||
|
||||
/* map the rom */
|
||||
/* If rom_base points to 0x00 try using standard ROM location for Mach64 */
|
||||
rom_base = (di->pcii.u.h0.rom_base == 0) ? 0x000c0000 : di->pcii.u.h0.rom_base;
|
||||
sprintf(buffer, "%04X_%04X_%02X%02X%02X rom",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
si->rom_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *)rom_base,
|
||||
di->pcii.u.h0.rom_size,
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
B_READ_AREA,
|
||||
(void **)&(si->rom));
|
||||
|
||||
/* return the error if there was some problem */
|
||||
if (si->rom_area < 0) {
|
||||
delete_area(si->regs_area);
|
||||
si->regs_area = -1;
|
||||
return si->rom_area;
|
||||
}
|
||||
|
||||
sprintf(buffer, "%04X_%04X_%02X%02X%02X framebuffer",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
si->fb_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
#if defined(__INTEL__)
|
||||
#if defined(POST_R4_0)
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
|
||||
#else
|
||||
B_ANY_KERNEL_ADDRESS | B_MTR_WC,
|
||||
#endif
|
||||
#else
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
#endif
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
&(si->framebuffer));
|
||||
|
||||
#if defined(__INTEL__)
|
||||
if (si->fb_area < 0) {
|
||||
/* try to map this time without write combining */
|
||||
/*
|
||||
After R4.0 (Intel), map_physical_memory() will try B_ANY_KERNEL_ADDRESS if
|
||||
a call with B_ANY_KERNEL_BLOCK_ADDRESS would fail. It always worked this way
|
||||
under PPC.
|
||||
*/
|
||||
si->fb_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
#if defined(POST_R4_0)
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
#else
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
#endif
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
&(si->framebuffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if there was an error, delete our other areas */
|
||||
if (si->fb_area < 0) {
|
||||
delete_area(si->regs_area);
|
||||
si->regs_area = -1;
|
||||
delete_area(si->rom_area);
|
||||
si->rom_area = -1;
|
||||
}
|
||||
/* remember the DMA address of the frame buffer for BDirectWindow purposes */
|
||||
si->framebuffer_pci = (void *) di->pcii.u.h0.base_registers_pci[fb];
|
||||
|
||||
return si->fb_area;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_device(device_info *di) {
|
||||
shared_info *si = di->si;
|
||||
uint32 tmpUlong;
|
||||
pci_info *pcii = &(di->pcii);
|
||||
|
||||
ddprintf(("unmap_device(%08lx) begins...\n", (uint32)di));
|
||||
ddprintf((" regs_area: %ld\n fb_area: %ld\n", si->regs_area, si->fb_area));
|
||||
/* disable memory mapped IO */
|
||||
tmpUlong = get_pci(PCI_command, 4);
|
||||
tmpUlong &= 0xfffffffc;
|
||||
set_pci(PCI_command, 4, tmpUlong);
|
||||
/* disable ROM decoding */
|
||||
tmpUlong = get_pci(PCI_rom_base, 4);
|
||||
tmpUlong &= 0xfffffffe;
|
||||
set_pci(PCI_rom_base, 4, tmpUlong);
|
||||
/* delete the areas */
|
||||
if (si->rom_area >= 0) delete_area(si->rom_area);
|
||||
/* if (si->regs_area >= 0) delete_area(si->regs_area);*/
|
||||
if (si->fb_area >= 0) delete_area(si->fb_area);
|
||||
si->rom_area = si->regs_area = si->fb_area = -1;
|
||||
si->framebuffer = NULL;
|
||||
di->regs = NULL;
|
||||
si->rom = NULL;
|
||||
ddprintf(("unmap_device() ends.\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
probe_devices(void) {
|
||||
uint32 pci_index = 0;
|
||||
uint32 count = 0;
|
||||
device_info *di = pd->di;
|
||||
|
||||
/* while there are more pci devices */
|
||||
while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) {
|
||||
int vendor = 0;
|
||||
|
||||
/* if we match a supported vendor */
|
||||
while (SupportedDevices[vendor].vendor) {
|
||||
if (SupportedDevices[vendor].vendor == di->pcii.vendor_id) {
|
||||
uint16 *devices = SupportedDevices[vendor].devices;
|
||||
/* while there are more supported devices */
|
||||
while (*devices) {
|
||||
/* if we match a supported device */
|
||||
if (*devices == di->pcii.device_id ) {
|
||||
/* publish the device name */
|
||||
sprintf(di->name, "graphics/%04X_%04X_%02X%02X%02X",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
ddprintf(("SKD: making /dev/%s\n", di->name));
|
||||
/* remember the name */
|
||||
pd->device_names[count] = di->name;
|
||||
/* mark the driver as available for R/W open */
|
||||
di->is_open = 0;
|
||||
/* mark areas as not yet created */
|
||||
di->shared_area = -1;
|
||||
/* mark pointer to shared data as invalid */
|
||||
di->si = NULL;
|
||||
/* inc pointer to device info */
|
||||
di++;
|
||||
/* inc count */
|
||||
count++;
|
||||
/* break out of these while loops */
|
||||
goto next_device;
|
||||
}
|
||||
/* next supported device */
|
||||
devices++;
|
||||
}
|
||||
}
|
||||
vendor++;
|
||||
}
|
||||
next_device:
|
||||
/* next pci_info struct, please */
|
||||
pci_index++;
|
||||
}
|
||||
/* propagate count */
|
||||
pd->count = count;
|
||||
/* terminate list of device names with a null pointer */
|
||||
pd->device_names[pd->count] = NULL;
|
||||
ddprintf(("SKD probe_devices: %ld supported devices\n", pd->count));
|
||||
}
|
||||
|
||||
static uint32
|
||||
thread_interrupt_work(int32 *flags, vuint32 *regs, shared_info *si) {
|
||||
uint32 handled = B_HANDLED_INTERRUPT;
|
||||
/* release the vblank semaphore */
|
||||
if (si->vblank >= 0) {
|
||||
int32 blocked;
|
||||
if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) {
|
||||
release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE);
|
||||
handled = B_INVOKE_SCHEDULER;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
static int32
|
||||
atimach64_interrupt(void *data)
|
||||
{
|
||||
int32 handled = B_UNHANDLED_INTERRUPT;
|
||||
device_info *di = (device_info *)data;
|
||||
shared_info *si = di->si;
|
||||
int32 *flags = &(si->flags);
|
||||
vuint32 *regs;
|
||||
|
||||
#if DEBUG > 0
|
||||
pd->total_interrupts++;
|
||||
#endif
|
||||
|
||||
/* is someone already handling an interrupt for this device? */
|
||||
if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) {
|
||||
#if DEBUG > 0
|
||||
kprintf("SKD: Already in handler!\n");
|
||||
#endif
|
||||
goto exit0;
|
||||
}
|
||||
/* get regs */
|
||||
regs = di->regs;
|
||||
|
||||
/* read the interrrupt status register */
|
||||
|
||||
/* did this card cause an interrupt */
|
||||
if (0 /* replace this expression */) {
|
||||
/* do our stuff */
|
||||
handled = thread_interrupt_work(flags, regs, si);
|
||||
#if DEBUG > 0
|
||||
/* increment the counter for this device */
|
||||
di->interrupt_count++;
|
||||
#endif
|
||||
/* clear the interrupt status */
|
||||
}
|
||||
|
||||
/* note that we're not in the handler any more */
|
||||
atomic_and(flags, ~SKD_HANDLER_INSTALLED);
|
||||
|
||||
exit0:
|
||||
return handled;
|
||||
}
|
||||
|
||||
#if SEMAPHORE
|
||||
#if defined(POST_R4_0)
|
||||
static int32 timer_interrupt_func(timer *te, uint32 pc) {
|
||||
bigtime_t now = system_time();
|
||||
/* get the pointer to the device we're handling this time */
|
||||
device_info *di = ((timer_info *)te)->di;
|
||||
shared_info *si = di->si;
|
||||
int32 *flags = &(si->flags);
|
||||
vuint32 *regs = di->regs;
|
||||
uint32 vbl_status = 0 /* read vertical blank status */;
|
||||
int32 result = B_HANDLED_INTERRUPT;
|
||||
|
||||
/* are we suppoesed to handle interrupts still? */
|
||||
if (atomic_and(flags, -1) & SKD_HANDLER_INSTALLED) {
|
||||
/* reschedule with same period by default */
|
||||
bigtime_t when = si->refresh_period;
|
||||
timer *to;
|
||||
|
||||
/* if interrupts are "enabled", do our thing */
|
||||
if (di->can_interrupt) {
|
||||
/* insert code to sync to interrupts here */
|
||||
if (!vbl_status) {
|
||||
when -= si->blank_period - 4;
|
||||
}
|
||||
/* do the things we do when we notice a vertical retrace */
|
||||
result = thread_interrupt_work(flags, regs, si);
|
||||
|
||||
}
|
||||
|
||||
/* pick the "other" timer */
|
||||
to = (timer *)&(di->ti_a);
|
||||
if (to == te) to = (timer *)&(di->ti_b);
|
||||
/* our guess as to when we should be back */
|
||||
((timer_info *)to)->when_target = now + when;
|
||||
/* reschedule the interrupt */
|
||||
add_timer(to, timer_interrupt_func, ((timer_info *)to)->when_target, B_ONE_SHOT_ABSOLUTE_TIMER);
|
||||
/* remember the currently active timer */
|
||||
di->current_timer = (timer_info *)to;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
static int32
|
||||
fake_interrupt_thread_func(void *_di)
|
||||
{
|
||||
device_info *di; /* = (device_info *)_di; */
|
||||
shared_info *si; /* = di->si; */
|
||||
int32 *flags; /* = &(si->flags); */
|
||||
vuint32 *regs; /* = di->regs; */
|
||||
|
||||
bigtime_t last_sync;
|
||||
bigtime_t this_sync;
|
||||
bigtime_t diff_sync;
|
||||
|
||||
uint32 counter = 1;
|
||||
|
||||
ddprintf((" Device info points to %08x\n",(device_info *)_di));
|
||||
di = (device_info *)_di;
|
||||
ddprintf((" Shared info points to %08x\n",di->si));
|
||||
si = di->si;
|
||||
ddprintf((" Flags points to %08x\n",&(si->flags)));
|
||||
flags = &(si->flags);
|
||||
ddprintf((" Regs points to %08x\n",di->regs));
|
||||
regs = di->regs;
|
||||
|
||||
/* a lie, but we have to start somewhen */
|
||||
|
||||
last_sync = system_time() - 8333;
|
||||
|
||||
ddprintf(("fake_interrupt_thread_func begins\ndi: 0x%08lx\nsi: 0x%08lx\nflags: 0x%08lx\n", (uint32)di, (uint32)si, (uint32)flags));
|
||||
|
||||
/* loop until notified */
|
||||
|
||||
while(atomic_and(flags, -1) & SKD_HANDLER_INSTALLED) {
|
||||
/* see if "interrupts" are enabled */
|
||||
|
||||
if((volatile int32)(di->can_interrupt)) {
|
||||
/* poll the retrace flag until set */
|
||||
|
||||
/* YOUR CODE HERE */
|
||||
|
||||
/* get the system_time */
|
||||
this_sync = system_time();
|
||||
|
||||
/* do our stuff */
|
||||
thread_interrupt_work(flags, regs, si);
|
||||
} else {
|
||||
/* get the system_time */
|
||||
this_sync = system_time();
|
||||
}
|
||||
|
||||
/* find out how long it took */
|
||||
diff_sync = this_sync - last_sync;
|
||||
|
||||
/* back off a little so we're sure to catch the retrace */
|
||||
diff_sync -= diff_sync / 10;
|
||||
|
||||
/*
|
||||
impose some limits so we can recover from refresh rate changes
|
||||
Supported refresh rates are 48 Hz - 120 Hz, so these limits should
|
||||
be slightly wider.
|
||||
*/
|
||||
if(diff_sync < 8000) {
|
||||
diff_sync = 8000; /* not less than 1/125th of sec */
|
||||
}
|
||||
|
||||
if(diff_sync > 16666) {
|
||||
diff_sync = 20000; /* not more than 1/40th of sec */
|
||||
}
|
||||
|
||||
if((counter++ & 0x01ff) == 0) {
|
||||
diff_sync >>= 2; /* periodically quarter the wait to resync */
|
||||
}
|
||||
|
||||
/* update for next go-around */
|
||||
last_sync = this_sync;
|
||||
|
||||
/* snooze until our next retrace */
|
||||
|
||||
snooze_until(this_sync + diff_sync, B_SYSTEM_TIMEBASE);
|
||||
}
|
||||
|
||||
ddprintf(("fake_interrupt_thread_func ends with flags = 0x%08lx\n", *flags));
|
||||
|
||||
/* gotta return something */
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DEBUG > 0
|
||||
static int dump(int argc, char **argv) {
|
||||
int i;
|
||||
|
||||
kprintf("ATIMach64 Kernel Driver Persistant Data\n\nThere are %ld card(s)\n", pd->count);
|
||||
kprintf("Driver wide benahpore: %ld/%ld\n", pd->kernel.ben, pd->kernel.sem);
|
||||
|
||||
kprintf("Total seen interrupts: %ld\n", pd->total_interrupts);
|
||||
for (i = 0; i < pd->count; i++) {
|
||||
device_info *di = &(pd->di[i]);
|
||||
uint16 device_id = di->pcii.device_id;
|
||||
shared_info *si = di->si;
|
||||
kprintf(" device_id: 0x%04x\n", device_id);
|
||||
kprintf(" interrupt count: %ld\n", di->interrupt_count);
|
||||
if (si) {
|
||||
kprintf(" cursor: %d,%d\n", si->cursor.x, si->cursor.y);
|
||||
kprintf(" flags:");
|
||||
if (si->flags & SKD_MOVE_CURSOR) kprintf(" SKD_MOVE_CURSOR");
|
||||
if (si->flags & SKD_PROGRAM_CLUT) kprintf(" SKD_PROGRAM_CLUT");
|
||||
if (si->flags & SKD_SET_START_ADDR) kprintf(" SKD_SET_START_ADDR");
|
||||
kprintf(" vblank semaphore id: %ld\n", si->vblank);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1; /* the magic number for success */
|
||||
}
|
||||
#endif
|
||||
|
||||
static status_t open_hook (const char* name, uint32 flags, void** cookie) {
|
||||
int32 index = 0;
|
||||
device_info *di;
|
||||
shared_info *si;
|
||||
#if SEMAPHORE
|
||||
thread_id thid;
|
||||
thread_info thinfo;
|
||||
#endif
|
||||
status_t result = B_OK;
|
||||
vuint32 *regs;
|
||||
char shared_name[B_OS_NAME_LENGTH];
|
||||
|
||||
ddprintf(("SKD open_hook(%s, %ld, 0x%08lx)\n", name, flags, (uint32)cookie));
|
||||
|
||||
/* find the device name in the list of devices */
|
||||
/* we're never passed a name we didn't publish */
|
||||
while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++;
|
||||
|
||||
/* for convienience */
|
||||
di = &(pd->di[index]);
|
||||
|
||||
/* make sure no one else has write access to the common data */
|
||||
AQUIRE_BEN(pd->kernel);
|
||||
|
||||
/* if it's already open for writing */
|
||||
if (di->is_open) {
|
||||
/* mark it open another time */
|
||||
goto mark_as_open;
|
||||
}
|
||||
/* create the shared area */
|
||||
sprintf(shared_name, "%04X_%04X_%02X%02X%02X shared",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
/* create this area with NO user-space read or write permissions, to prevent accidental dammage */
|
||||
di->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, 0);
|
||||
if (di->shared_area < 0) {
|
||||
/* return the error */
|
||||
result = di->shared_area;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* save a few dereferences */
|
||||
si = di->si;
|
||||
|
||||
/* save the vendor and device IDs */
|
||||
si->vendor_id = di->pcii.vendor_id;
|
||||
si->device_id = di->pcii.device_id;
|
||||
si->revision = di->pcii.revision;
|
||||
|
||||
|
||||
/* map the device */
|
||||
result = map_device(di);
|
||||
|
||||
if (result < 0) goto free_shared;
|
||||
|
||||
/* Find registers in memory */
|
||||
/* This is the place for 2MB and 8MB boards */
|
||||
si->regs = (void *)((unsigned int)si->framebuffer + 0x7ffc00);
|
||||
if ((unsigned int)si->device_id != (inw(CONFIG_CHIP_ID) & CFG_CHIP_TYPE)) {
|
||||
/* Try place for 4MB */
|
||||
si->regs = (void *)((unsigned int)si->framebuffer + 0x3ffc00);
|
||||
if (si->device_id != (inw(CONFIG_CHIP_ID) & CFG_CHIP_TYPE)) {
|
||||
ddprintf(("Registers not found ! \n"));
|
||||
goto free_shared;
|
||||
}
|
||||
}
|
||||
|
||||
/* obtain all information related to the Mach64 */
|
||||
|
||||
result = GetATIInfo(si);
|
||||
if (result < 0) goto free_shared;
|
||||
|
||||
|
||||
/* create a semaphore for vertical blank management */
|
||||
#if SEMAPHORE
|
||||
si->vblank = create_sem(0, di->name);
|
||||
if (si->vblank < 0) {
|
||||
result = si->vblank;
|
||||
goto unmap;
|
||||
}
|
||||
#else
|
||||
/* No semafore for the moment */
|
||||
si->vblank = B_ERROR;
|
||||
#endif
|
||||
|
||||
/* change the owner of the semaphores to the opener's team */
|
||||
/* this is required because apps can't aquire kernel semaphores */
|
||||
#if SEMAPHORE
|
||||
thid = find_thread(NULL);
|
||||
get_thread_info(thid, &thinfo);
|
||||
set_sem_owner(si->vblank, thinfo.team);
|
||||
#endif
|
||||
|
||||
/* assign local regs pointer for ATIMACH64xx() macros */
|
||||
regs = di->regs;
|
||||
|
||||
/* disable and clear any pending interrupts */
|
||||
|
||||
#if SEMAPHORE
|
||||
/* if we're faking interrupts */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
/* fake some kind of interrupt with a timer */
|
||||
di->can_interrupt = FALSE;
|
||||
si->flags = SKD_HANDLER_INSTALLED;
|
||||
si->refresh_period = 16666; /* fake 60Hz to start */
|
||||
si->blank_period = si->refresh_period / 20;
|
||||
#if defined(POST_R4_0)
|
||||
di->ti_a.di = di; /* refer to ourself */
|
||||
di->ti_b.di = di;
|
||||
di->current_timer = &(di->ti_a);
|
||||
/* program the first timer interrupt, and it will handle the rest */
|
||||
result = add_timer((timer *)(di->current_timer), timer_interrupt_func, si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER);
|
||||
/* bail if we can't add the timer */
|
||||
if (result != B_OK) goto delete_the_sem;
|
||||
#else */
|
||||
/* fake some kind of interrupt with a thread */
|
||||
result = di->tid = spawn_kernel_thread(fake_interrupt_thread_func, "SKD fake interrupt", B_REAL_TIME_DISPLAY_PRIORITY, di);
|
||||
/* bail if we can't spawn the thread */
|
||||
if(result < 0) goto delete_the_sem;
|
||||
/* start up the thread */
|
||||
resume_thread(di->tid);
|
||||
|
||||
#endif
|
||||
} else {
|
||||
/* otherwise install our interrupt handler */
|
||||
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, atimach64_interrupt, (void *)di, 0);
|
||||
/* bail if we couldn't install the handler */
|
||||
if (result != B_OK) goto delete_the_sem;
|
||||
}
|
||||
#endif
|
||||
|
||||
mark_as_open:
|
||||
/* mark the device open */
|
||||
di->is_open++;
|
||||
|
||||
/* send the cookie to the opener */
|
||||
*cookie = di;
|
||||
|
||||
goto done;
|
||||
|
||||
/* delete_the_sem: */
|
||||
delete_sem(si->vblank);
|
||||
|
||||
/* unmap: */
|
||||
unmap_device(di);
|
||||
|
||||
free_shared:
|
||||
/* clean up our shared area */
|
||||
delete_area(di->shared_area);
|
||||
di->shared_area = -1;
|
||||
di->si = NULL;
|
||||
|
||||
done:
|
||||
/* end of critical section */
|
||||
RELEASE_BEN(pd->kernel);
|
||||
|
||||
/* all done, return the status */
|
||||
ddprintf(("open_hook returning 0x%08lx\n", result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
read_hook - does nothing, gracefully
|
||||
----- */
|
||||
static status_t
|
||||
read_hook (void* dev, off_t pos, void* buf, size_t* len)
|
||||
{
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
write_hook - does nothing, gracefully
|
||||
----- */
|
||||
static status_t
|
||||
write_hook (void* dev, off_t pos, const void* buf, size_t* len)
|
||||
{
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
close_hook - does nothing, gracefully
|
||||
----- */
|
||||
static status_t
|
||||
close_hook (void* dev)
|
||||
{
|
||||
ddprintf(("SKD close_hook(%08lx)\n", (uint32)dev));
|
||||
/* we don't do anything on close: there might be dup'd fd */
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
/* -----------
|
||||
free_hook - close down the device
|
||||
----------- */
|
||||
static status_t
|
||||
free_hook (void* dev) {
|
||||
device_info *di = (device_info *)dev;
|
||||
shared_info *si = di->si;
|
||||
|
||||
ddprintf(("SKD free_hook() begins...\n"));
|
||||
/* lock the driver */
|
||||
AQUIRE_BEN(pd->kernel);
|
||||
|
||||
/* if opened multiple times, decrement the open count and exit */
|
||||
if (di->is_open > 1)
|
||||
goto unlock_and_exit;
|
||||
|
||||
#if SEMAPHORE
|
||||
/* disable and clear any pending interrupts */
|
||||
|
||||
|
||||
/* if we were faking the interrupts */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
/* stop our interrupt faking thread */
|
||||
si->flags = 0;
|
||||
di->can_interrupt = FALSE;
|
||||
#if defined(POST_R4_0)
|
||||
/* cancel the timer */
|
||||
/* we don't know which one is current, so cancel them both and ignore any error */
|
||||
cancel_timer((timer *)&(di->ti_a));
|
||||
cancel_timer((timer *)&(di->ti_b));
|
||||
#else
|
||||
/* we don't do anything here, as the R4 kernel reaps its own threads */
|
||||
/* After R4.0 we can do it ourselves, but we'd rather use timers */
|
||||
#endif
|
||||
/* otherwise */
|
||||
} else {
|
||||
/* remove interrupt handler */
|
||||
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, atimach64_interrupt, di);
|
||||
}
|
||||
|
||||
/* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */
|
||||
delete_sem(si->vblank);
|
||||
#endif
|
||||
si->vblank = -1;
|
||||
|
||||
|
||||
/* free regs and framebuffer areas */
|
||||
unmap_device(di);
|
||||
|
||||
/* clean up our shared area */
|
||||
delete_area(di->shared_area);
|
||||
di->shared_area = -1;
|
||||
di->si = NULL;
|
||||
|
||||
unlock_and_exit:
|
||||
/* mark the device available */
|
||||
di->is_open--;
|
||||
/* unlock the driver */
|
||||
RELEASE_BEN(pd->kernel);
|
||||
ddprintf(("SKD free_hook() ends.\n"));
|
||||
/* all done */
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* -----------
|
||||
control_hook - where the real work is done
|
||||
----------- */
|
||||
static status_t
|
||||
control_hook (void* dev, uint32 msg, void *buf, size_t len) {
|
||||
device_info *di = (device_info *)dev;
|
||||
status_t result = B_DEV_INVALID_IOCTL;
|
||||
|
||||
/* ddprintf(("ioctl: %d, buf: 0x%08x, len: %d\n", msg, buf, len));*/
|
||||
switch (msg) {
|
||||
/* the only PUBLIC ioctl */
|
||||
case B_GET_ACCELERANT_SIGNATURE: {
|
||||
char *sig = (char *)buf;
|
||||
strcpy(sig, "atimach64vt.accelerant");
|
||||
result = B_OK;
|
||||
} break;
|
||||
|
||||
/* PRIVATE ioctl from here on */
|
||||
case ATIMACH64_GET_PRIVATE_DATA: {
|
||||
atimach64_get_private_data *gpd = (atimach64_get_private_data *)buf;
|
||||
if (gpd->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
gpd->shared_info_area = di->shared_area;
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
case ATIMACH64_GET_PCI: {
|
||||
atimach64_get_set_pci *gsp = (atimach64_get_set_pci *)buf;
|
||||
if (gsp->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
pci_info *pcii = &(di->pcii);
|
||||
gsp->value = get_pci(gsp->offset, gsp->size);
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
case ATIMACH64_SET_PCI: {
|
||||
atimach64_get_set_pci *gsp = (atimach64_get_set_pci *)buf;
|
||||
if (gsp->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
pci_info *pcii = &(di->pcii);
|
||||
set_pci(gsp->offset, gsp->size, gsp->value);
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
case ATIMACH64_RUN_INTERRUPTS: {
|
||||
atimach64_set_bool_state *ri = (atimach64_set_bool_state *)buf;
|
||||
if (ri->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
/* are we faking interrupts? */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
di->can_interrupt = ri->do_it;
|
||||
} else {
|
||||
vuint32 *regs = di->regs;
|
||||
if (ri->do_it) {
|
||||
/* resume interrupts */
|
||||
*regs = *regs; /* CHANGE ME */
|
||||
} else {
|
||||
/* disable interrupts */
|
||||
*regs = *regs; /* CHANGE ME */
|
||||
}
|
||||
}
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/* All this code belongs to Linux Xfree86 Project with lots of modifications */
|
||||
/*
|
||||
Rene MacKinney <rene_@freenet.co.uk>
|
||||
|
||||
7.May.99
|
||||
*/
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include "DriverInterface.h"
|
||||
#include "regmach64.h"
|
||||
#include "string.h"
|
||||
|
||||
#if DEBUG > 0
|
||||
#define ddprintf(a) dprintf a
|
||||
#else
|
||||
#define ddprintf(a)
|
||||
#endif
|
||||
|
||||
status_t
|
||||
GetATIInfo(si)
|
||||
shared_info *si;
|
||||
{
|
||||
char signature[] = " 761295520";
|
||||
char *bios_data = rommem(0x00);
|
||||
char bios_signature[10];
|
||||
unsigned short *sbios_data = (unsigned short *)bios_data;
|
||||
int tmp,i,j;
|
||||
int ROM_Table_Offset;
|
||||
int Freq_Table_Ptr;
|
||||
int CDepth_Table_Ptr;
|
||||
int CTable_Size;
|
||||
|
||||
|
||||
if (si->rom == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
memcpy(bios_signature, rommem(0x30), 10);
|
||||
|
||||
if (strncmp( signature, bios_signature, 10 )) {
|
||||
ddprintf(("Mach64 probe failed on BIOS signature\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
si->board_identifier[0] = bios_data[ 0x40 ];
|
||||
si->board_identifier[1] = bios_data[ 0x41 ];
|
||||
si->equipment_flags[0] = bios_data[ 0x42 ];
|
||||
si->equipment_flags[1] = bios_data[ 0x44 ];
|
||||
si->asic_identifier = bios_data[ 0x43 ];
|
||||
si->bios_major = bios_data[ 0x4c ];
|
||||
si->bios_minor = bios_data[ 0x4d ];
|
||||
strncpy( si->bios_date, bios_data + 0x50, 20 );
|
||||
|
||||
si->VGA_Wonder_Present = bios_data[ 0x44 ] & 0x40;
|
||||
|
||||
si->Mach64_Present = 1; /* Test for Mach64 product */
|
||||
|
||||
tmp = inw(SCRATCH_REG0);
|
||||
|
||||
|
||||
outw(SCRATCH_REG0, 0x55555555);
|
||||
if (inw(SCRATCH_REG0) != 0x55555555) {
|
||||
si->Mach64_Present = 0;
|
||||
ddprintf(("Mach64 probe failed on read 1 of SCRATCH_REG0 %x\n",
|
||||
SCRATCH_REG0));
|
||||
} else {
|
||||
outw(SCRATCH_REG0, 0xaaaaaaaa);
|
||||
if (inw(SCRATCH_REG0) != 0xaaaaaaaa) {
|
||||
si->Mach64_Present = 0;
|
||||
ddprintf(("Mach64 probe failed on read 2 of SCRATCH_REG0 %x\n",
|
||||
SCRATCH_REG0));
|
||||
}
|
||||
}
|
||||
|
||||
outw(SCRATCH_REG0, tmp);
|
||||
|
||||
if (!si->Mach64_Present)
|
||||
return B_ERROR;
|
||||
|
||||
tmp = inw(CONFIG_CHIP_ID);
|
||||
if (si->device_id != (tmp & CFG_CHIP_TYPE)) {
|
||||
ddprintf(("%x %x: Mach64 chipset mismatch",
|
||||
si->device_id, tmp & CFG_CHIP_TYPE));
|
||||
return(B_ERROR);
|
||||
}
|
||||
|
||||
ddprintf(("CONFIG_CHIP_ID reports: %x rev %d\n",
|
||||
si->device_id, si->revision));
|
||||
|
||||
tmp = inw(CONFIG_STAT0);
|
||||
if (si->device_id == MACH64_GX_ID || si->device_id == MACH64_CX_ID) {
|
||||
si->Bus_Type = tmp & CFG_BUS_TYPE;
|
||||
si->Mem_Type = (tmp & CFG_MEM_TYPE) >> 3;
|
||||
si->DAC_Type = (tmp & CFG_INIT_DAC_TYPE) >> 9;
|
||||
si->DAC_SubType = (inb(SCRATCH_REG1+1) & 0xf0) | si->DAC_Type;
|
||||
} else {
|
||||
si->Mem_Type = tmp & CFG_MEM_TYPE_xT;
|
||||
si->DAC_Type = DAC_INTERNAL;
|
||||
si->DAC_SubType = DAC_INTERNAL;
|
||||
|
||||
ddprintf(("CONFIG_STAT0 reports mem type %d\n", si->Mem_Type));
|
||||
ddprintf(("CONFIG_STAT0 is 0x%08x\n", tmp));
|
||||
}
|
||||
|
||||
/* The copy of the registers starts at 0x7ffc00 or 0x3ffc00 depending on the
|
||||
memory on the card */
|
||||
|
||||
tmp = inw(MEM_CNTL);
|
||||
if (si->device_id == MACH64_GX_ID ||
|
||||
si->device_id == MACH64_CX_ID ||
|
||||
si->device_id == MACH64_CT_ID ||
|
||||
si->device_id == MACH64_ET_ID ||
|
||||
((si->device_id == MACH64_VT_ID || si->device_id == MACH64_GT_ID) &&
|
||||
!(si->revision & 0x07))) {
|
||||
switch (tmp & MEM_SIZE_ALIAS) {
|
||||
case MEM_SIZE_512K:
|
||||
si->mem_size = 512 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_1M:
|
||||
si->mem_size = 1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_2M:
|
||||
si->mem_size = 2*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_4M:
|
||||
si->mem_size = 4*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_6M:
|
||||
si->mem_size = 6*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_8M:
|
||||
si->mem_size = 8*1024 * 1024;
|
||||
break;
|
||||
}
|
||||
si->Mem_Size = tmp & MEM_SIZE_ALIAS;
|
||||
} else {
|
||||
switch (tmp & MEM_SIZE_ALIAS_GTB) {
|
||||
case MEM_SIZE_512K:
|
||||
si->mem_size = 512 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_1M:
|
||||
si->mem_size = 1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_2M_GTB:
|
||||
si->mem_size = 2*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_4M_GTB:
|
||||
si->mem_size = 4*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_6M_GTB:
|
||||
si->mem_size = 6*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_8M_GTB:
|
||||
si->mem_size = 8*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_16M_GTB:
|
||||
si->mem_size = 16*1024 * 1024;
|
||||
break;
|
||||
}
|
||||
si->Mem_Size = tmp & MEM_SIZE_ALIAS_GTB;
|
||||
}
|
||||
|
||||
ddprintf(("Card Reports 0x%08x Memory\n", si->mem_size));
|
||||
|
||||
ROM_Table_Offset = sbios_data[0x48 >> 1];
|
||||
Freq_Table_Ptr = sbios_data[(ROM_Table_Offset >> 1) + 8];
|
||||
si->Clock_Type = bios_data[Freq_Table_Ptr];
|
||||
|
||||
si->MinFreq = sbios_data[(Freq_Table_Ptr >> 1) + 1];
|
||||
si->MaxFreq = sbios_data[(Freq_Table_Ptr >> 1) + 2];
|
||||
si->RefFreq = sbios_data[(Freq_Table_Ptr >> 1) + 4];
|
||||
si->RefDivider = sbios_data[(Freq_Table_Ptr >> 1) + 5];
|
||||
si->NAdj = sbios_data[(Freq_Table_Ptr >> 1) + 6];
|
||||
si->DRAMMemClk = sbios_data[(Freq_Table_Ptr >> 1) + 8];
|
||||
si->VRAMMemClk = sbios_data[(Freq_Table_Ptr >> 1) + 9];
|
||||
si->MemClk = bios_data[Freq_Table_Ptr + 22];
|
||||
si->CXClk = bios_data[Freq_Table_Ptr + 6];
|
||||
|
||||
CDepth_Table_Ptr = sbios_data[(Freq_Table_Ptr >> 1) - 3];
|
||||
Freq_Table_Ptr = sbios_data[(Freq_Table_Ptr >> 1) - 1];
|
||||
|
||||
for (i = 0; i < MACH64_NUM_CLOCKS; i++)
|
||||
si->Clocks[i] = sbios_data[(Freq_Table_Ptr >> 1) + i];
|
||||
|
||||
si->MemCycle = bios_data[ROM_Table_Offset + 0];
|
||||
|
||||
CTable_Size = bios_data[CDepth_Table_Ptr - 1];
|
||||
for (i = 0, j = 0;
|
||||
bios_data[CDepth_Table_Ptr + i] != 0;
|
||||
i += CTable_Size, j++) {
|
||||
si->Freq_Table[j].h_disp = bios_data[CDepth_Table_Ptr + i];
|
||||
si->Freq_Table[j].dacmask = bios_data[CDepth_Table_Ptr + i + 1];
|
||||
si->Freq_Table[j].ram_req = bios_data[CDepth_Table_Ptr + i + 2];
|
||||
si->Freq_Table[j].max_dot_clock = bios_data[CDepth_Table_Ptr + i + 3];
|
||||
si->Freq_Table[j].color_depth = bios_data[CDepth_Table_Ptr + i + 4];
|
||||
switch(si->Freq_Table[j].color_depth) {
|
||||
case 2: /* 8 Bit */
|
||||
si->pix_clk_max8 = max(si->pix_clk_max8, si->Freq_Table[j].max_dot_clock);
|
||||
break;
|
||||
case 4: /* 16 Bit */
|
||||
si->pix_clk_max16 = max(si->pix_clk_max16, si->Freq_Table[j].max_dot_clock);
|
||||
break;
|
||||
case 6: /* 8 Bit */
|
||||
si->pix_clk_max32 = max(si->pix_clk_max32, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
si->Freq_Table[j].h_disp = 0;
|
||||
|
||||
if (bios_data[CDepth_Table_Ptr + i + 1] != 0) {
|
||||
CDepth_Table_Ptr += i + 2;
|
||||
CTable_Size = bios_data[CDepth_Table_Ptr - 1];
|
||||
for (i = 0, j = 0;
|
||||
bios_data[CDepth_Table_Ptr + i] != 0;
|
||||
i += CTable_Size, j++) {
|
||||
si->Freq_Table2[j].h_disp = bios_data[CDepth_Table_Ptr + i];
|
||||
si->Freq_Table2[j].dacmask = bios_data[CDepth_Table_Ptr + i +
|
||||
1];
|
||||
si->Freq_Table2[j].ram_req = bios_data[CDepth_Table_Ptr + i +
|
||||
2];
|
||||
si->Freq_Table2[j].max_dot_clock = bios_data[CDepth_Table_Ptr + i +
|
||||
3];
|
||||
si->Freq_Table2[j].color_depth = bios_data[CDepth_Table_Ptr + i +
|
||||
4];
|
||||
switch(si->Freq_Table[j].color_depth) {
|
||||
case 2: /* 8 Bit */
|
||||
si->pix_clk_max8 = max(si->pix_clk_max8, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
case 4: /* 16 Bit */
|
||||
si->pix_clk_max16 = max(si->pix_clk_max16, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
case 6: /* 8 Bit */
|
||||
si->pix_clk_max32 = max(si->pix_clk_max32, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
si->Freq_Table2[j].h_disp = 0;
|
||||
} else
|
||||
si->Freq_Table2[0].h_disp = 0;
|
||||
|
||||
/* Hardwired 120000 for 8bpp and 80000 for the rest */
|
||||
|
||||
ddprintf(("Clocks %ld %ld %ld\n",si->pix_clk_max32,
|
||||
si->pix_clk_max16, si->pix_clk_max8));
|
||||
|
||||
|
||||
si->pix_clk_max32 = 80000;
|
||||
si->pix_clk_max16 = 80000;
|
||||
si->pix_clk_max8 = 120000;
|
||||
|
||||
|
||||
ddprintf(("Clocks %ld %ld %ld\n",si->pix_clk_max32,
|
||||
si->pix_clk_max16, si->pix_clk_max8));
|
||||
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user