AIOWDM.dll Software Reference Manual
PCI/PCIe Plug-and-Play Driver API

Introduction

This manual provides a single reference to the functionality exposed by the AIOWDM driver package. AIOWDM supports PCI-based plug-and-play devices, including direct register access, watchdog timer control, change-of-state IRQ handling, DAC control, and board discovery.

All supported PCI and PCIe form factors other than serial boards use AIOWDM. This includes conventional PCI, PCI Express, mPCIe, M.2, PCI-104, PC/104+, and related form factors.

The manual is organized by function family. Functions marked Advanced are normally needed only for specialized applications. Deprecated APIs are hidden initially and can be displayed using the control above the table of contents.

General Information

Calling Conventions and Header Files

AIOWDM functions are exported in three forms: underscored with the cdecl calling convention, undecorated with the stdcall calling convention, and undecorated with the cdecl calling convention. The appropriate form depends on the language and import mechanism being used.

Language-specific declarations are supplied in files such as AIOWDM.h, AIOWDM.cs, and AIOWDM.vb. They are installed below C:\Users\Public\Documents\ACCES\{package name}\Win32\Driver.SRC\AIOWDM\Headers\. Use those declarations rather than recreating pointer types and calling conventions from this manual.

CardNum and Multiple-Card Systems

CardNum is a zero-based index into the list of AIOWDM devices detected in the system. In a system with one AIOWDM card, CardNum is normally zero.

Applications that can encounter multiple AIOWDM cards should call GetNumCards() and QueryCardInfo() during initialization. Once the correct CardNum has been selected, the remaining API calls are used in the same way as they are in a single-card system.

Accessing Registers

RelInPort*() / RelOutPort*()

Purpose

Read or write a register using a card-relative offset. Every function takes CardNum first and a register offset second. Output functions take the value to write as the final argument.

The RelInPort* family returns a byte-, word-, or 32-bit value. The RelOutPort* family writes the corresponding width. These operations are the plug-and-play equivalents of processor port-I/O instructions and the Windows kernel port-access macros.

Signature
UInt16 RelInPortB(Int32 CardNum, UInt32 Port);
UInt16 RelInPort(Int32 CardNum, UInt32 Port);
UInt32 RelInPortL(Int32 CardNum, UInt32 Port);
UInt16 RelOutPortB(Int32 CardNum, UInt32 Port, Byte Value);
UInt16 RelOutPort(Int32 CardNum, UInt32 Port, UInt16 Value);
UInt16 RelOutPortL(Int32 CardNum, UInt32 Port, UInt32 Value);
Arguments
CardNum
The zero-based AIOWDM card index.
Port
The register offset relative to the selected card's base address.
Value
The byte, word, or 32-bit value to write.
Returns

Read functions return the register value. All functions can return the sentinel 0xAA55 when the underlying AIOWDM.SYS driver is not installed or cannot be opened correctly.

Notes

Because 0xAA55 is a valid word or 32-bit value, perform one byte-sized read from a safe register during application initialization. A byte read cannot normally produce a 16-bit 0xAA55 value, making it an unambiguous driver check.

Example
value = RelInPort(0, 2);
value = RelInPortB(1, 12);
RelOutPortL(0, 0, value);

Migrating Legacy Code (ACCES95.dll, ACCES32.dll, VBACCES.dll, etc.)

The absolute-address APIs below are deprecated. They were used by legacy applications that located cards through PCIFind, registry data, or a separate non-plug-and-play driver. New and migrated applications should use the card-relative RelInPort* and RelOutPort* APIs.

InPort*() / OutPort*()

Purpose

Access an absolute I/O-space address. These functions do not take CardNum; the application must discover and track the card's plug-and-play-assigned base address itself.

AIOWDM's relative register functions eliminate the need for PCIFind, NTioPCI.SYS, legacy registry arrays such as PCI_COMMON_CONFIG, and application-side base-address arithmetic.

Signature
UInt16 InPortB(UInt32 Port);
UInt16 InPort(UInt32 Port);
UInt32 InPortL(UInt32 Port);
UInt16 OutPortB(UInt32 Port, Byte Value);
UInt16 OutPort(UInt32 Port, UInt16 Value);
UInt16 OutPortL(UInt32 Port, UInt32 Value);
Example
value = InPortL(CardBaseAddress + RegisterOffset);

Migration Procedure

