Some games with support for the haptic feedback and speaker features of the Sony DualSense controller select the controller's audio output by filtering on the ContainerId IMMDevice property to find one that matches the controller's HID's.
While MRs !359 and !360 implement getting the ContainerID of the IMMDevice, this MR implements getting the ContainerID from the HID device.
As for !360, I marked this MR as a draft because I understand that the way the ���GUID��� is generated is far from ideal. Furthermore, there is code duplication with !360 in the way the container's sysfspath is found and how a GUID is generated from it, so moving that part elsewhere would make sense. But as for !360, I think I will need help with those tasks.
From: Claire Girka claire@sitedethib.com
Store the sysfs path of container USB devices detected by the udev backend so a container ID can be assigned. --- dlls/winebus.sys/bus_udev.c | 34 ++++++++++++++++++++++++++++++++++ dlls/winebus.sys/unixlib.h | 1 + 2 files changed, 35 insertions(+)
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 21a70d0829b..bc6e8f6312d 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1218,6 +1218,36 @@ static const struct hid_device_vtbl lnxev_device_vtbl = }; #endif /* HAS_PROPER_INPUT_HEADER */
+static void get_device_container_syspath(const char *syspath, struct device_desc *desc) +{ + char path[MAX_PATH], buffer[10], *p; + + if (strlen(syspath) + strlen("/removable") + 1 > MAX_PATH) + return; + + strcpy(path, syspath); + + while ((p = strrchr(path, '/'))) { + FILE *f; + + strcpy(p, "/removable"); + f = fopen(path, "r"); + *p = 0; + + if (f) { + if (fgets(buffer, 10, f) && strcmp(buffer, "fixed") != 0) { + /* It's a potentially removable device, so treat it as a container */ + fclose(f); + break; + } + fclose(f); + } + } + + if (p && (p - path) > 12) + lstrcpynA(desc->container_syspath, path, sizeof(desc->container_syspath)); +} + static void get_device_subsystem_info(struct udev_device *dev, char const *subsystem, struct device_desc *desc, int *bus) { @@ -1276,6 +1306,10 @@ static void get_device_subsystem_info(struct udev_device *dev, char const *subsy
if (!desc->serialnumber[0] && (tmp = udev_device_get_sysattr_value(dev, "serial"))) ntdll_umbstowcs(tmp, strlen(tmp) + 1, desc->serialnumber, ARRAY_SIZE(desc->serialnumber)); + + if (!desc->container_syspath[0] && (tmp = udev_device_get_syspath(dev))) { + get_device_container_syspath(tmp, desc); + } }
static void hidraw_set_quirks(struct hidraw_device *impl, DWORD bus_type, WORD vid, WORD pid) diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index 68d59ac0333..944c1d375c7 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -42,6 +42,7 @@ struct device_desc WCHAR manufacturer[MAX_PATH]; WCHAR product[MAX_PATH]; WCHAR serialnumber[MAX_PATH]; + char container_syspath[MAX_PATH]; };
struct sdl_bus_options
From: Claire Girka claire@sitedethib.com
--- dlls/winebus.sys/Makefile.in | 2 +- dlls/winebus.sys/main.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/dlls/winebus.sys/Makefile.in b/dlls/winebus.sys/Makefile.in index da02ae06870..9677d3b908e 100644 --- a/dlls/winebus.sys/Makefile.in +++ b/dlls/winebus.sys/Makefile.in @@ -1,6 +1,6 @@ MODULE = winebus.sys UNIXLIB = winebus.so -IMPORTS = ntoskrnl hidparse +IMPORTS = ntoskrnl hidparse ole32 UNIX_LIBS = $(IOKIT_LIBS) $(UDEV_LIBS) $(PTHREAD_LIBS) $(INOTIFY_LIBS) UNIX_CFLAGS = $(UDEV_CFLAGS) $(SDL2_CFLAGS)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 1037295c955..c3a97413d01 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -37,6 +37,7 @@ #include "wine/debug.h" #include "wine/list.h" #include "wine/unixlib.h" +#include "ole2.h"
#include "unixlib.h"
@@ -197,6 +198,36 @@ static WCHAR *get_instance_id(DEVICE_OBJECT *device) return dst; }
+static WCHAR *get_container_id(DEVICE_OBJECT *device) +{ + struct device_extension *ext = (struct device_extension *)device->DeviceExtension; + UINT len = (38+1)*sizeof(WCHAR); + WCHAR *dst; + GUID guid; + const char *p; + + if (!ext->desc.container_syspath[0]) + return NULL; + + memset(&guid, 0, sizeof(GUID)); + guid.Data1 = (ext->desc.vid << 16) | ext->desc.pid; + + /* Get just the USB bus-devpath part */ + p = strrchr(ext->desc.container_syspath, '/'); + if (!p || (p - ext->desc.container_syspath) <= 12) + return NULL; + + for (int i = 0; p[i]; i++) { + ((char *) &guid)[4 + i % 12] ^= p[i]; + } + + if (!(dst = ExAllocatePool(PagedPool, len))) + return NULL; + + StringFromGUID2(&guid, dst, len); + return dst; +} + static WCHAR *get_device_id(DEVICE_OBJECT *device) { static const WCHAR input_format[] = L"&MI_%02u"; @@ -507,6 +538,10 @@ static NTSTATUS handle_IRP_MN_QUERY_ID(DEVICE_OBJECT *device, IRP *irp) TRACE("BusQueryInstanceID\n"); irp->IoStatus.Information = (ULONG_PTR)get_instance_id(device); break; + case BusQueryContainerID: + TRACE("BusQueryContainerID\n"); + irp->IoStatus.Information = (ULONG_PTR)get_container_id(device); + break; default: FIXME("Unhandled type %08x\n", type); return status;
Any update on this?
On Mon Sep 4 16:59:45 2023 +0000, Gabriele wrote:
Any update on this?
It's a draft so I'm assuming it's not ready for an actual review, it'd need some changes to fix the inconsistent style for instance.
Also, in its current state I don't think it does anything very useful, except maybe creating a BusQueryContainerID attribute. If that's the only thing we need, it could be done with dummy data and doesn't need anything in the winebus backend.
As I understand it, the idea and requirement is to ultimately reconcile and match together audio devices from mmdevapi and hid devices, to expose the same BusQueryContainerID on Sony controllers and their speaker device. I don't think we have any way to do that at the moment, especially since mmdevapi devices are much more high level.