Channels ▼
RSS

.NET

A WDM IEEE 1394 Configuration ROM Decoder

Source Code Accompanies This Article. Download It Now.


Dec99: A WDM IEEE 1394 Configuration ROM Decoder

Bill is a senior software engineer at LSI Logic (formerly Symbios Logic). His current responsibilities include developing 1394 device drivers, software, and utilities. He can be contacted at http://www .geocities.com/SiliconValley/Haven/4824.


In the August, 1999, issue of DDJ, I wrote the article "An IEEE 1394 Configuration ROM Decoder." That article discussed how to read and decode the configuration ROM of 1394 peripherals on Windows 95 using the Texas Instruments TSBKPCI 1394 controller and the TI LynxSoft drivers. In this article, I'll present a new version of the DumpRom utility that runs on Windows 98 and Windows 2000. (The complete source code to this version of DumpRom is available electronically; see "Resource Center," page 5.)

On Windows 98 and Windows 2000, Microsoft's 1394 architecture is much more complicated than that of TI's LynxSoft on Windows 95. Microsoft's architecture is based on the Windows Driver Model (WDM) and is a multilayered design. The most important layer in this design is 1394BUS.SYS, which is also known as the 1394 bus class driver. 1394BUS.SYS is responsible for presenting a unified, low-level interface to 1394. Underneath 1394BUS.SYS are the 1394 port drivers. These drivers are responsible for communicating directly to the various 1394 controllers. The port drivers shipped with Windows 98 include:

  • OHCI1394.SYS, port driver for the Open Host Controller Interface 1394 controllers.
  • TILYNX.SYS, port driver for the TI TSBKPCI and TSBKPCI403 1394 controllers.

  • AHA894X.SYS, port driver for the Adaptec AHA894X 1394 controllers.

On top of 1394BUS.SYS are the higher level drivers that control different categories of peripherals connected to the 1394 bus. Those I am familiar with include:

  • SBP2.SYS, file system driver for the 1394 disk drives.
  • SONYDCAM.SYS, video driver for the Sony CCM-DS250 and TI MC680-DCC 1394 digital cameras.

These high-level drivers, in turn, connect with various other subsystems. For example, SONYDCAM.SYS registers with the streaming drivers as a source of video. SBP2.SYS, on the other hand, registers with the SCSI subsystem to provide a source of file storage; see Figure 1.

Windows 1394 API

As far as I know, Microsoft has not published a 1394 API for applications to use directly. Luckily, the Windows 98 DDK provides the source to an application/driver combination that can be used to test and debug 1394 devices. These files are named Win1394.EXE and 1394Diag.SYS. Win1394.EXE is a Win32 application that communicates with the driver. 1394Diag .SYS is a WDM driver that registers with the system as the handler of diagnostic 1394 peripherals. A diagnostic peripheral is one that is plugged into the system when the 1394 port driver is in diagnostic mode. This is a special mode of the port driver that allows you to circumvent the normal binding of a device to higher level drivers. The binding of the device is then rerouted to a custom driver that is used to test and debug the device. Using the DDK source as a base, I ported the source code from the previous article into the new DumpRom.EXE utility. DumpRom .EXE uses the WDM driver DumpRomD .SYS to communicate with diagnostic 1394 peripherals.

DumpRom Installation and Device Recognition

Along with the source code to the WDM version of DumpRom, I have included a setup program that will install the source and executables. To install DumpRom, unzip WDUMPROM.ZIP onto a floppy disk. Then run SETUP.EXE from the floppy. SETUP will copy the files onto your hard drive and create task bar links to the DumpRom utility and documents. The default installation directory is C:\98ddk\ src\1394\DumpRom\.

To install a diagnostic 1394 device, you must first launch DumpRom. From the task bar, select Start|Programs|Alexander|WDM Dump ROM|DumpRom. DumpRom will not automatically put the 1394 port driver into diagnostic mode. To do this, select 1394 Device|Find Device. The Find Device code puts the 1394 port driver into diagnostic mode. At this point, connecting a 1394 device will cause the bus class driver to detect a new diagnostic device and Windows will look for INF files that contain an entry for 1394\ 031887&040892 type devices. Windows will now prompt you for the location of the INF file. Inside of DumpRomD .INF, Windows will find the following entry under the Alexander manufacturer section:

[Alexander]

; Generic Diagnostic Device

