You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2259 lines
96 KiB
2259 lines
96 KiB
/***************************************************************************
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
SERIOCTL.C
|
|
|
|
Abstract:
|
|
|
|
Routines to handle serial IOCTLs for Legacy USB Modem Driver.
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
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.
|
|
|
|
Copyright (c) 1998 Microsoft Corporation. All Rights Reserved.
|
|
|
|
|
|
Revision History:
|
|
|
|
12/27/97 : created
|
|
|
|
Authors:
|
|
|
|
Tom Green
|
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
#include <wdm.h>
|
|
#include <ntddser.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <usb.h>
|
|
#include <usbdrivr.h>
|
|
#include <usbdlib.h>
|
|
#include <usbcomm.h>
|
|
|
|
#ifdef WMI_SUPPORT
|
|
#include <wmilib.h>
|
|
#include <wmidata.h>
|
|
#include <wmistr.h>
|
|
#endif
|
|
|
|
#include "usbser.h"
|
|
#include "serioctl.h"
|
|
#include "utils.h"
|
|
#include "usbserpw.h"
|
|
#include "debugwdm.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGEUSBS, SetBaudRate)
|
|
#pragma alloc_text(PAGEUSBS, GetBaudRate)
|
|
#pragma alloc_text(PAGEUSBS, SetLineControl)
|
|
#pragma alloc_text(PAGEUSBS, GetLineControl)
|
|
#pragma alloc_text(PAGEUSBS, SetTimeouts)
|
|
#pragma alloc_text(PAGEUSBS, GetTimeouts)
|
|
#pragma alloc_text(PAGEUSBS, SetChars)
|
|
#pragma alloc_text(PAGEUSBS, GetChars)
|
|
#pragma alloc_text(PAGEUSBS, SetClrDtr)
|
|
#pragma alloc_text(PAGEUSBS, ResetDevice)
|
|
#pragma alloc_text(PAGEUSBS, SetRts)
|
|
#pragma alloc_text(PAGEUSBS, ClrRts)
|
|
#pragma alloc_text(PAGEUSBS, SetBreak)
|
|
#pragma alloc_text(PAGEUSBS, SetQueueSize)
|
|
#pragma alloc_text(PAGEUSBS, GetWaitMask)
|
|
#pragma alloc_text(PAGEUSBS, SetWaitMask)
|
|
#pragma alloc_text(PAGEUSBS, WaitOnMask)
|
|
#pragma alloc_text(PAGEUSBS, ImmediateChar)
|
|
#pragma alloc_text(PAGEUSBS, Purge)
|
|
#pragma alloc_text(PAGEUSBS, GetHandflow)
|
|
#pragma alloc_text(PAGEUSBS, SetHandflow)
|
|
#pragma alloc_text(PAGEUSBS, GetModemStatus)
|
|
#pragma alloc_text(PAGEUSBS, GetDtrRts)
|
|
#pragma alloc_text(PAGEUSBS, GetCommStatus)
|
|
#pragma alloc_text(PAGEUSBS, GetProperties)
|
|
#pragma alloc_text(PAGEUSBS, LsrmstInsert)
|
|
#pragma alloc_text(PAGEUSBS, ConfigSize)
|
|
#pragma alloc_text(PAGEUSBS, GetStats)
|
|
#pragma alloc_text(PAGEUSBS, ClearStats)
|
|
#pragma alloc_text(PAGEUSBS, SerialGetProperties)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
LOCAL UCHAR StopBits[] =
|
|
{
|
|
STOP_BIT_1, // USB_COMM_STOPBITS_10
|
|
STOP_BITS_1_5, // USB_COMM_STOPBITS_15
|
|
STOP_BITS_2 // USB_COMM_STOPBITS_20
|
|
};
|
|
|
|
LOCAL UCHAR ParityType[] =
|
|
{
|
|
NO_PARITY, // USB_COMM_PARITY_NONE
|
|
ODD_PARITY, // USB_COMM_PARITY_ODD
|
|
EVEN_PARITY, // USB_COMM_PARITY_EVEN
|
|
MARK_PARITY, // USB_COMM_PARITY_MARK
|
|
SPACE_PARITY // USB_COMM_PARITY_SPACE
|
|
};
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetBaudRate */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_BAUD_RATE */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetBaudRate(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
KIRQL OldIrql;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetBaudRate");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetBaudRate(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(SERIAL_BAUD_RATE)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
DeviceExtension->CurrentBaud = Br->BaudRate;
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_TRACE3(("BaudRate (%08X)\n", Br->BaudRate));
|
|
|
|
NtStatus = SetLineControlAndBaud(PDevObj);
|
|
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetBaudRate");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetBaudRate %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetBaudRate
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetBaudRate */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_BAUD_RATE */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetBaudRate(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetBaudRate");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetBaudRate(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_BAUD_RATE)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
GetLineControlAndBaud(PDevObj);
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
Br->BaudRate = DeviceExtension->CurrentBaud;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetBaudRate");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetBaudRate %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetBaudRate
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetLineControl */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_LINE_CONTROL */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetLineControl(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
PSERIAL_LINE_CONTROL LineControl
|
|
= (PSERIAL_LINE_CONTROL) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetLineControl");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetLineControl(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(SERIAL_LINE_CONTROL)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
DeviceExtension->LineControl = *LineControl;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
// set line control for USB modem
|
|
NtStatus = SetLineControlAndBaud(PDevObj);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetLineControl");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetLineControl %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetLineControl
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetLineControl */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_LINE_CONTROL */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetLineControl(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
PSERIAL_LINE_CONTROL LineControl =
|
|
(PSERIAL_LINE_CONTROL) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetLineControl");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetLineControl(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_LINE_CONTROL))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
GetLineControlAndBaud(PDevObj);
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*LineControl = DeviceExtension->LineControl;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetLineControl");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetLineControl %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetLineControl
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetTimeouts */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_TIMEOUTS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetTimeouts(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_TIMEOUTS Timeouts =
|
|
(PSERIAL_TIMEOUTS) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetTimeouts");
|
|
UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM,
|
|
(">SetTimeouts(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(SERIAL_TIMEOUTS))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
DeviceExtension->Timeouts = *Timeouts;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetTimeouts");
|
|
UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM, ("<SetTimeouts %08X\n",
|
|
NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetTimeouts
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetTimeouts */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_TIMEOUTS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetTimeouts(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_TIMEOUTS Timeouts =
|
|
(PSERIAL_TIMEOUTS) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetTimeouts");
|
|
UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM,
|
|
(">GetTimeouts(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_TIMEOUTS))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*Timeouts = DeviceExtension->Timeouts;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetTimeouts");
|
|
UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM, ("<GetTimeouts %08X\n",
|
|
NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetTimeouts
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetChars */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_CHARS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetChars(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_CHARS SpecialChars =
|
|
(PSERIAL_CHARS) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetChars");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetChars(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(SERIAL_CHARS))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
DeviceExtension->SpecialChars = *SpecialChars;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetChars");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetChars %08X\n"));
|
|
|
|
return NtStatus;
|
|
} // SetChars
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetChars */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_CHARS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetChars(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_CHARS SpecialChars =
|
|
(PSERIAL_CHARS) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetChars");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetChars(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_CHARS))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*SpecialChars = DeviceExtension->SpecialChars;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_CHARS);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetChars");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetChars %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetChars
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetClrDtr */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_DTR and IOCTL_SERIAL_CLR_DTR */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* PDevObj - pointer to device object */
|
|
/* Set - TRUE if setting DTR, FALSE if clearing DTR */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetClrDtr(IN PDEVICE_OBJECT PDevObj, IN BOOLEAN Set)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
USHORT State = 0;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetClrDtr");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetClrDtr\n"));
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
if(DeviceExtension->DTRRTSState & SERIAL_RTS_STATE)
|
|
State |= USB_COMM_RTS;
|
|
|
|
if (Set) {
|
|
DeviceExtension->DTRRTSState |= SERIAL_DTR_STATE;
|
|
State |= USB_COMM_DTR;
|
|
} else {
|
|
DeviceExtension->DTRRTSState &= ~SERIAL_DTR_STATE;
|
|
}
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
if(DeviceExtension->DTRRTSState & SERIAL_RTS_STATE)
|
|
State |= USB_COMM_RTS;
|
|
|
|
NtStatus = ClassVendorCommand(PDevObj, USB_COMM_SET_CONTROL_LINE_STATE,
|
|
State, DeviceExtension->CommInterface,
|
|
NULL, NULL, FALSE, USBSER_CLASS_COMMAND);
|
|
|
|
if(!NT_SUCCESS(NtStatus)) {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
DeviceExtension->DTRRTSState &= ~SERIAL_DTR_STATE;
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetClrDtr");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetClrDtr %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetClrDtr
|
|
|
|
|
|
/************************************************************************/
|
|
/* ResetDevice */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_RESET_DEVICE */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
ResetDevice(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter ResetDevice");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">ResetDevice(%08X)\n", Irp));
|
|
|
|
// get line control and baud rate info
|
|
GetLineControlAndBaud(PDevObj);
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
// do device extension device specific stuff here
|
|
DeviceExtension->SupportedBauds = SERIAL_BAUD_300 | SERIAL_BAUD_600
|
|
| SERIAL_BAUD_1200 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800
|
|
| SERIAL_BAUD_9600 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400
|
|
| SERIAL_BAUD_57600 | SERIAL_BAUD_115200;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_LOG_PATH("exit ResetDevice");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<ResetDevice %08X\n"));
|
|
|
|
return NtStatus;
|
|
} // ResetDevice
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetRts */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_RTS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetRts(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
USHORT State = 0;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetRts");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetRts(%08X)\n", Irp));
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
DeviceExtension->DTRRTSState |= SERIAL_RTS_STATE;
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_LOG_PATH("exit SetRts");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetRts %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetRts
|
|
|
|
|
|
/************************************************************************/
|
|
/* ClrRts */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_CLR_RTS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
ClrRts(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
USHORT State = 0;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter ClrRts");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">ClrRts(%08X)\n", Irp));
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
DeviceExtension->DTRRTSState &= ~SERIAL_RTS_STATE;
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_LOG_PATH("exit ClrRts");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<ClrRts %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // ClrRts
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetBreak */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_BREAK_ON & IOCTL_SERIAL_SET_BREAK_OFF */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* PDevObj - pointer to device object */
|
|
/* Time - time to assert break in ms */
|
|
/* (0xFFFF - on / 0x0000 - off) */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetBreak(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj, USHORT Time)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
USBSER_LOCKED_PAGED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetBreak");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetBreak(%08X)\n", Irp));
|
|
|
|
NtStatus = ClassVendorCommand(PDevObj, USB_COMM_SEND_BREAK, Time,
|
|
DeviceExtension->CommInterface, NULL,
|
|
NULL, FALSE, USBSER_CLASS_COMMAND);
|
|
|
|
DEBUG_LOG_PATH("exit SetBreak");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetBreak %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetBreak
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetQueueSize */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_QUEUE_SIZE */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetQueueSize(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
PULONG QueueSize = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
DEBUG_LOG_PATH("enter SetQueueSize");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetQueueSize(%08X)\n", Irp));
|
|
|
|
USBSER_LOCKED_PAGED_CODE();
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(ULONG))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_TRACE1(("SetQueueSize (%08X)\n", *QueueSize));
|
|
// we will go ahead and save this, but we don't care.
|
|
// DeviceExtension->RxQueueSize = *QueueSize;
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetQueueSize");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetQueueSize %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetQueueSize
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetWaitMask */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_WAIT_MASK */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetWaitMask(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PULONG WaitMask = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetWaitMask");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetWaitMask(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(ULONG))
|
|
{
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*WaitMask = DeviceExtension->IsrWaitMask;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetWaitMask");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetWaitMask %08X\n"));
|
|
|
|
return NtStatus;
|
|
} // GetWaitMask
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetWaitMask */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_WAIT_MASK */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetWaitMask(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PULONG WaitMask = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetWaitMask");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetWaitMask(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
// make sure it's a valid request
|
|
if (*WaitMask & ~( SERIAL_EV_RXCHAR |
|
|
SERIAL_EV_RXFLAG |
|
|
SERIAL_EV_TXEMPTY |
|
|
SERIAL_EV_CTS |
|
|
SERIAL_EV_DSR |
|
|
SERIAL_EV_RLSD |
|
|
SERIAL_EV_BREAK |
|
|
SERIAL_EV_ERR |
|
|
SERIAL_EV_RING |
|
|
SERIAL_EV_PERR |
|
|
SERIAL_EV_RX80FULL |
|
|
SERIAL_EV_EVENT1 |
|
|
SERIAL_EV_EVENT2)) {
|
|
NtStatus = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
UsbSerCompletePendingWaitMasks(DeviceExtension);
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
DeviceExtension->HistoryMask = 0;
|
|
|
|
DeviceExtension->IsrWaitMask = *WaitMask;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_TRACE3(("SetWaitMask (%08X)\n", *WaitMask));
|
|
}
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetWaitMask");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetWaitMask %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetWaitMask
|
|
|
|
|
|
/************************************************************************/
|
|
/* WaitOnMask */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_WAIT_ON_MASK */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
WaitOnMask(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PULONG WaitMask = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter WaitOnMask");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">WaitOnMask(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(ULONG)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
|
|
// if we have an event to report, just go ahead and return it
|
|
if (DeviceExtension->HistoryMask) {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*WaitMask = DeviceExtension->HistoryMask;
|
|
DeviceExtension->HistoryMask = 0;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
|
|
UsbSerSerialDump(USBSERCOMPEV,
|
|
("Completing maskirp(3) %08x\n",
|
|
*WaitMask));
|
|
|
|
DEBUG_TRACE3(("Signal Event (%08X)\n", *WaitMask));
|
|
} else {
|
|
KIRQL cancelIrql;
|
|
|
|
ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql);
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
// just in case something comes in, we'll do a while loop
|
|
while (DeviceExtension->CurrentMaskIrp) {
|
|
PIRP pOldIrp;
|
|
|
|
DEBUG_TRACE3(("Completing previous mask\n"));
|
|
|
|
pOldIrp = DeviceExtension->CurrentMaskIrp;
|
|
DeviceExtension->CurrentMaskIrp = NULL;
|
|
|
|
pOldIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSetCancelRoutine(pOldIrp, NULL);
|
|
|
|
*WaitMask = 0;
|
|
|
|
UsbSerSerialDump(USBSERCOMPEV,
|
|
("Completing maskirp(4)\n"));
|
|
|
|
//
|
|
// Release locks, complete request, then
|
|
// reacquire the locks
|
|
//
|
|
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock,
|
|
OldIrql);
|
|
|
|
RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
|
|
|
|
IoCompleteRequest(pOldIrp, IO_SERIAL_INCREMENT);
|
|
|
|
ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql);
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock,
|
|
&OldIrql);
|
|
}
|
|
|
|
|
|
//
|
|
// Check to see if it needs to be cancelled
|
|
//
|
|
|
|
if (Irp->Cancel) {
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
|
|
} else {
|
|
IoSetCancelRoutine(Irp, UsbSerCancelWaitOnMask);
|
|
NtStatus = Irp->IoStatus.Status = STATUS_PENDING;
|
|
|
|
DeviceExtension->CurrentMaskIrp = Irp;
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit WaitOnMask");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<WaitOnMask %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // WaitOnMask
|
|
|
|
|
|
/************************************************************************/
|
|
/* ImmediateChar */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_IMMEDIATE_CHAR */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceObject - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
ImmediateChar(IN PIRP Irp, IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PUCHAR Char = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_LOCKED_PAGED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter ImmediateChar");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">ImmediateChar(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
//
|
|
// We just treat this as a write since we have no internal
|
|
// data buffer.
|
|
//
|
|
|
|
IrpStack->Parameters.Write.Length = sizeof(UCHAR);
|
|
|
|
NtStatus = UsbSer_Write(DeviceObject, Irp);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit ImmediateChar");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<ImmediateChar, %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // ImmediateChar
|
|
|
|
|
|
/************************************************************************/
|
|
/* Purge */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_PURGE */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
Purge(IN PDEVICE_OBJECT PDevObj, IN PIRP Irp,
|
|
IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
ULONG Mask = *((PULONG) Irp->AssociatedIrp.SystemBuffer);
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
KIRQL OldIrql;
|
|
ULONG Count;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter Purge");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">Purge(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
// make sure purge request is valid
|
|
if ((!Mask) || (Mask & ( ~( SERIAL_PURGE_TXABORT |
|
|
SERIAL_PURGE_RXABORT |
|
|
SERIAL_PURGE_TXCLEAR |
|
|
SERIAL_PURGE_RXCLEAR)))) {
|
|
NtStatus = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
if (Mask & SERIAL_PURGE_RXCLEAR) {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
Count = DeviceExtension->CharsInReadBuff;
|
|
|
|
DeviceExtension->CharsInReadBuff = 0;
|
|
DeviceExtension->CurrentReadBuffPtr = 0;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
if(Count)
|
|
{
|
|
RestartRead(DeviceExtension);
|
|
}
|
|
}
|
|
|
|
if (Mask & SERIAL_PURGE_RXABORT) {
|
|
UsbSerKillAllReadsOrWrites(PDevObj, &DeviceExtension->ReadQueue,
|
|
&DeviceExtension->CurrentReadIrp);
|
|
}
|
|
|
|
if (Mask & SERIAL_PURGE_TXABORT) {
|
|
//
|
|
// DO NOTHING because USB owns the request. However, it may
|
|
// prove in practice that we will have to cancel the IRPs on behalf
|
|
// of the caller.
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit Purge");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<Purge %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // Purge
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetHandflow */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_HANDFLOW */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetHandflow(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_HANDFLOW HandFlow
|
|
= (PSERIAL_HANDFLOW) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetHandflow");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetHandFlow(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_HANDFLOW)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*HandFlow = DeviceExtension->HandFlow;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetHandflow");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetHandFlow %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetHandflow
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetHandflow */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_SET_HANDFLOW */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetHandflow(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_HANDFLOW HandFlow
|
|
= (PSERIAL_HANDFLOW) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SetHandflow");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SetHandFlow(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(SERIAL_HANDFLOW)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
DeviceExtension->HandFlow = *HandFlow;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_TRACE3(("ControlHandShake (%08X)\n",
|
|
DeviceExtension->HandFlow.ControlHandShake));
|
|
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit SetHandflow");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SetHandFlow %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // SetHandflow
|
|
|
|
/************************************************************************/
|
|
/* GetModemStatus */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_MODEMSTATUS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetModemStatus(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PULONG ModemStatus = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
KIRQL OldIrql;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetModemStatus");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetModemStatus(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(ULONG)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*ModemStatus = DeviceExtension->FakeModemStatus;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
|
|
DEBUG_TRACE3(("ModemStatus (%08X)\n", *ModemStatus));
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetModemStatus");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetModemStatus %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetModemStatus
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetDtrRts */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_DTRRTS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetDtrRts(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PULONG ModemControl = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
KIRQL OldIrql;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetDtrRts");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetDtrRts(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(ULONG)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*ModemControl = DeviceExtension->DTRRTSState;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetDtrRts");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetDtrRts %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetDtrRts
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetCommStatus */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_COMMSTATUS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetCommStatus(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIAL_STATUS SerialStatus
|
|
= (PSERIAL_STATUS) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetCommStatus");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetCommStatus(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_STATUS)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
RtlZeroMemory(SerialStatus, sizeof(SERIAL_STATUS));
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
SerialStatus->AmountInInQueue = DeviceExtension->CharsInReadBuff;
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_TRACE2(("AmountInInQueue (%08X)\n", SerialStatus->AmountInInQueue));
|
|
|
|
SerialStatus->Errors = 0;
|
|
SerialStatus->EofReceived = FALSE;
|
|
SerialStatus->AmountInOutQueue = 0;
|
|
SerialStatus->WaitForImmediate = 0;
|
|
SerialStatus->HoldReasons = 0;
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
|
|
}
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetCommStatus");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetCommStatus %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetCommStatus
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetProperties */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_PROPERTIES */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetProperties(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_LOCKED_PAGED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetProperties");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetProperties(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIAL_COMMPROP)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
SerialGetProperties(DeviceExtension,
|
|
(PSERIAL_COMMPROP)Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetProperties");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetProperties %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetProperties
|
|
|
|
|
|
/************************************************************************/
|
|
/* LsrmstInsert */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_LSRMST_INSERT */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
LsrmstInsert(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
USBSER_LOCKED_PAGED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter LsrmstInsert");
|
|
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">LsrmstInsert(%08X)\n", Irp));
|
|
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<LsrmstInsert (%08X)\n",
|
|
STATUS_NOT_SUPPORTED));
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
} // LsrmstInsert
|
|
|
|
|
|
/************************************************************************/
|
|
/* ConfigSize */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_CONFIG_SIZE */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
ConfigSize(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PULONG ConfigSize = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_LOCKED_PAGED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter ConfigSize");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">ConfigSize(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(ULONG)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
*ConfigSize = 0;
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit ConfigSize");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<ConfigSize %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // ConfigSize
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetStats */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_GET_STATS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetStats(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PSERIALPERF_STATS Stats
|
|
= (PSERIALPERF_STATS) Irp->AssociatedIrp.SystemBuffer;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter GetStats");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">GetStats(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(SERIALPERF_STATS)) {
|
|
NtStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
*Stats = DeviceExtension->PerfStats;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetStats");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<GetStats %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // GetStats
|
|
|
|
|
|
/************************************************************************/
|
|
/* ClearStats */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Handle IOCTL_SERIAL_CLEAR_STATS */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Irp - pointer to an I/O Request Packet */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
ClearStats(IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter ClearStats");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">ClearStats(%08X)\n", Irp));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
RtlZeroMemory(&DeviceExtension->PerfStats,
|
|
sizeof(SERIALPERF_STATS));
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_LOG_PATH("exit ClearStats");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<ClearStats %08X\n", NtStatus));
|
|
|
|
return NtStatus;
|
|
} // ClearStats
|
|
|
|
|
|
/************************************************************************/
|
|
/* SerialGetProperties */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Get serial device properties */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* DeviceExtension - pointer to device extension */
|
|
/* Properties - pointer to device properties to fill in */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/************************************************************************/
|
|
VOID
|
|
SerialGetProperties(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PSERIAL_COMMPROP Properties)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
USBSER_ALWAYS_LOCKED_CODE();
|
|
|
|
DEBUG_LOG_PATH("enter SerialGetProperties");
|
|
UsbSerSerialDump(USBSERTRACEIOC, (">SerialGetProperties\n"));
|
|
|
|
|
|
|
|
RtlZeroMemory(Properties, sizeof(SERIAL_COMMPROP));
|
|
|
|
Properties->PacketLength = sizeof(SERIAL_COMMPROP);
|
|
Properties->PacketVersion = 2;
|
|
Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
|
|
Properties->MaxTxQueue = 0;
|
|
Properties->MaxRxQueue = 0;
|
|
Properties->MaxBaud = SERIAL_BAUD_USER;
|
|
Properties->ProvSubType = SERIAL_SP_MODEM;
|
|
|
|
Properties->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_CD
|
|
| SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_TOTALTIMEOUTS
|
|
| SERIAL_PCF_INTTIMEOUTS;
|
|
|
|
Properties->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD
|
|
| SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING
|
|
| SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT;
|
|
|
|
|
|
Properties->SettableData = SERIAL_DATABITS_7 | SERIAL_DATABITS_8;
|
|
|
|
Properties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_PARITY_NONE
|
|
| SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK
|
|
| SERIAL_PARITY_SPACE;
|
|
|
|
Properties->CurrentTxQueue = 0;
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
Properties->CurrentRxQueue = DeviceExtension->RxQueueSize;
|
|
Properties->SettableBaud = DeviceExtension->SupportedBauds;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_LOG_PATH("exit SerialGetProperties");
|
|
UsbSerSerialDump(USBSERTRACEIOC, ("<SerialGetProperties\n"));
|
|
|
|
} // SerialGetProperties
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetLineControlAndBaud */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* CDC command to get line control settings and baud */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
GetLineControlAndBaud(IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
USB_COMM_LINE_CODING LineCoding;
|
|
ULONG Size = sizeof(LineCoding);
|
|
KIRQL OldIrql;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
DEBUG_LOG_PATH("enter GetLineControlAndBaud");
|
|
|
|
NtStatus = ClassVendorCommand(PDevObj, USB_COMM_GET_LINE_CODING, 0,
|
|
DeviceExtension->CommInterface,
|
|
&LineCoding, &Size, TRUE,
|
|
USBSER_CLASS_COMMAND);
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
DeviceExtension->CurrentBaud = LineCoding.DTERate;
|
|
DeviceExtension->LineControl.StopBits = StopBits[LineCoding.CharFormat];
|
|
DeviceExtension->LineControl.Parity = ParityType[LineCoding.ParityType];
|
|
DeviceExtension->LineControl.WordLength = LineCoding.DataBits;
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
DEBUG_TRACE3(("Baud (%08X) StopBits (%08X) DataBits (%08X)\n",
|
|
LineCoding.DTERate, LineCoding.CharFormat,
|
|
LineCoding.DataBits));
|
|
}
|
|
|
|
DEBUG_LOG_PATH("exit GetLineControlAndBaud");
|
|
|
|
return NtStatus;
|
|
} // GetLineControlAndBaud
|
|
|
|
|
|
/************************************************************************/
|
|
/* SetLineControlAndBaud */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* CDC command to set line control and baud */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* PDevObj - pointer to device object */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
SetLineControlAndBaud(IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
USB_COMM_LINE_CODING LineCoding;
|
|
ULONG Size = sizeof(LineCoding);
|
|
PSERIAL_LINE_CONTROL LineControl;
|
|
KIRQL OldIrql;
|
|
PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension;
|
|
|
|
DEBUG_LOG_PATH("enter SetLineControlAndBaud");
|
|
|
|
// get pointer to line control in extension
|
|
LineControl = &DeviceExtension->LineControl;
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
// set up the line coding data structure
|
|
LineCoding.DTERate = DeviceExtension->CurrentBaud;
|
|
LineCoding.DataBits = LineControl->WordLength;
|
|
|
|
switch (DeviceExtension->LineControl.StopBits) {
|
|
case STOP_BIT_1:
|
|
LineCoding.CharFormat = USB_COMM_STOPBITS_10;
|
|
break;
|
|
case STOP_BITS_1_5:
|
|
LineCoding.CharFormat = USB_COMM_STOPBITS_15;
|
|
break;
|
|
case STOP_BITS_2:
|
|
LineCoding.CharFormat = USB_COMM_STOPBITS_20;
|
|
break;
|
|
default:
|
|
NtStatus = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
switch (DeviceExtension->LineControl.Parity) {
|
|
case NO_PARITY:
|
|
LineCoding.ParityType = USB_COMM_PARITY_NONE;
|
|
break;
|
|
case ODD_PARITY:
|
|
LineCoding.ParityType = USB_COMM_PARITY_ODD;
|
|
break;
|
|
case EVEN_PARITY:
|
|
LineCoding.ParityType = USB_COMM_PARITY_EVEN;
|
|
break;
|
|
|
|
case MARK_PARITY:
|
|
LineCoding.ParityType = USB_COMM_PARITY_MARK;
|
|
break;
|
|
case SPACE_PARITY:
|
|
LineCoding.ParityType = USB_COMM_PARITY_SPACE;
|
|
break;
|
|
default:
|
|
NtStatus = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
// the request must be valid, so send it down to the device
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
NtStatus = ClassVendorCommand(PDevObj, USB_COMM_SET_LINE_CODING, 0,
|
|
DeviceExtension->CommInterface,
|
|
&LineCoding, &Size, FALSE,
|
|
USBSER_CLASS_COMMAND);
|
|
}
|
|
|
|
// let's go ahead and just grab this info again in case of an error
|
|
GetLineControlAndBaud(PDevObj);
|
|
|
|
DEBUG_LOG_PATH("exit SetLineControlAndBaud");
|
|
|
|
return NtStatus;
|
|
} // SetLineControlAndBaud
|
|
|
|
|
|
/************************************************************************/
|
|
/* NotifyCompletion */
|
|
/************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Notify completion routine. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* DeviceObject - pointer to a device object */
|
|
/* Irp - pointer to Irp */
|
|
/* Context - pointer to driver defined context */
|
|
/* */
|
|
/* Return Value: */
|
|
/* */
|
|
/* NTSTATUS */
|
|
/* */
|
|
/************************************************************************/
|
|
NTSTATUS
|
|
NotifyCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context;
|
|
PURB Urb;
|
|
ULONG Count;
|
|
KIRQL OldIrql;
|
|
KIRQL cancelIrql;
|
|
PUSB_COMM_SERIAL_STATUS SerialState;
|
|
USHORT ModemStatus;
|
|
USHORT OldModemStatus;
|
|
PIRP CurrentMaskIrp = NULL;
|
|
BOOLEAN startRead = FALSE;
|
|
|
|
DEBUG_LOG_PATH("enter NotifyCompletion");
|
|
|
|
Urb = DeviceExtension->NotifyUrb;
|
|
|
|
Count = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
SerialState = (PUSB_COMM_SERIAL_STATUS) DeviceExtension->NotificationBuff;
|
|
|
|
// see if it is our notification
|
|
if (SerialState->Notification == USB_COMM_SERIAL_STATE
|
|
&& Count == sizeof(USB_COMM_SERIAL_STATUS)) {
|
|
OldModemStatus = DeviceExtension->FakeModemStatus;
|
|
|
|
// cobble up a fake modem status
|
|
DeviceExtension->FakeModemStatus = SERIAL_MSR_CTS;
|
|
DeviceExtension->FakeLineStatus = 0;
|
|
DeviceExtension->HistoryMask = 0;
|
|
|
|
|
|
ModemStatus = SerialState->SerialState;
|
|
DeviceExtension->FakeLineStatus = 0;
|
|
|
|
DEBUG_TRACE1(("CDC Serial State (%08X)\n", ModemStatus));
|
|
|
|
if (ModemStatus & USB_COMM_DSR)
|
|
DeviceExtension->FakeModemStatus |= SERIAL_MSR_DSR;
|
|
|
|
if (ModemStatus & USB_COMM_DCD)
|
|
DeviceExtension->FakeModemStatus |= SERIAL_MSR_DCD;
|
|
|
|
if (ModemStatus & USB_COMM_RING)
|
|
DeviceExtension->FakeModemStatus |= SERIAL_MSR_RI;
|
|
|
|
// let's see what has changed in the status register
|
|
ModemStatus = OldModemStatus ^ DeviceExtension->FakeModemStatus;
|
|
|
|
if (ModemStatus & SERIAL_MSR_DSR)
|
|
DeviceExtension->HistoryMask |= SERIAL_EV_DSR;
|
|
|
|
if (ModemStatus & SERIAL_MSR_DCD)
|
|
DeviceExtension->HistoryMask |= SERIAL_EV_RLSD;
|
|
|
|
if (ModemStatus & SERIAL_MSR_RI)
|
|
DeviceExtension->HistoryMask |= SERIAL_EV_RING;
|
|
|
|
// see if we have any events we are waiting for
|
|
DeviceExtension->HistoryMask &= DeviceExtension->IsrWaitMask;
|
|
|
|
// update perf stats if we had any errors
|
|
if (ModemStatus & USB_COMM_FRAMING_ERROR) {
|
|
DeviceExtension->PerfStats.FrameErrorCount++;
|
|
DeviceExtension->FakeLineStatus |= SERIAL_LSR_FE;
|
|
}
|
|
|
|
if (ModemStatus & USB_COMM_OVERRUN) {
|
|
DeviceExtension->PerfStats.BufferOverrunErrorCount++;
|
|
DeviceExtension->FakeLineStatus |= SERIAL_LSR_OE;
|
|
}
|
|
|
|
if (ModemStatus & USB_COMM_PARITY_ERROR) {
|
|
DeviceExtension->PerfStats.ParityErrorCount++;
|
|
DeviceExtension->FakeLineStatus |= SERIAL_LSR_PE;
|
|
}
|
|
|
|
if (ModemStatus & USB_COMM_BREAK) {
|
|
DeviceExtension->FakeLineStatus |= SERIAL_LSR_BI;
|
|
}
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql);
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
// let's see if we have any events to signal
|
|
CurrentMaskIrp = DeviceExtension->CurrentMaskIrp;
|
|
|
|
if (CurrentMaskIrp && DeviceExtension->HistoryMask) {
|
|
*(PULONG) (CurrentMaskIrp->AssociatedIrp.SystemBuffer) =
|
|
DeviceExtension->HistoryMask;
|
|
|
|
CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
CurrentMaskIrp->IoStatus.Information = sizeof(ULONG);
|
|
|
|
DeviceExtension->CurrentMaskIrp = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
|
|
}
|
|
DEBUG_TRACE1(("Modem Status (%08X)\n", DeviceExtension->FakeModemStatus));
|
|
}
|
|
else
|
|
{
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
}
|
|
|
|
|
|
|
|
// complete the queued IRP if needed
|
|
if (CurrentMaskIrp && DeviceExtension->HistoryMask
|
|
&& Irp->IoStatus.Status == STATUS_SUCCESS)
|
|
{
|
|
|
|
//
|
|
// We should still be holding cancel spin lock because
|
|
// of above if()
|
|
|
|
|
|
UsbSerSerialDump(USBSERCOMPEV, ("Completing maskirp (4) %08X\n",
|
|
DeviceExtension->HistoryMask));
|
|
|
|
DeviceExtension->HistoryMask = 0;
|
|
|
|
IoSetCancelRoutine(CurrentMaskIrp, NULL);
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
|
|
|
|
IoCompleteRequest(CurrentMaskIrp, IO_NO_INCREMENT);
|
|
|
|
}
|
|
|
|
// check for Irp cancelled or error
|
|
if(Irp->IoStatus.Status == STATUS_CANCELLED)
|
|
{
|
|
goto NotifyCompletionErr;
|
|
}
|
|
else if(!NT_SUCCESS(Irp->IoStatus.Status))
|
|
{
|
|
UsbSerFetchBooleanLocked(&DeviceExtension->AcceptingRequests,
|
|
FALSE, &DeviceExtension->ControlLock);
|
|
goto NotifyCompletionErr;
|
|
}
|
|
|
|
|
|
ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
|
|
|
|
// kick off another notification request if we still need to
|
|
if (DeviceExtension->AcceptingRequests
|
|
&& (DeviceExtension->CurrentDevicePowerState == PowerDeviceD0))
|
|
{
|
|
// see if we have a work item queued already
|
|
if(DeviceExtension->IoWorkItem == NULL)
|
|
{
|
|
startRead = TRUE;
|
|
|
|
// kick off another read
|
|
DeviceExtension->IoWorkItem = IoAllocateWorkItem(DeviceExtension->PhysDeviceObject);
|
|
}
|
|
|
|
if(startRead && DeviceExtension->IoWorkItem)
|
|
{
|
|
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
|
|
IoQueueWorkItem(DeviceExtension->IoWorkItem,
|
|
USBSER_RestartNotifyReadWorkItem,
|
|
CriticalWorkQueue,
|
|
DeviceExtension);
|
|
}
|
|
else
|
|
{
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
}
|
|
|
|
} else {
|
|
RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
|
|
}
|
|
|
|
NotifyCompletionErr:;
|
|
|
|
//
|
|
// Notify everyone if this is the last IRP and we aren't starting another read
|
|
//
|
|
|
|
if((InterlockedDecrement(&DeviceExtension->PendingNotifyCount) == 0))
|
|
{
|
|
UsbSerSerialDump(USBSERTRACERD, ("Notify pipe is empty\n"));
|
|
|
|
if(!startRead)
|
|
{
|
|
KeSetEvent(&DeviceExtension->PendingNotifyEvent, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
DEBUG_LOG_PATH("exit NotifyCompletion");
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
} // NotifyCompletion
|
|
|
|
|
|
|