From 22f703cab05b7cd368f4de9e03991b7664dc5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 13:56:46 +0200 Subject: Initial import of argyll version 1.5.1-8 --- usb/driver/pnp.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 usb/driver/pnp.c (limited to 'usb/driver/pnp.c') diff --git a/usb/driver/pnp.c b/usb/driver/pnp.c new file mode 100644 index 0000000..b103650 --- /dev/null +++ b/usb/driver/pnp.c @@ -0,0 +1,302 @@ +/* libusb-win32, Generic Windows USB Library + * Copyright (c) 2002-2005 Stephan Meyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "libusb_driver.h" + + + +static NTSTATUS DDKAPI +on_start_complete(DEVICE_OBJECT *device_object, IRP *irp, + void *context); + +static NTSTATUS DDKAPI +on_device_usage_notification_complete(DEVICE_OBJECT *device_object, + IRP *irp, void *context); + +static NTSTATUS DDKAPI +on_query_capabilities_complete(DEVICE_OBJECT *device_object, + IRP *irp, void *context); + + +NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp); + UNICODE_STRING symbolic_link_name; + WCHAR tmp_name[128]; + + status = remove_lock_acquire(dev); + + if (!NT_SUCCESS(status)) + { + USBDBG("device %s is pending removal\n",dev->device_id); + return complete_irp(irp, status, 0); + } + + switch (stack_location->MinorFunction) + { + case IRP_MN_REMOVE_DEVICE: + + USBMSG("IRP_MN_REMOVE_DEVICE: is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + + if (dev->device_interface_in_use && dev->is_started) + { + set_filter_interface_key(dev,(ULONG)-1); + + status = IoSetDeviceInterfaceState(&dev->device_interface_name, FALSE); + if (!NT_SUCCESS(status)) + { + USBERR0("IRP_MN_REMOVE_DEVICE: disabling device interface failed\n"); + } + } + + dev->is_started = FALSE; + + /* wait until all outstanding requests are finished */ + remove_lock_release_and_wait(dev); + + status = pass_irp_down(dev, irp, NULL, NULL); + + USBMSG("deleting device #%d %s\n", dev->id, dev->device_id); + + _snwprintf(tmp_name, sizeof(tmp_name)/sizeof(WCHAR), L"%s%04d", + LIBUSB_SYMBOLIC_LINK_NAME, dev->id); + + /* delete the symbolic link */ + RtlInitUnicodeString(&symbolic_link_name, tmp_name); + IoDeleteSymbolicLink(&symbolic_link_name); + + if (dev->device_interface_in_use && dev->device_interface_name.Buffer) + { + RtlFreeUnicodeString(&dev->device_interface_name); + } + UpdateContextConfigDescriptor(dev,NULL,0,0,-1); + + /* delete the device object */ + IoDetachDevice(dev->next_stack_device); + IoDeleteDevice(dev->self); + + return status; + + case IRP_MN_SURPRISE_REMOVAL: + + dev->is_started = FALSE; + USBMSG("IRP_MN_SURPRISE_REMOVAL: is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + + if (dev->device_interface_in_use) + { + set_filter_interface_key(dev,(ULONG)-1); + IoSetDeviceInterfaceState(&dev->device_interface_name, FALSE); + dev->device_interface_in_use=FALSE; + if (dev->device_interface_name.Buffer) + { + RtlFreeUnicodeString(&dev->device_interface_name); + dev->device_interface_name.Buffer = NULL; + } + } + UpdateContextConfigDescriptor(dev,NULL,0,0,-1); + status = STATUS_SUCCESS; + + break; + + case IRP_MN_START_DEVICE: + USBMSG("IRP_MN_START_DEVICE: is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + + // A driver calls this routine after receiving a device set-power + // request and before calling PoStartNextPowerIrp. When handling a + // PnP IRP_MN_START_DEVICE request, the driver should call + // PoSetPowerState to notify the power manager that the device is + // in the D0 state. + // + PoSetPowerState(dev->self, DevicePowerState, dev->power_state); + if (dev->device_interface_in_use) + { + status = IoSetDeviceInterfaceState(&dev->device_interface_name, TRUE); + if (!NT_SUCCESS(status)) + { + USBERR0("IRP_MN_START_DEVICE: enabling device interface failed\n"); + } + } + return pass_irp_down(dev, irp, on_start_complete, NULL); + + case IRP_MN_STOP_DEVICE: + dev->is_started = FALSE; + USBDBG("IRP_MN_STOP_DEVICE: is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + USBDBG("IRP_MN_DEVICE_USAGE_NOTIFICATION: is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + + if (!dev->self->AttachedDevice + || (dev->self->AttachedDevice->Flags & DO_POWER_PAGABLE)) + { + dev->self->Flags |= DO_POWER_PAGABLE; + } + + return pass_irp_down(dev, irp, on_device_usage_notification_complete, NULL); + + case IRP_MN_QUERY_CAPABILITIES: + USBDBG("IRP_MN_QUERY_CAPABILITIES: is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + + if (!dev->is_filter) + { + /* apply registry setting */ + stack_location->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = dev->surprise_removal_ok; + } + + return pass_irp_down(dev, irp, on_query_capabilities_complete, NULL); + + default: + break; + + } + + remove_lock_release(dev); + return pass_irp_down(dev, irp, NULL, NULL); +} + +static NTSTATUS DDKAPI +on_start_complete(DEVICE_OBJECT *device_object, IRP *irp, void *context) +{ + libusb_device_t *dev = device_object->DeviceExtension; + + if (irp->PendingReturned) + { + IoMarkIrpPending(irp); + } + + USBDBG("is-filter=%c %s\n", + dev->is_filter ? 'Y' : 'N', + dev->device_id); + + if (dev->next_stack_device->Characteristics & FILE_REMOVABLE_MEDIA) + { + device_object->Characteristics |= FILE_REMOVABLE_MEDIA; + } +#ifndef SKIP_CONFIGURE_NORMAL_DEVICES + // select initial configuration if not a filter + if (!dev->is_filter && !dev->is_started) + { + // optionally, the initial configuration value can be specified + // in the inf file. See reg_get_properties() + // HKR,,"InitialConfigValue",0x00010001, + + // If initial_config_value is negative, the configuration will + // only be set if the device is not already configured. + if (dev->initial_config_value) + { + if (dev->initial_config_value == SET_CONFIG_ACTIVE_CONFIG) + { + USBDBG("applying active configuration for %s\n", + dev->device_id); + } + else + { + USBDBG("applying InitialConfigValue %d for %s\n", + dev->initial_config_value, dev->device_id); + } + + if(!NT_SUCCESS(set_configuration(dev, dev->initial_config_value, LIBUSB_DEFAULT_TIMEOUT))) + { + // we should always be able to apply the active configuration, + // even in the case of composite devices. + if (dev->initial_config_value == SET_CONFIG_ACTIVE_CONFIG) + { + USBERR("failed applying active configuration for %s\n", + dev->device_id); + } + else + { + USBERR("failed applying InitialConfigValue %d for %s\n", + dev->initial_config_value, dev->device_id); + } + } + } + } +#endif + dev->is_started = TRUE; + remove_lock_release(dev); + + return STATUS_SUCCESS; +} + +static NTSTATUS DDKAPI +on_device_usage_notification_complete(DEVICE_OBJECT *device_object, + IRP *irp, void *context) +{ + libusb_device_t *dev = device_object->DeviceExtension; + + if (irp->PendingReturned) + { + IoMarkIrpPending(irp); + } + + if (!(dev->next_stack_device->Flags & DO_POWER_PAGABLE)) + { + device_object->Flags &= ~DO_POWER_PAGABLE; + } + + remove_lock_release(dev); + + return STATUS_SUCCESS; +} + +static NTSTATUS DDKAPI +on_query_capabilities_complete(DEVICE_OBJECT *device_object, + IRP *irp, void *context) +{ + libusb_device_t *dev = device_object->DeviceExtension; + IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp); + + if (irp->PendingReturned) + { + IoMarkIrpPending(irp); + } + + if (NT_SUCCESS(irp->IoStatus.Status)) + { + if (!dev->is_filter) + { + /* apply registry setting */ + stack_location->Parameters.DeviceCapabilities.Capabilities + ->SurpriseRemovalOK = dev->surprise_removal_ok; + } + + /* save supported device power states */ + memcpy(dev->device_power_states, stack_location + ->Parameters.DeviceCapabilities.Capabilities->DeviceState, + sizeof(dev->device_power_states)); + } + + remove_lock_release(dev); + + return STATUS_SUCCESS; +} -- cgit v1.2.3