%1394\031887&040892.DeviceDesc%=DumpRom,1394\031887&040892

This entry identifies DumpRomD.SYS as the handler of all 1394 diagnostic devices.

All diagnostic devices are listed in the Windows 98 and Windows 2000 registry under the key HKLM\SYSTEM\CurrentControlSet\Enum\1394\031887&040892. Under this key, each diagnostic peripheral will have a subkey that is the byte-wise reversal of the device's global unique ID (GUID) stripped of leading zeros. For instance, my LSI SYM13FW500 1394-to-ATA/ATAPI bridge has the GUID 0x00A0B80000005009. So the subkey in the registry is 950000000B8A000.

Next, Windows will locate the DumpRomD.SYS driver and copy it to the C:\Windows\System32\Drivers directory. DumpRomD.SYS is dynamically loadable and should now be servicing the device. If DumpRom cannot find the device, you'll need to bring up the Device Manager and try to delete and reinstall the device. If this does not work, try the Update Driver button and direct Windows to use DumpRomD.SYS.

Dumping and Decoding the Configuration ROM

Once the device has been found and DumpRomD.SYS has been loaded, you can now read the configuration ROM and display it by selecting 1394 Device|Dump Configuration ROM. As you can see in Listing One, the output is very much like that in the Windows 95 version of DumpRom.

Disconnecting the Device

After reading and decoding the configuration ROM, the only other option you have is to disconnect from the device. You can do this by selecting 1394 Device|Disconnect from Device. The disconnect code takes the 1394 port driver out of diagnostic mode and then prompts the user to physically disconnect the device from the 1394 bus. A word of caution here: A device will continue to look like a diagnostic device until the port driver is out of diagnostic mode and the device is disconnected from the bus. Just taking the port driver out of diagnostic mode is not good enough. Disconnecting the device forces the port driver to remove the device from its topology map. When the device is reconnected, it will be reenumerated as a normal device and will be bound to the driver that handles that device category.

How the New Code Works

Because this is a follow-up from a previous article, I will not discuss the decode algorithm. The issues that are of interest are as follows:

  • Placing the 1394 bus class driver into diagnostic mode.
  • Binding DumpRomD.SYS to a device.

  • Interfacing to DumpRomD.SYS.

  • Interfacing to 1394BUS.SYS.

Before any device can be recognized as a diagnostic device, you must first select 1394 Device|Find Device to place the 1394 port driver, 1394BUS.SYS, into diagnostic mode. When this menu item is selected, DumpRom calls the Find1394Device() routine. Find1394Device() is a fairly simple routine that will prompt users to disconnect the target 1394 device, place the bus into diagnostic mode, prompt users to reconnect the device, and then confirm that there is a diagnostic device attached.

To place the bus in diagnostic mode, Find1394Device() calls the DiagnoseAllAdapters() routine. Before discussing DiagnoseAllAdapters(), I must explain a little about 1394BUS.SYS. Because 1394BUS.SYS is a class driver, it can have multiple port drivers underneath it. As a result, the class driver actually looks like a collection of 1394 buses to the system and you must place each bus or port into diagnostic mode. Port is an unfortunate naming with 1394. In Windows, port means the 1394 port driver that is controlling a 1394 adapter. Do not confuse this with the physical 1394 ports on the adapter to which you connect peripherals. There are generally three physical ports on a 1394 adapter, but to Windows, all three of these physical ports are handled by only one port driver. To avoid confusion, I called my function DiagnoseAllAdapters() instead of DiagnoseAllPorts().

When DiagnoseAllAdapters() is called, it enters a loop that will open all 1394 buses and put them into diagnostic mode. To open the first 1394 bus, the loop uses the standard Win32 CreateFile() function with the symbolic device link name "\\\\.\\1394BUS0." For each iteration through the loop, this symbolic link name is incremented to open the next device. For example, the second 1394 bus has the name "\\\\.\\1394BUS1." Once a bus device is open, DiagoseAllAdapters() calls the Win32 DeviceIoControl() function with IO Control Code IOCTL_1394_TOGGLE_ ENUM_TEST_ON, which places the bus into diagnostic mode (see Listing Two).

You will notice that DiagnoseAllAdapters() is also used to leave diagnostic mode. The bMode parameter indicates whether to enter or leave diagnostic mode. A value of True means to enter diagnostic mode, and False leaves diagnostic mode. In the case of False, the IO Control Code passed to DeviceIoControl() is IOCTL_1394_TOGGLE_ENUM_TEST_OFF.

Once all 1394 buses are in diagnostic mode, any device plugged in at this point will appear as a diagnostic device. Initially, the system will not know about the new device because it has not been registered previously. The system will run the setup process that prompts users for the location of the INF and driver files and loads DumpRomD.SYS.

To confirm that there is a device bound to DumpRomD.SYS, Find1394Device() next calls the ConfirmDeviceAttached() routine. ConfirmDeviceAttached() opens device "\\\\.\\DUMPROMD" and issues a GET_NODE_INFO IOCTL, which retrieves a list of devices that are bound to DumpRomD.SYS. The device list is built by a routine called DumpRomDGetDeviceInfo(), which lists all of the devices on every 1394 bus associated with DumpRomD. On return from DumpRomD, ConfirmDeviceAttached() selects one device from the list and returns to Find1394Devices() (see Listing Three).

Once a device is found and selected, DumpRom calls DecodeConfigRom(), which reads the entire configuration ROM on the device one QUADLET at a time and places the image into a buffer. The old DumpRom program used a routine called ReadQuadlet() to read the configuration ROM image. This version of DumpRom employs the Win32 ReadFile() function with a buffer of four bytes to accomplish the same task. The ReadFile() call is translated to an IRP_MJ_READ IOCTL by the system, which then calls DumpRomDRead() inside of DumpRomD .SYS. In a nutshell (that is, excluding all of the IRP details), DumpRomDRead() builds an IRB (IO Request Block) structure with a function code of REQUEST_ ASYNC_READ and calls 1394BUS.SYS. 1394BUS transmits the 1394 QUADLET Read Request packet on the bus and receives a Read Response packet back from the device. The quadlet value is conveyed to DumpRomDRead(), which returns the value back to ReadConfigRom(); see Figure 2.

The last thing that DumpRom does is decode the configuration ROM, which is achieved via the DecodeConfigRom() function. The source to DecodeConfigRom() did not change significantly from the old version of DumpRom. You can find a detailed description of DecodeConfigRom() in my August 1999 article.

Conclusion

The WDM version of DumpRom is much more complicated than its Windows 95 predecessor. The overall functionality is the same, but the additional driver module, DumpRomD.SYS, greatly increased the development time of the code. Also, hooking the device driver into the system by placing the bus class driver into diagnostic mode added to this level of complexity. Complexity aside, once the driver is installed properly, DumpRom works quite well. It also serves as a convenient tool to debug your configuration ROM under Windows 98 and Windows 2000. Because DumpRom can be dynamically hooked and unhooked from the system, you can decode the configuration ROM of your device and then reconnect the device to continue normal operation without rebooting the system.

References

Alexander, William F. "IEEE 1394 Configuration ROM Decoder," DDJ, August 1999.

ISO/IEC 13212: 1994(E) ANSI/IEEE Std 1212, 1994 Edition, pp. 79-100.

IEEE Standard for a High Performance Serial Bus, IEEE Std 1394-1995, August 30, 1996.

Microsoft Windows 2000 DDK, Beta 2, 1998.

Microsoft Windows 98 DDK, 1998.

Microsoft Developer Network Library, April 1999.

DDJ

Listing One

Device \\.\1394BUS0 in diagnostic mode
Found 1 devices on \\.\DUMPROMD
Device List:
Name = DumpRomD000, Port = 0000, Bus = 03FF, Node = 0000

Selected device: index=0,Name=\\.\DumpRomD000,Port=0000,Bus=03FF,Node=0000

Raw Data Dump of the Configuration ROM

1394 Addr Off    Data
-------------    --------  --------  --------  -------- 
FFFF:F0000400    04302F55  31333934  00FF5002  00A0B800  
FFFF:F0000410    00005009  0006E8D7  0C0083C0  0300A0B8  
FFFF:F0000420    81000011  0400500A  81000015  D1000001  
FFFF:F0000430    000C6208  1200609E  13010483  3C002600  
FFFF:F0000440    5400C000  3A401E08  3800609E  390104D8  
FFFF:F0000450    3B000000  3D000000  14000000  17000000  
FFFF:F0000460    8100000E  000568A5  00000000  00000000  
FFFF:F0000470    4C534920  4C6F6769  63000000  0006EBEF  
FFFF:F0000480    00000000  00000000  4C534920  35303120  
FFFF:F0000490    72657620  42330000  000AE09E  00000000  
FFFF:F00004A0    00000000  53594D31  33465735  30302D44  
FFFF:F00004B0    49534B20  44524956  45000000  00000000  
FFFF:F00004C0    00000000  

Decode of the Configuration ROM

1394 Addr Off Quadlet  Meaning
------------- -------- --------------------------------------------------

Confiruation ROM Header
FFFF:F0000400 04302F55 info_length=04, crc_length=30, rom_crc_value=2F55

Bus_Info_Block
FFFF:F0000404 31333934 bus_name=31333934 ("1394")
FFFF:F0000408 00FF5002 irmc=0, cmc=0, isc=0, bmc=0, cyc_clk_acc=FF, max_rec=5
FFFF:F000040C 00A0B800 node_vendor_id=00A0B8, chip_id_hi=00
FFFF:F0000410 00005009 chip_id_lo=00005009

Root_Directory
FFFF:F0000414 0006E8D7 length=0006, crc=E8D7
FFFF:F0000418 0C0083C0 Node_Capabilities spt 64 fix lst drg 
FFFF:F000041C 0300A0B8 Module_Vendor_Id 00A0B8
FFFF:F0000420 81000011 Textual_Descriptor leaf ind_off=000011 (FFFF:F0000464)
FFFF:F0000424 0400500A Module_Hw_Version 00500A
FFFF:F0000428 81000015 Textual_Descriptor leaf ind_off=000015 (FFFF:F000047C)
FFFF:F000042C D1000001 Unit_Directory directory ind_off=000001 (FFFF:F0000430)

Unit_Directory directory referenced from FFFF:F000042C
FFFF:F0000430 000C6208 length=000C, crc=6208
FFFF:F0000434 1200609E Unit_Spec_Id 00609E
FFFF:F0000438 13010483 Unit_Sw_Version 010483
FFFF:F000043C 3C002600 Firmware_Revision 002600
FFFF:F0000440 5400C000 Management_Agent crc_offset=00C000 (FFFF:F0030000)
FFFF:F0000444 3A401E08 Unit_Characteristics 401E08
FFFF:F0000448 3800609E Command_Set_Spec_Id 00609E
FFFF:F000044C 390104D8 Command_Set 0104D8
FFFF:F0000450 3B000000 Commanmd_Set_Revision 000000
FFFF:F0000454 3D000000 key=3D (UNKNOWN) value = 000000
FFFF:F0000458 14000000 Logical_Unit_Number o=0, device_type=00, lun=0000
FFFF:F000045C 17000000 Model_Id value = 000000
FFFF:F0000460 8100000E Textual_Descriptor leaf ind_off=00000E (FFFF:F0000498)

Textual_Descriptor leaf referenced from FFFF:F0000420
FFFF:F0000464 000568A5 length=0005, crc=68A5
FFFF:F0000468 00000000 ....
FFFF:F000046C 00000000 ....
FFFF:F0000470 4C534920 LSI 
FFFF:F0000474 4C6F6769 Logi
FFFF:F0000478 63000000 c...

Textual_Descriptor leaf referenced from FFFF:F0000428
FFFF:F000047C 0006EBEF length=0006, crc=EBEF
FFFF:F0000480 00000000 ....
FFFF:F0000484 00000000 ....
FFFF:F0000488 4C534920 LSI 
FFFF:F000048C 35303120 501 
FFFF:F0000490 72657620 rev 
FFFF:F0000494 42330000 B3..

Textual_Descriptor leaf referenced from FFFF:F0000460
FFFF:F0000498 000AE09E length=000A, crc=E09E
FFFF:F000049C 00000000 ....
FFFF:F00004A0 00000000 ....
FFFF:F00004A4 53594D31 SYM1
FFFF:F00004A8 33465735 3FW5
FFFF:F00004AC 30302D44 00-D
FFFF:F00004B0 49534B20 ISK 

FFFF:F00004B4 44524956 DRIV
FFFF:F00004B8 45000000 E...
FFFF:F00004BC 00000000 ....
FFFF:F00004C0 00000000 ....

Back to Article

