PLX_MasterDevice.cs
上传用户:huajielb
上传日期:2022-07-29
资源大小:626k
文件大小:20k
源码类别:

驱动编程

开发平台:

Visual C++

  1. using System;
  2. using System.Windows.Forms;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using System.Collections;
  6. using Jungo.wdapi_dotnet;
  7. using wdc_err = Jungo.wdapi_dotnet.WD_ERROR_CODES;
  8. using WDC_DEVICE_HANDLE = System.IntPtr;
  9. using DWORD = System.UInt32;
  10. using UINT32 = System.UInt32;
  11. using WORD = System.UInt16;
  12. using BOOL = System.Boolean;
  13. namespace Jungo.plx_lib
  14. {
  15.     /* Run-time registers of PLX master devices (9054, 9056, 9080, 9656) */
  16.     public enum PLX_M_REGS 
  17.     {
  18.         /* Local configuration registers */
  19.         PLX_M_LAS0RR = 0x00,    /* Local Addr Space 0 Range for PCI-to-Local Bus */
  20.         PLX_M_LAS0BA = 0x04,    /* Local BAR (Remap) for PCI-to-Local Addr 
  21.                                    Space 0 */
  22.         PLX_M_MARBR = 0x08,     /* Mode/DMA Arbitration */
  23.         PLX_M_BIGEND = 0x0C,    /* Big/Little Endian Descriptor */
  24.         PLX_M_LMISC = 0x0D,     /* Local Miscellananeous Control */
  25.         PLX_M_PROT_AREA = 0x0E, /* Serial EEPROM Write-Protected Addr Boundary */
  26.         PLX_M_EROMRR = 0x10,    /* Expansion ROM Range */
  27.         PLX_M_EROMBA = 0x14,    /* EROM Local BAR (Remap) & BREQ0 Control */
  28.         PLX_M_LBRD0 = 0x18,     /* Local Addr Space 0 Bus Region Descriptor */
  29.         PLX_M_DMRR = 0x1C,      /* Local Range for PCI initiatior-to-PCI */
  30.         PLX_M_DMLBAM = 0x20,    /* Local Bus Addr for PCI Initiatior-to-PCI Mem */
  31.         PLX_M_DMLBAI = 0x24,    /* Local BAR for PCI Initiatior-to-PCI I/O */
  32.         PLX_M_DMPBAM = 0x28,    /* PCI BAR (Remap) for Initiatior-to-PCI Mem */
  33.         PLX_M_DMCFGA = 0x2C,    /* PCI Config Addr for PCI Initiatior-to-PCI I/O */
  34.         PLX_M_LAS1RR = 0xF0,    /* Local Addr Space 1 Range for PCI-to-Local Bus */
  35.         PLX_M_LAS1BA = 0xF4,    /* Local Addr Space 1 Local BAR (Remap) */
  36.         PLX_M_LBRD1 = 0xF8,     /* Local Addr Space 1 Bus Region Descriptor */
  37.         PLX_M_DMDAC = 0xFC,     /* PCI Initiatior PCI Dual Address Cycle */
  38.         PLX_M_PCIARB = 0x100,   /* PCI Arbiter Control*/
  39.         PLX_M_PABTADR = 0x104,  /* PCI Abort Address */
  40.         /* mailbox, doorbell, interrupt status, control, id registers */
  41.         PLX_M_MBOX0 = 0x40,     /* Mailbox 0 */
  42.         PLX_M_MBOX1 = 0x44,     /* Mailbox 1 */
  43.         PLX_M_MBOX2 = 0x48,     /* Mailbox 2 */
  44.         PLX_M_MBOX3 = 0x4C,     /* Mailbox 3 */
  45.         PLX_M_MBOX4 = 0x50,     /* Mailbox 4 */
  46.         PLX_M_MBOX5 = 0x54,     /* Mailbox 5 */
  47.         PLX_M_MBOX6 = 0x58,     /* Mailbox 6 */
  48.         PLX_M_MBOX7 = 0x5C,     /* Mailbox 7 */
  49.         PLX_M_P2LDBELL = 0x60,  /* PCI-to-Local Doorbell */
  50.         PLX_M_L2PDBELL = 0x64,  /* Local-to-PCI Doorbell */
  51.         PLX_M_INTCSR = 0x68,    /* INTCSR - Interrupt Control/Status */
  52.         PLX_M_CNTRL = 0x6C,     /* Serial EEPROM/User I/O/Init Ctr & PCI Cmd 
  53.                                    Codes */
  54.         PLX_M_PCIHIDR = 0x70,   /* PCI Hardcoded Configuration ID */
  55.         PLX_M_PCIHREV = 0x74,   /* PCI Hardcoded Revision ID */
  56.         PLX_M_MBOX0_I2O = 0x78, /* Mailbox 0 - I2O enabled */
  57.         PLX_M_MBOX1_I2O = 0x7C, /* Mailbox 1 - I2O enabled */
  58.         /* DMA registers */
  59.         PLX_M_DMAMODE0 = 0x80,  /* DMA Channel 0 Mode */
  60.         PLX_M_DMAPADR0 = 0x84,  /* DMA Channel 0 PCI Address */
  61.         PLX_M_DMALADR0 = 0x88,  /* DMA Channel 0 Local Address */
  62.         PLX_M_DMASIZ0 = 0x8C,   /* DMA Channel 0 Transfer Size (bytes) */
  63.         PLX_M_DMADPR0 = 0x90,   /* DMA Channel 0 Descriptor Pointer */
  64.         PLX_M_DMAMODE1 = 0x94,  /* DMA Channel 1 Mode */
  65.         PLX_M_DMAPADR1 = 0x98,  /* DMA Channel 1 PCI Address */
  66.         PLX_M_DMALADR1 = 0x9C,  /* DMA Channel 1 Local Address */
  67.         PLX_M_DMASIZ1 = 0xA0,   /* DMA Channel 1 Transfer Size (bytes) */
  68.         PLX_M_DMADPR1 = 0xA4,   /* DMA Channel 1 Descriptor Pointer */
  69.         PLX_M_DMACSR0 = 0xA8,   /* DMA Channel 0 Command/Status */
  70.         PLX_M_DMACSR1 = 0xA9,   /* DMA Channel 1 Command/Status */
  71.         PLX_M_DMAARB = 0xAC,    /* DMA Arbitration */
  72.         PLX_M_DMATHR = 0xB0,    /* DMA Threshold (Channel 0 only) */
  73.         PLX_M_DMADAC0 = 0xB4,   /* DMA 0 PCI Dual Address Cycle Address */
  74.         PLX_M_DMADAC1 = 0xB8,   /* DMA 1 PCI Dual Address Cycle Address */
  75.         /* Messaging queue (I20) registers */
  76.         PLX_M_OPQIS = 0x30,     /* Outbound Post Queue Interrupt Status */
  77.         PLX_M_OPQIM = 0x34,     /* Outbound Post Queue Interrupt Mask */
  78.         PLX_M_IQP = 0x40,       /* Inbound Queue Post */
  79.         PLX_M_OQP = 0x44,       /* Outbound Queue Post */
  80.         PLX_M_MQCR = 0xC0,      /* Messaging Queue Configuration */
  81.         PLX_M_QBAR = 0xC4,      /* Queue Base Address */
  82.         PLX_M_IFHPR = 0xC8,     /* Inbound Free Head Pointer */
  83.         PLX_M_IFTPR = 0xCC,     /* Inbound Free Tail Pointer */
  84.         PLX_M_IPHPR = 0xD0,     /* Inbound Post Head Pointer */
  85.         PLX_M_IPTPR = 0xD4,     /* Inbound Post Tail Pointer */
  86.         PLX_M_OFHPR = 0xD8,     /* Outbound Free Head Pointer */
  87.         PLX_M_OFTPR = 0xDC,     /* Outbound Free Tail Pointer */
  88.         PLX_M_OPHPR = 0xE0,     /* Outbound Post Head Pointer */
  89.         PLX_M_OPTPR = 0xE4,     /* Outbound Post Tail Pointer */
  90.         PLX_M_QSR = 0xE8,        /* Queue Status/Control */
  91.     };
  92.     /* DMA channels */
  93.     public enum PLX_DMA_CHANNEL 
  94.     {
  95.         PLX_DMA_CHANNEL_0 = 0,
  96.         PLX_DMA_CHANNEL_1 = 1
  97.     };
  98.     public struct PlxChannel
  99.     {
  100.         public PLX_DMA_CHANNEL channel;
  101.         public BOOL bIsEnabled;
  102.         /* offsets of DMA registers */
  103.         public DWORD dwDMACSR;
  104.         public DWORD dwDMAMODE;
  105.         public DWORD dwDMAPADR;
  106.         public DWORD dwDMALADR;
  107.         public DWORD dwDMADPR;
  108.         public DWORD dwDMASIZ;
  109.         public UINT32 u32AbortMask;
  110.         public PlxChannel(PLX_DMA_CHANNEL chn)
  111.         {
  112.             channel = chn;
  113.             bIsEnabled = false;
  114.             if(chn == PLX_DMA_CHANNEL.PLX_DMA_CHANNEL_0)
  115.             {
  116.                 dwDMACSR = (DWORD) PLX_M_REGS.PLX_M_DMACSR0;
  117.                 dwDMAMODE = (DWORD) PLX_M_REGS.PLX_M_DMAMODE0;
  118.                 dwDMAPADR = (DWORD) PLX_M_REGS.PLX_M_DMAPADR0;
  119.                 dwDMALADR = (DWORD) PLX_M_REGS.PLX_M_DMALADR0;
  120.                 dwDMADPR = (DWORD) PLX_M_REGS.PLX_M_DMADPR0;
  121.                 dwDMASIZ = (DWORD) PLX_M_REGS.PLX_M_DMASIZ0;
  122.                 u32AbortMask = (UINT32) BITS.BIT25;
  123.             }
  124.             else
  125.             {
  126.                 dwDMACSR = (DWORD) PLX_M_REGS.PLX_M_DMACSR1;
  127.                 dwDMAMODE = (DWORD) PLX_M_REGS.PLX_M_DMAMODE1;
  128.                 dwDMAPADR = (DWORD) PLX_M_REGS.PLX_M_DMAPADR1;
  129.                 dwDMALADR = (DWORD) PLX_M_REGS.PLX_M_DMALADR1;
  130.                 dwDMADPR = (DWORD) PLX_M_REGS.PLX_M_DMADPR1;
  131.                 dwDMASIZ = (DWORD) PLX_M_REGS.PLX_M_DMASIZ1;
  132.                 u32AbortMask = (UINT32) BITS.BIT26;
  133.             }                        
  134.         }
  135.     }        
  136.     /* PLX diagnostics interrupt handler function type */
  137.     public delegate void USER_INTERRUPT_MASTER_CALLBACK(PLX_MasterDevice 
  138.         device, IntPtr pWdDma);
  139.     public class PLX_MasterDevice: PLX_Device
  140.     {
  141.         private USER_INTERRUPT_MASTER_CALLBACK m_userIntHandler;
  142.         private PlxChannel[] m_plxChannels;
  143.         private PlxChannel m_enabledChn;
  144.         private IntPtr m_pDmaCtx;
  145.         private Mutex m_hMutex = null;
  146.         private const UINT32 PLX_MASTER_INT_MASK = (UINT32)
  147.                 ( BITS.BIT5  /* power management */ 
  148.                 | BITS.BIT13 /* PCI Doorbell */ 
  149.                 | BITS.BIT14 /* PCI Abort */ 
  150.                 | BITS.BIT15 /* Local Input */ 
  151.                 | BITS.BIT20 /* Local Doorbell */ 
  152.                 | BITS.BIT21 /* DMA Channel 0 */ 
  153.                 | BITS.BIT22 /* DMA Channel 1 */
  154.                 | BITS.BIT23 /* BIST */ 
  155.                 );
  156.         /* constructors */
  157.         internal protected PLX_MasterDevice(WD_PCI_SLOT slot): 
  158.             this(0, 0, slot, ""){}
  159.         internal protected PLX_MasterDevice(DWORD dwVendorId, DWORD dwDeviceId,
  160.             WD_PCI_SLOT slot): this(dwVendorId, dwDeviceId, slot, ""){} 
  161.         internal protected PLX_MasterDevice(DWORD dwVendorId, DWORD dwDeviceId,
  162.             WD_PCI_SLOT slot, string sKP_PLX_DRIVER_NAME):
  163.             base(dwVendorId, dwDeviceId, slot, sKP_PLX_DRIVER_NAME) 
  164.         {
  165.             m_bIsMaster = true;
  166.             m_plxChannels = new PlxChannel[]{
  167.                 new PlxChannel(PLX_DMA_CHANNEL.PLX_DMA_CHANNEL_0), 
  168.                 new PlxChannel(PLX_DMA_CHANNEL.PLX_DMA_CHANNEL_1)
  169.             };                
  170.             m_dwLASBA = new DWORD[2];
  171.             m_hMutex = new Mutex();
  172.         }
  173.         protected override void DeviceInit()
  174.         {
  175.             /* NOTE: You can modify the implementation of this function in
  176.              * order to perform any additional device initialization you 
  177.              * require */
  178.             /* Set specific registers infomation */
  179.             m_dwINTCSR = (DWORD)PLX_M_REGS.PLX_M_INTCSR;
  180.             m_dwCNTRL = (DWORD)PLX_M_REGS.PLX_M_CNTRL;
  181.             m_dwPROT_AREA = (DWORD)PLX_M_REGS.PLX_M_PROT_AREA;
  182.             m_dwLASBA[0] = (DWORD)PLX_M_REGS.PLX_M_LAS0BA;
  183.             m_dwLASBA[1] = (DWORD)PLX_M_REGS.PLX_M_LAS1BA;
  184.             /* Enable target abort for master devices */
  185.             uint u32IntStatus = 0;
  186.             ReadReg32((DWORD)PLX_M_REGS.PLX_M_INTCSR, ref u32IntStatus);
  187.             WriteReg32((DWORD)PLX_M_REGS.PLX_M_INTCSR, u32IntStatus |
  188.                 (uint)BITS.BIT12);
  189.         }        
  190.         public override DWORD CreateIntTransCmds(out WD_TRANSFER[] pIntTransCmds,
  191.                 out DWORD dwNumCmds)
  192.         {
  193.             WDC_ADDR_DESC addrDesc = AddrDesc[PLX_ADDR_REG];
  194.             int NUM_TRANS_CMDS_MASTER = 4;
  195.             pIntTransCmds = new WD_TRANSFER[NUM_TRANS_CMDS_MASTER];
  196.             /* Prepare the interrupt transfer commands */
  197.             /* The transfer commands will be executed by WinDriver in the
  198.              * kernel for each interrupt that is received */
  199.             byte i = 0;
  200.             byte bDmaCsrIndex;
  201.             /* Read interrupt status from the INTCSR register */
  202.             pIntTransCmds[i].dwPort = addrDesc.kptAddr + m_dwINTCSR;
  203.             pIntTransCmds[i].cmdTrans =
  204.                 wdc_defs_macros.WDC_ADDR_IS_MEM(ref addrDesc) ?
  205.                 (DWORD)WD_TRANSFER_CMD.RM_DWORD :
  206.                 (DWORD)WD_TRANSFER_CMD.RP_DWORD;
  207.             i++;
  208.             /* Mask interrupt status from the INTCSR register */
  209.             pIntTransCmds[i].cmdTrans = (DWORD)WD_TRANSFER_CMD.CMD_MASK;
  210.             pIntTransCmds[i].Data.Dword = PLX_MASTER_INT_MASK;
  211.             i++;
  212.             /* Read DMA status from the DMACSR register */
  213.             pIntTransCmds[i].dwPort = addrDesc.kptAddr +
  214.                 m_enabledChn.dwDMACSR;
  215.             pIntTransCmds[i].cmdTrans =
  216.                 wdc_defs_macros.WDC_ADDR_IS_MEM(ref addrDesc) ?
  217.                 (DWORD)WD_TRANSFER_CMD.RM_BYTE :
  218.                 (DWORD)WD_TRANSFER_CMD.RP_BYTE;
  219.             bDmaCsrIndex = i;
  220.             i++;
  221.             /* Write to the DMACSR register to clear the DMA DONE 
  222.              * interrupt */
  223.             pIntTransCmds[i].dwPort = pIntTransCmds[bDmaCsrIndex].dwPort;
  224.             pIntTransCmds[i].cmdTrans = 
  225.                 wdc_defs_macros.WDC_ADDR_IS_MEM(ref addrDesc) ?
  226.                 (DWORD)WD_TRANSFER_CMD.WM_BYTE :
  227.                 (DWORD)WD_TRANSFER_CMD.WP_BYTE;
  228.             pIntTransCmds[i].Data.Byte = (byte)(BITS.BIT3);
  229.             i++;
  230.             dwNumCmds = i;
  231.             return (DWORD)wdc_err.WD_STATUS_SUCCESS;
  232.         }
  233.         public DWORD EnableInterrupts(USER_INTERRUPT_MASTER_CALLBACK userIntCb,
  234.             PLX_DMA_CHANNEL dmaChn)
  235.         {
  236.             uint u32INTCSR = 0;
  237.             uint u32DMAMODE = 0;
  238.             m_pDmaCtx = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(System.IntPtr))); 
  239.             m_hMutex.WaitOne();
  240.              
  241.             if(!IsEnabledInt())
  242.                 m_enabledChn = m_plxChannels[(DWORD)dmaChn];
  243.             
  244.             if(userIntCb == null)
  245.             {
  246.                 Log.ErrLog("PLX_Device.EnableInterrupts: "
  247.                     + "user callback is null");
  248.                 m_hMutex.ReleaseMutex();
  249.                 return (DWORD)wdc_err.WD_INVALID_PARAMETER;
  250.             }
  251.             m_userIntHandler = userIntCb; 
  252.             DWORD dwStatus = base.EnableInterrupts(new INT_HANDLER(DMAIntHandler), 
  253.                 (DWORD)WD_INTERRUPT_OPTIONS.INTERRUPT_CMD_COPY, m_pDmaCtx);
  254.        
  255.             m_hMutex.ReleaseMutex();
  256.             if(dwStatus != (DWORD)wdc_err.WD_STATUS_SUCCESS)
  257.             {
  258.                 m_userIntHandler = null;
  259.                 return dwStatus;
  260.             }
  261.             m_plxChannels[(DWORD)dmaChn].bIsEnabled = true;
  262.             /* Physically enable the interrupts on the board */
  263.             /* DMA DONE interrupt enable, route DMA channel interrupt to
  264.              * PCI interrupt */
  265.             ReadReg32(m_enabledChn.dwDMAMODE, ref u32DMAMODE);
  266.             WriteReg32(m_enabledChn.dwDMAMODE,
  267.                 u32DMAMODE | (DWORD)(BITS.BIT10 | BITS.BIT17));
  268.             /* PCI interrupt enable, DMA channel local interrupt enable */
  269.             ReadReg32(m_dwINTCSR, ref u32INTCSR);
  270.             WriteReg32(m_dwINTCSR, u32INTCSR | (DWORD)(BITS.BIT8 |
  271.                 ((PLX_DMA_CHANNEL.PLX_DMA_CHANNEL_0 == dmaChn)? 
  272.                 BITS.BIT18 : BITS.BIT19)));
  273.             Log.TraceLog("PLX_MasterDevice: enabled interrupts (" 
  274.                 + this.ToString(false) + ")" );
  275.             return (DWORD)wdc_err.WD_STATUS_SUCCESS;
  276.         }
  277.         public override void DisableCardInts()
  278.         {
  279.             uint u32INTCSR = 0, u32DMAMODE = 0;
  280.             ReadReg32((DWORD)PLX_M_REGS.PLX_M_INTCSR, ref u32INTCSR);
  281.             WriteReg32((DWORD)PLX_M_REGS.PLX_M_INTCSR,
  282.                 u32INTCSR & ~((DWORD)(BITS.BIT8 | BITS.BIT18 | BITS.BIT19)));
  283.             ReadReg32((DWORD)PLX_M_REGS.PLX_M_DMAMODE0, ref u32DMAMODE);
  284.             WriteReg32((DWORD)PLX_M_REGS.PLX_M_DMAMODE0,
  285.                 u32DMAMODE & ~(DWORD)BITS.BIT10);
  286.             ReadReg32((DWORD)PLX_M_REGS.PLX_M_DMAMODE1, ref u32DMAMODE);
  287.             WriteReg32((DWORD)PLX_M_REGS.PLX_M_DMAMODE1,
  288.                 u32DMAMODE & ~(DWORD)BITS.BIT10);
  289.             Marshal.FreeHGlobal(m_pDmaCtx);         
  290.             m_plxChannels[0].bIsEnabled = false;
  291.             m_plxChannels[1].bIsEnabled = false;
  292.         }
  293.         public BOOL IsChannelIntEnabled(PLX_DMA_CHANNEL chn)
  294.         {
  295.             return (IsEnabledInt() && m_plxChannels[(DWORD)chn].bIsEnabled);
  296.         }
  297.         private void DMAStart(PLX_DMA_CHANNEL plxDmaChn, DmaBuffer dmaBuffer)
  298.         {
  299.             DWORD u32DMAMODE = 0;
  300.             WD_DMA wdDma = dmaBuffer.MarshalDMA(dmaBuffer.pWdDma);
  301.             PlxChannel plxChn = m_plxChannels[(DWORD)plxDmaChn];
  302.             /* Common settings for chain and direct DMA */
  303.             ReadReg32(plxChn.dwDMAMODE, ref u32DMAMODE);
  304.             u32DMAMODE |= (dmaBuffer.IsAutoInc ? 0 : (DWORD)BITS.BIT11)
  305.                 | (DWORD)BITS.BIT6 /* Enable Ready input */
  306.                 | (DWORD)BITS.BIT8 /* Local burst */
  307.                 | (DWORD)(WDC_ADDR_MODE.WDC_MODE_8 == dmaBuffer.Mode ? 0 :
  308.                     WDC_ADDR_MODE.WDC_MODE_16 == dmaBuffer.Mode ?
  309.                     (DWORD)BITS.BIT0 :
  310.                     (DWORD)BITS.BIT1 | (DWORD)BITS.BIT0);
  311.             if (wdDma.dwPages == 1)
  312.             {
  313.                 /* DMA of one page ==> direct DMA */
  314.                 WriteReg32(plxChn.dwDMAMODE, u32DMAMODE);
  315.                 WriteReg32(plxChn.dwDMAPADR, (uint)wdDma.Page[0].pPhysicalAddr);
  316.                 WriteReg32(plxChn.dwDMALADR, dmaBuffer.LocalAddress);
  317.                 WriteReg32(plxChn.dwDMASIZ, (uint)wdDma.Page[0].dwBytes);
  318.                 WriteReg32(plxChn.dwDMADPR, dmaBuffer.IsRead ? (DWORD)BITS.BIT3 : 0);
  319.             }
  320.             else
  321.             {
  322.                 DmaBufferSG dmaSG = (DmaBufferSG)dmaBuffer;
  323.                 WD_DMA wdDmaList = dmaSG.MarshalDMA(dmaSG.pWdDmaList);
  324.                 DWORD u32AlignShift = 0x10 -
  325.                     ((uint)wdDma.pUserAddr.ToInt64() & 0xF);
  326.                 DWORD u32StartOfChain =
  327.                     (uint)wdDmaList.Page[0].pPhysicalAddr + u32AlignShift;
  328.                 /* Chain transfer */
  329.                 WriteReg32(plxChn.dwDMAMODE, u32DMAMODE | (DWORD)BITS.BIT9);
  330.                 WriteReg32(plxChn.dwDMADPR, u32StartOfChain | (DWORD)BITS.BIT0);
  331.             }
  332.             wdc_lib_decl.WDC_DMASyncCpu(dmaBuffer.pWdDma);
  333.             WriteReg8(plxChn.dwDMACSR, (byte)(BITS.BIT0 | BITS.BIT1));
  334.         }
  335.         private bool DMAIsAborted(PLX_DMA_CHANNEL plxDmaChn)
  336.         {
  337.             uint intcsr = 0, mask = 0;
  338.             mask = m_plxChannels[(DWORD)plxDmaChn].u32AbortMask;
  339.             ReadReg32(m_dwINTCSR, ref intcsr);
  340.             return ((intcsr & mask) != mask);
  341.         }
  342.         private bool DMAIsDone(PLX_DMA_CHANNEL plxDmaChn)
  343.         {
  344.             byte dmacsr = 0;
  345.             PlxChannel plxChn = m_plxChannels[(DWORD)plxDmaChn];
  346.             ReadReg8(plxChn.dwDMACSR, ref dmacsr);
  347.             return (dmacsr & (byte)BITS.BIT4) == (byte)BITS.BIT4;
  348.         }
  349.         private bool DMAPollCompletion(PLX_DMA_CHANNEL plxChn, DmaBuffer dmaBuffer)
  350.         {
  351.             while (!DMAIsDone(plxChn) && !DMAIsAborted(plxChn));
  352.             wdc_lib_decl.WDC_DMASyncIo(dmaBuffer.pWdDma);
  353.             return !DMAIsAborted(plxChn);
  354.         }
  355.         public DWORD DMATransfer(PLX_DMA_CHANNEL plxChn, DmaBuffer dmaBuffer,
  356.             BOOL bIsCompInt)
  357.         {
  358.             if(bIsCompInt)
  359.             {
  360.                 if(!IsChannelIntEnabled(plxChn))
  361.                 {
  362.                     Log.TraceLog("PLX_MasterDevice.DMATransfer: interrupts "
  363.                         + "on channel " + ((DWORD)plxChn).ToString() +
  364.                         "are disabled. can not initiate transfer with interrupt "
  365.                         + "completion mode (" + this.ToString(false) + ")" );
  366.                     return (DWORD)wdc_err.WD_INVALID_PARAMETER;
  367.                 }
  368.                 //copy the DMA data to the context IntPtr that was passed
  369.                 //to WDC_IntEnable.
  370.                 Marshal.WriteIntPtr(m_pDmaCtx, dmaBuffer.pWdDma);
  371.             }
  372.             else
  373.             {
  374.                 if(IsChannelIntEnabled(plxChn))
  375.                 {
  376.                     Log.TraceLog("PLX_MasterDevice.DMATransfer: interrupts "
  377.                         + "on channel " + ((DWORD)plxChn).ToString() + " are enabled. " +
  378.                         "can not initiate transfer with polling completion "
  379.                         + "mode (" + this.ToString(false) + ")" );
  380.                     return (DWORD)wdc_err.WD_INVALID_PARAMETER;
  381.                 }
  382.             }
  383.             DMAStart(plxChn, dmaBuffer);
  384.             if(!bIsCompInt)
  385.             {
  386.                 if (!DMAPollCompletion(plxChn, dmaBuffer))
  387.                 {
  388.                     Log.TraceLog("PLX_MasterDevice.DMATransfer: aborted");
  389.                     return (DWORD)wdc_err.WD_OPERATION_FAILED;
  390.                 }
  391.             }
  392.             return (DWORD)wdc_err.WD_STATUS_SUCCESS;
  393.         }
  394.         private void DMAIntHandler(IntPtr pCtx)
  395.         {
  396.             wdcDevice.Int = 
  397.                 (WD_INTERRUPT)m_wdcDeviceMarshaler.MarshalDevWdInterrupt(Handle);
  398.             /* to obtain the data that was read at interrupt use:
  399.              * WD_TRANSFER[] transCommands;
  400.              * transCommands = (WD_TRANSFER[])m_wdcDeviceMarshaler.MarshalDevpWdTrans(
  401.              *     wdcDevice.Int.Cmd, wdcDevice.Int.dwCmds); */
  402.             IntPtr pWdDma = Marshal.ReadIntPtr(pCtx);            
  403.             DWORD dwStatus = wdc_lib_decl.WDC_DMASyncIo(pWdDma);
  404.             if (m_userIntHandler != null)
  405.                 m_userIntHandler(this, pWdDma);                        
  406.         }
  407.     }        
  408. }