For a single-card application, migrate the old absolute-address code as follows:

  1. Locate initialization code that calls QueryCardInfo() for a base address or reads HKLM\Software\PCIFind\Parameters.
  2. Remove the obsolete base-address discovery code.
  3. Replace InPort* and OutPort* calls with the corresponding RelInPort* and RelOutPort* calls.
  4. Replace BASE + offset with 0, offset. In a multiple-card application, replace zero with the selected CardNum variable.
u32bData = InPortL(BASE + 3);

// After changing to the relative API:
u32bData = RelInPortL(0, 3);

// Multiple-card application:
u32bData = RelInPortL(CardNumVariable, 3);

Operating Analog Outputs (DACs)

The DAC_* functions operate supported PCI and PCIe DAC-output boards, from the PCIe-DA16-16 through the PCI-DA12-2 family.

These boards power up or reset with output voltage restricted. Before enabling normal output, write known values to the DACs, select the desired simultaneous or asynchronous update mode, issue an update if needed, and then clear voltage-restrict mode.

Unlike many older AIOWDM functions, these DAC APIs return Win32 error codes directly. ERROR_SUCCESS (zero) means success; any nonzero value is an error code.

DAC Information and Configuration

DAC_GetNumDacs()

Purpose

Retrieve the number of DAC channels on the selected card so an application can adapt to different models.

Signature
UInt32 DAC_GetNumDacs(UInt32 CardNum, UInt16 *numDacs);
Arguments
CardNum
The selected card.
numDacs
Receives the number of DAC channels.
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_GetMaxCounts()

Purpose

Retrieve the highest valid raw DAC count for the selected card: normally 4095 for a 12-bit DAC or 65535 for a 16-bit DAC.

Signature
UInt32 DAC_GetMaxCounts(UInt32 CardNum, UInt32 *maxCounts);
Arguments
CardNum
The selected card.
maxCounts
Receives the maximum count value.
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_ConfigureVoltageRestrictMode()

Purpose

Enable or disable the board's voltage-restrict safety mode. Pass false to permit normal DAC output after known output values and update mode have been configured.

Signature
UInt32 DAC_ConfigureVoltageRestrictMode(UInt32 CardNum, LongBool bRestricted);
Arguments
CardNum
The selected card.
bRestricted
Nonzero enables voltage restriction; zero disables it.
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_ConfigureSimultaneousMode()

Purpose

Select simultaneous or asynchronous DAC updating and optionally issue an update (LDAC) using the last commanded values.

Signature
UInt32 DAC_ConfigureSimultaneousMode(UInt32 CardNum, LongBool bUpdate, LongBool bSimultaneous);
Arguments
CardNum
The selected card.
bUpdate
Nonzero updates all DAC outputs to their last commanded values.
bSimultaneous
Nonzero selects simultaneous mode; zero selects asynchronous mode.
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

Notes

The native DLL parameter order is bUpdate, then bSimultaneous. Some older C# declarations and manual text reversed those two names.

DAC_GetRange() / DAC_GetRanges()

Purpose

Retrieve the configured range for one DAC or all DACs. When supported, the DLL reads the range selected by the board's DIP switches.

For boards that cannot report their switch-selected range, the value comes from DLL state previously established with DAC_SetRange() or DAC_SetRanges().

Signature
UInt32 DAC_GetRange(UInt32 CardNum, UInt16 iDac, UInt32 *RangeCode);
UInt32 DAC_GetRanges(UInt32 CardNum, UInt16 *numRangeCodes, UInt32 *RangeCodes);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_SetRange() / DAC_SetRanges()

Purpose

Tell the DLL which range is configured for one DAC or all DACs on boards that cannot read their range-selection switches.

Signature
UInt32 DAC_SetRange(UInt32 CardNum, UInt16 iDac, UInt32 RangeCode);
UInt32 DAC_SetRanges(UInt32 CardNum, UInt32 numRangeCodes, const UInt32 *RangeCodes);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_EnableCalibration()

Purpose

Enable or disable DLL-side software calibration using the per-range, per-DAC data stored in the board's EEPROM.

Signature
UInt32 DAC_EnableCalibration(UInt32 CardNum, UInt16 Enable);
Arguments
Enable
Pass 1 to enable calibration or 0 to disable it.
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_ReloadCalibrationData()

Purpose

Refresh the DLL's shadow copy of EEPROM calibration data after range-switch or EEPROM contents are changed while the process is running. This is primarily a factory or maintenance operation.

Signature
UInt32 DAC_ReloadCalibrationData(UInt32 CardNum);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_GetCalibrationData()

Purpose

Read the EEPROM-derived calibration data for all supported ranges and DACs. This function is primarily intended for factory and calibration utilities.

Signature
UInt32 DAC_GetCalibrationData(UInt32 CardNum, UInt16 *pBufLength, double *pBuf);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_WriteCalibrationData()

Purpose

Update the DLL's shadow copy of per-range, per-DAC calibration data and optionally write it to the board's EEPROM. This function is intended for factory and calibration utilities.

Signature
UInt32 DAC_WriteCalibrationData(UInt32 CardNum, UInt16 *pBufLength, const Byte *pBuf, Boolean bToEEPROM);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC Output and Conversion

DAC_OutputCount() / DAC_OutputCounts()

Purpose

Write raw count values to one DAC or to multiple DACs.

Signature
UInt32 DAC_OutputCount(UInt32 CardNum, UInt16 iDac, UInt32 Counts);
UInt32 DAC_OutputCounts(UInt32 CardNum, UInt16 numCounts, const UInt32 *Counts);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_Output() / DAC_Outputs()

Purpose

Output one or more floating-point voltage or current values. The DLL converts each value to counts using the configured range and resolution, and applies software calibration when enabled.

Signature
UInt32 DAC_Output(UInt32 CardNum, UInt16 iDac, double Value);
UInt32 DAC_Outputs(UInt32 CardNum, UInt16 NumValues, const double *Values);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

DAC_ValueFromCounts()

Purpose

Convert a raw DAC count into the equivalent floating-point voltage or current for the configured DAC range.

Signature
UInt32 DAC_ValueFromCounts(UInt32 CardNum, UInt16 iDac, UInt32 Counts, double *Value);
Returns

A Win32 error code. ERROR_SUCCESS (zero) means success.

Using Digital Integration Features

Many models support advanced digital input and output features, including pulse measurement and generation, edge counting, and IRQ generation. See the Digital Integration Features Register Reference Manual for the register model and API details.

Handling IRQs

WaitForIRQ()

Purpose

Block the calling thread until the selected card generates an IRQ, the request is aborted, or an error occurs. It is intended for a dedicated IRQ-service thread.

Signature
UInt32 WaitForIRQ(Int32 CardNum);
Arguments
CardNum
The card whose IRQ is being awaited.
Returns

Nonzero when the function returns because an IRQ occurred. Zero means the wait was aborted or failed.

After a zero return, GetLastError() returns ERROR_OPERATION_ABORTED for an aborted request and ERROR_INVALID_FUNCTION when another thread is already waiting on that card.

AbortRequest()

Purpose

Cancel the pending request begun by WaitForIRQ(), COSWaitForIRQ(), or the internal wait used by WDGHandleIRQ().

Signature
UInt32 AbortRequest(Int32 CardNum);
Returns

Nonzero on success; zero when there was no pending request to abort or the operation failed.

Notes

Call AbortRequest() or CloseCard() before terminating the thread or process that owns a pending wait. A wait left in the driver after its user-mode thread has disappeared can resume into invalid process state and crash Windows.

If an application has already crashed while a wait was pending, do not call AbortRequest() from another process. Disable all AIOWDM devices in Device Manager and then re-enable them to clear the stale request.

CloseCard()

Purpose

Abort pending IRQ activity and close the DLL handle for the selected card. Use it before changing or reloading card-number assignments and before terminating a thread that owns an IRQ wait.

Signature
UInt32 CloseCard(Int32 CardNum);
Returns

Nonzero on success; zero if there was no open handle or the close failed.

Notes

Windows closes ordinary handles when the DLL unloads, but that is too late to safely cancel a wait owned by a thread that has already exited.

Handling Change-of-State IRQs (8255 DIO Cards)

COSWaitForIRQ()

Purpose

Wait for an IRQ and immediately read the card's PPI data after the IRQ. This is designed for the PCI-DIO-24S, PCI-DIO-48S, IOD24S, and IOD48S.

Do not use this function on an unrelated card merely because it supports IRQs; reads can have side effects on some hardware. Verify the device ID with QueryCardInfo() first.

Signature
UInt32 COSWaitForIRQ(Int32 CardNum, UInt32 PPIs, void *pData);
Arguments
CardNum
The selected card.
PPIs
The number of PPIs to read. The PCI-DIO-24S has one; the PCI-DIO-48S has two. A PCI-DIO-48S may be read with one when the second PPI is not needed.
pData
A buffer with at least three bytes per PPI.
Notes

In Visual Basic, pass the first element of a byte array sized to at least three bytes per PPI. For two PPIs, for example: Dim Data(0 To 5) As Byte, then COSWaitForIRQ(CardNum, 2, Data(0)).

Watchdog Timer and Computer Status Monitor Functions

These functions are designed for supported watchdog boards, especially the PCI-WDG-CSM family. Verify the card's device ID before calling a watchdog-specific function.

WDGInit()

Purpose

Prepare the selected watchdog card for subsequent WDG* calls such as WDGPet() and WDGHandleIRQ().

Signature
UInt32 WDGInit(Int32 CardNum);
Returns

Nonzero on success; zero on failure.

WDGHandleIRQ()

Purpose

Configure how the next watchdog IRQ is handled. The card must first be prepared with WDGInit().

Signature
UInt32 WDGHandleIRQ(Int32 CardNum, UInt32 Action);
Arguments
Action
Selects one of the actions in the table below.
Returns

Nonzero on success; zero on failure. Values greater than 5 are not supported.

ActionBehavior
0Ignore. Allow the watchdog circuit to perform its configured hard reset when the timer expires.
1Disable. Disable the watchdog when its IRQ occurs.
2Soft shutdown and restart. Change the watchdog timeout to 90 seconds, then begin an ordinary Windows shutdown. The later hard reset provides a fallback.
3Disable and soft restart. Disable the watchdog, then begin an ordinary Windows restart.
4Mostly-soft shutdown and restart. Change the watchdog timeout to 90 seconds and begin a shutdown that allows a limited save interval but cannot be cancelled. The later hard reset provides a fallback.
5Disable and mostly-soft restart. Disable the watchdog, then begin the non-cancellable, limited-save restart sequence.

WDGSetTimeout()

Purpose

Stop the watchdog timer, configure its timeout, and prepare it for WDGStart(). The card must first be initialized with WDGInit().

Signature
double WDGSetTimeout(Int32 CardNum, double Milliseconds, double MHzClockRate);
Arguments
Milliseconds
The requested timeout in milliseconds.
MHzClockRate
The board clock in MHz. Use PCI_WDG_CSM_RATE or P104_WDG_CSM_RATE (2.08333), or ISA_WDG_CSM_RATE (0.894886), as appropriate.
Returns

The actual timeout achieved, which is quantized by counter resolution; zero on failure.

WDGSetResetDuration()

Purpose

Configure the PCI-WDG-CSM reset-pulse duration or control the ISA WDG-CSM buzzer. The card must first be initialized with WDGInit().

Signature
double WDGSetResetDuration(Int32 CardNum, double Milliseconds, double MHzClockRate);
Arguments
Milliseconds
Zero disables the ISA buzzer or prevents the PCI board from asserting reset. A value greater than zero and no more than 1.0 enables the buzzer or selects an infinite PCI reset duration. Larger values request a finite PCI reset duration.
MHzClockRate
The board clock in MHz.
Returns

The finite reset duration achieved. Returns zero for failure, buzzer-only operation, disabled reset, or infinite reset duration.

WDGPet()

Purpose

Reset the watchdog timers before they expire. The card must first be initialized with WDGInit().

Signature
UInt32 WDGPet(Int32 CardNum);
Returns

Nonzero on success; zero on failure.

WDGReadTemp()

Purpose

Read the watchdog board's temperature sensor in degrees Fahrenheit.

Signature
double WDGReadTemp(Int32 CardNum);
Returns

The measured temperature. A board without a temperature sensor reports 194.0 °F; failure returns 0.0 °F. A valid reading is not expected below 7.0 °F.

WDGReadStatus()

Purpose

Read the watchdog status byte at base offset 4. This read also enables watchdog IRQs, although IRQs remain ignored unless WDGHandleIRQ() has configured handling.

Signature
UInt32 WDGReadStatus(Int32 CardNum);
Returns

A status byte from 0x00 through 0xFF on success; a value greater than 0xFF on failure. The bit definitions are documented in the board manual.

WDGStart()

Purpose

Start watchdog timing after the timeout and reset behavior have been configured.

Signature
UInt32 WDGStart(Int32 CardNum);
Returns

Nonzero on success; zero on failure.

WDGStop()

Purpose

Stop watchdog timing.

Signature
UInt32 WDGStop(Int32 CardNum);
Returns

Nonzero on success; zero on failure.

EmergencyReboot()

Purpose

Begin a mostly-soft restart that gives Windows and applications a limited opportunity to save data but does not allow the restart to be cancelled.

Signature
UInt32 EmergencyReboot(void);
Returns

Nonzero on success; zero on failure, commonly because the process lacks permission to restart the system.

Plug-and-Play — Detecting and Identifying Hardware

Applications that may encounter more than one AIOWDM device should discover cards at runtime. GetNumCards() supplies the list size and QueryCardInfo() identifies each entry. Subsequent API calls use the selected zero-based CardNum.

Card Discovery

GetNumCards()

Purpose

Return the number of AIOWDM cards currently present in the DLL's card list. Valid card numbers are zero through one less than the returned count.

Signature
Int32 GetNumCards(void);
Returns

The number of detected cards.

QueryCardInfo()

Purpose

Retrieve the device ID, optional absolute base address, and friendly name for the selected card. Use this function to identify which model occupies a given CardNum.

Signature
UInt32 QueryCardInfo(Int32 CardNum, UInt32 *pDeviceID, UInt32 *pBase, UInt32 *pNameSize, unsigned char *pName);
Arguments
CardNum
The card to query.
pDeviceID
Receives the card's device ID. For PCI cards this is the PCI device ID. May be null when not needed.
pBase
Receives the absolute I/O base address. May be null. Modern applications using RelInPort* and RelOutPort* normally should pass null.
pNameSize
On entry, the friendly-name buffer size. On exit, receives the required size including the terminating null. May be null when the name is not needed.
pName
Receives the Windows ANSI friendly name. If the supplied size is zero or too small, the buffer is not modified.
Returns

Nonzero on success; zero on failure, commonly because CardNum is invalid or card information could not be read.

Card Number Assignment

These functions are intended for setup and configuration utilities that need to inspect or change the visible CardNum assigned to installed boards. Ordinary acquisition applications normally only need GetNumCards() and QueryCardInfo().

AIOWDM card numbers are zero-based. By default, detected cards are ordered by PCI bus, device, and function. The assignment API swaps two visible card numbers and persists that preference; it does not move hardware or change Windows device IDs or PCI location values.

Call CloseCard() for every open card before calling SwapCards(), ResetCardOrder(), or ReloadCardList(). The configuration process may need to run elevated because the persisted order is stored in Windows device-interface registry storage.

ErrorTypical meaning
ERROR_INVALID_PARAMETERAn invalid card number or output pointer was supplied.
ERROR_NOT_FOUNDThe requested card or its device-interface registry storage could not be found.
ERROR_BUSYA card is open or an IRQ wait/callback prevents the card list from being changed safely.
ERROR_ACCESS_DENIEDWindows denied permission to update the persisted order.

QueryCardLocation()

Purpose

Retrieve the PCI bus, device, and function numbers associated with a visible CardNum. Pair this with QueryCardInfo() when displaying a multi-card system to a user.

Signature
UInt32 QueryCardLocation(Int32 CardNum, UInt32 *pBus, UInt32 *pDev, UInt32 *pFun);
Arguments
CardNum
The visible card number to inspect.
pBus
Receives the PCI bus number; may be null.
pDev
Receives the PCI device number; may be null.
pFun
Receives the PCI function number; may be null.
Returns

Nonzero on success; zero on failure.

SwapCards()

Purpose

Exchange the visible card numbers assigned to two installed AIOWDM cards and persist the new order.

The calling process sees the new order immediately. Later processes and reboots use it while Windows continues to identify the same installed device/interface instances. The API is deliberately swap-based so the visible list remains compact and contains no gaps.

Signature
UInt32 SwapCards(Int32 CardNumA, Int32 CardNumB);
Arguments
CardNumA
The first visible card number.
CardNumB
The second visible card number.
Returns

Nonzero on success; zero on failure.

Example
// Cards 0 and 2 exchange positions.
SwapCards(0, 2);

ResetCardOrder()

Purpose

Delete all persisted card-order values and restore the DLL's default PCI bus/device/function ordering. The implementation reloads the card list in the calling process after a successful reset.

Signature
UInt32 ResetCardOrder(void);
Returns

Nonzero on success; zero on failure.

ReloadCardList()

Purpose

Rebuild the DLL's current card list from installed devices and persisted order values. Use it after hardware changes or after another process changes card order.

Signature
UInt32 ReloadCardList(void);
Returns

Nonzero on success; zero on failure. The function reports ERROR_BUSY when any card is open or an IRQ wait/callback is active.

  1. Start the setup utility elevated when system policy requires administrative rights for device-interface registry writes.
  2. Call GetNumCards().
  3. For each card, call QueryCardInfo() and QueryCardLocation(), then display the model, device ID, and PCI bus/device/function location.
  4. Ask the user which two visible card numbers should be exchanged.
  5. Call CloseCard() for every card that may be open in the process.
  6. Call SwapCards(cardA, cardB).
  7. Display the card list and locations again to confirm the new order.