📄 comport.c
字号:
}
NTSTATUS QueryInfo(POSPDOEXT *pdoExt, PIRP irp)
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation(irp);
switch (irpSp->Parameters.QueryFile.FileInformationClass){
case FileBasicInformation:
DBGVERBOSE((" QueryInfo: FileBasicInformation"));
{
PFILE_BASIC_INFORMATION basicInfoBuf = irp->AssociatedIrp.SystemBuffer;
ASSERT(basicInfoBuf);
RtlCopyMemory(basicInfoBuf, &pdoExt->fileBasicInfo, sizeof(FILE_BASIC_INFORMATION));
irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION);
status = STATUS_SUCCESS;
}
break;
case FileStandardInformation:
DBGVERBOSE((" QueryInfo: FileStandardInformation"));
{
PFILE_STANDARD_INFORMATION stdInfoBuf = irp->AssociatedIrp.SystemBuffer;
ASSERT(stdInfoBuf);
stdInfoBuf->AllocationSize.QuadPart = 0;
stdInfoBuf->EndOfFile = stdInfoBuf->AllocationSize;
stdInfoBuf->NumberOfLinks = 0;
stdInfoBuf->DeletePending = FALSE;
stdInfoBuf->Directory = FALSE;
irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
status = STATUS_SUCCESS;
}
break;
case FilePositionInformation:
DBGVERBOSE((" QueryInfo: FilePositionInformation"));
/*
* Always return position 0
*/
((PFILE_POSITION_INFORMATION)irp->AssociatedIrp.SystemBuffer)->CurrentByteOffset.QuadPart = 0;
irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
status = STATUS_SUCCESS;
break;
case FileEndOfFileInformation:
DBGWARN((" QueryInfo: FileEndOfFileInformation"));
irp->IoStatus.Information = 0;
status = STATUS_INVALID_PARAMETER;
break;
default:
DBGWARN((" QueryInfo: ??? (%xh)", (ULONG)irpSp->Parameters.QueryFile.FileInformationClass));
irp->IoStatus.Information = 0;
status = STATUS_INVALID_PARAMETER;
break;
}
return status;
}
NTSTATUS SetInfo(POSPDOEXT *pdoExt, PIRP irp)
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation(irp);
switch (irpSp->Parameters.SetFile.FileInformationClass){
case FileBasicInformation:
DBGVERBOSE((" SetInfo: FileBasicInformation"));
{
PFILE_BASIC_INFORMATION basicInfoBuf = irp->AssociatedIrp.SystemBuffer;
ASSERT(basicInfoBuf);
RtlCopyMemory(&pdoExt->fileBasicInfo, basicInfoBuf, sizeof(FILE_BASIC_INFORMATION));
irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION);
status = STATUS_SUCCESS;
}
break;
case FileEndOfFileInformation:
DBGVERBOSE((" SetInfo: FileEndOfFileInformation"));
irp->IoStatus.Information = 0;
status = STATUS_SUCCESS;
break;
#define FileAllocationInformation 19 // BUGBUG - defined in ntioapi.h
case FileAllocationInformation:
DBGVERBOSE((" SetInfo: FileAllocationInformation"));
irp->IoStatus.Information = 0;
status = STATUS_SUCCESS;
break;
default:
DBGWARN((" SetInfo: ??? (%xh)", (ULONG)irpSp->Parameters.SetFile.FileInformationClass));
irp->IoStatus.Information = 0;
status = STATUS_INVALID_PARAMETER;
break;
}
return status;
}
NTSTATUS FlushBuffers(POSPDOEXT *pdoExt)
{
LIST_ENTRY irpsToCompleteList;
PLIST_ENTRY listEntry;
PIRP irp;
KIRQL oldIrql;
NTSTATUS status = STATUS_SUCCESS;
DBGVERBOSE(("FlushBuffers"));
/*
* This is so we don't loop forever if they get re-queued on the same thread.
*/
InitializeListHead(&irpsToCompleteList);
KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
/*
* Flush all pending Read and Wait Irps (if serial emulation feature is ON)
*/
while (irp = DequeueReadIrp(pdoExt, TRUE)){
InsertTailList(&irpsToCompleteList, &irp->Tail.Overlay.ListEntry);
}
if (pdoExt->parentFdoExt->posFlag & SERIAL_EMULATION) {
while (irp = DequeueWaitIrp(pdoExt)){
InsertTailList(&irpsToCompleteList, &irp->Tail.Overlay.ListEntry);
}
}
/*
* Empty out the queued readPackets.
* It's ok to free locked memory with the spinlock held.
*/
while (!IsListEmpty(&pdoExt->completedReadPacketsList)){
READPACKET *readPacket;
listEntry = RemoveHeadList(&pdoExt->completedReadPacketsList);
ASSERT(listEntry);
readPacket = CONTAINING_RECORD(listEntry, READPACKET, listEntry);
FreeReadPacket(readPacket);
}
KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
while (!IsListEmpty(&irpsToCompleteList)) {
listEntry = RemoveHeadList(&irpsToCompleteList);
ASSERT(listEntry);
irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
return status;
}
NTSTATUS InternalIoctl(POSPDOEXT *pdoExt, PIRP irp)
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation(irp);
switch (irpSp->Parameters.DeviceIoControl.IoControlCode){
// BUGBUG FINISH
default:
DBGVERBOSE(("InternalIoctl: ??? (%xh)", (ULONG)irpSp->Parameters.DeviceIoControl.IoControlCode));
status = irp->IoStatus.Status;
break;
}
return status;
}
LONG GetComPort(PARENTFDOEXT *parentFdoExt, ULONG comInterfaceIndex)
/*++
Routine Description:
Get the serial COM port index for a serial interface we're about to create.
If this is not the first plug-in, it should be sitting in the registry.
If this is the first plug-in, call GetFreeComPortNumber to reserve a new
static COM port for this device and store it in our software key.
Arguments:
Return Value:
Return COM port number or -1 if unsuccessful.
--*/
{
LONG comNumber = -1;
NTSTATUS status;
HANDLE hRegDevice;
status = IoOpenDeviceRegistryKey( parentFdoExt->physicalDevObj,
PLUGPLAY_REGKEY_DEVICE,
KEY_READ,
&hRegDevice);
if (NT_SUCCESS(status)){
UNICODE_STRING keyName;
PKEY_VALUE_FULL_INFORMATION keyValueInfo;
ULONG keyValueTotalSize, actualLength;
WCHAR interfaceKeyName[] = L"COMPortForInterfaceXXXX";
NumToHexString( interfaceKeyName+sizeof(interfaceKeyName)/sizeof(WCHAR)-1-4,
(USHORT)comInterfaceIndex,
4);
RtlInitUnicodeString(&keyName, interfaceKeyName);
keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) +
keyName.Length*sizeof(WCHAR) +
sizeof(ULONG);
keyValueInfo = ALLOCPOOL(PagedPool, keyValueTotalSize);
if (keyValueInfo){
status = ZwQueryValueKey( hRegDevice,
&keyName,
KeyValueFullInformation,
keyValueInfo,
keyValueTotalSize,
&actualLength);
if (NT_SUCCESS(status)){
ASSERT(keyValueInfo->Type == REG_DWORD);
ASSERT(keyValueInfo->DataLength == sizeof(ULONG));
comNumber = (LONG)*((PULONG)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset));
DBGVERBOSE(("GetComPort: read comport #%xh for interface %xh from registry.", (ULONG)comNumber, comInterfaceIndex));
}
else {
/*
* No COM port number recorded in registry.
* Allocate a new static COM port from the COM name arbiter
* and record it in our software key for the next PnP.
*/
comNumber = GetFreeComPortNumber();
if (comNumber == -1){
DBGERR(("GetComPort: GetFreeComPortNumber failed"));
}
else {
status = ZwSetValueKey( hRegDevice,
&keyName,
0,
REG_DWORD,
&comNumber,
sizeof(ULONG));
if (!NT_SUCCESS(status)){
DBGERR(("GetComPort: ZwSetValueKey failed with status %xh.", status));
}
}
}
FREEPOOL(keyValueInfo);
}
else {
ASSERT(keyValueInfo);
}
ZwClose(hRegDevice);
}
else {
DBGERR(("GetComPort: IoOpenDeviceRegistryKey failed with %xh.", status));
}
return comNumber;
}
LONG GetFreeComPortNumber()
/*++
Routine Description:
Find the index of the next unused serial COM port name in the system
(e.g. COM3, COM4, etc).
Arguments:
Return Value:
Return COM port number or -1 if unsuccessful.
--*/
{
LONG comNumber = -1;
if (isWin9x){
/*
* Windows 98
* Find the first unused name under Hardware\DeviceMap\SerialComm.
*
*
* BUGBUG:
* This algorithm does not find all the COM ports reserved
* by modems. May want to port tomgreen's AllocateCommPort
* function from \faulty\Wdm10\usb\driver\ccport\utils.c
*/
HANDLE hKey;
UNICODE_STRING keyName;
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\Hardware\\DeviceMap\\SerialComm");
InitializeObjectAttributes( &objectAttributes,
&keyName,
OBJ_CASE_INSENSITIVE,
NULL,
(PSECURITY_DESCRIPTOR)NULL);
status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &objectAttributes);
if (NT_SUCCESS(status)){
#define MAX_COMPORT_NAME_LEN (sizeof("COMxxxx")-1)
UCHAR keyValueBytes[sizeof(KEY_VALUE_FULL_INFORMATION)+(MAX_COMPORT_NAME_LEN+1)*sizeof(WCHAR)+sizeof(ULONG)];
PKEY_VALUE_FULL_INFORMATION keyValueInfo = (PKEY_VALUE_FULL_INFORMATION)keyValueBytes;
ULONG i, actualLen;
ULONG keyIndex = 0;
/*
* This bitmask represents the used COM ports.
* Bit i set indicates com port i+1 is reserved.
* Initialize with COM1 and COM2 reserved.
*
* BUGBUG - only works for up to 32 ports.
*/
ULONG comNameMask = 3;
do {
status = ZwEnumerateValueKey(
hKey,
keyIndex++,
KeyValueFullInformation,
keyValueInfo,
sizeof(keyValueBytes),
&actualLen);
if (NT_SUCCESS(status)){
if (keyValueInfo->Type == REG_SZ){
PWCHAR valuePtr = (PWCHAR)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset);
if (!WStrNCmpI(valuePtr, L"COM", 3)){
/*
* valuePtr+3 points the index portion of the COMx string,
* but we can't call LAtoD on it because it is
* NOT NULL-TERMINATED.
* So copy the index into our own buffer,
* null-terminate that,
* and call LAtoD to get the numerical index.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -