static BOOL libusb_initialized;
+static BOOL device_exists( DEVICE_OBJECT *device )
+{
+ struct DeviceInstance *instance;
+
+ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+ if (instance->pdo == device)
+ return TRUE;
+ return FALSE;
+}
+
static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size )
{
int copy;
TRACE( "%p, %p\n", device, irp );
EnterCriticalSection( &usbhub_cs );
+ if (!device_exists( device )) goto done;
inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
if (inst->service) goto done;
irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
TRACE( "%p, %p\n", device, irp );
EnterCriticalSection( &usbhub_cs );
+ if (!device_exists( device )) goto done;
inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
if (!inst->service) goto done;
irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
TRACE( "%p, %p\n", device, irp );
EnterCriticalSection( &usbhub_cs );
+ if (!device_exists( device )) goto done;
inst = ((struct PdoExtension *)device->DeviceExtension)->instance;
if (!inst->service) goto done;
irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
struct PdoExtension *dx;
IO_STACK_LOCATION *irpsp;
- NTSTATUS status;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG_PTR info = 0;
TRACE( "%p, %p\n", device, irp );
EnterCriticalSection( &usbhub_cs );
- dx = device->DeviceExtension;
irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
+ if (!device_exists( device ))
+ {
+ if (irpsp->MinorFunction == IRP_MN_SURPRISE_REMOVAL ||
+ irpsp->MinorFunction == IRP_MN_REMOVE_DEVICE)
+ status = STATUS_SUCCESS;
+ goto done;
+ }
+ dx = device->DeviceExtension;
switch (irpsp->MinorFunction)
{
case IRP_MN_QUERY_DEVICE_RELATIONS:
status = STATUS_SUCCESS;
}
+done:
LeaveCriticalSection( &usbhub_cs );
irp->IoStatus.u.Status = status;
irp->IoStatus.Information = info;
return ret;
}
+static void stop_service( const WCHAR *name )
+{
+ SC_HANDLE scm, service;
+ SERVICE_STATUS ss;
+
+ scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );
+ if (scm == NULL)
+ return;
+
+ service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );
+ if (service == NULL)
+ {
+ CloseServiceHandle( scm );
+ return;
+ }
+
+ ControlService( service, SERVICE_CONTROL_STOP, &ss );
+
+ CloseServiceHandle( service );
+ CloseServiceHandle( scm );
+}
+
static BOOL create_pdo_name( UNICODE_STRING *pdo_name )
{
static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
}
}
+static NTSTATUS call_pnp_func( DEVICE_OBJECT *device, UCHAR minor_func )
+{
+ DRIVER_OBJECT *driver = device->DriverObject;
+ IO_STACK_LOCATION *irpsp;
+ PIRP irp;
+ NTSTATUS status;
+
+ if (driver->MajorFunction[IRP_MJ_PNP] == NULL)
+ return STATUS_NOT_SUPPORTED;
+ irp = IoAllocateIrp( device->StackSize, FALSE );
+ if (irp == NULL) return STATUS_NO_MEMORY;
+
+ irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
+ irp->RequestorMode = KernelMode;
+ irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+ irpsp->MajorFunction = IRP_MJ_PNP;
+ irpsp->MinorFunction = minor_func;
+ irpsp->DeviceObject = device;
+ device->CurrentIrp = irp;
+ status = IoCallDriver( device, irp );
+ IoFreeIrp( irp );
+ return status;
+}
+
+static void stop_device_driver( struct DeviceInstance *instance )
+{
+ if (instance->pdo)
+ {
+ NTSTATUS status;
+ DEVICE_OBJECT *attd = instance->pdo->AttachedDevice;
+ DEVICE_OBJECT *dev = (attd != NULL) ? attd : instance->pdo;
+
+ status = call_pnp_func( dev, IRP_MN_SURPRISE_REMOVAL );
+ if (status != STATUS_SUCCESS)
+ WARN( "handling IRP_MN_SURPRISE_REMOVAL failed: %08x\n", status );
+ status = call_pnp_func( dev, IRP_MN_REMOVE_DEVICE );
+ if (status != STATUS_SUCCESS)
+ WARN( "handling IRP_MN_REMOVE_DEVICE failed: %08x\n", status );
+ IoDeleteDevice( instance->pdo );
+ }
+ if (instance->service)
+ {
+ struct DeviceInstance *it;
+ BOOL stop = TRUE;
+
+ EnterCriticalSection( &usbhub_cs );
+ LIST_FOR_EACH_ENTRY( it, &Devices, struct DeviceInstance, entry )
+ if (it->pdo != NULL && it->service != NULL &&
+ !strcmpiW( it->service, instance->service ))
+ {
+ stop = FALSE;
+ break;
+ }
+ LeaveCriticalSection( &usbhub_cs );
+ if (stop)
+ stop_service( instance->service );
+ }
+ else
+ HeapFree( GetProcessHeap(), 0, instance->instance_id );
+#ifdef HAVE_LIBUSB_H
+ libusb_unref_device( instance->dev );
+#endif
+ list_remove( &instance->entry );
+ HeapFree( GetProcessHeap(), 0, instance );
+}
+
static BOOL is_new( void *dev )
{
struct DeviceInstance *instance;
return TRUE;
}
+static int add_to_remove_list( struct DeviceInstance *it, struct list *remove )
+{
+ struct DeviceInstance *copy;
+
+ if (it->service)
+ {
+ copy = HeapAlloc( GetProcessHeap(), 0, sizeof(*copy) );
+ if (!copy) return 1;
+ memcpy( copy, it, sizeof(struct DeviceInstance) );
+ copy->pdo = NULL;
+ copy->dev = NULL;
+ list_add_tail( &Devices, ©->entry);
+ }
+ list_remove( &it->entry );
+ list_add_tail( remove, &it->entry );
+ return 0;
+}
+
#ifdef HAVE_LIBUSB_H
static int initialize_libusb(void)
return libusb_init( NULL );
}
-void enum_usb_devices(void)
+void add_usb_devices(void)
{
libusb_device **devs, *dev;
struct libusb_device_descriptor desc;
LeaveCriticalSection( &usbhub_cs );
}
+void remove_usb_devices(void)
+{
+ struct list remove_list = LIST_INIT(remove_list);
+ libusb_device **devs, *dev;
+ struct DeviceInstance *it, *next;
+ unsigned int i;
+ BOOL found;
+
+ EnterCriticalSection( &usbhub_cs );
+ if (!libusb_initialized || libusb_get_device_list( NULL, &devs ) < 0)
+ goto end;
+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &Devices, struct DeviceInstance, entry )
+ {
+ if (!it->dev)
+ continue;
+ found = FALSE;
+ i = 0;
+ while ((dev = devs[i++]))
+ if (it->dev == dev)
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found && add_to_remove_list( it, &remove_list ))
+ break;
+ }
+end:
+ LeaveCriticalSection( &usbhub_cs );
+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &remove_list, struct DeviceInstance, entry )
+ {
+ TRACE( "remove %04x:%04x\n", it->vid, it->pid );
+ stop_device_driver( it );
+ }
+}
+
#else
static int initialize_libusb(void)
return 0;
}
-void enum_usb_devices(void)
+void add_usb_devices(void)
{
struct usb_device *dev;
struct usb_bus *bus;
LeaveCriticalSection( &usbhub_cs );
}
+void remove_usb_devices(void)
+{
+ struct list remove_list = LIST_INIT(remove_list);
+ struct usb_device *dev;
+ struct usb_bus *bus;
+ struct DeviceInstance *it, *next;
+ BOOL found;
+
+ EnterCriticalSection( &usbhub_cs );
+ if (!libusb_initialized)
+ goto end;
+ usb_find_busses();
+ usb_find_devices();
+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &Devices, struct DeviceInstance, entry )
+ {
+ if (!it->dev)
+ continue;
+ found = FALSE;
+ for (bus = usb_busses; bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next)
+ if (it->dev == dev)
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found && add_to_remove_list( it, &remove_list ))
+ break;
+ }
+end:
+ LeaveCriticalSection( &usbhub_cs );
+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &remove_list, struct DeviceInstance, entry )
+ {
+ TRACE( "remove %04x:%04x\n", it->vid, it->pid );
+ stop_device_driver( it );
+ }
+}
+
#endif
#else
-void enum_usb_devices(void)
+void add_usb_devices(void)
+{
+}
+
+void remove_usb_devices(void)
{
}
else
libusb_initialized = TRUE;
LeaveCriticalSection( &usbhub_cs );
- enum_usb_devices();
+ add_usb_devices();
event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );
SetEvent( event );
CloseHandle( event );