Other than saving you the trouble of the trouble of keeping a copy of the portcls's IRP_MJ_DEVICE_CONTROL handler, PcDispatchIrp also doe some additional parameter validations. Calling PcDispatchIrp allows portcls to do the default handling on behalf of miniport driver. You can do any proprietary handling for IRPs (IRP_MJ_DEVICE_CONTROL, IRP_MJ_CREATE, or IRP_MJ_CLOSE.....)destinating to your device before forwarding to portcls for all necessary default handling. Here is some example on how it can be used. NTSTATUS DriverEntry(IN PDRIVER_OBJECT _pDriverObject, IN PUNICODE_STRING _pRegistryPath) { ... status = PcInitializeAdapterDriver(_pDriverObject, _pRegistryPath, AddDevice); ... _pDriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = IoCtlHandler; .. } NTSTATUS IoCtlHandler(DEVICE_OBJECT *_Fdo, IRP *_Irp) { PAGED_CODE(); NTSTATUS status = STATUS_UNSUCCESSFUL; IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(_Irp); if ((NULL != _Irp->AssociatedIrp.SystemBuffer) && (NULL != stack) && (NULL != stack->FileObject)) { if (0 == RtlCompareUnicodeString (&gPrivateInterfaceRefStringCmp, &stack->FileObject->FileName, TRUE)) { // gPrivateInterfaceRefStringCmp is your prviate interface string that you register through IoRegisterDeviceInterface // in AddDevice routine ... // // Handle the various IOCTLs // switch (stack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_PRIVATE_CODE1: { .... break; } case IOCTL_PRIVATE_CODE2: { ..... break; } default: { ..... status = STATUS_INVALID_PARAMETER; break; } } // Set the IRP status appropriately, and complete the IRP. _Irp->IoStatus.Status = status; IoCompleteRequest(_Irp, IO_NO_INCREMENT); SET_STATUS_AND_JUMP(status, exit); } // gPrivateInterfaceRefStringCmp == stack->FileObject->FileName } // We don't handle this IRP. Forward it on to Portclass for handling. status = PcDispatchIrp(_Fdo, _Irp); exit: return status; } Regards, Cheng-mean Liu Audio Driver Developer Microsoft Corporation This posting is provided "AS IS" with no warranties, and confers no rights. From: wdmaudiodev-bounce@xxxxxxxxxxxxx [mailto:wdmaudiodev-bounce@xxxxxxxxxxxxx] On Behalf Of Tom Eckert Sent: Monday, April 09, 2007 6:09 AM To: wdmaudiodev@xxxxxxxxxxxxx Subject: [wdmaudiodev] Re: Overriding IRP_MJ_DEVICE_CONTROL handling is possible? Don, I don't think you should be calling IoSkipCurrentIrpStackLocation() and IoCallDriver() to pass the call to portcls. The miniport is not an upper driver for portcls, actually portcls takes over your stack location so once you've hooked it back (by overwriting the portcls call in the MajorFunction table) this will actually re-enter your driver instead of calling portcls (and overrun the stack). Save the address of the IRP_MJ_DEVICE_CONTROL handler that portcls installs and call it directly when you've determined that the IRP is not from your app. PDRIVER_DISPATCH pPortClsDeviceControl; extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPathName) { NTSTATUS ntStatus = PcInitializeAdapterDriver( DriverObject, RegistryPathName, (PDRIVER_ADD_DEVICE)AddDevice); if(NT_SUCCESS(ntStatus)) { pPortClsDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControlHandler; } return ntStatus; } and somewhere in DeviceControlHandler if(it's my IOCTL) status = HandleIt(); else status= pPortClsDeviceControl(fdo,Irp); This approach works for us but it looks like PcDispatchIrp saves you the trouble of keeping a copy of the portcls handler so to use that just eliminate the pPortClsDeviceControl variable and call PcDispatchIrp instead. Maybe someone from ms will want to chime in here if there's a reason why the PcDispatchIrp approach is better than simply calling the portcls entry? You'll also need to create symbolic link to use in your user mode CreateFile call. Hope this helps, Tom Thomas Eckert Sr Software Engineer Audioscience Inc. Don Bell wrote: I am trying to find a way to add some custom IOCTL handling to a miniport audio driver. The driver's DriverEntry() currently looks like this: extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPathName) { NTSTATUS ntStatus = PcInitializeAdapterDriver( DriverObject, RegistryPathName, (PDRIVER_ADD_DEVICE)AddDevice); return ntStatus; } And I was thinking of adding a DispatchDeviceControl() like this: extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPathName) { NTSTATUS ntStatus = PcInitializeAdapterDriver( DriverObject, RegistryPathName, (PDRIVER_ADD_DEVICE)AddDevice); if(NT_SUCCESS(ntStatus)) { DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControlHandler; } return ntStatus; } Then, in DeviceControlHandler(): (1) Use IoGetCurrentIrpStackLocation() - to obtain current stack location. (2) Handle it (i.e. the current IRP) if it's "mine" or pass it down the stack for processing by using IoSkipCurrentIrpStackLocation() and then calling IoCallDriver(). My questions is... Is this "legal"? That is, is the PortCls system designed to handle such customization (i.e. mixing PortCls high-level Pc* with Io*)? The main reason I am asking such a trivial question is that while I can make this appear to work, it may be in violation of some fundamental principle in the PortCls system, which will trigger bugs that could be a nightmare to debug. Am I in for trouble in attempting to hack something like this into PortCls? Many thanks in advance, Don ****************** WDMAUDIODEV addresses: Post message: mailto:wdmaudiodev@xxxxxxxxxxxxx Subscribe: mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=subscribe Unsubscribe: mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=unsubscribe Moderator: mailto:wdmaudiodev-moderators@xxxxxxxxxxxxx URL to WDMAUDIODEV page: http://www.wdmaudiodev.com/