/******************************Module*Header*******************************\
* Module Name: hw.h
*
* All the hardware specific driver file stuff.  Parts are mirrored in
* 'hw.inc'.
*
* Copyright (c) 1994-1995 Microsoft Corporation
*
\**************************************************************************/

#define GC_INDEX            0x3CE      /* Index and Data Registers */
#define GC_DATA             0x3CF
#define SEQ_INDEX           0x3C4
#define SEQ_DATA            0x3C5
#define CRTC_INDEX          0x3D4
#define CRTC_DATA           0x3D5
#define ATTR_INDEX          0x3C0
#define ATTR_DATA           0x3C0
#define ATTR_DATA_READ      0x3C1
#define MISC_OUTPUT         0x3C2
#define MISC_OUTPUT_READ    0x3CC
#define INPUT_STATUS_REG_1  0x3DA

#define CTRL_REG_0           0x40
#define CTRL_REG_1         0x63CA      /* Datapath Registers */
#define DATAPATH_CTRL        0x5A
#define GC_FG_COLOR          0x43
#define GC_BG_COLOR          0x44
#define SEQ_PIXEL_WR_MSK     0x02
#define GC_PLANE_WR_MSK      0x08
#define ROP_A              0x33C7
#define ROP_0              0x33C5
#define ROP_1              0x33C4
#define ROP_2              0x33C3
#define ROP_3              0x33C2
#define DATA_ROTATE          0x03
#define READ_CTRL            0x41

#define X0_SRC_ADDR_LO     0x63C0      /* BitBLT Registers */
#define Y0_SRC_ADDR_HI     0x63C2
#define DEST_ADDR_LO       0x63CC
#define DEST_ADDR_HI       0x63CE
#define BITMAP_WIDTH       0x23C2
#define BITMAP_HEIGHT      0x23C4
#define SRC_PITCH          0x23CA
#define DEST_PITCH         0x23CE
#define BLT_CMD_0          0x33CE
#define BLT_CMD_1          0x33CF
#define PREG_0             0x33CA
#define PREG_1             0x33CB
#define PREG_2             0x33CC
#define PREG_3             0x33CD
#define PREG_4             0x33CA
#define PREG_5             0x33CB
#define PREG_6             0x33CC
#define PREG_7             0x33CD

#define BLT_START_MASK     0x33C0      /* XccelVGA BitBlt Registers */
#define BLT_END_MASK       0x33C1
#define BLT_ROTATE         0x33C8
#define BLT_SKEW_MASK      0x33C9
#define BLT_SRC_ADDR       0x23C0
#define DEST_OFFSET        0x23CC


#define X1                 0x83CC      /* Line Draw Registers */
#define Y1                 0x83CE
#define LINE_PATTERN       0x83C0
#define PATTERN_END          0x62
#define LINE_CMD             0x60
#define LINE_PIX_CNT         0x64
#define LINE_ERR_TERM        0x66
#define SIGN_CODES           0x63
#define   X_MAJOR            0x00
#define   Y_MAJOR            0x01
#define   DELTA_Y_POS        0x00
#define   DELTA_Y_NEG        0x02
#define   DELTA_X_POS        0x00
#define   DELTA_X_NEG        0x04
#define K1_CONST             0x68
#define K2_CONST             0x6A

#define PALETTE_WRITE       0x3C8      /* DAC registers */
#define PALETTE_READ        0x3C7
#define PALETTE_DATA        0x3C9
#define DAC_CMD_0          0x83C6
#define DAC_CMD_1          0x13C8
#define DAC_CMD_2          0x13C9
#define   CURSOR_ENABLE      0x02
#define   CURSOR_DISABLE     0x00

#define CURSOR_WRITE        0x3C8     /* HW Cursor registers */
#define CURSOR_READ         0x3C7
#define   CURSOR_PLANE_0     0x00
#define   CURSOR_PLANE_1     0x80
#define CURSOR_DATA        0x13C7
#define CURSOR_COLOR_READ  0x83C7
#define CURSOR_COLOR_WRITE 0x83C8
#define CURSOR_COLOR_DATA  0x83C9
#define   OVERSCAN_COLOR     0x00
#define   CURSOR_COLOR_1     0x01
#define   CURSOR_COLOR_2     0x02
#define   CURSOR_COLOR_3     0x03
#define CURSOR_X           0x93C8     /* 16-bit register */
#define CURSOR_Y           0x93C6     /* 16-bit register */
#define   CURSOR_CX            32     /* h/w cursor width */
#define   CURSOR_CY            32     /* h/w cursor height */

#define PAGE_REG_0           0x45      /* Control Registers */
#define PAGE_REG_1           0x46
#define HI_ADDR_MAP          0x48        /* LO, HI is at 0x49 */
#define ENV_REG_1            0x50
#define VIRT_CTRLR_SEL     0x83C4

#define VER_NUM_REG         0x0C
#define EXT_VER_NUM_REG     0x0D
#define ENV_REG_0           0x0F
#define BLT_CONFIG          0x10
#define CONFIG_STATE        0x52         /* LO, HI is at 0x53 */
#define BIOS_DATA           0x54
#define DATAPATH_CONTROL    0x5A

#define LOCK_KEY_QVISION    0x05
#define EXT_COLOR_MODE      0x01

#define BLT_ENABLE          0x28       /* BLT_CONFIG values */
#define RESET_BLT           0x60       // Make sure we don't enable IRQ9


#define BUFFER_BUSY          0x80      /* CTRL_REG_1 values */
#define GLOBAL_BUSY          0x40
#define BLOCK_WRITE          0x20
#define PACKED_PIXEL_VIEW    0x00
#define PLANAR_VIEW          0x08
#define EXPAND_TO_FG         0x10
#define EXPAND_TO_BG         0x18
#define BITS_PER_PIX_4       0x00
#define BITS_PER_PIX_8       0x02
#define BITS_PER_PIX_16      0x04
#define BITS_PER_PIX_32      0x06
#define ENAB_TRITON_MODE     0x01

#define ROPSELECT_NO_ROPS              0x00      /* DATAPATH_CTRL values */
#define ROPSELECT_PRIMARY_ONLY         0x40
#define ROPSELECT_ALL_EXCPT_PRIMARY    0x80
#define ROPSELECT_ALL                  0xc0
#define PIXELMASK_ONLY                 0x00
#define PIXELMASK_AND_SRC_DATA         0x10
#define PIXELMASK_AND_CPU_DATA         0x20
#define PIXELMASK_AND_SCRN_LATCHES     0x30
#define PLANARMASK_ONLY                0x00
#define PLANARMASK_NONE_0XFF           0x04
#define PLANARMASK_AND_CPU_DATA        0x08
#define PLANARMASK_AND_SCRN_LATCHES    0x0c
#define SRC_IS_CPU_DATA                0x00
#define SRC_IS_SCRN_LATCHES            0x01
#define SRC_IS_PATTERN_REGS            0x02
#define SRC_IS_LINE_PATTERN            0x03

#define LOGICAL_0               0x00       // 0   (ROP values)
#define NOT_DEST_AND_NOT_SOURCE 0x01       // DSon
#define DEST_AND_NOT_SOURCE     0x02       // DSna
#define NOT_SOURCE              0x03       // Sn
#define NOT_DEST_AND_SOURCE     0x04       // SDna
#define NOT_DEST                0x05       // Dn
#define DEST_XOR_SOURCE         0x06       // DSx
#define NOT_DEST_OR_NOT_SOURCE  0x07       // DSan
#define DEST_AND_SOURCE         0x08       // DSa
#define DEST_XNOR_SOURCE        0x09       // DSxn
#define DEST_DATA               0x0A       // D
#define DEST_OR_NOT_SOURCE      0x0B       // DSno
#define SOURCE_DATA             0x0C       // S
#define NOT_DEST_OR_SOURCE      0x0D       // SDno
#define DEST_OR_SOURCE          0x0E       // DSo
#define LOGICAL_1               0x0F       // 1

#define START_BLT            0x01      /* BLT_CMD_0 values */
#define NO_BYTE_SWAP         0x00
#define BYTE_SWAP            0x20
#define FORWARD              0x00
#define BACKWARD             0x40
#define WRAP                 0x00
#define NO_WRAP              0x80

#define PRELOAD              0x02      /* BLT_CMD_0 XccelVGA values */
#define SKIP_LAST            0x04
#define SKIP_SRC             0x08
#define SKIP_DEST            0x10


#define LIN_SRC_ADDR         0x00      /* BLT_CMD_1 values */
#define XY_SRC_ADDR          0x40
#define LIN_DEST_ADDR        0x00
#define XY_DEST_ADDR         0x80

