Keyspan Developer Documentation
USB to Serial Programming
Windows 98/Me/2000/XP
 
Keyspan acknowledges that USB Serial conversion is becoming more and more useful to vertical markets. While our drivers are designed to be compatible with a large number of existing hardware and software applications, we realize developers may require features that are not supported in the existing product. We are always eager to learn of devices or applications that push our adapters/drivers capabilities. Below is information that may be useful to code developers but that is inappropriate for most "end-users."
 
Accessing USB Serial Adapters:
 
We attempted to support as much as possible of the "Microsoft Win32 Serial Communications" functionality. Please read "Serial Communications in Win32"( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp ) for an in depth description. 
 
The following fields (features) of the DCB structure are not supported:
      fBinary
      fNullStrip (will be added to an upcoming software release)
      EofChar
      fAbortOnError
      fDsrSensitivity (will be added to an upcoming software release)
      XonLim (this value is fixed at an appropriate value for the Keyspan Adapters)
      XoffLim (this value is fixed at an appropriate value for the Keyspan Adapters)
 
The TransmitCommChar() function is also not supported. However, we are hoping to add this feature to products released in the future.
 
Latency:
Due to the nature of usb to serial hardware, there is an inherent latency between when data is written to the driver and when it is sent over USB to the adapter and then written to the serial port. Applications should not depend on timing behavior that is unique to a 16550 compatible UART on the motherboard. While we try to emulate those devices as best as possible, the details of USB make it impossible to preserve the same timing. Further, applications wishing to obtain optimum data transfer should not make single byte "Writes" to the driver. This results in a separate 1-byte USB packet issued for each individual write. If the device is running in "Interrupt mode" (see adapter documentation for explanation of Interrupt versus Bulk mode) the minimum granularity for each packet is 1ms. This would significantly slow down the overall data transfer. Larger "writes" will utilize the USB stack more efficiently and take advantage of its greater transfer speeds. This also ensures that there is always data at the adapter to be sent on the serial port.
 
High Speed Baud Rates:
The Keyspan High Speed USB Serial Adapter (USA19W/USA19QW) and the 4-Port USB Serial Adapter (USA49W/USA49WLC) support baud rates above 115200. The following table shows supported extended baud rates by product part number.
 
USA19W                   230400
USA19QW                230400
USA49W                   230400, 460800, 921600
USA49WLC              230400 *
 
* While the USA49WLC is not rated nor do we support using 460800 or 921600, our testing has shown that stable communication can be made at these speeds.
 
Detecting Keyspan Serial Ports:
 The serial port driver for each Keyspan USB Serial Adapter will publish its "COM" port in the device registry under:
 
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
 
If the adapter is not plugged in, there will be no entry for the device. In this way, applications can locate serial ports that are in fact present.
 
Applications may also use the Setup Device Manager API to locate Serial Port devices. The following is sample code demonstrating how to find Keyspan serial ports and extract the "COMxx" name.
 
 
#include <setupapi.h>
#include <initguid.h>
 
#define MAX_PORTS 256
 
char m_PortArray[MAX_PORTS][10];
unsigned char m_PortCount = 0;
 
// 4d36e978-e325-11ce-bfc1-08002be10318}
DEFINE_GUID(GUID_PORTSDEVS, 0x4d36e978, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00,
0x2b, 0xe1, 0x03, 0x18);
 
void EnumerateKeyspanPorts()
{
      HDEVINFO hDevInfo = NULL;
      SP_DEVINFO_DATA DeviceInterfaceData;
      int i = 0;
      DWORD dataType, actualSize = 0;
      unsigned char dataBuf[MAX_PATH + 1];
 
      // Reset Port List
      m_PortCount = 0;
 
 
      // Search device set
      hDevInfo = SetupDiGetClassDevs((struct _GUID *)&GUID_PORTSDEVS,0,0,DIGCF_PRESENT);
      if ( hDevInfo )
      {
             while (TRUE)
             {
                     ZeroMemory(&DeviceInterfaceData, sizeof(DeviceInterfaceData));
                     DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
                     if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInterfaceData))
                     {
                            // SetupDiEnumDeviceInfo failed
                            break;
                     }
                     
                     if (SetupDiGetDeviceRegistryProperty(hDevInfo,
                            &DeviceInterfaceData,
                            SPDRP_FRIENDLYNAME,
                            &dataType,
                            dataBuf,
                            sizeof(dataBuf),
                            &actualSize))
                     {                           
                            // IF IT'S A KEYSPAN DEVICE
                            if (strstr((char *)dataBuf, "Keyspan"))
                            {
 
                                   char *begin, *end;
                                   m_PortArray[m_PortCount][0] = 0;
                                   if (begin = strstr((char *)dataBuf, "COM"))
                                   {
                                          if (end = strstr(begin, ")"))
                                          {
                                                 *end = 0;
                                                 strcpy(m_PortArray[m_PortCount], begin);
                                          }
                                          
                                   }
                                   // Even if PortName parse fails increment port count
                                   if (m_PortCount++ > MAX_PORTS) break;
                            }
 
                     }
 
                    i++;
                     
             }
      }
      SetupDiDestroyDeviceInfoList(hDevInfo);
}
 
 
Instead of extracting the "COM" name from the FriendlyName, applications can call SetupDiOpenDevRegKey() and then read the "PortName" field using  RegQueryValueEx().
 
Hot-Pluggable Serial Ports:
Since Keyspan USB Serial adapters are hot-pluggable (user may remove and attach the adapter during normal system operation), application developers should expect the serial port to be removed mid-communication. Upon detecting that the device has been removed, the application should close its connection and re-attempt opening the port at some specified interval in case the adapter is re-attached. If the application maintains its connection to a serial port that has been removed, the operating system is unable to clean-up the device object associated with that connection such that when the device is re-attached, a new device instance must be created. The application will no longer have a valid connection to the device even though it has been re-attached. If the application closes its connection and then periodically re-opens a connection to the same device name (COMxx) it can correctly link the appropriate device instance once the adapter has been plugged in. Because some systems power down the USB bus during sleep (resulting in the adapter being removed), this will also allow applications to continue communication with a Keyspan Serial port after sleep-resume.
 
Applications can use the RegisterDeviceNotification() function if running on Windows 2000/XP. This allows user-mode code to detect the removal of a device(s) based on device class (use class=Ports) or a file handle (use the handle returned from CreateFile()). 
 
An application could also assume a WriteFile() failure to indicate that the device has been removed. Generally, there is no reason why a WriteFile() call to a Keyspan Serial port should fail. In this context, failure is described either as a return of false from WriteFile() or that the number of bytes written is less than the number of bytes requested and the port is not in a handshaking hold state.