summaryrefslogtreecommitdiff
path: root/network/modem
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /network/modem
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'network/modem')
-rw-r--r--network/modem/fakemodem/ReadMe.md8
-rw-r--r--network/modem/fakemodem/driver.c474
-rw-r--r--network/modem/fakemodem/fakemodem.h156
-rw-r--r--network/modem/fakemodem/fakemodem.sln28
-rw-r--r--network/modem/fakemodem/fakemodem.vcxproj168
-rw-r--r--network/modem/fakemodem/fakemodem.vcxproj.Filters40
-rw-r--r--network/modem/fakemodem/ioctl.c790
-rw-r--r--network/modem/fakemodem/mdmfake.inx267
-rw-r--r--network/modem/fakemodem/readwrit.c465
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,
+ &currentWaitRequest);
+ // 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,
+ &currentWaitRequest);
+
+ 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,
+ &currentWaitRequest);
+ 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;
+}
+