#define BLT_ROP_ENABLE       0x10      /* BLT_CMD_1 XccelVGA values */
#define BLT_DSR              0x20

#define START_LINE           0x01      /* LINE_CMD values */
#define NO_CALC_ONLY         0x00
#define CALC_ONLY            0x02
#define LAST_PIXEL_ON        0x00
#define LAST_PIXEL_NULL      0x04
#define NO_KEEP_X0_Y0        0x00
#define KEEP_X0_Y0           0x08
#define RETAIN_PATTERN_PTR   0x00
#define RESET_PATTERN_PTR    0x10
#define USE_AXIAL_WHEN_ZERO  0x00
#define NO_USE_AXIAL_WHEN_ZERO 0x20
#define AXIAL_ROUND_DOWN     0x40
#define AXIAL_ROUND_UP       0x00
#define LINE_RESET           0x80

#define SS_BIT               0x01      /* BLT_CMD_0 bit */

#define START_BIT            0x01      /* LINE_CMD bit */

#define NO_ROTATE            0x00
#define NO_MASK              0xFF

/////////////////////////////////////////////////////////////////////
//

#define IO_WAIT_FOR_IDLE(ppdev, pjIoBase)                           \
{                                                                   \
    while (READ_PORT_UCHAR((pjIoBase) + CTRL_REG_1) & GLOBAL_BUSY)  \
        ;                                                           \
}

#define IO_WAIT_BUFFER_NOT_BUSY(ppdev, pjIoBase)                    \
{                                                                   \
    while (READ_PORT_UCHAR((pjIoBase) + CTRL_REG_1) & BUFFER_BUSY)  \
        ;                                                           \
}

// We occasionally hit a chip bug in QVision 1280's on monochrome
// expansions, where the the driver will get caught in an endless loop
// on engine-busy, even though all data has been transferred
// properly.  It turns out that some QVision chips have a bug where
// 'certain types of I/O writes abutting a write to the frame buffer'
// cause the data count occasionally to fail to increment.
//
// As a work-around, we'll always check for the hang condition after
// doing a monochrome expansion, looping a few times to allow the
// engine to catch up, and if it's still hung we reset the engine:

#define WAIT_TRANSFER_DONE_LOOP_COUNT       100

#define IO_WAIT_TRANSFER_DONE(ppdev, pjIoBase)                            \
{                                                                         \
    LONG i;                                                               \
    for (i = WAIT_TRANSFER_DONE_LOOP_COUNT; i != 0; i--)                  \
    {                                                                     \
        if (!(READ_PORT_UCHAR((pjIoBase) + CTRL_REG_1) & GLOBAL_BUSY))    \
            break;                                                        \
    }                                                                     \
    if (i == 0)                                                           \
    {                                                                     \
        IO_BLT_CMD_0(ppdev, (pjIoBase), 0);                               \
        IO_WAIT_FOR_IDLE(ppdev, (pjIoBase));                              \
    }                                                                     \
}

//

#define IO_CURSOR_X(ppdev, pjIoBase, x)                                   \
    WRITE_PORT_USHORT((pjIoBase) + CURSOR_X, (USHORT)(x))

#define IO_CURSOR_Y(ppdev, pjIoBase, x)                                   \
    WRITE_PORT_USHORT((pjIoBase) + CURSOR_Y, (USHORT)(x))

#define IO_CTRL_REG_1(ppdev, pjIoBase, x)                                 \
    WRITE_PORT_UCHAR((pjIoBase) + CTRL_REG_1, (x))

#define IO_DATAPATH_CTRL(ppdev, pjIoBase, x)                              \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)<<8)|DATAPATH_CTRL));\
    MEMORY_BARRIER();                                                     \
}

#define IO_FG_COLOR(ppdev, pjIoBase, x)                                   \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)<<8)|GC_FG_COLOR));\
    MEMORY_BARRIER();                                                     \
}

#define IO_BG_COLOR(ppdev, pjIoBase, x)                                   \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)<<8)|GC_BG_COLOR));\
    MEMORY_BARRIER();                                                     \
}

#define IO_BLT_CONFIG(ppdev, pjIoBase, x)                                 \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase) +GC_INDEX,(USHORT)(((x)<<8)|BLT_CONFIG));\
    MEMORY_BARRIER();                                                     \
}

#define IO_BLT_CMD_0(ppdev, pjIoBase, x)                                  \
{                                                                         \
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_UCHAR((pjIoBase) + BLT_CMD_0, (x));                        \
    MEMORY_BARRIER();                                                     \
}

#define IO_BLT_CMD_1(ppdev, pjIoBase, x)                                  \
    WRITE_PORT_UCHAR((pjIoBase) + BLT_CMD_1, (x))

#define IO_PREG_COLOR_8(ppdev, pjIoBase, x)                               \
{                                                                         \
    ULONG ul;                                                             \
                                                                          \
    /* Unfortunately, PREG_0 isn't dword aligned, so we can't */          \
    /* do a dword out to it...                                */          \
                                                                          \
    ul = ((x) << 8) | (x);                                                \
    WRITE_PORT_USHORT((pjIoBase) + PREG_4, (USHORT)(ul));                 \
    WRITE_PORT_USHORT((pjIoBase) + PREG_6, (USHORT)(ul));                 \
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase) + PREG_0, (USHORT)(ul));                 \
    WRITE_PORT_USHORT((pjIoBase) + PREG_2, (USHORT)(ul));                 \
}

#define IO_PREG_PATTERN(ppdev, pjIoBase, p)                               \
{                                                                         \
    USHORT* pw = (USHORT*) (p);                                           \
                                                                          \
    /* Unfortunately, PREG_0 isn't dword aligned, so we can't */          \
    /* do a dword out to it...                                */          \
                                                                          \
    WRITE_PORT_USHORT((pjIoBase) + PREG_4, (USHORT)(*(pw)));              \
    WRITE_PORT_USHORT((pjIoBase) + PREG_6, (USHORT)(*(pw + 1)));          \
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase) + PREG_0, (USHORT)(*(pw + 2)));          \
    WRITE_PORT_USHORT((pjIoBase) + PREG_2, (USHORT)(*(pw + 3)));          \
}

#define IO_BITMAP_WIDTH(ppdev, pjIoBase, x)                               \
    WRITE_PORT_USHORT((pjIoBase) + BITMAP_WIDTH, (USHORT)(x))

#define IO_BITMAP_HEIGHT(ppdev, pjIoBase, x)                              \
    WRITE_PORT_USHORT((pjIoBase) + BITMAP_HEIGHT, (USHORT)(x))

#define IO_PACKED_HEIGHT_WIDTH(ppdev, pjIoBase, yx)                       \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase) + BITMAP_HEIGHT, (USHORT)(yx));          \
    WRITE_PORT_USHORT((pjIoBase) + BITMAP_WIDTH, (USHORT)((yx) >> 16));   \
}

#define IO_SRC_LIN(ppdev, pjIoBase, x)                                    \
    WRITE_PORT_ULONG((pjIoBase) + X0_SRC_ADDR_LO, (x))

#define IO_SRC_ALIGN(ppdev, pjIoBase, x)                                  \
    WRITE_PORT_UCHAR((pjIoBase) + X0_SRC_ADDR_LO, (UCHAR)(x))

#define IO_DEST_LIN(ppdev, pjIoBase, x)                                   \
    WRITE_PORT_ULONG((pjIoBase) + DEST_ADDR_LO, (x))

/* Note that the pitch is specified in dwords */

#define IO_DEST_PITCH(ppdev, pjIoBase, x)                                 \
    WRITE_PORT_USHORT((pjIoBase) + DEST_PITCH, (USHORT)(x))

#define IO_SRC_PITCH(ppdev, pjIoBase, x)                                  \
    WRITE_PORT_USHORT((pjIoBase) + SRC_PITCH, (USHORT)(x))

#define IO_ROP_A(ppdev, pjIoBase, x)                                      \
    WRITE_PORT_UCHAR((pjIoBase) + ROP_A, (UCHAR)(x))

#define IO_K1_CONST(ppdev, pjIoBase, x)                                   \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)<<8)|(K1_CONST))); \
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)&0xff00)|(K1_CONST + 1)));\
    MEMORY_BARRIER();                                                     \
}

#define IO_K2_CONST(ppdev, pjIoBase, x)                                   \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase) +GC_INDEX,(USHORT)(((x)<<8)|(K2_CONST)));\
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)&0xff00)|(K2_CONST+1)));\
    MEMORY_BARRIER();                                                     \
}

#define IO_LINE_PIX_CNT(ppdev, pjIoBase, x)                               \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)<<8)|(LINE_PIX_CNT))); \
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)&0xff00)|(LINE_PIX_CNT+1))); \
    MEMORY_BARRIER();                                                     \
}

#define IO_LINE_ERR_TERM(ppdev, pjIoBase, x)                              \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)<<8)|(LINE_ERR_TERM)));\
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase)+GC_INDEX,(USHORT)(((x)&0xff00)|(LINE_ERR_TERM+1)));\
    MEMORY_BARRIER();                                                     \
}

#define IO_SIGN_CODES(ppdev, pjIoBase, x)                                 \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+ GC_INDEX,(USHORT)(((x)<<8)|SIGN_CODES));\
    MEMORY_BARRIER();                                                     \
}

#define IO_LINE_PATTERN(ppdev, pjIoBase, x)                               \
    WRITE_PORT_ULONG((pjIoBase) + LINE_PATTERN, (x))

#define IO_LINE_CMD(ppdev, pjIoBase, x)                                   \
{                                                                         \
    MEMORY_BARRIER();                                                     \
    WRITE_PORT_USHORT((pjIoBase) +GC_INDEX,(USHORT)(((x) << 8)|LINE_CMD));\
    MEMORY_BARRIER();                                                     \
}

#define IO_PIXEL_WRITE_MASK(ppdev, pjIoBase, x)                           \
{                                                                         \
    WRITE_PORT_USHORT((pjIoBase)+SEQ_INDEX,(USHORT)(((x)<<8)|SEQ_PIXEL_WR_MSK));\
}

//

#define IO_SRC_XY(ppdev, pjIoBase, x, y)                                  \
    WRITE_PORT_ULONG((pjIoBase) + X0_SRC_ADDR_LO,                         \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

#define IO_DEST_XY(ppdev, pjIoBase, x, y)                                 \
    WRITE_PORT_ULONG((pjIoBase) + DEST_ADDR_LO,                           \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

#define IO_DEST_X(ppdev, pjIoBase, x)                                     \
    WRITE_PORT_USHORT((pjIoBase) + DEST_ADDR_LO, ((x) + (USHORT) ppdev->xOffset))

#define IO_DEST_Y(ppdev, pjIoBase, x)                                     \
    WRITE_PORT_USHORT((pjIoBase) + DEST_ADDR_HI, ((x) + (USHORT) ppdev->yOffset))

#define IO_X0_Y0(ppdev, pjIoBase, x, y)                                   \
    WRITE_PORT_ULONG((pjIoBase) + X0_SRC_ADDR_LO,                         \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

#define IO_X1_Y1(ppdev, pjIoBase, x, y)                                   \
    WRITE_PORT_ULONG((pjIoBase) + X1,                                     \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

//

#define IO_ABS_SRC_XY(ppdev, pjIoBase, x, y)                              \
    WRITE_PORT_ULONG((pjIoBase) + X0_SRC_ADDR_LO, ((y) << 16) | (x))

#define IO_ABS_DEST_XY(ppdev, pjIoBase, x, y)                             \
    WRITE_PORT_ULONG((pjIoBase) + DEST_ADDR_LO, ((y) << 16) | (x))

#define IO_ABS_X0_Y0(ppdev, pjIoBase, x, y)                               \
    WRITE_PORT_ULONG((pjIoBase) + X0_SRC_ADDR_LO, ((y) << 16) | (x))

#define IO_ABS_X1_Y1(ppdev, pjIoBase, x, y)                               \
    WRITE_PORT_ULONG((pjIoBase) + X1, ((y) << 16) | (x))

/////////////////////////////////////////////////////////////////////

#define MEM_CTRL_REG_1       0xf3c
#define MEM_DATAPATH_CTRL    0xf3e
#define MEM_FG_COLOR         0xf40
#define MEM_BG_COLOR         0xf41
#define MEM_BLT_CMD_0        0xfb0
#define MEM_BLT_CMD_1        0xfb1
#define MEM_BROADCAST_COLOR  0xf42
#define MEM_PREG_0           0xfa0
#define MEM_PREG_1           0xfa1
#define MEM_PREG_2           0xfa2
#define MEM_PREG_3           0xfa3
#define MEM_PREG_4           0xfa4
#define MEM_PREG_5           0xfa5
#define MEM_PREG_6           0xfa6
#define MEM_PREG_7           0xfa7
#define MEM_BITMAP_HEIGHT    0xfac
#define MEM_BITMAP_WIDTH     0xfae
#define MEM_SRC_ADDR_LO      0xfb8
#define MEM_SRC_ADDR_HI      0xfba
#define MEM_DEST_ADDR_LO     0xfbc
#define MEM_DEST_ADDR_HI     0xfbe
#define MEM_DEST_PITCH       0xfaa
#define MEM_SRC_PITCH        0xfa8
#define MEM_ROP_A            0xf43
#define MEM_K1_CONST         0xf70
#define MEM_K2_CONST         0xf74
#define MEM_LINE_PIX_CNT     0xf68
#define MEM_LINE_ERR_TERM    0xf6c
#define MEM_SIGN_CODES       0xf63
#define MEM_LINE_PATTERN     0xf64
#define MEM_LINE_CMD         0xf60
#define MEM_X0               0xf78
#define MEM_Y0               0xf7a
#define MEM_X1               0xf7c
#define MEM_Y1               0xf7e
#define MEM_SEQ_PIXEL_WR_MSK 0xf30

//

#define MM_WAIT_FOR_IDLE(ppdev, pjMmBase)                                 \
{                                                                         \
    while (READ_REGISTER_UCHAR((pjMmBase) + MEM_CTRL_REG_1) & GLOBAL_BUSY)\
        ;                                                                 \
}

#define MM_WAIT_BUFFER_NOT_BUSY(ppdev, pjMmBase)                          \
{                                                                         \
    while (READ_REGISTER_UCHAR((pjMmBase) + MEM_CTRL_REG_1) & BUFFER_BUSY)\
        ;                                                                 \
}

// We occasionally hit a chip bug in QVision 1280's on monochrome
// expansions, where the the driver will get caught in an endless loop
// on engine-busy, even though all data has been transferred
// properly.  It turns out that some QVision chips have a bug where
// 'certain types of I/O writes abutting a write to the frame buffer'
// cause the data count occasionally to fail to increment.
//
// As a work-around, we'll always check for the hang condition after
// doing a monochrome expansion, looping a few times to allow the
// engine to catch up, and if it's still hung we reset the engine:

#define WAIT_TRANSFER_DONE_LOOP_COUNT       100

#define MM_WAIT_TRANSFER_DONE(ppdev, pjMmBase)                            \
{                                                                         \
    LONG i;                                                               \
    for (i = WAIT_TRANSFER_DONE_LOOP_COUNT; i != 0; i--)                  \
    {                                                                     \
        if (!(READ_REGISTER_UCHAR((pjMmBase) + MEM_CTRL_REG_1) & GLOBAL_BUSY))  \
            break;                                                        \
    }                                                                     \
    if (i == 0)                                                           \
    {                                                                     \
        MM_BLT_CMD_0(ppdev, (pjMmBase), 0);                               \
        MM_WAIT_FOR_IDLE(ppdev, (pjMmBase));                              \
    }                                                                     \
}

//

#define MM_CTRL_REG_1(ppdev, pjMmBase, x)                                 \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_CTRL_REG_1, (UCHAR) (x))

#define MM_DATAPATH_CTRL(ppdev, pjMmBase, x)                              \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_DATAPATH_CTRL, (UCHAR) (x))

#define MM_FG_COLOR(ppdev, pjMmBase, x)                                   \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_FG_COLOR, (UCHAR) (x))

#define MM_BG_COLOR(ppdev, pjMmBase, x)                                   \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_BG_COLOR, (UCHAR) (x))

#define MM_BLT_CMD_0(ppdev, pjMmBase, x)                                  \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_BLT_CMD_0, (UCHAR) (x))

#define MM_BLT_CMD_1(ppdev, pjMmBase, x)                                  \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_BLT_CMD_1, (UCHAR) (x))

#define MM_PREG_COLOR_8(ppdev, pjMmBase, x)                               \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_BROADCAST_COLOR, (UCHAR) (x))

#define MM_PREG_PATTERN(ppdev, pjMmBase, p)                               \
{                                                                         \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_PREG_4, *((ULONG*) (p)));       \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_PREG_0, *((ULONG*) (p) + 1));   \
}

#define MM_PREG_BLOCK(ppdev, pjMmBase, p)                                 \
{                                                                         \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_PREG_0, *((ULONG*) (p)));       \
}

#define MM_BITMAP_WIDTH(ppdev, pjMmBase, x)                               \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_BITMAP_WIDTH, (USHORT) (x))

#define MM_BITMAP_HEIGHT(ppdev, pjMmBase, x)                              \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_BITMAP_HEIGHT, (USHORT) (x))

#define MM_PACKED_HEIGHT_WIDTH(ppdev, pjMmBase, yx)                       \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_BITMAP_HEIGHT, (yx))

#define MM_SRC_LIN(ppdev, pjMmBase, x)                                    \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_SRC_ADDR_LO, (x))

#define MM_SRC_ALIGN(ppdev, pjMmBase, x)                                  \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_SRC_ADDR_LO, (UCHAR) (x))

#define MM_DEST_LIN(ppdev, pjMmBase, x)                                   \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_DEST_ADDR_LO, (x))

/* Note that the pitch is specified in dwords */

#define MM_DEST_PITCH(ppdev, pjMmBase, x)                                 \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_DEST_PITCH, (USHORT) (x))

#define MM_SRC_PITCH(ppdev, pjMmBase, x)                                  \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_SRC_PITCH, (USHORT) (x))

#define MM_ROP_A(ppdev, pjMmBase, x)                                      \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_ROP_A, (UCHAR) (x))

#define MM_K1_CONST(ppdev, pjMmBase, x)                                   \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_K1_CONST, (USHORT) (x))

#define MM_K2_CONST(ppdev, pjMmBase, x)                                   \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_K2_CONST, (USHORT) (x))

#define MM_LINE_PIX_CNT(ppdev, pjMmBase, x)                               \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_LINE_PIX_CNT, (USHORT) (x))

#define MM_LINE_ERR_TERM(ppdev, pjMmBase, x)                              \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_LINE_ERR_TERM, (USHORT) (x))

#define MM_SIGN_CODES(ppdev, pjMmBase, x)                                 \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_SIGN_CODES, (UCHAR) (x))

#define MM_LINE_PATTERN(ppdev, pjMmBase, x)                               \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_LINE_PATTERN, (x))

#define MM_LINE_CMD(ppdev, pjMmBase, x)                                   \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_LINE_CMD, (UCHAR) (x))

#define MM_PIXEL_WRITE_MASK(ppdev, pjMmBase, x)                           \
    WRITE_REGISTER_UCHAR((pjMmBase) + MEM_SEQ_PIXEL_WR_MSK, (UCHAR) (x))

//

#define MM_SRC_XY(ppdev, pjMmBase, x, y)                                  \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_SRC_ADDR_LO,                    \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

#define MM_DEST_XY(ppdev, pjMmBase, x, y)                                 \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_DEST_ADDR_LO,                   \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

#define MM_DEST_X(ppdev, pjMmBase, x)                                     \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_DEST_ADDR_LO,                  \
                          (USHORT) ((x) + (ppdev->xOffset)))

#define MM_DEST_Y(ppdev, pjMmBase, x)                                     \
    WRITE_REGISTER_USHORT((pjMmBase) + MEM_DEST_ADDR_HI,                  \
                          (USHORT) ((x) + (ppdev->yOffset)))

#define MM_X0_Y0(ppdev, pjMmBase, x, y)                                   \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_X0,                             \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

#define MM_X1_Y1(ppdev, pjMmBase, x, y)                                   \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_X1,                             \
        (((y) + ppdev->yOffset) << 16) | ((x) + ppdev->xOffset))

//

#define MM_ABS_SRC_XY(ppdev, pjMmBase, x, y)                              \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_SRC_ADDR_LO, ((y) << 16) | (x))

#define MM_ABS_DEST_XY(ppdev, pjMmBase, x, y)                             \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_DEST_ADDR_LO, ((y) << 16) | (x))

#define MM_ABS_X0_Y0(ppdev, pjMmBase, x, y)                               \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_X0, ((y) << 16) | (x))

#define MM_ABS_X1_Y1(ppdev, pjMmBase, x, y)                               \
    WRITE_REGISTER_ULONG((pjMmBase) + MEM_X1, ((y) << 16) | (x))