winebus.sys: Add implementation for device removal.
Signed-off-by: Aric Stewart <aric@codeweavers.com> Signed-off-by: Sebastian Lackner <sebastian@fds-team.de> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c29c3d1fad
commit
9f8758b19d
|
@ -19,8 +19,18 @@
|
||||||
/* Busses */
|
/* Busses */
|
||||||
NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_path) DECLSPEC_HIDDEN;
|
NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_path) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
/* Native device function table */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int (*compare_platform_device)(DEVICE_OBJECT *device, void *platform_dev);
|
||||||
|
} platform_vtbl;
|
||||||
|
|
||||||
|
void *get_platform_private(DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
/* HID Plug and Play Bus */
|
/* HID Plug and Play Bus */
|
||||||
NTSTATUS WINAPI common_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN;
|
NTSTATUS WINAPI common_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN;
|
||||||
DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW, void *native, WORD vid,
|
DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW, WORD vid, WORD pid,
|
||||||
WORD pid, DWORD version, DWORD uid, const WCHAR *serialW, BOOL is_gamepad,
|
DWORD version, DWORD uid, const WCHAR *serialW, BOOL is_gamepad,
|
||||||
const GUID *class) DECLSPEC_HIDDEN;
|
const GUID *class, const platform_vtbl *vtbl, DWORD platform_data_size) DECLSPEC_HIDDEN;
|
||||||
|
DEVICE_OBJECT *bus_find_hid_device(const platform_vtbl *vtbl, void *platform_dev) DECLSPEC_HIDDEN;
|
||||||
|
void bus_remove_hid_device(DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -61,6 +61,16 @@ static const WCHAR hidraw_busidW[] = {'H','I','D','R','A','W',0};
|
||||||
#include "initguid.h"
|
#include "initguid.h"
|
||||||
DEFINE_GUID(GUID_DEVCLASS_HIDRAW, 0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0x13,0xf3,0xaa,0x81);
|
DEFINE_GUID(GUID_DEVCLASS_HIDRAW, 0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0x13,0xf3,0xaa,0x81);
|
||||||
|
|
||||||
|
struct platform_private
|
||||||
|
{
|
||||||
|
struct udev_device *udev_device;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
|
||||||
|
{
|
||||||
|
return (struct platform_private *)get_platform_private(device);
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD get_sysattr_dword(struct udev_device *dev, const char *sysattr, int base)
|
static DWORD get_sysattr_dword(struct udev_device *dev, const char *sysattr, int base)
|
||||||
{
|
{
|
||||||
const char *attr = udev_device_get_sysattr_value(dev, sysattr);
|
const char *attr = udev_device_get_sysattr_value(dev, sysattr);
|
||||||
|
@ -88,6 +98,18 @@ static WCHAR *get_sysattr_string(struct udev_device *dev, const char *sysattr)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int compare_platform_device(DEVICE_OBJECT *device, void *platform_dev)
|
||||||
|
{
|
||||||
|
struct udev_device *dev1 = impl_from_DEVICE_OBJECT(device)->udev_device;
|
||||||
|
struct udev_device *dev2 = platform_dev;
|
||||||
|
return strcmp(udev_device_get_syspath(dev1), udev_device_get_syspath(dev2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const platform_vtbl hidraw_vtbl =
|
||||||
|
{
|
||||||
|
compare_platform_device,
|
||||||
|
};
|
||||||
|
|
||||||
static void try_add_device(struct udev_device *dev)
|
static void try_add_device(struct udev_device *dev)
|
||||||
{
|
{
|
||||||
DWORD vid = 0, pid = 0, version = 0;
|
DWORD vid = 0, pid = 0, version = 0;
|
||||||
|
@ -123,12 +145,15 @@ static void try_add_device(struct udev_device *dev)
|
||||||
subsystem = udev_device_get_subsystem(dev);
|
subsystem = udev_device_get_subsystem(dev);
|
||||||
if (strcmp(subsystem, "hidraw") == 0)
|
if (strcmp(subsystem, "hidraw") == 0)
|
||||||
{
|
{
|
||||||
device = bus_create_hid_device(udev_driver_obj, hidraw_busidW, dev, vid, pid,
|
device = bus_create_hid_device(udev_driver_obj, hidraw_busidW, vid, pid, version, 0, serial, FALSE,
|
||||||
version, 0, serial, FALSE, &GUID_DEVCLASS_HIDRAW);
|
&GUID_DEVCLASS_HIDRAW, &hidraw_vtbl, sizeof(struct platform_private));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device)
|
if (device)
|
||||||
udev_device_ref(dev);
|
{
|
||||||
|
impl_from_DEVICE_OBJECT(device)->udev_device = udev_device_ref(dev);
|
||||||
|
IoInvalidateDeviceRelations(device, BusRelations);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
WARN("Ignoring device %s with subsystem %s\n", debugstr_a(devnode), subsystem);
|
WARN("Ignoring device %s with subsystem %s\n", debugstr_a(devnode), subsystem);
|
||||||
|
|
||||||
|
@ -137,7 +162,12 @@ static void try_add_device(struct udev_device *dev)
|
||||||
|
|
||||||
static void try_remove_device(struct udev_device *dev)
|
static void try_remove_device(struct udev_device *dev)
|
||||||
{
|
{
|
||||||
/* FIXME */
|
DEVICE_OBJECT *device = bus_find_hid_device(&hidraw_vtbl, dev);
|
||||||
|
if (!device) return;
|
||||||
|
|
||||||
|
dev = impl_from_DEVICE_OBJECT(device)->udev_device;
|
||||||
|
bus_remove_hid_device(device);
|
||||||
|
udev_device_unref(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void build_initial_deviceset(void)
|
static void build_initial_deviceset(void)
|
||||||
|
|
|
@ -47,13 +47,16 @@ struct pnp_device
|
||||||
|
|
||||||
struct device_extension
|
struct device_extension
|
||||||
{
|
{
|
||||||
void *native; /* Must be the first member of the structure */
|
struct pnp_device *pnp_device;
|
||||||
|
|
||||||
WORD vid, pid;
|
WORD vid, pid;
|
||||||
DWORD uid, version, index;
|
DWORD uid, version, index;
|
||||||
BOOL is_gamepad;
|
BOOL is_gamepad;
|
||||||
WCHAR *serial;
|
WCHAR *serial;
|
||||||
const WCHAR *busid; /* Expected to be a static constant */
|
const WCHAR *busid; /* Expected to be a static constant */
|
||||||
|
|
||||||
|
const platform_vtbl *vtbl;
|
||||||
|
BYTE platform_private[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
static CRITICAL_SECTION device_list_cs;
|
static CRITICAL_SECTION device_list_cs;
|
||||||
|
@ -80,6 +83,12 @@ static inline WCHAR *strdupW(const WCHAR *src)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *get_platform_private(DEVICE_OBJECT *device)
|
||||||
|
{
|
||||||
|
struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
|
||||||
|
return ext->platform_private;
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD get_vidpid_index(WORD vid, WORD pid)
|
static DWORD get_vidpid_index(WORD vid, WORD pid)
|
||||||
{
|
{
|
||||||
struct pnp_device *ptr;
|
struct pnp_device *ptr;
|
||||||
|
@ -157,9 +166,9 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW, void *native, WORD vid,
|
DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW, WORD vid, WORD pid,
|
||||||
WORD pid, DWORD version, DWORD uid, const WCHAR *serialW, BOOL is_gamepad,
|
DWORD version, DWORD uid, const WCHAR *serialW, BOOL is_gamepad,
|
||||||
const GUID *class)
|
const GUID *class, const platform_vtbl *vtbl, DWORD platform_data_size)
|
||||||
{
|
{
|
||||||
static const WCHAR device_name_fmtW[] = {'\\','D','e','v','i','c','e','\\','%','s','#','%','p',0};
|
static const WCHAR device_name_fmtW[] = {'\\','D','e','v','i','c','e','\\','%','s','#','%','p',0};
|
||||||
struct device_extension *ext;
|
struct device_extension *ext;
|
||||||
|
@ -169,16 +178,18 @@ DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW,
|
||||||
WCHAR dev_name[256];
|
WCHAR dev_name[256];
|
||||||
HDEVINFO devinfo;
|
HDEVINFO devinfo;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
DWORD length;
|
||||||
|
|
||||||
TRACE("(%p, %s, %p, %04x, %04x, %u, %u, %s, %u, %s)\n", driver, debugstr_w(busidW), native,
|
TRACE("(%p, %s, %04x, %04x, %u, %u, %s, %u, %s, %p, %u)\n", driver, debugstr_w(busidW), vid, pid,
|
||||||
vid, pid, version, uid, debugstr_w(serialW), is_gamepad, debugstr_guid(class));
|
version, uid, debugstr_w(serialW), is_gamepad, debugstr_guid(class), vtbl, platform_data_size);
|
||||||
|
|
||||||
if (!(pnp_dev = HeapAlloc(GetProcessHeap(), 0, sizeof(*pnp_dev))))
|
if (!(pnp_dev = HeapAlloc(GetProcessHeap(), 0, sizeof(*pnp_dev))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
sprintfW(dev_name, device_name_fmtW, busidW, native);
|
sprintfW(dev_name, device_name_fmtW, busidW, pnp_dev);
|
||||||
RtlInitUnicodeString(&nameW, dev_name);
|
RtlInitUnicodeString(&nameW, dev_name);
|
||||||
status = IoCreateDevice(driver, sizeof(*ext), &nameW, 0, 0, FALSE, &device);
|
length = FIELD_OFFSET(struct device_extension, platform_private[platform_data_size]);
|
||||||
|
status = IoCreateDevice(driver, length, &nameW, 0, 0, FALSE, &device);
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
FIXME("failed to create device error %x\n", status);
|
FIXME("failed to create device error %x\n", status);
|
||||||
|
@ -190,7 +201,7 @@ DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW,
|
||||||
|
|
||||||
/* fill out device_extension struct */
|
/* fill out device_extension struct */
|
||||||
ext = (struct device_extension *)device->DeviceExtension;
|
ext = (struct device_extension *)device->DeviceExtension;
|
||||||
ext->native = native;
|
ext->pnp_device = pnp_dev;
|
||||||
ext->vid = vid;
|
ext->vid = vid;
|
||||||
ext->pid = pid;
|
ext->pid = pid;
|
||||||
ext->uid = uid;
|
ext->uid = uid;
|
||||||
|
@ -199,6 +210,7 @@ DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW,
|
||||||
ext->is_gamepad = is_gamepad;
|
ext->is_gamepad = is_gamepad;
|
||||||
ext->serial = strdupW(serialW);
|
ext->serial = strdupW(serialW);
|
||||||
ext->busid = busidW;
|
ext->busid = busidW;
|
||||||
|
ext->vtbl = vtbl;
|
||||||
|
|
||||||
/* add to list of pnp devices */
|
/* add to list of pnp devices */
|
||||||
pnp_dev->device = device;
|
pnp_dev->device = device;
|
||||||
|
@ -226,10 +238,52 @@ DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW,
|
||||||
else
|
else
|
||||||
ERR("failed to get ClassDevs: %x\n", GetLastError());
|
ERR("failed to get ClassDevs: %x\n", GetLastError());
|
||||||
|
|
||||||
IoInvalidateDeviceRelations(device, BusRelations);
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEVICE_OBJECT *bus_find_hid_device(const platform_vtbl *vtbl, void *platform_dev)
|
||||||
|
{
|
||||||
|
struct pnp_device *dev;
|
||||||
|
DEVICE_OBJECT *ret = NULL;
|
||||||
|
|
||||||
|
TRACE("(%p, %p)\n", vtbl, platform_dev);
|
||||||
|
|
||||||
|
EnterCriticalSection(&device_list_cs);
|
||||||
|
LIST_FOR_EACH_ENTRY(dev, &pnp_devset, struct pnp_device, entry)
|
||||||
|
{
|
||||||
|
struct device_extension *ext = (struct device_extension *)dev->device->DeviceExtension;
|
||||||
|
if (ext->vtbl != vtbl) continue;
|
||||||
|
if (ext->vtbl->compare_platform_device(dev->device, platform_dev) == 0)
|
||||||
|
{
|
||||||
|
ret = dev->device;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&device_list_cs);
|
||||||
|
|
||||||
|
TRACE("returning %p\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bus_remove_hid_device(DEVICE_OBJECT *device)
|
||||||
|
{
|
||||||
|
struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
|
||||||
|
struct pnp_device *pnp_device = ext->pnp_device;
|
||||||
|
|
||||||
|
TRACE("(%p)\n", device);
|
||||||
|
|
||||||
|
EnterCriticalSection(&device_list_cs);
|
||||||
|
list_remove(&pnp_device->entry);
|
||||||
|
LeaveCriticalSection(&device_list_cs);
|
||||||
|
|
||||||
|
IoInvalidateDeviceRelations(device, RemovalRelations);
|
||||||
|
HeapFree(GetProcessHeap(), 0, ext->serial);
|
||||||
|
IoDeleteDevice(device);
|
||||||
|
|
||||||
|
/* pnp_device must be released after the device is gone */
|
||||||
|
HeapFree(GetProcessHeap(), 0, pnp_device);
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS handle_IRP_MN_QUERY_ID(DEVICE_OBJECT *device, IRP *irp)
|
static NTSTATUS handle_IRP_MN_QUERY_ID(DEVICE_OBJECT *device, IRP *irp)
|
||||||
{
|
{
|
||||||
NTSTATUS status = irp->IoStatus.u.Status;
|
NTSTATUS status = irp->IoStatus.u.Status;
|
||||||
|
|
Loading…
Reference in New Issue