diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /network/modem | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'network/modem')
| -rw-r--r-- | network/modem/fakemodem/ReadMe.md | 8 | ||||
| -rw-r--r-- | network/modem/fakemodem/driver.c | 474 | ||||
| -rw-r--r-- | network/modem/fakemodem/fakemodem.h | 156 | ||||
| -rw-r--r-- | network/modem/fakemodem/fakemodem.sln | 28 | ||||
| -rw-r--r-- | network/modem/fakemodem/fakemodem.vcxproj | 168 | ||||
| -rw-r--r-- | network/modem/fakemodem/fakemodem.vcxproj.Filters | 40 | ||||
| -rw-r--r-- | network/modem/fakemodem/ioctl.c | 790 | ||||
| -rw-r--r-- | network/modem/fakemodem/mdmfake.inx | 267 | ||||
| -rw-r--r-- | network/modem/fakemodem/readwrit.c | 465 |
9 files changed, 2396 insertions, 0 deletions
diff --git a/network/modem/fakemodem/ReadMe.md b/network/modem/fakemodem/ReadMe.md new file mode 100644 index 00000000..6d6cdbc1 --- /dev/null +++ b/network/modem/fakemodem/ReadMe.md @@ -0,0 +1,8 @@ +Fakemodem Driver +================ + +The Fakemodem sample demonstrates a simple controller-less modem driver. This driver supports sending and receiving AT commands using the `ReadFile`/`WriteFile` calls or via a TAPI interface using an application such as *HyperTerminal.* + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + diff --git a/network/modem/fakemodem/driver.c b/network/modem/fakemodem/driver.c new file mode 100644 index 00000000..f482c890 --- /dev/null +++ b/network/modem/fakemodem/driver.c @@ -0,0 +1,474 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Driver.c + +Abstract: + + This is a simple form of function driver for fakemodem device. The driver + doesn't handle any PnP and Power events because the framework provides + default behaviour for those events. This driver has enough support to + allow an user application (toast/notify.exe) to open the device + interface registered by the driver and send read, write or ioctl requests. + +Environment: + + Kernel mode + +--*/ + +#include "fakemodem.h" + +#ifdef ALLOC_PRAGMA + #pragma alloc_text (INIT, DriverEntry) + #pragma alloc_text (PAGE, FmEvtDeviceAdd) + #pragma alloc_text (PAGE, FmCreateDosDevicesSymbolicLink) + #pragma alloc_text (PAGE, FmDeviceCleanup) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as FmAddDevice and FmUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + + KdPrint(("Fakemode Function Driver Sample - Driver Framework Edition.\n")); + KdPrint(("Built %s %s\n", __DATE__, __TIME__)); + + WDF_DRIVER_CONFIG_INIT( &config, FmEvtDeviceAdd ); + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, // Driver Config Info + WDF_NO_HANDLE + ); + + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + return status; +} + + +NTSTATUS +FmEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + FmEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of Fm device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PFM_DEVICE_DATA fmDeviceData; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES fdoAttributes; + WDFDEVICE hDevice; + WDFQUEUE defQueue; + + UNREFERENCED_PARAMETER(Driver); + + KdPrint( ("FmEvtDeviceAdd routine \n")); + + PAGED_CODE(); + + // + // Modem type is serial port. + // + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SERIAL_PORT); + + // + // Use Buffered IO. + // + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + // + // Specify the size of device extension where we track per device + // context. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FM_DEVICE_DATA); + // + // Register a cleanup callback on the device to free up some resources at the + // time the device is deleted. + // + fdoAttributes.EvtCleanupCallback = FmDeviceCleanup; + // + // By opting for SynchronizationScopeDevice, we tell the framework to + // synchronize callbacks events of all the objects directly associated + // with the device. In this driver, we will associate queues. + // By doing that we don't have to worrry about synchronizing + // access to device-context by various io Events. + // Framework will serialize them by using an internal device-lock. + // + fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice; + // + // Create a framework device object.This call will inturn create + // a WDM deviceobject, attach to the lower stack and set the + // appropriate flags and attributes. + // + + status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice); + + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDeviceCreate failed with Status code 0x%x\n", status)); + return status; + } + + // + // Get the DeviceExtension and initialize it. + // + fmDeviceData = FmDeviceDataGet(hDevice); + + // + // Tell the Framework that this device will need an interface + // + status = WdfDeviceCreateDeviceInterface( + hDevice, + (LPGUID) &GUID_DEVINTERFACE_MODEM, + NULL + ); + + if (!NT_SUCCESS (status)) { + KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); + return status; + } + + fmDeviceData->Flags = 0; + status = FmCreateDosDevicesSymbolicLink(hDevice, fmDeviceData); + + if (!NT_SUCCESS(status)) { + KdPrint( ("FmCreateDosDevicesSymbolicLink failed with Status code 0x%x\n", status)); + return status; + } + + // + // Initialize the context + // + fmDeviceData->BaudRate=1200; + fmDeviceData->LineControl = SERIAL_7_DATA | SERIAL_EVEN_PARITY | SERIAL_NONE_PARITY; + + // + // Register I/O callbacks to tell the framework that you are interested + // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. + // In case a specific handler is not specified for one of these, + // the request will be dispatched to the EvtIoDefault handler, if any. + // If there is no EvtIoDefault handler, the request will be failed with + // STATUS_INVALID_DEVICE_REQUEST. + // WdfIoQueueDispatchParallel means that we are capable of handling + // all the I/O request simultaneously and we are responsible for protecting + // data that could be accessed by these callbacks simultaneously. + // + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, + WdfIoQueueDispatchParallel); + + queueConfig.EvtIoRead = FmEvtIoRead; + queueConfig.EvtIoWrite = FmEvtIoWrite; + queueConfig.EvtIoDeviceControl = FmEvtIoDeviceControl; + + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate( + hDevice, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &defQueue // pointer to default queue + ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS (status)) { + + // + // We don't need to cleanup symbolic link here. The destroy callback for + // the device object will do it. + // + return status; + } + + // + // Create a manual queue to hold pending read requests. By keeping + // them in the queue, framework takes care of cancelling them if the app exits + // + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, + WdfIoQueueDispatchManual); + + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(hDevice, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &fmDeviceData->FmReadQueue + ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS (status)) { + KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + // + // Create a manual queue to hold pending ioctl wait mask requests. By keeping + // them in the queue, framework takes care of cancelling them if the app exits + // + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, + WdfIoQueueDispatchManual); + + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(hDevice, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &fmDeviceData->FmMaskWaitQueue + ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS (status)) { + KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + return status; +} + + +VOID +FmDeviceCleanup( + WDFOBJECT Device + ) +/*++ +Routine Description: + + This event is called when the device object is destroyed. + Cleanup any associated data. + +Arguments: + +Return Value: + + VOID + +--*/ +{ + PFM_DEVICE_DATA fmData; + + PAGED_CODE(); + + fmData = FmDeviceDataGet((WDFDEVICE)Device); + + if (fmData->Flags & REG_VALUE_CREATED_FLAG) { + RtlDeleteRegistryValue( + RTL_REGISTRY_DEVICEMAP, + L"SERIALCOMM", + fmData->PdoName.Buffer + ); + } +} + +NTSTATUS +FmCreateDosDevicesSymbolicLink( + WDFDEVICE Device, + PFM_DEVICE_DATA FmDeviceData + ) +{ + NTSTATUS status; + UNICODE_STRING comPort; + UNICODE_STRING pdoName; + UNICODE_STRING symbolicLink; + WDFKEY hKey = NULL; + DECLARE_CONST_UNICODE_STRING(valueName, L"PortName"); + WDFSTRING string = NULL; + WDFMEMORY memory; + WDF_OBJECT_ATTRIBUTES memoryAttributes; + size_t bufferLength; + + + PAGED_CODE(); + + symbolicLink.Buffer = NULL; + + // + // Open the device registry and read the "PortName" value written by the + // class installer. + // + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + NULL, // PWDF_OBJECT_ATTRIBUTES + &hKey); + + if (!NT_SUCCESS (status)) { + goto Error; + } + status = WdfStringCreate( + NULL, + WDF_NO_OBJECT_ATTRIBUTES , + &string + ); + + if (!NT_SUCCESS(status)) { + goto Error; + } + + // + // Retrieve the value of ValueName from registry + // + status = WdfRegistryQueryString( + hKey, + &valueName, + string + ); + + + if (!NT_SUCCESS (status)) { + goto Error; + } + + // + // Retrieve the UNICODE_STRING from string object + // + WdfStringGetUnicodeString( + string, + &comPort + ); + + WdfRegistryClose(hKey); + hKey = NULL; + + symbolicLink.Length=0; + symbolicLink.MaximumLength = sizeof(OBJECT_DIRECTORY) + comPort.MaximumLength; + + symbolicLink.Buffer = ExAllocatePoolWithTag(PagedPool, + symbolicLink.MaximumLength + sizeof(WCHAR), + 'wkaF'); + + if (symbolicLink.Buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Error; + } + RtlZeroMemory(symbolicLink.Buffer, symbolicLink.MaximumLength); + RtlAppendUnicodeToString(&symbolicLink, OBJECT_DIRECTORY); + RtlAppendUnicodeStringToString(&symbolicLink, &comPort); + // + // This DDI will get the underlying PDO name and create a symbolic to that + // because our FDO doesn't have a name. + // + status = WdfDeviceCreateSymbolicLink(Device, + &symbolicLink); + + if (!NT_SUCCESS(status)) { + goto Error; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes); + memoryAttributes.ParentObject = Device; + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyPhysicalDeviceObjectName, + PagedPool, + &memoryAttributes, + &memory); + if (!NT_SUCCESS(status)) { + // + // We expect a zero length buffer. Anything else is fatal. + // + goto Error; + } + + pdoName.Buffer = WdfMemoryGetBuffer(memory, &bufferLength); + + if (pdoName.Buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Error; + + } + pdoName.MaximumLength = (USHORT) bufferLength; + pdoName.Length = (USHORT) bufferLength - sizeof(UNICODE_NULL); + + status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, + L"SERIALCOMM", + pdoName.Buffer, + REG_SZ, + comPort.Buffer, + comPort.Length); + + if (!NT_SUCCESS(status)) { + goto Error; + } + FmDeviceData->Flags |= REG_VALUE_CREATED_FLAG; + // + // Store it so it can be deleted later. + // + + FmDeviceData->PdoName = pdoName; + + Error: + + if (symbolicLink.Buffer != NULL) { + ExFreePool(symbolicLink.Buffer); + } + + if (hKey != NULL) { + WdfRegistryClose(hKey); + } + if (string != NULL) { + WdfObjectDelete(string); + } + + return status; +} + diff --git a/network/modem/fakemodem/fakemodem.h b/network/modem/fakemodem/fakemodem.h new file mode 100644 index 00000000..bb06c2fe --- /dev/null +++ b/network/modem/fakemodem/fakemodem.h @@ -0,0 +1,156 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + fakemodem.h + +Abstract: + + Header file for the toaster driver modules. + +Environment: + + Kernel mode + +--*/ + + +#if !defined(_FAKEMODEM_H_) +#define _FAKEMODEM_H_ + +#include <NTDDK.h> +#include <wdf.h> +#include <ntddser.h> +#include <initguid.h> +#define NTSTRSAFE_LIB +#include <ntstrsafe.h> +#include <ntintsafe.h> + +#ifdef DEFINE_GUID + +DEFINE_GUID(GUID_DEVINTERFACE_MODEM,0x2c7089aa, 0x2e0e,0x11d1,0xb1, 0x14, 0x00, 0xc0, 0x4f, 0xc2, 0xaa, 0xe4); + +#endif //DEFINE_GUID + + +#define OBJECT_DIRECTORY L"\\DosDevices\\" + +#define READ_BUFFER_SIZE 128 + +#define COMMAND_MATCH_STATE_IDLE 0 +#define COMMAND_MATCH_STATE_GOT_A 1 +#define COMMAND_MATCH_STATE_GOT_T 2 + +// +// This defines the bit used to control whether the device is sending +// a break. When this bit is set the device is sending a space (logic 0). +// +// Most protocols will assume that this is a hangup. + + +#define SERIAL_LCR_BREAK 0x40 + +// +// These defines are used to define the line control register +// + +#define SERIAL_5_DATA ((UCHAR)0x00) +#define SERIAL_6_DATA ((UCHAR)0x01) +#define SERIAL_7_DATA ((UCHAR)0x02) +#define SERIAL_8_DATA ((UCHAR)0x03) +#define SERIAL_DATA_MASK ((UCHAR)0x03) + +#define SERIAL_1_STOP ((UCHAR)0x00) +#define SERIAL_1_5_STOP ((UCHAR)0x04) // Only valid for 5 data bits +#define SERIAL_2_STOP ((UCHAR)0x04) // Not valid for 5 data bits +#define SERIAL_STOP_MASK ((UCHAR)0x04) + +#define SERIAL_NONE_PARITY ((UCHAR)0x00) +#define SERIAL_ODD_PARITY ((UCHAR)0x08) +#define SERIAL_EVEN_PARITY ((UCHAR)0x18) +#define SERIAL_MARK_PARITY ((UCHAR)0x28) +#define SERIAL_SPACE_PARITY ((UCHAR)0x38) +#define SERIAL_PARITY_MASK ((UCHAR)0x38) + +#define REG_VALUE_CREATED_FLAG 0x1 +// +// The device extension for the device object +// +typedef struct _FM_DEVICE_DATA +{ + + UNICODE_STRING PdoName; //save this so that we can use it to delete the registry value later + WDFQUEUE FmReadQueue; // Staging area for pending Read requests + WDFQUEUE FmMaskWaitQueue; + ULONG CurrentMask; + SERIAL_TIMEOUTS CurrentTimeouts; + ULONG ReadBufferBegin; + ULONG ReadBufferEnd; + ULONG BytesInReadBuffer; + UCHAR CommandMatchState; + BOOLEAN ConnectCommand; + BOOLEAN IgnoreNextChar; + BOOLEAN CapsQueried; + ULONG ModemStatus; + BOOLEAN CurrentlyConnected; + BOOLEAN ConnectionStateChanged; + UCHAR ReadBuffer[READ_BUFFER_SIZE]; + ULONG BaudRate; + UCHAR LineControl; + UCHAR ValidDataMask; + UCHAR Flags; + +} FM_DEVICE_DATA, *PFM_DEVICE_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FM_DEVICE_DATA, FmDeviceDataGet) + +#define FM_COM_PORT_STRING_LENGTH 80 + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD FmEvtDeviceAdd; +EVT_WDF_DEVICE_CONTEXT_CLEANUP FmDeviceCleanup; + +EVT_WDF_IO_QUEUE_IO_READ FmEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE FmEvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FmEvtIoDeviceControl; + +NTSTATUS +FmCreateDosDevicesSymbolicLink( + WDFDEVICE Device, + PFM_DEVICE_DATA FmDeviceData + ); + +VOID +ProcessConnectionStateChange( + IN PFM_DEVICE_DATA FmDeviceData + ); +VOID +ProcessWriteBytes( + PFM_DEVICE_DATA FmDeviceData, + PUCHAR Characters, + ULONG Length + ); + + +VOID +PutCharInReadBuffer( + PFM_DEVICE_DATA FmDeviceData, + UCHAR Character + ); + + + +VOID +ProcessReadBuffer( + IN PFM_DEVICE_DATA FmDeviceData, + IN PUCHAR SystemBuffer, + IN ULONG Length, + OUT PULONG ByesToMove + ); + +#endif // _FAKEMODEM_H + + diff --git a/network/modem/fakemodem/fakemodem.sln b/network/modem/fakemodem/fakemodem.sln new file mode 100644 index 00000000..6804feb5 --- /dev/null +++ b/network/modem/fakemodem/fakemodem.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem", "fakemodem.vcxproj", "{3744C5BD-A12A-429F-9312-DFD04AC69078}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|Win32.ActiveCfg = Debug|Win32 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|Win32.Build.0 = Debug|Win32 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|Win32.ActiveCfg = Release|Win32 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|Win32.Build.0 = Release|Win32 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|x64.ActiveCfg = Debug|x64 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|x64.Build.0 = Debug|x64 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|x64.ActiveCfg = Release|x64 + {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/network/modem/fakemodem/fakemodem.vcxproj b/network/modem/fakemodem/fakemodem.vcxproj new file mode 100644 index 00000000..c2a2dd8d --- /dev/null +++ b/network/modem/fakemodem/fakemodem.vcxproj @@ -0,0 +1,168 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{3744C5BD-A12A-429F-9312-DFD04AC69078}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{74C5BB58-0CB8-4E8E-8FD7-065CBE6051A7}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\mdmfake.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\mdmfake.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>fakemodem</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>fakemodem</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>fakemodem</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>fakemodem</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="driver.c" /> + <ClCompile Include="ioctl.c" /> + <ClCompile Include="readwrit.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/network/modem/fakemodem/fakemodem.vcxproj.Filters b/network/modem/fakemodem/fakemodem.vcxproj.Filters new file mode 100644 index 00000000..7c8d71ab --- /dev/null +++ b/network/modem/fakemodem/fakemodem.vcxproj.Filters @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{66A2BE8B-87F0-4F4B-AB28-9C66471A8B7B}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F31D838F-78A7-4140-B15C-4C9485DDB150}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{8A726BCF-D9F0-4948-8219-B0CCAC8AA786}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{A5962758-E097-4C00-A4FB-3A630B0E5405}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\mdmfake.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\mdmfake.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ioctl.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="readwrit.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/network/modem/fakemodem/ioctl.c b/network/modem/fakemodem/ioctl.c new file mode 100644 index 00000000..445910bd --- /dev/null +++ b/network/modem/fakemodem/ioctl.c @@ -0,0 +1,790 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + ioctl.c + +Abstract: + + This is the ioctl handler for the fakemodem. +Environment: + + Kernel mode + +--*/ + +#include "fakemodem.h" + + + +VOID +FmEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ +{ + + PFM_DEVICE_DATA fmDeviceData = FmDeviceDataGet(WdfIoQueueGetDevice(Queue)); + NTSTATUS status ; + PVOID requestBuffer; + ULONG information = 0; + size_t bufSize; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + status = STATUS_SUCCESS; + + switch (IoControlCode) { + + case IOCTL_SERIAL_GET_WAIT_MASK: { + + status = WdfRequestRetrieveOutputBuffer ( Request, + sizeof(ULONG), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(( "Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + + *((PULONG)requestBuffer)= fmDeviceData->CurrentMask; + + information = sizeof(ULONG); + + break; + } + + case IOCTL_SERIAL_SET_WAIT_MASK: { + + WDFREQUEST currentWaitRequest=NULL; + ULONG newMask; + + status = WdfRequestRetrieveInputBuffer (Request, + sizeof(ULONG), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + break; + + } + else { + NTSTATUS tempStatus; + // + // get rid of the current wait + // + + newMask = *((ULONG *)requestBuffer); + + fmDeviceData->CurrentMask = newMask; + + KdPrint(("FAKEMODEM: set wait mask, %08lx\n", newMask)); + + tempStatus = WdfIoQueueRetrieveNextRequest(fmDeviceData->FmMaskWaitQueue, + ¤tWaitRequest); + // save the new mask + + if (NT_SUCCESS(tempStatus)) {//currentWaitRequest != NULL) { + + PULONG outBuffer; + + KdPrint(("FAKEMODEM: set wait mask- complete wait\n")); + + // + // The length was validated already. + // + tempStatus = WdfRequestRetrieveOutputBuffer(currentWaitRequest, + sizeof(ULONG), + &outBuffer, + &bufSize); + if (NT_SUCCESS(tempStatus)) { + if (outBuffer) { // FIXME SAL + *outBuffer = 0; + } + + WdfRequestCompleteWithInformation(currentWaitRequest, + STATUS_SUCCESS, + sizeof(ULONG)); + } else { + WdfRequestComplete(currentWaitRequest, tempStatus); + } + } + information = sizeof(ULONG); + } + break; + } + + case IOCTL_SERIAL_WAIT_ON_MASK: { + + WDFREQUEST currentWaitRequest = NULL; + NTSTATUS tempStatus; + + status = WdfRequestRetrieveOutputBuffer (Request, + sizeof(ULONG), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + KdPrint(("FAKEMODEM: wait on mask\n")); + // + // remove the current request if any + // + tempStatus = WdfIoQueueRetrieveNextRequest(fmDeviceData->FmMaskWaitQueue, + ¤tWaitRequest); + + if (NT_SUCCESS(tempStatus)) { //currentWaitRequest != NULL) { + + PULONG outBuffer; + + KdPrint(("FAKEMODEM: wait on mask- complete wait\n")); + + // + // The length was validated already. + // + + tempStatus = WdfRequestRetrieveOutputBuffer(currentWaitRequest, + sizeof(ULONG), + &outBuffer, + &bufSize); + if(NT_SUCCESS(tempStatus)) { + if (outBuffer) { // FIXME SAL + *((PULONG)outBuffer) = 0; + } + + WdfRequestCompleteWithInformation(currentWaitRequest, + STATUS_SUCCESS, + sizeof(ULONG)); + } else { + WdfRequestComplete(currentWaitRequest, tempStatus); + } + + } + + if (fmDeviceData->CurrentMask == 0) { + // + // can only set if mask is not zero + // + status=STATUS_UNSUCCESSFUL; + + } else { + + // + // add the current request to the wait queue + // + status = WdfRequestForwardToIoQueue(Request, fmDeviceData->FmMaskWaitQueue); + if (!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, STATUS_UNSUCCESSFUL, 0); + return; + } + + status=STATUS_PENDING; + } + + break; + } + + case IOCTL_SERIAL_PURGE: { + + ULONG mask; + status = WdfRequestRetrieveInputBuffer (Request, + sizeof(ULONG), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + break; + + } + mask=*((PULONG)requestBuffer); + + if (mask & SERIAL_PURGE_RXABORT) { + + WdfIoQueuePurge( fmDeviceData->FmReadQueue, + WDF_NO_EVENT_CALLBACK, + WDF_NO_CONTEXT ); + + WdfIoQueueStart(fmDeviceData->FmReadQueue); + } + information = sizeof(ULONG); + break; + } + + + case IOCTL_SERIAL_GET_MODEMSTATUS: { + + status = WdfRequestRetrieveOutputBuffer ( Request, + sizeof(ULONG), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(( "Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + + information = sizeof(ULONG); + + *((PULONG)requestBuffer) = fmDeviceData->ModemStatus; + + break; + } + + + case IOCTL_SERIAL_SET_TIMEOUTS: { + PSERIAL_TIMEOUTS NewTimeouts; + + status = WdfRequestRetrieveInputBuffer (Request, + sizeof(SERIAL_TIMEOUTS), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + break; + + } + NewTimeouts= ((PSERIAL_TIMEOUTS)(requestBuffer)); + + if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) && + (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && + (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + information = sizeof(SERIAL_TIMEOUTS); + + break; + } + + case IOCTL_SERIAL_GET_TIMEOUTS: { + + status = WdfRequestRetrieveOutputBuffer ( Request, + sizeof(SERIAL_TIMEOUTS), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(( "Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + + *((PSERIAL_TIMEOUTS)requestBuffer) = + fmDeviceData->CurrentTimeouts; + + information = sizeof(SERIAL_TIMEOUTS); + + break; + } + + case IOCTL_SERIAL_GET_COMMSTATUS: { + + PSERIAL_STATUS serialStatus ; + status = WdfRequestRetrieveOutputBuffer ( Request, + sizeof(SERIAL_STATUS), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(( "Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + + serialStatus = (PSERIAL_STATUS) requestBuffer; + + RtlZeroMemory( serialStatus, sizeof(*serialStatus) ); // FIXME SAL + + serialStatus->AmountInInQueue = fmDeviceData->BytesInReadBuffer; + + information = sizeof(SERIAL_STATUS); + + break; + } + + case IOCTL_SERIAL_SET_DTR: + case IOCTL_SERIAL_CLR_DTR: { + + if (IoControlCode == IOCTL_SERIAL_SET_DTR) { + + // + // raising DTR + // + + fmDeviceData->ModemStatus=SERIAL_DTR_STATE | SERIAL_DSR_STATE; + + KdPrint(("FAKEMODEM: Set DTR\n")); + + } else { + // + // dropping DTR, drop connection if there is one + // + KdPrint(("FAKEMODEM: Clear DTR\n")); + + if (fmDeviceData->CurrentlyConnected == TRUE) { + // + // not connected any more + // + fmDeviceData->CurrentlyConnected=FALSE; + + fmDeviceData->ConnectionStateChanged=TRUE; + } + } + + ProcessConnectionStateChange( fmDeviceData); + + information = sizeof(ULONG); + + break; + } + + case IOCTL_SERIAL_SET_QUEUE_SIZE: { + + status = WdfRequestRetrieveInputBuffer (Request, + sizeof(SERIAL_QUEUE_SIZE), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + break; + + } + + // + // This ioctl doesn't do anyhing except test for the size of the + // buffer passed in. + // + information = sizeof(SERIAL_QUEUE_SIZE); + break; + } + + + case IOCTL_SERIAL_SET_BAUD_RATE: { + + status = WdfRequestRetrieveInputBuffer (Request, + sizeof(SERIAL_BAUD_RATE), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + else { + fmDeviceData->BaudRate = ((PSERIAL_BAUD_RATE)requestBuffer)->BaudRate; + } + information = sizeof(SERIAL_BAUD_RATE); + break; + } + + case IOCTL_SERIAL_GET_BAUD_RATE: { + + PSERIAL_BAUD_RATE pBaudRate ; + + status = WdfRequestRetrieveOutputBuffer ( Request, + sizeof(SERIAL_BAUD_RATE), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(( "Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + + pBaudRate = (PSERIAL_BAUD_RATE)requestBuffer; + pBaudRate->BaudRate = fmDeviceData->BaudRate; + information = sizeof(SERIAL_BAUD_RATE); + + break; + } + + case IOCTL_SERIAL_SET_LINE_CONTROL: { + + PSERIAL_LINE_CONTROL pLineControl ; + UCHAR LData = 0; + UCHAR LStop = 0; + UCHAR LParity = 0; + UCHAR Mask = 0xff; + + status = WdfRequestRetrieveInputBuffer (Request, + sizeof(SERIAL_LINE_CONTROL), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(("Could not get request memory buffer status %X\n", status)); + information = 0; + break; + + } + pLineControl = ((PSERIAL_LINE_CONTROL)requestBuffer); + + switch(pLineControl->WordLength) + { + case 5: { + + LData = SERIAL_5_DATA; + Mask = 0x1f; + break; + + } + case 6: { + + LData = SERIAL_6_DATA; + Mask = 0x3f; + break; + + } + case 7: { + + LData = SERIAL_7_DATA; + Mask = 0x7f; + break; + + } + case 8: { + + LData = SERIAL_8_DATA; + break; + + } + default: { + + status = STATUS_INVALID_PARAMETER; + + } + } + + if (status != STATUS_SUCCESS) + { + break; + } + + switch (pLineControl->Parity) { + + case NO_PARITY: { + LParity = SERIAL_NONE_PARITY; + break; + + } + case EVEN_PARITY: { + LParity = SERIAL_EVEN_PARITY; + break; + + } + case ODD_PARITY: { + LParity = SERIAL_ODD_PARITY; + break; + + } + case SPACE_PARITY: { + LParity = SERIAL_SPACE_PARITY; + break; + + } + case MARK_PARITY: { + LParity = SERIAL_MARK_PARITY; + break; + + } + default: { + + status = STATUS_INVALID_PARAMETER; + break; + } + + } + + if (status != STATUS_SUCCESS) + { + break; + } + + switch (pLineControl->StopBits) { + + case STOP_BIT_1: { + + LStop = SERIAL_1_STOP; + break; + } + + case STOP_BITS_1_5: { + + if (LData != SERIAL_5_DATA) { + + status = STATUS_INVALID_PARAMETER; + break; + } + LStop = SERIAL_1_5_STOP; + break; + + } + case STOP_BITS_2: { + + if (LData == SERIAL_5_DATA) { + + status = STATUS_INVALID_PARAMETER; + break; + } + + LStop = SERIAL_2_STOP; + break; + } + + default: { + + status = STATUS_INVALID_PARAMETER; + } + + } + + if (status != STATUS_SUCCESS) + { + break; + } + + fmDeviceData->LineControl = + (UCHAR)((fmDeviceData->LineControl & SERIAL_LCR_BREAK) | + (LData | LParity | LStop)); + + fmDeviceData->ValidDataMask = Mask; + information = sizeof(SERIAL_LINE_CONTROL); + break; + } + + case IOCTL_SERIAL_GET_LINE_CONTROL: { + PSERIAL_LINE_CONTROL pLineControl ; + + status = WdfRequestRetrieveOutputBuffer ( Request, + sizeof(SERIAL_LINE_CONTROL), + &requestBuffer, + &bufSize ); + if( !NT_SUCCESS(status) ) { + KdPrint(( "Could not get request memory buffer status %X\n", status)); + information = 0; + break; + } + + + pLineControl = + (PSERIAL_LINE_CONTROL)requestBuffer; + + RtlZeroMemory(requestBuffer, + bufSize); + + + switch (fmDeviceData->LineControl & SERIAL_DATA_MASK) { + case SERIAL_5_DATA: + pLineControl->WordLength = 5; + break; + case SERIAL_6_DATA: + pLineControl->WordLength = 6; + break; + case SERIAL_7_DATA: + pLineControl->WordLength = 7; + break; + case SERIAL_8_DATA: + pLineControl->WordLength = 8; + break; + default: + break; + + } + + switch (fmDeviceData->LineControl & SERIAL_PARITY_MASK) { + case SERIAL_NONE_PARITY: + pLineControl->Parity = NO_PARITY; + break; + case SERIAL_ODD_PARITY: + pLineControl->Parity = ODD_PARITY; + break; + case SERIAL_EVEN_PARITY: + pLineControl->Parity = EVEN_PARITY; + break; + case SERIAL_MARK_PARITY: + pLineControl->Parity = MARK_PARITY; + break; + case SERIAL_SPACE_PARITY: + pLineControl->Parity = SPACE_PARITY; + break; + default: + break; + + } + + if (fmDeviceData->LineControl & SERIAL_2_STOP) { + + if (pLineControl->WordLength == 5) { + + pLineControl->StopBits = STOP_BITS_1_5; + + } else { + + pLineControl->StopBits = STOP_BITS_2; + + } + + } else { + + pLineControl->StopBits = STOP_BIT_1; + } + + information = sizeof(SERIAL_LINE_CONTROL); + + break; + } + + case IOCTL_SERIAL_SET_RTS: + case IOCTL_SERIAL_CLR_RTS: + case IOCTL_SERIAL_SET_XON: + case IOCTL_SERIAL_SET_XOFF: + case IOCTL_SERIAL_SET_CHARS: + case IOCTL_SERIAL_GET_CHARS: + case IOCTL_SERIAL_GET_HANDFLOW: + case IOCTL_SERIAL_SET_HANDFLOW: + case IOCTL_SERIAL_RESET_DEVICE: { + // + // NOTE: The application expects STATUS_SUCCESS for these ioctsl. + // so don't merge this with default. + // + break; + } + default: + status=STATUS_NOT_SUPPORTED; + break; + + } + + if (status != STATUS_PENDING) { + // + // complete now if not pending + // + WdfRequestCompleteWithInformation(Request, status, information); + } +} + + + +VOID +ProcessConnectionStateChange( + IN PFM_DEVICE_DATA FmDeviceData + ) +{ + WDFREQUEST currentWaitRequest = NULL; + NTSTATUS status; + + if (FmDeviceData->ConnectionStateChanged) { + + // + // state changed + // + + FmDeviceData->ConnectionStateChanged=FALSE; + + if (FmDeviceData->CurrentlyConnected) { + // + // now it is connected, raise CD + // + FmDeviceData->ModemStatus |= SERIAL_DCD_STATE; + + + } else { + // + // not connected any more, clear CD + // + FmDeviceData->ModemStatus &= ~(SERIAL_DCD_STATE); + + } + + + if (FmDeviceData->CurrentMask & SERIAL_EV_RLSD) { + + // + // app want's to know about these changes, tell it + // + status = WdfIoQueueRetrieveNextRequest(FmDeviceData->FmMaskWaitQueue, + ¤tWaitRequest); + if(!NT_SUCCESS(status)){ + ASSERT(status == STATUS_NO_MORE_ENTRIES); + } + } + + } + + + if (currentWaitRequest != NULL) { + + PULONG outBuffer; + size_t bufSize; + + KdPrint(("FAKEMODEM: ProcessConectionState\n")); + + // + // The length was validated already. + // + + (VOID)WdfRequestRetrieveOutputBuffer(currentWaitRequest, + sizeof(ULONG), + &outBuffer, + &bufSize); + + if (outBuffer) { // FIXME SAL + *outBuffer = SERIAL_EV_RLSD; + } + + WdfRequestCompleteWithInformation(currentWaitRequest, + STATUS_SUCCESS, + sizeof(ULONG)); + + } + + return; + +} + + diff --git a/network/modem/fakemodem/mdmfake.inx b/network/modem/fakemodem/mdmfake.inx new file mode 100644 index 00000000..4342404a --- /dev/null +++ b/network/modem/fakemodem/mdmfake.inx @@ -0,0 +1,267 @@ +; +; "Fakemodem" Controllerless driver illustrative example +; +; Copyright (c) Microsoft Corporation. All rights reserved. +; +; ******************************************************************* +; * * +; * The following INF is used in order to load this sample driver. * +; * Further information about INF design can be found in the DDK * +; * * +; ******************************************************************* + +; ------------------------------------------------------------------------------ +; Check final modem INF with CINF tool then test with +; NDIS Test prior to final distribution. +;------------------------------------------------------------------------------- + +;------------------------------------------------------------------------------------------------------ +;This section must specify the following entries with the indicated values: +;Signature entry as the $Windows NT$ value. This value indicates that the INF is only valid for NT-based operating systems. +;Class entry as "MODEM". +;ClassGUID entry as {4D36E96D-E325-11CE-BFC1-08002BE10318}. +;Provider is the company responsible for the provision of the INF. +;DriverVer must be in the following format = mm/dd/yyyy[,x.y.v.z] + +[Version] +Signature="$WINDOWS NT$" +Class=Modem +ClassGUID={4D36E96D-E325-11CE-BFC1-08002BE10318} +Provider=%Mfg% +DriverVer=11/11/2002,5.1.3711 + +;INF files that are not distributed with the OS should contain the following line: +CatalogFile=KmdfSamples.cat + +;INF files that are to be distributed with the OS that load a service and or files on the CD, should contain the following line: +;Layoutfile=layout.inf + +;----------------------------------------------------------------------------------------------------------------------------; Below is list of manufacturers that will appear in the +; Install New Modem wizard's list of manufacturers as well as define what sections to install ID's from +; The vendor will be required to change the provider key before a +; driver submission is made + +[Manufacturer] +%Generic% = Generic,NT$ARCH$ + + +;------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +;This section references the INF-writer-defined DDInstall and DDInstall.Services sections for the Modem device, and specifies the hardware identifier for the Modem device. + +[Generic.NT$ARCH$] +%ModemX% = ModemX, {b85b7c50-6a01-11d2-b841-00c04fad5171}\fakemodem + +;------------------------------------------------------------------------------------------------------- +; For detailed explanation of DDInstall.Services section, please reference DDK. +; Installation section references other INF sections to be installed for a specific modem. +; The AddReg line points to sections of the INF file that list registry entries to be added when +; installing this modem. For example, the line below instructs the installer to add the registry +; entries listed in the following sections of this INF file: +; [All], [MfgAddReg], [ExtraCRLFResponses], [ModemX.AddReg], [INTERNAL] +; It is not necessary to break up the registry additions into different sections in the +; INF. However, breaking out common entries into sections can help to reduce the size of +; the INF if multiple modems are installed from the same INF and have common registry +; entries. + +[ModemX.NT] +CopyFiles = CopyFileSection +AddReg = All, MfgAddReg, ExtraCRLFResponses, ModemX.AddReg, INTERNAL + +[ModemX.NT.Services] +AddService = fakemdm, 0x00000000, FakeModm_Service_Inst, FakeModm_Logging_Inst + +[ModemX.NT.HW] +AddReg = LowerFilterAddReg + +[LowerFilterAddReg] +HKR,,"LowerFilters",0x00010000,fakemdm + +[FakeModm_Service_Inst] +DisplayName = %ModemX% +ServiceType = 1 +StartType = 3 +ErrorControl = 0 +ServiceBinary = %12%\fakemodem.sys + +;-------------------------------------------------------------------------------------------------------------------- +; An event-log-install-section + +[FakeModm_Logging_Inst] +AddReg = FakeModm_Logging_Inst_AddReg + +[FakeModm_Logging_Inst_AddReg] +HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\Fakemodem.sys" +HKR,,TypesSupported,0x00010001,7 + +[SourceDisksNames] +99=%FakeDisk%, disk1,,"" + +[SourceDisksFiles] +fakemodem.sys = 99 + +;------------------------------------------------------------------------------------------------------------------- +; Section used to copy files required for device to function + +[CopyFileSection] +fakemodem.sys + +;-------------------------------------------------------------------------------------------------------------------------- +; This section lists the Default location to copy the files listed in the copyfiles directive +; 12 = %Windows%\System32\Drivers + +[DestinationDirs] +CopyFileSection=12 +DefaultDestDir=12 + + +; +;--- ModemX Coinstaller installation ------ +; +[DestinationDirs] +ModemX_CoInstaller_CopyFiles = 11 + +[ModemX.NT.CoInstallers] +AddReg=ModemX_CoInstaller_AddReg +CopyFiles=ModemX_CoInstaller_CopyFiles + +[ModemX_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[ModemX_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=99 ; make sure the number matches with SourceDisksNames + +[ModemX.NT.Wdf] +KmdfService = fakemdm, fakemdm_wdfsect +[fakemdm_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + + +;------------------------------------------------------------------------------------------------------- +; DDK procalc tool can be used to check properties settings which describes modem' properties. +; Generally, customization entries are added here which override commands from the All section + +[ModemX.AddReg] +HKR,,Properties, 1, 80,01,00,00, ff,00,00,00, ff,00,00,00, 07,00,00,00, 0f,00,00,00, f7,03,00,00, 00,c2,01,00, 40,38,00,00 +HKR,,InactivityScale, 1, 0a,00,00,00 +HKR, Settings, InactivityTimeout,, "S30=<#>" +HKR, Settings, ErrorControl_On,, "\N3" +HKR, Settings, ErrorControl_Forced,, "\N2" +HKR, Settings, Compression_On,, "%%C3" +HKR, Settings, SpeedNegotiation_Off,, "N0" +HKR, Settings, SpeedNegotiation_On,, "N1" + +;-------------------------------------------------------------------------------------------------------------------------- +;This section will define the type of modem and thus present the appropriate icon in the Device manager + +[INTERNAL] +HKR,, DeviceType, 1, 02 + +;------------------------------------------------------------------------------------------------------------------------- +; Responses section contains all of the appropriate and required responses in order for the O/S to understand the +; Modem responses to system queries. + +[All] +HKR,,ConfigDialog,,modemui.dll +HKR,,EnumPropPages,,"modemui.dll,EnumPropPages" +HKR,,PortSubClass,1,02 +HKR,Init,1,,"AT<cr>" +HKR,Init, 2,, "AT &F E0 V1 &D2 &C1 S0=0 W2 S95=47<cr>" + +[MfgAddReg] +HKR,, InactivityScale, 1, 01,00,00,00 +HKR, Monitor, 1,, "ATS0=0<cr>" +HKR, Monitor, 2,, "None" +HKR, Hangup, 1,, "ATH<cr>" +HKR, Answer, 1,, "ATA<cr>" +HKR,, Reset,, "ATZ<cr>" +HKR, Settings, Prefix,, "AT" +HKR, Settings, Terminator,, "<cr>" +HKR, Settings, DialPrefix,, "D" +HKR, Settings, DialSuffix,, ";" +HKR, Settings, SpeakerVolume_Low,, "L1" +HKR, Settings, SpeakerVolume_Med,, "L2" +HKR, Settings, SpeakerVolume_High,, "L3" +HKR, Settings, SpeakerMode_Off,, "M0" +HKR, Settings, SpeakerMode_Dial,, "M1" +HKR, Settings, SpeakerMode_On,, "M2" +HKR, Settings, SpeakerMode_Setup,, "M3" +HKR, Settings, FlowControl_Off,, "&K0" +HKR, Settings, FlowControl_Hard,, "&K3" +HKR, Settings, FlowControl_Soft,, "&K4" +HKR, Settings, ErrorControl_On,, "\N5" +HKR, Settings, ErrorControl_Off,, "\N0" +HKR, Settings, ErrorControl_Forced,, "\N4" +HKR, Settings, Compression_On,, "%%C1" +HKR, Settings, Compression_Off,, "%%C0" +HKR, Settings, Modulation_CCITT,, "B0 " +HKR, Settings, Modulation_Bell,, "B1 " +HKR, Settings, SpeedNegotiation_Off,, "*S0" +HKR, Settings, SpeedNegotiation_On,, "*S1" +HKR, Settings, Pulse,, "P" +HKR, Settings, Tone,, "T" +HKR, Settings, Blind_Off,, "X4" +HKR, Settings, Blind_On,, "X3" +HKR, Settings, CallSetupFailTimer,, "S7=<#>" + +HKR, Responses, "<cr><lf>+FCERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>BLACKLISTED<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>BUSY<cr><lf>", 1, 06, 00, 00,00,00,00, 00,00,00,00 + +HKR, Responses, "<cr><lf>CONNECT<cr><lf>", 1, 02, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>DATA<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>DELAYED<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>ERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 + +HKR, Responses, "<cr><lf>FAX<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>NO ANSWER<cr><lf>", 1, 07, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>NO CARRIER<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>NO DIALTONE<cr><lf>", 1, 05, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>NOTUSED<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>OK<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>RING<cr><lf>", 1, 08, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf>RINGING<cr><lf>", 1, 01, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "0<cr>", 1, 00, 00, 00,00,00,00, 00,00,00,00 ; OK +HKR, Responses, "1<cr>", 1, 02, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "10<cr>", 1, 02, 00, 60,09,00,00, 00,00,00,00 +HKR, Responses, "11<cr>", 1, 02, 00, c0,12,00,00, 00,00,00,00 +HKR, Responses, "12<cr>", 1, 02, 00, 80,25,00,00, 00,00,00,00 +HKR, Responses, "13<cr>", 1, 02, 00, 20,1c,00,00, 00,00,00,00 +HKR, Responses, "14<cr>", 1, 02, 00, e0,2e,00,00, 00,00,00,00 +HKR, Responses, "15<cr>", 1, 02, 00, 40,38,00,00, 00,00,00,00 ; connect at 14400 +HKR, Responses, "2<cr>", 1, 08, 00, 00,00,00,00, 00,00,00,00 ; RING +HKR, Responses, "3<cr>", 1, 04, 00, 00,00,00,00, 00,00,00,00 ; NO CARRIER +HKR, Responses, "4<cr>", 1, 03, 00, 00,00,00,00, 00,00,00,00 ; ERROR +HKR, Responses, "5<cr>", 1, 02, 00, b0,04,00,00, 00,00,00,00 +HKR, Responses, "6<cr>", 1, 05, 00, 00,00,00,00, 00,00,00,00 ; NO DIALTONE +HKR, Responses, "69<cr>", 1, 01, 03, 00,00,00,00, 00,00,00,00 +HKR, Responses, "7<cr>", 1, 06, 00, 00,00,00,00, 00,00,00,00 ; BUSY +HKR, Responses, "70<cr>", 1, 01, 01, 00,00,00,00, 00,00,00,00 ; Protocol:None +HKR, Responses, "77<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:LAPM +HKR, Responses, "78<cr>", 1, 01, 03, 00,00,00,00, 00,00,00,00 ; Connect V42BIS +HKR, Responses, "8<cr>", 1, 07, 00, 00,00,00,00, 00,00,00,00 ; NO ANSWER +HKR, Responses, "80<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:ALT +HKR, Responses, "81<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 + +[ExtraCRLFResponses] +HKR, Responses, "<cr><lf><cr><lf>OK<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf><cr><lf>ERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf><cr><lf>BUSY<cr><lf>", 1, 06, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf><cr><lf>NO ANSWER<cr><lf>", 1, 07, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf><cr><lf>NO CARRIER<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00 +HKR, Responses, "<cr><lf><cr><lf>NO DIALTONE<cr><lf>", 1, 05, 00, 00,00,00,00, 00,00,00,00 + +;------------------------------------------------------------------------------------------------------- +;This section defines each %strkey% token specified in the INF and lists strings that are used by the Modems +;control panel applet and the Install New Modem wizard. +; For example, ModemX will appear as "FakeModem DDK Sample controllerless driver" + +[Strings] +mfg = "Microsoft" +FakeDisk = "Fake Modem Install Disk" +Generic = "(Standard Modem Types)" +ModemX = "FakeModem DDK Sample controllerless driver" +ServiceName = "Fakemodem" diff --git a/network/modem/fakemodem/readwrit.c b/network/modem/fakemodem/readwrit.c new file mode 100644 index 00000000..af6da937 --- /dev/null +++ b/network/modem/fakemodem/readwrit.c @@ -0,0 +1,465 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + ioctl.c + +Abstract: + + This is a simple form of function driver for Fm device. The driver + doesn't handle any PnP and Power events because the framework provides + default behaviour for those events. This driver has enough support to + allow an user application (toast/notify.exe) to open the device + interface registered by the driver and send read, write or ioctl requests. + +Environment: + + Kernel mode + +--*/ + +#include "fakemodem.h" + + +VOID +FmEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ +Routine Description: + + This event is called when the framework receives IRP_MJ_READ + requests from the system. + This routines defers read for later processing if there is no data to read. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + Length - Length of the IO operation + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + PFM_DEVICE_DATA fmDeviceData = FmDeviceDataGet(WdfIoQueueGetDevice(Queue)); + ULONG information; + NTSTATUS status; + PUCHAR systemBuffer; + size_t bufLen; + + status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &bufLen); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + return; + } + + if (fmDeviceData->BytesInReadBuffer > 0) { + + ProcessReadBuffer(fmDeviceData, + systemBuffer, + (ULONG) Length, + &information); + + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, information); + + return; + + } else { + + // + // No data to read. Queue the request for later processing. + // + + status = WdfRequestForwardToIoQueue(Request, fmDeviceData->FmReadQueue); + if (!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, 0); + return; + } + } +} + +VOID +FmEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ +Routine Description: + + This event is called when the framework receives IRP_MJ_WRITE + requests from the system. + This routine will also drain the read queue if there are pending reads. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + Length - Length of the IO operation + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + PFM_DEVICE_DATA fmDeviceData = FmDeviceDataGet(WdfIoQueueGetDevice(Queue)); + PUCHAR systemBuffer; + NTSTATUS status; + size_t length; + WDFREQUEST readRequest; + + status = WdfRequestRetrieveInputBuffer(Request, Length, &systemBuffer, &length); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + return; + } + + ProcessWriteBytes( fmDeviceData, systemBuffer, (ULONG) Length); + + // + // Process read requests and complete them here. + // + + while (fmDeviceData->BytesInReadBuffer > 0) { + ULONG bytesToMove = 0; + + status = WdfIoQueueRetrieveNextRequest(fmDeviceData->FmReadQueue, &readRequest); + if (!NT_SUCCESS(status)) { + break; + } + + status = WdfRequestRetrieveOutputBuffer(readRequest, 0, &systemBuffer, &length); + if (NT_SUCCESS(status)) { + ProcessReadBuffer(fmDeviceData, + systemBuffer, + (ULONG) length, + &bytesToMove); + } + WdfRequestCompleteWithInformation(readRequest, status, bytesToMove); + } + + ProcessConnectionStateChange( fmDeviceData); + + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, Length); +} + +VOID +ProcessWriteBytes( + PFM_DEVICE_DATA FmDeviceData, + PUCHAR Characters, + ULONG Length + ) +/*++ +Routine Description: + + This function is called when the framework receives IRP_MJ_WRITE + requests from the system. The write event handler(FmEvtIoWrite) calls ProcessWriteBytes. + It parses the Characters passed in and looks for the for sequences "AT" -ok , + "ATA" --CONNECT, ATD<number> -- CONNECT and sets the state of the device appropriately. + These bytes are placed in the read Buffer to be processed later since this device + works in a loopback fashion. + + +Arguments: + + FmDeviceData - Handle to the framework queue object that is associated + with the I/O request. + Characters - Pointer to the write IRP's system buffer. + + Length - Length of the IO operation + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ + +{ + + UCHAR currentCharacter; + + while (Length != 0) { + + currentCharacter=*Characters++; + Length--; + + if(currentCharacter == '\0') + { + continue; + } + + PutCharInReadBuffer( FmDeviceData, currentCharacter); + + switch (FmDeviceData->CommandMatchState) { + + case COMMAND_MATCH_STATE_IDLE: + + if ((currentCharacter == 'a') || (currentCharacter == 'A')) { + // got an A + FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_GOT_A; + + FmDeviceData->ConnectCommand=FALSE; + + FmDeviceData->IgnoreNextChar=FALSE; + + } + + break; + + case COMMAND_MATCH_STATE_GOT_A: + + if ((currentCharacter == 't') || (currentCharacter == 'T')) { + // got an T + FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_GOT_T; + + } else { + + if (currentCharacter == '\r') { + + FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_IDLE; + } + } + + break; + + case COMMAND_MATCH_STATE_GOT_T: + + if (!FmDeviceData->IgnoreNextChar) { + // the last char was not a special char + // check for CONNECT command + if ((currentCharacter == 'A') || (currentCharacter == 'a')) { + + FmDeviceData->ConnectCommand=TRUE; + } + + if ((currentCharacter == 'D') || (currentCharacter == 'd')) { + + FmDeviceData->ConnectCommand=TRUE; + } + } + + FmDeviceData->IgnoreNextChar=TRUE; + + if (currentCharacter == '\r') { + // + // got a CR, send a response to the command + // + FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_IDLE; + + if (FmDeviceData->ConnectCommand) { + // + // place <cr><lf>CONNECT<cr><lf> in the buffer + // + PutCharInReadBuffer(FmDeviceData,'\r'); + PutCharInReadBuffer(FmDeviceData,'\n'); + + PutCharInReadBuffer(FmDeviceData,'C'); + PutCharInReadBuffer(FmDeviceData,'O'); + PutCharInReadBuffer(FmDeviceData,'N'); + PutCharInReadBuffer(FmDeviceData,'N'); + PutCharInReadBuffer(FmDeviceData,'E'); + PutCharInReadBuffer(FmDeviceData,'C'); + PutCharInReadBuffer(FmDeviceData,'T'); + + PutCharInReadBuffer(FmDeviceData,'\r'); + PutCharInReadBuffer(FmDeviceData,'\n'); + + // + // connected now raise CD + // + FmDeviceData->CurrentlyConnected=TRUE; + + FmDeviceData->ConnectionStateChanged=TRUE; + + } else { + + // place <cr><lf>OK<cr><lf> in the buffer + + PutCharInReadBuffer(FmDeviceData,'\r'); + PutCharInReadBuffer(FmDeviceData,'\n'); + PutCharInReadBuffer(FmDeviceData,'O'); + PutCharInReadBuffer(FmDeviceData,'K'); + PutCharInReadBuffer(FmDeviceData,'\r'); + PutCharInReadBuffer(FmDeviceData,'\n'); + } + } + + + break; + + default: + + break; + + } + } + + return; + +} + +VOID +PutCharInReadBuffer( + PFM_DEVICE_DATA FmDeviceData, + UCHAR Character + ) +/*++ +Routine Description: + + This routine puts the charcter into the circular read buffer checking for overflows while doing it. + +Arguments: + + FmDeviceData - Handle to the framework queue object that is associated + with the I/O request. + Characters - Handle to a framework request object. + + +Return Value: + + VOID + +--*/ + +{ + + if (FmDeviceData->BytesInReadBuffer < READ_BUFFER_SIZE) { + + // room in buffer + FmDeviceData->ReadBuffer[FmDeviceData->ReadBufferEnd]=Character; + FmDeviceData->ReadBufferEnd++; + FmDeviceData->ReadBufferEnd %= READ_BUFFER_SIZE; + FmDeviceData->BytesInReadBuffer++; + + } + + return; + +} + +VOID +ProcessReadBuffer( + IN PFM_DEVICE_DATA FmDeviceData, + IN PUCHAR SystemBuffer, + IN ULONG Length, + OUT PULONG BytesToMove + ) +/*++ +Routine Description: + + This event is called when the framework receives IRP_MJ_READ + requests from the system. It is called by the read event handler. + It copies data from the IRp's system buffer to the device read buffer. + if the size of data from the Irp's system buffer is greater than the size of the + read buffer the number of bytes remaining is passed back in BytesToMove. + + +Arguments: + + FmDeviceData - Handle to the framework queue object that is associated + with the I/O request. + SystemBuffer - The buffer passed in the IRP which contains the read data. + + Length - Length of data in the systembuffer + BytesToMove - Remaining bytes not copied into the read buffer. +Return Value: + + VOID + +--*/ +{ + ULONG firstHalf; + ULONG secondHalf; + ULONG bytesToMove; + NTSTATUS status; + ULONG safeBoundsCheck; + + // + // there is an IRP and there are characters waiting + // + + + bytesToMove = (Length < FmDeviceData->BytesInReadBuffer) ? Length + : FmDeviceData->BytesInReadBuffer; + + status = RtlULongAdd (FmDeviceData->ReadBufferBegin, + bytesToMove, + &safeBoundsCheck); + + if (!NT_SUCCESS(status)) { + return; + } + + if (safeBoundsCheck > READ_BUFFER_SIZE) { + + // + // the buffer is wrapped around, have move in two pieces + // + + firstHalf = READ_BUFFER_SIZE - FmDeviceData->ReadBufferBegin; + + secondHalf= bytesToMove - firstHalf; + + RtlCopyMemory( + SystemBuffer, + &FmDeviceData->ReadBuffer[FmDeviceData->ReadBufferBegin], + firstHalf); + + RtlCopyMemory( + (SystemBuffer + firstHalf), + &FmDeviceData->ReadBuffer[0], + secondHalf); + + } else { + + // + // can do it all at once + // + + RtlCopyMemory( + SystemBuffer, + &FmDeviceData->ReadBuffer[FmDeviceData->ReadBufferBegin], + bytesToMove); + } + + // + // fix up queue pointers + // + FmDeviceData->BytesInReadBuffer -= bytesToMove; + + FmDeviceData->ReadBufferBegin += bytesToMove; + + FmDeviceData->ReadBufferBegin %= READ_BUFFER_SIZE; + + *BytesToMove = bytesToMove; +} + |
