/* * title: hidbatt.c * * purpose: wdm kernel client interface between HID class and power class * * Initial checkin for the hid to battery class driver. This should be * the same for both Win 98 and NT 5. Alpha level source. Requires * modified composite battery driver and modified battery class driver for * windows 98 support * */ #include "hidbatt.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,DriverEntry) #endif // Global ULONG HidBattDebug = HIDBATT_PRINT_NEVER; USHORT HidBreakFlag = HIDBATT_BREAK_NEVER; USHORT gusInstance = 0; // // Device Names // #define HidBattDeviceName L"\\Device\\HIDBattery" // local protos NTSTATUS HidBattSystemControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status; HidBattPrint (HIDBATT_TRACE, ("HidBatt:DriverEntry\n")); HIDDebugBreak(HIDBATT_BREAK_FULL); /************************************************************************************/ /* */ /* fill in the slots for the functions in */ /* the Driver object. */ /* */ /************************************************************************************/ DriverObject->MajorFunction[IRP_MJ_CREATE] = HidBattOpen; DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidBattClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidBattIoControl; DriverObject->MajorFunction[IRP_MJ_POWER] = HidBattPowerDispatch; DriverObject->MajorFunction[IRP_MJ_PNP] = HidBattPnpDispatch; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HidBattSystemControl; // pass down to hid class DriverObject->DriverUnload = HidBattUnload; // this is unloadable with current rev of battery class DriverObject->DriverExtension->AddDevice = HidBattAddDevice; return STATUS_SUCCESS; } NTSTATUS HidBattAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pHidPdo ) { BOOL bResult; PUNICODE_STRING unicodeString; PDEVICE_OBJECT pBatteryFdo = NULL; NTSTATUS ntStatus; CBatteryDevExt * pDevExt; UNICODE_STRING numberString; WCHAR numberBuffer[10]; CUString * pBatteryName; // enters here with pdo of hidclass - power class object HIDDebugBreak(HIDBATT_BREAK_ALWAYS); HidBattPrint (HIDBATT_TRACE, ("HidBattAddDevice\n")); /* sberard - Removed due to changes in hidclass.sys (bug #274422) HID_COLLECTION_INFORMATION HidInfo; RtlZeroMemory(&HidInfo,sizeof(HID_COLLECTION_INFORMATION)); ntStatus = DoIoctl( pHidPdo, IOCTL_HID_GET_COLLECTION_INFORMATION, NULL, 0, &HidInfo, sizeof(HID_COLLECTION_INFORMATION), (CHidDevice *) NULL ); if(NT_ERROR(ntStatus)) { HidBattPrint (HIDBATT_ERROR_ONLY, ("HidBattAddDevice: IOCTL_HID_GET_COLLECTION_INFORMATION failed 0x%08x\n", ntStatus)); return STATUS_UNSUCCESSFUL; } */ // too early to communicate with device, stash hid pdo and complete pBatteryName = new (NonPagedPool, HidBattTag) CUString(HidBattDeviceName); if (!pBatteryName) { return STATUS_INSUFFICIENT_RESOURCES; } // Create the UPS PDO device name based on the battery instance // CUString * pInstanceNumber = new (NonPagedPool, HidBattTag) CUString(++gusInstance,10); if (!pInstanceNumber) { return STATUS_INSUFFICIENT_RESOURCES; } pBatteryName->Append(&pInstanceNumber->m_String); delete pInstanceNumber; ntStatus = IoCreateDevice( DriverObject, sizeof (CBatteryDevExt), &pBatteryName->m_String, FILE_DEVICE_BATTERY, 0, FALSE, &pBatteryFdo ); if (ntStatus != STATUS_SUCCESS) { HidBattPrint(HIDBATT_ERROR, ("HidBattCreateFdo: error (0x%x) creating device object\n", ntStatus)); delete pBatteryName; --gusInstance; // reflect loss of device to instance return(ntStatus); } // pBatteryFdo->DeviceExtension = new (NonPagedPool, HidBattTag) CBatteryDevExt; // pBatteryFdo->StackSize++; // add one stack entry for battery class // layer the battery pdo to the hid class pdo // so that we begin to receive the device irps PDEVICE_OBJECT pHidDeviceObject = IoAttachDeviceToDeviceStack(pBatteryFdo,pHidPdo); pDevExt = (CBatteryDevExt *) pBatteryFdo->DeviceExtension; pDevExt->m_RegistryPath.Length = 0; pDevExt->m_RegistryPath.MaximumLength = sizeof(pDevExt->m_RegistryBuffer); RtlZeroMemory(&pDevExt->m_RegistryBuffer, sizeof(pDevExt->m_RegistryBuffer)); pDevExt->m_RegistryPath.Buffer = &pDevExt->m_RegistryBuffer[0]; // set buffer pointer pDevExt->m_pBattery = NULL; pBatteryFdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; pBatteryFdo->Flags &= ~DO_DEVICE_INITIALIZING; pDevExt->m_pHidPdo = pHidPdo; pDevExt->m_pBatteryFdo = pBatteryFdo; pDevExt->m_pLowerDeviceObject = pHidDeviceObject; pDevExt->m_eExtType = eBatteryDevice; pDevExt->m_bFirstStart = TRUE; pDevExt->m_bJustStarted = FALSE; pDevExt->m_ulDefaultAlert1 = (ULONG)-1; pDevExt->m_pBatteryName = pBatteryName; IoInitializeRemoveLock (&pDevExt->m_RemoveLock, HidBattTag, 10, 20); IoInitializeRemoveLock (&pDevExt->m_StopLock, HidBattTag, 10, 20); IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag); IoReleaseRemoveLockAndWait (&pDevExt->m_StopLock, (PVOID) HidBattTag); return STATUS_SUCCESS; } NTSTATUS HidBattOpen( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION irpSp; HIDDebugBreak(HIDBATT_BREAK_ALWAYS); HidBattPrint (HIDBATT_TRACE, ("HidBattOpen\n")); CBatteryDevExt * pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension; if (NT_SUCCESS (IoAcquireRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag))) { IoSkipCurrentIrpStackLocation (pIrp); ntStatus = IoCallDriver(pDevExt->m_pLowerDeviceObject, pIrp); HidBattPrint (HIDBATT_NOTE, ("HidBattOpen: lower driver returned 0x%08x\n", ntStatus)); IoReleaseRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag); } else { ntStatus = STATUS_NO_SUCH_DEVICE; pIrp->IoStatus.Status = ntStatus; IoCompleteRequest (pIrp, IO_NO_INCREMENT); } return ntStatus; } NTSTATUS HidBattClose( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION irpSp; HidBattPrint (HIDBATT_TRACE, ("HidBattClose\n")); // get the device extension CBatteryDevExt * pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension; HidBattCallLowerDriver(ntStatus, pDevExt->m_pLowerDeviceObject, pIrp); HidBattPrint (HIDBATT_NOTE, ("HidBattClose: lower driver returned 0x%08x\n", ntStatus)); return ntStatus; } NTSTATUS HidBattSystemControl( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { HidBattPrint (HIDBATT_TRACE, ("HidBattSystemControl\n")); HIDDebugBreak(HIDBATT_BREAK_ALWAYS); // all system control calls are passed down for now. NTSTATUS ntStatus = STATUS_SUCCESS; CBatteryDevExt * pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension; HidBattCallLowerDriver(ntStatus,pDevExt->m_pLowerDeviceObject,pIrp); return ntStatus; } VOID HidBattUnload( IN PDRIVER_OBJECT pDriverObject ) { HIDDebugBreak(HIDBATT_BREAK_ALWAYS); // we can just return, no driver-only (non-device) resources were allocated return; } NTSTATUS HidBattPnpDispatch( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { /*++ Routine Description: This routine is the dispatch routine for plug and play requests. Arguments: DeviceObject - Pointer to class device object. Irp - Pointer to the request packet. Return Value: Status is returned. --*/ HIDDebugBreak(HIDBATT_BREAK_ALWAYS); PIO_STACK_LOCATION pIrpStack; CBatteryDevExt * pDevExt; NTSTATUS ntStatus; BOOLEAN lockReleased = FALSE; // PAGED_CODE(); ntStatus = STATUS_NOT_SUPPORTED; // // Get a pointer to the current parameters for this request. The // information is contained in the current stack location. // pIrpStack = IoGetCurrentIrpStackLocation(pIrp); pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension; IoAcquireRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag); // // Dispatch minor function // switch (pIrpStack->MinorFunction) { case IRP_MN_STOP_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_STOP_DEVICE\n")); ntStatus = HidBattStopDevice(pDeviceObject, pIrp); break; } // IRP_MN_STOP_DEVICE case IRP_MN_QUERY_DEVICE_RELATIONS: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_DEVICE_RELATIONS - type (%d)\n", pIrpStack->Parameters.QueryDeviceRelations.Type)); break; } // IRP_MN_QUERY_DEVICE_RELATIONS case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_FILTER_RESOURCE_REQUIREMENTS - type (%d)\n", pIrpStack->Parameters.QueryDeviceRelations.Type)); break; } // IRP_MN_FILTER_RESOURCE_REQUIREMENTS case IRP_MN_REMOVE_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_REMOVE_DEVICE\n")); HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: Waiting to remove\n")); IoReleaseRemoveLockAndWait (&pDevExt->m_RemoveLock, (PVOID) HidBattTag); lockReleased = TRUE; // then remove device from device stack IoDetachDevice(pDevExt->m_pLowerDeviceObject); // delete our device IoDeleteDevice(pDeviceObject); ntStatus = STATUS_SUCCESS; break; } // IRP_MN_REMOVE_DEVICE case IRP_MN_SURPRISE_REMOVAL: case IRP_MN_QUERY_REMOVE_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_REMOVE_DEVICE\n")); ntStatus = HidBattStopDevice(pDeviceObject, pIrp); ntStatus = STATUS_SUCCESS; break; } // IRP_MN_QUERY_REMOVE_DEVICE case IRP_MN_START_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_START_DEVICE\n")); if (pDevExt->m_bFirstStart) { pDevExt->m_bJustStarted = TRUE; pDevExt->m_bFirstStart = FALSE; ntStatus = STATUS_SUCCESS; break; } // else fall through and do the same thing as the cancel remove. } // IRP_MN_START_DEVICE case IRP_MN_CANCEL_REMOVE_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE\n")); KEVENT cancelRemoveComplete; KeInitializeEvent(&cancelRemoveComplete, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext (pIrp); IoSetCompletionRoutine (pIrp, HidBattIoCompletion, &cancelRemoveComplete, TRUE, TRUE, TRUE); pIrp->IoStatus.Status = STATUS_SUCCESS; ntStatus = IoCallDriver (pDevExt->m_pLowerDeviceObject, pIrp); HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE, Lower driver status: %08x\n", ntStatus)); if (ntStatus == STATUS_PENDING) { KeWaitForSingleObject (&cancelRemoveComplete, Executive, KernelMode, FALSE, NULL); ntStatus = pIrp->IoStatus.Status; HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE, Lower driver 2nd status: %08x\n", ntStatus)); } if (NT_SUCCESS (ntStatus)) { ntStatus = HidBattInitializeDevice (pDeviceObject, pIrp); HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE, Our status: %08x\n", ntStatus)); } pIrp->IoStatus.Status = ntStatus; IoCompleteRequest (pIrp, IO_NO_INCREMENT); IoReleaseRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag); return ntStatus; } // IRP_MN_CANCEL_REMOVE_DEVICE case IRP_MN_QUERY_STOP_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_STOP_DEVICE\n")); ntStatus = STATUS_SUCCESS; break; } // IRP_MN_QUERY_STOP_DEVICE case IRP_MN_CANCEL_STOP_DEVICE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_STOP_DEVICE\n")); ntStatus = STATUS_SUCCESS; break; } // IRP_MN_CANCEL_STOP_DEVICE case IRP_MN_QUERY_RESOURCES: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_RESOURCES\n")); break; } // IRP_MN_QUERY_RESOURCES case IRP_MN_READ_CONFIG: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_READ_CONFIG\n")); break; } // IRP_MN_READ_CONFIG case IRP_MN_WRITE_CONFIG: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_WRITE_CONFIG\n")); break; } // IRP_MN_WRITE_CONFIG case IRP_MN_EJECT: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_EJECT\n")); break; } // IRP_MN_EJECT case IRP_MN_SET_LOCK: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_SET_LOCK\n")); break; } // IRP_MN_SET_LOCK case IRP_MN_QUERY_ID: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_ID\n")); break; } // IRP_MN_QUERY_ID case IRP_MN_QUERY_CAPABILITIES: { PDEVICE_CAPABILITIES deviceCaps; HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES\n")); deviceCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities; deviceCaps->Removable = TRUE; deviceCaps->SurpriseRemovalOK = TRUE; ntStatus = STATUS_SUCCESS; break; } // IRP_MN_QUERY_CAPABILITIES case IRP_MN_QUERY_PNP_DEVICE_STATE: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_PNP_DEVICE_STATE\n")); if (pDevExt->m_bJustStarted == TRUE) { pDevExt->m_bJustStarted = FALSE; ntStatus = HidBattInitializeDevice (pDeviceObject, pIrp); } if (!NT_SUCCESS (ntStatus)) { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: HidBattInitializeDevice failed %0x\n", ntStatus)); pIrp->IoStatus.Information |= PNP_DEVICE_FAILED; pIrp->IoStatus.Status = STATUS_SUCCESS; } break; } // IRP_MN_PNP_DEVICE_STATE default: { HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: Unimplemented minor %0x\n", pIrpStack->MinorFunction)); break; } } if (ntStatus != STATUS_NOT_SUPPORTED) { pIrp->IoStatus.Status = ntStatus; } if (NT_SUCCESS(ntStatus) || (ntStatus == STATUS_NOT_SUPPORTED)) { HidBattCallLowerDriver (ntStatus, pDevExt->m_pLowerDeviceObject, pIrp); } else { IoCompleteRequest (pIrp, IO_NO_INCREMENT); } if (lockReleased == FALSE) { IoReleaseRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag); } return ntStatus; } NTSTATUS HidBattPowerDispatch( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: This routine is the dispatch routine for power requests. Arguments: DeviceObject - Pointer to class device object. Irp - Pointer to the request packet. Return Value: Status is returned. --*/ { PIO_STACK_LOCATION pIrpStack; CBatteryDevExt * pDevExt; NTSTATUS ntStatus; HIDDebugBreak(HIDBATT_BREAK_ALWAYS); // PAGED_CODE(); HidBattPrint ((HIDBATT_TRACE | HIDBATT_POWER), ("HidBattPowerDispatch\n")); // // Never fail a power IRP, even if we don't do anything. // ntStatus = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; // // Get a pointer to the current parameters for this request. The // information is contained in the current stack location. // pIrpStack = IoGetCurrentIrpStackLocation(pIrp); pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension; // // Dispatch minor function // // this switch currently does no dispatches, and is expanded only for // documentary purposes switch (pIrpStack->MinorFunction) { case IRP_MN_WAIT_WAKE: { HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_WAIT_WAKE\n")); break; } case IRP_MN_POWER_SEQUENCE: { HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n")); break; } case IRP_MN_SET_POWER: { HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_SET_POWER\n")); if (pIrpStack->Parameters.Power.Type == SystemPowerState && pIrpStack->Parameters.Power.State.SystemState >= PowerSystemShutdown) { if (NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)) ) { // // Write default RemainingCapcitylimit back to UPS so when the system reboots, // the data returned by the device will be correct. // pDevExt->m_pBattery->GetSetValue(REMAINING_CAPACITY_LIMIT_INDEX, &pDevExt->m_ulDefaultAlert1,TRUE); IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag); } } break; } case IRP_MN_QUERY_POWER: { HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_QUERY_POWER\n")); break; } default: { HidBattPrint(HIDBATT_LOW, ("HidBattPowerDispatch: minor %d\n", pIrpStack->MinorFunction)); break; } } PoStartNextPowerIrp(pIrp); // inform system we are done with this irp IoSkipCurrentIrpStackLocation(pIrp); ntStatus = PoCallDriver(pDevExt->m_pLowerDeviceObject,pIrp); return ntStatus; } NTSTATUS HidBattSetInformation( IN PVOID Context, IN ULONG BatteryTag, IN BATTERY_SET_INFORMATION_LEVEL Level, IN PVOID Buffer OPTIONAL ) { /* Routine Description: Called by the class driver to set the battery's charge/discharge state. The smart battery does not support the critical bias function of this call. Arguments: Context - Miniport context value for battery BatteryTag - Tag of current battery Level - Action being asked for Return Value: NTSTATUS --*/ // charge and discharge forcing not supported for UPS's HidBattPrint (HIDBATT_TRACE, ("HidBattSetInformation\n")); HIDDebugBreak(HIDBATT_BREAK_ALWAYS); return STATUS_UNSUCCESSFUL; }