📄 ul_wdpnp.c
字号:
/******************************************************************* uLan Communication - uL_DRV - multiplatform uLan driver ul_wdpnp.c - Windows WDM PnP events processing code (C) Copyright 1996-2004 by Pavel Pisa - project originator http://cmp.felk.cvut.cz/~pisa (C) Copyright 1996-2004 PiKRON Ltd. http://www.pikron.com (C) Copyright 2002-2004 Petr Smolik The uLan driver project can be used and distributed in compliance with any of next licenses - GPL - GNU Public License See file COPYING for details. - LGPL - Lesser GNU Public License - MPL - Mozilla Public License - and other licenses added by project originator Code can be modified and re-distributed under any combination of the above listed licenses. If contributor does not agree with some of the licenses, he/she can delete appropriate line. WARNING: if you delete all lines, you are not allowed to distribute code or sources in any form. *******************************************************************///#include <initguid.h>////{3EF4F782-AF00-11d5-87B2-00D0595444D7}//DEFINE_GUID(GUID_ULAN_WDM_DRIVER1, // 0x3ef4f782, 0xaf00, 0x11d5, 0x87, 0xb2, 0x0, 0xd0, 0x59, 0x54, 0x44, 0xd7);VOID PrintState(PULAN_DEVICE_EXTENSION devExt);VOID PrintCapabilityInfo(PDEVICE_CAPABILITIES Capabilities);VOID RequestIncrement(PULAN_DEVICE_EXTENSION devExt);VOID RequestDecrement(PULAN_DEVICE_EXTENSION devExt);VOID WaitForStop(PULAN_DEVICE_EXTENSION devExt);VOID WaitForRemove(PULAN_DEVICE_EXTENSION devExt);VOID ClearQueues(PULAN_DEVICE_EXTENSION devExt){/*stub*/};VOID ProcessQueuedRequests(PULAN_DEVICE_EXTENSION devExt){/*stub*/};NTSTATUS StartDevice (IN PULAN_DEVICE_EXTENSION devExt,IN PIO_STACK_LOCATION IrpSp);NTSTATUS StartUSBDevice (IN PULAN_DEVICE_EXTENSION devExt,IN PIO_STACK_LOCATION IrpSp);NTSTATUS CanStopDevice(PULAN_DEVICE_EXTENSION devExt, PIRP Irp);NTSTATUS CanRemoveDevice(PULAN_DEVICE_EXTENSION devExt, PIRP Irp);static NTSTATUS PnpComplete (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context);static PSTR pnpMinorCodes[] = { "IRP_MN_START_DEVICE", "IRP_MN_QUERY_REMOVE_DEVICE", "IRP_MN_REMOVE_DEVICE", "IRP_MN_CANCEL_REMOVE_DEVICE", "IRP_MN_STOP_DEVICE", "IRP_MN_QUERY_STOP_DEVICE", "IRP_MN_CANCEL_STOP_DEVICE", "IRP_MN_QUERY_DEVICE_RELATIONS", "IRP_MN_QUERY_INTERFACE", "IRP_MN_QUERY_CAPABILITIES", "IRP_MN_QUERY_RESOURCES", "IRP_MN_QUERY_RESOURCE_REQUIREMENTS", "IRP_MN_QUERY_DEVICE_TEXT", "IRP_MN_FILTER_RESOURCE_REQUIREMENTS", "***** FUNCTION 0x0e", "IRP_MN_READ_CONFIG", "IRP_MN_WRITE_CONFIG", "IRP_MN_EJECT", "IRP_MN_SET_LOCK", "IRP_MN_QUERY_ID", "IRP_MN_QUERY_PNP_DEVICE_STATE", "IRP_MN_QUERY_BUS_INFORMATION", "IRP_MN_DEVICE_USAGE_NOTIFICATION", "IRP_MN_SURPRISE_REMOVAL", "IRP_MN_QUERY_LEGACY_BUS_INFORMATION"};static PSTR SystemPowerStateString[] = {"PowerSystemUnspecified","PowerSystemWorking","PowerSystemSleeping1","PowerSystemSleeping2","PowerSystemSleeping3","PowerSystemHibernate","PowerSystemShutdown","PowerSystemMaximum"};static PSTR DevicePowerStateString[] = {"PowerDeviceUnspecified","PowerDeviceD0","PowerDeviceD1","PowerDeviceD2","PowerDeviceD3","PowerDeviceMaximum"};#if DBGVOID PrintResourceList(PCM_RESOURCE_LIST);VOID PrintConfig(PPCI_COMMON_CONFIG configInfo);#endifint uLanInstanceCounter=0;/////////////////////////////////////////////////////////////////////////////////// AddDevice//// We are called at this entry point by the Plug and Play Manager// to add a Functional Device Object for a Physical Device Object.// Note that we may NOT access the device in this routine, as the// Plug and Play Manager has not yet given us any hardware resoruces.// We get these hardware resources via the IRP_MJ_PNP IRP with// a minor function IRP_MN_START_DEVICE.////// INPUTS://// DriverObj - Address of our DRIVER_OBJECT.//// OUTPUTS://// None.//// RETURNS://// None.//// IRQL://// This routine is called at IRQL_PASSIVE_LEVEL.//// NOTES://///////////////////////////////////////////////////////////////////////////////NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject){ PULAN_DEVICE_EXTENSION devExt; PDEVICE_OBJECT functionalDeviceObject; UNICODE_STRING devName; UNICODE_STRING linkName; UNICODE_STRING tempName; NTSTATUS code = STATUS_SUCCESS; LOG_FILEIO("uLan: AddDevice: entered for instance %d\n",uLanInstanceCounter); LOG_FILEIO("uLan: AddDevice: PDO = 0x%0x\n", PhysicalDeviceObject); // Only up to 10 instances are handled if(uLanInstanceCounter>=10){ uLan_DbgPrint("uLan: Too many instances, no more added\n"); return(STATUS_UNSUCCESSFUL); } // // Initialize the UNICODE device name. This will be the "native NT" name // for our device. // RtlInitUnicodeString(&tempName,NT_DEVICE_NAME); code=MyAllocUnicodeString(&devName, &tempName, tempName.Length+4); if(uLanInstanceCounter){ devName.Buffer[devName.Length/2]='0'+uLanInstanceCounter; devName.Length+=2; } uLan_DbgPrint("uLan: Ready to Call IoCreateDevice for DevName=\"%ws\" Len=%d\n", devName.Buffer,devName.Length); // // Ask the I/O Manager to create the device object and // device extension. In PnP terms, this is the FUNCTIONAL // Device Object (FDO) for the device. // code = IoCreateDevice(DriverObject, sizeof(ULAN_DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &functionalDeviceObject); if(!NT_SUCCESS(code)) { if(devName.Buffer) ExFreePool(devName.Buffer);; uLan_DbgPrint("uLan: IoCreateDevice failed. Dev=%ws Status = 0x%0x\n", devName.Buffer,code); return(STATUS_UNSUCCESSFUL); } // // Get a pointer to our device extension // devExt = (PULAN_DEVICE_EXTENSION)functionalDeviceObject->DeviceExtension; LOG_FILEIO("uLan: AddDevice: FDO = 0x%0x\n", functionalDeviceObject); // // Zero out the device extension. While not strictly necessary // (the documentation says the device extension is zeroed) it's // better to be safe. // RtlZeroMemory(devExt, sizeof(ULAN_DEVICE_EXTENSION)); // // Save the device object pointer away for future reference // devExt->DeviceObject = functionalDeviceObject; // // Save the address of the physical device object away for future reference // devExt->PhysicalDeviceObject = PhysicalDeviceObject; // // Clear the Device Initializing bit since the Device Object was created // outside of DriverEntry. // functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; // // Create a familiar name for this device, so that non-kernel mode // programs can open the device. // // NOTE: WDM Drivers on Win98 MUST create this link in the // \DosDevices directory. \?? will NOT work. // RtlInitUnicodeString(&tempName,DOS_DEVICE_NAME); code=MyAllocUnicodeString(&linkName, &tempName, tempName.Length+4); if(uLanInstanceCounter){ linkName.Buffer[linkName.Length/2]='0'+uLanInstanceCounter; linkName.Length+=2; } LOG_FILEIO("uLan: AddDevice: Dev=%ws Link=%ws\n",devName.Buffer,linkName.Buffer); // // IoCreateSymbolicLink IS a WDM function... // code = IoCreateSymbolicLink(&linkName, &devName); if (!NT_SUCCESS(code)) { uLan_DbgPrint("uLan: IoCreateSymbolicLink failed. Status = 0x%x\n", code); code = STATUS_UNSUCCESSFUL; // // Clean up the mess // IoDeleteDevice(functionalDeviceObject); if(linkName.Buffer) ExFreePool(linkName.Buffer); if(devName.Buffer) ExFreePool(devName.Buffer);; // // Indicate load failure to the I/O manager; driver image is deleted... // return(code); } devExt->link_name=linkName; devExt->ntdev_name=devName; // // Ask the I/O Manager to use buffered I/O // functionalDeviceObject->Flags |= DO_BUFFERED_IO; // // Set up the "Remove Event" and "Stop Event". // // Note that we can't use an official "Remove Lock" here, because // the Remove Lock related calls are not in WDM. // KeInitializeEvent(&devExt->RemoveEvent, NotificationEvent, FALSE); // KeInitializeEvent(&devExt->StopEvent, NotificationEvent, TRUE); // // Init the count of in-progress I/O requests to zero. We use this // to keep track of when we can remove the device. // // devExt->OutstandingIO = 0; // // Internal device state flags, used for managing PnP state of device // // devExt->Started = FALSE; // devExt->HoldNewRequests = TRUE; // devExt->Removed = FALSE; // // Set initial state // devExt->State = STATE_NEVER_STARTED; // Initial uLan state ul_drv_new_init_state(devExt,2); // // Attach our FDO to the underlying PDO // devExt->DeviceToSendIrpsTo = IoAttachDeviceToDeviceStack(functionalDeviceObject, PhysicalDeviceObject); // // If that didn't work... // if (!devExt->DeviceToSendIrpsTo) { uLan_DbgPrint("uLan: IoAttachDeviceToDeviceStack failed to attach to Target Device"); // // Clean up the mess // IoDeleteDevice(functionalDeviceObject); // // Indicate load failure to the I/O manager; driver image is deleted... // return(STATUS_UNSUCCESSFUL); } #ifdef UL_WITH_WIN_PWR // this event is triggered when self-requested power irps complete KeInitializeEvent(&devExt->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE); #endif /* UL_WITH_WIN_PWR */ // Successfully added device, prepare number for next instance uLanInstanceCounter++; uLan_DbgPrint("uLan: AddDevice: done\n"); return code;}/////////////////////////////////////////////////////////////////////////////////// DispatchPnp//// This is the dispatch entry point for IRP_MJ_PNP requests. The// driver processes these requets, based on the current state of// the device.////// INPUTS://// DeviceObject - Address of the Functional DEVICE_OBJECT for our device.// // Irp - Address of the IRP representing the IRP_MJ_PNP request.//// OUTPUTS://// None.//// RETURNS:////// IRQL://// This routine is called at IRQL_PASSIVE_LEVEL.//// NOTES://// There are several difficulties implementing Plug and Play.// Perhaps the greatest difficulty is deciding precisely how you// want your device to work, given the various requests the driver// can receive and the states the device can be in. In our driver,// we've decided to implement the following policies://// 1) When a removal of the device is requested, we will reject// any new IRPs we receive (completing them with an error// status in the dispatch routine). We will wait until all IRPs// that are already present on the device's queue are complete// and then allow the remove.//// 2) When a stop of the device is requested, we'll queue any// newly received IRPs, but not initiate them. We will wait// until any IRPs that are presently ACTIVE in progress on the// device complete, and then allow the stop.//// 3) When a SUPRISE removal of the device is indicated, we// immediately cancel any requests that are queued, reject any// newly arriving requests.//// Of course, the second complexity in implementing plug and play// is getting the logic in your driver correct, so that it works// as you intend. According to our experience, this is easier said// than done./////////////////////////////////////////////////////////////////////////////////NTSTATUS DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION ioStackLocation; NTSTATUS code = STATUS_SUCCESS; PULAN_DEVICE_EXTENSION devExt; KEVENT eventWaitLowerDrivers; PDEVICE_OBJECT targetDevice; uLan_DbgPrint("uLan: DispatchPnp: called\n"); // // Get a pointer to our (FUNCTIONAL) device object's device // extension. // devExt = (PULAN_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // Up the count of in-progress requests // RequestIncrement(devExt); ioStackLocation = IoGetCurrentIrpStackLocation(Irp); KeInitializeEvent(&eventWaitLowerDrivers, NotificationEvent, FALSE); uLan_DbgPrint("uLan: DispatchPnp: Current state: "); PrintState(devExt); uLan_DbgPrint("uLan: DispatchPnp: MINOR 0x%0X\n",ioStackLocation->MinorFunction); if(ioStackLocation->MinorFunction<=IRP_MN_SURPRISE_REMOVAL+1) uLan_DbgPrint("uLan: DispatchPnp: *** PNP Minor Function is %s\n", pnpMinorCodes[ioStackLocation->MinorFunction]); switch( devExt->State + ioStackLocation->MinorFunction ) { // // STATE: STOPPED or NEVER_STARTED // IRP_MN: _START_DEVICE // // We're here if we've received an AddDevice() call, but we
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -