/*++ Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation Module Name: pnp.c Abstract: This module contains the code that handles the plug and play IRPs for the serial driver. Environment: Kernel mode Revision History : --*/ #include "precomp.h" #define ALLF 0xffffffff static const PHYSICAL_ADDRESS SerialPhysicalZero = {0}; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGESRP0, SerialCreateDevObj) #pragma alloc_text(PAGESRP0, SerialAddDevice) #pragma alloc_text(PAGESRP0, SerialPnpDispatch) #pragma alloc_text(PAGESRP0, SerialStartDevice) #pragma alloc_text(PAGESRP0, SerialFinishStartDevice) #pragma alloc_text(PAGESRP0, SerialGetPortInfo) #pragma alloc_text(PAGESRP0, SerialDoExternalNaming) #pragma alloc_text(PAGESRP0, SerialReportMaxBaudRate) #pragma alloc_text(PAGESRP0, SerialControllerCallBack) #pragma alloc_text(PAGESRP0, SerialItemCallBack) #pragma alloc_text(PAGESRP0, SerialUndoExternalNaming) #endif // ALLOC_PRAGMA // // Instantiate the GUID // #if !defined(FAR) #define FAR #endif // !defined(FAR) #include DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73); #if DBG UCHAR *SerSystemCapString[] = { "PowerSystemUnspecified", "PowerSystemWorking", "PowerSystemSleeping1", "PowerSystemSleeping2", "PowerSystemSleeping3", "PowerSystemHibernate", "PowerSystemShutdown", "PowerSystemMaximum" }; UCHAR *SerDeviceCapString[] = { "PowerDeviceUnspecified", "PowerDeviceD0", "PowerDeviceD1", "PowerDeviceD2", "PowerDeviceD3", "PowerDeviceMaximum" }; #endif // DBG NTSTATUS SerialSyncCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT SerialSyncEvent) { KeSetEvent(SerialSyncEvent, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS SerialCreateDevObj(IN PDRIVER_OBJECT DriverObject, OUT PDEVICE_OBJECT *NewDeviceObject) /*++ Routine Description: This routine will create and initialize a functional device object to be attached to a Serial controller PDO. Arguments: DriverObject - a pointer to the driver object this is created under NewDeviceObject - a location to store the pointer to the new device object Return Value: STATUS_SUCCESS if everything was successful reason for failure otherwise --*/ { UNICODE_STRING deviceObjName; PDEVICE_OBJECT deviceObject = NULL; PSERIAL_DEVICE_EXTENSION pDevExt; NTSTATUS status = STATUS_SUCCESS; static ULONG currentInstance = 0; UNICODE_STRING instanceStr; WCHAR instanceNumberBuffer[20]; PAGED_CODE(); SerialDump (SERTRACECALLS,("SERIAL: Enter SerialCreateDevObj\n")); // // Zero out allocated memory pointers so we know if they must be freed // RtlZeroMemory(&deviceObjName, sizeof(UNICODE_STRING)); deviceObjName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR); deviceObjName.Buffer = ExAllocatePool(PagedPool, deviceObjName.MaximumLength + sizeof(WCHAR)); if (deviceObjName.Buffer == NULL) { SerialLogError(DriverObject, NULL, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for device name" "\n")); return STATUS_SUCCESS; } RtlZeroMemory(deviceObjName.Buffer, deviceObjName.MaximumLength + sizeof(WCHAR)); #if defined(NEC_98) RtlAppendUnicodeToString(&deviceObjName, L"\\Device\\Ser71051"); #else RtlAppendUnicodeToString(&deviceObjName, L"\\Device\\Serial"); #endif //defined(NEC_98) RtlInitUnicodeString(&instanceStr, NULL); instanceStr.MaximumLength = sizeof(instanceNumberBuffer); instanceStr.Buffer = instanceNumberBuffer; RtlIntegerToUnicodeString(currentInstance++, 10, &instanceStr); RtlAppendUnicodeStringToString(&deviceObjName, &instanceStr); // // Create the device object // status = IoCreateDevice(DriverObject, sizeof(SERIAL_DEVICE_EXTENSION), &deviceObjName, FILE_DEVICE_SERIAL_PORT, FILE_DEVICE_SECURE_OPEN, TRUE, &deviceObject); if (!NT_SUCCESS(status)) { SerialDump(SERERRORS, ("SerialAddDevice: Create device failed - %x \n", status)); goto SerialCreateDevObjError; } ASSERT(deviceObject != NULL); // // The device object has a pointer to an area of non-paged // pool allocated for this device. This will be the device // extension. Zero it out. // pDevExt = deviceObject->DeviceExtension; RtlZeroMemory(pDevExt, sizeof(SERIAL_DEVICE_EXTENSION)); // // Initialize the count of IRP's pending // pDevExt->PendingIRPCnt = 1; // // Initialize the count of DPC's pending // pDevExt->DpcCount = 1; // // Allocate Pool and save the nt device name in the device extension. // pDevExt->DeviceName.Buffer = ExAllocatePool(PagedPool, deviceObjName.Length + sizeof(WCHAR)); if (!pDevExt->DeviceName.Buffer) { SerialLogError( DriverObject, NULL, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL ); SerialDump( SERERRORS, ("SERIAL: Couldn't allocate memory for DeviceName\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialCreateDevObjError; } pDevExt->DeviceName.MaximumLength = deviceObjName.Length + sizeof(WCHAR); // // Zero fill it. // RtlZeroMemory(pDevExt->DeviceName.Buffer, pDevExt->DeviceName.MaximumLength); RtlAppendUnicodeStringToString(&pDevExt->DeviceName, &deviceObjName); pDevExt->NtNameForPort.Buffer = ExAllocatePool(PagedPool, deviceObjName.MaximumLength); if (pDevExt->NtNameForPort.Buffer == NULL) { SerialDump(SERERRORS, ("SerialAddDevice: Cannot allocate memory for " "NtName\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialCreateDevObjError; } pDevExt->NtNameForPort.MaximumLength = deviceObjName.MaximumLength; RtlAppendUnicodeStringToString(&pDevExt->NtNameForPort, &deviceObjName); // // Set up the device extension. // pDevExt->DeviceIsOpened = FALSE; pDevExt->DeviceObject = deviceObject; pDevExt->DriverObject = DriverObject; pDevExt->DeviceObject = deviceObject; pDevExt->PowerState = PowerDeviceD0; pDevExt->TxFifoAmount = driverDefaults.TxFIFODefault; pDevExt->CreatedSymbolicLink = TRUE; pDevExt->OwnsPowerPolicy = TRUE; InitializeListHead(&pDevExt->CommonInterruptObject); InitializeListHead(&pDevExt->TopLevelSharers); InitializeListHead(&pDevExt->MultiportSiblings); InitializeListHead(&pDevExt->AllDevObjs); InitializeListHead(&pDevExt->ReadQueue); InitializeListHead(&pDevExt->WriteQueue); InitializeListHead(&pDevExt->MaskQueue); InitializeListHead(&pDevExt->PurgeQueue); InitializeListHead(&pDevExt->StalledIrpQueue); ExInitializeFastMutex(&pDevExt->OpenMutex); ExInitializeFastMutex(&pDevExt->CloseMutex); KeInitializeEvent(&pDevExt->PendingIRPEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&pDevExt->PendingDpcEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&pDevExt->PowerD0Event, SynchronizationEvent, FALSE); deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; *NewDeviceObject = deviceObject; ExFreePool(deviceObjName.Buffer); SerialDump (SERTRACECALLS,("SERIAL: Leave SerialCreateDevObj\n") ); return STATUS_SUCCESS; SerialCreateDevObjError: SerialDump (SERERRORS,("SERIAL: SerialCreateDevObj Error, Cleaning up\n") ); // // Free the allocated strings for the NT and symbolic names if they exist. // if (deviceObjName.Buffer != NULL) { ExFreePool(deviceObjName.Buffer); } if (deviceObject) { if (pDevExt->NtNameForPort.Buffer != NULL) { ExFreePool(pDevExt->NtNameForPort.Buffer); } if (pDevExt->DeviceName.Buffer != NULL) { ExFreePool(pDevExt->DeviceName.Buffer); } IoDeleteDevice(deviceObject); } *NewDeviceObject = NULL; SerialDump (SERTRACECALLS,("SERIAL: Leave SerialCreateDevObj\n") ); return status; } NTSTATUS SerialAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PPdo) /*++ Routine Description: This routine creates a functional device object for com ports in the system and attaches them to the physical device objects for the ports Arguments: DriverObject - a pointer to the object for this driver PPdo - a pointer to the PDO in the stack we need to attach to Return Value: status from device creation and initialization --*/ { PDEVICE_OBJECT pNewDevObj = NULL; PDEVICE_OBJECT pLowerDevObj = NULL; NTSTATUS status; PSERIAL_DEVICE_EXTENSION pDevExt; PAGED_CODE(); SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialAddDevice with PPdo " "0x%x\n", PPdo)); if (PPdo == NULL) { // // Return no more devices // SerialDump(SERERRORS, ("SerialAddDevice: Enumeration request, returning" " NO_MORE_ENTRIES\n")); return (STATUS_NO_MORE_ENTRIES); } // // create and initialize the new device object // status = SerialCreateDevObj(DriverObject, &pNewDevObj); if (!NT_SUCCESS(status)) { SerialDump(SERERRORS, ("SerialAddDevice - error creating new devobj [%#08lx]\n", status)); return status; } // // Layer our DO on top of the lower device object // The return value is a pointer to the device object to which the // DO is actually attached. // pLowerDevObj = IoAttachDeviceToDeviceStack(pNewDevObj, PPdo); // // No status. Do the best we can. // ASSERT(pLowerDevObj != NULL); pDevExt = pNewDevObj->DeviceExtension; pDevExt->LowerDeviceObject = pLowerDevObj; pDevExt->Pdo = PPdo; // // Specify that this driver only supports buffered IO. This basically // means that the IO system copies the users data to and from // system supplied buffers. // // Also specify that we are power pagable. // pNewDevObj->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; SerialDump(SERTRACECALLS, ("SERIAL: Leave SerialAddDevice\n")); return status; } NTSTATUS SerialPnpDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp) /*++ Routine Description: This is a dispatch routine for the IRPs that come to the driver with the IRP_MJ_PNP major code (plug-and-play IRPs). Arguments: PDevObj - Pointer to the device object for this device PIrp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call --*/ { PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension; PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp); NTSTATUS status; PDEVICE_CAPABILITIES pDevCaps; PAGED_CODE(); if ((status = SerialIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) { SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } switch (pIrpStack->MinorFunction) { case IRP_MN_QUERY_CAPABILITIES: { PKEVENT pQueryCapsEvent; SYSTEM_POWER_STATE cap; SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_QUERY_DEVICE_CAPABILITIES " "IRP\n")); pQueryCapsEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT)); if (pQueryCapsEvent == NULL) { PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeEvent(pQueryCapsEvent, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(PIrp); IoSetCompletionRoutine(PIrp, SerialSyncCompletion, pQueryCapsEvent, TRUE, TRUE, TRUE); status = IoCallDriver(pLowerDevObj, PIrp); // // Wait for lower drivers to be done with the Irp // if (status == STATUS_PENDING) { KeWaitForSingleObject(pQueryCapsEvent, Executive, KernelMode, FALSE, NULL); } ExFreePool(pQueryCapsEvent); status = PIrp->IoStatus.Status; if (pIrpStack->Parameters.DeviceCapabilities.Capabilities == NULL) { goto errQueryCaps; } // // Save off their power capabilities // SerialDump(SERPNPPOWER, ("SERIAL: Mapping power capabilities\n")); pIrpStack = IoGetCurrentIrpStackLocation(PIrp); pDevCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities; for (cap = PowerSystemSleeping1; cap < PowerSystemMaximum; cap++) { SerialDump(SERPNPPOWER, (" SERIAL: %d: %s <--> %s\n", cap, SerSystemCapString[cap], SerDeviceCapString[pDevCaps->DeviceState[cap]] )); pDevExt->DeviceStateMap[cap] = pDevCaps->DeviceState[cap]; } pDevExt->DeviceStateMap[PowerSystemUnspecified] = PowerDeviceUnspecified; pDevExt->DeviceStateMap[PowerSystemWorking] = PowerDeviceD0; pDevExt->SystemWake = pDevCaps->SystemWake; pDevExt->DeviceWake = pDevCaps->DeviceWake; errQueryCaps:; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } case IRP_MN_QUERY_DEVICE_RELATIONS: // // We just pass this down -- serenum enumerates our bus for us. // SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_QUERY_DEVICE_RELATIONS " "Irp\n")); switch (pIrpStack->Parameters.QueryDeviceRelations.Type) { case BusRelations: SerialDump(SERPNPPOWER, ("------- BusRelations Query\n")); break; case EjectionRelations: SerialDump(SERPNPPOWER, ("------- EjectionRelations Query\n")); break; case PowerRelations: SerialDump(SERPNPPOWER, ("------- PowerRelations Query\n")); break; case RemovalRelations: SerialDump(SERPNPPOWER, ("------- RemovalRelations Query\n")); break; case TargetDeviceRelation: SerialDump(SERPNPPOWER, ("------- TargetDeviceRelation Query\n")); break; default: SerialDump(SERPNPPOWER, ("------- Unknown Query\n")); break; } IoSkipCurrentIrpStackLocation(PIrp); status = SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); return status; case IRP_MN_QUERY_INTERFACE: SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_QUERY_INTERFACE Irp\n")); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: SerialDump (SERPNPPOWER, ("SERIAL: Got " "IRP_MN_QUERY_RESOURCE_REQUIREMENTS Irp\n")); break; case IRP_MN_START_DEVICE: { PVOID startLockPtr; SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_START_DEVICE Irp\n")); // // SerialStartDevice will pass this Irp to the next driver, // and process it as completion so just complete it here. // SerialLockPagableSectionByHandle(SerialGlobals.PAGESER_Handle); // // We used to make sure the stack was powered up, but now it // is supposed to be done implicitly by start_device. // If that wasn't the case we would just make this call: // // status = SerialGotoPowerState(PDevObj, pDevExt, PowerDeviceD0); // pDevExt->PowerState = PowerDeviceD0; status = SerialStartDevice(PDevObj, PIrp); (void)SerialGotoPowerState(PDevObj, pDevExt, PowerDeviceD3); SerialUnlockPagableImageSection(SerialGlobals.PAGESER_Handle); PIrp->IoStatus.Status = status; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } case IRP_MN_READ_CONFIG: SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_READ_CONFIG Irp\n")); break; case IRP_MN_WRITE_CONFIG: SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_WRITE_CONFIG Irp\n")); break; case IRP_MN_EJECT: SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_EJECT Irp\n")); break; case IRP_MN_SET_LOCK: SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_SET_LOCK Irp\n")); break; case IRP_MN_QUERY_ID: { UNICODE_STRING pIdBuf; PWCHAR pPnpIdStr; ULONG pnpIdStrLen; ULONG isMulti = 0; HANDLE pnpKey; SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_QUERY_ID Irp\n")); if (pIrpStack->Parameters.QueryId.IdType != BusQueryHardwareIDs && pIrpStack->Parameters.QueryId.IdType != BusQueryCompatibleIDs) { IoSkipCurrentIrpStackLocation(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } if (pIrpStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) { PIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_WRITE, &pnpKey); if (!NT_SUCCESS(status)) { PIrp->IoStatus.Status = status; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } status = SerialGetRegistryKeyValue (pnpKey, L"MultiportDevice", sizeof(L"MultiportDevice"), &isMulti, sizeof (ULONG)); ZwClose(pnpKey); if (!NT_SUCCESS(status)) { PIrp->IoStatus.Status = status; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } pPnpIdStr = isMulti ? SERIAL_PNP_MULTI_ID_STR : SERIAL_PNP_ID_STR; pnpIdStrLen = isMulti ? sizeof(SERIAL_PNP_MULTI_ID_STR) : sizeof(SERIAL_PNP_ID_STR); if (PIrp->IoStatus.Information != 0) { ULONG curStrLen; ULONG allocLen = 0; PWSTR curStr = (PWSTR)PIrp->IoStatus.Information; // // We have to walk the strings to count the amount of space to // reallocate // while ((curStrLen = wcslen(curStr)) != 0) { allocLen += curStrLen * sizeof(WCHAR) + sizeof(UNICODE_NULL); curStr += curStrLen + 1; } allocLen += sizeof(UNICODE_NULL); pIdBuf.Buffer = ExAllocatePool(PagedPool, allocLen + pnpIdStrLen + sizeof(WCHAR)); if (pIdBuf.Buffer == NULL) { // // Clean up after other drivers since we are // sending the irp back up. // ExFreePool((PWSTR)PIrp->IoStatus.Information); PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; PIrp->IoStatus.Information = 0; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } pIdBuf.MaximumLength = (USHORT)(allocLen + pnpIdStrLen); pIdBuf.Length = (USHORT)allocLen - sizeof(UNICODE_NULL); RtlZeroMemory(pIdBuf.Buffer, pIdBuf.MaximumLength + sizeof(WCHAR)); RtlCopyMemory(pIdBuf.Buffer, (PWSTR)PIrp->IoStatus.Information, allocLen); RtlAppendUnicodeToString(&pIdBuf, pPnpIdStr); // // Free what the previous driver allocated // ExFreePool((PWSTR)PIrp->IoStatus.Information); } else { SerialDump(SERPNPPOWER, ("SERIAL: ID is sole ID\n")); pIdBuf.Buffer = ExAllocatePool(PagedPool, pnpIdStrLen + sizeof(WCHAR) * 2); if (pIdBuf.Buffer == NULL) { PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; PIrp->IoStatus.Information = 0; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } pIdBuf.MaximumLength = (USHORT)pnpIdStrLen; pIdBuf.Length = 0; RtlZeroMemory(pIdBuf.Buffer, pIdBuf.MaximumLength + sizeof(WCHAR) * 2); RtlAppendUnicodeToString(&pIdBuf, pPnpIdStr); } PIrp->IoStatus.Information = (ULONG_PTR)pIdBuf.Buffer; PIrp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: { HANDLE pnpKey; PKEVENT pResFiltEvent; ULONG isMulti = 0; PIO_RESOURCE_REQUIREMENTS_LIST pReqList; PIO_RESOURCE_LIST pResList; PIO_RESOURCE_DESCRIPTOR pResDesc; ULONG i, j; ULONG reqCnt; ULONG gotISR; ULONG gotInt; ULONG listNum; SerialDump(SERPNPPOWER, ("SERIAL: Got " "IRP_MN_FILTER_RESOURCE_REQUIREMENTS Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); pResFiltEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT)); if (pResFiltEvent == NULL) { PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeEvent(pResFiltEvent, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(PIrp); IoSetCompletionRoutine(PIrp, SerialSyncCompletion, pResFiltEvent, TRUE, TRUE, TRUE); status = IoCallDriver(pLowerDevObj, PIrp); // // Wait for lower drivers to be done with the Irp // if (status == STATUS_PENDING) { KeWaitForSingleObject (pResFiltEvent, Executive, KernelMode, FALSE, NULL); } ExFreePool(pResFiltEvent); if (PIrp->IoStatus.Information == 0) { if (pIrpStack->Parameters.FilterResourceRequirements .IoResourceRequirementList == 0) { SerialDump(SERPNPPOWER, ("------- Can't filter NULL resources!" "\n")); status = PIrp->IoStatus.Status; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } PIrp->IoStatus.Information = (ULONG_PTR)pIrpStack->Parameters .FilterResourceRequirements .IoResourceRequirementList; } status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_WRITE, &pnpKey); if (!NT_SUCCESS(status)) { PIrp->IoStatus.Status = status; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return status; } // // No matter what we add our filter if we can and return success. // status = SerialGetRegistryKeyValue (pnpKey, L"MultiportDevice", sizeof(L"MultiportDevice"), &isMulti, sizeof (ULONG)); ZwClose(pnpKey); // // Force ISR ports in IO_RES_REQ_LIST to shared status // Force interrupts to shared status // // // We will only process the first list -- multiport boards // should not have alternative resources // pReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)PIrp->IoStatus.Information; pResList = &pReqList->List[0]; SerialDump(SERPNPPOWER, ("------- List has %x lists " "(including alternatives)\n", pReqList->AlternativeLists)); for (listNum = 0; listNum < (pReqList->AlternativeLists); listNum++) { gotISR = 0; gotInt = 0; SerialDump(SERPNPPOWER, ("------- List has %x resources in it\n", pResList->Count)); for (j = 0; (j < pResList->Count); j++) { pResDesc = &pResList->Descriptors[j]; switch (pResDesc->Type) { case CmResourceTypePort: if (isMulti && (pResDesc->u.Port.Length == SERIAL_STATUS_LENGTH) && !gotISR) { gotISR = 1; pResDesc->ShareDisposition = CmResourceShareShared; SerialDump(SERPNPPOWER, ("------- Sharing I/O port for " "device %x\n", pLowerDevObj)); } break; case CmResourceTypeInterrupt: if (!gotInt) { gotInt = 1; if (pResDesc->ShareDisposition != CmResourceShareShared) { pResDesc->ShareDisposition = CmResourceShareShared; SerialDump(SERPNPPOWER, ("------- Sharing interrupt " "for device %x\n", pLowerDevObj)); } else { pDevExt->InterruptShareable = TRUE; SerialDump(SERPNPPOWER, ("------- Globally sharing " " interrupt for device %x\n", pLowerDevObj)); } } break; default: break; } // // If we found what we need, we can break out of the loop // if ((isMulti && gotInt && gotISR) || (!isMulti && gotInt)) { break; } } pResList = (PIO_RESOURCE_LIST)((PUCHAR)pResList + sizeof(IO_RESOURCE_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR) * (pResList->Count - 1)); } PIrp->IoStatus.Status = STATUS_SUCCESS; SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } case IRP_MN_QUERY_PNP_DEVICE_STATE: { if (pDevExt->Flags & SERIAL_FLAGS_BROKENHW) { (PNP_DEVICE_STATE)PIrp->IoStatus.Information |= PNP_DEVICE_FAILED; PIrp->IoStatus.Status = STATUS_SUCCESS; } IoCopyCurrentIrpStackLocationToNext(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } case IRP_MN_STOP_DEVICE: { ULONG pendingIRPs; KIRQL oldIrql; SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_STOP_DEVICE Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); ASSERT(!pDevExt->PortOnAMultiportCard); SerialSetFlags(pDevExt, SERIAL_FLAGS_STOPPED); SerialSetAccept(pDevExt,SERIAL_PNPACCEPT_STOPPED); SerialClearAccept(pDevExt, SERIAL_PNPACCEPT_STOPPING); pDevExt->PNPState = SERIAL_PNP_STOPPING; // // From this point on all non-PNP IRP's will be queued // // // Decrement for entry here // InterlockedDecrement(&pDevExt->PendingIRPCnt); // // Decrement for stopping // pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt); if (pendingIRPs) { KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive, KernelMode, FALSE, NULL); } // // Re-increment the count for later // InterlockedIncrement(&pDevExt->PendingIRPCnt); // // We need to free resources...basically this is a remove // without the detach from the stack. // if (pDevExt->Flags & SERIAL_FLAGS_STARTED) { SerialReleaseResources(pDevExt); } // // Pass the irp down // PIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(PIrp); return IoCallDriver(pLowerDevObj, PIrp); } case IRP_MN_QUERY_STOP_DEVICE: { KIRQL oldIrql; SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_QUERY_STOP_DEVICE Irp\n") ); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); // // See if we should succeed a stop query // if (pDevExt->PortOnAMultiportCard) { PIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; SerialDump(SERPNPPOWER, ("------- failing; multiport node\n")); SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_NOT_SUPPORTED; } // // If the device hasn't started yet, we ignore this request // and just pass it down. // if (pDevExt->PNPState != SERIAL_PNP_STARTED) { IoSkipCurrentIrpStackLocation(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } // // Lock around the open status // ExAcquireFastMutex(&pDevExt->OpenMutex); if (pDevExt->DeviceIsOpened) { ExReleaseFastMutex(&pDevExt->OpenMutex); PIrp->IoStatus.Status = STATUS_DEVICE_BUSY; SerialDump(SERPNPPOWER, ("------- failing; device open\n")); SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_DEVICE_BUSY; } pDevExt->PNPState = SERIAL_PNP_QSTOP; SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_STOPPING); // // Unlock around the open status // ExReleaseFastMutex(&pDevExt->OpenMutex); PIrp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } case IRP_MN_CANCEL_STOP_DEVICE: SerialDump(SERPNPPOWER, ("SERIAL: Got " "IRP_MN_CANCEL_STOP_DEVICE Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); if (pDevExt->PNPState == SERIAL_PNP_QSTOP) { // // Restore the device state // pDevExt->PNPState = SERIAL_PNP_STARTED; SerialClearAccept(pDevExt, SERIAL_PNPACCEPT_STOPPING); } PIrp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); case IRP_MN_CANCEL_REMOVE_DEVICE: SerialDump(SERPNPPOWER, ("SERIAL: Got " "IRP_MN_CANCEL_REMOVE_DEVICE Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); // // Restore the device state // pDevExt->PNPState = SERIAL_PNP_STARTED; SerialClearAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING); PIrp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); case IRP_MN_QUERY_REMOVE_DEVICE: { KIRQL oldIrql; SerialDump(SERPNPPOWER, ("SERIAL: Got " "IRP_MN_QUERY_REMOVE_DEVICE Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); ExAcquireFastMutex(&pDevExt->OpenMutex); // // See if we should succeed a remove query // if (pDevExt->DeviceIsOpened) { ExReleaseFastMutex(&pDevExt->OpenMutex); PIrp->IoStatus.Status = STATUS_DEVICE_BUSY; SerialDump(SERPNPPOWER, ("------- failing; device open\n")); SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return STATUS_DEVICE_BUSY; } pDevExt->PNPState = SERIAL_PNP_QREMOVE; SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING); ExReleaseFastMutex(&pDevExt->OpenMutex); PIrp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } case IRP_MN_SURPRISE_REMOVAL: { ULONG pendingIRPs; KIRQL oldIrql; SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_SURPRISE_REMOVAL Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); // // Prevent any new I/O to the device // SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_SURPRISE_REMOVING); // // Dismiss all pending requests // SerialKillPendingIrps(PDevObj); // // Wait for any pending requests we raced on. // // // Decrement once for ourselves // InterlockedDecrement(&pDevExt->PendingIRPCnt); // // Decrement for the remove // pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt); if (pendingIRPs) { KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive, KernelMode, FALSE, NULL); } // // Reset for subsequent remove // InterlockedIncrement(&pDevExt->PendingIRPCnt); // // Remove any external interfaces and release resources // SerialDisableInterfacesResources(PDevObj, FALSE); PIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(PIrp); return SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); } case IRP_MN_REMOVE_DEVICE: { ULONG pendingIRPs; KIRQL oldIrql; SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_REMOVE_DEVICE Irp\n")); SerialDump(SERPNPPOWER, ("------- for device %x\n", pLowerDevObj)); // // If we get this, we have to remove // // // Mark as not accepting requests // SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING); // // Complete all pending requests // SerialKillPendingIrps(PDevObj); // // Decrement for this Irp itself // InterlockedDecrement(&pDevExt->PendingIRPCnt); // // Wait for any pending requests we raced on -- this decrement // is for our "placeholder". // pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt); if (pendingIRPs) { KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive, KernelMode, FALSE, NULL); } // // Remove us // SerialRemoveDevObj(PDevObj); // // Pass the irp down // PIrp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(PIrp); // // We do decrement here because we incremented on entry here. // IoCallDriver(pLowerDevObj, PIrp); return STATUS_SUCCESS; } default: break; } // switch (pIrpStack->MinorFunction) // // Pass to driver beneath us // IoSkipCurrentIrpStackLocation(PIrp); status = SerialIoCallDriver(pDevExt, pLowerDevObj, PIrp); return status; } UINT32 SerialReportMaxBaudRate(ULONG Bauds) /*++ Routine Description: This routine returns the max baud rate given a selection of rates Arguments: Bauds - Bit-encoded list of supported bauds Return Value: The max baud rate listed in Bauds --*/ { PAGED_CODE(); if (Bauds & SERIAL_BAUD_128K) { return (128U * 1024U); } if (Bauds & SERIAL_BAUD_115200) { return 115200U; } if (Bauds & SERIAL_BAUD_56K) { return (56U * 1024U); } if (Bauds & SERIAL_BAUD_57600) { return 57600U; } if (Bauds & SERIAL_BAUD_38400) { return 38400U; } if (Bauds & SERIAL_BAUD_19200) { return 19200U; } if (Bauds & SERIAL_BAUD_14400) { return 14400U; } if (Bauds & SERIAL_BAUD_9600) { return 9600U; } if (Bauds & SERIAL_BAUD_7200) { return 7200U; } if (Bauds & SERIAL_BAUD_4800) { return 4800U; } if (Bauds & SERIAL_BAUD_2400) { return 2400U; } if (Bauds & SERIAL_BAUD_1800) { return 1800U; } if (Bauds & SERIAL_BAUD_1200) { return 1200U; } if (Bauds & SERIAL_BAUD_600) { return 600U; } if (Bauds & SERIAL_BAUD_300) { return 300U; } if (Bauds & SERIAL_BAUD_150) { return 150U; } if (Bauds & SERIAL_BAUD_134_5) { return 135U; // Close enough } if (Bauds & SERIAL_BAUD_110) { return 110U; } if (Bauds & SERIAL_BAUD_075) { return 75U; } // // We're in bad shape // return 0; } NTSTATUS SerialFinishStartDevice(IN PDEVICE_OBJECT PDevObj, IN PCM_RESOURCE_LIST PResList, IN PCM_RESOURCE_LIST PTrResList, PSERIAL_USER_DATA PUserData) /*++ Routine Description: This routine does serial-specific procedures to start a device. It does this either for a legacy device detected by its registry entries, or for a PnP device after the start IRP has been sent down the stack. Arguments: PDevObj - Pointer to the devobj that is starting PResList - Pointer to the untranslated resources needed by this device PTrResList - Pointer to the translated resources needed by this device PUserData - Pointer to the user-specified resources/attributes Return Value: STATUS_SUCCESS on success, something else appropriate on failure --*/ { PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension; #if defined(NEC_98) // // This argument use at MACRO only. // PSERIAL_DEVICE_EXTENSION Extension = PDevObj->DeviceExtension; #else #endif //defined(NEC_98) NTSTATUS status; PCONFIG_DATA pConfig; HANDLE pnpKey; ULONG one = 1; PAGED_CODE(); // // See if this is a restart, and if so don't reallocate the world // if ((pDevExt->Flags & SERIAL_FLAGS_STOPPED) && (pDevExt->Flags & SERIAL_FLAGS_STARTED)) { SerialClearFlags(pDevExt, SERIAL_FLAGS_STOPPED); pDevExt->PNPState = SERIAL_PNP_RESTARTING; // // Re-init resource-related things in the extension // pDevExt->TopLevelOurIsr = NULL; pDevExt->TopLevelOurIsrContext = NULL; pDevExt->OriginalController = SerialPhysicalZero; pDevExt->OriginalInterruptStatus = SerialPhysicalZero; pDevExt->OurIsr = NULL; pDevExt->OurIsrContext = NULL; pDevExt->Controller = NULL; pDevExt->InterruptStatus = NULL; pDevExt->Interrupt = NULL; pDevExt->SpanOfController = 0; pDevExt->SpanOfInterruptStatus = 0; pDevExt->Vector = 0; pDevExt->Irql = 0; pDevExt->OriginalVector = 0; pDevExt->OriginalIrql = 0; pDevExt->AddressSpace = 0; pDevExt->BusNumber = 0; pDevExt->InterfaceType = 0; pDevExt->CIsrSw = NULL; ASSERT(PUserData == NULL); PUserData = ExAllocatePool(PagedPool, sizeof(SERIAL_USER_DATA)); if (PUserData == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(PUserData, sizeof(SERIAL_USER_DATA)); PUserData->DisablePort = FALSE; PUserData->UserClockRate = pDevExt->ClockRate; PUserData->TxFIFO = pDevExt->TxFifoAmount; PUserData->PermitShareDefault = pDevExt->PermitShare; // // Map betweeen trigger and amount // switch (pDevExt->RxFifoTrigger) { case SERIAL_1_BYTE_HIGH_WATER: PUserData->RxFIFO = 1; break; case SERIAL_4_BYTE_HIGH_WATER: PUserData->RxFIFO = 4; break; case SERIAL_8_BYTE_HIGH_WATER: PUserData->RxFIFO = 8; break; case SERIAL_14_BYTE_HIGH_WATER: PUserData->RxFIFO = 14; break; default: PUserData->RxFIFO = 1; } } else { // // Mark as serenumerable -- toss status because we can // still start without this key. // status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_WRITE, &pnpKey); if (NT_SUCCESS(status)) { ULONG powerPolicy = 0; // // Find out if we own power policy // SerialGetRegistryKeyValue(pnpKey, L"SerialRelinquishPowerPolicy", sizeof(L"SerialRelinquishPowerPolicy"), &powerPolicy, sizeof(ULONG)); pDevExt->OwnsPowerPolicy = powerPolicy ? FALSE : TRUE; ZwClose(pnpKey); } } // // Allocate the config record. // pConfig = ExAllocatePool (PagedPool, sizeof(CONFIG_DATA)); if (pConfig == NULL) { SerialLogError(pDevExt->DriverObject, NULL, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 37, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for the\n" "------ user configuration record\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialFinishStartDeviceError; } RtlZeroMemory(pConfig, sizeof(CONFIG_DATA)); // // Get the configuration info for the device. // status = SerialGetPortInfo(PDevObj, PResList, PTrResList, pConfig, PUserData); if (!NT_SUCCESS(status)) { goto SerialFinishStartDeviceError; } // // See if we are in the proper power state. // if (pDevExt->PowerState != PowerDeviceD0) { status = SerialGotoPowerState(pDevExt->Pdo, pDevExt, PowerDeviceD0); if (!NT_SUCCESS(status)) { goto SerialFinishStartDeviceError; } } // // Find and initialize the controller // status = SerialFindInitController(PDevObj, pConfig); if (!NT_SUCCESS(status)) { goto SerialFinishStartDeviceError; } // // The hardware that is set up to NOT interrupt, connect an interrupt. // // // If a device doesn't already have an interrupt and it has an isr then // we attempt to connect to the interrupt if it is not shareing with other // serial devices. If we fail to connect to an interrupt we will delete // this device. // if (pDevExt != NULL) { SerialDump(SERDIAG5, ("SERIAL: pDevExt: Interrupt %x\n" "------- OurIsr %x\n", pDevExt->Interrupt, pDevExt->OurIsr)); } else { SerialDump(SERERRORS, ("SERIAL: SerialFinishStartDevice got NULL " "pDevExt\n")); } if ((!pDevExt->Interrupt) && (pDevExt->OurIsr)) { SerialDump( SERDIAG5, ("SERIAL: About to connect to interrupt for port %wZ\n" "------- address of extension is %x\n", &pDevExt->DeviceName, pDevExt) ); SerialDump(SERDIAG5, ("SERIAL: IoConnectInterrupt Args:\n" "------- Interrupt %x\n" "------- OurIsr %x\n" "------- OurIsrContext %x\n" "------- NULL\n" "------- Vector %x\n" "------- Irql %x\n" "------- InterruptMode %x\n" "------- InterruptShareable %x\n" "------- ProcessorAffinity %x\n" "------- FALSE\n", &pDevExt->Interrupt, SerialCIsrSw, pDevExt->CIsrSw, pDevExt->Vector, pDevExt->Irql, pConfig->InterruptMode, pDevExt->InterruptShareable, pConfig->Affinity )); // // Do a just in time construction of the ISR switch. // pDevExt->CIsrSw->IsrFunc = pDevExt->OurIsr; pDevExt->CIsrSw->Context = pDevExt->OurIsrContext; status = IoConnectInterrupt(&pDevExt->Interrupt, SerialCIsrSw, pDevExt->CIsrSw, NULL, pDevExt->Vector, pDevExt->Irql, pDevExt->Irql, pConfig->InterruptMode, pDevExt->InterruptShareable, pConfig->Affinity, FALSE); if (!NT_SUCCESS(status)) { // // Hmmm, how'd that happen? Somebody either // didn't report their resources, or they // sneaked in since the last time I looked. // // Oh well, delete this device. // SerialDump(SERERRORS, ("SERIAL: Couldn't connect to interrupt for " "%wZ\n", &pDevExt->DeviceName)); SerialDump(SERERRORS, ("SERIAL: IoConnectInterrupt Args:\n" "------- Interrupt %x\n" "------- OurIsr %x\n" "------- OurIsrContext %x\n" "------- NULL\n" "------- Vector %x\n" "------- Irql %x\n" "------- InterruptMode %x\n" "------- InterruptShareable %x\n" "------- ProcessorAffinity %x\n" "------- FALSE\n", &pDevExt->Interrupt, SerialCIsrSw, pDevExt->CIsrSw, pDevExt->Vector, pDevExt->Irql, pConfig->InterruptMode, pDevExt->InterruptShareable, pConfig->Affinity )); SerialLogError(PDevObj->DriverObject, PDevObj, pDevExt->OriginalController, SerialPhysicalZero, 0, 0, 0, 1, status, SERIAL_UNREPORTED_IRQL_CONFLICT, pDevExt->DeviceName.Length + sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL); status = SERIAL_UNREPORTED_IRQL_CONFLICT; goto SerialFinishStartDeviceError; } } SerialDump(SERDIAG5, ("Connected interrupt %08X\n", pDevExt->Interrupt)); // // Add the PDevObj to the master list // InsertTailList(&SerialGlobals.AllDevObjs, &pDevExt->AllDevObjs); // // Reset the device. // // // While the device isn't open, disable all interrupts. // DISABLE_ALL_INTERRUPTS (pDevExt->Controller); if (pDevExt->Jensen) { WRITE_MODEM_CONTROL( pDevExt->Controller, (UCHAR)SERIAL_MCR_OUT2 ); } else { WRITE_MODEM_CONTROL( pDevExt->Controller, (UCHAR)0 ); } // // This should set up everything as it should be when // a device is to be opened. We do need to lower the // modem lines, and disable the recalcitrant fifo // so that it will show up if the user boots to dos. // KeSynchronizeExecution( pDevExt->Interrupt, SerialReset, pDevExt ); KeSynchronizeExecution( //Disables the fifo. pDevExt->Interrupt, SerialMarkClose, pDevExt ); KeSynchronizeExecution( pDevExt->Interrupt, SerialClrRTS, pDevExt ); KeSynchronizeExecution( pDevExt->Interrupt, SerialClrDTR, pDevExt ); if (pDevExt->PNPState == SERIAL_PNP_ADDED ) { // // Do the external naming now that the device is accessible. // status = SerialDoExternalNaming(pDevExt, pDevExt->DeviceObject-> DriverObject); if (!NT_SUCCESS(status)) { SerialDump (SERERRORS,("SERIAL: External Naming Failed - Status %x\n", status)); // // Allow the device to start anyhow // status = STATUS_SUCCESS; } } else { SerialDump(SERPNPPOWER, ("Not doing external naming -- state is %x\n", pDevExt->PNPState)); } SerialFinishStartDeviceError:; if (!NT_SUCCESS (status)) { SerialDump(SERDIAG1,("SERIAL: Cleaning up failed start\n")); // // Resources created by this routine will be cleaned up by the remove // if (pDevExt->PNPState == SERIAL_PNP_RESTARTING) { // // Kill all that lives and breathes -- we'll clean up the // rest on the impending remove // SerialKillPendingIrps(PDevObj); // // In fact, pretend we're removing so we don't take any // more irps // SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING); SerialClearFlags(pDevExt, SERIAL_FLAGS_STARTED); } } else { // SUCCESS // // Fill in WMI hardware data // pDevExt->WmiHwData.IrqNumber = pDevExt->Irql; pDevExt->WmiHwData.IrqLevel = pDevExt->Irql; pDevExt->WmiHwData.IrqVector = pDevExt->Vector; pDevExt->WmiHwData.IrqAffinityMask = pConfig->Affinity; pDevExt->WmiHwData.InterruptType = pConfig->InterruptMode == Latched ? SERIAL_WMI_INTTYPE_LATCHED : SERIAL_WMI_INTTYPE_LEVEL; pDevExt->WmiHwData.BaseIOAddress = (ULONG_PTR)pDevExt->Controller; // // Fill in WMI device state data (as defaults) // pDevExt->WmiCommData.BaudRate = pDevExt->CurrentBaud; pDevExt->WmiCommData.BitsPerByte = (pDevExt->LineControl & 0x03) + 5; pDevExt->WmiCommData.ParityCheckEnable = (pDevExt->LineControl & 0x08) ? TRUE : FALSE; switch (pDevExt->LineControl & SERIAL_PARITY_MASK) { case SERIAL_NONE_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; case SERIAL_ODD_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; break; case SERIAL_EVEN_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; break; #if defined(NEC_98) // // COM1 of PC-9800 series is not support MarkParity and SpaceParity. // #else case SERIAL_MARK_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; break; case SERIAL_SPACE_PARITY: pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; break; #endif //defined(NEC_98) default: ASSERTMSG(0, "SERIAL: Illegal Parity setting for WMI"); pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; } pDevExt->WmiCommData.StopBits = pDevExt->LineControl & SERIAL_STOP_MASK ? (pDevExt->WmiCommData.BitsPerByte == 5 ? SERIAL_WMI_STOP_1_5 : SERIAL_WMI_STOP_2) : SERIAL_WMI_STOP_1; pDevExt->WmiCommData.XoffCharacter = pDevExt->SpecialChars.XoffChar; pDevExt->WmiCommData.XoffXmitThreshold = pDevExt->HandFlow.XoffLimit; pDevExt->WmiCommData.XonCharacter = pDevExt->SpecialChars.XonChar; pDevExt->WmiCommData.XonXmitThreshold = pDevExt->HandFlow.XonLimit; pDevExt->WmiCommData.MaximumBaudRate = SerialReportMaxBaudRate(pDevExt->SupportedBauds); pDevExt->WmiCommData.MaximumOutputBufferSize = (UINT32)((ULONG)-1); pDevExt->WmiCommData.MaximumInputBufferSize = (UINT32)((ULONG)-1); pDevExt->WmiCommData.Support16BitMode = FALSE; pDevExt->WmiCommData.SupportDTRDSR = TRUE; pDevExt->WmiCommData.SupportIntervalTimeouts = TRUE; pDevExt->WmiCommData.SupportParityCheck = TRUE; pDevExt->WmiCommData.SupportRTSCTS = TRUE; pDevExt->WmiCommData.SupportXonXoff = TRUE; pDevExt->WmiCommData.SettableBaudRate = TRUE; pDevExt->WmiCommData.SettableDataBits = TRUE; pDevExt->WmiCommData.SettableFlowControl = TRUE; pDevExt->WmiCommData.SettableParity = TRUE; pDevExt->WmiCommData.SettableParityCheck = TRUE; pDevExt->WmiCommData.SettableStopBits = TRUE; pDevExt->WmiCommData.IsBusy = FALSE; // // Fill in wmi perf data (all zero's) // RtlZeroMemory(&pDevExt->WmiPerfData, sizeof(pDevExt->WmiPerfData)); if (pDevExt->PNPState == SERIAL_PNP_ADDED) { PULONG countSoFar = &IoGetConfigurationInformation()->SerialCount; (*countSoFar)++; // // Register for WMI // pDevExt->WmiLibInfo.GuidCount = sizeof(SerialWmiGuidList) / sizeof(WMIGUIDREGINFO); pDevExt->WmiLibInfo.GuidList = SerialWmiGuidList; ASSERT (pDevExt->WmiLibInfo.GuidCount == SERIAL_WMI_GUID_LIST_SIZE); pDevExt->WmiLibInfo.QueryWmiRegInfo = SerialQueryWmiRegInfo; pDevExt->WmiLibInfo.QueryWmiDataBlock = SerialQueryWmiDataBlock; pDevExt->WmiLibInfo.SetWmiDataBlock = SerialSetWmiDataBlock; pDevExt->WmiLibInfo.SetWmiDataItem = SerialSetWmiDataItem; pDevExt->WmiLibInfo.ExecuteWmiMethod = NULL; pDevExt->WmiLibInfo.WmiFunctionControl = NULL; IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_REGISTER); } if (pDevExt->PNPState == SERIAL_PNP_RESTARTING) { // // Release the stalled IRP's // SerialUnstallIrps(pDevExt); } pDevExt->PNPState = SERIAL_PNP_STARTED; SerialClearAccept(pDevExt, ~SERIAL_PNPACCEPT_OK); SerialSetFlags(pDevExt, SERIAL_FLAGS_STARTED); } if (pConfig) { ExFreePool (pConfig); } if ((PUserData != NULL) && (pDevExt->PNPState == SERIAL_PNP_RESTARTING)) { ExFreePool(PUserData); } SerialDump (SERTRACECALLS, ("SERIAL: leaving SerialFinishStartDevice\n")); return status; } NTSTATUS SerialStartDevice(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp) /*++ Routine Description: This routine first passes the start device Irp down the stack then it picks up the resources for the device, ititializes, puts it on any appropriate lists (i.e shared interrupt or interrupt status) and connects the interrupt. Arguments: PDevObj - Pointer to the device object for this device PIrp - Pointer to the IRP for the current request Return Value: Return status --*/ { PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp); NTSTATUS status = STATUS_NOT_IMPLEMENTED; PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension; PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject; PAGED_CODE(); SerialDump (SERTRACECALLS, ("SERIAL: entering SerialStartDevice\n")); // // Pass this down to the next device object // KeInitializeEvent(&pDevExt->SerialStartEvent, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(PIrp); IoSetCompletionRoutine(PIrp, SerialSyncCompletion, &pDevExt->SerialStartEvent, TRUE, TRUE, TRUE); status = IoCallDriver(pLowerDevObj, PIrp); // // Wait for lower drivers to be done with the Irp // if (status == STATUS_PENDING) { KeWaitForSingleObject (&pDevExt->SerialStartEvent, Executive, KernelMode, FALSE, NULL); status = PIrp->IoStatus.Status; } if (!NT_SUCCESS(status)) { SerialDump (SERERRORS, ("SERIAL: error with IoCallDriver %x\n", status)); return status; } // // Do the serial specific items to start the device // status = SerialFinishStartDevice(PDevObj, pIrpStack->Parameters.StartDevice .AllocatedResources, pIrpStack->Parameters.StartDevice .AllocatedResourcesTranslated, NULL); return status; } NTSTATUS SerialItemCallBack( IN PVOID Context, IN PUNICODE_STRING PathName, IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PKEY_VALUE_FULL_INFORMATION *BusInformation, IN CONFIGURATION_TYPE ControllerType, IN ULONG ControllerNumber, IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, IN CONFIGURATION_TYPE PeripheralType, IN ULONG PeripheralNumber, IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ) /*++ Routine Description: This routine is called to check if a particular item is present in the registry. Arguments: Context - Pointer to a boolean. PathName - unicode registry path. Not Used. BusType - Internal, Isa, ... BusNumber - Which bus if we are on a multibus system. BusInformation - Configuration information about the bus. Not Used. ControllerType - Controller type. ControllerNumber - Which controller if there is more than one controller in the system. ControllerInformation - Array of pointers to the three pieces of registry information. PeripheralType - Should be a peripheral. PeripheralNumber - Which peripheral - not used.. PeripheralInformation - Configuration information. Not Used. Return Value: STATUS_SUCCESS --*/ { PAGED_CODE(); *((BOOLEAN *)Context) = TRUE; return STATUS_SUCCESS; } NTSTATUS SerialControllerCallBack( IN PVOID Context, IN PUNICODE_STRING PathName, IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PKEY_VALUE_FULL_INFORMATION *BusInformation, IN CONFIGURATION_TYPE ControllerType, IN ULONG ControllerNumber, IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, IN CONFIGURATION_TYPE PeripheralType, IN ULONG PeripheralNumber, IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ) /*++ Routine Description: This routine is called to check if a particular item is present in the registry. Arguments: Context - Pointer to a boolean. PathName - unicode registry path. Not Used. BusType - Internal, Isa, ... BusNumber - Which bus if we are on a multibus system. BusInformation - Configuration information about the bus. Not Used. ControllerType - Controller type. ControllerNumber - Which controller if there is more than one controller in the system. ControllerInformation - Array of pointers to the three pieces of registry information. PeripheralType - Should be a peripheral. PeripheralNumber - Which peripheral - not used.. PeripheralInformation - Configuration information. Not Used. Return Value: STATUS_SUCCESS --*/ { PCM_FULL_RESOURCE_DESCRIPTOR controllerData; PSERIAL_PTR_CTX pContext = (PSERIAL_PTR_CTX)Context; ULONG i; PAGED_CODE(); if (ControllerInformation[IoQueryDeviceConfigurationData]->DataLength == 0) { pContext->isPointer = FALSE; return STATUS_SUCCESS; } controllerData = (PCM_FULL_RESOURCE_DESCRIPTOR) (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) + ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset); // // See if this is the exact port we are testing // for (i = 0; i < controllerData->PartialResourceList.Count; i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR partial = &controllerData->PartialResourceList.PartialDescriptors[i]; switch (partial->Type) { case CmResourceTypePort: if (partial->u.Port.Start.QuadPart == pContext->Port.QuadPart) { // // Pointer on same controller. Bail out. // pContext->isPointer = SERIAL_FOUNDPOINTER_PORT; return STATUS_SUCCESS; } case CmResourceTypeInterrupt: if (partial->u.Interrupt.Vector == pContext->Vector) { // // Pointer sharing this interrupt. Bail out. // pContext->isPointer = SERIAL_FOUNDPOINTER_VECTOR; return STATUS_SUCCESS; } default: break; } } pContext->isPointer = FALSE; return STATUS_SUCCESS; } NTSTATUS SerialGetPortInfo(IN PDEVICE_OBJECT PDevObj, IN PCM_RESOURCE_LIST PResList, IN PCM_RESOURCE_LIST PTrResList, OUT PCONFIG_DATA PConfig, IN PSERIAL_USER_DATA PUserData) /*++ Routine Description: This routine will get the configuration information and put it and the translated values into CONFIG_DATA structures. It first sets up with defaults and then queries the registry to see if the user has overridden these defaults; if this is a legacy multiport card, it uses the info in PUserData instead of groping the registry again. Arguments: PDevObj - Pointer to the device object. PResList - Pointer to the untranslated resources requested. PTrResList - Pointer to the translated resources requested. PConfig - Pointer to configuration info PUserData - Pointer to data discovered in the registry for legacy devices. Return Value: STATUS_SUCCESS if consistant configuration was found - otherwise. returns STATUS_SERIAL_NO_DEVICE_INITED. --*/ { PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension; PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject; NTSTATUS status = STATUS_NOT_IMPLEMENTED; CONFIGURATION_TYPE pointer = PointerPeripheral; CONFIGURATION_TYPE controllerType = SerialController; HANDLE keyHandle; ULONG count; ULONG i; INTERFACE_TYPE interfaceType; PCM_PARTIAL_RESOURCE_LIST pPartialResourceList, pPartialTrResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResourceDesc, pPartialTrResourceDesc; PCM_FULL_RESOURCE_DESCRIPTOR pFullResourceDesc = NULL, pFullTrResourceDesc = NULL; ULONG defaultInterruptMode; ULONG defaultAddressSpace; ULONG defaultInterfaceType; ULONG defaultClockRate; ULONG zero = 0; SERIAL_PTR_CTX foundPointerCtx; ULONG isMulti = 0; ULONG gotInt = 0; ULONG gotISR = 0; ULONG gotIO = 0; ULONG ioResIndex = 0; ULONG curIoIndex = 0; PAGED_CODE(); SerialDump(SERTRACECALLS, ("SERIAL: entering SerialGetPortInfo\n")); SerialDump(SERPNPPOWER, ("SERIAL: resource pointer is %x\n", PResList)); SerialDump(SERPNPPOWER, ("SERIAL: TR resource pointer is %x\n", PTrResList)); if ((PResList == NULL) || (PTrResList == NULL)) { // // This shouldn't happen in theory // ASSERT(PResList != NULL); ASSERT(PTrResList != NULL); // // This status is as appropriate as I can think of // return STATUS_INSUFFICIENT_RESOURCES; } // // Each resource list should have only one set of resources // ASSERT(PResList->Count == 1); ASSERT(PTrResList->Count == 1); // // See if this is a multiport device. This way we allow other // pseudo-serial devices with extra resources to specify another range // of I/O ports. If this is not a multiport, we only look at the first // range. If it is a multiport, we look at the first two ranges. // status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_WRITE, &keyHandle); if (!NT_SUCCESS(status)) { return status; } status = SerialGetRegistryKeyValue(keyHandle, L"MultiportDevice", sizeof(L"MultiportDevice"), &isMulti, sizeof (ULONG)); if (!NT_SUCCESS(status)) { isMulti = 0; } status = SerialGetRegistryKeyValue(keyHandle, L"SerialIoResourcesIndex", sizeof(L"SerialIoResourcesIndex"), &ioResIndex, sizeof(ULONG)); if (!NT_SUCCESS(status)) { ioResIndex = 0; } ZwClose(keyHandle); pFullResourceDesc = &PResList->List[0]; pFullTrResourceDesc = &PTrResList->List[0]; // // Ok, if we have a full resource descriptor. Let's take it apart. // if (pFullResourceDesc) { pPartialResourceList = &pFullResourceDesc->PartialResourceList; pPartialResourceDesc = pPartialResourceList->PartialDescriptors; count = pPartialResourceList->Count; // // Pull out the stuff that is in the full descriptor. // PConfig->InterfaceType = pFullResourceDesc->InterfaceType; PConfig->BusNumber = pFullResourceDesc->BusNumber; // // Now run through the partial resource descriptors looking for the port, // interrupt, and clock rate. // PConfig->ClockRate = 1843200; PConfig->InterruptStatus = SerialPhysicalZero; PConfig->SpanOfInterruptStatus = SERIAL_STATUS_LENGTH; for (i = 0; i < count; i++, pPartialResourceDesc++) { switch (pPartialResourceDesc->Type) { case CmResourceTypePort: { #if defined(NEC_98) // // NEC98 can't decide by length. // if (pPartialResourceDesc->u.Port.Start.LowPart == 0x130 && (gotIO == 0)) { // This is the serial register set gotIO = 1; PConfig->Controller = pPartialResourceDesc->u.Port.Start; PConfig->SpanOfController = SERIAL_REGISTER_SPAN; PConfig->AddressSpace = pPartialResourceDesc->Flags; } #else if (pPartialResourceDesc->u.Port.Length == SERIAL_STATUS_LENGTH && (gotISR == 0)) { // This is an ISR if (isMulti) { gotISR = 1; PConfig->InterruptStatus = pPartialResourceDesc->u.Port.Start; PConfig->SpanOfInterruptStatus = pPartialResourceDesc->u.Port.Length; PConfig->AddressSpace = pPartialResourceDesc->Flags; } } else { if (gotIO == 0) { // This is the serial register set if (curIoIndex == ioResIndex) { gotIO = 1; PConfig->Controller = pPartialResourceDesc->u.Port.Start; PConfig->SpanOfController = SERIAL_REGISTER_SPAN; PConfig->AddressSpace = pPartialResourceDesc->Flags; } else { curIoIndex++; } } } #endif //defined(NEC_98) break; } case CmResourceTypeInterrupt: { if (gotInt == 0) { gotInt = 1; PConfig->OriginalIrql = pPartialResourceDesc->u.Interrupt.Level; PConfig->OriginalVector = pPartialResourceDesc->u.Interrupt.Vector; PConfig->Affinity = pPartialResourceDesc->u.Interrupt.Affinity; if (pPartialResourceDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) { PConfig->InterruptMode = Latched; } else { PConfig->InterruptMode = LevelSensitive; } } break; } case CmResourceTypeDeviceSpecific: { PCM_SERIAL_DEVICE_DATA sDeviceData; sDeviceData = (PCM_SERIAL_DEVICE_DATA)(pPartialResourceDesc + 1); PConfig->ClockRate = sDeviceData->BaudClock; break; } default: { break; } } // switch (pPartialResourceDesc->Type) } // for (i = 0; i < count; i++, pPartialResourceDesc++) } // if (pFullResourceDesc) // // Do the same for the translated resources // gotInt = 0; gotISR = 0; gotIO = 0; curIoIndex = 0; if (pFullTrResourceDesc) { pPartialTrResourceList = &pFullTrResourceDesc->PartialResourceList; pPartialTrResourceDesc = pPartialTrResourceList->PartialDescriptors; count = pPartialTrResourceList->Count; // // Reload PConfig with the translated values for later use // PConfig->InterfaceType = pFullTrResourceDesc->InterfaceType; PConfig->BusNumber = pFullTrResourceDesc->BusNumber; PConfig->TrInterruptStatus = SerialPhysicalZero; for (i = 0; i < count; i++, pPartialTrResourceDesc++) { switch (pPartialTrResourceDesc->Type) { case CmResourceTypePort: { #if defined(NEC_98) // // NEC98 can't decide by length. // if (pPartialTrResourceDesc->u.Port.Start.LowPart == 0x130 && (gotIO == 0)) { // This is the serial register set gotIO = 1; PConfig->TrController = pPartialTrResourceDesc->u.Port.Start; PConfig->AddressSpace = pPartialTrResourceDesc->Flags; } #else if (pPartialTrResourceDesc->u.Port.Length == SERIAL_STATUS_LENGTH && (gotISR == 0)) { // This is an ISR if (isMulti) { gotISR = 1; PConfig->TrInterruptStatus = pPartialTrResourceDesc ->u.Port.Start; } } else { // This is the serial register set if (gotIO == 0) { if (curIoIndex == ioResIndex) { gotIO = 1; PConfig->TrController = pPartialTrResourceDesc->u.Port.Start; PConfig->AddressSpace = pPartialTrResourceDesc->Flags; } else { curIoIndex++; } } } #endif //defined(NEC_98) break; } case CmResourceTypeInterrupt: { if (gotInt == 0) { gotInt = 1; PConfig->TrVector = pPartialTrResourceDesc->u.Interrupt.Vector; PConfig->TrIrql = pPartialTrResourceDesc->u.Interrupt.Level; PConfig->Affinity = pPartialTrResourceDesc->u.Interrupt.Affinity; } break; } default: { break; } } // switch (pPartialTrResourceDesc->Type) } // for (i = 0; i < count; i++, pPartialTrResourceDesc++) } // if (pFullTrResourceDesc) // // Initialize a config data structure with default values for those that // may not already be initialized. // PConfig->PortIndex = 0; PConfig->DisablePort = 0; PConfig->PermitSystemWideShare = FALSE; PConfig->MaskInverted = 0; PConfig->Indexed = 0; PConfig->ForceFifoEnable = driverDefaults.ForceFifoEnableDefault; PConfig->RxFIFO = driverDefaults.RxFIFODefault; PConfig->TxFIFO = driverDefaults.TxFIFODefault; PConfig->PermitShare = driverDefaults.PermitShareDefault; PConfig->LogFifo = driverDefaults.LogFifoDefault; PConfig->Jensen = driverDefaults.JensenDetected; // // Query the registry to look for the first bus on // the system (that isn't the internal bus - we assume // that the firmware code knows about those ports). We // will use that as the default bus if no bustype or bus // number is specified in the "user" configuration records. // defaultInterfaceType = (ULONG)Isa; defaultClockRate = 1843200; for (interfaceType = 0; interfaceType < MaximumInterfaceType; interfaceType++ ) { ULONG busZero = 0; BOOLEAN foundOne = FALSE; if (interfaceType != Internal) { IoQueryDeviceDescription( &interfaceType, &busZero, NULL, NULL, NULL, NULL, SerialItemCallBack, &foundOne ); if (foundOne) { defaultInterfaceType = (ULONG)interfaceType; if (defaultInterfaceType == MicroChannel) { defaultInterruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; } break; } } // if (interfaceType != Internal) } // for (interfaceType = 0 // // Get any user data associated with the port now and override the // values passed in if applicable. If this a legacy device, this // is where we may actually get the parameters. // // // Open the "Device Parameters" section of registry for this device object. // If PUserData is NULL, this is PnP enumerated and we need to check, // otherwise we are doing a legacy device and have the info already. // if (PUserData == NULL) { status = IoOpenDeviceRegistryKey (pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (!NT_SUCCESS(status)) { SerialDump(SERERRORS, ("SERIAL: IoOpenDeviceRegistryKey failed - %x " "\n", status)); goto PortInfoCleanUp; } else { status = SerialGetRegistryKeyValue (keyHandle, L"DisablePort", sizeof(L"DisablePort"), &PConfig->DisablePort, sizeof (ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"ForceFifoEnable", sizeof(L"ForceFifoEnable"), &PConfig->ForceFifoEnable, sizeof (ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"RxFIFO", sizeof(L"RxFIFO"), &PConfig->RxFIFO, sizeof (ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"TxFIFO", sizeof(L"TxFIFO"), &PConfig->TxFIFO, sizeof (ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"MaskInverted", sizeof(L"MaskInverted"), &PConfig->MaskInverted, sizeof (ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"Share System Interrupt", sizeof(L"Share System Interrupt"), &PConfig->PermitShare, sizeof (ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"PortIndex", sizeof(L"PortIndex"), &PConfig->PortIndex, sizeof (ULONG)); status = SerialGetRegistryKeyValue(keyHandle, L"Indexed", sizeof(L"Indexed"), &PConfig->Indexed, sizeof(ULONG)); status = SerialGetRegistryKeyValue (keyHandle, L"ClockRate", sizeof(L"ClockRate"), &PConfig->ClockRate, sizeof (ULONG)); if (!NT_SUCCESS(status)) { PConfig->ClockRate = defaultClockRate; } ZwClose (keyHandle); } } else { // // This was a legacy device, either use a driver default or copy over // the user-specified values. // ULONG badValue = (ULONG)-1; PConfig->DisablePort = (PUserData->DisablePort == badValue) ? 0 : PUserData->DisablePort; PConfig->ForceFifoEnable = (PUserData->ForceFIFOEnable == badValue) ? PUserData->ForceFIFOEnableDefault : PUserData->ForceFIFOEnable; PConfig->RxFIFO = (PUserData->RxFIFO == badValue) ? PUserData->RxFIFODefault : PUserData->RxFIFO; PConfig->Indexed = (PUserData->UserIndexed == badValue) ? 0 : PUserData->UserIndexed; PConfig->TxFIFO = (PUserData->TxFIFO == badValue) ? PUserData->TxFIFODefault : PUserData->TxFIFO; PConfig->MaskInverted = (PUserData->MaskInverted == badValue) ? 0 : PUserData->MaskInverted; PConfig->ClockRate = (PUserData->UserClockRate == badValue) ? defaultClockRate : PUserData->UserClockRate; PConfig->PermitShare = PUserData->PermitShareDefault; PConfig->PortIndex = PUserData->UserPortIndex; } // // Do some error checking on the configuration info we have. // // Make sure that the interrupt is non zero (which we defaulted // it to). // // Make sure that the portaddress is non zero (which we defaulted // it to). // // Make sure that the DosDevices is not NULL (which we defaulted // it to). // // We need to make sure that if an interrupt status // was specified, that a port index was also specfied, // and if so that the port index is <= maximum ports // on a board. // // We should also validate that the bus type and number // are correct. // // We will also validate that the interrupt mode makes // sense for the bus. // if (!PConfig->Controller.LowPart) { // // Ehhhh! Lose Game. // SerialLogError( PDevObj->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 58, STATUS_SUCCESS, SERIAL_INVALID_USER_CONFIG, 0, NULL, sizeof(L"PortAddress") + sizeof(WCHAR), L"PortAddress" ); SerialDump (SERERRORS, ("SERIAL: Bogus port address %x\n", PConfig->Controller.LowPart)); status = SERIAL_INVALID_USER_CONFIG; goto PortInfoCleanUp; } if (!PConfig->OriginalVector) { // // Ehhhh! Lose Game. // SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 59, STATUS_SUCCESS, SERIAL_INVALID_USER_CONFIG, pDevExt->DeviceName.Length, pDevExt->DeviceName.Buffer, sizeof (L"Interrupt"), L"Interrupt" ); SerialDump (SERERRORS,("SERIAL: Bogus vector %x\n", PConfig->OriginalVector)); status = SERIAL_INVALID_USER_CONFIG; goto PortInfoCleanUp; } if (PConfig->InterruptStatus.LowPart != 0) { if (PConfig->PortIndex == MAXULONG) { // // Ehhhh! Lose Game. // SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 30, STATUS_SUCCESS, SERIAL_INVALID_PORT_INDEX, 0, NULL, 0, NULL ); SerialDump (SERERRORS, ("SERIAL: Bogus port index %x\n", PConfig->PortIndex)); status = SERIAL_INVALID_PORT_INDEX; goto PortInfoCleanUp; } else if (!PConfig->PortIndex) { // // So sorry, you must have a non-zero port index. // SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 31, STATUS_SUCCESS, SERIAL_INVALID_PORT_INDEX, 0, NULL, 0, NULL ); SerialDump( SERERRORS, ("SERIAL: Port index must be > 0 for any\n" "------- port on a multiport card: %x\n", PConfig->PortIndex) ); status = SERIAL_INVALID_PORT_INDEX; goto PortInfoCleanUp; } else { if (PConfig->Indexed) { if (PConfig->PortIndex > SERIAL_MAX_PORTS_INDEXED) { SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 32, STATUS_SUCCESS, SERIAL_PORT_INDEX_TOO_HIGH, 0, NULL, 0, NULL ); SerialDump (SERERRORS, ("SERIAL: port index to large %x\n", PConfig->PortIndex)); status = SERIAL_PORT_INDEX_TOO_HIGH; goto PortInfoCleanUp; } } else { if (PConfig->PortIndex > SERIAL_MAX_PORTS_NONINDEXED) { SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 33, STATUS_SUCCESS, SERIAL_PORT_INDEX_TOO_HIGH, 0, NULL, 0, NULL ); SerialDump (SERERRORS, ("SERIAL: port index to large %x\n", PConfig->PortIndex)); status = SERIAL_PORT_INDEX_TOO_HIGH; goto PortInfoCleanUp; } } } // else (if !PConfig->PortIndex) } // if (PConfig->InterruptStatus != 0) // // We don't want to cause the hal to have a bad day, // so let's check the interface type and bus number. // // We only need to check the registry if they aren't // equal to the defaults. // if (PConfig->BusNumber != 0) { BOOLEAN foundIt; if (PConfig->InterfaceType >= MaximumInterfaceType) { // // Ehhhh! Lose Game. // SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 34, STATUS_SUCCESS, SERIAL_UNKNOWN_BUS, 0, NULL, 0, NULL ); SerialDump (SERERRORS, ("SERIAL: Invalid Bus type %x\n", PConfig->BusNumber)); status = SERIAL_UNKNOWN_BUS; goto PortInfoCleanUp; } IoQueryDeviceDescription( (INTERFACE_TYPE *)&PConfig->InterfaceType, &zero, NULL, NULL, NULL, NULL, SerialItemCallBack, &foundIt ); if (!foundIt) { SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 35, STATUS_SUCCESS, SERIAL_BUS_NOT_PRESENT, 0, NULL, 0, NULL ); SerialDump( SERERRORS, ("SERIAL: There aren't that many of those\n" "------- busses on this system,%x\n", PConfig->BusNumber) ); status = SERIAL_BUS_NOT_PRESENT; goto PortInfoCleanUp; } } // if (PConfig->BusNumber != 0) if ((PConfig->InterfaceType == MicroChannel) && (PConfig->InterruptMode == CM_RESOURCE_INTERRUPT_LATCHED)) { SerialLogError( pDevExt->DriverObject, NULL, PConfig->Controller, SerialPhysicalZero, 0, 0, 0, 36, STATUS_SUCCESS, SERIAL_BUS_INTERRUPT_CONFLICT, 0, NULL, 0, NULL ); SerialDump( SERERRORS, ("SERIAL: Latched interrupts and MicroChannel\n" "------- busses don't mix\n") ); status = SERIAL_BUS_INTERRUPT_CONFLICT; goto PortInfoCleanUp; } status = STATUS_SUCCESS; // // Dump out the port configuration. // SerialDump(SERDIAG1, ("SERIAL: Com Port address: %x\n", PConfig->Controller.LowPart)); SerialDump(SERDIAG1, ("SERIAL: Com Interrupt Status: %x\n", PConfig->InterruptStatus)); SerialDump(SERDIAG1, ("SERIAL: Com Port Index: %x\n", PConfig->PortIndex)); SerialDump(SERDIAG1, ("SERIAL: Com Port ClockRate: %x\n", PConfig->ClockRate)); SerialDump(SERDIAG1, ("SERIAL: Com Port BusNumber: %x\n", PConfig->BusNumber)); SerialDump(SERDIAG1, ("SERIAL: Com AddressSpace: %x\n", PConfig->AddressSpace)); SerialDump(SERDIAG1, ("SERIAL: Com InterruptMode: %x\n", PConfig->InterruptMode)); SerialDump(SERDIAG1, ("SERIAL: Com InterfaceType: %x\n", PConfig->InterfaceType)); SerialDump(SERDIAG1, ("SERIAL: Com OriginalVector: %x\n", PConfig->OriginalVector)); SerialDump(SERDIAG1, ("SERIAL: Com OriginalIrql: %x\n", PConfig->OriginalIrql)); SerialDump(SERDIAG1, ("SERIAL: Com Indexed: %x\n", PConfig->Indexed)); PortInfoCleanUp:; return status; } NTSTATUS SerialDoExternalNaming(IN PSERIAL_DEVICE_EXTENSION PDevExt, IN PDRIVER_OBJECT PDrvObj) /*++ Routine Description: This routine will be used to create a symbolic link to the driver name in the given object directory. It will also create an entry in the device map for this device - IF we could create the symbolic link. Arguments: Extension - Pointer to the device extension. Return Value: None. --*/ { NTSTATUS status = STATUS_SUCCESS; HANDLE keyHandle; WCHAR *pRegName = NULL; UNICODE_STRING linkName; PDEVICE_OBJECT pLowerDevObj, pDevObj; ULONG bufLen; PAGED_CODE(); pDevObj = PDevExt->DeviceObject; pLowerDevObj = PDevExt->LowerDeviceObject; status = IoOpenDeviceRegistryKey(PDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); // // Check to see if we are allowed to do external naming; if not, // then we just return success // if (status != STATUS_SUCCESS) { return status; } SerialGetRegistryKeyValue(keyHandle, L"SerialSkipExternalNaming", sizeof(L"SerialSkipExternalNaming"), &PDevExt->SkipNaming, sizeof(ULONG)); if (PDevExt->SkipNaming) { ZwClose(keyHandle); return STATUS_SUCCESS; } RtlZeroMemory(&linkName, sizeof(UNICODE_STRING)); linkName.MaximumLength = SYMBOLIC_NAME_LENGTH*sizeof(WCHAR); linkName.Buffer = ExAllocatePool(PagedPool, linkName.MaximumLength + sizeof(WCHAR)); if (linkName.Buffer == NULL) { SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for device name" "\n")); status = STATUS_INSUFFICIENT_RESOURCES; ZwClose(keyHandle); goto SerialDoExternalNamingError; } RtlZeroMemory(linkName.Buffer, linkName.MaximumLength + sizeof(WCHAR)); pRegName = ExAllocatePool(PagedPool, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR) + sizeof(WCHAR)); if (pRegName == NULL) { SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for buffer" "\n")); status = STATUS_INSUFFICIENT_RESOURCES; ZwClose(keyHandle); goto SerialDoExternalNamingError; } // // Fetch PortName which contains the suggested REG_SZ symbolic name. // status = SerialGetRegistryKeyValue(keyHandle, L"PortName", sizeof(L"PortName"), pRegName, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR)); if (!NT_SUCCESS(status)) { // // This is for PCMCIA which currently puts the name under Identifier. // status = SerialGetRegistryKeyValue(keyHandle, L"Identifier", sizeof(L"Identifier"), pRegName, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR)); if (!NT_SUCCESS(status)) { // // Hmm. Either we have to pick a name or bail... // // ...we will bail. // SerialDump(SERERRORS, ("SERIAL: Getting PortName/Identifier failed - " "%x\n", status)); ZwClose (keyHandle); goto SerialDoExternalNamingError; } } ZwClose (keyHandle); bufLen = wcslen(pRegName) * sizeof(WCHAR) + sizeof(UNICODE_NULL); PDevExt->WmiIdentifier.Buffer = ExAllocatePool(PagedPool, bufLen); if (PDevExt->WmiIdentifier.Buffer == NULL) { SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for WMI name\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialDoExternalNamingError; } RtlZeroMemory(PDevExt->WmiIdentifier.Buffer, bufLen); PDevExt->WmiIdentifier.Length = 0; PDevExt->WmiIdentifier.MaximumLength = (USHORT)bufLen - sizeof(WCHAR); RtlAppendUnicodeToString(&PDevExt->WmiIdentifier, pRegName); // // Create the "\\DosDevices\\" string // RtlAppendUnicodeToString(&linkName, L"\\"); RtlAppendUnicodeToString(&linkName, DEFAULT_DIRECTORY); RtlAppendUnicodeToString(&linkName, L"\\"); RtlAppendUnicodeToString(&linkName, pRegName); // // Allocate Pool and save the symbolic link name in the device extension. // PDevExt->SymbolicLinkName.MaximumLength = linkName.Length + sizeof(WCHAR); PDevExt->SymbolicLinkName.Buffer = ExAllocatePool(PagedPool, PDevExt->SymbolicLinkName.MaximumLength); if (!PDevExt->SymbolicLinkName.Buffer) { SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for symbolic link name\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialDoExternalNamingError; } // // Zero fill it. // RtlZeroMemory(PDevExt->SymbolicLinkName.Buffer, PDevExt->SymbolicLinkName.MaximumLength); RtlAppendUnicodeStringToString(&PDevExt->SymbolicLinkName, &linkName); PDevExt->DosName.Buffer = ExAllocatePool(PagedPool, 64 + sizeof(WCHAR)); if (!PDevExt->DosName.Buffer) { SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't allocate memory for Dos name\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto SerialDoExternalNamingError; } PDevExt->DosName.MaximumLength = 64 + sizeof(WCHAR); // // Zero fill it. // PDevExt->DosName.Length = 0; RtlZeroMemory(PDevExt->DosName.Buffer, PDevExt->DosName.MaximumLength); RtlAppendUnicodeToString(&PDevExt->DosName, pRegName); RtlZeroMemory(((PUCHAR)(&PDevExt->DosName.Buffer[0])) + PDevExt->DosName.Length, sizeof(WCHAR)); SerialDump(SERDIAG1, ("SERIAL: DosName is %wZ\n", &PDevExt->DosName)); // status = IoCreateSymbolicLink (&PDevExt->SymbolicLinkName, &PDevExt->DeviceName); if (!NT_SUCCESS(status)) { // // Oh well, couldn't create the symbolic link. No point // in trying to create the device map entry. // SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 52, status, SERIAL_NO_SYMLINK_CREATED, PDevExt->DeviceName.Length + sizeof(WCHAR), PDevExt->DeviceName.Buffer, 0, NULL); SerialDump( SERERRORS, ("SERIAL: Couldn't create the symbolic link\n" "------- for port %wZ\n", &PDevExt->DeviceName) ); goto SerialDoExternalNamingError; } PDevExt->CreatedSymbolicLink = TRUE; status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"SERIALCOMM", PDevExt->DeviceName.Buffer, REG_SZ, PDevExt->DosName.Buffer, PDevExt->DosName.Length + sizeof(WCHAR)); if (!NT_SUCCESS(status)) { SerialLogError(PDrvObj, pDevObj, SerialPhysicalZero, SerialPhysicalZero, 0, 0, 0, 53, status, SERIAL_NO_DEVICE_MAP_CREATED, PDevExt->DeviceName.Length + sizeof(WCHAR), PDevExt->DeviceName.Buffer, 0, NULL); SerialDump(SERERRORS, ("SERIAL: Couldn't create the device map entry\n" "------- for port %wZ\n", &PDevExt->DeviceName)); goto SerialDoExternalNamingError; } PDevExt->CreatedSerialCommEntry = TRUE; // // Make the device visible via a device association as well. // The reference string is the eight digit device index // status = IoRegisterDeviceInterface(PDevExt->Pdo, (LPGUID)&GUID_CLASS_COMPORT, NULL, &PDevExt->DeviceClassSymbolicName); if (!NT_SUCCESS(status)) { SerialDump(SERERRORS, ("SERIAL: Couldn't register class association\n" "------- for port %wZ\n", &PDevExt->DeviceName)); PDevExt->DeviceClassSymbolicName.Buffer = NULL; goto SerialDoExternalNamingError; } // // Now set the symbolic link for the association // status = IoSetDeviceInterfaceState(&PDevExt->DeviceClassSymbolicName, TRUE); if (!NT_SUCCESS(status)) { SerialDump(SERERRORS, ("SERIAL: Couldn't set class association\n" "------- for port %wZ\n", &PDevExt->DeviceName)); } SerialDoExternalNamingError:; // // Clean up error conditions // if (!NT_SUCCESS(status)) { if (PDevExt->DosName.Buffer != NULL) { ExFreePool(PDevExt->DosName.Buffer); PDevExt->DosName.Buffer = NULL; } if (PDevExt->CreatedSymbolicLink == TRUE) { IoDeleteSymbolicLink(&PDevExt->SymbolicLinkName); PDevExt->CreatedSymbolicLink = FALSE; } if (PDevExt->SymbolicLinkName.Buffer != NULL) { ExFreePool(PDevExt->SymbolicLinkName.Buffer); PDevExt->SymbolicLinkName.Buffer = NULL; } if (PDevExt->DeviceName.Buffer != NULL) { RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, PDevExt->DeviceName.Buffer); } if (PDevExt->DeviceClassSymbolicName.Buffer) { IoSetDeviceInterfaceState (&PDevExt->DeviceClassSymbolicName, FALSE); } if (PDevExt->WmiIdentifier.Buffer != NULL) { ExFreePool(PDevExt->WmiIdentifier.Buffer); PDevExt->WmiIdentifier.Buffer = NULL; } } // // Always clean up our temp buffers. // if (linkName.Buffer != NULL) { ExFreePool(linkName.Buffer); } if (pRegName != NULL) { ExFreePool(pRegName); } return status; } VOID SerialUndoExternalNaming(IN PSERIAL_DEVICE_EXTENSION Extension) /*++ Routine Description: This routine will be used to delete a symbolic link to the driver name in the given object directory. It will also delete an entry in the device map for this device if the symbolic link had been created. Arguments: Extension - Pointer to the device extension. Return Value: None. --*/ { NTSTATUS status; PAGED_CODE(); SerialDump( SERDIAG3, ("SERIAL: In SerialUndoExternalNaming for\n" "------- extension: %x of port %wZ\n", Extension,&Extension->DeviceName) ); // // Maybe there is nothing for us to do // if (Extension->SkipNaming) { return; } // // We're cleaning up here. One reason we're cleaning up // is that we couldn't allocate space for the directory // name or the symbolic link. // if (Extension->SymbolicLinkName.Buffer && Extension->CreatedSymbolicLink) { if (Extension->DeviceClassSymbolicName.Buffer) { status = IoSetDeviceInterfaceState (&Extension-> DeviceClassSymbolicName, FALSE); // // IoRegisterDeviceClassInterface() allocated this string for us, // and we no longer need it. // ExFreePool( Extension->DeviceClassSymbolicName.Buffer ); } IoDeleteSymbolicLink (&Extension->SymbolicLinkName); } if (Extension->WmiIdentifier.Buffer) { ExFreePool(Extension->WmiIdentifier.Buffer); Extension->WmiIdentifier.MaximumLength = Extension->WmiIdentifier.Length = 0; Extension->WmiIdentifier.Buffer = NULL; } // // We're cleaning up here. One reason we're cleaning up // is that we couldn't allocate space for the NtNameOfPort. // if ((Extension->DeviceName.Buffer != NULL) && Extension->CreatedSerialCommEntry) { status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, Extension->DeviceName.Buffer); if (!NT_SUCCESS(status)) { SerialLogError( Extension->DeviceObject->DriverObject, Extension->DeviceObject, Extension->OriginalController, SerialPhysicalZero, 0, 0, 0, 55, status, SERIAL_NO_DEVICE_MAP_DELETED, Extension->DeviceName.Length+sizeof(WCHAR), Extension->DeviceName.Buffer, 0, NULL ); SerialDump( SERERRORS, ("SERIAL: Couldn't delete value entry %wZ\n", &Extension->DeviceName) ); } } }