Listing Two

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  DiagnoseAllAdapters
//      Puts/Takes all 1394 controllers into/out of diagnostics mode
//  Entry:
//      hWnd    Window handle
//      bMode   Mode flag
//              TRUE = turn on diagnostic mode
//              FALSE = turn off diagnostic mode
//  Exit:
//      TRUE    All 1394 adapters are in/out of diagnostic mode
//      FALSE   operation failed
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL
DiagnoseAllAdapters (
    HWND hWnd, 
    BOOL bMode)
{
    //#define DEBUGFLAGS DebugThisRoutine

    BOOL            retcode;
    HANDLE          hDev;
    DWORD           dwRet;
    DWORD           dwBytesRet;
    CHAR            DeviceName[STRING_SIZE];
    DWORD           index;
    DWORD           numAdaptersToggled;

    DBOUT (DBG_LF_ENTRY, "DiagnoseAllAdapters\r\n");

    // Assume failure
    retcode = FALSE;

    // Get 1394 bus class driver's symbolic name
    strcpy (DeviceName, BUS_SYMBOLIC_LINK);
    pDiagnosticDeviceName = DeviceName;

    // Find all of the host controllers
    for(index = 0, numAdaptersToggled = 0; index < 10; index++)
    {
        // Create next host controller name
        pDiagnosticDeviceName[11] = (char)('0' + index);
        // try to open it
        //MyPrintf ("Attempting to open 1394 adapter %s  ...",
                                           pDiagnosticDeviceName);
        hDev = CreateFile(
                    pDiagnosticDeviceName,
                    GENERIC_WRITE | GENERIC_READ,
                    FILE_SHARE_WRITE | FILE_SHARE_READ,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL);
        if(hDev == INVALID_HANDLE_VALUE)
        {
            continue;
        }
        // Put into or take out of diagnostic mode
        dwRet = DeviceIoctl( hWnd, hDev, DeviceName,
            (bMode) ? IOCTL_1394_TOGGLE_ENUM_TEST_ON : 
            IOCTL_1394_TOGGLE_ENUM_TEST_OFF, NULL, 0, NULL, 0, &dwBytesRet);
        if (!dwRet)
        {
            dwRet = GetLastError();
            MyPrintf ("\r\nError = 0x%08X\r\n");
        }
        else
        {
            numAdaptersToggled++;
            if (bMode == TRUE)
                MyPrintf ("Device %s in diagnostic mode\r\n", DeviceName);
            else
             MyPrintf ("Device %s out of diagnostic mode\r\n", DeviceName);
        }
        // Close the current host controller
        CloseHandle(hDev);
    }
    // Did we toggle any adapters?
    if (numAdaptersToggled != 0)
        retcode = TRUE;
    DBOUT1 (DBG_LF_EXIT, "DiagnoseAllAdapters exit, retcode = %s\r\n",
                                          retcode==TRUE?"TRUE":"FALSE");
    return (retcode);

    #define DEBUGFLAGS DebugFlags
}

Back to Article

Listing Three

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ConfirmDeviceAttached
//      Confirms that a diagnostic 1394 device is attached and ready to go.
//  Entry:
//      hWnd            Window handle
//      szDeviceName    Name of driver device to which a 
//                      diagnotic device should be attached.
//  Exit:
//      TRUE            Device is attached and ready
//      FALSE           No devices present
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL 
ConfirmDeviceAttached (
    HWND hWnd, 
    PSTR szDeviceName)
{
    //#define DEBUGFLAGS DebugThisRoutine

    BOOL            retcode;
    HANDLE          hDev;
    DWORD           dwRet, dwBytesRet;
    PNODE_INFO      pNodeInfo;
    CHAR            tmpBuff[STRING_SIZE];
    ULONG           Node = 0L;
    ULONG           i;
     int ccode;

    DBOUT (DBG_LF_ENTRY, "ConfirmDeviceAttached\r\n");

    // Assume failure
    retcode = FALSE;
    
    // set this to no device under test
    numDevices = 0;
    hDev = INVALID_HANDLE_VALUE;

    // Open the adapter
    hDev = OpenDevice(hWnd, szDeviceName, TRUE);
    if(hDev == INVALID_HANDLE_VALUE)
        goto OpenError;

    // Allocate a buffer
    pNodeInfo = (PNODE_INFO) GlobalAlloc(GPTR, MAX_INFO_BUFF_SIZE);
    if(pNodeInfo == NULL)
        goto AllocError;
    // Extract node info
    dwRet = DeviceIoctl(hWnd, hDev, szDeviceName, GET_NODE_INFO, NULL, 0, 
                               pNodeInfo, MAX_INFO_BUFF_SIZE, &dwBytesRet);
    if(dwRet == 0)
        goto NodeInfoError;
    // let's go ahead and throw this in the edit control
    // get the number of current devices
    numDevices = pNodeInfo->numEntries;
    MyPrintf ("Found %d devices on %s\r\n", numDevices, szDeviceName);

    // allocate memory for keeping info about devices around
    // if we have device info get rid of it for new
    if(pDeviceInfo != NULL)
        GlobalFree(pDeviceInfo);
    // now allocate memory for device info on all devices
    pDeviceInfo = (PDEVICE_INFO) GlobalAlloc(GPTR, 
                                   sizeof(DEVICE_INFO) * numDevices);
    i = pNodeInfo->numEntries-1;
    
    // print out node info
    if (pNodeInfo->numEntries)
        MyPrintf ("Device List:\r\n");
    while(Node < pNodeInfo->numEntries)
    {
        // save device info in our freshly allocated buffer
        pDeviceInfo[i].nodeInfo = pNodeInfo->entry[Node];
        MyPrintf (  "Name = %s, Port = %04X, Bus = %04X, Node = %04X\r\n", 
                    pDeviceInfo[i].nodeInfo.LinkName, 
                    pDeviceInfo[i].nodeInfo.RawAddress.Port, 
                    pDeviceInfo[i].nodeInfo.RawAddress.NA_Bus_Number,
                    pDeviceInfo[i].nodeInfo.RawAddress.NA_Node_Number);
        // if it's a raw device then save that in link name
        // otherwise, fill in with real name
        if(strcmp(pDeviceInfo[i].nodeInfo.LinkName, RAW_DEVICE) != 0)
        {
            // it's not a raw device so let's stick stuff on front
            strcpy(tmpBuff, DEFAULT_DEVICE_LINK);
            strcpy(&tmpBuff[4], pDeviceInfo[i].nodeInfo.LinkName);
            strcpy(pDeviceInfo[i].nodeInfo.LinkName, tmpBuff);
            pDeviceInfo[i].bRawDevice = FALSE;
        }
        else
        {
            // just copy in global symbolic link
            strcpy(pDeviceInfo[i].nodeInfo.LinkName, GLOBAL_SYMBOLIC_LINK);
            pDeviceInfo[i].bRawDevice = TRUE;
        }
        // next node
        Node++;
        i--;
    }
    // Select a device and default to the first one
    deviceUnderTest = 0;
    if (pNodeInfo->numEntries > 1)
    {
        // Display device dialog box and let use chose one
        ccode = DialogBox((HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE), "SelectDevice", hWnd, (DLGPROC) SelectDeviceDlgProc);
        if (ccode != TRUE)
            goto Exit;

    }
    // Do we have any entries?
    if (pNodeInfo->numEntries)
        retcode = TRUE;
    // Display selected device
    i = deviceUnderTest;
    MyPrintf ("\r\n\r\nSelected device:  index = %d, Name = %s, 
           Port = %04X, Bus = %04X, Node = %04X\r\n", i,
                pDeviceInfo[i].nodeInfo.LinkName, 
                pDeviceInfo[i].nodeInfo.RawAddress.Port, 
                pDeviceInfo[i].nodeInfo.RawAddress.NA_Bus_Number,
                pDeviceInfo[i].nodeInfo.RawAddress.NA_Node_Number);
Exit:
    // free up resources
    if (hDev != INVALID_HANDLE_VALUE)
        CloseHandle(hDev);
    if(pNodeInfo)
        GlobalFree(pNodeInfo);
    DBOUT1 (DBG_LF_EXIT, "ConfirmDeviceAttached exit, retcode = %s\r\n", 
                                             retcode==TRUE?"TRUE":"FALSE");
    return (retcode);
OpenError:
   MyPrintf ("\r\nConfirmDeviceAttached: Unable to open %s\r\n",szDeviceName);
   goto Exit;
AllocError:
    MyPrintf ("\r\nConfirmDeviceAttached: Unable to allocate memory\r\n");
    goto Exit;
NodeInfoError:
    MyPrintf ("\r\nConfirmDeviceAttached: 
                               Unable to read node information from %s\r\n");
    goto Exit;

    #define DEBUGFLAGS DebugFlags
}

Back to Article


Copyright © 1999, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video