extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { KdPrint((DRIVERNAME " - Entering DriverEntry: DriverObject %8.8lX\n", DriverObject)); // Insist that OS support at least the WDM level of the DDK we use if(!IoIsWdmVersionAvailable(1, 0)) { KdPrint((DRIVERNAME " - Expected version of WDM (%d.%2.2d) not available\n", 1, 0)); return STATUS_UNSUCCESSFUL; } // See if we're running under Win98 or NT: win98 = IsWin98(); if(win98) KdPrint((DRIVERNAME " - Running under Windows 98\n")); else KdPrint((DRIVERNAME " - Running under NT\n")); // Initialize function pointers DriverObject->DriverUnload = DriverUnload; DriverObject->DriverExtension->AddDevice = AddDevice; DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWriteFlush; DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWriteFlush; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = DispatchReadWriteFlush; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCleanup; DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = DispatchInternalControl; DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceIoControl; return STATUS_SUCCESS; }
GENERICAPI NTSTATUS InitializeGenericExtension(PGENERIC_EXTENSION pdx, PGENERIC_INIT_STRUCT isp) { // InitializeGenericExtension if(isp->Size < FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) || !isp->DeviceObject || !isp->Ldo || !isp->Pdo || !isp->StartDevice || !isp->StopDevice || !isp->RemoveDevice || isp->DeviceQueue && !isp->StartIo) return STATUS_INVALID_PARAMETER; RtlZeroMemory(pdx, sizeof(GENERIC_EXTENSION)); pdx->DeviceObject = isp->DeviceObject; pdx->LowerDeviceObject = isp->Ldo; pdx->Pdo = isp->Pdo; pdx->StartDevice = isp->StartDevice; pdx->StopDevice = isp->StopDevice; pdx->RemoveDevice = isp->RemoveDevice; if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, OkayToRemove) + sizeof(PQUERYFUNCTION)) { // set OkayToStop & OkayToRemove pointers pdx->OkayToStop = isp->OkayToStop; pdx->OkayToRemove = isp->OkayToRemove; } // set OkayToStop & OkayToRemove pointers if((pdx->RemoveLock = isp->RemoveLock)) IoInitializeRemoveLock(pdx->RemoveLock, 0, 0, 0); pdx->state = STOPPED; pdx->devpower = PowerDeviceD0; pdx->syspower = PowerSystemWorking; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pdx->DeviceObject, DevicePowerState, state); // In version 1.3, I added support for multiple IRP queues if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, NumberOfQueues) + sizeof(ULONG) && isp->NumberOfQueues) { // multiple queues ULONG i; if(isp->DeviceQueue || isp->StartIo) return STATUS_INVALID_PARAMETER; // can't mix new and old ways of identifying queues if(isp->Size < FIELD_OFFSET(GENERIC_INIT_STRUCT, Queues) + isp->NumberOfQueues * 2 * sizeof(PVOID)) return STATUS_INVALID_PARAMETER; // init structure not big enough for (i = 0; i < isp->NumberOfQueues; ++i) if(!isp->Queues[i].DeviceQueue || !isp->Queues[i].StartIo) return STATUS_INVALID_PARAMETER; // none of the entries can be NULL pdx->nqueues = isp->NumberOfQueues; pdx->queues = (PDEVQUEUE*) ExAllocatePoolWithTag(NonPagedPool, isp->NumberOfQueues * sizeof(PDEVQUEUE), SPOT_TAG); if(!pdx->queues) return STATUS_INSUFFICIENT_RESOURCES; for (i = 0; i < isp->NumberOfQueues; ++i) { // for each queue pdx->queues[i] = isp->Queues[i].DeviceQueue; InitializeQueue(pdx->queues[i], isp->Queues[i].StartIo); } // for each queue } // multiple queues else if(isp->DeviceQueue) { // single queue pdx->nqueues = 1; pdx->queues = (PDEVQUEUE*) ExAllocatePoolWithTag(NonPagedPool, sizeof(PDEVQUEUE), SPOT_TAG); if(!pdx->queues) return STATUS_INSUFFICIENT_RESOURCES; pdx->queues[0] = isp->DeviceQueue; InitializeQueue(pdx->queues[0], isp->StartIo); } // single queue // In version 1.9, I added support for FlushPendingIo. // In version 1.10, GetDevicePowerState if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, Queues)) { // additional reserved fields pdx->FlushPendingIo = isp->FlushPendingIo; pdx->GetDevicePowerState = isp->GetDevicePowerState; } // additional reserved fields // Capture the mini-driver name for messages. This needs to be in ANSI because // unicode conversions at or above DISPATCH_LEVEL are not allowed. In retrospect, I // should have made the field in the INIT struct be in ANSI to start with... if(!isp->DebugName.Length) strcpy(pdx->DebugName, "GENERIC"); else { // convert debug name ANSI_STRING asname = {0, sizeof(pdx->DebugName) - 1, pdx->DebugName}; RtlUnicodeStringToAnsiString(&asname, &isp->DebugName, FALSE); pdx->DebugName[asname.Length] = 0; } // convert debug name if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) + sizeof(ULONG)) pdx->Flags = isp->Flags & GENERIC_CLIENT_FLAGS; if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, RestoreDeviceContext) + sizeof(PCONTEXTFUNCTION)) { // get power helper functions pdx->QueryPower = isp->QueryPower; pdx->SaveDeviceContext = isp->SaveDeviceContext; pdx->RestoreDeviceContext = isp->RestoreDeviceContext; } // get power helper functions if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, PerfBoundary) + sizeof(DEVICE_POWER_STATE)) pdx->PerfBoundary = isp->PerfBoundary; else pdx->PerfBoundary = PowerDeviceUnspecified; if(pdx->PerfBoundary == PowerDeviceUnspecified) pdx->PerfBoundary = PowerDeviceMaximum; // inhibit POWER_SEQUENCE optimization // Initialize variables related to asynchrounous IOCTL management. In version 2.0, this // is now always done rather than depending on a flag in the init struct. InitializeListHead(&pdx->PendingIoctlList); pdx->IoctlAbortStatus = 0; KeInitializeSpinLock(&pdx->IoctlListLock); // Initialize to manage registered device interfaces KeInitializeEvent(&pdx->iflock, SynchronizationEvent, TRUE); InitializeListHead(&pdx->iflist); // Indicate we handle power IRPs at PASSIVE_LEVEL pdx->DeviceObject->Flags |= DO_POWER_PAGABLE; KdPrint(("GENERIC - Initializing for %s\n", pdx->DebugName)); // If device honors paging-path notifications, initialize a synchronization // event in the signalled state to act as a simple mutex (SP-7) if(pdx->Flags & GENERIC_USAGE_PAGING) KeInitializeEvent(&pdx->evPagingPath, SynchronizationEvent, TRUE); // If requested to do so, register an AutoLaunch interface if(pdx->Flags & GENERIC_AUTOLAUNCH) GenericRegisterInterface(pdx, &GUID_AUTOLAUNCH_NOTIFY); // Register a power management interface GenericRegisterInterface(pdx, &GUID_GENERIC_POWER); #ifdef _X86_ win98 = IsWin98(); #endif return STATUS_SUCCESS; } // InitializeGenericExtension
GENERICAPI NTSTATUS GENERIC_EXPORT InitializeGenericExtension(PGENERIC_EXTENSION pdx, PGENERIC_INIT_STRUCT isp) { // InitializeGenericExtension if (isp->Size < FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) || !isp->DeviceObject || !isp->Ldo || !isp->Pdo || !isp->StartDevice || !isp->StopDevice || !isp->RemoveDevice || isp->DeviceQueue && !isp->StartIo) return STATUS_INVALID_PARAMETER; RtlZeroMemory(pdx, sizeof(GENERIC_EXTENSION)); pdx->DeviceObject = isp->DeviceObject; pdx->LowerDeviceObject = isp->Ldo; pdx->Pdo = isp->Pdo; pdx->StartDevice = isp->StartDevice; pdx->StopDevice = isp->StopDevice; pdx->RemoveDevice = isp->RemoveDevice; if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, OkayToRemove) + sizeof(PQUERYFUNCTION)) { // set OkayToStop & OkayToRemove pointers pdx->OkayToStop = isp->OkayToStop; pdx->OkayToRemove = isp->OkayToRemove; } // set OkayToStop & OkayToRemove pointers if ((pdx->dqReadWrite = isp->DeviceQueue)) { // queue reads & writes if (!isp->StartIo) return STATUS_INVALID_PARAMETER; InitializeQueue(pdx->dqReadWrite, isp->StartIo); } // queue reads & writes if ((pdx->RemoveLock = isp->RemoveLock)) IoInitializeRemoveLock(pdx->RemoveLock, 0, 0, 0); pdx->state = STOPPED; pdx->devpower = PowerDeviceD0; pdx->syspower = PowerSystemWorking; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pdx->DeviceObject, DevicePowerState, state); // Capture the mini-driver name for messages. This needs to be in ANSI because // unicode conversions at or above DISPATCH_LEVEL are not allowed if (!isp->DebugName.Length) strcpy(pdx->DebugName, "GENERIC"); else { // convert debug name ANSI_STRING asname = {0, sizeof(pdx->DebugName) - 1, pdx->DebugName}; RtlUnicodeStringToAnsiString(&asname, &isp->DebugName, FALSE); pdx->DebugName[asname.Length] = 0; } // convert debug name if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) + sizeof(ULONG)) pdx->Flags = isp->Flags & GENERIC_CLIENT_FLAGS; if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, RestoreDeviceContext) + sizeof(PCONTEXTFUNCTION)) { // get power helper functions pdx->QueryPower = isp->QueryPower; pdx->SaveDeviceContext = isp->SaveDeviceContext; pdx->RestoreDeviceContext = isp->RestoreDeviceContext; } // get power helper functions if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, PerfBoundary) + sizeof(DEVICE_POWER_STATE)) pdx->PerfBoundary = isp->PerfBoundary; else pdx->PerfBoundary = PowerDeviceUnspecified; if (pdx->PerfBoundary == PowerDeviceUnspecified) pdx->PerfBoundary = PowerDeviceMaximum; // inhibit POWER_SEQUENCE optimization // Initialize variables related to asynchrounous IOCTL management. if (pdx->Flags & GENERIC_PENDING_IOCTLS) { // driver may cache asyncronous IOCTLs InitializeListHead(&pdx->PendingIoctlList); pdx->IoctlAbortStatus = 0; // We need to initialize our IOCTL spin lock sometime, but just once. // Acquiring the cancel spin lock to guard this operation is a bit of // a hack, I suppose, but note that a class driver like this one never // gets an actual chance to initialize, so it's not my fault... KIRQL oldirql; IoAcquireCancelSpinLock(&oldirql); // any global spin lock would do if (!IoctlListLockInitialized) { // initialize global lock IoctlListLockInitialized = TRUE; KeInitializeSpinLock(&IoctlListLock); } // initialize global lock IoReleaseCancelSpinLock(oldirql); } // driver may cache asynchronous IOCTLs // Initialize to manage registered device interfaces ExInitializeFastMutex(&pdx->iflock); InitializeListHead(&pdx->iflist); // Indicate we handle power IRPs at PASSIVE_LEVEL pdx->DeviceObject->Flags |= DO_POWER_PAGABLE; KdPrint(("GENERIC - Initializing for %s\n", pdx->DebugName)); // If requested to do so, register an AutoLaunch interface if (pdx->Flags & GENERIC_AUTOLAUNCH) GenericRegisterInterface(pdx, &GUID_AUTOLAUNCH_NOTIFY); // Register a power management interface GenericRegisterInterface(pdx, &GUID_GENERIC_POWER); #ifdef _X86_ win98 = IsWin98(); #endif return STATUS_SUCCESS; } // InitializeGenericExtension
//------------------------------------------------------------------------ // GetDeviceStrings() // // dwDeviceNum: Position of device entry in the Windows registry list. // dev: container class where device description strings will be stored. // // Copies device description from the registry for single device. //------------------------------------------------------------------------ void CUsbIF::GetDeviceStrings(DWORD dwDeviceNum, CDeviceListEntry& dev) { // Clear the device info dev.m_friendlyname = ""; dev.m_linkname = ""; dev.m_serialnumber = ""; // Retrieve device list for GUID that has been specified. HDEVINFO hDevInfoList = SetupDiGetClassDevs (&m_GUID, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); if (hDevInfoList != NULL) { SP_DEVICE_INTERFACE_DATA deviceInfoData; // Clear data structure ZeroMemory(&deviceInfoData, sizeof(deviceInfoData)); deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); // retrieves a context structure for a device interface of a device information set. if (SetupDiEnumDeviceInterfaces (hDevInfoList, 0, &m_GUID, dwDeviceNum, &deviceInfoData)) { // Must get the detailed information in two steps // First get the length of the detailed information and allocate the buffer // retrieves detailed information about a specified device interface. PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL; ULONG predictedLength, requiredLength; predictedLength = requiredLength = 0; SetupDiGetDeviceInterfaceDetail ( hDevInfoList, &deviceInfoData, NULL, // Not yet allocated 0, // Set output buffer length to zero &requiredLength,// Find out memory requirement NULL); predictedLength = requiredLength; functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc (predictedLength); functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); SP_DEVINFO_DATA did = {sizeof(SP_DEVINFO_DATA)}; // Second, get the detailed information if ( SetupDiGetDeviceInterfaceDetail ( hDevInfoList, &deviceInfoData, functionClassDeviceData, predictedLength, &requiredLength, &did)) { TCHAR fname[256]; // Try by friendly name first. if (!SetupDiGetDeviceRegistryProperty(hDevInfoList, &did, SPDRP_FRIENDLYNAME, NULL, (PBYTE) fname, sizeof(fname), NULL)) { // Try by device description if friendly name fails. if (!SetupDiGetDeviceRegistryProperty(hDevInfoList, &did, SPDRP_DEVICEDESC, NULL, (PBYTE) fname, sizeof(fname), NULL)) { // Use the raw path information for linkname and friendlyname strncpy(fname, functionClassDeviceData->DevicePath, 256); } } dev.m_friendlyname = fname; dev.m_linkname = functionClassDeviceData->DevicePath; // Now get the Serial Number this is OS dependent as the registry // has to be manually parsed under Win98 if(!IsWin98()) { GetSerialNumber(functionClassDeviceData->DevicePath, &(dev.m_serialnumber)); } else { HKEY tempkey = NULL; LONG lRet; char szDeviceInstance[256]; DWORD dwBufLen=256; //KeyPath is the known location of our device using SIBULK GUID {37538c66-9584-42d3-9632-ebad0a230d13} under Win98SE std::string KeyPath = "System\\CurrentControlSet\\Control\\DeviceClasses\\{37538c66-9584-42d3-9632-ebad0a230d13}\\"; //SymLinkName is the dynamically allocated path of this particular instance of the Xpress USB device std::string SymLinkName = functionClassDeviceData->DevicePath; //You cannot use '/' symbols in a registry path name so replace them with "# SymLinkName = SymLinkName.replace(0,4,"##.#"); //Add the dynamic SymLinkName to the known KeyPath string and you have the key path to this device instance KeyPath += SymLinkName; //Get the Key lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyPath.c_str() , NULL, KEY_READ, &tempkey); if( lRet != ERROR_SUCCESS ) tempkey = NULL; //error retrieving key // Get the Device Instance string using the key lRet = RegQueryValueEx( tempkey, "DeviceInstance", NULL, NULL, (LPBYTE) szDeviceInstance, &dwBufLen); if( (lRet != ERROR_SUCCESS) || (dwBufLen > 80) ) tempkey = NULL; //error retrieving instance string std::string SerialNumber = szDeviceInstance; SerialNumber.erase(0,22); dev.m_serialnumber = SerialNumber; } free( functionClassDeviceData ); } } } // SetupDiDestroyDeviceInfoList() destroys a device information set // and frees all associated memory. SetupDiDestroyDeviceInfoList (hDevInfoList); }