示例#1
0
void BankMap_m(LONG BankRead, LONG BankWrite, PVOID Context)
{
    OUTPW( reg1CE, (USHORT)(((BankWrite & 0x0f) << 9) | 0xb2));
    OUTPW( reg1CE, (USHORT)(((BankWrite & 0x30) << 4) | 0xae));

    return;

}   /* BankMap_m() */
示例#2
0
VOID vShowHwPointer (
    BOOL      bShow )

{
    OUTPW(EPR_INDEX, SELECT_CUR | DISABLE_INC);          // select H/W pointer registers
    if (bShow) {
        OUTPW(EPR_DATA, INPW(EPR_DATA) |  CUR_ENABLE);   // enable H/W pointer
    } else {
        OUTPW(EPR_DATA, INPW(EPR_DATA) & ~CUR_ENABLE);   // disable H/W pointer
    } /* endif */
}
示例#3
0
void ResetDevice_m(void)
{

    /*
     * If we are using the VGA aperture on a Mach 32, put its
     * VGA controller into planar mode.
     */
    if (phwDeviceExtension->FrameLength == 0x10000)
        {
        OUTPW(reg1CE, SavedExtRegs[0]);
        OUTPW(reg1CE, SavedExtRegs[1]);
        OUTPW(reg1CE, SavedExtRegs[2]);
        OUTP(reg1CE, 0xBE);
        OUTPW(reg1CE, (WORD)(((INP(reg1CF) & 0xF7) << 8) | 0xBE));
        }
    UninitTiDac_m();
    Passth8514_m(SHOW_VGA);

}   /* ResetDevice_m() */
示例#4
0
/******************************Public*Routine******************************\
* VOID vHwRestoreScreen
*
* Restore screen image from off-screen memory using WD hardware accelerator
*
\**************************************************************************/
VOID vHwRestoreScreen (
    PPDEV     ppdev,
    RECTL    *prclDst,
    ULONG     ulSrc )

{
    ULONG     source, target, direction, width, height;

    //
    // Retrieve the screen image from the off-screen memory
    //
    width = prclDst->right  - prclDst->left;
    height = prclDst->bottom - prclDst->top;

    direction = 0;               // Start BITBLT at top left corner of rectangle
    source = ulSrc;
    target = prclDst->top * ppdev->lDeltaScreen + prclDst->left;

    //
    // Adjust start address if 16bpp mode
    //
    if (ppdev->ulBitCount == 16) {
        target += prclDst->left;
        width  *= 2;
    } /* endif */

    WAIT_BLT_COMPLETE();         // wait for BITBLT completion

    OUTPW(EPR_DATA, BLT_CTRL2  | 0);
    OUTPW(EPR_DATA, BLT_SRC_LO | (USHORT)( source        & 0x0FFF));
    OUTPW(EPR_DATA, BLT_SRC_HI | (USHORT)((source >> 12) & 0x01FF));
    OUTPW(EPR_DATA, BLT_DST_LO | (USHORT)( target        & 0x0FFF));
    OUTPW(EPR_DATA, BLT_DST_HI | (USHORT)((target >> 12) & 0x01FF));
    OUTPW(EPR_DATA, BLT_SIZE_X | (USHORT)width);
    OUTPW(EPR_DATA, BLT_SIZE_Y | (USHORT)height);
    OUTPW(EPR_DATA, BLT_DELTA  | (USHORT)ppdev->lDeltaScreen);
    OUTPW(EPR_DATA, BLT_ROPS   | 0x0300);                      // source copy operation
    OUTPW(EPR_DATA, BLT_PLANE  | 0x00FF);                      // enable all planes
    OUTPW(EPR_DATA, BLT_CTRL1  | 0x0940 | (USHORT)direction ); // start BITBLT

    return;
}
示例#5
0
BOOL bSetHwPointerShape (
    SURFOBJ  *pso,
    SURFOBJ  *psoMask,
    SURFOBJ  *psoColor,
    XLATEOBJ *pxlo,
    LONG      x,
    LONG      y,
    FLONG     fl )

{
    PPDEV     ppdev = (PPDEV) pso->dhpdev;
    PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
    LONG      dx, dy;
    ULONG     cx, cy;
    ULONG     cxSrc, cySrc, cxSrcBytes, cxSrcFraction;
    ULONG     cxDst, cyDst, cxDstBytes;
    LONG      lDeltaSrc, lDeltaDst;
    ULONG     ulOffset;
    PUSHORT   pusPointerPattern;
    PUSHORT   pusDst;
    PBYTE     pjSrcAnd, pjSrcXor, pjSA, pjSX;

    //
    // Check if new pointer is monochrome or not
    //
    if ((psoColor != (SURFOBJ *) NULL) ||
        (!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER))) {
        return FALSE;
    } /* endif */

    //
    // Check if the size of new pointer is smaller than hardware capability
    //
    cxSrc = psoMask->sizlBitmap.cx;
    cySrc = psoMask->sizlBitmap.cy >> 1;
    cxSrcBytes = (cxSrc + 7) / 8;
    cxSrcFraction = cxSrc % 8;               // Number of fractional pels

    cxDst = ppdev->PointerCapabilities.MaxWidth;
    cyDst = ppdev->PointerCapabilities.MaxHeight;
    cxDstBytes = (cxDst + 7) / 8;

    if ((cxSrc > cxDst) ||
        (cySrc > cyDst) ||
        (!(psoMask->fjBitmap & BMF_TOPDOWN))) {
        return FALSE;
    } /* endif */

    //
    // Update the attributes of pointer
    //
    pPointerAttributes->Flags |=  VIDEO_MODE_MONO_POINTER;
    pPointerAttributes->Flags &= ~VIDEO_MODE_COLOR_POINTER;
    pPointerAttributes->Width  = cxSrc;
    pPointerAttributes->Height = cySrc;
    pPointerAttributes->WidthInBytes = cxSrcBytes;

    //
    // Set entire pointer pattern area as transparent
    //
    // Before accessing to the off-screen memory, wait for a while until on-going
    // BITBLT completes.
    //
    ulOffset = ppdev->cyScreen * ppdev->lDeltaScreen;
    ulOffset += 64;              // skip over solid color pattern used in bitblt.c
    pusPointerPattern = (PUSHORT)(ppdev->pjScreen + ulOffset);

    WAIT_BLT_COMPLETE();         // wait for BITBLT completion

    pusDst = pusPointerPattern;
    for (cy = 0; cy < cyDst; cy++) {
        for (cx = 0; cx < cxDstBytes; cx++) {
            *pusDst++ = 0x00FF;
        } /* endfor */
    } /* endfor */

    //
    // Load new pointer pattern in the off-screen memory
    //
    pjSrcAnd = psoMask->pvBits;
    pjSrcXor = pjSrcAnd + cySrc * (ULONG) psoMask->lDelta;
    lDeltaSrc = psoMask->lDelta;
    lDeltaDst = cxDstBytes;

    for (cy = 0; cy < cySrc; cy++) {
        pusDst = pusPointerPattern;
        pjSA = pjSrcAnd;
        pjSX = pjSrcXor;

        //
        // Interleave AND and XOR bytes
        //
        for (cx = 0; cx < (cxSrcBytes - 1); cx++) {
            *pusDst++ = ( (*pjSA++ & 0x00ff) |
                         ((*pjSX++ & 0x00ff) << 8));
        } /* endfor */

        //
        // Mask off the right edge if bitmap width is not a multiple of 8
        //
        *pusDst++ = ( (*pjSA++ |  gajMask[cxSrcFraction]) |
                     ((*pjSX++ & ~gajMask[cxSrcFraction]) << 8));

        pusPointerPattern += lDeltaDst;
        pjSrcAnd += lDeltaSrc;
        pjSrcXor += lDeltaSrc;
    } /* endfor */

    //
    // Set hardware cursor registers
    //
    dx = ppdev->ptlHotSpot.x;
    dy = ppdev->ptlHotSpot.y;

    OUTPW(EPR_INDEX, SELECT_CUR | DISABLE_INC);          // select H/W pointer registers
    OUTPW(EPR_DATA, CUR_ORIGIN  | (USHORT)((dy << 6) | dx));
    OUTPW(EPR_DATA, CUR_PAT_LO  | (USHORT)(ulOffset >>  2) & 0x0FFF);
    OUTPW(EPR_DATA, CUR_PAT_HI  | (USHORT)(ulOffset >> 14) & 0x00FF);
    OUTPW(EPR_DATA, CUR_PRI_CLR | 0xFF);
    OUTPW(EPR_DATA, CUR_SEC_CLR | 0);
    OUTPW(EPR_DATA, INPW(EPR_DATA) | 0x0220);

    return TRUE;
}
示例#6
0
文件: 8514a.c 项目: Gaikokujin/WinNT4
BOOLEAN
A8514StartIO(
    PVOID HwDeviceExtension,
    PVIDEO_REQUEST_PACKET RequestPacket
    )

/*++

Routine Description:

    This routine is the main execution routine for the miniport driver. It
    accepts a Video Request Packet, performs the request, and then returns
    with the appropriate status.

Arguments:

    HwDeviceExtension - Supplies a pointer to the miniport's device extension.

    RequestPacket - Pointer to the video request packet. This structure
        contains all the parameters passed to the VideoIoControl function.

Return Value:


--*/

{
    PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
    VP_STATUS status;
    PVIDEO_MODE_INFORMATION modeInformation;
    PVIDEO_MEMORY_INFORMATION memoryInformation;
    PVIDEO_CLUT clutBuffer;
    ULONG modeNumber;
    VIDEO_MODE_INFORMATION A8514ModeInformation =
    {
        sizeof(VIDEO_MODE_INFORMATION), // Size of the mode informtion structure
        0,                              // Mode index used in setting the mode
        1024,                           // X Resolution, in pixels
        768,                            // Y Resolution, in pixels
        1024,                           // Screen stride, in bytes (distance
                                        // between the start point of two
                                        // consecutive scan lines, in bytes)
        1,                              // Number of video memory planes
        8,                              // Number of bits per plane
        1,                              // Screen Frequency, in Hertz
        320,                            // Horizontal size of screen in millimeters
        240,                            // Vertical size of screen in millimeters
        6,                              // Number Red pixels in DAC
        6,                              // Number Green pixels in DAC
        6,                              // Number Blue pixels in DAC
        0x00000000,                     // Mask for Red Pixels in non-palette modes
        0x00000000,                     // Mask for Green Pixels in non-palette modes
        0x00000000,                     // Mask for Blue Pixels in non-palette modes
        VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS | VIDEO_MODE_PALETTE_DRIVEN |
          VIDEO_MODE_MANAGED_PALETTE, // Mode description flags.
        1024,                           // Video Memory Bitmap Width
        1024                            // Video Memory Bitmap Height
    };

    //
    // Assume we'll succeed.
    //

    status = NO_ERROR;

    //
    // Switch on the IoContolCode in the RequestPacket. It indicates which
    // function must be performed by the driver.
    //

    switch (RequestPacket->IoControlCode) {


    case IOCTL_VIDEO_MAP_VIDEO_MEMORY:

        VideoDebugPrint((2, "A8514tartIO - MapVideoMemory\n"));

        if ( (RequestPacket->OutputBufferLength <
              (RequestPacket->StatusBlock->Information =
                                     sizeof(VIDEO_MEMORY_INFORMATION))) ||
             (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {

            status = ERROR_INSUFFICIENT_BUFFER;
            break;
        }

        memoryInformation = RequestPacket->OutputBuffer;

        //
        // The only field we need to fill is VideoRamLength.  With this
        // miniport, we support only one meg 8514/A's:
        //

        memoryInformation->VideoRamLength    = 0x100000;
        memoryInformation->FrameBufferBase   = NULL;
        memoryInformation->FrameBufferLength = 0;

        break;


    case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:

        break;


    case IOCTL_VIDEO_QUERY_AVAIL_MODES:

        VideoDebugPrint((2, "A8514StartIO - QueryAvailableModes\n"));

        if (RequestPacket->OutputBufferLength <
            (RequestPacket->StatusBlock->Information =
                 sizeof(VIDEO_MODE_INFORMATION)) ) {

            status = ERROR_INSUFFICIENT_BUFFER;

        } else {

            modeInformation = RequestPacket->OutputBuffer;

            *modeInformation = A8514ModeInformation;
        }

        break;


     case IOCTL_VIDEO_QUERY_CURRENT_MODE:

        VideoDebugPrint((2, "A8514StartIO - QueryCurrentModes\n"));

        if (RequestPacket->OutputBufferLength <
            (RequestPacket->StatusBlock->Information =
            sizeof(VIDEO_MODE_INFORMATION)) ) {

            status = ERROR_INSUFFICIENT_BUFFER;

        } else {

            *((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer) =
                A8514ModeInformation;

        }

        break;


    case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:

        VideoDebugPrint((2, "A8514StartIO - QueryNumAvailableModes\n"));

        //
        // Find out the size of the data to be put in the the buffer and
        // return that in the status information (whether or not the
        // information is there). If the buffer passed in is not large
        // enough return an appropriate error code.
        //

        if (RequestPacket->OutputBufferLength <
                (RequestPacket->StatusBlock->Information =
                                                sizeof(VIDEO_NUM_MODES)) ) {

            status = ERROR_INSUFFICIENT_BUFFER;

        } else {

            ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes = 1;

            ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->ModeInformationLength =
                sizeof(VIDEO_MODE_INFORMATION);

        }

        break;


    case IOCTL_VIDEO_SET_CURRENT_MODE:

        VideoDebugPrint((2, "A8514StartIO - SetCurrentMode\n"));

        //
        // Check if the size of the data in the input buffer is large enough.
        //

        if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) {

            status = ERROR_INSUFFICIENT_BUFFER;
            break;

        }

        //
        // Check to see if we are requesting a valid mode
        //

        modeNumber = ((PVIDEO_MODE) RequestPacket->InputBuffer)->RequestedMode;

        if (modeNumber >= 1) {

            status = ERROR_INVALID_PARAMETER;
            break;

        }

        //
        // Reset the draw engine.
        //

        OUTPW(hwDeviceExtension, INDEX_SUBSYS_CNTL,   0x9000);
        OUTPW(hwDeviceExtension, INDEX_SUBSYS_CNTL,   0x5000);

        //
        // Mode setting courtesy of p. 2-2, "Programmer's Guide to the
        // Mach-8 Extended Registers Supplement, Technical Reference
        // Manuals," ATI Technologies Inc., 1992 and pp 276-278, "Graphics
        // Programming for the 8514/A," Jake Richter and Bud Smith, M & T
        // Publishing, 1990.
        //

        OUTPW(hwDeviceExtension, INDEX_DISP_CNTL,     0x0053);
        OUTPW(hwDeviceExtension, INDEX_H_TOTAL,       0x009d);
        OUTPW(hwDeviceExtension, INDEX_H_DISP,        0x007f);
        OUTPW(hwDeviceExtension, INDEX_H_SYNC_STRT,   0x0081);
        OUTPW(hwDeviceExtension, INDEX_H_SYNC_WID,    0x0016);
        OUTPW(hwDeviceExtension, INDEX_V_TOTAL,       0x0660);
        OUTPW(hwDeviceExtension, INDEX_V_DISP,        0x05fb);
        OUTPW(hwDeviceExtension, INDEX_V_SYNC_STRT,   0x0600);
        OUTPW(hwDeviceExtension, INDEX_V_SYNC_WID,    0x0008);
        OUTPW(hwDeviceExtension, INDEX_ADVFUNC_CNTL,  0x0007);
        OUTPW(hwDeviceExtension, INDEX_DISP_CNTL,     0x0033);

        OUTPW(hwDeviceExtension, INDEX_MEM_CNTL,      0x500c);

        OUTP(hwDeviceExtension,  INDEX_DAC_MASK,      0xff);

        //
        // Initialize some drawing registers.
        //

        while (INPW(hwDeviceExtension, INDEX_GE_STAT) & FIFO_6_EMPTY)
            ;

        OUTPW(hwDeviceExtension, INDEX_PIX_CNTL,      0x5006);
        OUTPW(hwDeviceExtension, INDEX_SCISSORS_T,    0x1000);
        OUTPW(hwDeviceExtension, INDEX_SCISSORS_L,    0x2000);
        OUTPW(hwDeviceExtension, INDEX_SCISSORS_B,    0x35ff);
        OUTPW(hwDeviceExtension, INDEX_SCISSORS_R,    0x45ff);
        OUTPW(hwDeviceExtension, INDEX_WRT_MASK,      0xff);

        //
        // Black out the screen so that we don't display garbage until the
        // display driver has a chance to clear everything.
        //

        while (INPW(hwDeviceExtension, INDEX_GE_STAT) & FIFO_7_EMPTY)
            ;

        OUTPW(hwDeviceExtension, INDEX_PIX_CNTL,      0xa000); // ALL_ONES
        OUTPW(hwDeviceExtension, INDEX_FRGD_MIX,      0x0001); // LOGICAL_0
        OUTPW(hwDeviceExtension, INDEX_CUR_X,         0);
        OUTPW(hwDeviceExtension, INDEX_CUR_Y,         0);
        OUTPW(hwDeviceExtension, INDEX_MAJ_AXIS_PCNT, 0x05ff);
        OUTPW(hwDeviceExtension, INDEX_MIN_AXIS_PCNT, 0x05ff);
        OUTPW(hwDeviceExtension, INDEX_CMD,           0x40b3);
                // ( RECTANGLE_FILL | DRAWING_DIR_TBLRXM | DRAW |
                //   MULTIPLE_PIXELS | WRITE )

        break;

    case IOCTL_VIDEO_SET_COLOR_REGISTERS:

        VideoDebugPrint((2, "A8514StartIO - SetColorRegs\n"));

        clutBuffer = RequestPacket->InputBuffer;

        status = A8514SetColorLookup(HwDeviceExtension,
                                   (PVIDEO_CLUT) RequestPacket->InputBuffer,
                                   RequestPacket->InputBufferLength);
        break;


    case IOCTL_VIDEO_RESET_DEVICE:

        VideoDebugPrint((2, "A8514StartIO - RESET_DEVICE\n"));

        //
        // Wait for the 8514/A graphics engine to become idle.
        //

        while (INPW(hwDeviceExtension, INDEX_GE_STAT) & 0x0200);

        //
        // Enable VGA pass-through.
        //

        OUTPW(hwDeviceExtension, INDEX_ADVFUNC_CNTL, 0x0006);

        break;

    //
    // if we get here, an invalid IoControlCode was specified.
    //

    default:

        VideoDebugPrint((1, "Fell through A8514 startIO routine - invalid command\n"));

        status = ERROR_INVALID_FUNCTION;

        break;

    }

    VideoDebugPrint((2, "Leaving A8514 startIO routine\n"));

    RequestPacket->StatusBlock->Status = status;

    return TRUE;

} // end A8514StartIO()
示例#7
0
文件: 8514a.c 项目: Gaikokujin/WinNT4
VP_STATUS
A8514FindAdapter(
    PVOID HwDeviceExtension,
    PVOID HwContext,
    PWSTR ArgumentString,
    PVIDEO_PORT_CONFIG_INFO ConfigInfo,
    PUCHAR Again
    )

/*++

Routine Description:

    This routine is called to determine if the adapter for this driver
    is present in the system.
    If it is present, the function fills out some information describing
    the adapter.

Arguments:

    HwDeviceExtension - Supplies the miniport driver's adapter storage. This
        storage is initialized to zero before this call.

    HwContext - Supplies the context value which was passed to
        VideoPortInitialize().

    ArgumentString - Suuplies a NULL terminated ASCII string. This string
        originates from the user.

    ConfigInfo - Returns the configuration information structure which is
        filled by the miniport driver. This structure is initialized with
        any knwon configuration information (such as SystemIoBusNumber) by
        the port driver. Where possible, drivers should have one set of
        defaults which do not require any supplied configuration information.

    Again - Indicates if the miniport driver wants the port driver to call
        its VIDEO_HW_FIND_ADAPTER function again with a new device extension
        and the same config info. This is used by the miniport drivers which
        can search for several adapters on a bus.

Return Value:

    This routine must return:

    NO_ERROR - Indicates a host adapter was found and the
        configuration information was successfully determined.

    ERROR_INVALID_PARAMETER - Indicates an adapter was found but there was an
        error obtaining the configuration information. If possible an error
        should be logged.

    ERROR_DEV_NOT_EXIST - Indicates no host adapter was found for the
        supplied configuration information.

--*/

{

    PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
    ULONG i;
    VP_STATUS status;

    USHORT SubSysCntlRegisterValue;
    USHORT ErrTermRegisterValue;
    USHORT SubSysStat;
    USHORT ErrTerm5555;
    USHORT ErrTermAAAA;

    VIDEO_ACCESS_RANGE accessRange[] = {
        { PORT_H_TOTAL,         0, 2, 1, 1, 0}, // INDEX_H_TOTAL
        { PORT_H_DISP,          0, 2, 1, 1, 0}, // INDEX_H_DISP
        { PORT_H_SYNC_STRT,     0, 2, 1, 1, 0}, // INDEX_H_SYNC_STRT
        { PORT_H_SYNC_WID,      0, 2, 1, 1, 0}, // INDEX_H_SYNC_WID
        { PORT_V_TOTAL,         0, 2, 1, 1, 0}, // INDEX_V_TOTAL
        { PORT_V_DISP,          0, 2, 1, 1, 0}, // INDEX_V_DISP
        { PORT_V_SYNC_STRT,     0, 2, 1, 1, 0}, // INDEX_V_SYNC_STRT
        { PORT_V_SYNC_WID,      0, 2, 1, 1, 0}, // INDEX_V_SYNC_WID
        { PORT_ADVFUNC_CNTL,    0, 2, 1, 1, 0}, // INDEX_ADVFUNC_CNTL
        { PORT_MEM_CNTL,        0, 2, 1, 1, 0}, // INDEX_MEM_CNTL
        { PORT_DAC_MASK,        0, 2, 1, 1, 0}, // INDEX_DAC_MASK
        { PORT_SUBSYS_CNTL,     0, 2, 1, 1, 0}, // INDEX_SUBSYS_CNTL
        { PORT_DISP_CNTL,       0, 2, 1, 1, 0}, // INDEX_DISP_CNTL
        { PORT_SUBSYS_STATUS,   0, 2, 1, 1, 0}, // INDEX_SUBSYS_STATUS
        { PORT_GE_STAT,         0, 2, 1, 1, 0}, // INDEX_GE_STAT
        { PORT_DAC_W_INDEX,     0, 2, 1, 1, 0}, // INDEX_DAC_W_INDEX
        { PORT_DAC_DATA,        0, 2, 1, 1, 0}, // INDEX_DAC_DATA
        { PORT_CUR_Y,           0, 2, 1, 1, 0}, // INDEX_CUR_Y
        { PORT_CUR_X,           0, 2, 1, 1, 0}, // INDEX_CUR_X
        { PORT_DEST_Y,          0, 2, 1, 1, 0}, // INDEX_DEST_Y
        { PORT_DEST_X,          0, 2, 1, 1, 0}, // INDEX_DEST_X
        { PORT_AXSTP,           0, 2, 1, 1, 0}, // INDEX_AXSTP
        { PORT_DIASTP,          0, 2, 1, 1, 0}, // INDEX_DIASTP
        { PORT_ERR_TERM,        0, 2, 1, 1, 0}, // INDEX_ERR_TERM
        { PORT_MAJ_AXIS_PCNT,   0, 2, 1, 1, 0}, // INDEX_MAJ_AXIS_PCNT
        { PORT_CMD,             0, 2, 1, 1, 0}, // INDEX_CMD
        { PORT_SHORT_STROKE,    0, 2, 1, 1, 0}, // INDEX_SHORT_STROKE
        { PORT_BKGD_COLOR,      0, 2, 1, 1, 0}, // INDEX_BKGD_COLOR
        { PORT_FRGD_COLOR,      0, 2, 1, 1, 0}, // INDEX_FRGD_COLOR
        { PORT_WRT_MASK,        0, 2, 1, 1, 0}, // INDEX_WRT_MASK
        { PORT_RD_MASK,         0, 2, 1, 1, 0}, // INDEX_RD_MASK
        { PORT_COLOR_CMP,       0, 2, 1, 1, 0}, // INDEX_COLOR_CMP
        { PORT_BKGD_MIX,        0, 2, 1, 1, 0}, // INDEX_BKGD_MIX
        { PORT_FRGD_MIX,        0, 2, 1, 1, 0}, // INDEX_FRGD_MIX
        { PORT_MULTIFUNC_CNTL,  0, 2, 1, 1, 0}, // INDEX_MULTIFUNC_CNTL
        { PORT_MIN_AXIS_PCNT,   0, 2, 1, 1, 0}, // INDEX_MIN_AXIS_PCNT
        { PORT_SCISSORS_T,      0, 2, 1, 1, 0}, // INDEX_SCISSORS_T
        { PORT_SCISSORS_L,      0, 2, 1, 1, 0}, // INDEX_SCISSORS_L
        { PORT_SCISSORS_B,      0, 2, 1, 1, 0}, // INDEX_SCISSORS_B
        { PORT_SCISSORS_R,      0, 2, 1, 1, 0}, // INDEX_SCISSORS_R
        { PORT_PIX_CNTL,        0, 2, 1, 1, 0}, // INDEX_PIX_CNTL
        { PORT_PIX_TRANS,       0, 2, 1, 1, 0}  // INDEX_PIX_TRANS
    };

    VideoDebugPrint((2, "8514/A: Running A8514FindAdapter\n"));

    //
    // Make sure the size of the structure is at least as large as what we
    // are expecting (check version of the config info structure).
    //

    if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {

        return (ERROR_INVALID_PARAMETER);

    }

    //
    // Check to see if there is a hardware resource conflict.
    //

    status = VideoPortVerifyAccessRanges(hwDeviceExtension,
                                         NUM_A8514_ACCESS_RANGES,
                                         accessRange);

    if (status != NO_ERROR) {

        VideoDebugPrint((1, "8514/A: Access Range conflict\n"));
        return status;

    }

    //
    // Get the mapped addresses for all the registers.
    //

    for (i = 0; i < NUM_A8514_ACCESS_RANGES; i++) {

        if ( (hwDeviceExtension->MappedAddress[i] =
                  VideoPortGetDeviceBase(hwDeviceExtension,
                                         accessRange[i].RangeStart,
                                         accessRange[i].RangeLength,
                                         accessRange[i].RangeInIoSpace)) == NULL) {

            VideoDebugPrint((1, "8514/A: DeviceBase mapping failed\n"));
            return ERROR_INVALID_PARAMETER;

        }
    }

    //
    // Remember the original value of any registers we'll muck with.
    //

    SubSysCntlRegisterValue = INPW(hwDeviceExtension, INDEX_SUBSYS_CNTL);
    ErrTermRegisterValue = INPW(hwDeviceExtension, INDEX_ERR_TERM);

    //
    // Reset the draw engine.
    //

    OUTPW(hwDeviceExtension, INDEX_SUBSYS_CNTL, 0x9000);
    OUTPW(hwDeviceExtension, INDEX_SUBSYS_CNTL, 0x5000);

    //
    // We detect an 8514/A by writing a value to the error term register,
    // and reading it back to see if it's the same value we wrote.
    //

    OUTPW(hwDeviceExtension, INDEX_ERR_TERM, 0x5555);
    ErrTerm5555 = INPW(hwDeviceExtension, INDEX_ERR_TERM);

    OUTPW(hwDeviceExtension, INDEX_ERR_TERM, 0xAAAA);
    ErrTermAAAA = INPW(hwDeviceExtension, INDEX_ERR_TERM);

    if ((ErrTerm5555 != 0x5555) || (ErrTermAAAA != 0xAAAA))
    {
        //
        // It's not an 8514/A, so we'd better try to restore the registers'
        // original values.
        //

        OUTPW(hwDeviceExtension, INDEX_ERR_TERM, ErrTermRegisterValue);
        OUTPW(hwDeviceExtension, INDEX_SUBSYS_CNTL, SubSysCntlRegisterValue);

        VideoDebugPrint((2, "8514/A: No 8514/A was detected\n"));
        return ERROR_DEV_NOT_EXIST;
    }

    VideoDebugPrint((2, "8514/A: An 8514/A was detected\n"));

    SubSysStat = INPW(hwDeviceExtension, INDEX_SUBSYS_STATUS);

    //
    // Now that we're done mucking with the hardware state, we have to
    // restore everything to the way it was.
    //

    OUTPW(hwDeviceExtension, INDEX_ERR_TERM, ErrTermRegisterValue);
    OUTPW(hwDeviceExtension, INDEX_SUBSYS_CNTL, SubSysCntlRegisterValue);

    //
    // Okay, we're probably running on an 8514/A.  See if there's one
    // meg of memory, because that's all we support.
    //

    if ((SubSysStat & 0x80) == 0)
    {
        VideoPortLogError(hwDeviceExtension,
                          NULL,
                          A8514_NOT_ENOUGH_VRAM,
                          __LINE__);


        VideoDebugPrint((2, "8514/A: Not enough memory\n"));
        return ERROR_INVALID_PARAMETER;
    }

    //
    // We have this so that the int10 will also work on the VGA also if we
    // use it in this driver.
    //

    ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart  = 0x000A0000;
    ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
    ConfigInfo->VdmPhysicalVideoMemoryLength           = 0x00020000;

    //
    // Clear out the Emulator entries and the state size since this driver
    // does not support them.
    //

    ConfigInfo->NumEmulatorAccessEntries     = 0;
    ConfigInfo->EmulatorAccessEntries        = NULL;
    ConfigInfo->EmulatorAccessEntriesContext = 0;

    //
    // This driver does not do SAVE/RESTORE of hardware state.
    //

    ConfigInfo->HardwareStateSize = 0;

    //
    // Indicate we do not wish to be called over
    //

    *Again = 0;

    //
    // Indicate a successful completion status.
    //

    return NO_ERROR;

} // end A8514FindAdapter()
示例#8
0
void SetCurrentMode_m(struct query_structure *QueryPtr, struct st_mode_table *CrtTable)
{
    WORD MiscOptions;   /* Contents of MISC_OPTIONS register */
    USHORT Scratch;     /* Temporary variable */

    /*
     * Put the DAC in a known state before we start.
     */
    UninitTiDac_m();

    Passth8514_m(SHOW_ACCEL);    // turn vga pass through off

    /*
     * On cards with the "MISC_OPTIONS doesn't report video memory size
     * correctly" bug, reset MISC_OPTIONS to show the true amount of
     * video memory. This is done here rather than when we determine
     * how much memory is present in order to avoid trashing the "blue
     * screen" (no adverse effects on operation, but would generate
     * large numbers of user complaints).
     */
    if (((QueryPtr->q_asic_rev == CI_68800_6) || (QueryPtr->q_asic_rev == CI_68800_AX)) &&
        (QueryPtr->q_VGA_type == 1) &&
        ((QueryPtr->q_memory_type == VMEM_DRAM_256Kx4) ||
         (QueryPtr->q_memory_type == VMEM_DRAM_256Kx16) ||
         (QueryPtr->q_memory_type == VMEM_DRAM_256Kx4_GRAP)))
        {
        MiscOptions = INPW(MISC_OPTIONS) & MEM_SIZE_STRIPPED;

        switch (QueryPtr->q_memory_size)
            {
            case VRAM_512k:
                MiscOptions |= MEM_SIZE_512K;
                break;

            case VRAM_1mb:
                MiscOptions |= MEM_SIZE_1M;
                break;

            case VRAM_2mb:
                MiscOptions |= MEM_SIZE_2M;
                break;

            case VRAM_4mb:
                MiscOptions |= MEM_SIZE_4M;
                break;
            }
        OUTPW(MISC_OPTIONS, MiscOptions);
        }

    setmode_m(CrtTable, (ULONG) &(phwDeviceExtension->RomBaseRange), (ULONG) phwDeviceExtension->ModelNumber);

    /*
     * On a Mach 8 card, 1280x1024 can only be done in split
     * pixel mode. If we are running on a Mach 8, and this
     * resolution was selected, go into split pixel mode.
     *
     * Bit 4 of EXT_GE_CONFIG is set for split pixel mode and
     * clear for normal mode. Bit 3 must be set, since clearing
     * it accesses EEPROM read/write mode.
     */
    if    ((phwDeviceExtension->ModelNumber == _8514_ULTRA)
        || (phwDeviceExtension->ModelNumber == GRAPHICS_ULTRA))
        {
        if (QueryPtr->q_desire_x == 1280)
                OUTPW(EXT_GE_CONFIG, 0x0018);
        else    OUTPW(EXT_GE_CONFIG, 0x0008);
        }

    /*
     * Default to 8 bits per pixel. Modes which require a different
     * setting will change this in the init_ti_<depth>_m() function.
     */
    OUTP(DAC_MASK, 0xff);

    if (phwDeviceExtension->ModelNumber == MACH32_ULTRA)
        {
        switch (CrtTable->m_pixel_depth)    // program the DAC for the
            {                               // other resolutions
            case 4:
            case 8:
                InitTi_8_m((WORD)(CrtTable->ColourDepthInfo | 0x0a));
                break;

            case 16:
                InitTi_16_m((WORD)(CrtTable->ColourDepthInfo | 0x0a), (ULONG) &(phwDeviceExtension->RomBaseRange));   /* 16 bit 565 */
                break;

            case 24:
            case 32:
                /*
                 * RGB/BGR and 24/32 bit mode information is
                 * stored in CrtTable->ColourDepthInfo.
                 */
                InitTi_24_m((WORD)(CrtTable->ColourDepthInfo | 0x0a), (ULONG) &(phwDeviceExtension->RomBaseRange));
                break;
            }
        }

    /*
     * If we are going to be using the VGA aperture on a Mach 32,
     * initialize the bank manager by saving the ATI extended register
     * values and putting the VGA controller into packed pixel mode.
     *
     * We can't identify this case by looking at
     * phwDeviceExtension->FrameLength because it is set to 0x10000
     * when the VGA aperture is being used in the
     * IOCTL_VIDEO_MAP_VIDEO_MEMORY packet which may or may not
     * have been called by the time we reach this point.
     */
    if ((phwDeviceExtension->ModelNumber == MACH32_ULTRA) &&
        (QueryPtr->q_aperture_cfg == 0) &&
        (QueryPtr->q_VGA_type == 1))
        {
        for (Scratch = 0; Scratch <= 2; Scratch++)
            {
            OUTP(reg1CE, (BYTE)(SavedExtRegs[Scratch] & 0x00FF));
            SavedExtRegs[Scratch] = (SavedExtRegs[Scratch] & 0x00FF) | (INP(reg1CF) << 8);
            }
        OUTPW(HI_SEQ_ADDR, 0x0F02);
        OUTPW(HI_SEQ_ADDR, 0x0A04);
        OUTPW(reg3CE, 0x1000);
        OUTPW(reg3CE, 0x0001);
        OUTPW(reg3CE, 0x0002);
        OUTPW(reg3CE, 0x0003);
        OUTPW(reg3CE, 0x0004);
        OUTPW(reg3CE, 0x0005);
        OUTPW(reg3CE, 0x0506);
        OUTPW(reg3CE, 0x0F07);
        OUTPW(reg3CE, 0xFF08);
        OUTPW(reg1CE, 0x28B0);  /* Enable 256 colour, 1M video RAM */
        OUTPW(reg1CE, 0x04B6);  /* Select linear addressing */
        OUTP(reg1CE, 0xBE);
        OUTPW(reg1CE, (WORD)(((INP(reg1CF) & 0xF7) << 8) | 0xBE));
        }


    /*
     * phwDeviceExtension->ReInitializing becomes TRUE in
     * IOCTL_VIDEO_SET_COLOR_REGISTERS packet of ATIMPStartIO().
     *
     * If this is not the first time we are switching into graphics
     * mode, set the palette to the last set of colours that was
     * selected while in graphics mode.
     */
    if (phwDeviceExtension->ReInitializing)
        {
        SetPalette_m(phwDeviceExtension->Clut,
                     phwDeviceExtension->FirstEntry,
                     phwDeviceExtension->NumEntries);
        }

    /*
     * Clear visible screen.
     *
     * 24 and 32 BPP would require a q_desire_y value beyond the
     * maximum allowable clipping value (1535) if we clear the screen
     * using a normal blit. Since these pixel depths are only supported
     * up to 800x600, we can fake it by doing a 16BPP blit of double the
     * screen height, clipping the special case of 640x480 24BPP on
     * a 1M card (this is the only true colour mode that will fit in
     * 1M, so if we hit this case on a 1M card, we know which mode
     * we're dealing with) to avoid running off the end of video memory.
     */
    if (CrtTable->m_pixel_depth >= 24)
        {
        /*
         * Save the colour depth configuration and switch into 16BPP
         */
        Scratch = INPW(R_EXT_GE_CONFIG);
        OUTPD(EXT_GE_CONFIG, (Scratch & 0xFFCF) | PIX_WIDTH_16BPP);

        CheckFIFOSpace_m(SIXTEEN_WORDS);

        OUTPW(DP_CONFIG, 0x2011);
        OUTPW(ALU_FG_FN, 0x7);          // Paint 
        OUTPW(FRGD_COLOR, 0);	        // Black 
        OUTPW(CUR_X, 0);
        OUTPW(CUR_Y, 0);
        OUTPW(DEST_X_START, 0);
        OUTPW(DEST_X_END, QueryPtr->q_desire_x);

        if (QueryPtr->q_memory_size == VRAM_1mb)
            OUTPW(DEST_Y_END, 720);     /* Only 640x480 24BPP will fit in 1M */
        else
            OUTPW(DEST_Y_END, (WORD)(2*(QueryPtr->q_desire_y)));

        /*
         * Let the blit finish then restore the colour depth configuration
         */
        WaitForIdle_m();
        OUTPD(EXT_GE_CONFIG, Scratch);

        }
    else{
        /*
         * Other colour depths can be handled by a normal blit, and the
         * LFB may not be available, so use a blit to clear the screen.
         */
        CheckFIFOSpace_m(SIXTEEN_WORDS);

        OUTPW(DP_CONFIG, 0x2011);
        OUTPW(ALU_FG_FN, 0x7);          // Paint 
        OUTPW(FRGD_COLOR, 0);	        // Black 
        OUTPW(CUR_X, 0);
        OUTPW(CUR_Y, 0);
        OUTPW(DEST_X_START, 0);
        OUTPW(DEST_X_END, QueryPtr->q_desire_x);
        OUTPW(DEST_Y_END, QueryPtr->q_desire_y);
        }

#if 0
    /*
     * In 800x600 24BPP, set the offset to start 1 pixel into video
     * memory to avoid screen tearing. The MAP_VIDEO_MEMORY packet
     * must adjust the framebuffer base to compensate for this.
     */
    if ((QueryPtr->q_desire_x == 800) && (QueryPtr->q_pix_depth == 24))
        {
        OUTPW(CRT_OFFSET_LO, 3);
        }
    else
        {
        OUTPW(CRT_OFFSET_HI, 0);
        }
#endif

    WaitForIdle_m();

    return;

}   /* SetCurrentMode_m() */
示例#9
0
void Initialize_m(void)
{
    /*
     * Make sure we have enough available FIFO entries
     * to initialize the card.
     */
    CheckFIFOSpace_m(SIXTEEN_WORDS);

    /*
     * On the 68800, set the memory boundary to shared VGA memory.
     * On all cards, set the screen and drawing engine to start
     * at the beginning of accelerator memory and MEM_CNTL
     * to linear.
     */
    if (phwDeviceExtension->ModelNumber == MACH32_ULTRA)
        OUTP (MEM_BNDRY,0);

    OUTPW(CRT_OFFSET_LO, 0);
    OUTPW(GE_OFFSET_LO,  0);
    OUTPW(CRT_OFFSET_HI, 0);
    OUTPW(GE_OFFSET_HI,  0);
    OUTPW(MEM_CNTL,0x5006);

    /*
     * Reset the engine and FIFO, then return to normal operation.
     */
    OUTPW(SUBSYS_CNTL,0x9000);
    OUTPW(SUBSYS_CNTL,0x5000);

    /*
     * The hardware cursor is available only for Mach 32 cards.
     * disable the cursor and initialize it to display quadrant I - 0
     */
    if (phwDeviceExtension->ModelNumber == MACH32_ULTRA)
        {
        OUTPW(CURSOR_OFFSET_HI,0);

        OUTPW(HORZ_CURSOR_OFFSET,0);
        OUTP(VERT_CURSOR_OFFSET,0);
        OUTPW(CURSOR_COLOR_0, 0x0FF00);         /* Colour 0 black, colour 1 white */
        OUTPW(EXT_CURSOR_COLOR_0,0);	// black
        OUTPW(EXT_CURSOR_COLOR_1,0xffff);	// white
        }

    return;

}   /* Initialize_m() */
示例#10
0
void AlphaInit_m(void)
{
    OUTPW(MEM_CFG, 0);
    DEC_DELAY
    OUTPW(MISC_OPTIONS, 0xb0a9);
    DEC_DELAY
    OUTPW(MEM_BNDRY, 0);
    DEC_DELAY
#if 0
    OUTPW(CONFIG_STATUS_1, 0x1410);
    DEC_DELAY
    OUTPW(SCRATCH_PAD_1, 0);
    DEC_DELAY
    OUTPW(SCRATCH_PAD_0, 0);
    DEC_DELAY
#endif
    OUTPW(CLOCK_SEL, 0x250);
    DEC_DELAY
    OUTPW(DAC_W_INDEX, 0x40);
    DEC_DELAY
    OUTPW(MISC_CNTL, 0xC00);
    DEC_DELAY
    OUTPW(LOCAL_CONTROL, 0x1402);
#if defined (MIPS) || defined (_MIPS_)
    DEC_DELAY
    OUTPW(OVERSCAN_COLOR_8, 0);    //RKE: to eliminate left overscan on MIPS
#endif
    DEC_DELAY

    return;

}   /* AlphaInit_m() */
示例#11
0
VP_STATUS SetPowerManagement_m(struct query_structure *QueryPtr, DWORD DpmsState)
{
    struct st_mode_table *CrtTable; /* Mode table, used to obtain sync values */

    /*
     * Only accept valid states.
     */
    if ((DpmsState < VideoPowerOn) || (DpmsState > VideoPowerOff))
        return ERROR_INVALID_PARAMETER;

    /*
     * Set CrtTable to point to the mode table associated with the
     * selected mode. 
     *
     * When a pointer to a structure is incremented by an integer,
     * the integer represents the number of structure-sized blocks
     * to skip over, not the number of bytes to skip over.
     */
    CrtTable = (struct st_mode_table *)QueryPtr;
    ((struct query_structure *)CrtTable)++;
    CrtTable += phwDeviceExtension->ModeIndex;

    /*
     * Mach 32 rev. 6 and later supports turning the sync signals on and off
     * through the HORZ_OVERSCAN registers, but some chips that report as
     * rev. 6 don't have this implemented. Also, Mach 32 rev. 3 and Mach 8
     * don't support this mechanism.
     *
     * Disabling the sync by setting it to start after the total will work
     * for all chips. Most chips will de-synchronize if the sync is set
     * to 1 more than the total, but some need higher values. To be sure
     * of de-synchronizing, set the disabled sync signal to start at
     * the highest possible value.
     */
    switch (DpmsState)
        {
        case VideoPowerOn:
            OUTP(H_SYNC_STRT,	CrtTable->m_h_sync_strt);
            OUTPW(V_SYNC_STRT,	CrtTable->m_v_sync_strt);
            break;

        case VideoPowerStandBy:
            OUTP(H_SYNC_STRT,	0xFF);
            OUTPW(V_SYNC_STRT,	CrtTable->m_v_sync_strt);
            break;

        case VideoPowerSuspend:
            OUTP(H_SYNC_STRT,	CrtTable->m_h_sync_strt);
            OUTPW(V_SYNC_STRT,	0x0FFF);
            break;

        case VideoPowerOff:
            OUTP(H_SYNC_STRT,	0xFF);
            OUTPW(V_SYNC_STRT,	0x0FFF);
            break;

        /*
         * This case should never happen, because the initial
         * acceptance of only valid states should have already
         * rejected anything that will appear here.
         */
        default:
            break;
        }
        return NO_ERROR;

}   /* SetPowerManagement_m() */
示例#12
0
文件: khyt1331.c 项目: wuchen1106/DAQ
static int khyt1331_ioctl(struct inode *inode, struct file *file,
                          unsigned int opcode, unsigned long param)
{
   int i, j;
   int c, n, a, f, data_size, write_flag, read_flag;
   unsigned char status;
   unsigned short adr = 0;
   unsigned int lam;
   CNAF_BUF cnaf_buf;
   void *buf;

   // printk(KERN_INFO "khyt1331: ioctl %d, param  %lX\n", opcode, param);

   switch (opcode) {
    /*---- initialization functions --------------------------------*/

   case OP_CRATE_ZINIT:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      OUTP(adr + 10, 34);
      break;

   case OP_CRATE_CLEAR:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      OUTP(adr + 10, 36);
      break;

   case OP_CRATE_CHECK:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);

      /* dummy clear inhibit operation */
      OUTP(adr + 8, 1);
      OUTP(adr + 6, 2);
      OUTP(adr + 10, 32);

      /* readback n, a, f */
      a = INP(adr + 10);
      n = INP(adr + 10);
      f = INP(adr + 10);

      if (n != 1 || a != 2 || f != 32)
         return 0;
      return 1;

    /*---- normal CAMAC functions ----------------------------------*/

   case OP_CNAF8:
   case OP_CNAF16:
   case OP_CNAF24:
      /*
         printk(KERN_INFO "khyt1331: CNAF: %d %d %d %d %d\n",
         cnaf_buf.c, cnaf_buf.n, cnaf_buf.a, cnaf_buf.f, cnaf_buf.d);
       */

      if (copy_from_user(&cnaf_buf, (void *) param, sizeof(cnaf_buf)) > 0)
         return -EFAULT;

      if (cnaf_buf.c > 3 || cnaf_buf.c < 0)
         return -EINVAL;

      adr = io_base + (cnaf_buf.c << 4);

      OUTP(adr + 8, cnaf_buf.n);

      if (cnaf_buf.f >= 8) {
         /* write operation */
         OUTP(adr, (unsigned char) cnaf_buf.d);
         if (opcode != OP_CNAF8) {
            OUTP(adr + 2, *(((unsigned char *) &cnaf_buf.d) + 1));
            if (opcode == OP_CNAF24)
               OUTP(adr + 4, *(((unsigned char *) &cnaf_buf.d) + 2));
         }
      }
      OUTP(adr + 6, cnaf_buf.a);
      OUTP(adr + 10, cnaf_buf.f);

      status = (unsigned char) INP(adr + 6);
      cnaf_buf.q = status & 1;
      cnaf_buf.x = status >> 7;

      if (cnaf_buf.f < 8) {
         cnaf_buf.d = 0;
         /* read operation */
         *((unsigned char *) &cnaf_buf.d) = INP(adr);
         if (opcode != OP_CNAF8) {
            *(((unsigned char *) &cnaf_buf.d) + 1) = INP(adr + 2);
            if (opcode == OP_CNAF24)
               *(((unsigned char *) &cnaf_buf.d) + 2) = INP(adr + 4);
         }
      }

      if (copy_to_user((void *) param, &cnaf_buf, sizeof(cnaf_buf)) > 0)
         return -EFAULT;
      break;

    /*---- repeat CAMAC functions ----------------------------------*/

   case OP_CNAF8R:
   case OP_CNAF16R:
   case OP_CNAF24R:

      data_size = opcode == OP_CNAF8R ? 1 : opcode == OP_CNAF16R ? 2 : 4;

      if (copy_from_user(&cnaf_buf, (void *) param, sizeof(cnaf_buf)) > 0)
         return -EFAULT;

      printk(KERN_INFO "khyt1331: CNAFR: %d %d %d %d %lX %d %d\n",
             cnaf_buf.c, cnaf_buf.n, cnaf_buf.a, cnaf_buf.f, cnaf_buf.d,
             cnaf_buf.r, cnaf_buf.m);

      /* check for valid crate parameter */
      if (cnaf_buf.c > 3 || cnaf_buf.c < 0)
         return -EINVAL;

      /* check for valid repeat count, allow 1M max. size */
      if (cnaf_buf.r < 0 || cnaf_buf.r > 1024 * 1024)
         return -EINVAL;

      /* check for valid repeat mode */
      if (cnaf_buf.m < RM_COUNT || cnaf_buf.m > RM_NSCAN)
         return -EINVAL;

      /* allocate local data buffer */
      buf = kmalloc(cnaf_buf.r * data_size, GFP_KERNEL);
      if (buf == NULL)
         return -ENOMEM;

      read_flag = (cnaf_buf.f < 8);
      write_flag = (cnaf_buf.f >= 16 && cnaf_buf.f <= 23);

      if (write_flag) {
         /* copy data buffer */
         if (copy_from_user(buf, (void *) cnaf_buf.d, cnaf_buf.r * data_size) > 0) {
            kfree(buf);
            return -EFAULT;
         }
      }

      /* Turn on the Q-mode for repeat until Q=1 in the INPW(adr+12) */
      if (cnaf_buf.m == RM_QMODE)
         OUTP(adr + 1, 0x10);

      adr = io_base + (cnaf_buf.c << 4);

      OUTP(adr + 8, cnaf_buf.n);
      OUTP(adr + 6, cnaf_buf.a);

      if (write_flag) {
         if (data_size == 1) {
            OUTP(adr, *((unsigned char *) buf));
         } else if (data_size == 2) {
            //printk("OUT0: %d\n", *((unsigned short *) buf));
            OUTP(adr, *((unsigned char *) buf));
            OUTP(adr + 2, *((unsigned char *) buf + 1));
         } else if (data_size == 4) {
            OUTP(adr, *((unsigned char *) buf));
            OUTP(adr + 2, *((unsigned char *) buf + 1));
            OUTP(adr + 4, *((unsigned char *) buf + 2));
         }
      }

      /* trigger first cycle */
      OUTP(adr + 10, cnaf_buf.f);

      if (read_flag) {
         if (data_size == 1) {
            *((unsigned char *) buf) = INP(adr);
         } else if (data_size == 2) {
            *((unsigned char *) buf) = INP(adr);
            *((unsigned char *) buf + 1) = INP(adr + 2);
         } else if (data_size == 4) {
            *((unsigned char *) buf) = INP(adr);
            *((unsigned char *) buf + 1) = INP(adr + 2);
            *((unsigned char *) buf + 1) = INP(adr + 4);
         }

         /* trigger first cycle */
         INPW(adr + 12);
         INP(adr + 6);          /* some delay */
      }

      /* repeat cycles */
      for (i = 1; i < cnaf_buf.r; i++) {
         if (write_flag) {
            if (data_size == 1) {
               OUTPW(adr + 12, *((unsigned char *) buf + i));
            } else if (data_size == 2) {
               //printk("OUT%d: %d\n", i, *((unsigned short *) buf+i));
               OUTPW(adr + 12, *((unsigned short *) buf + i));
            } else if (data_size == 4) {
               /* write high byte */
               OUTP(adr + 4, *((unsigned char *) buf + 4 * i + 2));

               /* write low and middle bytes to repeat register */
               OUTPW(adr + 12, *((unsigned short *) buf + 2 * i));
            }
         }

         if (read_flag) {
            if (data_size == 1) {
               *((unsigned char *) buf + i) = (unsigned char) INPW(adr + 12);
            } else if (data_size == 2) {
               *((unsigned short *) buf + i) = INPW(adr + 12);
            } else if (data_size == 4) {
               /* read high byte */
               *((unsigned char *) buf + 4 * i + 2) = INP(adr + 4);

               /* read low and middle bytes from repeat register */
               *((unsigned short *) buf + i) = INPW(adr + 12);
            }
         }

         if (cnaf_buf.m == RM_QMODE) {
            /* in Q mode, test FAIL bit in status register */
            status = (unsigned char) INP(adr + 6);
            if ((status & (1 << 5)) > 0)
               break;
         }

         if (cnaf_buf.m == RM_ASCAN)
            OUTP(adr + 6, ++cnaf_buf.a);

         if (cnaf_buf.m == RM_NSCAN)
            OUTP(adr + 8, ++cnaf_buf.n);

         for (j = 0; j < 1000; j++)
            udelay(1000);
      }

      /* Turn off the Q-mode */
      if (cnaf_buf.m == RM_QMODE)
         OUTP(adr + 1, 0);

      if (read_flag)
         if (copy_to_user((void *) cnaf_buf.d, buf, i * data_size) > 0) {
            kfree(buf);
            return -EFAULT;
         }

      kfree(buf);
      break;

   case OP_INHIBIT_SET:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      OUTP(adr + 10, 33);
      break;

   case OP_INHIBIT_CLEAR:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      OUTP(adr + 10, 32);
      break;

   case OP_INHIBIT_TEST:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      status = INP(adr + 6);
      return (status & (1 << 1)) > 0;

   case OP_LAM_ENABLE:
      c = param >> 16;
      n = param & 0xFF;
      if (c > 3 || c < 0 || n > 24 || n < 0)
         return -EINVAL;

      adr = io_base + (c << 4);
      OUTP(adr + 10, 64 + n);
      break;

   case OP_LAM_DISABLE:
      c = param >> 16;
      n = param & 0xFF;
      if (c > 3 || c < 0 || n > 24 || n < 0)
         return -EINVAL;

      adr = io_base + (c << 4);
      OUTP(adr + 10, 128 + n);
      break;

   case OP_LAM_READ:
      /*
         return a BITWISE coded station NOT the station number
         i.e.: n = 5  ==> lam = 0x10
       */

      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      status = INP(adr + 6);
      if (status & (1 << 3)) {
         lam = (INP(adr + 8) & 0x1F);   // mask upper 3 bits
         lam = 1 << (lam - 1);
      } else
         lam = 0;
      return lam;

   case OP_LAM_CLEAR:
      c = param >> 16;
      n = param & 0xFF;
      if (c > 3 || c < 0 || n > 24 || n < 0)
         return -EINVAL;

      adr = io_base + (c << 4);

      /* restart LAM scanner in controller */
      INP(adr + 8);
      break;

   case OP_INTERRUPT_ENABLE:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      OUTP(adr + 10, 41);
      break;

   case OP_INTERRUPT_DISABLE:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      OUTP(adr + 10, 40);
      break;

   case OP_INTERRUPT_TEST:
      if (param > 3 || param < 0)
         return -EINVAL;

      adr = io_base + (param << 4);
      status = INP(adr + 6);
      return (status & (1 << 2)) > 0;
   }

   /* signal success */
   return 1;
}