Uploaded image for project: 'Core ReactOS'
  1. Core ReactOS
  2. CORE-20776

FTDI USB to Serial port doesn't work.

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • Major
    • None
    • None

    Description

      I connected the adapter to my ReactOS laptop, installed the drivers, then connected the serial cable to a Linux PC with cutecom.  Then I tried testing it with echo hello > COM3.  It didn't work.  <0xff> is all that showed up in cutecom no matter what I typed.  I tried figuring out the problem with Claude and Gemini but it kept finding bug after bug, but couldn't get the adapter to work.  This took me like a month, so I decided to just put we found here.  I'm giving up on making this work for now. 

       

      Here's a summary with the bugs and code Claude and Gemini found.

       

      Compatibility Report: Official FTDI CDM Driver Stack on ReactOS
       
      Target Driver: Official FTDI CDM v2.08.24 WHQL driver package (ftdibus.sys,
      ftser2k.sys, ftcserco.dll, serenum.sys)
      Target Hardware: FTDI FT232R USB-to-UART (VID: 0x0403, PID: 0x6001)
      Tested Build: ReactOS 0.4.17-x86-dev (Build 20260826-5483dc0 / NT 5.2 Build 3790
      SP2 target)
      Testing Platforms: Bare-metal Intel ICH7/ICH8 chipset (Toshiba Satellite) & QEMU
      x86
       
      Clean-Room & Provenance Notice:
      All analysis and suggested patches below are derived strictly from black-box
      behavioral testing, live serial/KDB logging, public Microsoft MSDN/WDK
      documentation, and the official Intel UHCI Design Guide [3].
       
      1. NT Kernel I/O Manager (ntoskrnl/iomgr)
       
      Issue: Buffer Corruption & Invalid VA Handling in IoBuildPartialMdl
       
        - File: ntoskrnl/io/iomgr/iomdl.c
        - Applicable Specification: Microsoft WDK documentation for IoBuildPartialMdl
          and MmGetSystemAddressForMdlSafe.
        - Problem Description:
          1.  For Direct/Buffered I/O user requests, SourceMdl->MappedSystemVa is
              initially NULL. ReactOS previously evaluated:
              \text\{TargetMdl->MappedSystemVa} = (\text\{PCHAR})\text\{SourceMdl->MappedSystemVa} + \text\{Offset};
              This produced an invalid low address pointer ((PVOID)Offset). When
              drivers subsequently called MmUnmapLockedPages, dereferencing this
              address caused a Bug Check 0x0A or 0x7E.
          2.  In IoBuildPartialMdl, ReactOS omitted MDL_PAGES_LOCKED from the
              inherited FlagsMask.
          3.  ReactOS unconditionally copied MDL_MAPPED_TO_SYSTEM_VA into
              TargetMdl->MdlFlags even when MappedSystemVa was NULL. When subsequent
              drivers (e.g., usbport.sys) invoked
              MmGetSystemAddressForMdlSafe(TargetMdl), the macro saw
              MDL_MAPPED_TO_SYSTEM_VA asserted, skipped mapping the locked pages, and
              returned NULL, causing silent data drops.
        - Suggested Fix: Ensure TargetMdl inherits MDL_PAGES_LOCKED, and only apply
          MDL_MAPPED_TO_SYSTEM_VA if a non-NULL system address exists:
       
      // In ntoskrnl/io/iomgr/iomdl.c -> IoBuildPartialMdl
       
      ULONG FlagsMask = (MDL_IO_PAGE_READ |
                         MDL_SOURCE_IS_NONPAGED_POOL |
                         MDL_PAGES_LOCKED |
                         MDL_IO_SPACE);
       
      TargetMdl->MdlFlags &= (MDL_ALLOCATED_FIXED_SIZE | MDL_ALLOCATED_MUST_SUCCEED);
      TargetMdl->MdlFlags |= SourceMdl->MdlFlags & FlagsMask;
      TargetMdl->MdlFlags |= MDL_PARTIAL;
       
      /* Only propagate mapped VA if source was mapped */
      if (SourceMdl->MappedSystemVa != NULL)
      {
          TargetMdl->MappedSystemVa = (PCHAR)SourceMdl->MappedSystemVa + Offset;
          TargetMdl->MdlFlags |= (SourceMdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
      }
      else
      {
          TargetMdl->MappedSystemVa = NULL;
      }
       
      2. Run-Time Library / Configuration Manager (sdk/lib/rtl)
       
      Issue: RTL_REGISTRY_DEVICEMAP Rejection Under Volatile \HARDWARE Hive
       
        - File: sdk/lib/rtl/registry.c
        - Applicable Specification: Windows NT Configuration Manager hive semantics;
          MSDN RtlWriteRegistryValue.
        - Problem Description:
          ftser2k.sys registers its serial mapping via
          RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"SERIALCOMM", ...).
          RtlpGetRegistryHandle invoked ZwCreateKey with CreateOptions =
          REG_OPTION_NON_VOLATILE. Because \Registry\Machine\HARDWARE is strictly an
          in-memory volatile tree, cmparse.c correctly enforces that non-volatile
          child keys cannot reside under a volatile parent hive, returning
          STATUS_CHILD_MUST_BE_VOLATILE (0xC0000181).
          ftser2k.sys treats this as a fatal initialization error: it immediately
          calls IoDeleteSymbolicLink, destroys \DosDevices\COMx, and unregisters the
          port.
        - Suggested Fix:
          Ensure RtlpGetRegistryHandle marks keys created relative to
          RTL_REGISTRY_DEVICEMAP (and RTL_REGISTRY_HARDWARE) as REG_OPTION_VOLATILE:
       
      --- a/sdk/lib/rtl/registry.c
      +++ b/sdk/lib/rtl/registry.c
      @@ -113,11 +113,16 @@ RtlpGetRegistryHandle(IN ULONG RelativeTo,
           if (Create)
           {
      +        ULONG CreateOptions = REG_OPTION_NON_VOLATILE;
      +
      +        if (RelativeTo == RTL_REGISTRY_DEVICEMAP || RelativeTo == RTL_REGISTRY_HARDWARE)
      +            CreateOptions = REG_OPTION_VOLATILE;
      +
               Status = ZwCreateKey(KeyHandle,
                                    GENERIC_WRITE,
                                    &ObjectAttributes,
                                    0,
                                    NULL,
      -                             0,
      +                             CreateOptions,
                                    NULL);
           }
       
      3. Serial Class Driver / Upper Filter (drivers/serial/serenum)
       
      Issue: Unbounded Synchronous Read Deadlocks Central PnP Worker
       
        - File: drivers/serial/serenum/detect.c
        - Applicable Specification: WDK Synchronous IRP handling in UpperFilter
          drivers.
        - Problem Description:
          During device enumeration (IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations),
          serenum.sys probes the serial port for legacy mice using
          IoBuildSynchronousFsdRequest(IRP_MJ_READ). ReadBytes waits on a KEVENT using
          KeWaitForSingleObject with Timeout = NULL (infinite).
          When non-mouse serial devices (such as USB UART adapters) are attached,
          ftser2k.sys pends the read request indefinitely. Because this call executes
          synchronously inside the central executive work item
          (PipDeviceActionWorker), the entire PnP subsystem deadlocks permanently,
          freezing device enumeration and system startup.
        - Suggested Fix:
          Add a relative timeout (e.g., 2 seconds) and an IoCancelIrp fallback to
          allow legacy probing to abort gracefully when no device responds:
       
      // In drivers/serial/serenum/detect.c -> ReadBytes
       
      Status = IoCallDriver(LowerDevice, Irp);
      if (Status == STATUS_PENDING)
      {
          /* 2-second relative safety timeout (-20,000,000 in 100ns units) */
          LARGE_INTEGER timeout;
          timeout.QuadPart = -20000000LL;
       
          Status = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, &timeout);
          if (Status == STATUS_TIMEOUT)
          {
              IoCancelIrp(Irp);
              KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
              Status = STATUS_IO_TIMEOUT;
          }
          else
          {
              Status = ioStatus.Status;
          }
      }
       
      4. Setup API (dll/win32/setupapi)
       
      Issue: Omission of Default Parameters Subkey on Driver Service Creation
       
        - File: dll/win32/setupapi/install.c
        - Applicable Specification: Windows Driver Installation Model / SCM Service
          Parameters.
        - Problem Description:
          When installing kernel driver services from an .inf file via
          SetupInstallServicesFromInfSectionExW, ReactOS creates
          HKLM\SYSTEM\CurrentControlSet\Services\<ServiceName>, but does not create
          the standard Parameters subkey unless explicitly instructed by a dedicated
          INF directive. Standard Windows co-installers (such as ftcserco.dll) attempt
          to open Services\<ServiceName>\Parameters to store hardware arbitration
          data; when this key is absent, the co-installer fails.
        - Suggested Fix:
          Automatically create the Parameters subkey when registering any
          SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER:
       
      // In dll/win32/setupapi/install.c -> create_service
       
      if (ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))
      {
          HKEY hParametersKey;
          if (RegCreateKeyExW(hServiceKey, L"Parameters", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hParametersKey, NULL) == ERROR_SUCCESS)
          {
              RegCloseKey(hParametersKey);
          }
      }
       
      5. USB 1.1 UHCI Miniport Driver (drivers/usb/usbuhci)
       
      Issue A: Division-by-Zero on Uninitialized Endpoint Packet Sizes
       
        - File: drivers/usb/usbuhci/usbuhci.c
        - Problem Description:
          In UhciQueryEndpointRequirements, TdCount was computed using direct division
          by EndpointProperties->TotalMaxPacketSize. If queried when descriptors are
          uninitialized or packet sizes report zero, the kernel triggers an immediate
          divide-by-zero Bug Check (0x7E).
        - Suggested Fix:
          Guard the calculations for both Control and Bulk transfer queries:
          if (EndpointProperties->TotalMaxPacketSize == 0)
              TdCount = 0;
          else
              TdCount = EndpointProperties->MaxTransferSize / EndpointProperties->TotalMaxPacketSize;
       
      Issue B: Missing Endpoint Data Toggle Implementation
       
        - File: drivers/usb/usbuhci/usbuhci.c
        - Problem Description:
          UhciSetEndpointDataToggle was left as an unimplemented stub
          (DPRINT_IMPL("UNIMPLEMENTED. FIXME\n")). Without tracking the toggle state,
          bulk endpoints fail to maintain DATA0/DATA1 PID synchronization, causing
          devices to discard subsequent transactions.
        - Suggested Fix:
          VOID NTAPI UhciSetEndpointDataToggle(IN PVOID uhciExtension, IN PVOID uhciEndpoint, IN ULONG DataToggle)
          {
              PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint;
              UhciEndpoint->DataToggle = (BOOL)DataToggle;
          }
       
      Issue C: Invalid Short Packet Detect (SPD) on OUT Tokens Halts Hardware Queue
       
        - File: drivers/usb/usbuhci/usbuhci.c
        - Applicable Specification: Intel Universal Host Controller Interface (UHCI)
          Design Guide, Section 3.2.2 [3].
        - Problem Description:
          In UhciMapAsyncTransferToTDs, TD->HwTD.ControlStatus.ShortPacketDetect = 1;
          was set unconditionally. Per Section 3.2.2 of the Intel UHCI Specification,
          Bit 29 (SPD) is only valid for IN transactions [3]; setting SPD on OUT
          transactions is undefined behavior that causes physical Intel ICH host
          controllers to halt processing the transfer queue [3].
        - Suggested Fix:
          Restrict the SPD bit strictly to IN transactions:
          TD->HwTD.ControlStatus.ShortPacketDetect = (PIDCode == UHCI_TD_PID_IN);
       
      6. Ports Class Installer (dll/win32/msports)
       
      Issue: Non-Standard Third-Party Serial Adapters Bypassed in Device Manager
       
        - File: dll/win32/msports/classinst.c
        - Problem Description:
          In classinst.c, GetPortType exclusively checked for the proprietary binary
          registry value PortSubClass (which Microsoft defines in its inbox serial
          INF). Third-party USB-to-serial manufacturers (FTDI, Prolific, Silicon Labs,
          WCH) do not provide this value.
          As a result, GetPortType returned UnknownPort, causing InstallPort to fall
          through to default: return ERROR_DI_DO_DEFAULT; and bypass InstallSerialPort
          entirely. This prevented FriendlyName (USB Serial Port (COMx)) from being
          set and left the device named generically as USB Serial Port.
        - Suggested Fix:
          If PortSubClass is absent, check DIREG_DEV for PortName: if it does not
          begin with LPT, classify any device in the Ports setup class as a
          SerialPort:
       
      // In dll/win32/msports/classinst.c -> GetPortType
       
      if (PortType == UnknownPort)
      {
          HKEY hDevKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
          if (hDevKey != INVALID_HANDLE_VALUE)
          {
              WCHAR szName[16];
              dwSize = sizeof(szName);
              if (RegQueryValueExW(hDevKey, L"PortName", NULL, NULL, (PBYTE)szName, &dwSize) == ERROR_SUCCESS)
              {
                  if (_wcsnicmp(szName, L"LPT", 3) == 0)
                      PortType = ParallelPort;
                  else
                      PortType = SerialPort;
              }
              RegCloseKey(hDevKey);
          }
       
          /* Fallback: any non-parallel port in GUID_DEVCLASS_PORTS is a serial port */
          if (PortType == UnknownPort)
              PortType = SerialPort;
      }
       
      7. Command Shell Output Redirection (base/shell/cmd)
       
      Issue: CreateFile Disposition Failure on Hardware Communications Resources
       
        - File: base/shell/cmd/redir.c
        - Applicable Specification: Win32 CreateFile specification for communications
          resources (COM1–COM9).
        - Problem Description:
          When shell redirection is targeted at a COM port (e.g., echo text > COM3),
          redir.c calls GetFileAttributesW(s). Because serial drivers manage character
          stream devices, they return STATUS_INVALID_DEVICE_REQUEST to file attribute
          queries, causing GetFileAttributesW to return INVALID_FILE_ATTRIBUTES.
          redir.c then falls back to dwCreationDisposition = CREATE_ALWAYS and
          dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE. Per Win32 specification,
          opening communications resources with CREATE_ALWAYS or non-zero share modes
          fails with ERROR_INVALID_PARAMETER (87). cmd.exe fails silently and never
          writes to the port.
        - Suggested Fix:
          Identify reserved device names (COMx, LPTx, CON, NUL) and enforce
          dwCreationDisposition = OPEN_EXISTING and dwShareMode = 0:
       
      // In base/shell/cmd/redir.c -> PerformRedirection
       
      if (IsDeviceName(s) || ((dwAttributes != INVALID_FILE_ATTRIBUTES) && (dwAttributes & FILE_ATTRIBUTE_DEVICE)))
      {
          dwCreationDisposition = OPEN_EXISTING;
          dwShareMode = 0;
      }
      else
      {
          dwCreationDisposition = (Append ? OPEN_ALWAYS : CREATE_ALWAYS);
      }
      

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              gokuo64 gokuo64
              Votes:
              1 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated: