|
|
/*
************************************************************************* * File: HID.C * * Module: HID1394.SYS * HID (Human Input Device) minidriver for IEEE 1394 devices. * * Copyright (c) 1998 Microsoft Corporation * * * Author: ervinp * ************************************************************************* */
#include <wdm.h>
#include <hidport.h>
#include <1394.h>
#include "hid1394.h"
#include "debug.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, HIDT_GetHidDescriptor)
#pragma alloc_text(PAGE, HIDT_GetReportDescriptor)
#pragma alloc_text(PAGE, HIDT_GetStringDescriptor)
#pragma alloc_text(PAGE, HIDT_GetPhysicalDescriptor)
#pragma alloc_text(PAGE, HIDT_GetFeature)
#pragma alloc_text(PAGE, HIDT_SetFeature)
#pragma alloc_text(PAGE, HIDT_GetDeviceAttributes)
#endif
resetWorkItemContext *resetWorkItemsList = NULL; KSPIN_LOCK resetWorkItemsListSpinLock;
/*
************************************************************ * EnqueueResetWorkItem ************************************************************ * * This function must be called with resetWorkItemsListSpinLock held. */ VOID EnqueueResetWorkItem(resetWorkItemContext *workItem) { workItem->next = resetWorkItemsList; resetWorkItemsList = workItem; }
/*
************************************************************ * DequeueResetWorkItemWithIrp ************************************************************ * * Dequeue the workItem with the given IRP * AND mark it as cancelled in case the work item didn't fire yet. * * */ BOOLEAN DequeueResetWorkItemWithIrp(PIRP Irp, BOOLEAN irpWasCancelled) { BOOLEAN didDequeue = FALSE; if (resetWorkItemsList){ resetWorkItemContext *removedItem = NULL;
if (resetWorkItemsList->irpToComplete == Irp){ removedItem = resetWorkItemsList; resetWorkItemsList = resetWorkItemsList->next; } else { resetWorkItemContext *thisWorkItem = resetWorkItemsList; while (thisWorkItem->next && (thisWorkItem->next->irpToComplete != Irp)){ thisWorkItem = thisWorkItem->next; } removedItem = thisWorkItem->next; if (removedItem){ thisWorkItem->next = removedItem->next; } }
if (removedItem){ removedItem->next = BAD_POINTER;
/*
* Mark this workItem as cancelled so we won't touch * it's cancelled IRP when the workItem fires. */ if (irpWasCancelled){ removedItem->irpWasCancelled = TRUE; removedItem->irpToComplete = BAD_POINTER; }
didDequeue = TRUE; } }
return didDequeue; }
/*
******************************************************************************** * HIDT_GetHidDescriptor ******************************************************************************** * * Routine Description: * * Free all the allocated resources, etc. * * Arguments: * * DeviceObject - pointer to a device object. * * Return Value: * * NT status code. * */ NTSTATUS HIDT_GetHidDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus; PDEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack;
PAGED_CODE();
IrpStack = IoGetCurrentIrpStackLocation(Irp); DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
// BUGBUG FINISH
ntStatus = STATUS_UNSUCCESSFUL;
ASSERT(NT_SUCCESS(ntStatus)); return ntStatus; }
/*
******************************************************************************** * HIDT_GetDeviceAttributes ******************************************************************************** * * Routine Description: * * Fill in the given struct _HID_DEVICE_ATTRIBUTES * * Arguments: * * DeviceObject - pointer to a device object. * * Return Value: * * NT status code. * */ NTSTATUS HIDT_GetDeviceAttributes(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion) { NTSTATUS ntStatus; PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; PHID_DEVICE_ATTRIBUTES deviceAttributes;
PAGED_CODE();
irpStack = IoGetCurrentIrpStackLocation(Irp); deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject); deviceAttributes = (PHID_DEVICE_ATTRIBUTES) Irp->UserBuffer;
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (HID_DEVICE_ATTRIBUTES)){
//
// Report how many bytes were copied
//
Irp->IoStatus.Information = sizeof (HID_DEVICE_ATTRIBUTES);
deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
// BUGBUG FINISH
// deviceAttributes->VendorID = deviceExtension->DeviceDescriptor->idVendor;
// deviceAttributes->ProductID = deviceExtension->DeviceDescriptor->idProduct;
// deviceAttributes->VersionNumber = deviceExtension->DeviceDescriptor->bcdDevice;
ntStatus = STATUS_SUCCESS; } else { ntStatus = STATUS_INVALID_BUFFER_SIZE; }
ASSERT(NT_SUCCESS(ntStatus)); return ntStatus; }
/*
******************************************************************************** * HIDT_GetReportDescriptor ******************************************************************************** * * */ NTSTATUS HIDT_GetReportDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
// BUGBUG FINISH
return ntStatus; }
/*
******************************************************************************** * HIDT_IncrementPendingRequestCount ******************************************************************************** * * */ NTSTATUS HIDT_IncrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension) { LONG newRequestCount; NTSTATUS ntStatus = STATUS_SUCCESS;
newRequestCount = InterlockedIncrement(&DeviceExtension->NumPendingRequests);
//
// Make sure that the device is capable of receiving new requests.
//
if (DeviceExtension->DeviceState != DEVICE_STATE_RUNNING) {
//
// Device cannot receive any more IOs, decrement back, fail the increment
//
HIDT_DecrementPendingRequestCount(DeviceExtension); ntStatus = STATUS_NO_SUCH_DEVICE; }
return ntStatus; }
/*
******************************************************************************** * HIDT_DecrementPendingRequestCount ******************************************************************************** * * */ VOID HIDT_DecrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension) { LONG PendingCount;
ASSERT(DeviceExtension->NumPendingRequests >= 0);
PendingCount = InterlockedDecrement(&DeviceExtension->NumPendingRequests); if (PendingCount < 0){ ASSERT(DeviceExtension->DeviceState != DEVICE_STATE_RUNNING);
/*
* The device state is stopping, and the last outstanding request * has just completed. * * Note: RemoveDevice does an extra decrement, so we complete * the REMOVE IRP on the transition to -1, whether this * happens in RemoveDevice itself or subsequently while * RemoveDevice is waiting for this event to fire. */
KeSetEvent(&DeviceExtension->AllRequestsCompleteEvent, 0, FALSE); } }
/*
******************************************************************************** * HIDT_GetPortStatus ******************************************************************************** * * */ NTSTATUS HIDT_GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN PULONG PortStatus) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
// BUGBUG FINISH
return ntStatus; }
/*
******************************************************************************** * HIDT_EnableParentPort ******************************************************************************** * * */ NTSTATUS HIDT_EnableParentPort(IN PDEVICE_OBJECT DeviceObject) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
// BUGBUG FINISH
return ntStatus; }
/*
******************************************************************************** * HIDT_ResetWorkItem ******************************************************************************** * * Resets the interrupt pipe after a read error is encountered. * */ NTSTATUS HIDT_ResetWorkItem(IN PVOID Context) { resetWorkItemContext *resetWorkItemObj; PDEVICE_EXTENSION DeviceExtension; NTSTATUS ntStatus; ULONG portStatus; BOOLEAN didDequeue; KIRQL oldIrql;
/*
* Get the information out of the resetWorkItemContext and free it. */ resetWorkItemObj = (resetWorkItemContext *)Context; ASSERT(resetWorkItemObj); ASSERT(resetWorkItemObj->sig == RESET_WORK_ITEM_CONTEXT_SIG);
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(resetWorkItemObj->deviceObject);
if (DEVICE_STATE_RUNNING == DeviceExtension->DeviceState) { //
// Check the port state, if it is disabled we will need
// to re-enable it
//
ntStatus = HIDT_GetPortStatus(resetWorkItemObj->deviceObject, &portStatus);
if (NT_SUCCESS(ntStatus)) {
//
// port is disabled, attempt reset
//
HIDT_AbortPendingRequests(resetWorkItemObj->deviceObject); HIDT_EnableParentPort(resetWorkItemObj->deviceObject); }
//
// now attempt to reset the stalled pipe, this will clear the stall
// on the device as well.
//
if (NT_SUCCESS(ntStatus)) { // BUGBUG ntStatus = HIDT_ResetInterruptPipe(resetWorkItemObj->deviceObject);
}
}
/*
* Clear the ResetWorkItem ptr in the device extension * AFTER resetting the pipe so we don't end up with * two threads resetting the same pipe at the same time. */ (VOID)InterlockedExchange ((PVOID) &DeviceExtension->ResetWorkItem, 0);
/*
* The IRP that returned the error which prompted us to do this reset * is still owned by this driver because we returned * STATUS_MORE_PROCESSING_REQUIRED in the completion routine. * Now that the hub is reset, complete this failed IRP. * * Note: we check the irpWasCancelled as well as checking * if the IRP is in the queue to deal with the pathological * case of the IRP being cancelled, re-allocated, and * re-queued. */ KeAcquireSpinLock(&resetWorkItemsListSpinLock, &oldIrql); if (resetWorkItemObj->irpWasCancelled){ didDequeue = FALSE; } else { IoSetCancelRoutine(resetWorkItemObj->irpToComplete, NULL); didDequeue = DequeueResetWorkItemWithIrp(resetWorkItemObj->irpToComplete, FALSE); } KeReleaseSpinLock(&resetWorkItemsListSpinLock, oldIrql);
/*
* If we found a waiting IRP, complete it _after_ releasing the spinlock. */ if (didDequeue){ IoCompleteRequest(resetWorkItemObj->irpToComplete, IO_NO_INCREMENT); } ExFreePool(resetWorkItemObj);
HIDT_DecrementPendingRequestCount(DeviceExtension);
return ntStatus; }
/*
******************************************************************************** * ResetCancelRoutine ******************************************************************************** * * */ VOID ResetCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { BOOLEAN didDequeue; KIRQL oldIrql;
KeAcquireSpinLock(&resetWorkItemsListSpinLock, &oldIrql); didDequeue = DequeueResetWorkItemWithIrp(Irp, TRUE); KeReleaseSpinLock(&resetWorkItemsListSpinLock, oldIrql);
/*
* We must release the CancelSpinLock whether or not * we are completing the IRP here. */ IoReleaseCancelSpinLock(Irp->CancelIrql);
/*
* Complete this Irp only if we found it in our queue. */ if (didDequeue){ Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); } }
/*
******************************************************************************** * HIDT_GetPhysicalDescriptor ******************************************************************************** * * */ NTSTATUS HIDT_GetPhysicalDescriptor( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion) { NTSTATUS status = STATUS_UNSUCCESSFUL;
// BUGBUG FINISH ? REMOVE ?
return status; }
/*
******************************************************************************** * HIDT_GetStringDescriptor ******************************************************************************** * * */ NTSTATUS HIDT_GetStringDescriptor( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_PENDING; PDEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack; PVOID buffer; ULONG bufferSize; BOOLEAN isIndexedString;
PAGED_CODE();
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
IrpStack = IoGetCurrentIrpStackLocation(Irp);
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode){ case IOCTL_HID_GET_INDEXED_STRING: /*
* IOCTL_HID_GET_INDEXED_STRING uses buffering method * METHOD_OUT_DIRECT, which passes the buffer in the MDL. */ buffer = MmGetSystemAddressForMdl(Irp->MdlAddress); isIndexedString = TRUE; break;
case IOCTL_HID_GET_STRING: /*
* IOCTL_HID_GET_STRING uses buffering method * METHOD_NEITHER, which passes the buffer in Irp->UserBuffer. */ buffer = Irp->UserBuffer; isIndexedString = FALSE; break;
default: ASSERT(0); buffer = NULL; break; }
bufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (buffer && bufferSize){
/*
* BUGBUG - hack * String id and language id are in Type3InputBuffer field * of IRP stack location. * * Note: the string ID should be identical to the string's * field offset given in Chapter 9 of the USB spec. */ ULONG languageId = ((ULONG)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) >> 16; ULONG stringIndex;
if (isIndexedString){ stringIndex = ((ULONG)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) & 0x0ffff; } else { ULONG stringId = ((ULONG)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) & 0x0ffff;
switch (stringId){ case HID_STRING_ID_IMANUFACTURER: // BUGBUG FINISH stringIndex = DeviceExtension->DeviceDescriptor->iManufacturer;
break; case HID_STRING_ID_IPRODUCT: // BUGBUG FINISH stringIndex = DeviceExtension->DeviceDescriptor->iProduct;
break; case HID_STRING_ID_ISERIALNUMBER: // BUGBUG FINISH stringIndex = DeviceExtension->DeviceDescriptor->iSerialNumber;
break; default: stringIndex = -1; break; } }
if (stringIndex == -1){ ntStatus = STATUS_INVALID_PARAMETER; } else {
// BUGBUG FINISH
ntStatus = STATUS_UNSUCCESSFUL; } } else { ntStatus = STATUS_INVALID_USER_BUFFER; }
return ntStatus; }
/*
******************************************************************************** * HIDT_GetFeatureCompletion ******************************************************************************** * * */ NTSTATUS HIDT_GetFeatureCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PDEVICE_EXTENSION deviceExtension;
deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject); HIDT_DecrementPendingRequestCount(deviceExtension);
if (NT_SUCCESS(Irp->IoStatus.Status)){ /*
* Record the number of bytes written. */ // BUGBUG FINISH Irp->IoStatus.Information =
}
/*
* If the lower driver returned PENDING, mark our stack location as * pending also. This prevents the IRP's thread from being freed if * the client's call returns pending. */ if (Irp->PendingReturned){ IoMarkIrpPending(Irp); }
return STATUS_SUCCESS; }
/*
******************************************************************************** * HIDT_GetFeature ******************************************************************************** * * */ NTSTATUS HIDT_GetFeature(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
// BUGBUG FINISH
return ntStatus; }
/*
******************************************************************************** * HIDT_SetFeatureCompletion ******************************************************************************** * * */ NTSTATUS HIDT_SetFeatureCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PDEVICE_EXTENSION deviceExtension;
deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject); HIDT_DecrementPendingRequestCount(deviceExtension);
if (NT_SUCCESS(Irp->IoStatus.Status)){ /*
* Record the number of bytes written. */ // BUGBUG FINISH Irp->IoStatus.Information =
}
/*
* If the lower driver returned PENDING, mark our stack location as * pending also. This prevents the IRP's thread from being freed if * the client's call returns pending. */ if (Irp->PendingReturned){ IoMarkIrpPending(Irp); }
return STATUS_SUCCESS; }
/*
******************************************************************************** * HIDT_SetFeature ******************************************************************************** * * */ NTSTATUS HIDT_SetFeature(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
// BUGBUG FINISH
return ntStatus; }
|